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);
}
Пример #2
0
/// 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);
    }
}