static char *build_ids_from_core_backtrace(const char *dump_dir_name) { char *error = NULL; char *core_backtrace_path = xasprintf("%s/"FILENAME_CORE_BACKTRACE, dump_dir_name); char *json = xmalloc_open_read_close(core_backtrace_path, /*maxsize:*/ NULL); free(core_backtrace_path); if (!json) return NULL; struct sr_core_stacktrace *stacktrace = sr_core_stacktrace_from_json_text(json, &error); free(json); if (!stacktrace) { if (error) { log_info("Failed to parse core backtrace: %s", error); free(error); } return NULL; } struct sr_core_thread *thread = sr_core_stacktrace_find_crash_thread(stacktrace); if (!thread) { log_info("Failed to find crash thread"); sr_core_stacktrace_free(stacktrace); return NULL; } void *build_id_list = NULL; struct strbuf *strbuf = strbuf_new(); for (struct sr_core_frame *frame = thread->frames; frame; frame = frame->next) { if (frame->build_id) build_id_list = g_list_prepend(build_id_list, frame->build_id); } build_id_list = g_list_sort(build_id_list, (GCompareFunc)strcmp); for (GList *iter = build_id_list; iter; iter = g_list_next(iter)) { GList *next = g_list_next(iter); if (next == NULL || 0 != strcmp(iter->data, next->data)) { strbuf = strbuf_append_strf(strbuf, "%s\n", (char *)iter->data); } } g_list_free(build_id_list); sr_core_stacktrace_free(stacktrace); return strbuf_free_nobuf(strbuf); }
char * sr_abrt_get_core_stacktrace_from_core_hook(pid_t thread_id, const char *executable, int signum, char **error_message) { struct sr_core_stacktrace *core_stacktrace; core_stacktrace = sr_core_stacktrace_from_core_hook(thread_id, executable, signum, error_message); if (!core_stacktrace) return false; fulfill_missing_values(core_stacktrace); char *json = sr_core_stacktrace_to_json(core_stacktrace); sr_core_stacktrace_free(core_stacktrace); // Add newline to the end of core stacktrace file to make text // editors happy. json = sr_realloc(json, strlen(json) + 2); strcat(json, "\n"); return json; ; }
struct sr_core_stacktrace * sr_core_stacktrace_from_json(struct sr_json_value *root, char **error_message) { if (!JSON_CHECK_TYPE(root, SR_JSON_OBJECT, "stacktrace")) return NULL; struct sr_core_stacktrace *result = sr_core_stacktrace_new(); bool success = JSON_READ_UINT16(root, "signal", &result->signal) && JSON_READ_STRING(root, "executable", &result->executable) && JSON_READ_BOOL(root, "only_crash_thread", &result->only_crash_thread); if (!success) goto fail; /* Read threads. */ struct sr_json_value *stacktrace = json_element(root, "stacktrace"); if (stacktrace) { if (!JSON_CHECK_TYPE(stacktrace, SR_JSON_ARRAY, "stacktrace")) goto fail; struct sr_json_value *json_thread; FOR_JSON_ARRAY(stacktrace, json_thread) { struct sr_core_thread *thread = sr_core_thread_from_json(json_thread, error_message); if (!thread) goto fail; struct sr_json_value *crash_thread = json_element(json_thread, "crash_thread"); if (crash_thread) { if (!JSON_CHECK_TYPE(crash_thread, SR_JSON_BOOLEAN, "crash_thread")) { sr_core_thread_free(thread); goto fail; } if (crash_thread->u.boolean) result->crash_thread = thread; } result->threads = sr_core_thread_append(result->threads, thread); } } return result; fail: sr_core_stacktrace_free(result); return NULL; }
static bool create_core_stacktrace(const char *directory, const char *gdb_output, bool hash_fingerprints, char **error_message) { char *executable_contents = file_contents(directory, "executable", error_message); if (!executable_contents) return NULL; char *coredump_filename = sr_build_path(directory, "coredump", NULL); struct sr_core_stacktrace *core_stacktrace; if (gdb_output) core_stacktrace = sr_core_stacktrace_from_gdb(gdb_output, coredump_filename, executable_contents, error_message); else core_stacktrace = sr_parse_coredump(coredump_filename, executable_contents, error_message); free(executable_contents); free(coredump_filename); if (!core_stacktrace) return false; fulfill_missing_values(core_stacktrace); #if 0 sr_core_fingerprint_generate(core_stacktrace, error_message); if (hash_fingerprints) sr_core_fingerprint_hash(core_stacktrace); #endif char *json = sr_core_stacktrace_to_json(core_stacktrace); // Add newline to the end of core stacktrace file to make text // editors happy. json = sr_realloc(json, strlen(json) + 2); strcat(json, "\n"); char *core_backtrace_filename = sr_build_path(directory, "core_backtrace", NULL); bool success = sr_string_to_file(core_backtrace_filename, json, error_message); free(core_backtrace_filename); free(json); sr_core_stacktrace_free(core_stacktrace); return success; }
struct sr_core_stacktrace * sr_parse_coredump_maps(const char *core_file, const char *exe_file, const char *maps_file, char **error_msg) { struct sr_core_stacktrace *stacktrace = NULL; /* Initialize error_msg to 'no error'. */ if (error_msg) *error_msg = NULL; struct core_handle *ch = open_coredump(core_file, exe_file, maps_file, error_msg); if (!ch) goto fail; if (dwfl_core_file_attach(ch->dwfl, ch->eh) < 0) { set_error_dwfl("dwfl_core_file_attach"); goto fail; } stacktrace = sr_core_stacktrace_new(); if (!stacktrace) { set_error("Failed to initialize stacktrace memory"); goto fail; } struct thread_callback_arg thread_arg = { .stacktrace = stacktrace, .error_msg = NULL }; int ret = dwfl_getthreads(ch->dwfl, unwind_thread, &thread_arg); if (ret != 0) { if (ret == -1) set_error_dwfl("dwfl_getthreads"); else if (ret == DWARF_CB_ABORT) { set_error("%s", thread_arg.error_msg); free(thread_arg.error_msg); } else set_error("Unknown error in dwfl_getthreads"); sr_core_stacktrace_free(stacktrace); stacktrace = NULL; goto fail; } stacktrace->executable = sr_strdup(exe_file); stacktrace->signal = get_signal_number(ch->eh, core_file); /* FIXME: is this the best we can do? */ stacktrace->crash_thread = stacktrace->threads; fail: core_handle_free(ch); return stacktrace; }
struct sr_core_stacktrace * sr_parse_coredump(const char *core_file, const char *exe_file, char **error_msg) { struct sr_core_stacktrace *stacktrace = NULL; /* Initialize error_msg to 'no error'. */ if (error_msg) *error_msg = NULL; struct core_handle *ch = open_coredump(core_file, exe_file, error_msg); if (*error_msg) return NULL; unw_addr_space_t as; struct UCD_info *ui; as = unw_create_addr_space(&_UCD_accessors, 0); if (!as) { set_error("Failed to create address space"); goto fail_destroy_handle; } ui = _UCD_create(core_file); if (!ui) { set_error("Failed to set up core dump accessors for '%s'", core_file); goto fail_destroy_as; } struct exe_mapping_data *s; for (s = ch->segments; s != NULL; s = s->next) { if (_UCD_add_backing_file_at_vaddr(ui, s->start, s->filename) < 0) { /* Sometimes produces: * >_UCD_add_backing_file_at_segment: * Error reading from '/usr/lib/modules/3.6.9-2.fc17.x86_64/vdso/vdso.so' * Ignore errors for now & fail later. */ warn("Can't add backing file '%s' at addr 0x%jx", s->filename, (uintmax_t)s->start); /* goto fail_destroy_ui; */ } } stacktrace = sr_core_stacktrace_new(); int tnum, nthreads = _UCD_get_num_threads(ui); for (tnum = 0; tnum < nthreads; ++tnum) { struct sr_core_thread *trace = unwind_thread(ui, as, ch->dwfl, tnum, error_msg); if (trace) { stacktrace->threads = sr_core_thread_append(stacktrace->threads, trace); } else { sr_core_stacktrace_free(stacktrace); stacktrace = NULL; break; } } stacktrace->executable = realpath(exe_file, NULL); stacktrace->signal = get_signal_number_libunwind(ui); /* FIXME: is this the best we can do? */ stacktrace->crash_thread = stacktrace->threads; _UCD_destroy(ui); fail_destroy_as: unw_destroy_addr_space(as); fail_destroy_handle: core_handle_free(ch); return stacktrace; }