mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-14 17:28:07 +00:00
print out last captured output when a test fails or crashes
This commit is contained in:
committed by
Ryan Fleury
parent
a645622b10
commit
887ee21d94
+68
-30
@@ -17,6 +17,8 @@ T_Test g_torture_tests[0xffffff];
|
|||||||
|
|
||||||
// invoke
|
// invoke
|
||||||
global int g_last_exit_code;
|
global int g_last_exit_code;
|
||||||
|
global Arena *g_output_arena;
|
||||||
|
global String8 g_output;
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
t_test_name_from_idx(Arena *arena, U64 test_idx)
|
t_test_name_from_idx(Arena *arena, U64 test_idx)
|
||||||
@@ -180,6 +182,11 @@ t_run(T_Run run, String8 user_data)
|
|||||||
} else {
|
} else {
|
||||||
t_run_caller(&ctx);
|
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;
|
return ctx.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,19 +236,18 @@ t_cl_version(void)
|
|||||||
if ( ! version.size) {
|
if ( ! version.size) {
|
||||||
Temp scratch = scratch_begin(0, 0);
|
Temp scratch = scratch_begin(0, 0);
|
||||||
|
|
||||||
String8 output = {0};
|
t_invoke_cl("");
|
||||||
t_invoke_(t_cl_path(), str8_zero(), max_U64, scratch.arena, &output);
|
|
||||||
AssertAlways(g_last_exit_code == 0);
|
AssertAlways(g_last_exit_code == 0);
|
||||||
|
|
||||||
String8 needle = str8_lit("Version");
|
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;
|
version_lo += needle.size + 1;
|
||||||
AssertAlways(version_lo < output.size);
|
AssertAlways(version_lo < g_output.size);
|
||||||
|
|
||||||
U64 version_hi = str8_find_needle(output, version_lo, str8_lit(" "), 0);
|
U64 version_hi = str8_find_needle(g_output, version_lo, str8_lit(" "), 0);
|
||||||
AssertAlways(version_hi < output.size);
|
AssertAlways(version_hi < g_output.size);
|
||||||
|
|
||||||
version = str8_substr(output, r1u64(version_lo, version_hi));
|
version = str8_substr(g_output, r1u64(version_lo, version_hi));
|
||||||
AssertAlways(version.size > 0);
|
AssertAlways(version.size > 0);
|
||||||
|
|
||||||
local_persist U8 buffer[4096];
|
local_persist U8 buffer[4096];
|
||||||
@@ -249,6 +255,7 @@ t_cl_version(void)
|
|||||||
Arena *arena = arena_alloc_(¶ms);
|
Arena *arena = arena_alloc_(¶ms);
|
||||||
version = str8_copy(arena, version);
|
version = str8_copy(arena, version);
|
||||||
|
|
||||||
|
MemoryZeroStruct(&g_output);
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,27 +329,27 @@ t_src_path(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal B32
|
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 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;
|
g_last_exit_code = -1;
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
File read_pipe_handle = {0}, write_pipe_handle = {0};
|
File read_pipe_handle = {0}, write_pipe_handle = {0};
|
||||||
if (capture_output) {
|
|
||||||
HANDLE read_pipe, write_pipe;
|
HANDLE read_pipe, write_pipe;
|
||||||
SECURITY_ATTRIBUTES at = { .nLength = sizeof(at), .bInheritHandle = 1 };
|
SECURITY_ATTRIBUTES at = { .nLength = sizeof(at), .bInheritHandle = 1 };
|
||||||
if (!CreatePipe(&read_pipe, &write_pipe, &at, 0)) {
|
if (!CreatePipe(&read_pipe, &write_pipe, &at, 0)) { AssertAlways(0 && "failed to create a pipe"); }
|
||||||
AssertAlways(0 && "failed to create a pipe");
|
|
||||||
}
|
|
||||||
read_pipe_handle = (File){ .u64[0] = (U64)read_pipe };
|
read_pipe_handle = (File){ .u64[0] = (U64)read_pipe };
|
||||||
write_pipe_handle = (File){ .u64[0] = (U64)write_pipe };
|
write_pipe_handle = (File){ .u64[0] = (U64)write_pipe };
|
||||||
}
|
#else
|
||||||
|
# error NotImplemented
|
||||||
|
#endif
|
||||||
// Build Launch Options
|
// Build Launch Options
|
||||||
ProcessLaunchParams launch_opts = {
|
ProcessLaunchParams launch_opts = {
|
||||||
.path = g_wdir,
|
.path = g_wdir,
|
||||||
@@ -362,12 +369,11 @@ t_invoke_env(String8 exe_path, String8 cmdline, String8List env, U64 timeout, Ar
|
|||||||
|
|
||||||
// invoke exe
|
// invoke exe
|
||||||
Process process_handle = process_launch(&launch_opts);
|
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
|
// close handle so last to ReadFile does not block
|
||||||
file_close(write_pipe_handle);
|
file_close(write_pipe_handle);
|
||||||
|
|
||||||
if ( ! process_match(process_handle, process_zero())) {
|
|
||||||
if (capture_output) {
|
|
||||||
// capture process output
|
// capture process output
|
||||||
String8List output = {0};
|
String8List output = {0};
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -377,15 +383,13 @@ t_invoke_env(String8 exe_path, String8 cmdline, String8List env, U64 timeout, Ar
|
|||||||
}
|
}
|
||||||
file_close(read_pipe_handle);
|
file_close(read_pipe_handle);
|
||||||
|
|
||||||
if (output_out) {
|
// update output global
|
||||||
*output_out = str8_list_join(output_arena, &output, 0);
|
g_output = str8_list_join(g_output_arena, &output, 0);
|
||||||
}
|
|
||||||
|
|
||||||
// write to the output file
|
// write to the output file
|
||||||
if (g_redirect_stdout) {
|
if (g_redirect_stdout) {
|
||||||
write_data_list_to_file_path(g_stdout_file_name, output);
|
write_data_list_to_file_path(g_stdout_file_name, output);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
U64 exit_code_u64 = 0;
|
U64 exit_code_u64 = 0;
|
||||||
if (process_join(process_handle, timeout, &exit_code_u64)) {
|
if (process_join(process_handle, timeout, &exit_code_u64)) {
|
||||||
@@ -394,22 +398,55 @@ t_invoke_env(String8 exe_path, String8 cmdline, String8List env, U64 timeout, Ar
|
|||||||
} else {
|
} else {
|
||||||
process_kill(process_handle);
|
process_kill(process_handle);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
exit:;
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
return is_ok;
|
return is_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal B32
|
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
|
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
|
internal void
|
||||||
@@ -422,10 +459,10 @@ t_kill_all(String8 pattern)
|
|||||||
while (dmn_process_iter_next(scratch.arena, &it, &info)) {
|
while (dmn_process_iter_next(scratch.arena, &it, &info)) {
|
||||||
if (str8_match_wildcard(info.name, pattern, StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive)) {
|
if (str8_match_wildcard(info.name, pattern, StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive)) {
|
||||||
#if OS_WINDOWS
|
#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
|
#elif OS_LINUX
|
||||||
NotImplemented; // TODO: test
|
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
|
#else
|
||||||
# error NotImplemented
|
# error NotImplemented
|
||||||
#endif
|
#endif
|
||||||
@@ -703,6 +740,7 @@ t_entry_point(CmdLine *cmdline)
|
|||||||
g_verbose = cmd_line_has_flag(cmdline, str8_lit("verbose"));
|
g_verbose = cmd_line_has_flag(cmdline, str8_lit("verbose"));
|
||||||
g_redirect_stdout = !cmd_line_has_flag(cmdline, str8_lit("print_stdout"));
|
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_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
|
// default options when running under debugger
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
|||||||
@@ -90,7 +90,13 @@ internal String8 t_radlink_path(void);
|
|||||||
internal String8 t_cwd_path(void);
|
internal String8 t_cwd_path(void);
|
||||||
internal String8 t_src_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);
|
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);
|
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)
|
||||||
|
|
||||||
|
|||||||
@@ -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")));
|
B32 was_pdb_deleted = delete_file_at_path(t_make_file_path(scratch.arena, str8_lit("a.pdb")));
|
||||||
Assert(was_pdb_deleted);
|
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);
|
Assert(g_last_exit_code == 0);
|
||||||
|
|
||||||
String8 raw_rdi = t_read_file(arena, str8_lit("a.rdi"));
|
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 EachElement(i, test_table) {
|
||||||
for EachIndex(k, test_table[i].line_size) {
|
for EachIndex(k, test_table[i].line_size) {
|
||||||
String8 cmd_line = str8f(arena, "-voff2line -voff:0x%llx a.rdi", test_table[i].voff + k);
|
t_invoke_radbin("-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_Ok(g_last_exit_code == 0);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,9 +34,7 @@ t_dbg_send_cmd(String8 cmd, U64 timeout_us, Arena *reply_arena, RD_IpcReply *rep
|
|||||||
|
|
||||||
// send command
|
// send command
|
||||||
String8 cmdline = str8f(scratch.arena, "--ipc --pid:%u %S", dbg_pid, cmd);
|
String8 cmdline = str8f(scratch.arena, "--ipc --pid:%u %S", dbg_pid, cmd);
|
||||||
Arena *output_arena = reply_arena ? reply_arena : scratch.arena;
|
if (t_invoke(t_raddbg_path(), cmdline, timeout_us) == 0) { goto exit; }
|
||||||
String8 output = {0};
|
|
||||||
if (t_invoke_(t_raddbg_path(), cmdline, timeout_us, output_arena, &output) == 0) { goto exit; }
|
|
||||||
|
|
||||||
B32 has_reply = 1;
|
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) {
|
if (has_reply) {
|
||||||
// parse 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 (rd_ipc_reply_is_ok(&reply) == 0) { goto exit; }
|
||||||
if (md_node_is_nil(reply.msg)) { goto exit; }
|
if (md_node_is_nil(reply.msg)) { goto exit; }
|
||||||
if (reply_arena && reply_out) { *reply_out = reply; }
|
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
|
// send status request
|
||||||
RD_IpcReply reply = {0};
|
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
|
// parse reply
|
||||||
if ( ! rd_ipc_parse_b32 (reply.msg, str8_lit("ok"), &is_ok)) { AssertAlways(0); goto exit; }
|
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_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 ( ! 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:;
|
exit:;
|
||||||
return is_ok;
|
return is_ok;
|
||||||
@@ -223,7 +223,7 @@ t_dbg_send_cmd_and_wait_stop(String8 cmd, U64 timeout_us)
|
|||||||
} while (t > 0);
|
} while (t > 0);
|
||||||
|
|
||||||
//--- Status ---------------------
|
//--- Status ---------------------
|
||||||
if (is_stopped) {
|
if (0 && is_stopped) {
|
||||||
T_DbgStatus status = {0};
|
T_DbgStatus status = {0};
|
||||||
AssertAlways(t_dbg_status(&status, 0));
|
AssertAlways(t_dbg_status(&status, 0));
|
||||||
|
|
||||||
@@ -272,7 +272,8 @@ t_dbg_launch(String8 cmdline, U64 timeout_us)
|
|||||||
B32 dbg_ready = 0;
|
B32 dbg_ready = 0;
|
||||||
|
|
||||||
String8 user_path = t_make_file_path(scratch.arena, str8_lit("test.raddbg_user"));
|
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 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
|
// launch debugger
|
||||||
OS_ProcessLaunchParams launch_opts = {
|
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_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_Run: t_dbg_send_cmd(str8_lit("run"), timeout_us, 0, 0); break;
|
||||||
case T_DbgScriptCmdKind_At: {
|
case T_DbgScriptCmdKind_At: {
|
||||||
|
T_DbgStatus status = {0};
|
||||||
|
AssertAlways(t_dbg_status(&status, 0));
|
||||||
|
AssertAlways(status.running == 0);
|
||||||
|
|
||||||
// map IP -> source location
|
// map IP -> source location
|
||||||
U64 ip = u64_from_str8(t_dbg_value_from_exprf(scratch.arena, "reg:rip"), 10);
|
U64 ip = u64_from_str8(t_dbg_value_from_exprf(scratch.arena, "reg:rip"), 10);
|
||||||
T_DbgSourceLocation loc = {0};
|
T_DbgSourceLocation loc = {0};
|
||||||
|
|||||||
@@ -5011,14 +5011,15 @@ TEST(debug_p_sig_mismatch)
|
|||||||
T_Ok(t_write_file(str8_lit("b.obj"), b_obj));
|
T_Ok(t_write_file(str8_lit("b.obj"), b_obj));
|
||||||
T_Ok(t_write_entry_obj());
|
T_Ok(t_write_entry_obj());
|
||||||
|
|
||||||
String8 output = {0};
|
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:full a.obj b.obj entry.obj");
|
||||||
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_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
|
|
||||||
B32 found_error = 0;
|
B32 found_error = 0;
|
||||||
String8 a_obj_path = t_make_file_path(arena, str8_lit("a.obj"));
|
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 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 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) {
|
while (output.size) {
|
||||||
String8 line = t_chop_line(&output);
|
String8 line = t_chop_line(&output);
|
||||||
found_error = str8_match(line, expected_line, StringMatchFlag_CaseInsensitive);
|
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());
|
T_Ok(t_write_entry_obj());
|
||||||
String8 output = {0};
|
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:full pch.obj entry.obj");
|
||||||
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_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
|
|
||||||
|
String8 output = g_output;
|
||||||
B32 found_warning = 0;
|
B32 found_warning = 0;
|
||||||
String8 pch_obj_path = t_make_file_path(arena, str8_lit("pch.obj"));
|
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);
|
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,11 +5532,10 @@ TEST(cyclic_type)
|
|||||||
T_Ok(t_write_entry_obj());
|
T_Ok(t_write_entry_obj());
|
||||||
T_Ok(t_write_file(str8_lit("cycle.obj"), raw_coff));
|
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);
|
t_invoke_linkerf("/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_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
|
|
||||||
|
String8 output = g_output;
|
||||||
B32 is_cycle_detected = 0;
|
B32 is_cycle_detected = 0;
|
||||||
while (output.size && !is_cycle_detected) {
|
while (output.size && !is_cycle_detected) {
|
||||||
is_cycle_detected = t_match_linef(&output,
|
is_cycle_detected = t_match_linef(&output,
|
||||||
@@ -6006,14 +6006,13 @@ TEST(ghash_check_corrupt)
|
|||||||
T_Ok(t_write_file(str8_lit("debug.obj"), debug_obj));
|
T_Ok(t_write_file(str8_lit("debug.obj"), debug_obj));
|
||||||
T_Ok(t_write_entry_obj());
|
T_Ok(t_write_entry_obj());
|
||||||
|
|
||||||
String8 output = {0};
|
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj");
|
||||||
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_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
|
|
||||||
B32 is_warning_found = 0;
|
B32 is_warning_found = 0;
|
||||||
String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj"));
|
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);
|
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);
|
String8 line = t_chop_line(&i);
|
||||||
is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive);
|
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_file(str8_lit("debug.obj"), debug_obj));
|
||||||
T_Ok(t_write_entry_obj());
|
T_Ok(t_write_entry_obj());
|
||||||
|
|
||||||
String8 output = {0};
|
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj");
|
||||||
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_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
|
|
||||||
B32 is_warning_found = 0;
|
B32 is_warning_found = 0;
|
||||||
String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj"));
|
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);
|
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);
|
String8 line = t_chop_line(&i);
|
||||||
is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive);
|
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_file(str8_lit("debug.obj"), debug_obj));
|
||||||
T_Ok(t_write_entry_obj());
|
T_Ok(t_write_entry_obj());
|
||||||
|
|
||||||
String8 output = {0};
|
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj");
|
||||||
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_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
|
|
||||||
B32 is_warning_found = 0;
|
B32 is_warning_found = 0;
|
||||||
String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj"));
|
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);
|
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);
|
String8 line = t_chop_line(&i);
|
||||||
is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive);
|
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_file(str8_lit("debug.obj"), debug_obj));
|
||||||
T_Ok(t_write_entry_obj());
|
T_Ok(t_write_entry_obj());
|
||||||
|
|
||||||
String8 output = {0};
|
t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj");
|
||||||
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_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
|
|
||||||
B32 is_warning_found = 0;
|
B32 is_warning_found = 0;
|
||||||
String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj"));
|
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);
|
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; ) {
|
for (String8 i = g_output; i.size > 0 && !is_warning_found; ) {
|
||||||
String8 line = t_chop_line(&i);
|
String8 line = t_chop_line(&i);
|
||||||
is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive);
|
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());
|
T_Ok(t_write_entry_obj());
|
||||||
|
|
||||||
String8 output = {0};
|
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);
|
T_Ok(g_last_exit_code == 0);
|
||||||
|
|
||||||
B32 is_warning_found = 0;
|
B32 is_warning_found = 0;
|
||||||
String8 debug_obj_path = t_make_file_path(arena, str8_lit("debug.obj"));
|
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);
|
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; ) {
|
for (String8 i = g_output; i.size > 0 && !is_warning_found; ) {
|
||||||
String8 line = t_chop_line(&i);
|
String8 line = t_chop_line(&i);
|
||||||
is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive);
|
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);
|
Temp scratch = scratch_begin(0,0);
|
||||||
B32 is_ok = 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; }
|
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 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");
|
char *old_path_cstr = getenv("PATH");
|
||||||
String8List env = {0};
|
String8List env = {0};
|
||||||
str8_list_pushf(scratch.arena, &env, "PATH=%S;%S", str8_chop_last_slash(t_cl_path()), str8_cstring(old_path_cstr));
|
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);
|
String8 header = t_chop_line(&s);
|
||||||
if ( ! str8_match(header, str8_lit("================================================================="), 0)) {
|
if ( ! str8_match(header, str8_lit("================================================================="), 0)) {
|
||||||
@@ -6469,8 +6464,7 @@ TEST(infer_asan)
|
|||||||
// /MD
|
// /MD
|
||||||
{
|
{
|
||||||
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
||||||
String8 cl_output = {0};
|
t_invoke_cl("/MD /fsanitize=address /Z7 /c /Fo:main_md.obj main.c");
|
||||||
t_invoke_(t_cl_path(), str8_lit("/MD /fsanitize=address /Z7 /c /Fo:main_md.obj main.c"), max_U64, arena, &cl_output);
|
|
||||||
T_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
T_Ok(t_radlink_validate_asan_out(str8_lit("main_md.obj")));
|
T_Ok(t_radlink_validate_asan_out(str8_lit("main_md.obj")));
|
||||||
}
|
}
|
||||||
@@ -6478,8 +6472,7 @@ TEST(infer_asan)
|
|||||||
// /MDd
|
// /MDd
|
||||||
{
|
{
|
||||||
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
||||||
String8 cl_output = {0};
|
t_invoke_cl("/MDd /fsanitize=address /Z7 /c /Fo:main_mdd.obj main.c");
|
||||||
t_invoke_(t_cl_path(), str8_lit("/MDd /fsanitize=address /Z7 /c /Fo:main_mdd.obj main.c"), max_U64, arena, &cl_output);
|
|
||||||
T_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
T_Ok(t_radlink_validate_asan_out(str8_lit("main_mdd.obj")));
|
T_Ok(t_radlink_validate_asan_out(str8_lit("main_mdd.obj")));
|
||||||
}
|
}
|
||||||
@@ -6487,8 +6480,7 @@ TEST(infer_asan)
|
|||||||
// /MT
|
// /MT
|
||||||
{
|
{
|
||||||
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
||||||
String8 cl_output = {0};
|
t_invoke_cl("/MT /fsanitize=address /Z7 /c /Fo:main_mt.obj main.c");
|
||||||
t_invoke_(t_cl_path(), str8_lit("/MT /fsanitize=address /Z7 /c /Fo:main_mt.obj main.c"), max_U64, arena, &cl_output);
|
|
||||||
T_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
T_Ok(t_radlink_validate_asan_out(str8_lit("main_mt.obj")));
|
T_Ok(t_radlink_validate_asan_out(str8_lit("main_mt.obj")));
|
||||||
}
|
}
|
||||||
@@ -6496,8 +6488,7 @@ TEST(infer_asan)
|
|||||||
// /MTd
|
// /MTd
|
||||||
{
|
{
|
||||||
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
||||||
String8 cl_output = {0};
|
t_invoke_cl("/MT /fsanitize=address /Z7 /c /Fo:main_mtd.obj main.c");
|
||||||
t_invoke_(t_cl_path(), str8_lit("/MT /fsanitize=address /Z7 /c /Fo:main_mtd.obj main.c"), max_U64, arena, &cl_output);
|
|
||||||
T_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
T_Ok(t_radlink_validate_asan_out(str8_lit("main_mtd.obj")));
|
T_Ok(t_radlink_validate_asan_out(str8_lit("main_mtd.obj")));
|
||||||
}
|
}
|
||||||
@@ -6509,9 +6500,7 @@ TEST(infer_asan)
|
|||||||
TEST(determ_test)
|
TEST(determ_test)
|
||||||
{
|
{
|
||||||
// compile the test target (torture)
|
// 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());
|
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());
|
||||||
String8 cl_out = {0};
|
|
||||||
t_invoke_(t_cl_path(), cl_line, max_U64, arena, &cl_out);
|
|
||||||
T_Ok(g_last_exit_code == 0);
|
T_Ok(g_last_exit_code == 0);
|
||||||
|
|
||||||
U64 run_count = 25;
|
U64 run_count = 25;
|
||||||
|
|||||||
@@ -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 T_Linker t_id_linker(void);
|
||||||
|
|
||||||
internal COFF_ObjSection * t_push_text_section(COFF_ObjWriter *obj_writer, String8 data);
|
internal COFF_ObjSection * t_push_text_section(COFF_ObjWriter *obj_writer, String8 data);
|
||||||
|
|||||||
Reference in New Issue
Block a user