sketch out stepping/eval exemplar testing; step-to-exit first pass

This commit is contained in:
Ryan Fleury
2026-06-02 12:11:04 -07:00
parent a0bf825169
commit dc61f20e3b
20 changed files with 568 additions and 75 deletions
+1 -1
View File
@@ -41,6 +41,6 @@ target:
{ {
executable: "build/torture.exe" executable: "build/torture.exe"
working_directory: build working_directory: build
arguments: "raddbg/*"
enabled: 1 enabled: 1
arguments: "raddbg/* --gui"
} }
+9 -1
View File
@@ -23,7 +23,7 @@ struct TestResult
char *fail_cond; char *fail_cond;
}; };
#define TEST_FUNCTION_SIG(name) void name(Arena *arena, CmdLine *cmdline, String8 test_artifacts_path, TestResult *result_out, String8List *test_out) #define TEST_FUNCTION_SIG(name) void name(Arena *arena, CmdLine *cmdline, String8 test_exemplars_path, String8 test_artifacts_path, TestResult *result_out, String8List *test_out)
#define TEST_FUNCTION_DEF(name) TEST_FUNCTION_SIG(test__##name) #define TEST_FUNCTION_DEF(name) TEST_FUNCTION_SIG(test__##name)
typedef TEST_FUNCTION_SIG(TestFunctionType); typedef TEST_FUNCTION_SIG(TestFunctionType);
@@ -76,10 +76,18 @@ TEST_FUNCTION_DEF(name)
#define SkippedTest(name) DeclareTest(name, 1)\ #define SkippedTest(name) DeclareTest(name, 1)\
TEST_FUNCTION_DEF(name) TEST_FUNCTION_DEF(name)
#define test_out(string) str8_list_push(arena, test_out, (string))
#define test_outf(...) str8_list_pushf(arena, test_out, __VA_ARGS__)
#define TestCheck(c) do { if (!(c)) {\ #define TestCheck(c) do { if (!(c)) {\
*result_out = (TestResult){ .fail_file = __FILE__, .fail_line = __LINE__, .fail_cond = Stringify(c) };\ *result_out = (TestResult){ .fail_file = __FILE__, .fail_line = __LINE__, .fail_cond = Stringify(c) };\
if(debugger_is_attached()) { Trap(); }\ if(debugger_is_attached()) { Trap(); }\
return;\ return;\
} } while(0) } } while(0)
#define TestSkip() do {\
*result_out = (TestResult){ .status = TestStatus_Skip };\
return;\
} while(0)
#endif // BASE_TEST_H #endif // BASE_TEST_H
+1
View File
@@ -21,6 +21,7 @@ D_CmdTable: // | | | |
{StepIntoLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" } {StepIntoLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" }
{StepOverLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" } {StepOverLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" }
{StepOut 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the first instruction after the current scope is exited." "" "" } {StepOut 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the first instruction after the current scope is exited." "" "" }
{StepToExit 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOut "step_to_exit" "Step To Exit" "Runs to the first encountered instruction which will exit the current scope." "" "" }
{Halt 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" } {Halt 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" }
{SoftHaltRefresh 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" } {SoftHaltRefresh 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" }
{SetThreadIP 0 1 0 0 "" Vaddr null Nil Null 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" } {SetThreadIP 0 1 0 0 "" Vaddr null Nil Null 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" }
+111 -1
View File
@@ -447,6 +447,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, D_Entity *thread)
DASM_InstFlag_UnconditionalJump| DASM_InstFlag_UnconditionalJump|
DASM_InstFlag_ChangesStackPointer| DASM_InstFlag_ChangesStackPointer|
DASM_InstFlag_Return, DASM_InstFlag_Return,
0,
arch, arch,
line_vaddr_rng.min, line_vaddr_rng.min,
machine_code); machine_code);
@@ -641,6 +642,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, D_Entity *thread)
DASM_InstFlag_UnconditionalJump| DASM_InstFlag_UnconditionalJump|
DASM_InstFlag_ChangesStackPointer| DASM_InstFlag_ChangesStackPointer|
DASM_InstFlag_Return, DASM_InstFlag_Return,
0,
arch, arch,
line_vaddr_rng.min, line_vaddr_rng.min,
machine_code); machine_code);
@@ -807,7 +809,7 @@ d_trap_net_from_thread__step_out_scope(Arena *arena, D_Entity *thread)
{ {
result.good_read = 1; result.good_read = 1;
String8 code = code_slice.data; String8 code = code_slice.data;
DASM_CtrlFlowInfo ctrl_flow_info = dasm_ctrl_flow_info_from_arch_vaddr_code(scratch.arena, DASM_InstFlag_Branch|DASM_InstFlag_UnconditionalJump|DASM_InstFlag_Return, arch, vaddr_range.min, code); DASM_CtrlFlowInfo ctrl_flow_info = dasm_ctrl_flow_info_from_arch_vaddr_code(scratch.arena, DASM_InstFlag_Branch|DASM_InstFlag_UnconditionalJump|DASM_InstFlag_Return, 0, arch, vaddr_range.min, code);
// rjf: add traps at all jump destinations which do *not* fall into any of the scope's ranges // rjf: add traps at all jump destinations which do *not* fall into any of the scope's ranges
for EachNode(exit_pt_n, DASM_CtrlFlowPointNode, ctrl_flow_info.exit_points.first) for EachNode(exit_pt_n, DASM_CtrlFlowPointNode, ctrl_flow_info.exit_points.first)
@@ -878,6 +880,105 @@ d_trap_net_from_thread__step_out_scope(Arena *arena, D_Entity *thread)
return result; return result;
} }
internal D_TrapNet
d_trap_net_from_thread__step_to_exit(Arena *arena, D_Entity *thread)
{
D_TrapNet result = {0};
{
U64 read_endt_us = now_time_us() + 1000000;
Temp scratch = scratch_begin(&arena, 1);
Access *access = access_open();
// rjf: unpack thread
Arch arch = thread->arch;
U64 ip_vaddr = d_cached_ip_from_thread(thread->handle);
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
D_Entity *module = d_module_from_process_vaddr(process, ip_vaddr);
DI_Key dbgi_key = d_dbgi_key_from_module(module);
D_CallStack callstack = d_call_stack_from_thread(access, thread->handle, 1, read_endt_us);
// rjf: ip => enclosing scope's list(voff_range)
Rng1U64List scope_voff_rngs = {0};
{
U64 ip_voff = d_voff_from_vaddr(module, ip_vaddr);
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, 0);
if(rdi != &rdi_parsed_nil)
{
RDI_Scope *scope = rdi_scope_from_voff(rdi, ip_voff);
U64 all_scope_voffs_count = 0;
U64 *all_scope_voffs = rdi_table_from_name(rdi, ScopeVOffData, &all_scope_voffs_count);
for(U64 voff_idx = scope->voff_range_first; voff_idx+1 < scope->voff_range_opl; voff_idx += 1)
{
Rng1U64 voff_range = r1u64(all_scope_voffs[voff_idx], all_scope_voffs[voff_idx+1]);
rng1u64_list_push(scratch.arena, &scope_voff_rngs, voff_range);
}
}
}
// rjf: place traps at all possible exit points of all scope's ranges
result.good_read = 1;
for EachNode(n, Rng1U64Node, scope_voff_rngs.first)
{
Rng1U64 voff_range = n->v;
Rng1U64 vaddr_range = d_vaddr_range_from_voff_range(module, voff_range);
D_ProcessMemorySlice code_slice = d_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, vaddr_range, 0, read_endt_us);
if(!code_slice.any_byte_bad)
{
result.good_read = 1;
String8 code = code_slice.data;
DASM_CtrlFlowInfo ctrl_flow_info = dasm_ctrl_flow_info_from_arch_vaddr_code(scratch.arena, DASM_InstFlag_Branch|DASM_InstFlag_UnconditionalJump|DASM_InstFlag_Return, 1, arch, vaddr_range.min, code);
// rjf: add traps at all jumps whose destinations do *not* fall into any of the scope's ranges
for EachNode(exit_pt_n, DASM_CtrlFlowPointNode, ctrl_flow_info.exit_points.first)
{
U64 jump_vaddr = exit_pt_n->v.vaddr;
U64 jump_dest_vaddr = exit_pt_n->v.jump_dest_vaddr;
B32 jump_dest_vaddr_is_out_of_scope = 1;
for EachNode(scope_n, Rng1U64Node, scope_voff_rngs.first)
{
if(contains_1u64(scope_n->v, d_voff_from_vaddr(module, jump_dest_vaddr)))
{
jump_dest_vaddr_is_out_of_scope = 0;
break;
}
}
if(jump_dest_vaddr_is_out_of_scope)
{
D_Trap trap = {D_TrapFlag_EndStepping|D_TrapFlag_IgnoreStackPointerCheck, jump_vaddr};
d_trap_list_push(arena, &result.traps, &trap);
}
}
}
else
{
result.good_read = 0;
break;
}
}
// rjf: use first unwind frame to generate trap
if(result.good_read && callstack.concrete_frames_count > 1)
{
ARCH_Info *arch_info = arch_info_from_arch(thread->arch);
U64 vaddr = arch_ip_from_reg_block(arch_info, callstack.concrete_frames[1]->regs);
D_Trap trap = {D_TrapFlag_EndStepping|D_TrapFlag_IgnoreStackPointerCheck, vaddr};
d_trap_list_push(arena, &result.traps, &trap);
}
else
{
result.good_read = 0;
}
// NOTE(rjf): we always want to support missing line info for "step to exit", because
// we should always be able to fall back to just using the unwind, so just always
// mark this bit as a success.
result.good_line_info = 1;
access_close(access);
scratch_end(scratch);
}
return result;
}
//////////////////////////////// ////////////////////////////////
//~ rjf: Debug Info Lookups //~ rjf: Debug Info Lookups
@@ -1315,6 +1416,12 @@ d_ctrl_targets_running(void)
return d_user_state->ctrl_is_running; return d_user_state->ctrl_is_running;
} }
internal U64
d_stop_count(void)
{
return d_user_state->stop_count;
}
//- rjf: active entity based queries //- rjf: active entity based queries
internal DI_KeyList internal DI_KeyList
@@ -1610,6 +1717,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
case D_EventKind_Stopped: case D_EventKind_Stopped:
{ {
d_user_state->stop_count += 1;
d_user_state->ctrl_is_running = 0; d_user_state->ctrl_is_running = 0;
d_user_state->ctrl_thread_run_state = 0; d_user_state->ctrl_thread_run_state = 0;
d_user_state->ctrl_soft_halt_issued = 0; d_user_state->ctrl_soft_halt_issued = 0;
@@ -1903,6 +2011,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
case D_CmdKind_StepIntoLine: case D_CmdKind_StepIntoLine:
case D_CmdKind_StepOverLine: case D_CmdKind_StepOverLine:
case D_CmdKind_StepOut: case D_CmdKind_StepOut:
case D_CmdKind_StepToExit:
{ {
D_Entity *thread = d_entity_from_handle(params->thread); D_Entity *thread = d_entity_from_handle(params->thread);
if(thread == &d_entity_nil) if(thread == &d_entity_nil)
@@ -1931,6 +2040,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
case D_CmdKind_StepIntoLine: {trap_net = d_trap_net_from_thread__step_into_line(scratch.arena, thread);}break; case D_CmdKind_StepIntoLine: {trap_net = d_trap_net_from_thread__step_into_line(scratch.arena, thread);}break;
case D_CmdKind_StepOverLine: {trap_net = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break; case D_CmdKind_StepOverLine: {trap_net = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break;
case D_CmdKind_StepOut: {trap_net = d_trap_net_from_thread__step_out_scope(scratch.arena, thread);}break; case D_CmdKind_StepOut: {trap_net = d_trap_net_from_thread__step_out_scope(scratch.arena, thread);}break;
case D_CmdKind_StepToExit: {trap_net = d_trap_net_from_thread__step_to_exit(scratch.arena, thread);}break;
} }
B32 good_trap_net = (trap_net.good_read || !trap_net.good_line_info); B32 good_trap_net = (trap_net.good_read || !trap_net.good_line_info);
if(good_trap_net && trap_net.traps.count != 0) if(good_trap_net && trap_net.traps.count != 0)
+3
View File
@@ -378,6 +378,7 @@ struct D_UserState
D_EntityCtxRWStore *ctrl_entity_store; D_EntityCtxRWStore *ctrl_entity_store;
Arena *ctrl_stop_arena; Arena *ctrl_stop_arena;
D_Event ctrl_last_stop_event; D_Event ctrl_last_stop_event;
U64 stop_count;
}; };
//////////////////////////////// ////////////////////////////////
@@ -424,6 +425,7 @@ internal D_TrapNet d_trap_net_from_thread__step_over_inst(Arena *arena, D_Entity
internal D_TrapNet d_trap_net_from_thread__step_over_line(Arena *arena, D_Entity *thread); internal D_TrapNet d_trap_net_from_thread__step_over_line(Arena *arena, D_Entity *thread);
internal D_TrapNet d_trap_net_from_thread__step_into_line(Arena *arena, D_Entity *thread); internal D_TrapNet d_trap_net_from_thread__step_into_line(Arena *arena, D_Entity *thread);
internal D_TrapNet d_trap_net_from_thread__step_out_scope(Arena *arena, D_Entity *thread); internal D_TrapNet d_trap_net_from_thread__step_out_scope(Arena *arena, D_Entity *thread);
internal D_TrapNet d_trap_net_from_thread__step_to_exit(Arena *arena, D_Entity *thread);
//////////////////////////////// ////////////////////////////////
//~ rjf: Debug Info Lookups //~ rjf: Debug Info Lookups
@@ -460,6 +462,7 @@ internal U64 d_frame_index(void);
internal D_RunKind d_ctrl_last_run_kind(void); internal D_RunKind d_ctrl_last_run_kind(void);
internal U64 d_ctrl_last_run_frame_idx(void); internal U64 d_ctrl_last_run_frame_idx(void);
internal B32 d_ctrl_targets_running(void); internal B32 d_ctrl_targets_running(void);
internal U64 d_stop_count(void);
//- rjf: active entity based queries //- rjf: active entity based queries
internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena); internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena);
@@ -20,6 +20,7 @@ D_CmdKind_StepOverInst,
D_CmdKind_StepIntoLine, D_CmdKind_StepIntoLine,
D_CmdKind_StepOverLine, D_CmdKind_StepOverLine,
D_CmdKind_StepOut, D_CmdKind_StepOut,
D_CmdKind_StepToExit,
D_CmdKind_Halt, D_CmdKind_Halt,
D_CmdKind_SoftHaltRefresh, D_CmdKind_SoftHaltRefresh,
D_CmdKind_SetThreadIP, D_CmdKind_SetThreadIP,
+2 -2
View File
@@ -28,7 +28,7 @@ dasm_inst_from_code(Arena *arena, Arch arch, U64 vaddr, String8 code, DASM_Synta
//~ rjf: Control Flow Analysis //~ rjf: Control Flow Analysis
internal DASM_CtrlFlowInfo internal DASM_CtrlFlowInfo
dasm_ctrl_flow_info_from_arch_vaddr_code(Arena *arena, DASM_InstFlags exit_points_mask, Arch arch, U64 vaddr, String8 code) dasm_ctrl_flow_info_from_arch_vaddr_code(Arena *arena, DASM_InstFlags exit_points_mask, B32 include_last_inst, Arch arch, U64 vaddr, String8 code)
{ {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
DASM_CtrlFlowInfo info = {0}; DASM_CtrlFlowInfo info = {0};
@@ -38,7 +38,7 @@ dasm_ctrl_flow_info_from_arch_vaddr_code(Arena *arena, DASM_InstFlags exit_point
U64 inst_vaddr = vaddr+offset; U64 inst_vaddr = vaddr+offset;
offset += inst.size; offset += inst.size;
info.total_size += inst.size; info.total_size += inst.size;
if(inst.flags & exit_points_mask) if(inst.flags & exit_points_mask || (include_last_inst && offset >= code.size))
{ {
DASM_CtrlFlowPoint point = {0}; DASM_CtrlFlowPoint point = {0};
point.inst_flags = inst.flags; point.inst_flags = inst.flags;
+1 -1
View File
@@ -183,7 +183,7 @@ internal DASM_Inst dasm_inst_from_code(Arena *arena, Arch arch, U64 vaddr, Strin
//////////////////////////////// ////////////////////////////////
//~ rjf: Control Flow Analysis //~ rjf: Control Flow Analysis
internal DASM_CtrlFlowInfo dasm_ctrl_flow_info_from_arch_vaddr_code(Arena *arena, DASM_InstFlags exit_points_mask, Arch arch, U64 vaddr, String8 code); internal DASM_CtrlFlowInfo dasm_ctrl_flow_info_from_arch_vaddr_code(Arena *arena, DASM_InstFlags exit_points_mask, B32 include_last_inst, Arch arch, U64 vaddr, String8 code);
//////////////////////////////// ////////////////////////////////
//~ rjf: Parameter Type Functions //~ rjf: Parameter Type Functions
+104
View File
@@ -1205,6 +1205,110 @@ md_debug_string_list_from_tree(Arena *arena, MD_Node *root)
return strings; return strings;
} }
internal String8List
md_string_list_from_tree(Arena *arena, MD_Node *root)
{
String8List strings = {0};
{
char *indentation = " ";
S32 depth = 0;
B32 delimit_with_newlines = 1;
for(MD_Node *node = root, *next = &md_nil_node; !md_node_is_nil(node); node = next)
{
Temp scratch = scratch_begin(&arena, 1);
// rjf: get next recursion
MD_NodeRec rec = md_node_rec_depth_first_pre(node, root);
next = rec.next;
// rjf: sanitize string
String8 node_string_sanitized = node->string;
{
MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, node_string_sanitized);
B32 is_simple_string = (tokenize.tokens.count == 1 && (tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier|
MD_TokenFlag_Numeric)));
if(tokenize.tokens.count > 0 && !is_simple_string)
{
node_string_sanitized = str8f(scratch.arena, "\"%S\"", escaped_from_raw_str8(scratch.arena, node_string_sanitized));
}
if(node_string_sanitized.size == 0 && node->first == &md_nil_node)
{
node_string_sanitized = s("\"\"");
}
}
// rjf: turn off newline delimiting for implicit child sets
B32 next_delimit_with_newlines = delimit_with_newlines;
if(node->first != &md_nil_node && !(node->flags & (MD_NodeFlag_HasParenLeft|MD_NodeFlag_HasBracketLeft|MD_NodeFlag_HasBraceLeft)))
{
next_delimit_with_newlines = 0;
}
// rjf: push node line
if(node_string_sanitized.size != 0)
{
str8_list_pushf(arena, &strings, "%.*s%S%S%S", delimit_with_newlines ? depth : 1, indentation, node_string_sanitized,
(rec.push_count != 0 && node_string_sanitized.size != 0) ? s(":") : s(""),
next_delimit_with_newlines ? s("\n") : s(""));
}
// rjf: children -> open brace
if(rec.push_count != 0)
{
String8 opener_symbol = s("");
if(node->flags & MD_NodeFlag_HasParenLeft) { opener_symbol = s("("); }
if(node->flags & MD_NodeFlag_HasBracketLeft) { opener_symbol = s("["); }
if(node->flags & MD_NodeFlag_HasBraceLeft) { opener_symbol = s("{"); }
if(opener_symbol.size != 0)
{
str8_list_pushf(arena, &strings, "%.*s%S\n", depth, indentation, opener_symbol);
}
}
// rjf: descend
depth += rec.push_count;
delimit_with_newlines = next_delimit_with_newlines;
// rjf: popping -> close braces
{
MD_Node *popped = node->parent;
for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1, popped = popped->parent)
{
String8 closer_symbol = s("");
if(popped->flags & MD_NodeFlag_HasParenRight) { closer_symbol = s(")"); }
if(popped->flags & MD_NodeFlag_HasBracketRight) { closer_symbol = s("]"); }
if(popped->flags & MD_NodeFlag_HasBraceRight) { closer_symbol = s("}"); }
if(!delimit_with_newlines)
{
str8_list_push(arena, &strings, s("\n"));
delimit_with_newlines = 1;
}
else if(closer_symbol.size != 0)
{
str8_list_pushf(arena, &strings, "%.*s%S\n", (depth-1-pop_idx), indentation, closer_symbol);
}
}
}
// rjf: ascend
depth -= rec.pop_count;
scratch_end(scratch);
}
}
return strings;
}
internal String8
md_string_from_tree(Arena *arena, MD_Node *root)
{
Temp scratch = scratch_begin(&arena, 1);
String8List strings = md_string_list_from_tree(scratch.arena, root);
String8 string = str8_list_join(arena, &strings, 0);
scratch_end(scratch);
return string;
}
//////////////////////////////// ////////////////////////////////
//~ rjf: Node Pointer List Functions //~ rjf: Node Pointer List Functions
+2
View File
@@ -336,6 +336,8 @@ internal MD_ParseResult md_parse_from_text(Arena *arena, String8 filename, Strin
//~ rjf: Tree -> Text Functions //~ rjf: Tree -> Text Functions
internal String8List md_debug_string_list_from_tree(Arena *arena, MD_Node *root); internal String8List md_debug_string_list_from_tree(Arena *arena, MD_Node *root);
internal String8List md_string_list_from_tree(Arena *arena, MD_Node *root);
internal String8 md_string_from_tree(Arena *arena, MD_Node *root);
//////////////////////////////// ////////////////////////////////
//~ rjf: Node Pointer List Functions //~ rjf: Node Pointer List Functions
+6 -6
View File
@@ -700,12 +700,14 @@ type_coverage_eval_tests(void)
int_vector.push_back(6); int_vector.push_back(6);
int_vector.push_back(7); int_vector.push_back(7);
#if 0
std::unordered_map<std::string, int> people = std::unordered_map<std::string, int> people =
{ {
{"Peter", 1}, {"Peter", 1},
{"Oliver", 2}, {"Oliver", 2},
{"Jack", 3}, {"Jack", 3},
}; };
#endif
std::vector<int> *pint_vector = &int_vector; std::vector<int> *pint_vector = &int_vector;
std::vector<int> &rint_vector = int_vector; std::vector<int> &rint_vector = int_vector;
@@ -718,9 +720,9 @@ type_coverage_eval_tests(void)
SizedKind sized_kind = SizedKind_C; SizedKind sized_kind = SizedKind_C;
variadic_params("foo", 123, 456);
int x = (int)(Anonymous_D); int x = (int)(Anonymous_D);
variadic_params("foo", 123, 456);
} }
//////////////////////////////// ////////////////////////////////
@@ -3198,7 +3200,6 @@ mule_main(int argc, char** argv)
mule_init(); mule_init();
// NOTE(allen): Eval Tests
type_coverage_eval_tests(); type_coverage_eval_tests();
mutating_variables_eval_tests(); mutating_variables_eval_tests();
@@ -3231,9 +3232,6 @@ mule_main(int argc, char** argv)
exception_filter_test(); exception_filter_test();
markup_tests();
// NOTE(allen): Stepping Tests
control_flow_stepping_tests(); control_flow_stepping_tests();
indirect_call_jump_stepping_tests(); indirect_call_jump_stepping_tests();
@@ -3264,6 +3262,8 @@ mule_main(int argc, char** argv)
interrupt_stepping_tests(); interrupt_stepping_tests();
markup_tests();
exception_stepping_tests(); exception_stepping_tests();
return(0); return(0);
+8 -4
View File
@@ -62,7 +62,7 @@ str8_lit_comp(""),
str8_lit_comp(""), str8_lit_comp(""),
}; };
RD_VocabInfo rd_vocab_info_table[364] = RD_VocabInfo rd_vocab_info_table[365] =
{ {
{str8_lit_comp("type_view"), str8_lit_comp("type_views"), str8_lit_comp("Type View"), str8_lit_comp("Type Views"), RD_IconKind_Binoculars}, {str8_lit_comp("type_view"), str8_lit_comp("type_views"), str8_lit_comp("Type View"), str8_lit_comp("Type Views"), RD_IconKind_Binoculars},
{str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline}, {str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline},
@@ -188,6 +188,7 @@ RD_VocabInfo rd_vocab_info_table[364] =
{str8_lit_comp("step_into_line"), str8_lit_comp(""), str8_lit_comp("Step Into (Line)"), str8_lit_comp(""), RD_IconKind_StepInto}, {str8_lit_comp("step_into_line"), str8_lit_comp(""), str8_lit_comp("Step Into (Line)"), str8_lit_comp(""), RD_IconKind_StepInto},
{str8_lit_comp("step_over_line"), str8_lit_comp(""), str8_lit_comp("Step Over (Line)"), str8_lit_comp(""), RD_IconKind_StepOver}, {str8_lit_comp("step_over_line"), str8_lit_comp(""), str8_lit_comp("Step Over (Line)"), str8_lit_comp(""), RD_IconKind_StepOver},
{str8_lit_comp("step_out"), str8_lit_comp(""), str8_lit_comp("Step Out"), str8_lit_comp(""), RD_IconKind_StepOut}, {str8_lit_comp("step_out"), str8_lit_comp(""), str8_lit_comp("Step Out"), str8_lit_comp(""), RD_IconKind_StepOut},
{str8_lit_comp("step_to_exit"), str8_lit_comp(""), str8_lit_comp("Step To Exit"), str8_lit_comp(""), RD_IconKind_StepOut},
{str8_lit_comp("halt"), str8_lit_comp(""), str8_lit_comp("Halt"), str8_lit_comp(""), RD_IconKind_Pause}, {str8_lit_comp("halt"), str8_lit_comp(""), str8_lit_comp("Halt"), str8_lit_comp(""), RD_IconKind_Pause},
{str8_lit_comp("soft_halt_refresh"), str8_lit_comp(""), str8_lit_comp("Soft Halt Refresh"), str8_lit_comp(""), RD_IconKind_Refresh}, {str8_lit_comp("soft_halt_refresh"), str8_lit_comp(""), str8_lit_comp("Soft Halt Refresh"), str8_lit_comp(""), RD_IconKind_Refresh},
{str8_lit_comp("set_thread_ip"), str8_lit_comp(""), str8_lit_comp("Set Thread IP"), str8_lit_comp(""), RD_IconKind_Null}, {str8_lit_comp("set_thread_ip"), str8_lit_comp(""), str8_lit_comp("Set Thread IP"), str8_lit_comp(""), RD_IconKind_Null},
@@ -473,7 +474,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[39] =
{str8_lit_comp("thread"), 0, str8_lit_comp("x:{'label':code_string, 'id':u64, @no_expand 'active':bool, 'call_stack':set}")}, {str8_lit_comp("thread"), 0, str8_lit_comp("x:{'label':code_string, 'id':u64, @no_expand 'active':bool, 'call_stack':set}")},
}; };
String8 rd_reg_slot_code_name_table[49] = String8 rd_reg_slot_code_name_table[50] =
{ {
{0}, {0},
str8_lit_comp("machine"), str8_lit_comp("machine"),
@@ -520,13 +521,14 @@ str8_lit_comp("all_windows"),
str8_lit_comp("non_graphical"), str8_lit_comp("non_graphical"),
str8_lit_comp("prefer_new_tab"), str8_lit_comp("prefer_new_tab"),
str8_lit_comp("activate_with_single_click"), str8_lit_comp("activate_with_single_click"),
str8_lit_comp("disable_addresses"),
str8_lit_comp("dir2"), str8_lit_comp("dir2"),
str8_lit_comp("string"), str8_lit_comp("string"),
str8_lit_comp("cmd_name"), str8_lit_comp("cmd_name"),
str8_lit_comp("wm_event"), str8_lit_comp("wm_event"),
}; };
Rng1U64 rd_reg_slot_range_table[49] = Rng1U64 rd_reg_slot_range_table[50] =
{ {
{0}, {0},
{OffsetOf(RD_Regs, machine), OffsetOf(RD_Regs, machine) + sizeof(D_Handle)}, {OffsetOf(RD_Regs, machine), OffsetOf(RD_Regs, machine) + sizeof(D_Handle)},
@@ -573,13 +575,14 @@ Rng1U64 rd_reg_slot_range_table[49] =
{OffsetOf(RD_Regs, non_graphical), OffsetOf(RD_Regs, non_graphical) + sizeof(B32)}, {OffsetOf(RD_Regs, non_graphical), OffsetOf(RD_Regs, non_graphical) + sizeof(B32)},
{OffsetOf(RD_Regs, prefer_new_tab), OffsetOf(RD_Regs, prefer_new_tab) + sizeof(B32)}, {OffsetOf(RD_Regs, prefer_new_tab), OffsetOf(RD_Regs, prefer_new_tab) + sizeof(B32)},
{OffsetOf(RD_Regs, activate_with_single_click), OffsetOf(RD_Regs, activate_with_single_click) + sizeof(B32)}, {OffsetOf(RD_Regs, activate_with_single_click), OffsetOf(RD_Regs, activate_with_single_click) + sizeof(B32)},
{OffsetOf(RD_Regs, disable_addresses), OffsetOf(RD_Regs, disable_addresses) + sizeof(B32)},
{OffsetOf(RD_Regs, dir2), OffsetOf(RD_Regs, dir2) + sizeof(Dir2)}, {OffsetOf(RD_Regs, dir2), OffsetOf(RD_Regs, dir2) + sizeof(Dir2)},
{OffsetOf(RD_Regs, string), OffsetOf(RD_Regs, string) + sizeof(String8)}, {OffsetOf(RD_Regs, string), OffsetOf(RD_Regs, string) + sizeof(String8)},
{OffsetOf(RD_Regs, cmd_name), OffsetOf(RD_Regs, cmd_name) + sizeof(String8)}, {OffsetOf(RD_Regs, cmd_name), OffsetOf(RD_Regs, cmd_name) + sizeof(String8)},
{OffsetOf(RD_Regs, wm_event), OffsetOf(RD_Regs, wm_event) + sizeof(WM_Event *)}, {OffsetOf(RD_Regs, wm_event), OffsetOf(RD_Regs, wm_event) + sizeof(WM_Event *)},
}; };
RD_CmdKindInfo rd_cmd_kind_info_table[252] = RD_CmdKindInfo rd_cmd_kind_info_table[253] =
{ {
{0}, {0},
{ str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets"), str8_lit_comp(""), D_EntityKind_Null}}, { str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets"), str8_lit_comp(""), D_EntityKind_Null}},
@@ -593,6 +596,7 @@ RD_CmdKindInfo rd_cmd_kind_info_table[252] =
{ str8_lit_comp("step_into_line"), str8_lit_comp("Performs a step that goes into calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}}, { str8_lit_comp("step_into_line"), str8_lit_comp("Performs a step that goes into calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}},
{ str8_lit_comp("step_over_line"), str8_lit_comp("Performs a step that skips calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}}, { str8_lit_comp("step_over_line"), str8_lit_comp("Performs a step that skips calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}},
{ str8_lit_comp("step_out"), str8_lit_comp("Runs to the first instruction after the current scope is exited."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}}, { str8_lit_comp("step_out"), str8_lit_comp("Runs to the first instruction after the current scope is exited."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}},
{ str8_lit_comp("step_to_exit"), str8_lit_comp("Runs to the first encountered instruction which will exit the current scope."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}},
{ str8_lit_comp("halt"), str8_lit_comp("Halts all attached processes."), str8_lit_comp("pause"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}}, { str8_lit_comp("halt"), str8_lit_comp("Halts all attached processes."), str8_lit_comp("pause"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}},
{ str8_lit_comp("soft_halt_refresh"), str8_lit_comp("Interrupts all attached processes to collect data, and then resumes them."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}}, { str8_lit_comp("soft_halt_refresh"), str8_lit_comp("Interrupts all attached processes to collect data, and then resumes them."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}},
{ str8_lit_comp("set_thread_ip"), str8_lit_comp("Sets the specified thread's instruction pointer at the specified address."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}}, { str8_lit_comp("set_thread_ip"), str8_lit_comp("Sets the specified thread's instruction pointer at the specified address."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp(""), str8_lit_comp(""), D_EntityKind_Null}},
+7 -3
View File
@@ -53,6 +53,7 @@ RD_RegSlot_AllWindows,
RD_RegSlot_NonGraphical, RD_RegSlot_NonGraphical,
RD_RegSlot_PreferNewTab, RD_RegSlot_PreferNewTab,
RD_RegSlot_ActivateWithSingleClick, RD_RegSlot_ActivateWithSingleClick,
RD_RegSlot_DisableAddresses,
RD_RegSlot_Dir2, RD_RegSlot_Dir2,
RD_RegSlot_String, RD_RegSlot_String,
RD_RegSlot_CmdName, RD_RegSlot_CmdName,
@@ -74,6 +75,7 @@ RD_CmdKind_StepOverInst,
RD_CmdKind_StepIntoLine, RD_CmdKind_StepIntoLine,
RD_CmdKind_StepOverLine, RD_CmdKind_StepOverLine,
RD_CmdKind_StepOut, RD_CmdKind_StepOut,
RD_CmdKind_StepToExit,
RD_CmdKind_Halt, RD_CmdKind_Halt,
RD_CmdKind_SoftHaltRefresh, RD_CmdKind_SoftHaltRefresh,
RD_CmdKind_SetThreadIP, RD_CmdKind_SetThreadIP,
@@ -498,6 +500,7 @@ B32 all_windows;
B32 non_graphical; B32 non_graphical;
B32 prefer_new_tab; B32 prefer_new_tab;
B32 activate_with_single_click; B32 activate_with_single_click;
B32 disable_addresses;
Dir2 dir2; Dir2 dir2;
String8 string; String8 string;
String8 cmd_name; String8 cmd_name;
@@ -598,6 +601,7 @@ Z(getting_started)\
.non_graphical = rd_regs()->non_graphical,\ .non_graphical = rd_regs()->non_graphical,\
.prefer_new_tab = rd_regs()->prefer_new_tab,\ .prefer_new_tab = rd_regs()->prefer_new_tab,\
.activate_with_single_click = rd_regs()->activate_with_single_click,\ .activate_with_single_click = rd_regs()->activate_with_single_click,\
.disable_addresses = rd_regs()->disable_addresses,\
.dir2 = rd_regs()->dir2,\ .dir2 = rd_regs()->dir2,\
.string = rd_regs()->string,\ .string = rd_regs()->string,\
.cmd_name = rd_regs()->cmd_name,\ .cmd_name = rd_regs()->cmd_name,\
@@ -606,10 +610,10 @@ Z(getting_started)\
C_LINKAGE_BEGIN C_LINKAGE_BEGIN
extern String8 rd_tab_fast_path_view_name_table[25]; extern String8 rd_tab_fast_path_view_name_table[25];
extern String8 rd_tab_fast_path_query_name_table[25]; extern String8 rd_tab_fast_path_query_name_table[25];
extern RD_VocabInfo rd_vocab_info_table[364]; extern RD_VocabInfo rd_vocab_info_table[365];
extern RD_NameSchemaInfo rd_name_schema_info_table[39]; extern RD_NameSchemaInfo rd_name_schema_info_table[39];
extern String8 rd_reg_slot_code_name_table[49]; extern String8 rd_reg_slot_code_name_table[50];
extern Rng1U64 rd_reg_slot_range_table[49]; extern Rng1U64 rd_reg_slot_range_table[50];
extern String8 rd_binding_version_remap_old_name_table[9]; extern String8 rd_binding_version_remap_old_name_table[9];
extern String8 rd_binding_version_remap_new_name_table[9]; extern String8 rd_binding_version_remap_new_name_table[9];
extern String8 rd_icon_kind_text_table[75]; extern String8 rd_icon_kind_text_table[75];
+1
View File
@@ -891,6 +891,7 @@ RD_RegTable:
{B32 non_graphical NonGraphical } {B32 non_graphical NonGraphical }
{B32 prefer_new_tab PreferNewTab } {B32 prefer_new_tab PreferNewTab }
{B32 activate_with_single_click ActivateWithSingleClick } {B32 activate_with_single_click ActivateWithSingleClick }
{B32 disable_addresses DisableAddresses }
{Dir2 dir2 Dir2 } {Dir2 dir2 Dir2 }
{String8 string String } {String8 string String }
{String8 cmd_name CmdName } {String8 cmd_name CmdName }
+57 -10
View File
@@ -10302,6 +10302,7 @@ rd_init(CmdLine *cmdln)
rd_state->arena = arena; rd_state->arena = arena;
rd_state->quit_after_success = (cmd_line_has_flag(cmdln, str8_lit("quit_after_success")) || rd_state->quit_after_success = (cmd_line_has_flag(cmdln, str8_lit("quit_after_success")) ||
cmd_line_has_flag(cmdln, str8_lit("q"))); cmd_line_has_flag(cmdln, str8_lit("q")));
rd_state->override_focus_on_stop = (cmd_line_has_flag(cmdln, s("no_focus_on_stop")));
rd_state->user_path_arena = arena_alloc(); rd_state->user_path_arena = arena_alloc();
rd_state->project_path_arena = arena_alloc(); rd_state->project_path_arena = arena_alloc();
rd_state->theme_path_arena = arena_alloc(); rd_state->theme_path_arena = arena_alloc();
@@ -12584,6 +12585,7 @@ rd_frame(void)
{ {
String8 msg = rd_regs()->string; String8 msg = rd_regs()->string;
String8List msg_parts = str8_split(scratch.arena, msg, (U8 *)" ", 1, 0); String8List msg_parts = str8_split(scratch.arena, msg, (U8 *)" ", 1, 0);
str8_list_push_front(scratch.arena, &msg_parts, s("ipc_command"));
CmdLine msg_cmd_line = cmd_line_from_string_list(scratch.arena, msg_parts); CmdLine msg_cmd_line = cmd_line_from_string_list(scratch.arena, msg_parts);
String8 cmd_kind_name = str8_list_first(&msg_cmd_line.inputs); String8 cmd_kind_name = str8_list_first(&msg_cmd_line.inputs);
RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_kind_name); RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_kind_name);
@@ -12609,8 +12611,8 @@ rd_frame(void)
primary_args_string = str8_list_join(scratch.arena, &primary_args_strings, &(StringJoin){.sep = str8_lit(" ")}); primary_args_string = str8_list_join(scratch.arena, &primary_args_strings, &(StringJoin){.sep = str8_lit(" ")});
} }
rd_regs_fill_slot_from_string(cmd_kind_info->query.slot, cmd_kind_info->query.expr, primary_args_string); rd_regs_fill_slot_from_string(cmd_kind_info->query.slot, cmd_kind_info->query.expr, primary_args_string);
rd_regs()->disable_addresses = 1;
rd_push_cmd(cmd_kind_name, rd_regs()); rd_push_cmd(cmd_kind_name, rd_regs());
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, "ack:{cmd:%S}\n", cmd_kind_name);
} }
else else
{ {
@@ -12622,15 +12624,32 @@ rd_frame(void)
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, "state:\n{\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, "state:\n{\n");
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " running: %i\n", d_ctrl_targets_running()); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " running: %i\n", d_ctrl_targets_running());
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " run_gen: %I64u\n", d_run_gen()); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " run_gen: %I64u\n", d_run_gen());
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " ip: 0x%I64x\n", d_ctrl_last_stop_event().rip_vaddr); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " stop_count: %I64u\n", d_stop_count());
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " ip: 0x%I64x\n", d_ctrl_last_stop_event().rip_vaddr);
{
Access *access = access_open();
D_Event evt = d_ctrl_last_stop_event();
U64 vaddr = evt.rip_vaddr;
D_Entity *thread = d_entity_from_handle(rd_base_regs()->thread);
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
D_Entity *module = d_module_from_process_vaddr(process, vaddr);
U64 voff = d_voff_from_vaddr(module, vaddr);
DI_Key dbgi_key = d_dbgi_key_from_module(module);
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0);
RDI_Symbol *procedure = rdi_procedure_from_voff(rdi, voff);
String8 name = fully_qualified_str8_from_rdi_symbol(scratch.arena, rdi, procedure);
name = escaped_from_raw_str8(scratch.arena, name);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " ip_voff: 0x%I64x\n", voff);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " ip_voff_symbol: \"%S\"\n", name);
access_close(access);
}
{ {
D_Event evt = d_ctrl_last_stop_event(); D_Event evt = d_ctrl_last_stop_event();
DR_FStrList explanation_fstrs = rd_stop_explanation_fstrs_from_ctrl_event(scratch.arena, &evt); DR_FStrList explanation_fstrs = rd_stop_explanation_fstrs_from_ctrl_event(scratch.arena, &evt);
String8 explanation_string = dr_string_from_fstrs(scratch.arena, &explanation_fstrs); String8 explanation_string = dr_string_from_fstrs(scratch.arena, &explanation_fstrs);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " stop_event:\n {\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " stop_event:\n {\n");
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " arch: %S\n", string_from_arch(evt.arch)); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " arch: %S\n", string_from_arch(evt.arch));
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " vaddr_range_min: 0x%I64x\n", evt.vaddr_rng.min); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " vaddr_range: [0x%I64x, 0x%I64x)\n", evt.vaddr_rng.min, evt.vaddr_rng.max);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " vaddr_range_max: 0x%I64x\n", evt.vaddr_rng.max);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " ip_vaddr: 0x%I64x\n", evt.rip_vaddr); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " ip_vaddr: 0x%I64x\n", evt.rip_vaddr);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " stack_base: 0x%I64x\n", evt.stack_base); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " stack_base: 0x%I64x\n", evt.stack_base);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " tls_root: 0x%I64x\n", evt.tls_root); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " tls_root: 0x%I64x\n", evt.tls_root);
@@ -12643,6 +12662,25 @@ rd_frame(void)
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " explanation: \"%S\"\n", escaped_from_raw_str8(scratch.arena, explanation_string)); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " explanation: \"%S\"\n", escaped_from_raw_str8(scratch.arena, explanation_string));
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n");
} }
{
Access *access = access_open();
D_Event evt = d_ctrl_last_stop_event();
U64 vaddr = evt.rip_vaddr;
D_Entity *thread = d_entity_from_handle(rd_base_regs()->thread);
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
D_Entity *module = d_module_from_process_vaddr(process, vaddr);
U64 voff = d_voff_from_vaddr(module, vaddr);
DI_Key dbgi_key = d_dbgi_key_from_module(module);
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0);
E_String2NumMap *locals_map = e_push_locals_map_from_rdi_voff(scratch.arena, rdi, voff);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " locals:\n {\n");
for(E_String2NumMapNode *n = locals_map->first; n != 0; n = n->order_next)
{
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " %S\n", n->string);
}
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n");
access_close(access);
}
{ {
D_Event evt = d_ctrl_last_stop_event(); D_Event evt = d_ctrl_last_stop_event();
U64 vaddr = evt.rip_vaddr; U64 vaddr = evt.rip_vaddr;
@@ -12656,12 +12694,12 @@ rd_frame(void)
for EachNode(n, D_LineNode, lines.first) for EachNode(n, D_LineNode, lines.first)
{ {
D_Line line = n->v; D_Line line = n->v;
String8 line_file_path_relative = path_relative_dst_from_absolute_dst_src(scratch.arena, line.file_path, module->string);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " {\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " {\n");
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " file_path: \"%S\"\n", line.file_path); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " file_path: \"%S\"\n", line_file_path_relative);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " line_num: %I64d\n", line.pt.line); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " line_num: %I64d\n", line.pt.line);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " column_num: %I64d\n", line.pt.column); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " column_num: %I64d\n", line.pt.column);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " voff_range_min: 0x%I64x\n", line.voff_range.min); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " voff_range: [0x%I64x, 0x%I64x)\n", line.voff_range.min, line.voff_range.max);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " voff_range_max: 0x%I64x\n", line.voff_range.max);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n");
} }
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n");
@@ -12688,8 +12726,7 @@ rd_frame(void)
D_Entity *module = modules.v[idx]; D_Entity *module = modules.v[idx];
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " {\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " {\n");
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " name: \"%S\"\n", escaped_from_raw_str8(scratch.arena, module->string)); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " name: \"%S\"\n", escaped_from_raw_str8(scratch.arena, module->string));
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " vaddr_range_min: 0x%I64x\n", module->vaddr_range.min); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " vaddr_range: [0x%I64x, 0x%I64x)\n", module->vaddr_range.min, module->vaddr_range.max);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " vaddr_range_max: 0x%I64x\n", module->vaddr_range.max);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n");
} }
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " }\n");
@@ -12698,6 +12735,12 @@ rd_frame(void)
}break; }break;
case RD_CmdKind_Eval: case RD_CmdKind_Eval:
{ {
// TODO(rjf): to use this for evaluation testing, we need some way to temporarily
// call the eval system with ctrl-thread-like evaluation rules (e.g. waiting for
// memory, never accepting stale results, not looking into caches, etc.). currently
// we'd only be able to do that by setting up an entirely new evaluation context,
// which is currently a ton of code & laborious & duplicative, so we need to tighten
// that up first. @eval_regressions
String8 expr = rd_regs()->expr; String8 expr = rd_regs()->expr;
E_Eval eval = e_eval_from_string(expr); E_Eval eval = e_eval_from_string(expr);
E_Eval type_eval = e_eval_from_stringf("typeof(%S)", expr); E_Eval type_eval = e_eval_from_stringf("typeof(%S)", expr);
@@ -12706,6 +12749,10 @@ rd_frame(void)
.flags = EV_StringFlag_ReadOnlyDisplayRules | rd_state->eval_viz_base_string_flags, .flags = EV_StringFlag_ReadOnlyDisplayRules | rd_state->eval_viz_base_string_flags,
.radix = 10, .radix = 10,
}; };
if(rd_regs()->disable_addresses)
{
string_params.flags |= EV_StringFlag_DisableAddresses;
}
String8 value_string = ev_value_string_from_eval(scratch.arena, &string_params, eval, 512); String8 value_string = ev_value_string_from_eval(scratch.arena, &string_params, eval, 512);
String8 type_value_string = ev_value_string_from_eval(scratch.arena, &string_params, type_eval, 512); String8 type_value_string = ev_value_string_from_eval(scratch.arena, &string_params, type_eval, 512);
String8List msgs_strings = {0}; String8List msgs_strings = {0};
@@ -16903,7 +16950,7 @@ rd_frame(void)
} }
// rjf: focus window if none focused, and if we have a thread to snap to // rjf: focus window if none focused, and if we have a thread to snap to
if(need_refocus && (selected_thread != &d_entity_nil || thread != &d_entity_nil)) if(!rd_state->override_focus_on_stop && need_refocus && (selected_thread != &d_entity_nil || thread != &d_entity_nil))
{ {
B32 any_window_is_focused = 0; B32 any_window_is_focused = 0;
for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next) for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next)
+2 -1
View File
@@ -388,6 +388,7 @@ struct RD_State
Arena *arena; Arena *arena;
B32 quit; B32 quit;
B32 quit_after_success; B32 quit_after_success;
B32 override_focus_on_stop;
S32 frame_depth; S32 frame_depth;
U64 frame_eval_memread_endt_us; U64 frame_eval_memread_endt_us;
@@ -444,7 +445,7 @@ struct RD_State
Access *frame_access; Access *frame_access;
String8 last_window_title; String8 last_window_title;
// rjf: evaluation cache // rjf: evaluation caches
E_Cache *eval_cache; E_Cache *eval_cache;
// rjf: ambiguous path table (constructed from-scratch each frame) // rjf: ambiguous path table (constructed from-scratch each frame)
+7 -3
View File
@@ -426,7 +426,7 @@ struct IPCInfo
//~ rjf: Globals //~ rjf: Globals
//- rjf: IPC resources //- rjf: IPC resources
#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(4) #define IPC_SHARED_MEMORY_BUFFER_SIZE KB(64)
StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement); StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement);
global Semaphore ipc_sender2main_signal_semaphore = {0}; global Semaphore ipc_sender2main_signal_semaphore = {0};
global Semaphore ipc_sender2main_lock_semaphore = {0}; global Semaphore ipc_sender2main_lock_semaphore = {0};
@@ -434,7 +434,7 @@ global U8 *ipc_sender2main_shared_memory_base = 0;
global Semaphore ipc_main2sender_signal_semaphore = {0}; global Semaphore ipc_main2sender_signal_semaphore = {0};
global Semaphore ipc_main2sender_lock_semaphore = {0}; global Semaphore ipc_main2sender_lock_semaphore = {0};
global U8 *ipc_main2sender_shared_memory_base = 0; global U8 *ipc_main2sender_shared_memory_base = 0;
global U8 ipc_s2m_ring_buffer[MB(4)] = {0}; global U8 ipc_s2m_ring_buffer[KB(64)] = {0};
global U64 ipc_s2m_ring_write_pos = 0; global U64 ipc_s2m_ring_write_pos = 0;
global U64 ipc_s2m_ring_read_pos = 0; global U64 ipc_s2m_ring_read_pos = 0;
global Mutex ipc_s2m_ring_mutex = {0}; global Mutex ipc_s2m_ring_mutex = {0};
@@ -666,6 +666,7 @@ entry_point(CmdLine *cmd_line)
if(msg.size != 0) if(msg.size != 0)
{ {
log_infof("ipc_msg: \"%S\"", msg); log_infof("ipc_msg: \"%S\"", msg);
String8List cmd_parts_of_msg = str8_split(scratch.arena, msg, (U8 *)";", 1, 0);
RD_WindowState *dst_ws = rd_state->first_window_state; RD_WindowState *dst_ws = rd_state->first_window_state;
for(RD_WindowState *ws = dst_ws; ws != &rd_nil_window_state; ws = ws->order_next) for(RD_WindowState *ws = dst_ws; ws != &rd_nil_window_state; ws = ws->order_next)
{ {
@@ -690,7 +691,10 @@ entry_point(CmdLine *cmd_line)
rd_regs()->view = panel_tree.focused->selected_tab->id; rd_regs()->view = panel_tree.focused->selected_tab->id;
scratch_end(scratch); scratch_end(scratch);
} }
rd_cmd(RD_CmdKind_RunExternalDriverTextCommand, .string = msg); for EachNode(n, String8Node, cmd_parts_of_msg.first)
{
rd_cmd(RD_CmdKind_RunExternalDriverTextCommand, .string = n->string);
}
rd_request_frame(); rd_request_frame();
} }
} }
+235 -40
View File
@@ -1,6 +1,16 @@
// Copyright (c) Epic Games Tools // Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Debugger Testing IPC Driving Helpers
internal String8
rd_test__mule_main_path(Arena *arena)
{
String8 mule_main_exe_path = str8f(arena, "%S/%S%S", get_process_info()->binary_path, s("mule_main"), program_ext_postfix_from_os(OperatingSystem_CURRENT));
return mule_main_exe_path;
}
internal String8 internal String8
rd_test__raddbg_path(Arena *arena, CmdLine *cmdline) rd_test__raddbg_path(Arena *arena, CmdLine *cmdline)
{ {
@@ -14,9 +24,9 @@ rd_test__open_debugger(CmdLine *cmdline, String8 test_artifacts_path, String8 ta
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
String8 raddbg_path = rd_test__raddbg_path(scratch.arena, cmdline); String8 raddbg_path = rd_test__raddbg_path(scratch.arena, cmdline);
String8 user_file_path = str8f(scratch.arena, "%S/test.raddbg_user", test_artifacts_path);\ String8 user_file_path = str8f(scratch.arena, "%S/test.raddbg_user", test_artifacts_path);
delete_file_at_path(user_file_path); delete_file_at_path(user_file_path);
Process process = launch_cmd_linef("%S --gen_crash_dump --user:test.raddbg_user --logs:logs %S", raddbg_path, target_cmd_line); Process process = launch_cmd_linef("%S --gen_crash_dump --no_focus_on_stop --user:%S --logs:logs %S", raddbg_path, user_file_path, target_cmd_line);
scratch_end(scratch); scratch_end(scratch);
return process; return process;
} }
@@ -41,64 +51,249 @@ rd_test__ipc_cmd(Arena *arena, CmdLine *cmdline, String8 test_artifacts_path, U6
return response; return response;
} }
Test(stepping) ////////////////////////////////
//~ rjf: Exemplar Test Helpers
internal void
rd_test__exemplar_test_finish(Arena *arena, String8List test_log_strings, String8 test_exemplars_path, String8 test_artifacts_path, TestResult *result_out, String8List *test_out)
{ {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
String8 mule_main_exe_path = str8f(scratch.arena, "%S/%S%S", get_process_info()->binary_path, s("mule_main"), program_ext_postfix_from_os(OperatingSystem_CURRENT));
struct // rjf: combine all current test log output; write to 'current' data
String8 test_log_current = str8_list_join(scratch.arena, &test_log_strings, 0);
String8 test_log_current_path = str8f(scratch.arena, "%S/current", test_artifacts_path);
write_data_to_file_path(test_log_current_path, test_log_current);
// rjf: load test log exemplar
make_directory(test_exemplars_path);
String8 exemplar_path = str8f(scratch.arena, "%S/exemplar", test_exemplars_path);
String8 exemplar_data = data_from_file_path(scratch.arena, exemplar_path);
// rjf: if exemplar data is empty -> just save our output as the new exemplar
if(exemplar_data.size == 0)
{ {
String8 cmdline; copy_file_path(exemplar_path, test_log_current_path);
String8 start_symbol;
B32 step_over_on_even;
} }
test_cases[] =
// rjf: if we have exemplar data, then we need to check that it matches
if(exemplar_data.size != 0)
{ {
{ mule_main_exe_path, s("mule_main"), 0 }, B32 current_matches_exemplar = str8_match(test_log_current, exemplar_data, 0);
{ mule_main_exe_path, s("mule_main"), 1 }, if(!current_matches_exemplar)
{ mule_main_exe_path, s("control_flow_stepping_tests"), 0 },
{ mule_main_exe_path, s("control_flow_stepping_tests"), 1 },
};
for EachElement(test_case_idx, test_cases)
{
String8 test_cmdline = test_cases[test_case_idx].cmdline;
String8 start_symbol = test_cases[test_case_idx].start_symbol;
B32 step_over_on_even = test_cases[test_case_idx].step_over_on_even;
Process debugger = rd_test__open_debugger(cmdline, test_artifacts_path, test_cmdline);
U64 debugger_pid = pid_from_process(debugger);
String8 next_step_cmd = {0};
rd_test__ipc_cmd(scratch.arena, cmdline, test_artifacts_path, debugger_pid, str8f(scratch.arena, "run_to_name %S", start_symbol));
for(U64 cmd_idx = 0;; cmd_idx += 1)
{ {
String8 step_cmd = s("step_into"); String8 diff_cmd = str8f(scratch.arena, "diff %S %S",
if((cmd_idx % 2 == 0 && step_over_on_even) || (cmd_idx % 2 == 1 && !step_over_on_even)) path_normalized_from_string(scratch.arena, exemplar_path),
path_normalized_from_string(scratch.arena, test_log_current_path));
test_outf("Current log does not match exemplar; run `%S`\n", diff_cmd);
}
TestCheck(current_matches_exemplar);
}
scratch_end(scratch);
}
////////////////////////////////
//~ rjf: Test Helpers
internal void
rd_test__stepping_regressions(Arena *arena, CmdLine *cmdline, String8 test_exemplars_path, String8 test_artifacts_path, TestResult *result_out, String8List *test_out, String8 target_cmdline, String8 start_symbol, B32 step_over_on_even)
{
Temp scratch = scratch_begin(&arena, 1);
String8List test_log_strings = {0};
// rjf: start debugger
Process debugger = rd_test__open_debugger(cmdline, test_artifacts_path, target_cmdline);
U64 debugger_pid = pid_from_process(debugger);
// rjf: step & gather info
{
U64 last_stop_count = max_U64;
B32 ready_for_next_operation = 0;
String8 next_step_cmd = {0};
for(U64 cmd_idx = 0;;)
{
Temp scratch2 = scratch_begin(&scratch.arena, 1);
// rjf: need next operation -> do op
if(ready_for_next_operation)
{ {
step_cmd = s("step_over"); ready_for_next_operation = 0;
String8 step_cmd = s("step_into");
if(cmd_idx == 0)
{
step_cmd = str8f(scratch2.arena, "run_to_name %S", start_symbol);
}
else if((cmd_idx % 2 == 0 && step_over_on_even) || (cmd_idx % 2 == 1 && !step_over_on_even))
{
step_cmd = s("step_over");
}
if(next_step_cmd.size != 0)
{
step_cmd = next_step_cmd;
MemoryZeroStruct(&next_step_cmd);
}
String8 step_response = rd_test__ipc_cmd(scratch2.arena, cmdline, test_artifacts_path, debugger_pid, step_cmd);
(void)step_response;
cmd_idx += 1;
} }
if(next_step_cmd.size != 0)
{ // rjf: query state, parse
step_cmd = next_step_cmd; String8 state_response = rd_test__ipc_cmd(scratch2.arena, cmdline, test_artifacts_path, debugger_pid, s("state"));
MemoryZeroStruct(&next_step_cmd); MD_Node *state_response_tree = md_tree_from_string(scratch2.arena, state_response);
}
String8 step_response = rd_test__ipc_cmd(scratch.arena, cmdline, test_artifacts_path, debugger_pid, step_cmd);
String8 state_response = rd_test__ipc_cmd(scratch.arena, cmdline, test_artifacts_path, debugger_pid, s("state"));
MD_Node *state_response_tree = md_tree_from_string(scratch.arena, state_response);
MD_Node *state = md_child_from_string(state_response_tree, s("state"), 0); MD_Node *state = md_child_from_string(state_response_tree, s("state"), 0);
U64 ip_vaddr = 0;
try_u64_from_str8_c_rules(md_child_from_string(state, s("ip"), 0)->first->string, &ip_vaddr); // rjf: we are only ready for next step command when the stop count has changed
if(ip_vaddr != 0 && md_child_from_string(state, s("lines"), 0)->first == &md_nil_node)
{ {
next_step_cmd = s("step_out"); U64 stop_count = 0;
try_u64_from_str8_c_rules(md_child_from_string(state, s("stop_count"), 0)->first->string, &stop_count);
if(stop_count != last_stop_count)
{
ready_for_next_operation = 1;
last_stop_count = stop_count;
}
} }
// rjf: if we are ready for the next operation, then accumulate deterministic log info
if(ready_for_next_operation)
{
MD_Node *lines = md_child_from_string(state, s("lines"), 0);
MD_Node *ip_voff = md_child_from_string(state, s("ip_voff"), 0);
MD_Node *ip_voff_symbol = md_child_from_string(state, s("ip_voff_symbol"), 0);
String8 lines_dump = md_string_from_tree(scratch.arena, lines);
String8 ip_voff_dump = md_string_from_tree(scratch.arena, ip_voff);
String8 ip_voff_symbol_dump = md_string_from_tree(scratch.arena, ip_voff_symbol);
str8_list_push(scratch.arena, &test_log_strings, lines_dump);
str8_list_push(scratch.arena, &test_log_strings, ip_voff_dump);
str8_list_push(scratch.arena, &test_log_strings, ip_voff_symbol_dump);
}
// rjf: are we without line info? -> step out
if(ready_for_next_operation)
{
U64 ip_vaddr = 0;
try_u64_from_str8_c_rules(md_child_from_string(state, s("ip"), 0)->first->string, &ip_vaddr);
if(ip_vaddr != 0 && md_child_from_string(state, s("lines"), 0)->first == &md_nil_node)
{
next_step_cmd = s("step_out");
}
}
scratch_end(scratch2);
if(cmd_idx >= 100) if(cmd_idx >= 100)
{ {
break; break;
} }
} }
rd_test__close_debugger(debugger);
} }
// rjf: end exemplar test
rd_test__exemplar_test_finish(arena, test_log_strings, test_exemplars_path, test_artifacts_path, result_out, test_out);
// rjf: close debugger
rd_test__close_debugger(debugger);
scratch_end(scratch); scratch_end(scratch);
} }
internal void
rd_test__eval_regressions(Arena *arena, CmdLine *cmdline, String8 test_exemplars_path, String8 test_artifacts_path, TestResult *result_out, String8List *test_out, String8 target_cmdline, String8 target_line)
{
Temp scratch = scratch_begin(&arena, 1);
String8List test_log_strings = {0};
// rjf: start debugger
Process debugger = rd_test__open_debugger(cmdline, test_artifacts_path, target_cmdline);
U64 debugger_pid = pid_from_process(debugger);
// rjf: query state
U64 initial_stop_count = 0;
{
String8 response = rd_test__ipc_cmd(scratch.arena, cmdline, test_artifacts_path, debugger_pid, s("state"));
MD_Node *state = md_child_from_string(md_tree_from_string(scratch.arena, response), s("state"), 0);
MD_Node *stop_count = md_child_from_string(state, s("stop_count"), 0);
try_u64_from_str8_c_rules(stop_count->first->string, &initial_stop_count);
}
// rjf: run to target line
rd_test__ipc_cmd(scratch.arena, cmdline, test_artifacts_path, debugger_pid, str8f(scratch.arena, "run_to_line %S", target_line));
// rjf: wait for stop, collect locals
String8List locals = {0};
for(;;)
{
Temp scratch2 = scratch_begin(&scratch.arena, 1);
String8 response = rd_test__ipc_cmd(scratch.arena, cmdline, test_artifacts_path, debugger_pid, s("state"));
MD_Node *state = md_child_from_string(md_tree_from_string(scratch.arena, response), s("state"), 0);
MD_Node *stop_count = md_child_from_string(state, s("stop_count"), 0);
U64 new_stop_count = 0;
try_u64_from_str8_c_rules(stop_count->first->string, &new_stop_count);
scratch_end(scratch2);
if(new_stop_count != initial_stop_count)
{
MD_Node *locals_root = md_child_from_string(state, s("locals"), 0);
for MD_EachNode(c, locals_root->first)
{
str8_list_push(scratch.arena, &locals, c->string);
}
break;
}
}
// rjf: evaluate all locals
String8List eval_cmd_strings = {0};
for EachNode(n, String8Node, locals.first)
{
str8_list_pushf(scratch.arena, &eval_cmd_strings, "eval %S", n->string);
}
StringJoin join = {.sep = s(" ; ")};
String8 eval_msg = str8_list_join(scratch.arena, &eval_cmd_strings, &join);
String8 response = rd_test__ipc_cmd(scratch.arena, cmdline, test_artifacts_path, debugger_pid, eval_msg);
MD_Node *response_tree = md_tree_from_string(scratch.arena, response);
for MD_EachNode(n, response_tree->first)
{
if(str8_match(n->string, s("eval"), 0))
{
String8 eval_dump = md_string_from_tree(scratch.arena, n);
str8_list_push(scratch.arena, &test_log_strings, eval_dump);
}
}
// rjf: end exemplar test
rd_test__exemplar_test_finish(arena, test_log_strings, test_exemplars_path, test_artifacts_path, result_out, test_out);
// rjf: close debugger
rd_test__close_debugger(debugger);
scratch_end(scratch);
}
////////////////////////////////
//~ rjf: Tests
#if 0
Test(mule_main_step_regressions_0)
{
String8 exe_path = {0};
rd_test__stepping_regressions(arena, cmdline, test_exemplars_path, test_artifacts_path, result_out, test_out, rd_test__mule_main_path(arena), s("mule_main"), 0);
}
Test(mule_main_step_regressions_1)
{
rd_test__stepping_regressions(arena, cmdline, test_exemplars_path, test_artifacts_path, result_out, test_out, rd_test__mule_main_path(arena), s("mule_main"), 1);
}
Test(control_flow_step_regressions)
{
rd_test__stepping_regressions(arena, cmdline, test_exemplars_path, test_artifacts_path, result_out, test_out, rd_test__mule_main_path(arena), s("mule_main"), 0);
}
SkippedTest(type_coverage_eval_regressions)
{
// TODO(rjf): see @eval_regressions
rd_test__eval_regressions(arena, cmdline, test_exemplars_path, test_artifacts_path, result_out, test_out, rd_test__mule_main_path(arena), s("C:/devel/raddebugger/src/mule/mule_main.cpp:723"));
}
#endif
#if 0 #if 0
//////////////////////////////// ////////////////////////////////
// IPC Controller // IPC Controller
+9 -1
View File
@@ -4,6 +4,7 @@
// command line // command line
global String8 g_stdout_file_name = str8_lit_comp("torture.out"); global String8 g_stdout_file_name = str8_lit_comp("torture.out");
global String8 g_wdir; global String8 g_wdir;
global String8 g_exemplar_dir;
global String8 g_out = str8_lit_comp("torture_artifacts"); global String8 g_out = str8_lit_comp("torture_artifacts");
global B32 g_verbose; global B32 g_verbose;
global B32 g_redirect_stdout = 1; global B32 g_redirect_stdout = 1;
@@ -168,7 +169,7 @@ t_run_caller(void *raw_ctx)
if (ctx->test->skip) { if (ctx->test->skip) {
ctx->result.status = TestStatus_Skip; ctx->result.status = TestStatus_Skip;
} else { } else {
ctx->test->test_fn(scratch.arena, ctx->cmdline, g_wdir, &ctx->result, &test_out); ctx->test->test_fn(scratch.arena, ctx->cmdline, g_exemplar_dir, g_wdir, &ctx->result, &test_out);
} }
if (ctx->result.status == TestStatus_Fail || ctx->result.status == TestStatus_Crash) { if (ctx->result.status == TestStatus_Fail || ctx->result.status == TestStatus_Crash) {
@@ -1273,6 +1274,13 @@ t_entry_point(CmdLine *cmdline)
fprintf(stdout, " %.*s ", (int)dots_count, dots); fprintf(stdout, " %.*s ", (int)dots_count, dots);
fflush(stdout); fflush(stdout);
// rjf: find exemplar data directory
{
String8 binary_dir_path = get_process_info()->binary_path;
String8 root_dir_path = str8_chop_last_slash(binary_dir_path);
g_exemplar_dir = str8f(scratch.arena, "%S/data/test_exemplars/%S", root_dir_path, test->label);
}
// setup output directory // setup output directory
g_wdir = str8f(scratch.arena, "%S/%S", g_out, test->label); g_wdir = str8f(scratch.arena, "%S/%S", g_out, test->label);
g_wdir = full_path_from_path(scratch.arena, g_wdir); g_wdir = full_path_from_path(scratch.arena, g_wdir);
+1 -1
View File
@@ -7,7 +7,7 @@
#endif #endif
internal DASM_Inst internal DASM_Inst
x64_dasm_inst_from_code(Arena *arena, U64 vaddr, String8 code, DASM_Syntax syntax) x64_dasm_inst_from_code(Arena *arena, U64 vaddr, String8 code, DASM_Syntax syntax)
{ {
DASM_Inst inst = {0}; DASM_Inst inst = {0};