mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-08 23:08:08 +00:00
raddbg: stepping regression tests
This commit is contained in:
+3
-2
@@ -7,7 +7,6 @@ target:
|
||||
working_directory: build
|
||||
arguments: "--user:raddbg_test.user --project:raddbg_test.project"
|
||||
debug_subprocesses: 0
|
||||
enabled: 1
|
||||
}
|
||||
target:
|
||||
{
|
||||
@@ -41,5 +40,7 @@ target:
|
||||
target:
|
||||
{
|
||||
executable: "build/torture.exe"
|
||||
working_directory: "build/"
|
||||
working_directory: build
|
||||
enabled: 1
|
||||
arguments: "raddbg/* --gui"
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ internal U32 get_process_start_time_unix(void);
|
||||
//~ rjf: @per_os_impl Child Processes
|
||||
|
||||
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 void process_detach(Process process);
|
||||
internal B32 process_kill(Process process);
|
||||
|
||||
@@ -1491,6 +1491,21 @@ program_data_folder_prefix_from_os(OperatingSystem os)
|
||||
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
|
||||
str8_chop_last_slash(String8 string)
|
||||
{
|
||||
|
||||
@@ -324,6 +324,7 @@ g_path_style_map[] =
|
||||
};
|
||||
|
||||
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_skip_last_slash(String8 string);
|
||||
|
||||
@@ -23,7 +23,7 @@ struct TestResult
|
||||
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)
|
||||
typedef TEST_FUNCTION_SIG(TestFunctionType);
|
||||
|
||||
|
||||
@@ -1299,6 +1299,13 @@ process_launch(ProcessLaunchParams *params)
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal U64
|
||||
pid_from_process(Process process)
|
||||
{
|
||||
U64 result = process.u64[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
process_join(Process process, U64 endt_us, U64 *exit_code_out)
|
||||
{
|
||||
|
||||
@@ -12382,12 +12382,6 @@ rd_frame(void)
|
||||
// rjf: 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
|
||||
CFG_Node *cfg = &cfg_nil_node;
|
||||
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, " }\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");
|
||||
D_EntityArray threads = d_entity_array_from_kind(D_EntityKind_Thread);
|
||||
|
||||
@@ -1,9 +1,102 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// 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
|
||||
|
||||
@@ -168,7 +168,7 @@ t_run_caller(void *raw_ctx)
|
||||
if (ctx->test->skip) {
|
||||
ctx->result.status = TestStatus_Skip;
|
||||
} 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) {
|
||||
@@ -187,9 +187,9 @@ t_run_caller(void *raw_ctx)
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (ctx.result.status == TestStatus_Fail || ctx.result.status == TestStatus_Crash) {
|
||||
@@ -1290,7 +1290,7 @@ t_entry_point(CmdLine *cmdline)
|
||||
|
||||
// run test
|
||||
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();
|
||||
|
||||
// update
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TestInfo *test;
|
||||
String8 user_data;
|
||||
TestInfo *test;
|
||||
CmdLine *cmdline;
|
||||
String8 user_data;
|
||||
TestResult result;
|
||||
} T_RunCtx;
|
||||
|
||||
@@ -47,7 +48,7 @@ internal String8 t_make_file_path(Arena *arena, String8 name);
|
||||
// test runner
|
||||
internal void t_run_caller(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
|
||||
internal String8 t_radbin_path(void);
|
||||
|
||||
@@ -1421,6 +1421,14 @@ process_launch(ProcessLaunchParams *params)
|
||||
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
|
||||
process_join(Process process, U64 endt_us, U64 *exit_code_out)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user