From 17853e2316aed32d56343b2c4a73fa82b43a078d Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Mon, 21 Oct 2013 14:53:02 +0200 Subject: [SATYR PATCH 2/3] unwind: Port to current API of elfutils unwinder Related to rhbz#1051569. Signed-off-by: Martin Milata --- configure.ac | 2 +- lib/core_unwind_elfutils.c | 164 +++++++++++++++++++++++++++++---------------- lib/internal_unwind.h | 2 +- 3 files changed, 110 insertions(+), 58 deletions(-) diff --git a/configure.ac b/configure.ac index af6cb3f..cf3a193 100644 --- a/configure.ac +++ b/configure.ac @@ -104,7 +104,7 @@ AC_CHECK_LIB([elf], [main]) AC_CHECK_LIB([dw], [main]) AC_CHECK_LIB([dwfl], [main]) AC_CHECK_LIB([dl], [main]) -AC_CHECK_FUNC(dwfl_frame_state_core, AC_DEFINE(HAVE_DWFL_FRAME_STATE_CORE, [], [Have function dwfl_frame_state_core for coredump unwinding])) +AC_CHECK_FUNC(dwfl_getthreads, AC_DEFINE(HAVE_DWFL_NEXT_THREAD, [], [Have function dwfl_getthreads for coredump unwinding])) # libunwind AC_CHECK_HEADERS([libunwind-coredump.h]) diff --git a/lib/core_unwind_elfutils.c b/lib/core_unwind_elfutils.c index 9a489ac..a8d8b3f 100644 --- a/lib/core_unwind_elfutils.c +++ b/lib/core_unwind_elfutils.c @@ -29,59 +29,108 @@ #include #include -static struct sr_core_thread * -unwind_thread(Dwfl *dwfl, Dwfl_Frame_State *state, char **error_msg) +struct frame_callback_arg { - struct sr_core_frame *head = NULL, *tail = NULL; - pid_t tid = 0; + struct sr_core_thread *thread; + char *error_msg; +}; - if (state) +struct thread_callback_arg +{ + struct sr_core_stacktrace *stacktrace; + char *error_msg; +}; + +static int CB_STOP_UNWIND = DWARF_CB_ABORT+1; + +static int +frame_callback(Dwfl_Frame *frame, void *data) +{ + struct frame_callback_arg *frame_arg = data; + char **error_msg = &frame_arg->error_msg; + + Dwarf_Addr pc; + bool minus_one; + if (!dwfl_frame_pc(frame, &pc, &minus_one)) { - tid = dwfl_frame_tid_get(state); + set_error_dwfl("dwfl_frame_pc"); + return DWARF_CB_ABORT; } - while (state) + Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(frame)); + struct sr_core_frame *result = resolve_frame(dwfl, pc, minus_one); + + /* Do not unwind below __libc_start_main. */ + if (0 == sr_strcmp0(result->function_name, "__libc_start_main")) { - Dwarf_Addr pc; - bool minus_one; - if (!dwfl_frame_state_pc(state, &pc, &minus_one)) - { - warn("Failed to obtain PC: %s", dwfl_errmsg(-1)); - break; - } - - struct sr_core_frame *frame = resolve_frame(dwfl, pc, minus_one); - list_append(head, tail, frame); - - /* Do not unwind below __libc_start_main. */ - if (0 == sr_strcmp0(frame->function_name, "__libc_start_main")) - break; - - if (!dwfl_frame_unwind(&state)) - { - warn("Cannot unwind frame: %s", dwfl_errmsg(-1)); - break; - } + sr_core_frame_free(result); + return CB_STOP_UNWIND; } - if (!error_msg && !head) + frame_arg->thread->frames = + sr_core_frame_append(frame_arg->thread->frames, result); + + return DWARF_CB_OK; +} + +static int +unwind_thread(Dwfl_Thread *thread, void *data) +{ + struct thread_callback_arg *thread_arg = data; + char **error_msg = &thread_arg->error_msg; + + struct sr_core_thread *result = sr_core_thread_new(); + if (!result) { - set_error("No frames found for thread id %d", (int)tid); + set_error("Failed to initialize stacktrace memory"); + return DWARF_CB_ABORT; } + result->id = (int64_t)dwfl_thread_tid(thread); + + struct frame_callback_arg frame_arg = + { + .thread = result, + .error_msg = NULL + }; - struct sr_core_thread *thread = sr_core_thread_new(); - thread->id = (int64_t)tid; - thread->frames = head; - return thread; + int ret = dwfl_thread_getframes(thread, frame_callback, &frame_arg); + if (ret == -1) + { + warn("dwfl_thread_getframes failed for thread id %d: %s", + (int)result->id, dwfl_errmsg(-1)); + } + else if (ret == DWARF_CB_ABORT) + { + *error_msg = frame_arg.error_msg; + goto abort; + } + else if (ret != 0 && ret != CB_STOP_UNWIND) + { + *error_msg = sr_strdup("Unknown error in dwfl_thread_getframes"); + goto abort; + } + + if (!error_msg && !frame_arg.thread->frames) + { + set_error("No frames found for thread id %d", (int)result->id); + goto abort; + } + + thread_arg->stacktrace->threads = + sr_core_thread_append(thread_arg->stacktrace->threads, result); + return DWARF_CB_OK; + +abort: + sr_core_thread_free(result); + return DWARF_CB_ABORT; } struct sr_core_stacktrace * sr_parse_coredump(const char *core_file, - const char *exe_file, - char **error_msg) + const char *exe_file, + char **error_msg) { struct sr_core_stacktrace *stacktrace = NULL; - short signal = 0; /* Initialize error_msg to 'no error'. */ if (error_msg) @@ -91,11 +140,9 @@ sr_parse_coredump(const char *core_file, if (*error_msg) return NULL; - Dwfl_Frame_State *state = dwfl_frame_state_core(ch->dwfl, core_file); - if (!state) + if (dwfl_core_file_attach(ch->dwfl, ch->eh) < 0) { - set_error("Failed to initialize frame state from core '%s'", - core_file); + set_error_dwfl("dwfl_core_file_attach"); goto fail_destroy_handle; } @@ -105,20 +152,30 @@ sr_parse_coredump(const char *core_file, set_error("Failed to initialize stacktrace memory"); goto fail_destroy_handle; } - struct sr_core_thread *threads_tail = NULL; - do + struct thread_callback_arg thread_arg = { - struct sr_core_thread *t = unwind_thread(ch->dwfl, state, error_msg); - if (*error_msg) - { - goto fail_destroy_trace; - } - list_append(stacktrace->threads, threads_tail, t); - state = dwfl_frame_thread_next(state); - } while (state); + .stacktrace = stacktrace, + .error_msg = NULL + }; - signal = get_signal_number(ch->eh, core_file); + 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) + *error_msg = thread_arg.error_msg; + else + *error_msg = sr_strdup("Unknown error in dwfl_getthreads"); + + goto fail_destroy_trace; + } + + 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_destroy_trace: if (*error_msg) @@ -128,11 +185,6 @@ fail_destroy_trace: } fail_destroy_handle: core_handle_free(ch); - - stacktrace->executable = sr_strdup(exe_file); - stacktrace->signal = signal; - /* FIXME: is this the best we can do? */ - stacktrace->crash_thread = stacktrace->threads; return stacktrace; } diff --git a/lib/internal_unwind.h b/lib/internal_unwind.h index d537f86..2c9abb7 100644 --- a/lib/internal_unwind.h +++ b/lib/internal_unwind.h @@ -27,7 +27,7 @@ #include "config.h" /* define macros indicating what unwinder are we using */ -#if (defined HAVE_LIBELF_H && defined HAVE_GELF_H && defined HAVE_LIBELF && defined HAVE_LIBDW && defined HAVE_ELFUTILS_LIBDWFL_H && defined HAVE_DWFL_FRAME_STATE_CORE) +#if (defined HAVE_LIBELF_H && defined HAVE_GELF_H && defined HAVE_LIBELF && defined HAVE_LIBDW && defined HAVE_ELFUTILS_LIBDWFL_H && defined HAVE_DWFL_NEXT_THREAD) # define WITH_LIBDWFL #endif -- 1.8.3.1