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
|
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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
TestInfo *test;
|
TestInfo *test;
|
||||||
|
CmdLine *cmdline;
|
||||||
String8 user_data;
|
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);
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user