static void terminating_signal_handler(int sig) { fprintf(stderr, "Signal handler called (signal=%d). Exiting.\n", sig); if (CURRENT_CONFIGURATION != NULL && !CURRENT_CONFIGURATION->debug_options.do_not_run_gdb // Do not call the debugger for Ctrl-C && sig != SIGINT) run_gdb(); if (!in_cleanup_routine) cleanup_routine(); raise(sig); }
/// Gathers a stacktrace of a crashed program. /// /// \param program The name of the binary that crashed and dumped a core file. /// Can be either absolute or relative. /// \param dead_pid The PID of the process that dumped core. /// \param original_run_params Parameters with which the original binary was /// executed. These are reused to run GDB, but adjusted with GDB-specific /// settings. Of special interest, the work directory is used to search for /// the core file. /// \param output Stream into which to dump the stack trace and any additional /// information. /// /// \post If anything goes wrong, the diagnostic messages are written to the /// output. This function returns no errors. void kyua_stacktrace_dump(const char* program, const pid_t dead_pid, const kyua_run_params_t* original_run_params, FILE* output) { fprintf(output, "Process with PID %d dumped core; attempting to gather " "stack trace\n", dead_pid); const kyua_run_params_t run_params = gdb_run_params(original_run_params); kyua_error_t error = kyua_error_ok(); char* core_file = kyua_stacktrace_find_core(const_basename(program), run_params.work_directory, dead_pid); if (core_file == NULL) { fprintf(output, "Cannot find any core file\n"); goto out; } // We must flush the output stream right before invoking fork, so that the // subprocess does not have any unflushed data. Failure to do so results in // the messages above being written twice to the output. fflush(output); pid_t pid; error = kyua_run_fork(&run_params, &pid); if (!kyua_error_is_set(error) && pid == 0) { run_gdb(program, core_file, output); } assert(pid != -1 && pid != 0); if (kyua_error_is_set(error)) goto out_core_file; int status; bool timed_out; error = kyua_run_wait(pid, &status, &timed_out); if (kyua_error_is_set(error)) goto out_core_file; if (timed_out) { fprintf(output, "GDB failed; timed out\n"); } else { if (WIFEXITED(status)) { if (WEXITSTATUS(status) == EXIT_SUCCESS) fprintf(output, "GDB exited successfully\n"); else fprintf(output, "GDB failed with code %d; see output above for " "details\n", WEXITSTATUS(status)); } else { assert(WIFSIGNALED(status)); fprintf(output, "GDB received signal %d; see output above for " "details\n", WTERMSIG(status)); } } out_core_file: free(core_file); out: if (kyua_error_is_set(error)) { kyua_error_fprintf(output, error, "Failed to gather stacktrace"); free(error); } }