From: Serhei Makarov Date: Thu, 5 Dec 2024 21:16:00 +0000 (-0500) Subject: eu-stacktrace: use libebl register handling api X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=82269576d12d6478d56900ed731294ac75e8453a;p=thirdparty%2Felfutils.git eu-stacktrace: use libebl register handling api Change the sample_set_initial_registers callback in eu-stacktrace to use the proper libebl ebl_set_initial_registers_sample function. * src/Makefile.am (stacktrace_LDADD): Add libebl. * src/stacktrace.c (sample_registers_cb): New function, though identical to pid_thread_state_registers_cb. (sample_set_initial_registers): Invoke ebl_set_initial_registers_sample instead of containing platform-specific code directly. --- diff --git a/src/Makefile.am b/src/Makefile.am index 6bdf2dfb..20ee3e8f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -99,7 +99,7 @@ ar_LDADD = libar.a $(libelf) $(libeu) $(argp_LDADD) $(obstack_LIBS) unstrip_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) stack_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) $(demanglelib) if ENABLE_STACKTRACE -stacktrace_LDADD = $(libelf) $(libdw) $(libeu) $(argp_LDADD) +stacktrace_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) endif elfcompress_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) elfclassify_LDADD = $(libelf) $(libdw) $(libeu) $(argp_LDADD) diff --git a/src/stacktrace.c b/src/stacktrace.c index 438cb1dd..3813e340 100644 --- a/src/stacktrace.c +++ b/src/stacktrace.c @@ -92,9 +92,11 @@ * Includes: libdwfl data structures * *************************************/ +#include ELFUTILS_HEADER(ebl) /* #include ELFUTILS_HEADER(dwfl) */ #include "../libdwfl/libdwflP.h" -/* XXX: Private header needed for find_procfile, sysprof_init_dwfl */ +/* XXX: Private header needed for find_procfile, sysprof_init_dwfl, + sample_set_initial_registers. */ /************************************* * Includes: sysprof data structures * @@ -573,42 +575,41 @@ sample_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg) return true; } -/* TODO: Need to generalize this code beyond x86 architectures. */ +/* Implement the ebl_set_initial_registers_sample setfunc callback. */ static bool -sample_set_initial_registers (Dwfl_Thread *thread, void *thread_arg) +sample_registers_cb (int firstreg, unsigned nregs, + const Dwarf_Word *regs, void *arg) { - /* The following facts are needed to translate x86 registers correctly: - - perf register order seen in linux arch/x86/include/uapi/asm/perf_regs.h - The registers array is built in the same order as the enum! - (See the code in tools/perf/util/intel-pt.c intel_pt_add_gp_regs().) - - sysprof libsysprof/perf-event-stream-private.h records all registers - except segment and flags. - - TODO: Should include the perf regs mask in sysprof data and - translate registers in fully-general fashion, removing this assumption. - - dwarf register order seen in elfutils backends/{x86_64,i386}_initreg.c; - and it's a fairly different register order! - - For comparison, you can study codereview.qt-project.org/gitweb?p=qt-creator/perfparser.git;a=blob;f=app/perfregisterinfo.cpp;hb=HEAD - and follow the code which uses those tables of magic numbers. - But it's better to follow original sources of truth for this. */ - struct __sample_arg *sample_arg = (struct __sample_arg *)thread_arg; - bool is_abi32 = (sample_arg->abi == PERF_SAMPLE_REGS_ABI_32); - static const int regs_i386[] = {0, 2, 3, 1, 7/*sp*/, 6, 4, 5, 8/*ip*/}; - static const int regs_x86_64[] = {0, 3, 2, 1, 4, 5, 6, 7/*sp*/, 9, 10, 11, 12, 13, 14, 15, 16, 8/*ip*/}; - const int *reg_xlat = is_abi32 ? regs_i386 : regs_x86_64; - int n_regs = is_abi32 ? 9 : 17; - dwfl_thread_state_register_pc (thread, sample_arg->pc); - if (sample_arg->n_regs < (uint64_t)n_regs && show_failures) - fprintf(stderr, N_("sample_set_initial_regs: n_regs=%ld, expected %d\n"), - sample_arg->n_regs, n_regs); - for (int i = 0; i < n_regs; i++) + /* TODO Identical to pid_thread_state_registers_cb in linux-pid-attach.c. */ + Dwfl_Thread *thread = (Dwfl_Thread *)arg; + if (firstreg == -1) { - int j = reg_xlat[i]; - if (j < 0) continue; - if (sample_arg->n_regs <= (uint64_t)j) continue; - dwfl_thread_state_registers (thread, i, 1, &sample_arg->regs[j]); + assert (nregs == 1); + dwfl_thread_state_register_pc (thread, *regs); + return true; } - return true; + else if (firstreg == -2) + { + assert (nregs == 1); + dwfl_thread_state_registers (thread, firstreg, nregs, regs); + return true; + } + assert (nregs > 0); + return dwfl_thread_state_registers (thread, firstreg, nregs, regs); +} + +static bool +sample_set_initial_registers (Dwfl_Thread *thread, void *arg) +{ + struct __sample_arg *sample_arg = (struct __sample_arg *)arg; + dwfl_thread_state_register_pc (thread, sample_arg->pc); + Dwfl_Process *process = thread->process; + Ebl *ebl = process->ebl; + /* XXX Sysprof provides exactly the required registers for unwinding: */ + uint64_t regs_mask = ebl_perf_frame_regs_mask (ebl); + return ebl_set_initial_registers_sample + (ebl, sample_arg->regs, sample_arg->n_regs, regs_mask, sample_arg->abi, + sample_registers_cb, thread); } static void