diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 60b25d9c..0fa56b46 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -10479,9 +10479,9 @@ rd_ipc_make_reply_stop_event(Arena *arena) return result; } -internal String8 -rd_ipc_make_reply_eval(Arena *arena, String8 expr, E_Eval eval, U64 cap) -{ +internal String8 +rd_ipc_make_reply_eval(Arena *arena, String8 expr, E_Eval eval, U64 cap) +{ Temp scratch = scratch_begin(&arena, 1); // gather value & type @@ -10510,62 +10510,62 @@ rd_ipc_make_reply_eval(Arena *arena, String8 expr, E_Eval eval, U64 cap) String8 result = str8_list_join(arena, &reply, 0); scratch_end(scratch); - return result; -} - -internal String8 -rd_ipc_make_reply_source_location_from_address(Arena *arena, U64 vaddr) -{ - Temp scratch = scratch_begin(&arena, 1); - - D_Entity *process = d_entity_from_handle(&d_user_state->ctrl_entity_store->ctx, rd_base_regs()->process); - if(process == &d_entity_nil) - { - D_Entity *thread = d_entity_from_handle(&d_user_state->ctrl_entity_store->ctx, rd_base_regs()->thread); - process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); - } - - D_Entity *module = &d_entity_nil; - DI_Key dbgi_key = {0}; - U64 voff = 0; - D_LineList lines = {0}; - if(process != &d_entity_nil) - { - module = d_module_from_process_vaddr(process, vaddr); - if(module != &d_entity_nil) - { - dbgi_key = d_dbgi_key_from_module(module); - voff = d_voff_from_vaddr(module, vaddr); - lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, voff); - } - } - D_Line line = {0}; - if(lines.first != 0) - { - line = lines.first->v; - } - - B32 is_ok = (process != &d_entity_nil && module != &d_entity_nil && lines.first != 0); - - String8List reply = {0}; - rd_ipc_reply_block_begin(arena, &reply, "source_location_from_address"); - rd_ipc_reply_push_b32 (arena, &reply, "ok", is_ok); - rd_ipc_reply_push_u64 (arena, &reply, "vaddr", vaddr); - rd_ipc_reply_push_u64 (arena, &reply, "voff", voff); - rd_ipc_reply_push_str8(arena, &reply, "file_path", line.file_path); - rd_ipc_reply_push_u64 (arena, &reply, "line", line.pt.line); - rd_ipc_reply_push_u64 (arena, &reply, "column", line.pt.column); - rd_ipc_reply_push_u64 (arena, &reply, "voff_min", line.voff_range.min); - rd_ipc_reply_push_u64 (arena, &reply, "voff_max", line.voff_range.max); - rd_ipc_reply_block_end(arena, &reply); - String8 result = str8_list_join(arena, &reply, 0); - - scratch_end(scratch); - return result; -} - -//////////////////////////////// -//~ rjf: Main Layer Top-Level Calls + return result; +} + +internal String8 +rd_ipc_make_reply_source_location_from_address(Arena *arena, U64 vaddr) +{ + Temp scratch = scratch_begin(&arena, 1); + + D_Entity *process = d_entity_from_handle(&d_user_state->ctrl_entity_store->ctx, rd_base_regs()->process); + if(process == &d_entity_nil) + { + D_Entity *thread = d_entity_from_handle(&d_user_state->ctrl_entity_store->ctx, rd_base_regs()->thread); + process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); + } + + D_Entity *module = &d_entity_nil; + DI_Key dbgi_key = {0}; + U64 voff = 0; + D_LineList lines = {0}; + if(process != &d_entity_nil) + { + module = d_module_from_process_vaddr(process, vaddr); + if(module != &d_entity_nil) + { + dbgi_key = d_dbgi_key_from_module(module); + voff = d_voff_from_vaddr(module, vaddr); + lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, voff); + } + } + D_Line line = {0}; + if(lines.first != 0) + { + line = lines.first->v; + } + + B32 is_ok = (process != &d_entity_nil && module != &d_entity_nil && lines.first != 0); + + String8List reply = {0}; + rd_ipc_reply_block_begin(arena, &reply, "source_location_from_address"); + rd_ipc_reply_push_b32 (arena, &reply, "ok", is_ok); + rd_ipc_reply_push_u64 (arena, &reply, "vaddr", vaddr); + rd_ipc_reply_push_u64 (arena, &reply, "voff", voff); + rd_ipc_reply_push_str8(arena, &reply, "file_path", line.file_path); + rd_ipc_reply_push_u64 (arena, &reply, "line", line.pt.line); + rd_ipc_reply_push_u64 (arena, &reply, "column", line.pt.column); + rd_ipc_reply_push_u64 (arena, &reply, "voff_min", line.voff_range.min); + rd_ipc_reply_push_u64 (arena, &reply, "voff_max", line.voff_range.max); + rd_ipc_reply_block_end(arena, &reply); + String8 result = str8_list_join(arena, &reply, 0); + + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Main Layer Top-Level Calls #if !defined(STBI_INCLUDE_STB_IMAGE_H) # define STB_IMAGE_IMPLEMENTATION @@ -12906,24 +12906,24 @@ rd_frame(void) rd_cmd(RD_CmdKind_StepIntoLine); str8_list_push(rd_state->cmd_output_arena, &rd_state->cmd_outputs, rd_ipc_make_reply_ack(rd_state->cmd_output_arena, str8_lit("step_into_line"), 1)); } - else if(str8_match(cmd_kind_name, str8_lit("eval"), 0)) - { - U64 cap_end = str8_find_needle(cmd_args, 0, str8_lit(" "), 0); - String8 cap_str = str8_substr(cmd_args, r1u64(0, cap_end)); - U64 cap = 0; - try_u64_from_str8_c_rules(cap_str, &cap); - String8 expr = str8_skip(cmd_args, cap_str.size); - str8_list_push(rd_state->cmd_output_arena, &rd_state->cmd_outputs, rd_ipc_make_reply_eval(rd_state->cmd_output_arena, expr, e_eval_from_string(expr), cap)); - } - else if(str8_match(cmd_kind_name, str8_lit("source_location_from_address"), 0)) - { - String8 vaddr_str = str8_skip_chop_whitespace(cmd_args); - U64 vaddr = 0; - try_u64_from_str8_c_rules(vaddr_str, &vaddr); - str8_list_push(rd_state->cmd_output_arena, &rd_state->cmd_outputs, rd_ipc_make_reply_source_location_from_address(rd_state->cmd_output_arena, vaddr)); - } - else if(cmd_kind_info != &rd_nil_cmd_kind_info) RD_RegsScope() - { + else if(str8_match(cmd_kind_name, str8_lit("eval"), 0)) + { + U64 cap_end = str8_find_needle(cmd_args, 0, str8_lit(" "), 0); + String8 cap_str = str8_substr(cmd_args, r1u64(0, cap_end)); + U64 cap = 0; + try_u64_from_str8_c_rules(cap_str, &cap); + String8 expr = str8_skip(cmd_args, cap_str.size); + str8_list_push(rd_state->cmd_output_arena, &rd_state->cmd_outputs, rd_ipc_make_reply_eval(rd_state->cmd_output_arena, expr, e_eval_from_string(expr), cap)); + } + else if(str8_match(cmd_kind_name, str8_lit("source_location_from_address"), 0)) + { + String8 vaddr_str = str8_skip_chop_whitespace(cmd_args); + U64 vaddr = 0; + try_u64_from_str8_c_rules(vaddr_str, &vaddr); + str8_list_push(rd_state->cmd_output_arena, &rd_state->cmd_outputs, rd_ipc_make_reply_source_location_from_address(rd_state->cmd_output_arena, vaddr)); + } + else if(cmd_kind_info != &rd_nil_cmd_kind_info) RD_RegsScope() + { for EachNonZeroEnumVal(RD_RegSlot, s) { String8 reg_slot_name = rd_reg_slot_code_name_table[s]; diff --git a/src/torture/torture.c b/src/torture/torture.c index aa6b79ee..f218c0a8 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -2,21 +2,23 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) // command line -global String8 g_stdout_file_name = str8_lit_comp("torture.out"); -global String8 g_wdir; -global String8 g_out = str8_lit_comp("torture"); -global B32 g_verbose; -global B32 g_redirect_stdout = 1; -global B32 g_stop_on_first_fail_or_crash = 1; -global String8 g_linker; -global String8 g_test_data; +global String8 g_stdout_file_name = str8_lit_comp("torture.out"); +global String8 g_wdir; +global String8 g_out = str8_lit_comp("torture"); +global B32 g_verbose; +global B32 g_redirect_stdout = 1; +global B32 g_stop_on_first_fail_or_crash = 1; +global String8 g_linker; +global String8 g_test_data; // tests U64 g_torture_test_count; T_Test g_torture_tests[0xffffff]; // invoke -global int g_last_exit_code; +global int g_last_exit_code; +global Arena *g_output_arena; +global String8 g_output; internal String8 t_test_name_from_idx(Arena *arena, U64 test_idx) @@ -180,6 +182,11 @@ t_run(T_Run run, String8 user_data) } else { t_run_caller(&ctx); } + + if (ctx.result.status == T_RunStatus_Fail || ctx.result.status == T_RunStatus_Crash) { + fprintf(stderr, "Last captured output:\n%.*s\n", str8_varg(g_output)); + } + return ctx.result; } @@ -228,27 +235,27 @@ t_cl_version(void) if ( ! version.size) { Temp scratch = scratch_begin(0, 0); - - String8 output = {0}; - t_invoke_(t_cl_path(), str8_zero(), max_U64, scratch.arena, &output); + + t_invoke_cl(""); AssertAlways(g_last_exit_code == 0); String8 needle = str8_lit("Version"); - U64 version_lo = str8_find_needle(output, 0, needle, 0); + U64 version_lo = str8_find_needle(g_output, 0, needle, 0); version_lo += needle.size + 1; - AssertAlways(version_lo < output.size); - - U64 version_hi = str8_find_needle(output, version_lo, str8_lit(" "), 0); - AssertAlways(version_hi < output.size); - - version = str8_substr(output, r1u64(version_lo, version_hi)); + AssertAlways(version_lo < g_output.size); + + U64 version_hi = str8_find_needle(g_output, version_lo, str8_lit(" "), 0); + AssertAlways(version_hi < g_output.size); + + version = str8_substr(g_output, r1u64(version_lo, version_hi)); AssertAlways(version.size > 0); local_persist U8 buffer[4096]; ArenaParams params = { .reserve_size = sizeof(buffer), .commit_size = sizeof(buffer), .optional_backing_buffer = buffer }; Arena *arena = arena_alloc_(¶ms); version = str8_copy(arena, version); - + + MemoryZeroStruct(&g_output); scratch_end(scratch); } @@ -322,27 +329,27 @@ t_src_path(void) } internal B32 -t_invoke_env(String8 exe_path, String8 cmdline, String8List env, U64 timeout, Arena *output_arena, String8 *output_out) +t_invoke_env(String8 exe_path, String8 cmdline, String8List env, U64 timeout) { - Temp scratch = scratch_begin(&output_arena,1); - + Temp scratch = scratch_begin(&g_output_arena,1); + B32 is_ok = 0; - - B32 capture_output = output_out || g_redirect_stdout; - + + // clean up global state + arena_pop_to(g_output_arena, 0); + MemoryZeroStruct(&g_output); g_last_exit_code = -1; - + +#if OS_WINDOWS File read_pipe_handle = {0}, write_pipe_handle = {0}; - if (capture_output) { - HANDLE read_pipe, write_pipe; - SECURITY_ATTRIBUTES at = { .nLength = sizeof(at), .bInheritHandle = 1 }; - if (!CreatePipe(&read_pipe, &write_pipe, &at, 0)) { - AssertAlways(0 && "failed to create a pipe"); - } - read_pipe_handle = (File){ .u64[0] = (U64)read_pipe }; - write_pipe_handle = (File){ .u64[0] = (U64)write_pipe }; - } - + HANDLE read_pipe, write_pipe; + SECURITY_ATTRIBUTES at = { .nLength = sizeof(at), .bInheritHandle = 1 }; + if (!CreatePipe(&read_pipe, &write_pipe, &at, 0)) { AssertAlways(0 && "failed to create a pipe"); } + read_pipe_handle = (File){ .u64[0] = (U64)read_pipe }; + write_pipe_handle = (File){ .u64[0] = (U64)write_pipe }; +#else +# error NotImplemented +#endif // Build Launch Options ProcessLaunchParams launch_opts = { .path = g_wdir, @@ -362,54 +369,84 @@ t_invoke_env(String8 exe_path, String8 cmdline, String8List env, U64 timeout, Ar // invoke exe Process process_handle = process_launch(&launch_opts); + if (process_match(process_handle, process_zero())) { goto exit; } // close handle so last to ReadFile does not block file_close(write_pipe_handle); - if ( ! process_match(process_handle, process_zero())) { - if (capture_output) { - // capture process output - String8List output = {0}; - for (;;) { - String8 string = file_read_cstring(scratch.arena, read_pipe_handle, 0); - if (string.size == 0) { break; } - str8_list_push(scratch.arena, &output, string); - } - file_close(read_pipe_handle); - - if (output_out) { - *output_out = str8_list_join(output_arena, &output, 0); - } - - // write to the output file - if (g_redirect_stdout) { - write_data_list_to_file_path(g_stdout_file_name, output); - } - } - - U64 exit_code_u64 = 0; - if (process_join(process_handle, timeout, &exit_code_u64)) { - g_last_exit_code = (int)exit_code_u64; - is_ok = 1; - } else { - process_kill(process_handle); - } + // capture process output + String8List output = {0}; + for (;;) { + String8 string = file_read_cstring(scratch.arena, read_pipe_handle, 0); + if (string.size == 0) { break; } + str8_list_push(scratch.arena, &output, string); + } + file_close(read_pipe_handle); + + // update output global + g_output = str8_list_join(g_output_arena, &output, 0); + + // write to the output file + if (g_redirect_stdout) { + write_data_list_to_file_path(g_stdout_file_name, output); + } + + U64 exit_code_u64 = 0; + if (process_join(process_handle, timeout, &exit_code_u64)) { + g_last_exit_code = (int)exit_code_u64; + is_ok = 1; + } else { + process_kill(process_handle); } + exit:; scratch_end(scratch); return is_ok; } internal B32 -t_invoke_(String8 exe_path, String8 cmdline, U64 timeout, Arena *output_arena, String8 *output_out) +t_invoke(String8 exe_path, String8 cmdline, U64 timeout) { - return t_invoke_env(exe_path, cmdline, (String8List){0}, timeout, output_arena, output_out); + return t_invoke_env(exe_path, cmdline, (String8List){0}, timeout); } internal B32 -t_invoke(String8 exe_path, String8 cmdline, U64 timeout) +t_invoke_cl(char *fmt, ...) { - return t_invoke_(exe_path, cmdline, timeout, 0, 0); + Temp scratch = scratch_begin(0,0); + va_list args; + va_start(args, fmt); + String8 cmdl = push_str8fv(scratch.arena, fmt, args); + va_end(args); + B32 is_ok = t_invoke(t_cl_path(), cmdl, max_U64); + scratch_end(scratch); + return is_ok; +} + +internal B32 +t_invoke_linkerf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0,0); + va_list args; + va_start(args, fmt); + String8 cmdl = push_str8fv(scratch.arena, fmt, args); + va_end(args); + B32 is_ok = t_invoke(t_radlink_path(), cmdl, max_U64); + scratch_end(scratch); + return is_ok; +} + +internal B32 +t_invoke_radbin(char *fmt, ...) +{ + Temp scratch = scratch_begin(0,0); + va_list args; + va_start(args, fmt); + String8 cmdl = push_str8fv(scratch.arena, fmt, args); + va_end(args); + B32 is_ok = t_invoke(t_radbin_path(), cmdl, max_U64); + scratch_end(scratch); + return is_ok; } internal void @@ -422,10 +459,10 @@ t_kill_all(String8 pattern) while (dmn_process_iter_next(scratch.arena, &it, &info)) { if (str8_match_wildcard(info.name, pattern, StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive)) { #if OS_WINDOWS - if (!t_invoke_(str8_lit("taskkill"), str8f(scratch.arena, "/PID %u /F", info.pid), max_U64, 0, 0)) { fprintf(stderr, "ERROR: failed to invoke taskkill\n"); } + if (!t_invoke(str8_lit("taskkill"), str8f(scratch.arena, "/PID %u /F", info.pid), max_U64)) { fprintf(stderr, "ERROR: failed to invoke taskkill\n"); } #elif OS_LINUX NotImplemented; // TODO: test - if (!t_invoke_(str8_lit("kill"), str8f(scratch.arena, " -9 %u", info.pid), max_U64, 0, 0)) { fprintf(stderr, "ERROR: failed to invoke kill\n"); } + if (!t_invoke(str8_lit("kill"), str8f(scratch.arena, " -9 %u", info.pid), max_U64)) { fprintf(stderr, "ERROR: failed to invoke kill\n"); } #else # error NotImplemented #endif @@ -703,7 +740,8 @@ t_entry_point(CmdLine *cmdline) g_verbose = cmd_line_has_flag(cmdline, str8_lit("verbose")); g_redirect_stdout = !cmd_line_has_flag(cmdline, str8_lit("print_stdout")); g_stop_on_first_fail_or_crash = !cmd_line_has_flag(cmdline, str8_lit("keep_going")); - + g_output_arena = arena_alloc(); + // default options when running under debugger #if OS_WINDOWS if (!cmd_line_has_flag(cmdline, str8_lit("print_stdout")) && IsDebuggerPresent()) { diff --git a/src/torture/torture.h b/src/torture/torture.h index f4742a2e..140ab95f 100644 --- a/src/torture/torture.h +++ b/src/torture/torture.h @@ -90,7 +90,13 @@ internal String8 t_radlink_path(void); internal String8 t_cwd_path(void); internal String8 t_src_path(void); -internal B32 t_invoke_(String8 exe_path, String8 cmdline, U64 timeout, Arena *output_arena, String8 *output_out); internal B32 t_invoke(String8 exe, String8 cmdline, U64 timeout); -#define t_invoke_cl(f, ...) t_invoke_(t_cl_path(), str8f(scratch.arena, f, ## __VA_ARGS__), max_U64, 0, 0) +internal B32 t_invoke_cl(char *fmt, ...); +internal B32 t_invoke_linkerf(char *fmt, ...); +internal B32 t_invoke_radbin(char *fmt, ...); internal void t_kill_all(String8 pattern); + +#define t_invoke_linker_timeout(c, t) T_Ok(t_invoke(g_linker, c, t)) +#define t_invoke_linker_timeoutf(t, f, ...) t_invoke_linker_timeout(push_str8f(arena, f, ##__VA_ARGS__), t) +#define t_invoke_linker(c) t_invoke_linker_timeout(c, max_U64) + diff --git a/src/torture/torture_d2r.c b/src/torture/torture_d2r.c index 7006a8b0..98b23d9f 100644 --- a/src/torture/torture_d2r.c +++ b/src/torture/torture_d2r.c @@ -32,7 +32,7 @@ d2r_rdi_from_dwarf_writer(Arena *arena, DW_Writer *writer) B32 was_pdb_deleted = delete_file_at_path(t_make_file_path(scratch.arena, str8_lit("a.pdb"))); Assert(was_pdb_deleted); - t_invoke_(t_radbin_path(), str8_lit("-rdi a.exe -out:a.rdi"), max_U64, 0, 0); + t_invoke(t_radbin_path(), str8_lit("-rdi a.exe -out:a.rdi"), max_U64); Assert(g_last_exit_code == 0); String8 raw_rdi = t_read_file(arena, str8_lit("a.rdi")); @@ -275,11 +275,9 @@ TEST(d2r_line_table) for EachElement(i, test_table) { for EachIndex(k, test_table[i].line_size) { - String8 cmd_line = str8f(arena, "-voff2line -voff:0x%llx a.rdi", test_table[i].voff + k); - String8 output = {0}; - t_invoke_(t_radbin_path(), cmd_line, max_U64, arena, &output); + t_invoke_radbin("-voff2line -voff:0x%llx a.rdi", test_table[i].voff + k); T_Ok(g_last_exit_code == 0); - T_MatchLinef(&output, "%S:%llu", test_table[i].file->path, test_table[i].ln); + T_MatchLinef(&g_output, "%S:%llu", test_table[i].file->path, test_table[i].ln); } } diff --git a/src/torture/torture_dbg.c b/src/torture/torture_dbg.c index c081dd5a..c3cbd477 100644 --- a/src/torture/torture_dbg.c +++ b/src/torture/torture_dbg.c @@ -33,10 +33,8 @@ t_dbg_send_cmd(String8 cmd, U64 timeout_us, Arena *reply_arena, RD_IpcReply *rep #endif // send command - String8 cmdline = str8f(scratch.arena, "--ipc --pid:%u %S", dbg_pid, cmd); - Arena *output_arena = reply_arena ? reply_arena : scratch.arena; - String8 output = {0}; - if (t_invoke_(t_raddbg_path(), cmdline, timeout_us, output_arena, &output) == 0) { goto exit; } + String8 cmdline = str8f(scratch.arena, "--ipc --pid:%u %S", dbg_pid, cmd); + if (t_invoke(t_raddbg_path(), cmdline, timeout_us) == 0) { goto exit; } B32 has_reply = 1; @@ -55,7 +53,9 @@ t_dbg_send_cmd(String8 cmd, U64 timeout_us, Arena *reply_arena, RD_IpcReply *rep if (has_reply) { // parse reply - RD_IpcReply reply = rd_ipc_mdesk_reply_from_string(output_arena, output); + Arena *a = reply_arena ? reply_arena : scratch.arena; + String8 reply_text = str8_copy(a, g_output); + RD_IpcReply reply = rd_ipc_mdesk_reply_from_string(a, reply_text); if (rd_ipc_reply_is_ok(&reply) == 0) { goto exit; } if (md_node_is_nil(reply.msg)) { goto exit; } if (reply_arena && reply_out) { *reply_out = reply; } @@ -111,7 +111,7 @@ t_dbg_stop_event(Arena *arena, T_DbgStopEvent *out, U64 timeout_us) // send status request RD_IpcReply reply = {0}; - if ( ! t_dbg_send_cmd(str8_lit("stop_event"), timeout_us, scratch.arena, &reply)) { goto exit; } + if ( ! t_dbg_send_cmd(str8_lit("stop_event"), timeout_us, arena ? arena : scratch.arena, &reply)) { goto exit; } // parse reply if ( ! rd_ipc_parse_b32 (reply.msg, str8_lit("ok"), &is_ok)) { AssertAlways(0); goto exit; } @@ -131,7 +131,7 @@ t_dbg_stop_event(Arena *arena, T_DbgStopEvent *out, U64 timeout_us) if ( ! rd_ipc_parse_int (reply.msg, str8_lit("tls_model"), &v.tls_model)) { AssertAlways(0); goto exit; } if ( ! rd_ipc_parse_string (reply.msg, str8_lit("stop_cause"), &v.stop_cause)) { AssertAlways(0); goto exit; } - if (out != 0) { *out = v; } + if (arena && out != 0) { *out = v; } exit:; return is_ok; @@ -223,7 +223,7 @@ t_dbg_send_cmd_and_wait_stop(String8 cmd, U64 timeout_us) } while (t > 0); //--- Status --------------------- - if (is_stopped) { + if (0 && is_stopped) { T_DbgStatus status = {0}; AssertAlways(t_dbg_status(&status, 0)); @@ -271,8 +271,9 @@ t_dbg_launch(String8 cmdline, U64 timeout_us) Temp scratch = scratch_begin(0, 0); B32 dbg_ready = 0; - String8 user_path = t_make_file_path(scratch.arena, str8_lit("test.raddbg_user")); - cmdline = str8f(scratch.arena, "--user:\"%S\" %S", user_path, cmdline); + String8 user_path = t_make_file_path(scratch.arena, str8_lit("test.raddbg_user")); + String8 project_path = t_make_file_path(scratch.arena, str8_lit("test.raddbg_project")); + cmdline = str8f(scratch.arena, "--user:\"%S\" --project:\"%S\" %S", user_path, project_path, cmdline); // launch debugger OS_ProcessLaunchParams launch_opts = { @@ -585,6 +586,10 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) case T_DbgScriptCmdKind_ClearBreakpoints: t_dbg_send_cmdf(0,0,0, "clear_breakpoints"); break; case T_DbgScriptCmdKind_Run: t_dbg_send_cmd(str8_lit("run"), timeout_us, 0, 0); break; case T_DbgScriptCmdKind_At: { + T_DbgStatus status = {0}; + AssertAlways(t_dbg_status(&status, 0)); + AssertAlways(status.running == 0); + // map IP -> source location U64 ip = u64_from_str8(t_dbg_value_from_exprf(scratch.arena, "reg:rip"), 10); T_DbgSourceLocation loc = {0}; diff --git a/src/torture/torture_radlink.c b/src/torture/torture_radlink.c index f19db27b..e21192ef 100644 --- a/src/torture/torture_radlink.c +++ b/src/torture/torture_radlink.c @@ -5011,14 +5011,15 @@ TEST(debug_p_sig_mismatch) T_Ok(t_write_file(str8_lit("b.obj"), b_obj)); T_Ok(t_write_entry_obj()); - String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full a.obj b.obj entry.obj"), max_U64, arena, &output); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:full a.obj b.obj entry.obj"); T_Ok(g_last_exit_code == 0); B32 found_error = 0; String8 a_obj_path = t_make_file_path(arena, str8_lit("a.obj")); String8 b_obj_path = t_make_file_path(arena, str8_lit("b.obj")); String8 expected_line = str8f(arena, "Error(%03d): %S: PCH signature mismatch, expected 0x%x got 0x%x; PCH obj %S", LNK_Error_PrecompSigMismatch, b_obj_path, b_sig, a_sig, a_obj_path); + + String8 output = g_output; while (output.size) { String8 line = t_chop_line(&output); found_error = str8_match(line, expected_line, StringMatchFlag_CaseInsensitive); @@ -5124,10 +5125,10 @@ TEST(debug_p_and_debug_t_in_obj) } })); T_Ok(t_write_entry_obj()); - String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full pch.obj entry.obj"), max_U64, arena, &output); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:full pch.obj entry.obj"); T_Ok(g_last_exit_code == 0); + String8 output = g_output; B32 found_warning = 0; String8 pch_obj_path = t_make_file_path(arena, str8_lit("pch.obj")); String8 expected_line = str8f(arena, "Warning(%03d): %S: multiple sections with debug types detected, obj must have either .debug$T or .debug$P; discarding both sections", LNK_Warning_MultipleDebugTAndDebugP, pch_obj_path); @@ -5531,12 +5532,11 @@ TEST(cyclic_type) T_Ok(t_write_entry_obj()); T_Ok(t_write_file(str8_lit("cycle.obj"), raw_coff)); - String8 cmd_line = str8f(arena, "/subsystem:console /entry:entry /out:a.exe /debug:full /rad_ignore:-%u cycle.obj entry.obj", LNK_Error_InvalidTypeIndex); - String8 output = {0}; - t_invoke_(t_radlink_path(), cmd_line, max_U64, arena, &output); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:full /rad_ignore:-%u cycle.obj entry.obj", LNK_Error_InvalidTypeIndex); T_Ok(g_last_exit_code == 0); - B32 is_cycle_detected = 0; + String8 output = g_output; + B32 is_cycle_detected = 0; while (output.size && !is_cycle_detected) { is_cycle_detected = t_match_linef(&output, "Error(043): %S: LF_POINTER(type_index: 0x1000) forward refs member type index 0x1001 (leaf struct offset: 0x0)", @@ -6006,14 +6006,13 @@ TEST(ghash_check_corrupt) T_Ok(t_write_file(str8_lit("debug.obj"), debug_obj)); T_Ok(t_write_entry_obj()); - String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"); T_Ok(g_last_exit_code == 0); B32 is_warning_found = 0; String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj")); String8 expected_line = str8f(arena, "Warning(%03u): %S: .debug$H section is too small to contain the header", LNK_Warning_GHash, debug_obj_path, LLVM_GHash_Magic); - for (String8 i = output; i.size > 0 && !is_warning_found; ) { + for (String8 i = g_output; i.size > 0 && !is_warning_found; ) { String8 line = t_chop_line(&i); is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive); } @@ -6056,14 +6055,13 @@ TEST(ghash_check_magic) T_Ok(t_write_file(str8_lit("debug.obj"), debug_obj)); T_Ok(t_write_entry_obj()); - String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"); T_Ok(g_last_exit_code == 0); B32 is_warning_found = 0; String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj")); String8 expected_line = str8f(arena, "Warning(%03u): %S: .debug$H contains invalid magic: got 0x7b, expected 0x%x", LNK_Warning_GHash, debug_obj_path, LLVM_GHash_Magic); - for (String8 i = output; i.size > 0 && !is_warning_found; ) { + for (String8 i = g_output; i.size > 0 && !is_warning_found; ) { String8 line = t_chop_line(&i); is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive); } @@ -6106,14 +6104,13 @@ TEST(ghash_check_version) T_Ok(t_write_file(str8_lit("debug.obj"), debug_obj)); T_Ok(t_write_entry_obj()); - String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"); T_Ok(g_last_exit_code == 0); B32 is_warning_found = 0; String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj")); String8 expected_line = str8f(arena, "Warning(%03u): %S: mismatched .debug$H version: got %u, expected %u", LNK_Warning_GHash, debug_obj_path, 0xbeef, LLVM_GHash_CurrentVersion); - for (String8 i = output; i.size > 0 && !is_warning_found; ) { + for (String8 i = g_output; i.size > 0 && !is_warning_found; ) { String8 line = t_chop_line(&i); is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive); } @@ -6148,14 +6145,13 @@ TEST(ghash_check_hash_alg) T_Ok(t_write_file(str8_lit("debug.obj"), debug_obj)); T_Ok(t_write_entry_obj()); - String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"); T_Ok(g_last_exit_code == 0); - B32 is_warning_found = 0; - String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj")); - String8 expected_line = str8f(arena, "Warning(%03u): %S: mismatched .debug$H hash algorithm: got SHA1_8, expected BALK3", LNK_Warning_GHash, debug_obj_path); - for (String8 i = output; i.size > 0 && !is_warning_found; ) { + B32 is_warning_found = 0; + String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj")); + String8 expected_line = str8f(arena, "Warning(%03u): %S: mismatched .debug$H hash algorithm: got SHA1_8, expected BALK3", LNK_Warning_GHash, debug_obj_path); + for (String8 i = g_output; i.size > 0 && !is_warning_found; ) { String8 line = t_chop_line(&i); is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive); } @@ -6191,13 +6187,13 @@ TEST(ghash_match_debug_t) T_Ok(t_write_entry_obj()); String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"); T_Ok(g_last_exit_code == 0); - B32 is_warning_found = 0; - String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj")); - String8 expected_line = str8f(arena, "Warning(%03u): %S: mismatched .debug$H hash count and type count: got 3 hashes for 2 types", LNK_Warning_GHash, debug_obj_path); - for (String8 i = output; i.size > 0 && !is_warning_found; ) { + B32 is_warning_found = 0; + String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj")); + String8 expected_line = str8f(arena, "Warning(%03u): %S: mismatched .debug$H hash count and type count: got 3 hashes for 2 types", LNK_Warning_GHash, debug_obj_path); + for (String8 i = g_output; i.size > 0 && !is_warning_found; ) { String8 line = t_chop_line(&i); is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive); } @@ -6426,18 +6422,17 @@ t_radlink_validate_asan_out(String8 obj_name) Temp scratch = scratch_begin(0,0); B32 is_ok = 0; - t_invoke_(t_radlink_path(), str8f(scratch.arena, "%S /debug:full", obj_name), max_U64, 0, 0); + t_invoke_linkerf("%S /debug:full", obj_name); if (g_last_exit_code != 0) { goto exit; } String8 exe_path = t_make_file_path(scratch.arena, str8f(scratch.arena, "%S.exe", str8_chop_last_dot(obj_name))); - String8 out = {0}; char *old_path_cstr = getenv("PATH"); String8List env = {0}; str8_list_pushf(scratch.arena, &env, "PATH=%S;%S", str8_chop_last_slash(t_cl_path()), str8_cstring(old_path_cstr)); - t_invoke_env(exe_path, str8_zero(), env, max_U64, scratch.arena, &out); + t_invoke_env(exe_path, str8_zero(), env, max_U64); - String8 s = out; + String8 s = g_output; String8 header = t_chop_line(&s); if ( ! str8_match(header, str8_lit("================================================================="), 0)) { @@ -6469,8 +6464,7 @@ TEST(infer_asan) // /MD { T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program))); - String8 cl_output = {0}; - t_invoke_(t_cl_path(), str8_lit("/MD /fsanitize=address /Z7 /c /Fo:main_md.obj main.c"), max_U64, arena, &cl_output); + t_invoke_cl("/MD /fsanitize=address /Z7 /c /Fo:main_md.obj main.c"); T_Ok(g_last_exit_code == 0); T_Ok(t_radlink_validate_asan_out(str8_lit("main_md.obj"))); } @@ -6478,8 +6472,7 @@ TEST(infer_asan) // /MDd { T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program))); - String8 cl_output = {0}; - t_invoke_(t_cl_path(), str8_lit("/MDd /fsanitize=address /Z7 /c /Fo:main_mdd.obj main.c"), max_U64, arena, &cl_output); + t_invoke_cl("/MDd /fsanitize=address /Z7 /c /Fo:main_mdd.obj main.c"); T_Ok(g_last_exit_code == 0); T_Ok(t_radlink_validate_asan_out(str8_lit("main_mdd.obj"))); } @@ -6487,8 +6480,7 @@ TEST(infer_asan) // /MT { T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program))); - String8 cl_output = {0}; - t_invoke_(t_cl_path(), str8_lit("/MT /fsanitize=address /Z7 /c /Fo:main_mt.obj main.c"), max_U64, arena, &cl_output); + t_invoke_cl("/MT /fsanitize=address /Z7 /c /Fo:main_mt.obj main.c"); T_Ok(g_last_exit_code == 0); T_Ok(t_radlink_validate_asan_out(str8_lit("main_mt.obj"))); } @@ -6496,8 +6488,7 @@ TEST(infer_asan) // /MTd { T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program))); - String8 cl_output = {0}; - t_invoke_(t_cl_path(), str8_lit("/MT /fsanitize=address /Z7 /c /Fo:main_mtd.obj main.c"), max_U64, arena, &cl_output); + t_invoke_cl("/MT /fsanitize=address /Z7 /c /Fo:main_mtd.obj main.c"); T_Ok(g_last_exit_code == 0); T_Ok(t_radlink_validate_asan_out(str8_lit("main_mtd.obj"))); } @@ -6509,9 +6500,7 @@ TEST(infer_asan) TEST(determ_test) { // compile the test target (torture) - String8 cl_line = str8f(arena, "/fsanitize=address /c /Z7 /Fo:test.obj -I%S /Zc:preprocessor %S/torture/torture_main.c", t_src_path(), t_src_path()); - String8 cl_out = {0}; - t_invoke_(t_cl_path(), cl_line, max_U64, arena, &cl_out); + t_invoke_cl("/fsanitize=address /c /Z7 /Fo:test.obj -I%S /Zc:preprocessor %S/torture/torture_main.c", t_src_path(), t_src_path()); T_Ok(g_last_exit_code == 0); U64 run_count = 25; diff --git a/src/torture/torture_radlink.h b/src/torture/torture_radlink.h index fcfd5820..53858548 100644 --- a/src/torture/torture_radlink.h +++ b/src/torture/torture_radlink.h @@ -22,11 +22,6 @@ typedef enum //////////////////////////////// -#define t_invoke_linker_timeout(c, t) T_Ok(t_invoke(g_linker, c, t)) -#define t_invoke_linker_timeoutf(t, f, ...) t_invoke_linker_timeout(push_str8f(arena, f, ##__VA_ARGS__), t) -#define t_invoke_linker(c) t_invoke_linker_timeout(c, max_U64) -#define t_invoke_linkerf(f, ...) t_invoke_linker(push_str8f(arena, f, ##__VA_ARGS__)) - internal T_Linker t_id_linker(void); internal COFF_ObjSection * t_push_text_section(COFF_ObjWriter *obj_writer, String8 data);