raddbg: stepping regression tests

This commit is contained in:
Ryan Fleury
2026-06-02 12:11:02 -07:00
parent 685c408a13
commit 8564884d76
11 changed files with 162 additions and 18 deletions
+3 -2
View File
@@ -7,7 +7,6 @@ target:
working_directory: build working_directory: build
arguments: "--user:raddbg_test.user --project:raddbg_test.project" arguments: "--user:raddbg_test.user --project:raddbg_test.project"
debug_subprocesses: 0 debug_subprocesses: 0
enabled: 1
} }
target: target:
{ {
@@ -41,5 +40,7 @@ target:
target: target:
{ {
executable: "build/torture.exe" executable: "build/torture.exe"
working_directory: "build/" working_directory: build
enabled: 1
arguments: "raddbg/* --gui"
} }
+1
View File
@@ -82,6 +82,7 @@ internal U32 get_process_start_time_unix(void);
//~ rjf: @per_os_impl Child Processes //~ rjf: @per_os_impl Child Processes
internal Process process_launch(ProcessLaunchParams *params); internal Process process_launch(ProcessLaunchParams *params);
internal U64 pid_from_process(Process process);
internal B32 process_join(Process process, U64 endt_us, U64 *exit_code_out); internal B32 process_join(Process process, U64 endt_us, U64 *exit_code_out);
internal void process_detach(Process process); internal void process_detach(Process process);
internal B32 process_kill(Process process); internal B32 process_kill(Process process);
+15
View File
@@ -1491,6 +1491,21 @@ program_data_folder_prefix_from_os(OperatingSystem os)
return result; return result;
} }
internal String8
program_ext_postfix_from_os(OperatingSystem os)
{
String8 result = {0};
switch(os)
{
default:{}break;
case OperatingSystem_Windows:
{
result = s(".exe");
}break;
}
return result;
}
internal String8 internal String8
str8_chop_last_slash(String8 string) str8_chop_last_slash(String8 string)
{ {
+1
View File
@@ -324,6 +324,7 @@ g_path_style_map[] =
}; };
internal String8 program_data_folder_prefix_from_os(OperatingSystem os); internal String8 program_data_folder_prefix_from_os(OperatingSystem os);
internal String8 program_ext_postfix_from_os(OperatingSystem os);
internal String8 str8_chop_last_slash(String8 string); internal String8 str8_chop_last_slash(String8 string);
internal String8 str8_skip_last_slash(String8 string); internal String8 str8_skip_last_slash(String8 string);
+1 -1
View File
@@ -23,7 +23,7 @@ struct TestResult
char *fail_cond; char *fail_cond;
}; };
#define TEST_FUNCTION_SIG(name) void name(Arena *arena, TestResult *result_out, String8List *test_out) #define TEST_FUNCTION_SIG(name) void name(Arena *arena, CmdLine *cmdline, 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);
+7
View File
@@ -1299,6 +1299,13 @@ process_launch(ProcessLaunchParams *params)
return handle; return handle;
} }
internal U64
pid_from_process(Process process)
{
U64 result = process.u64[0];
return result;
}
internal B32 internal B32
process_join(Process process, U64 endt_us, U64 *exit_code_out) process_join(Process process, U64 endt_us, U64 *exit_code_out)
{ {
+23 -6
View File
@@ -12382,12 +12382,6 @@ rd_frame(void)
// rjf: request frame // rjf: request frame
rd_request_frame(); rd_request_frame();
// rjf: record 'ack' for this command
if(kind != RD_CmdKind_Null)
{
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, "ack:{cmd:%S}\n", cmd->name);
}
// rjf: process command // rjf: process command
CFG_Node *cfg = &cfg_nil_node; CFG_Node *cfg = &cfg_nil_node;
String8 dst_path = {0}; String8 dst_path = {0};
@@ -12649,6 +12643,29 @@ 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");
} }
{
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);
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, voff);
str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " lines:\n {\n");
for EachNode(n, D_LineNode, lines.first)
{
D_Line line = n->v;
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, " 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, " voff_range_min: 0x%I64x\n", line.voff_range.min);
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, " threads:\n {\n"); str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, " threads:\n {\n");
D_EntityArray threads = d_entity_array_from_kind(D_EntityKind_Thread); D_EntityArray threads = d_entity_array_from_kind(D_EntityKind_Thread);
+94 -1
View File
@@ -1,9 +1,102 @@
// 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/)
Test(stepping_regressions) internal String8
rd_test__raddbg_path(Arena *arena, CmdLine *cmdline)
{ {
String8 raddbg_exe_name = cmd_line_has_flag(cmdline, s("gui")) ? s("raddbg") : s("raddbg_non_graphical");
String8 raddbg_exe_filename = str8f(arena, "%S/%S%S", get_process_info()->binary_path, raddbg_exe_name, program_ext_postfix_from_os(OperatingSystem_CURRENT));
return raddbg_exe_filename;
}
internal Process
rd_test__open_debugger(CmdLine *cmdline, String8 test_artifacts_path, String8 target_cmd_line)
{
Temp scratch = scratch_begin(0, 0);
String8 raddbg_path = rd_test__raddbg_path(scratch.arena, cmdline);
String8 user_file_path = str8f(scratch.arena, "%S/test.raddbg_user", test_artifacts_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);
scratch_end(scratch);
return process;
}
internal void
rd_test__close_debugger(Process process)
{
process_kill(process);
}
internal String8
rd_test__ipc_cmd(Arena *arena, CmdLine *cmdline, String8 test_artifacts_path, U64 debugger_pid, String8 string)
{
Temp scratch = scratch_begin(&arena, 1);
String8 raddbg_path = rd_test__raddbg_path(scratch.arena, cmdline);
String8 stdout_path = str8f(scratch.arena, "%S/ipc_output", test_artifacts_path);
Process process = launch_cmd_linef("%S --ipc --pid:%I64u %S > %S", raddbg_path, debugger_pid, string, stdout_path);
process_join(process, max_U64, 0);
String8 response = data_from_file_path(arena, stdout_path);
delete_file_at_path(stdout_path);
scratch_end(scratch);
return response;
}
Test(stepping)
{
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
{
String8 cmdline;
String8 start_symbol;
B32 step_over_on_even;
}
test_cases[] =
{
{ mule_main_exe_path, s("mule_main"), 0 },
{ mule_main_exe_path, s("mule_main"), 1 },
{ 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");
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(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);
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");
}
if(cmd_idx >= 100)
{
break;
}
}
rd_test__close_debugger(debugger);
}
scratch_end(scratch);
} }
#if 0 #if 0
+4 -4
View File
@@ -168,7 +168,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->result, &test_out); ctx->test->test_fn(scratch.arena, ctx->cmdline, 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) {
@@ -187,9 +187,9 @@ t_run_caller(void *raw_ctx)
} }
internal TestResult internal TestResult
t_run(TestInfo *test, String8 user_data) t_run(CmdLine *cmdline, TestInfo *test, String8 user_data)
{ {
T_RunCtx ctx = { .test = test, .user_data = user_data, .result.status = TestStatus_Fail }; T_RunCtx ctx = { .test = test, .cmdline = cmdline, .user_data = user_data, .result.status = TestStatus_Fail };
t_run_caller(&ctx); t_run_caller(&ctx);
if (ctx.result.status == TestStatus_Fail || ctx.result.status == TestStatus_Crash) { if (ctx.result.status == TestStatus_Fail || ctx.result.status == TestStatus_Crash) {
@@ -1290,7 +1290,7 @@ t_entry_point(CmdLine *cmdline)
// run test // run test
U64 run_start_time = now_time_us(); U64 run_start_time = now_time_us();
TestResult result = t_run(test, str8_zero()); TestResult result = t_run(cmdline, test, str8_zero());
U64 run_end_time = now_time_us(); U64 run_end_time = now_time_us();
// update // update
+4 -3
View File
@@ -13,8 +13,9 @@
typedef struct typedef struct
{ {
TestInfo *test; TestInfo *test;
String8 user_data; CmdLine *cmdline;
String8 user_data;
TestResult result; TestResult result;
} T_RunCtx; } T_RunCtx;
@@ -47,7 +48,7 @@ internal String8 t_make_file_path(Arena *arena, String8 name);
// test runner // test runner
internal void t_run_caller(void *raw_ctx); internal void t_run_caller(void *raw_ctx);
internal void t_run_fail_handler(void *raw_ctx); internal void t_run_fail_handler(void *raw_ctx);
internal TestResult t_run(TestInfo *test, String8 user_data); internal TestResult t_run(CmdLine *cmdline, TestInfo *test, String8 user_data);
// tools // tools
internal String8 t_radbin_path(void); internal String8 t_radbin_path(void);
+8
View File
@@ -1421,6 +1421,14 @@ process_launch(ProcessLaunchParams *params)
return result; return result;
} }
internal U64
pid_from_process(Process process)
{
HANDLE process_handle = (HANDLE)process.u64[0];
U64 result = (U64)GetProcessId(process_handle);
return result;
}
internal B32 internal B32
process_join(Process process, U64 endt_us, U64 *exit_code_out) process_join(Process process, U64 endt_us, U64 *exit_code_out)
{ {