From 09afff7957ae7054d43e83fbbd868a5a02824d8d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 20 May 2026 17:27:21 -0700 Subject: [PATCH] improve error handling in the debugger harness (source file + line number for error reports and allow scripts without header) --- src/torture/torture.c | 61 +++++++++-- src/torture/torture.h | 18 +++- src/torture/torture_dbg.c | 215 ++++++++++++++++++++++---------------- src/torture/torture_dbg.h | 2 + 4 files changed, 193 insertions(+), 103 deletions(-) diff --git a/src/torture/torture.c b/src/torture/torture.c index 754c05b4..66e65d64 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -14,6 +14,7 @@ global String8 g_test_data; U64 g_torture_test_count; T_Test **g_torture_tests; T_Test g_torture_tests_[0xffffff]; +B32 g_is_first_print; // invoke global U64 g_last_exit_code; @@ -159,21 +160,27 @@ internal void t_run_caller(void *raw_ctx) { Temp scratch = scratch_begin(0,0); + + g_is_first_print = 1; + T_RunCtx *ctx = raw_ctx; - String8List test_out = {0}; ctx->result.status = T_RunStatus_Pass; + + String8List test_out = {0}; ctx->run(scratch.arena, ctx->user_data, &ctx->result, &test_out); + if (ctx->result.status == T_RunStatus_Fail || ctx->result.status == T_RunStatus_Crash) { for EachNode(n, String8Node, test_out.first) { - fprintf(stderr, "%.*s", str8_varg(n->string)); + t_errorf("%S", n->string); } if (g_errors.size) { - fprintf(stderr, "stderr: \"%.*s\"\n", str8_varg(g_errors)); + t_errorf("stderr: \"%S\"\n", g_errors); } if (g_output.size) { - fprintf(stderr, "stdout: \"%.*s\"\n", str8_varg(g_output)); + t_errorf("stdout: \"%S\"\n", g_output); } } + scratch_end(scratch); } @@ -479,11 +486,7 @@ t_invoke_env(String8 exe_path, String8 cmdline, String8List env, U64 timeout_us) }; str8_list_push_front(scratch.arena, &launch_opts.cmd_line, exe_path); - if (g_verbose) { - String8 full_cmd_line = str8_list_join(scratch.arena, &launch_opts.cmd_line, &(StringJoin){ .sep = str8_lit(" ") }); - fprintf(stdout, "Command Line: %.*s\n", str8_varg(full_cmd_line)); - fprintf(stdout, "Working Dir: %.*s\n", str8_varg(g_wdir)); - } + String8 full_cmd_line = str8_list_join(scratch.arena, &launch_opts.cmd_line, &(StringJoin){ .sep = str8_lit(" ") }); // invoke exe Process process_handle = process_launch(&launch_opts); @@ -757,6 +760,12 @@ t_invoke_env(String8 exe_path, String8 cmdline, String8List env, U64 timeout_us) } #endif + t_infof("Invoke: {\n"); + t_infof(" CMDL: %S\n", full_cmd_line); + t_infof(" WDIR: %S\n", g_wdir); + t_infof(" Exit: %u\n", g_last_exit_code); + t_infof("}\n"); + // update output global g_output = str8_list_join(g_output_arena, &stdout_parts, 0); g_errors = str8_list_join(g_output_arena, &stderr_parts, 0); @@ -971,6 +980,40 @@ t_match_folders(String8 a, String8 b) return is_match; } +internal void +t_infof(char *fmt, ...) +{ + if (g_verbose) { + Temp scratch = scratch_begin(0,0); + va_list args; + va_start(args, fmt); + String8 result = push_str8fv(scratch.arena, fmt, args); + if (g_is_first_print) { + g_is_first_print = 0; + fprintf(stderr, "\n"); + } + fprintf(stderr, "%.*s", str8_varg(result)); + va_end(args); + scratch_end(scratch); + } +} + +internal void +t_errorf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0,0); + va_list args; + va_start(args, fmt); + String8 result = push_str8fv(scratch.arena, fmt, args); + if (g_is_first_print) { + g_is_first_print = 0; + fprintf(stderr, "\n"); + } + fprintf(stderr, "%.*s", str8_varg(result)); + va_end(args); + scratch_end(scratch); +} + internal void t_entry_point(CmdLine *cmdline) { diff --git a/src/torture/torture.h b/src/torture/torture.h index 9007056c..80a5995d 100644 --- a/src/torture/torture.h +++ b/src/torture/torture.h @@ -101,7 +101,7 @@ internal void t_break_if_debugger_present(void); #define ENDT_MS(x) TIMEOUT_US((x)*1000ull) #define ENDT_SEC(x) TIMEOUT_MS((x)*1000ull) -//////////////////////////////// +//////////////////////////////////////////////////////////////// // output directory internal B32 t_write_file_list(String8 name, String8List data); @@ -115,6 +115,7 @@ internal void t_run_caller(void *raw_ctx); internal void t_run_fail_handler(void *raw_ctx); internal T_RunResult t_run(T_Run run, String8 user_data); +// tools internal String8 t_radbin_path(void); internal String8 t_cl_path(void); internal String8 t_clang_path(void); @@ -128,7 +129,20 @@ 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(t_radlink_path(), 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) + +internal void t_kill_all(String8 pattern); + +internal String8 t_chop_line(String8 *string); +internal B32 t_match_line(String8 *output, String8 expected_line); +internal B32 t_match_linef(String8 *output, char *fmt, ...); + +// files helper +internal String8List t_file_paths_from_dir(Arena *arena, String8 dir); + +// printer +internal void t_infof(char *fmt, ...); +internal void t_errorf(char *fmt, ...); + diff --git a/src/torture/torture_dbg.c b/src/torture/torture_dbg.c index e60d1591..b52c8880 100644 --- a/src/torture/torture_dbg.c +++ b/src/torture/torture_dbg.c @@ -86,15 +86,15 @@ t_dbg_status(T_DbgStatus *status_out, U64 timeout_us) if ( ! t_dbg_send_cmd(str8_lit("status"), timeout_us, scratch.arena, &reply)) { goto exit; } // parse reply - if ( ! rd_ipc_parse_b32(reply.msg, str8_lit("ok"), &is_ok)) { fprintf(stderr, "ERROR: failed to parse reply member: ok\n"); Assert(0); goto exit; } - if ( ! rd_ipc_parse_b32(reply.msg, str8_lit("running"), &status.running)) { fprintf(stderr, "ERROR: failed to parse reply member: running\n"); Assert(0); goto exit; } - if ( ! rd_ipc_parse_int(reply.msg, str8_lit("run_gen"), &status.run_gen)) { fprintf(stderr, "ERROR: failed to parse reply member: run_gen\n"); Assert(0); goto exit; } - if ( ! rd_ipc_parse_int(reply.msg, str8_lit("ip"), &status.ip)) { fprintf(stderr, "ERROR: failed to parse reply member: ip\n"); Assert(0); goto exit; } + if ( ! rd_ipc_parse_b32(reply.msg, str8_lit("ok"), &is_ok)) { t_errorf("ERROR: failed to parse reply member: ok\n"); Assert(0); goto exit; } + if ( ! rd_ipc_parse_b32(reply.msg, str8_lit("running"), &status.running)) { t_errorf("ERROR: failed to parse reply member: running\n"); Assert(0); goto exit; } + if ( ! rd_ipc_parse_int(reply.msg, str8_lit("run_gen"), &status.run_gen)) { t_errorf("ERROR: failed to parse reply member: run_gen\n"); Assert(0); goto exit; } + if ( ! rd_ipc_parse_int(reply.msg, str8_lit("ip"), &status.ip)) { t_errorf("ERROR: failed to parse reply member: ip\n"); Assert(0); goto exit; } if (status_out != 0) { *status_out = status; } exit:; if ( ! is_ok && reply.parse.root) { - fprintf(stderr, "\tReply: %.*s\n", str8_varg(reply.parse.root->raw_string)); + t_errorf("\tReply: %S\n", reply.parse.root->raw_string); } scratch_end(scratch); return is_ok; @@ -319,10 +319,10 @@ t_dbg_eval(Arena *arena, String8 expr, T_Eval *eval_out) B32 is_ok = t_dbg_send_cmd(cmd, T_Dbg_DefaultTimeout, arena, &reply); T_Eval e = {0}; - if ( ! rd_ipc_parse_string(reply.msg, str8_lit("expr"), &e.expr)) { fprintf(stderr, "ERROR: failed to parse reply member: expr\n"); Assert(0); goto exit; } - if ( ! rd_ipc_parse_string(reply.msg, str8_lit("value"), &e.value)) { fprintf(stderr, "ERROR: failed to parse reply member: value\n"); Assert(0); goto exit; } - if ( ! rd_ipc_parse_string(reply.msg, str8_lit("type"), &e.type)) { fprintf(stderr, "ERROR: failed to parse reply member: type\n"); Assert(0); goto exit; } - if ( ! rd_ipc_parse_string(reply.msg, str8_lit("error"), &e.error)) { fprintf(stderr, "ERROR: failed to parse reply member: error\n"); Assert(0); goto exit; } + if ( ! rd_ipc_parse_string(reply.msg, str8_lit("expr"), &e.expr)) { t_errorf("ERROR: failed to parse reply member: expr\n"); Assert(0); goto exit; } + if ( ! rd_ipc_parse_string(reply.msg, str8_lit("value"), &e.value)) { t_errorf("ERROR: failed to parse reply member: value\n"); Assert(0); goto exit; } + if ( ! rd_ipc_parse_string(reply.msg, str8_lit("type"), &e.type)) { t_errorf("ERROR: failed to parse reply member: type\n"); Assert(0); goto exit; } + if ( ! rd_ipc_parse_string(reply.msg, str8_lit("error"), &e.error)) { t_errorf("ERROR: failed to parse reply member: error\n"); Assert(0); goto exit; } if (eval_out) { *eval_out = e; } exit:; @@ -346,29 +346,44 @@ t_dbg_script_program_is_before(void *raw_a, void *raw_b) return t_dbg_script_program_compar(raw_a, raw_b) < 0; } +internal String8 +t_string_from_dbg_script_cmd_kind(T_DbgScriptCmdKind v) +{ + switch (v) { + case T_DbgScriptCmdKind_Null: return str8_zero(); + case T_DbgScriptCmdKind_Breakpoint: return str8_lit("bp"); + case T_DbgScriptCmdKind_ClearBreakpoints: return str8_lit("bp_clear"); + case T_DbgScriptCmdKind_Run: return str8_lit("run"); + case T_DbgScriptCmdKind_Halt: return str8_lit("halt"); + case T_DbgScriptCmdKind_StepOver: return str8_lit("step_over"); + case T_DbgScriptCmdKind_StepInto: return str8_lit("step_into"); + case T_DbgScriptCmdKind_StepOut: return str8_lit("step_out"); + case T_DbgScriptCmdKind_StepOverInst: return str8_lit("step_over_inst"); + case T_DbgScriptCmdKind_StepIntoInst: return str8_lit("step_into_inst"); + case T_DbgScriptCmdKind_StepOverLine: return str8_lit("step_over_line"); + case T_DbgScriptCmdKind_StepIntoLine: return str8_lit("step_into_line"); + case T_DbgScriptCmdKind_KillAll: return str8_lit("kill_all"); + case T_DbgScriptCmdKind_At: return str8_lit("at"); + case T_DbgScriptCmdKind_Eval: return str8_lit("eval"); + default: InvalidPath; + } + return str8_zero(); +} + internal T_DbgScriptCmdKind t_dbg_script_cmd_kind_from_string(String8 cmd) { - if (str8_matchi(cmd, str8_lit("bp"))) { return T_DbgScriptCmdKind_Breakpoint; } - else if (str8_matchi(cmd, str8_lit("bp_clear"))) { return T_DbgScriptCmdKind_ClearBreakpoints; } - else if (str8_matchi(cmd, str8_lit("run"))) { return T_DbgScriptCmdKind_Run; } - else if (str8_matchi(cmd, str8_lit("halt"))) { return T_DbgScriptCmdKind_Halt; } - else if (str8_matchi(cmd, str8_lit("step_over"))) { return T_DbgScriptCmdKind_StepOver; } - else if (str8_matchi(cmd, str8_lit("step_into"))) { return T_DbgScriptCmdKind_StepInto; } - else if (str8_matchi(cmd, str8_lit("step_out"))) { return T_DbgScriptCmdKind_StepOut; } - else if (str8_matchi(cmd, str8_lit("step_over_inst"))) { return T_DbgScriptCmdKind_StepOverInst; } - else if (str8_matchi(cmd, str8_lit("step_into_inst"))) { return T_DbgScriptCmdKind_StepIntoInst; } - else if (str8_matchi(cmd, str8_lit("step_over_line"))) { return T_DbgScriptCmdKind_StepOverLine; } - else if (str8_matchi(cmd, str8_lit("step_into_line"))) { return T_DbgScriptCmdKind_StepIntoLine; } - else if (str8_matchi(cmd, str8_lit("at"))) { return T_DbgScriptCmdKind_At; } - else if (str8_matchi(cmd, str8_lit("eval"))) { return T_DbgScriptCmdKind_Eval; } + for EachIndex(i, T_DbgScriptCmdKind_Count) { + if (str8_matchi(t_string_from_dbg_script_cmd_kind(i), cmd)) { return i; } + } return T_DbgScriptCmdKind_Null; } -internal T_DbgScript -t_dbg_script_from_source(Arena *arena, String8 file_path, String8 source) +internal B32 +t_dbg_script_from_source(Arena *arena, String8 file_path, String8 source, T_DbgScript *script_out) { Temp scratch = scratch_begin(&arena, 1); + B32 is_ok = 0; T_DbgScript script = { .file_path = push_str8_copy(arena, file_path) }; @@ -409,43 +424,44 @@ t_dbg_script_from_source(Arena *arena, String8 file_path, String8 source) { MD_Node *test = script_parse.root->first; AssertAlways( ! md_node_is_nil(test)); - AssertAlways(str8_matchi(test->string, str8_lit("test"))); + if (str8_matchi(test->string, str8_lit("test"))) { + for MD_EachNode(n, test->first) { + OperatingSystem os = operating_system_from_string(n->string); + AssertAlways(os != OperatingSystem_Null); - String8 os_name = string_from_operating_system(OperatingSystem_CURRENT); + for MD_EachNode(field, n->first) { + T_DbgScriptDirectiveKind kind = T_DbgScriptDirectiveKind_Null; + if (str8_matchi(field->string, str8_lit("compile"))) { kind = T_DbgScriptDirectiveKind_Compile; } + else if (str8_matchi(field->string, str8_lit("link"))) { kind = T_DbgScriptDirectiveKind_Link; } + else if (str8_matchi(field->string, str8_lit("launch"))) { kind = T_DbgScriptDirectiveKind_Launch; } + AssertAlways(kind != T_DbgScriptDirectiveKind_Null); - for MD_EachNode(n, test->first) { - OperatingSystem os = operating_system_from_string(n->string); - AssertAlways(os != OperatingSystem_Null); + // syntax check + AssertAlways( !md_node_is_nil(field->first)); + AssertAlways(md_node_is_nil(field->first->next)); + Assert(field->first->flags & MD_NodeFlag_StringLiteral); - for MD_EachNode(field, n->first) { - T_DbgScriptDirectiveKind kind = T_DbgScriptDirectiveKind_Null; - if (str8_matchi(field->string, str8_lit("compile"))) { kind = T_DbgScriptDirectiveKind_Compile; } - else if (str8_matchi(field->string, str8_lit("link"))) { kind = T_DbgScriptDirectiveKind_Link; } - else if (str8_matchi(field->string, str8_lit("launch"))) { kind = T_DbgScriptDirectiveKind_Launch; } - AssertAlways(kind != T_DbgScriptDirectiveKind_Null); + // src_offset -> line + // + // TODO: super silly!! mdesk should export line numbers + U64 line = 1; + String8 text_before_src = str8_prefix(source, field->src_offset); + for EachIndex(idx, text_before_src.size) { line += (text_before_src.str[idx] == '\n'); } - // syntax check - AssertAlways( !md_node_is_nil(field->first)); - AssertAlways(md_node_is_nil(field->first->next)); - Assert(field->first->flags & MD_NodeFlag_StringLiteral); + T_DbgScriptDirective *n = push_array(arena, T_DbgScriptDirective, 1); + n->kind = kind; + n->line = line; + n->args = str8_copy(arena, field->first->string); + // TODO: expand % in compile: and link: to current source file name and esacpe with %% - // src_offset -> line - // - // TODO: super silly!! mdesk should export line numbers - U64 line = 1; - String8 text_before_src = str8_prefix(source, field->src_offset); - for EachIndex(idx, text_before_src.size) { line += (text_before_src.str[idx] == '\n'); } - - T_DbgScriptDirective *n = push_array(arena, T_DbgScriptDirective, 1); - n->kind = kind; - n->line = line; - n->args = str8_copy(arena, field->first->string); - // TODO: expand % in compile: and link: to current source file name and esacpe with %% - - T_DbgScriptDirectiveList *list = &script.directives[os][kind]; - SLLQueuePush(list->first, list->last, n); - list->count += 1; + T_DbgScriptDirectiveList *list = &script.directives[os][kind]; + SLLQueuePush(list->first, list->last, n); + list->count += 1; + } } + } else { + t_errorf("ERROR: %S: missing test header\n", file_path); + goto exit; } } @@ -523,28 +539,28 @@ t_dbg_script_from_source(Arena *arena, String8 file_path, String8 source) p->file = file; hash_table_push_u64_raw(scratch.arena, ht, order, p); } else { - fprintf(stderr, "ERROR: duplicate order number %llu found on line %llu\n", (unsigned long long)order, (unsigned long long)p->line); + t_errorf("ERROR: duplicate order number %llu found on line %llu\n", (unsigned long long)order, (unsigned long long)p->line); } - MD_Node *cmd_name = n->first; - MD_Node *cmd_arg = cmd_name->first; - AssertAlways(!md_node_is_nil(cmd_name)); + for MD_EachNode(cmd_n, n->first) { + // push new cmd + T_DbgScriptCmd *cmd = push_array(arena, T_DbgScriptCmd, 1); + cmd->kind = t_dbg_script_cmd_kind_from_string(cmd_n->string); + cmd->line = line; + Assert(cmd->kind != T_DbgScriptCmdKind_Null); + SLLQueuePush(p->first, p->last, cmd); + p->count += 1; - // push new cmd - T_DbgScriptCmd *cmd = push_array(arena, T_DbgScriptCmd, 1); - cmd->kind = t_dbg_script_cmd_kind_from_string(cmd_name->string); - AssertAlways(cmd->kind != T_DbgScriptCmdKind_Null); - SLLQueuePush(p->first, p->first, cmd); - p->count += 1; - - // parse cmd args - if ( ! md_node_is_nil(cmd_arg)) { - if (cmd->kind == T_DbgScriptCmdKind_At) { - AssertAlways(try_s64_from_str8_c_rules(cmd_arg->string, &cmd->at.delta)); - } else if (cmd->kind == T_DbgScriptCmdKind_Eval) { - NotImplemented; - } else if (cmd->kind == T_DbgScriptCmdKind_Breakpoint) { - NotImplemented; + // parse cmd args + MD_Node *cmd_arg = cmd_n->first; + if ( ! md_node_is_nil(cmd_arg)) { + if (cmd->kind == T_DbgScriptCmdKind_At) { + AssertAlways(try_s64_from_str8_c_rules(cmd_arg->string, &cmd->at.delta)); + } else if (cmd->kind == T_DbgScriptCmdKind_Eval) { + NotImplemented; + } else if (cmd->kind == T_DbgScriptCmdKind_Breakpoint) { + NotImplemented; + } } } } @@ -555,8 +571,13 @@ t_dbg_script_from_source(Arena *arena, String8 file_path, String8 source) radsort(script.programs, script.program_count, t_dbg_script_program_is_before); } + is_ok = 1; + exit:; + if (script_out) { + *script_out = script; + } scratch_end(scratch); - return script; + return is_ok; } internal B32 @@ -571,6 +592,8 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) if (program->os == OperatingSystem_CURRENT) { for EachNode(cmd, T_DbgScriptCmd, program->first) { + t_infof("[%llu] Command: %S:%llu %S\n", program->order, script->file_path, (unsigned long long)cmd->line, t_string_from_dbg_script_cmd_kind(cmd->kind)); + switch (cmd->kind) { case T_DbgScriptCmdKind_Null: break; case T_DbgScriptCmdKind_Halt: t_dbg_send_cmd_and_wait_stop(str8_lit("halt"), timeout_us); break; // NOTE: does not auto-magically select main thread on stop @@ -597,7 +620,7 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) #else T_DbgStatus temp_status = {0}; if ( ! t_dbg_status(&temp_status, T_Dbg_DefaultTimeout)) { - fprintf(stderr, "ERROR: failed to query IP\n"); + t_errorf("ERROR: %S:%llu: failed to query IP\n", script->file_path, (unsigned long long)cmd->line); goto exit; } U64 ip = temp_status.ip; @@ -606,7 +629,7 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) // map IP -> source location T_DbgSourceLocation loc = {0}; if (t_dbg_src_line(scratch.arena, ip, &loc, T_Dbg_DefaultTimeout) == 0) { - fprintf(stderr, "ERROR: failed to map IP (0x%llx) to source location\n", (unsigned long long)ip); + t_errorf("ERROR: %S:%llu: IP (0x%llx) does not map to a source line\n", script->file_path, (unsigned long long)cmd->line, (unsigned long long)ip); goto exit; } @@ -619,11 +642,10 @@ t_dbg_script_invoke(T_DbgScript *script, U64 timeout_us) B32 mismatch = loc.pt.line != at_line_u64 || !str8_match(loc.file_path, program->file->path, StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive); if (mismatch) { - fprintf(stderr, "ERROR: location check did not pass:\n"); - fprintf(stderr, " Script : %.*s\n", str8_varg(script->file_path)); - fprintf(stderr, " Expected: %.*s:%llu\n", str8_varg(program->file->path), (unsigned long long)at_line_u64); - fprintf(stderr, " Got : %.*s:%llu\n", str8_varg(loc.file_path), (unsigned long long)loc.pt.line); - fprintf(stderr, " IP : 0x%llx\n", (unsigned long long)ip); + t_errorf("ERROR: %S:%llu: location check did not pass:\n", script->file_path, (unsigned long long)cmd->line); + t_errorf(" Expected: %S:%llu\n", program->file->path, (unsigned long long)at_line_u64); + t_errorf(" Got : %S:%llu\n", loc.file_path, (unsigned long long)loc.pt.line); + t_errorf(" IP : 0x%llx\n", (unsigned long long)ip); goto exit; } } break; @@ -645,24 +667,27 @@ internal T_RunSig(dbg_script_runner) { if ( ! file_path_exists(t_raddbg_path())) { - fprintf(stderr, "ERROR: failed to find debugger \"%.*s\"\n", str8_varg(t_raddbg_path())); + t_errorf("ERROR: failed to find debugger \"%S\"\n", t_raddbg_path()); T_Ok(0); } // read source file String8 source = data_from_file_path(arena, user_data); if (source.size == 0) { - fprintf(stderr, "ERROR: failed to read script: \"%.*s\"\n", str8_varg(user_data)); + t_errorf("ERROR: failed to read script: \"%S\"\n", user_data); T_Ok(0); } // source -> script - T_DbgScript script = t_dbg_script_from_source(arena, user_data, source); + T_DbgScript script = {0}; + if ( ! t_dbg_script_from_source(arena, user_data, source, &script)) { + goto exit; + } // write source files to test folder for EachNode(file, T_DbgScriptFile, script.files.first) { if (write_data_to_file_path(file->path, file->source) == 0) { - fprintf(stderr, "ERROR: %.*s:%llu: failed to write: \"%.*s\"\n", str8_varg(user_data), (unsigned long long)file->line, str8_varg(file->path)); + t_errorf("ERROR: %S:%llu: failed to write: \"%S\"\n", user_data, (unsigned long long)file->line, file->path); T_Ok(0); } } @@ -695,11 +720,11 @@ T_RunSig(dbg_script_runner) // invoke compiler with arguments from directive String8 expanded_args = lnk_expand_env_vars_windows(arena, script_vars, directive->args); if (t_invoke(compiler_path, expanded_args, max_U64) == 0) { - fprintf(stderr, "ERROR: failed to launch compiler: \"%.*s %.*s\"\n", str8_varg(compiler_path), str8_varg(expanded_args)); + t_errorf("ERROR: failed to launch compiler: \"%S %S\"\n", compiler_path, expanded_args); T_Ok(0); } if (g_last_exit_code) { - fprintf(stderr, "ERROR: %.*s\n", str8_varg(g_output)); + t_errorf("ERROR: %S:%llu: %S\n", script.file_path, (unsigned long long)directive->line, g_errors); if (g_stop_on_first_fail_or_crash) { T_Ok(0); } @@ -711,7 +736,11 @@ T_RunSig(dbg_script_runner) for EachNode(directive, T_DbgScriptDirective, script.directives[OperatingSystem_CURRENT][T_DbgScriptDirectiveKind_Link].first) { String8 expanded_args = lnk_expand_env_vars_windows(arena, script_vars, directive->args); if (t_invoke(linker_path, expanded_args, max_U64) == 0) { - fprintf(stderr, "ERROR: failed to launch linker: \"%.*s %.*s\"\n", str8_varg(linker_path), str8_varg(expanded_args)); + t_errorf("ERROR: failed to launch linker: \"%S %S\"\n", linker_path, expanded_args); + T_Ok(0); + } + if (g_last_exit_code != 0) { + t_errorf("ERROR: %S:%llu: %S\n", script.file_path, (unsigned long long)directive->line, g_errors); T_Ok(0); } } @@ -721,14 +750,14 @@ T_RunSig(dbg_script_runner) String8 expanded_args = lnk_expand_env_vars_windows(arena, script_vars, directive->args); String8 cmdl = str8f(arena, "--user:%S.raddbg_user %S", t_make_file_path(arena, str8_lit("temp")), expanded_args); if (t_dbg_launch(cmdl, T_Dbg_DefaultTimeout) == 0) { - fprintf(stderr, "ERROR: failed to launch debugger with command line \"%.*s %.*s\"; work dir \"%.*s\"\n", str8_varg(t_raddbg_path()), str8_varg(cmdl), str8_varg(g_wdir)); + t_errorf("ERROR: failed to launch debugger with command line \"%S %S\"; work dir \"%S\"\n", t_raddbg_path(), cmdl, g_wdir); T_Ok(0); } } // debugger is ready -- now invoke script if (t_dbg_script_invoke(&script, T_Dbg_DefaultTimeout) == 0) { - fprintf(stderr, "ERROR: %.*s: failed to run to completion\n", str8_varg(user_data)); + t_errrof("ERROR: %S: failed to run to completion\n", user_data); T_Ok(0); } @@ -742,6 +771,8 @@ T_RunSig(dbg_script_runner) #else kill(g_dbg_pid, SIGKILL); #endif + + exit:; g_dbg_pid = 0; } @@ -751,7 +782,7 @@ t_dbg_register_script_tests(Arena *arena, String8 folder_path) Temp scratch = scratch_begin(&arena, 1); if ( ! folder_path_exists(folder_path)) { - fprintf(stderr, "ERROR: this folder does not exists: %.*s\n", str8_varg(folder_path)); + t_errof("ERROR: this folder does not exists: %S\n", folder_path); return; } diff --git a/src/torture/torture_dbg.h b/src/torture/torture_dbg.h index 85366d9b..c61f878d 100644 --- a/src/torture/torture_dbg.h +++ b/src/torture/torture_dbg.h @@ -38,6 +38,7 @@ typedef enum T_DbgScriptCmdKind_KillAll, T_DbgScriptCmdKind_At, T_DbgScriptCmdKind_Eval, + T_DbgScriptCmdKind_Count } T_DbgScriptCmdKind; typedef struct T_DbgScriptCmd @@ -107,6 +108,7 @@ typedef struct T_DbgScriptFileList files; U64 program_count; T_DbgScriptProgram **programs; + B32 skip; } T_DbgScript; ////////////////////////////////