diff --git a/project.4coder b/project.4coder index 0b10da9c..b5fb9e8d 100644 --- a/project.4coder +++ b/project.4coder @@ -49,7 +49,7 @@ commands = // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/project.raddbg b/project.raddbg index 7570552c..2401ecf6 100644 --- a/project.raddbg +++ b/project.raddbg @@ -1,4 +1,4 @@ -// raddbg 0.9.27 project file +// raddbg 0.9.28 project file name: "The RAD Debugger" target: @@ -7,7 +7,6 @@ target: working_directory: "../raddebugger" arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user" debug_subprocesses: 0 - enabled: 1 } target: { @@ -31,3 +30,9 @@ target: working_directory: build arguments: "--rdi raddbg" } +target: +{ + executable: "build/ryan_scratch.exe" + working_directory: "build/" + enabled: 1 +} diff --git a/src/arch/arch.c b/src/arch/arch.c index 25e07963..50361259 100644 --- a/src/arch/arch.c +++ b/src/arch/arch.c @@ -1,170 +1,174 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Abstracted Architecture Functions - -internal ARCH_Info * -arch_info_from_arch(Arch arch) -{ - ARCH_Info *result = &arch_info_nil; - switch(arch) - { - default:{}break; -#if defined(X64_H) - case Arch_x64: - { - local_persist U8 trap_inst_bytes[] = {0xcc}; - local_persist read_only ARCH_Info info = - { - .reg_block_size = sizeof(X64_RegBlock), - .instruction_pointer_reg_code = X64_RegCode_rip, - .stack_pointer_reg_code = X64_RegCode_rsp, - .reg_code_count = X64_RegCode_COUNT, - .trap_instruction = {trap_inst_bytes, sizeof(trap_inst_bytes)}, - .reg_code_rng_table = x64_reg_code_rng_table, - .reg_code_name_table = x64_reg_code_name_table, - .reg_code_base_table = x64_reg_code_base_table, - .reg_code_is_vector_table = x64_reg_code_is_vector_table, - }; - result = &info; - }break; -#endif - } - return result; -} - -internal ARCH_RegCode -arch_reg_code_from_name(ARCH_Info *arch_info, String8 name) -{ - ARCH_RegCode result = 0; - for EachIndex(code, arch_info->reg_code_count) - { - if(str8_match(arch_info->reg_code_name_table[code], name, 0)) - { - result = code; - break; - } - } - return result; -} - -internal ARCH_RegCode -arch_reg_code_from_rdi(Arch arch, RDI_RegCode code) -{ - ARCH_RegCode result = 0; - { - ARCH_Info *arch_info = arch_info_from_arch(arch); - U8 *rdi_from_reg_code_table = arch_rdi_from_reg_code_table_from_arch(arch); - for EachIndex(c, arch_info->reg_code_count) - { - if(rdi_from_reg_code_table[c] == code) - { - result = c; - break; - } - } - } - return result; -} - -internal ARCH_RegCode -arch_reg_code_from_dw(Arch arch, DW_RegCode code) -{ - ARCH_RegCode result = 0; - { - ARCH_Info *arch_info = arch_info_from_arch(arch); - U8 *dw_from_reg_code_table = arch_dw_from_reg_code_table_from_arch(arch); - for EachIndex(c, arch_info->reg_code_count) - { - if(dw_from_reg_code_table[c] == code) - { - result = c; - break; - } - } - } - return result; -} - -internal B32 -arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst) -{ - B32 result = 0; - { - Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size); - Rng1U16 try_range = range; - Rng1U16 read_range = intersect_1u16(legal_range, try_range); - U64 read_size = dim_1u16(read_range); - if(read_size != 0) - { - MemoryCopy(dst, (U8 *)block + read_range.min, read_size); - result = 1; - } - } - return result; -} - -internal B32 -arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src) -{ - B32 result = 0; - Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size); - Rng1U16 try_range = range; - Rng1U16 write_range = intersect_1u16(legal_range, try_range); - U64 write_size = dim_1u16(write_range); - if(write_size != 0) - { - MemoryCopy((U8 *)block + write_range.min, src, write_size); - result = 1; - } - return result; -} - -internal U64 -arch_ip_from_reg_block(ARCH_Info *arch_info, void *block) -{ - U64 result = 0; - ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code; - if(reg_code < arch_info->reg_code_count) - { - arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result); - } - return result; -} - -internal U64 -arch_sp_from_reg_block(ARCH_Info *arch_info, void *block) -{ - U64 result = 0; - ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code; - if(reg_code < arch_info->reg_code_count) - { - arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result); - } - return result; -} - -internal B32 -arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip) -{ - B32 result = 0; - ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code; - if(reg_code < arch_info->reg_code_count) - { - result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &ip); - } - return result; -} - -internal B32 -arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp) -{ - B32 result = 0; - ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code; - if(reg_code < arch_info->reg_code_count) - { - result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &sp); - } - return result; -} +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Abstracted Architecture Functions + +internal ARCH_Info * +arch_info_from_arch(Arch arch) +{ + ARCH_Info *result = &arch_info_nil; + switch(arch) + { + default:{}break; +#if defined(X64_H) + case Arch_x64: + { + local_persist U8 trap_inst_bytes[] = {0xcc}; + local_persist read_only ARCH_Info info = + { + .reg_block_size = sizeof(X64_RegBlock), + .instruction_pointer_reg_code = X64_RegCode_rip, + .stack_pointer_reg_code = X64_RegCode_rsp, + .reg_code_count = X64_RegCode_COUNT, + .trap_instruction = {trap_inst_bytes, sizeof(trap_inst_bytes)}, + .reg_code_rng_table = x64_reg_code_rng_table, + .reg_code_name_table = x64_reg_code_name_table, + .reg_code_base_table = x64_reg_code_base_table, + .reg_code_is_vector_table = x64_reg_code_is_vector_table, + }; + result = &info; + }break; +#endif + } + return result; +} + +internal ARCH_RegCode +arch_reg_code_from_name(ARCH_Info *arch_info, String8 name) +{ + ARCH_RegCode result = 0; + for EachIndex(code, arch_info->reg_code_count) + { + if(str8_match(arch_info->reg_code_name_table[code], name, 0)) + { + result = code; + break; + } + } + return result; +} + +internal B32 +arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst) +{ + B32 result = 0; + { + Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size); + Rng1U16 try_range = range; + Rng1U16 read_range = intersect_1u16(legal_range, try_range); + U64 read_size = dim_1u16(read_range); + if(read_size != 0) + { + MemoryCopy(dst, (U8 *)block + read_range.min, read_size); + result = 1; + } + } + return result; +} + +internal B32 +arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src) +{ + B32 result = 0; + Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size); + Rng1U16 try_range = range; + Rng1U16 write_range = intersect_1u16(legal_range, try_range); + U64 write_size = dim_1u16(write_range); + if(write_size != 0) + { + MemoryCopy((U8 *)block + write_range.min, src, write_size); + result = 1; + } + return result; +} + +internal U64 +arch_ip_from_reg_block(ARCH_Info *arch_info, void *block) +{ + U64 result = 0; + ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code; + if(reg_code < arch_info->reg_code_count) + { + arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result); + } + return result; +} + +internal U64 +arch_sp_from_reg_block(ARCH_Info *arch_info, void *block) +{ + U64 result = 0; + ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code; + if(reg_code < arch_info->reg_code_count) + { + arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result); + } + return result; +} + +internal B32 +arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip) +{ + B32 result = 0; + ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code; + if(reg_code < arch_info->reg_code_count) + { + result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &ip); + } + return result; +} + +internal B32 +arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp) +{ + B32 result = 0; + ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code; + if(reg_code < arch_info->reg_code_count) + { + result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &sp); + } + return result; +} + +#if defined(RDI_H) +internal ARCH_RegCode +arch_reg_code_from_rdi(Arch arch, RDI_RegCode code) +{ + ARCH_RegCode result = 0; + { + ARCH_Info *arch_info = arch_info_from_arch(arch); + U8 *rdi_from_reg_code_table = arch_rdi_from_reg_code_table_from_arch(arch); + for EachIndex(c, arch_info->reg_code_count) + { + if(rdi_from_reg_code_table[c] == code) + { + result = c; + break; + } + } + } + return result; +} +#endif + +#if defined(DWARF_H) +internal ARCH_RegCode +arch_reg_code_from_dw(Arch arch, DW_RegCode code) +{ + ARCH_RegCode result = 0; + { + ARCH_Info *arch_info = arch_info_from_arch(arch); + U8 *dw_from_reg_code_table = arch_dw_from_reg_code_table_from_arch(arch); + for EachIndex(c, arch_info->reg_code_count) + { + if(dw_from_reg_code_table[c] == code) + { + result = c; + break; + } + } + } + return result; +} +#endif diff --git a/src/arch/arch.h b/src/arch/arch.h index dbdb1b28..be53103f 100644 --- a/src/arch/arch.h +++ b/src/arch/arch.h @@ -1,49 +1,54 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef ARCH_H -#define ARCH_H - -//////////////////////////////// -//~ rjf: Abstraction Backend Info - -typedef U8 ARCH_RegCode; - -typedef struct ARCH_Info ARCH_Info; -struct ARCH_Info -{ - U16 reg_block_size; - ARCH_RegCode instruction_pointer_reg_code; - ARCH_RegCode stack_pointer_reg_code; - U16 reg_code_count; - String8 trap_instruction; - Rng1U16 *reg_code_rng_table; - String8 *reg_code_name_table; - U8 *reg_code_base_table; - B8 *reg_code_is_vector_table; -}; - -//////////////////////////////// -//~ rjf: Globals - -global read_only Rng1U16 arch_reg_code_rng_nil = {0}; -global read_only String8 arch_reg_code_name_nil = {0}; -global read_only U8 arch_reg_code_u8_nil = 0; -global read_only B8 arch_reg_code_b8_nil = 0; -global read_only ARCH_Info arch_info_nil = {0, 0, 0, 0, {0}, &arch_reg_code_rng_nil, &arch_reg_code_name_nil, &arch_reg_code_u8_nil, &arch_reg_code_b8_nil}; - -//////////////////////////////// -//~ rjf: Abstracted Architecture Functions - -internal ARCH_Info *arch_info_from_arch(Arch arch); -internal ARCH_RegCode arch_reg_code_from_name(ARCH_Info *arch_info, String8 name); -internal ARCH_RegCode arch_reg_code_from_rdi(Arch arch, RDI_RegCode code); -internal ARCH_RegCode arch_reg_code_from_dw(Arch arch, DW_RegCode code); -internal B32 arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst); -internal B32 arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src); -internal U64 arch_ip_from_reg_block(ARCH_Info *arch_info, void *block); -internal U64 arch_sp_from_reg_block(ARCH_Info *arch_info, void *block); -internal B32 arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip); -internal B32 arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp); - -#endif // REGS_H +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef ARCH_H +#define ARCH_H + +//////////////////////////////// +//~ rjf: Abstraction Backend Info + +typedef U8 ARCH_RegCode; + +typedef struct ARCH_Info ARCH_Info; +struct ARCH_Info +{ + U16 reg_block_size; + ARCH_RegCode instruction_pointer_reg_code; + ARCH_RegCode stack_pointer_reg_code; + U16 reg_code_count; + String8 trap_instruction; + Rng1U16 *reg_code_rng_table; + String8 *reg_code_name_table; + U8 *reg_code_base_table; + B8 *reg_code_is_vector_table; +}; + +//////////////////////////////// +//~ rjf: Globals + +global read_only Rng1U16 arch_reg_code_rng_nil = {0}; +global read_only String8 arch_reg_code_name_nil = {0}; +global read_only U8 arch_reg_code_u8_nil = 0; +global read_only B8 arch_reg_code_b8_nil = 0; +global read_only ARCH_Info arch_info_nil = {0, 0, 0, 0, {0}, &arch_reg_code_rng_nil, &arch_reg_code_name_nil, &arch_reg_code_u8_nil, &arch_reg_code_b8_nil}; + +//////////////////////////////// +//~ rjf: Abstracted Architecture Functions + +internal ARCH_Info *arch_info_from_arch(Arch arch); +internal ARCH_RegCode arch_reg_code_from_name(ARCH_Info *arch_info, String8 name); +internal B32 arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst); +internal B32 arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src); +internal U64 arch_ip_from_reg_block(ARCH_Info *arch_info, void *block); +internal U64 arch_sp_from_reg_block(ARCH_Info *arch_info, void *block); +internal B32 arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip); +internal B32 arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp); + +#if defined(RDI_H) +internal ARCH_RegCode arch_reg_code_from_rdi(Arch arch, RDI_RegCode code); +#endif +#if defined(DWARF_H) +internal ARCH_RegCode arch_reg_code_from_dw(Arch arch, DW_RegCode code); +#endif + +#endif // REGS_H diff --git a/src/eval2/eval2.c b/src/eval2/eval2.c index 4aa40b17..4f1295aa 100644 --- a/src/eval2/eval2.c +++ b/src/eval2/eval2.c @@ -117,24 +117,24 @@ e2_expr_from_name(E2_ExprMap *map, String8 name) //~ rjf: Messages internal E2_Msg * -e2_msg(Arena *arena, E2_MsgList *msgs, U64 src_off, String8 string) +e2_msg(Arena *arena, E2_MsgList *msgs, Rng1U64 src_range, String8 string) { E2_Msg *msg = push_array(arena, E2_Msg, 1); SLLQueuePush(msgs->first, msgs->last, msg); msgs->count += 1; - msg->src_off = src_off; + msg->src_range = src_range; msg->string = str8_copy(arena, string); return msg; } internal E2_Msg * -e2_msgf(Arena *arena, E2_MsgList *msgs, U64 src_off, char *fmt, ...) +e2_msgf(Arena *arena, E2_MsgList *msgs, Rng1U64 src_range, char *fmt, ...) { Temp scratch = scratch_begin(&arena, 1); va_list args; va_start(args, fmt); String8 string = str8fv(scratch.arena, fmt, args); - E2_Msg *msg = e2_msg(arena, msgs, src_off, string); + E2_Msg *msg = e2_msg(arena, msgs, src_range, string); va_end(args); scratch_end(scratch); return msg; @@ -155,7 +155,7 @@ e2_type_key_basic(E2_TypeKind kind) //~ rjf: String -> Expression internal E2_Token -e2_token_from_string(String8 string) +e2_token_from_string_off(String8 string, U64 start_off) { E2_Token token = {E2_TokenKind_Null}; B32 identifier_tick_mode = 0; @@ -163,7 +163,7 @@ e2_token_from_string(String8 string) B32 numeric_exponent = 0; B32 escaped = 0; B32 done = 0; - for(U64 off = 0; !done && off <= string.size; off += 1) + for(U64 off = start_off; !done && off <= string.size; off += 1) { U8 next_byte = (off < string.size ? string.str[off] : 0); U8 next2_byte = (off+1 < string.size ? string.str[off+1] : 0); @@ -173,7 +173,11 @@ e2_token_from_string(String8 string) //- rjf: no set token kind => look for starters default: { - if(next_byte <= 32) + if(next_byte == 0) + { + done = 1; + } + else if(next_byte <= 32) { token.kind = E2_TokenKind_Whitespace; token.range.min = token.range.max = off; @@ -263,6 +267,7 @@ e2_token_from_string(String8 string) if(numeric_exponent && (next_byte == '+' || next_byte == '-')){} else if((next_byte < 'a' || 'z' < next_byte) && (next_byte < 'A' || 'Z' < next_byte) && + (next_byte < '0' || '9' < next_byte) && next_byte != '.' && next_byte != ':') { @@ -323,7 +328,7 @@ e2_token_from_string(String8 string) internal U64 e2_read_token(String8 string, U64 off, E2_Token *token_out) { - E2_Token token = e2_token_from_string(str8_skip(string, off)); + E2_Token token = e2_token_from_string_off(string, off); if(token_out != 0) { token_out[0] = token; @@ -344,6 +349,10 @@ e2_try_token(String8 string, E2_TokenKind kind, String8 expected_string, U64 *of if(next_token.kind == kind && (expected_string.size == 0 || str8_match(str8_substr(string, next_token.range), expected_string, 0))) { result = 1; + if(token_out != 0) + { + token_out[0] = next_token; + } break; } else if(next_token.kind != E2_TokenKind_Comment && next_token.kind != E2_TokenKind_Whitespace) @@ -351,7 +360,7 @@ e2_try_token(String8 string, E2_TokenKind kind, String8 expected_string, U64 *of break; } } - if(result) + if(result && off_out != 0) { off_out[0] = off; } @@ -368,6 +377,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_SpaceMap *space_map, // then it is just the result for(B32 done = 0; !done;) { + S64 max_precedence = state->top_task ? state->top_task->max_precedence : max_S64; E2_Expr *expr = &e2_expr_nil; E2_Token token = {0}; @@ -387,25 +397,48 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_SpaceMap *space_map, MemoryCopyStruct(task->parent, &e2_expr_nil); task->expected_closer = s(")"); task->child_count_target = 1; + task->max_precedence = max_S64; SLLStackPush(state->top_task, task); } //- rjf: prefix unaries else if(e2_try_token(string, E2_TokenKind_Symbol, s(""), &off, &token)) { - E2_ParseTask *task = state->free_task; - if(task != 0) + // rjf: string -> operator kind + E2_OpKind op_kind = E2_OpKind_Null; { - SLLStackPop(state->free_task); + String8 token_string = str8_substr(string, token.range); + for EachNonZeroEnumVal(E2_OpKind, k) + { + if(e2_op_kind_info_table[k].parse_kind == E2_OpParseKind_UnaryPrefix && + e2_op_kind_info_table[k].precedence <= max_precedence && + str8_match(token_string, e2_op_kind_info_table[k].pre, 0)) + { + op_kind = k; + break; + } + } } - else + + // rjf: push task for operand + if(op_kind != E2_OpKind_Null) { - task = push_array(arena, E2_ParseTask, 1); + E2_ParseTask *task = state->free_task; + if(task != 0) + { + SLLStackPop(state->free_task); + } + else + { + task = push_array(arena, E2_ParseTask, 1); + } + task->parent = push_array(arena, E2_Expr, 1); + MemoryCopyStruct(task->parent, &e2_expr_nil); + task->child_count_target = 1; + task->op_kind = op_kind; + task->max_precedence = e2_op_kind_info_table[op_kind].precedence; + SLLStackPush(state->top_task, task); } - task->parent = push_array(arena, E2_Expr, 1); - MemoryCopyStruct(task->parent, &e2_expr_nil); - task->child_count_target = 1; - SLLStackPush(state->top_task, task); } //- rjf: leaf identifiers @@ -462,7 +495,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_SpaceMap *space_map, case 8:{expr->op = RDI_EvalOp_ConstU512; expr->type_key = e2_type_key_basic(E2_TypeKind_U512);}break; default: { - e2_msgf(arena, &parse.msgs, token.range.min, "Invalid number of numeric portions specified (%I64u; must be 2, 4, or 8).", u64_idx); + e2_msgf(arena, &parse.msgs, token.range, "Invalid number of numeric portions specified (%I64u; must be 2, 4, or 8).", u64_idx); }break; } scratch_end(scratch); @@ -492,29 +525,149 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_SpaceMap *space_map, } } - //- rjf: attach formed expressions to task - if(expr != &e2_expr_nil && state->top_task != 0) + //- rjf: extend parsed expression tree with trailing binary operators + if(expr != &e2_expr_nil) { - SLLQueuePush(state->top_task->parent->first, state->top_task->parent->last, expr); - state->top_task->child_count += 1; - if(state->top_task->child_count == state->top_task->child_count_target) + U64 trailing_symbol_off = off; + if(e2_try_token(string, E2_TokenKind_Symbol, s(""), &trailing_symbol_off, &token)) { - // TODO(rjf): pop task, insert to parent, or decay to result - should naturally express below block too + // rjf: token string -> operator kind + E2_OpKind op_kind = E2_OpKind_Null; + { + String8 token_string = str8_substr(string, token.range); + for EachNonZeroEnumVal(E2_OpKind, k) + { + if(e2_op_kind_info_table[k].parse_kind == E2_OpParseKind_Binary && + e2_op_kind_info_table[k].precedence <= max_precedence && + str8_match(token_string, e2_op_kind_info_table[k].pre, 0)) + { + op_kind = k; + break; + } + } + } + + // rjf: non-null operator kind -> build binary expression node, push task to fill other child + if(op_kind != E2_OpKind_Null) + { + E2_ParseTask *task = state->free_task; + if(task != 0) + { + SLLStackPop(state->free_task); + } + else + { + task = push_array(arena, E2_ParseTask, 1); + } + task->parent = push_array(arena, E2_Expr, 1); + MemoryCopyStruct(task->parent, &e2_expr_nil); + SLLQueuePush_NZ(&e2_expr_nil, task->parent->first, task->parent->last, expr, next); + task->child_count = 1; + task->child_count_target = 2; + task->op_kind = op_kind; + task->max_precedence = e2_op_kind_info_table[op_kind].precedence; + SLLStackPush(state->top_task, task); + } } } - //- rjf: no task -> formed expr is result - if(expr != &e2_expr_nil && state->top_task == 0) + //- rjf: attach formed expressions to parent task exprs; pop tasks when they're done. + // if we have no parent task, then we just fill the result, and we're done with the parse. + if(expr != &e2_expr_nil) { - parse.expr = expr; - break; + //- rjf: pop finished expressions + E2_Expr *finished_expr = expr; + for(;state->top_task != 0;) + { + //- rjf: add finished expression to current parent; increase task child count + E2_Expr *finished_expr_parent = state->top_task->parent; + SLLQueuePush_NZ(&e2_expr_nil, finished_expr_parent->first, finished_expr_parent->last, finished_expr, next); + state->top_task->child_count += 1; + + //- rjf: task child count hits limit -> complete this child + if(state->top_task->child_count >= state->top_task->child_count_target) + { + //- rjf: release task; iterate to this finished expression next + E2_ParseTask *completed_task = state->top_task; + SLLStackPop(state->top_task); + SLLStackPush(state->free_task, completed_task); + + //- rjf: finish expression with operator info, if applicable + { + E2_Expr *root = completed_task->parent; + switch(completed_task->op_kind) + { + default:{}break; + + //- rjf: dereference + case E2_OpKind_Deref: + { + // rjf: unpack operand + E2_Expr *rhs = root->first; + // E2_TypeKey rhs_type_key = e2_type_key_unwrap(rhs->type_key, E2_TypeUnwrapFlag_AllDecorative & ~E2_TypeUnwrapFlag_Enums); + // E2_TypeKind rhs_type_kind = e2_type_kind_from_key(rhs_type_key); + // E2_TypeKey dereferenced_type = e2_type_key_unwrap(rhs->type_key, E2_TypeUnwrapFlag_All & ~E2_TypeUnwrapFlag_Enums); + // U64 dereferenced_type_size = e2_byte_size_from_type_key(dereferenced_type); + + // rjf: collect info about malformed situations + B32 malformed = 0; + // if(dereferenced_type_size == 0 && e2_type_kind_is_ptr_or_ref(rhs_type_kind)) + { + malformed = 1; + // e2_msgf(arena, &parse.msgs, src->root_range, ""); + } + }break; + + case E2_OpKind_Address:{}break; + case E2_OpKind_Pos:{}break; + case E2_OpKind_Neg:{}break; + case E2_OpKind_LogNot:{}break; + case E2_OpKind_BitNot:{}break; + case E2_OpKind_Mul:{}break; + case E2_OpKind_Div:{}break; + case E2_OpKind_Mod:{}break; + case E2_OpKind_Add:{}break; + case E2_OpKind_Sub:{}break; + case E2_OpKind_LShift:{}break; + case E2_OpKind_RShift:{}break; + case E2_OpKind_Less:{}break; + case E2_OpKind_LtEq:{}break; + case E2_OpKind_Grtr:{}break; + case E2_OpKind_GrEq:{}break; + case E2_OpKind_EqEq:{}break; + case E2_OpKind_NtEq:{}break; + case E2_OpKind_BitAnd:{}break; + case E2_OpKind_BitXor:{}break; + case E2_OpKind_BitOr:{}break; + case E2_OpKind_LogAnd:{}break; + case E2_OpKind_LogOr:{}break; + case E2_OpKind_Define:{}break; + } + } + + //- rjf: iterate to the completed task's expression node next, to try & finish it for *its* parent + finished_expr = completed_task->parent; + } + } + + //- rjf: for the last finished expression, if we do not have any further tasks, + // this is our result. + if(finished_expr != &e2_expr_nil && state->top_task == 0) + { + parse.expr = finished_expr; + if(parse.status == E2_Status_Error) + { + parse.status = E2_Status_Good; + } + break; + } } } //- rjf: advance offset if successful if(parse.status == E2_Status_Good) { - state->string_off += off; + state->string_off = off; } return parse; } diff --git a/src/eval2/eval2.h b/src/eval2/eval2.h index f9d776fd..e56d35da 100644 --- a/src/eval2/eval2.h +++ b/src/eval2/eval2.h @@ -205,33 +205,6 @@ struct E2_Val typedef U64 E2_SpaceID; -typedef struct E2_DbgInfo E2_DbgInfo; -struct E2_DbgInfo -{ - DI_Key dbgi_key; - RDI_Parsed *rdi; - String8 name; -}; - -typedef struct E2_Module E2_Module; -struct E2_Module -{ - E2_SpaceID space_id; - Rng1U64 addr_range; - E2_DbgInfo *dbg_info; - Arch arch; - String8 name; -}; - -typedef struct E2_Assets E2_Assets; -struct E2_Assets -{ - E2_Module *modules; - U64 modules_count; - E2_DbgInfo *dbg_infos; - U64 dbg_infos_count; -}; - //////////////////////////////// //~ rjf: Evaluation Contexts @@ -298,6 +271,7 @@ struct E2_Expr E2_Expr *first; E2_Expr *last; E2_Expr *next; + Rng1U64 src_range; String8 string; RDI_EvalOp op; E2_TypeKey type_key; @@ -327,6 +301,8 @@ struct E2_ParseTask E2_Expr *parent; U64 child_count; U64 child_count_target; + S64 max_precedence; + E2_OpKind op_kind; String8 expected_closer; }; @@ -342,7 +318,7 @@ typedef struct E2_Msg E2_Msg; struct E2_Msg { E2_Msg *next; - U64 src_off; + Rng1U64 src_range; String8 string; }; @@ -358,10 +334,6 @@ typedef struct E2_Parse E2_Parse; struct E2_Parse { E2_Status status; - E2_SpaceID space_id; - Rng1U64 missed_read_space_addr_range; - E2_CtxID ctx_id; - E2_CtxFlags missing_ctx_flags; String8 missed_identifier; E2_Expr *expr; E2_Expr *access_expr; @@ -433,8 +405,8 @@ internal E2_Expr *e2_expr_from_name(E2_ExprMap *map, String8 name); //////////////////////////////// //~ rjf: Messages -internal E2_Msg *e2_msg(Arena *arena, E2_MsgList *msgs, U64 src_off, String8 string); -internal E2_Msg *e2_msgf(Arena *arena, E2_MsgList *msgs, U64 src_off, char *fmt, ...); +internal E2_Msg *e2_msg(Arena *arena, E2_MsgList *msgs, Rng1U64 src_range, String8 string); +internal E2_Msg *e2_msgf(Arena *arena, E2_MsgList *msgs, Rng1U64 src_range, char *fmt, ...); //////////////////////////////// //~ rjf: Types @@ -444,7 +416,7 @@ internal E2_TypeKey e2_type_key_basic(E2_TypeKind kind); //////////////////////////////// //~ rjf: String -> Expression -internal E2_Token e2_token_from_string(String8 string); +internal E2_Token e2_token_from_string_off(String8 string, U64 start_off); internal U64 e2_read_token(String8 string, U64 off, E2_Token *token_out); internal B32 e2_try_token(String8 string, E2_TokenKind kind, String8 expected_string, U64 *off_out, E2_Token *token_out); internal E2_Parse e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_SpaceMap *space_map, E2_ExprMap *expr_map, String8 string); diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 314db20a..a61108aa 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -436,7 +436,7 @@ RD_VocabInfo rd_vocab_info_table[368] = RD_NameSchemaInfo rd_name_schema_info_table[39] = { -{str8_lit_comp("user"), 0, str8_lit_comp("@expand_commands(edit_user_theme) x:\n{\n //- rjf: animations\n @display_name('Animations') @description(\"Enables animations.\")\n @default(1) 'animations': bool,\n @display_name('Scrolling Animations') @description(\"Enables scrolling animations.\")\n @expand_if(\"$.animations\") @default(1) 'scrolling_animations': bool,\n @display_name('Tooltip Animations') @description(\"Enables tooltip animations.\")\n @expand_if(\"$.animations\") @default(1) 'tooltip_animations': bool,\n @display_name('Menu Animations') @description(\"Enables menu animations.\")\n @expand_if(\"$.animations\") @default(1) 'menu_animations': bool,\n\n //- rjf: fonts\n @display_name('UI Font') @description(\"The name of, or path to, the font used when displaying non-code UI elements.\")\n @default('') 'main_font': string,\n @display_name('Code Font') @description(\"The name of, or path to, the font used when displaying code.\")\n @default('') 'code_font': string,\n\n //- rjf: theme\n @default(\"Default (Dark)\") @display_name('User Theme')\n @description(\"The user's theme, which describes all colors used throughout the UI.\")\n 'theme': string,\n @no_expand @display_name('User Theme')\n 'theme_colors': set,\n\n //- rjf: auto eval\n @display_name('Show Auto Watches In Source / Disassembly') @description(\"Enables the display of auto watch expressions inline in source and disassembly views.\") @default(1)\n 'show_autos_in_src_and_disasm': bool,\n\n //- rjf: autocompletion\n @display_name('Autocompletion Lister') @description(\"Enables the autocompletion lister while typing expressions.\") @default(1)\n 'autocompletion_lister': bool,\n @display_name('View Call Argument Helper') @description(\"Enables the view call argument helper, which shows view arguments and documentation, while typing expressions.\") @default(1)\n 'view_call_argument_helper': bool,\n\n //- rjf: scope decorations\n @default(1) @display_name('Cursor Scope Lines') @description(\"Controls whether or not scopes containing the cursor in text views are drawn.\")\n 'cursor_scope_lines': bool,\n @default(1) @display_name('Cursor Scope End Annotations') @description(\"Controls whether or not ending annotations for scopes containing the cursor are drawn.\")\n 'cursor_scope_end_annotations': bool,\n\n //- rjf: cursor decorations\n @default(1) @display_name('Cursor Trail') @description(\"Controls whether or not a movement trail of the cursor is drawn.\")\n 'cursor_trail': bool,\n\n //- rjf: thread & breakpoint decorations\n @default(1) @display_name('Thread Lines') @description(\"Controls whether or not a long horizontal line is drawn before the next line or instruction that the selected thread will execute in source and disassembly views.\")\n 'thread_lines': bool,\n @default(1) @display_name('Thread Glow') @description(\"Controls whether or not a glowing effect is drawn on the selected thread in source and disassembly views.\")\n 'thread_glow': bool,\n @default(1) @display_name('Breakpoint Lines') @description(\"Controls whether or not a long horizontal line is drawn before the line or instruction at which a breakpoint is placed, in source and disassembly views.\")\n 'breakpoint_lines': bool,\n @default(1) @display_name('Breakpoint Glow') @description(\"Controls whether or not a glowing effect is drawn on breakpoints in source and disassembly views.\")\n 'breakpoint_glow': bool,\n\n //- rjf: occluding background settings\n @default(0) @display_name('Opaque Backgrounds') @description(\"Controls whether or not all floating background colors are forced to be fully opaque.\")\n 'opaque_backgrounds': bool,\n @default(1) @display_name('Background Blur') @description(\"Controls whether or not occluded regions behind floating elements are blurred.\")\n 'background_blur': bool,\n\n //- rjf: appearance settings\n @default(1) @display_name('Drop Shadows') @description(\"Controls whether or not drop shadows are drawn.\")\n 'drop_shadows': bool,\n @default(1.f) @display_name('Rounded Corner Amount') @description(\"Controls the degree to which UI corners are rounded.\")\n 'rounded_corner_amount': @range[0, 1] f32,\n\n //- rjf: code formatting settings\n @default(2) @display_name('User Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: windows style menu bar\n @default(1) @display_name('Focus Menu Bar With Alt') @description(\"Mimics standard Windows behavior of focusing the menu bar using the Alt key.\")\n 'focus_menu_bar_with_alt': bool,\n\n //- rjf: native filesystem dialogues\n @default(0) @display_name('Use Native File System Dialog') @description(\"Uses the operating system's file system dialog box, rather than the debugger's built-in UI.\")\n 'use_native_file_system_dialog': bool,\n\n //- rjf: transient tabs\n @default(1) @display_name('Transient Tabs') @description(\"When snapping to source code locations, opens new files in a 'transient' tab if they are not already open. Transient tabs are replaced on subsequent snaps automatically.\")\n 'transient_tabs': bool,\n\n //- rjf: auto-load last project\n @default(0) @display_name('Auto Load Last Project') @description(\"Enables loading the most recently opened project, if one is not specified from the command line.\")\n 'auto_load_last_project': bool,\n\n //- rjf: symbol server\n @default(0) @display_name('Auto Download Debug Info') @description(\"Automatically tries to download missing debug info from symbol server(s).\")\n 'auto_download_debug_info': bool,\n}\n")}, +{str8_lit_comp("user"), 0, str8_lit_comp("@expand_commands(edit_user_theme) x:\n{\n //- rjf: animations\n @display_name('Animations') @description(\"Enables animations.\")\n @default(1) 'animations': bool,\n @display_name('Scrolling Animations') @description(\"Enables scrolling animations.\")\n @expand_if(\"$.animations\") @default(1) 'scrolling_animations': bool,\n @display_name('Tooltip Animations') @description(\"Enables tooltip animations.\")\n @expand_if(\"$.animations\") @default(1) 'tooltip_animations': bool,\n @display_name('Menu Animations') @description(\"Enables menu animations.\")\n @expand_if(\"$.animations\") @default(1) 'menu_animations': bool,\n\n //- rjf: fonts\n @display_name('UI Font') @description(\"The name of, or path to, the font used when displaying non-code UI elements.\")\n @default('') 'main_font': string,\n @display_name('Code Font') @description(\"The name of, or path to, the font used when displaying code.\")\n @default('') 'code_font': string,\n\n //- rjf: theme\n @default(\"Default (Dark)\") @display_name('User Theme')\n @description(\"The user's theme, which describes all colors used throughout the UI.\")\n 'theme': string,\n @no_expand @display_name('User Theme')\n 'theme_colors': set,\n\n //- rjf: auto eval\n @display_name('Show Auto Watches In Source / Disassembly') @description(\"Enables the display of auto watch expressions inline in source and disassembly views.\") @default(1)\n 'show_autos_in_src_and_disasm': bool,\n\n //- rjf: autocompletion\n @display_name('Autocompletion Lister') @description(\"Enables the autocompletion lister while typing expressions.\") @default(1)\n 'autocompletion_lister': bool,\n @display_name('View Call Argument Helper') @description(\"Enables the view call argument helper, which shows view arguments and documentation, while typing expressions.\") @default(1)\n 'view_call_argument_helper': bool,\n\n //- rjf: scope decorations\n @default(1) @display_name('Cursor Scope Lines') @description(\"Controls whether or not scopes containing the cursor in text views are drawn.\")\n 'cursor_scope_lines': bool,\n @default(1) @display_name('Cursor Scope End Annotations') @description(\"Controls whether or not ending annotations for scopes containing the cursor are drawn.\")\n 'cursor_scope_end_annotations': bool,\n\n //- rjf: cursor decorations\n @default(1) @display_name('Cursor Trail') @description(\"Controls whether or not a movement trail of the cursor is drawn.\")\n 'cursor_trail': bool,\n\n //- rjf: thread & breakpoint decorations\n @default(1) @display_name('Thread Lines') @description(\"Controls whether or not a long horizontal line is drawn before the next line or instruction that the selected thread will execute in source and disassembly views.\")\n 'thread_lines': bool,\n @default(1) @display_name('Thread Glow') @description(\"Controls whether or not a glowing effect is drawn on the selected thread in source and disassembly views.\")\n 'thread_glow': bool,\n @default(1) @display_name('Breakpoint Lines') @description(\"Controls whether or not a long horizontal line is drawn before the line or instruction at which a breakpoint is placed, in source and disassembly views.\")\n 'breakpoint_lines': bool,\n @default(1) @display_name('Breakpoint Glow') @description(\"Controls whether or not a glowing effect is drawn on breakpoints in source and disassembly views.\")\n 'breakpoint_glow': bool,\n\n //- rjf: occluding background settings\n @default(0) @display_name('Opaque Backgrounds') @description(\"Controls whether or not all floating background colors are forced to be fully opaque.\")\n 'opaque_backgrounds': bool,\n @default(1) @display_name('Background Blur') @description(\"Controls whether or not occluded regions behind floating elements are blurred.\")\n 'background_blur': bool,\n\n //- rjf: appearance settings\n @default(1) @display_name('Drop Shadows') @description(\"Controls whether or not drop shadows are drawn.\")\n 'drop_shadows': bool,\n @default(1.f) @display_name('Rounded Corner Amount') @description(\"Controls the degree to which UI corners are rounded.\")\n 'rounded_corner_amount': @range[0, 1] f32,\n\n //- rjf: code formatting settings\n @default(2) @display_name('User Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: windows style menu bar\n @default(1) @display_name('Focus Menu Bar With Alt') @description(\"Mimics standard Windows behavior of focusing the menu bar using the Alt key.\")\n 'focus_menu_bar_with_alt': bool,\n\n //- rjf: native filesystem dialogues\n @default(0) @display_name('Use Native File System Dialog') @description(\"Uses the operating system's file system dialog box, rather than the debugger's built-in UI.\")\n 'use_native_file_system_dialog': bool,\n\n //- rjf: transient tabs\n @default(1) @display_name('Transient Tabs') @description(\"When snapping to source code locations, opens new files in a 'transient' tab if they are not already open. Transient tabs are replaced on subsequent snaps automatically.\")\n 'transient_tabs': bool,\n\n //- rjf: auto-load last project\n @default(0) @display_name('Auto Load Last Project') @description(\"Enables loading the most recently opened project, if one is not specified from the command line.\")\n 'auto_load_last_project': bool,\n\n //- rjf: symbol server\n @default(0) @display_name('Auto Download Debug Info') @description(\"Automatically tries to download missing debug info from symbol server(s).\")\n 'auto_download_debug_info': bool,\n\n //- rjf: update check\n @default(1) @display_name('Check For Updates') @description(\"Enables a small network request to check if there is a newer release version available.\")\n 'check_for_updates': bool,\n}\n")}, {str8_lit_comp("project"), 0, str8_lit_comp("@expand_commands(edit_project_theme) x:\n{\n @display_name('Project Name') 'name': string,\n @default(2) @display_name('Project Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: visualizers\n @display_name('Display Pointer Addresses Before Contents') @description(\"When visualizing pointers, always shows the address first, before showing contents at the pointer's address.\")\n @default(0) display_pointer_addresses_before_contents: bool,\n @display_name('Use Default C++ STL Type Visualizers') @description(\"Enables the built-in type views for C++ STL types.\")\n @default(1) use_default_stl_type_views: bool,\n @display_name('Use Default Unreal Engine Type Visualizers') @description(\"Enables the built-in type views for Unreal Engine types.\")\n @default(1) use_default_ue_type_views: bool,\n\n //- rjf: theme\n @default(\"None\") @display_name('Project Theme') @description(\"The project's theme, which describes all colors used throughout the UI, and can override the user's theme.\")\n 'theme': string,\n @no_expand @display_name('Project Theme') @description(\"The project's theme, which describes all colors used throughout the UI, and can override the user's theme.\")\n 'theme_colors': set,\n\n //- rjf: exception settings\n @default(1) @display_name(\"Break On Win32 Control-C Exceptions\") @description(\"Code: 0x40010005\")\n win32_ctrl_c: bool;\n @default(1) @display_name(\"Break On Win32 Control-Break Exceptions\") @description(\"Code: 0x40010008\")\n win32_ctrl_break: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Originate Error Exceptions\") @description(\"Code: 0x40080201\")\n win32_win_rt_originate_error: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Transform Error Exceptions\") @description(\"Code: 0x40080202\")\n win32_win_rt_transform_error: bool;\n @default(0) @display_name(\"Break On Win32 RPC Call Cancelled Exceptions\") @description(\"Code: 0x0000071a\")\n win32_rpc_call_cancelled: bool;\n @default(0) @display_name(\"Break On Win32 Data Type Misalignment Exceptions\") @description(\"Code: 0x80000002\")\n win32_datatype_misalignment: bool;\n @default(1) @display_name(\"Break On Win32 Access Violation Exceptions\") @description(\"Code: 0xc0000005\")\n win32_access_violation: bool;\n @default(0) @display_name(\"Break On Win32 In Page Error Exceptions\") @description(\"Code: 0xc0000006\")\n win32_in_page_error: bool;\n @default(1) @display_name(\"Break On Win32 Invalid Handle Specified Exceptions\") @description(\"Code: 0xc0000008\")\n win32_invalid_handle: bool;\n @default(0) @display_name(\"Break On Win32 Not Enough Quota Exceptions\") @description(\"Code: 0xc0000017\")\n win32_not_enough_quota: bool;\n @default(0) @display_name(\"Break On Win32 Illegal Instruction Exceptions\") @description(\"Code: 0xc000001d\")\n win32_illegal_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Cannot Continue From Exception Exceptions\") @description(\"Code: 0xc0000025\")\n win32_cannot_continue_exception: bool;\n @default(0) @display_name(\"Break On Win32 Invalid Exception Disposition Returned By Handler Exceptions\") @description(\"Code: 0xc0000026\")\n win32_invalid_exception_disposition: bool;\n @default(0) @display_name(\"Break On Win32 Array Bounds Exceeded Exceptions\") @description(\"Code: 0xc000008c\")\n win32_array_bounds_exceeded: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Denormal Operand Exceptions\") @description(\"Code: 0xc000008d\")\n win32_floating_point_denormal_operand: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Division By Zero Exceptions\") @description(\"Code: 0xc000008e\")\n win32_floating_point_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Inexact Result Exceptions\") @description(\"Code: 0xc000008f\")\n win32_floating_point_inexact_result: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Invalid Operation Exceptions\") @description(\"Code: 0xc0000090\")\n win32_floating_point_invalid_operation: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Overflow Exceptions\") @description(\"Code: 0xc0000091\")\n win32_floating_point_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Stack Check Exceptions\") @description(\"Code: 0xc0000092\")\n win32_floating_point_stack_check: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Underflow Exceptions\") @description(\"Code: 0xc0000093\")\n win32_floating_point_underflow: bool;\n @default(0) @display_name(\"Break On Win32 Integer Division By Zero Exceptions\") @description(\"Code: 0xc0000094\")\n win32_integer_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Integer Overflow Exceptions\") @description(\"Code: 0xc0000095\")\n win32_integer_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Privileged Instruction Exceptions\") @description(\"Code: 0xc0000096\")\n win32_privileged_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Stack Overflow Exceptions\") @description(\"Code: 0xc00000fd\")\n win32_stack_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Unable To Locate DLL Exceptions\") @description(\"Code: 0xc0000135\")\n win32_unable_to_locate_dll: bool;\n @default(0) @display_name(\"Break On Win32 Ordinal Not Found Exceptions\") @description(\"Code: 0xc0000138\")\n win32_ordinal_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Entry Point Not Found Exceptions\") @description(\"Code: 0xc0000139\")\n win32_entry_point_not_found: bool;\n @default(0) @display_name(\"Break On Win32 DLL Initialization Failed Exceptions\") @description(\"Code: 0xc0000142\")\n win32_dll_initialization_failed: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Faults Exceptions\") @description(\"Code: 0xc00002b4\")\n win32_floating_point_sse_multiple_faults: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Traps Exceptions\") @description(\"Code: 0xc00002b5\")\n win32_floating_point_sse_multiple_traps: bool;\n @default(1) @display_name(\"Break On Win32 Assertion Failed Exceptions\") @description(\"Code: 0xc0000420\")\n win32_assertion_failed: bool;\n @default(0) @display_name(\"Break On Win32 Module Not Found Exceptions\") @description(\"Code: 0xc06d007e\")\n win32_module_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Procedure Not Found Exceptions\") @description(\"Code: 0xc06d007f\")\n win32_procedure_not_found: bool;\n @default(1) @display_name(\"Break On Win32 Sanitizer Error Detected Exceptions\") @description(\"Code: 0xe073616e\")\n win32_sanitizer_error_detected: bool;\n @default(0) @display_name(\"Break On Win32 Sanitizer Raw Access Violation Exceptions\") @description(\"Code: 0xe0736171\")\n win32_sanitizer_raw_access_violation: bool;\n @default(1) @display_name(\"Break On Win32 DirectX Debug Layer Exceptions\") @description(\"Code: 0x0000087a\")\n win32_directx_debug_layer: bool;\n}\n")}, {str8_lit_comp("theme_color"), 0, str8_lit_comp("@collection_commands(add_theme_color, fork_theme, save_theme, save_and_set_theme)\n@row_commands(duplicate_cfg, remove_cfg)\nx:\n{\n @display_name('Tags') tags: string,\n @display_name('Value') value: @color @hex u32,\n}\n")}, {str8_lit_comp("window"), 0, str8_lit_comp("x:\n{\n //- rjf: text rasterization settings\n @default(1) @display_name('Smooth UI Text') @description(\"Controls whether or not UI text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_ui_text': bool,\n @default(1) @display_name('Hint UI Text') @description(\"Controls whether or not UI text is hinted, for better text readability at small sizes.\")\n 'hint_ui_text': bool,\n @default(0) @display_name('Smooth Code Text') @description(\"Controls whether or not code text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_code_text': bool,\n @default(1) @display_name('Hint Code Text') @description(\"Controls whether or not code text is hinted, for better text readability at small sizes.\")\n 'hint_code_text': bool,\n @default(11) @display_name('Window Font Size') @description(\"Controls the window's default font size. Does not apply to tabs with their own font size set.\")\n 'font_size': @range[6, 72] u64,\n\n //- rjf: size settings\n @default(3.f) @display_name('Window Row Height') @description(\"Controls the window's default row height, in multiples of the font size. Does not apply to tabs with their own row height set.\")\n 'row_height': @range[1.75f, 5.f] f32,\n @default(3.f) @description(\"Controls the height of tabs, in multiples of the font size.\")\n 'tab_height': @range[1.75f, 5.f] f32,\n\n //- rjf: theme settings\n @default(1) @display_name('Use Project Theme') @description(\"Prefer using the project theme for this window, if any. If off, only the user's theme settings will be used.\")\n 'use_project_theme': bool,\n}\n")}, diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 40196307..ff696199 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -320,6 +320,10 @@ RD_VocabTable: //- rjf: symbol server @default(0) @display_name('Auto Download Debug Info') @description("Automatically tries to download missing debug info from symbol server(s).") 'auto_download_debug_info': bool, + + //- rjf: update check + @default(1) @display_name('Check For Updates') @description("Enables a small network request to check if there is a newer release version available.") + 'check_for_updates': bool, } ``` } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index a5c0250e..9fec8814 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -10771,14 +10771,6 @@ rd_init(CmdLine *cmdln) { rd_state->update_check_arena = arena_alloc(); rd_state->update_check_http_ring = guarded_ring_alloc(rd_state->update_check_arena, KB(8)); - HTTP_RequestParams p = - { - .id = 1, - .method = HTTP_Method_Get, - .url = s("https://api.github.com/repos/EpicGamesExt/raddebugger/releases/latest"), - .user_agent = s("raddebugger"), - }; - http_push_request(rd_state->update_check_http_ring, &p, 0); } // rjf: set up schemas @@ -11183,50 +11175,6 @@ rd_frame(void) MemoryZeroStruct(&rd_state->cmd_outputs); } - ////////////////////////////// - //- rjf: check for updates - // - if(!rd_state->got_update_check) - { - // rjf: pop all responses that we can - B32 done = 0; - for(HTTP_Response response = {0}; http_pop_response(rd_state->update_check_arena, rd_state->update_check_http_ring, &response, 0);) - { - str8_list_push(rd_state->update_check_arena, &rd_state->update_check_response_body_pieces, response.body); - if(!response.has_more) - { - done = 1; - } - } - - // rjf: if we're done -> parse response & determine if there is a new version - if(done) - { - rd_state->got_update_check = 1; - Temp scratch = scratch_begin(0, 0); - String8 response_body = str8_list_join(rd_state->update_check_arena, &rd_state->update_check_response_body_pieces, 0); - MD_Node *root = md_tree_from_string(scratch.arena, response_body)->first; - MD_Node *html_url = md_child_from_string(root, s("html_url"), 0); - String8 newest_release_url = html_url->first->string; - U64 tag_pos = str8_find_needle(newest_release_url, 0, s("tag/v"), 0); - String8 tag_name = str8_skip(newest_release_url, tag_pos); - U64 suffix_pos = str8_find_needle(tag_name, 0, s("-"), 0); - String8 version_name = str8_prefix(tag_name, suffix_pos); - U64 release_version = version_from_str8(version_name); - U64 current_version = Version(BUILD_VERSION_MAJOR, BUILD_VERSION_MINOR, BUILD_VERSION_PATCH); - if(current_version < release_version) - { - rd_state->newer_update_available = 1; - } - guarded_ring_release(rd_state->update_check_http_ring); - arena_release(rd_state->update_check_arena); - rd_state->update_check_arena = 0; - rd_state->update_check_http_ring = 0; - MemoryZeroStruct(&rd_state->update_check_response_body_pieces); - scratch_end(scratch); - } - } - ////////////////////////////// //- rjf: iterate all tabs, touch their view-states // @@ -12867,6 +12815,91 @@ rd_frame(void) rd_state->eval_viz_base_string_flags |= EV_StringFlag_DisplayAddressUnmappedStatus; } + //////////////////////////// + //- rjf: send update check if needed + // + if(!rd_state->sent_update_check && !rd_state->got_update_check && rd_setting_b32_from_name(s("check_for_updates"))) + { + rd_state->sent_update_check = 1; + Temp scratch = scratch_begin(0, 0); + String8 cached_version_check_path = str8f(scratch.arena, "%S/raddbg/last_version_check", get_process_info()->user_program_config_data_path); + String8 cached_version_check_data = data_from_file_path(scratch.arena, cached_version_check_path); + MD_Node *root = md_tree_from_string(scratch.arena, cached_version_check_data)->first; + U64 cached_dense_time = u64_from_str8(root->string, 10); + DateTime cached_date_time = date_time_from_dense_time(cached_dense_time); + DateTime now_date_time = now_time_universal(); + B32 should_rerequest = 0; + if(now_date_time.day != cached_date_time.day || + now_date_time.month != cached_date_time.month || + now_date_time.year != cached_date_time.year) + { + should_rerequest = 1; + } + if(should_rerequest) + { + HTTP_RequestParams p = + { + .id = 1, + .method = HTTP_Method_Get, + .url = s("https://api.github.com/repos/EpicGamesExt/raddebugger/releases/latest"), + .user_agent = s("raddebugger"), + }; + http_push_request(rd_state->update_check_http_ring, &p, 0); + } + else + { + rd_state->got_update_check = 1; + rd_state->newer_update_available = (B32)u64_from_str8(root->first->string, 10); + } + scratch_end(scratch); + } + + ////////////////////////////// + //- rjf: check for updates + // + if(rd_state->sent_update_check && !rd_state->got_update_check) + { + // rjf: pop all responses that we can + B32 done = 0; + for(HTTP_Response response = {0}; http_pop_response(rd_state->update_check_arena, rd_state->update_check_http_ring, &response, 0);) + { + str8_list_push(rd_state->update_check_arena, &rd_state->update_check_response_body_pieces, response.body); + if(!response.has_more) + { + done = 1; + } + } + + // rjf: if we're done -> parse response & determine if there is a new version + if(done) + { + rd_state->got_update_check = 1; + Temp scratch = scratch_begin(0, 0); + String8 response_body = str8_list_join(rd_state->update_check_arena, &rd_state->update_check_response_body_pieces, 0); + MD_Node *root = md_tree_from_string(scratch.arena, response_body)->first; + MD_Node *html_url = md_child_from_string(root, s("html_url"), 0); + String8 newest_release_url = html_url->first->string; + U64 tag_pos = str8_find_needle(newest_release_url, 0, s("tag/v"), 0); + String8 tag_name = str8_skip(newest_release_url, tag_pos); + U64 suffix_pos = str8_find_needle(tag_name, 0, s("-"), 0); + String8 version_name = str8_prefix(tag_name, suffix_pos); + U64 release_version = version_from_str8(version_name); + U64 current_version = Version(BUILD_VERSION_MAJOR, BUILD_VERSION_MINOR, BUILD_VERSION_PATCH); + if(current_version < release_version) + { + rd_state->newer_update_available = 1; + } + String8 cached_version_check_path = str8f(scratch.arena, "%S/raddbg/last_version_check", get_process_info()->user_program_config_data_path); + write_data_to_file_path(cached_version_check_path, str8f(scratch.arena, "%I64u: %i", dense_time_from_date_time(now_time_universal()), !!rd_state->newer_update_available)); + guarded_ring_release(rd_state->update_check_http_ring); + arena_release(rd_state->update_check_arena); + rd_state->update_check_arena = 0; + rd_state->update_check_http_ring = 0; + MemoryZeroStruct(&rd_state->update_check_response_body_pieces); + scratch_end(scratch); + } + } + //////////////////////////// //- rjf: autosave if needed // diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 472bcdab..b7994c02 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -391,6 +391,7 @@ struct RD_State U64 frame_eval_memread_endt_us; // rjf: update checker + B32 sent_update_check; B32 got_update_check; B32 newer_update_available; Arena *update_check_arena; diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 41df35d1..1f2d914e 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -12,19 +12,17 @@ //- rjf: [h] #include "base/base_inc.h" -#include "content/content.h" -#include "artifact_cache/artifact_cache.h" -#include "file_stream/file_stream.h" +#include "x64/x64.h" #include "rdi/rdi_local.h" -#include "dbg_info/dbg_info.h" +#include "arch/arch_inc.h" +#include "eval2/eval2.h" //- rjf: [c] #include "base/base_inc.c" -#include "content/content.c" -#include "artifact_cache/artifact_cache.c" -#include "file_stream/file_stream.c" +#include "x64/x64.c" #include "rdi/rdi_local.c" -#include "dbg_info/dbg_info.c" +#include "arch/arch_inc.c" +#include "eval2/eval2.c" //////////////////////////////// //~ rjf: Entry Point @@ -32,53 +30,17 @@ internal void entry_point(CmdLine *cmdline) { - local_persist char *pdb_paths[] = - { - "C:/devel/raddebugger/build/raddbg.pdb", - // #include "fn_debug_infos.inc" - }; - - DI_Key keys[ArrayCount(pdb_paths)] = {0}; - for EachElement(idx, pdb_paths) - { - String8 path = str8_cstring(pdb_paths[idx]); - keys[idx] = di_key_from_path_timestamp(path, 0); - di_open(keys[idx]); - } - + Temp scratch = scratch_begin(0, 0); + E2_ParseState state = {0}; + E2_SpaceMap space_map = {0}; + E2_ExprMap expr_map = {0}; for(;;) { - Access *access = access_open(); - B32 got_all_rdis = 1; - U64 num_rdis_loaded = 0; - for EachElement(idx, pdb_paths) + E2_Parse parse = e2_parse_from_string(scratch.arena, &state, &space_map, &expr_map, s("!123")); + if(parse.status == E2_Status_Good) { - RDI_Parsed *rdi = di_rdi_from_key(access, keys[idx], 1, 0); - if(rdi == &rdi_parsed_nil) - { - got_all_rdis = 0; - } - else - { - num_rdis_loaded += 1; - } - } - printf("\rloaded [%I64u/%I64u], %I64u active threads, %I64u active processes", num_rdis_loaded, ArrayCount(pdb_paths), di_shared->conversion_thread_count, di_shared->conversion_process_count); - access_close(access); - if(got_all_rdis) - { - Access *access = access_open(); - String8 search_query = str8_lit("rd_"); - DI_SearchItemArray items = di_search_item_array_from_target_query(access, RDI_SectionKind_Procedures, search_query, max_U64); - printf("\n"); - printf("fuzzy searched for %.*s, found %I64u items\n", str8_varg(search_query), items.count); - access_close(access); - - String8 match_query = str8_lit("rd_frame"); - DI_Match match = di_match_from_string(match_query, 0, max_U64); - printf("searched for %.*s, found at %i in [%I64x:%I64x]\n", str8_varg(match_query), match.idx, match.key.u64[0], match.key.u64[1]); - break; } } + scratch_end(scratch); }