Remove the code from src/stacktrace.c that is now covered by libdwfl/dwfl_perf_frame.c and dwfl_perf_sample_getframes.
* src/stacktrace.c (show_memory_reads): Remove this verbose option as the relevant code is inside libdwfl now. (struct __sample_arg): Remove, handled by libdwfl/dwfl_perf_frame.c. (sample_next_thread): Ditto. (sample_getthread): Ditto. (copy_word_64): Ditto. (copy_word_32): Ditto. (elf_memory_read): Ditto. (sample_memory_read): Ditto. (sample_set_initial_registers): Ditto. (sample_detach): Ditto. (sample_thread_callbacks): Ditto. (sysprof_find_dwfl): Now also return the Elf* so that it can be passed to dwfl_perf_sample_getframes. Don't create sample_arg. Do record sp in sui->last_sp. Don't dwfl_attach_state, dwfl_perf_sample_getframes handles that now. (sysprof_unwind_cb): Adapt to sysprof_find_dwfl changes, now invoke dwfl_perf_sample_getframes instead of dwfl_getthread_frames. (parse_opt): Remove show_memory_reads. (main): Remove show_memory_reads. --- src/stacktrace.c | 233 +++++++---------------------------------------- 1 file changed, 33 insertions(+), 200 deletions(-) diff --git a/src/stacktrace.c b/src/stacktrace.c index 89e1866e..d43b70de 100644 --- a/src/stacktrace.c +++ b/src/stacktrace.c @@ -96,8 +96,7 @@ #include ELFUTILS_HEADER(ebl) /* #include ELFUTILS_HEADER(dwfl) */ #include "../libdwfl/libdwflP.h" -/* XXX: Private header needed for find_procfile, sysprof_find_dwfl, - sample_set_initial_registers. */ +/* XXX: Private header needed for find_procfile. */ /************************************* * Includes: sysprof data structures * @@ -176,11 +175,13 @@ static int processing_mode = MODE_NAIVE; static int input_format; static int output_format = FORMAT_SYSPROF; +/* XXX Used to decide regs_mask for dwfl_perf_sample_getframes. */ +Ebl *default_ebl = NULL; + /* non-printable argp options. */ #define OPT_DEBUG 0x100 /* Diagnostic options. */ -static bool show_memory_reads = false; static bool show_frames = false; static bool show_samples = false; static bool show_failures = false; @@ -190,9 +191,6 @@ static bool show_summary = true; #define ELFUTILS_STACKTRACE_VERBOSE_ENV_VAR "ELFUTILS_STACKTRACE_VERBOSE" /* Valid values that turn on diagnostics: 'true', 'verbose', 'debug', '1', '2'. */ -/* Enables detailed tracing of simulated memory reads: */ -/* #define DEBUG_MEMORY_READ */ - /* Enables even more diagnostics on modules: */ /* #define DEBUG_MODULES */ @@ -469,144 +467,6 @@ sysprof_reader_getframes (SysprofReader *reader, #endif /* HAVE_SYSPROF_HEADERS */ -/******************************************* - * Memory read interface for stack samples * - *******************************************/ - -/* TODO: elfutils (internal) libraries use libNN_set_errno and DWFL_E_WHATEVER; - this code fails silently in sample_getthread. */ - -struct __sample_arg -{ - int tid; - Dwarf_Addr base_addr; - uint64_t size; - uint8_t *data; - uint64_t n_regs; - uint64_t abi; /* PERF_SAMPLE_REGS_ABI_{32,64} */ - Dwarf_Addr pc; - Dwarf_Addr sp; - Dwarf_Addr *regs; -}; - -/* The next few functions imitate the corefile interface for a single - stack sample, with very restricted access to registers and memory. */ - -/* Just yield the single thread id matching the sample. */ -static pid_t -sample_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg, - void **thread_argp) -{ - struct __sample_arg *sample_arg = (struct __sample_arg *)dwfl_arg; - if (*thread_argp == NULL) - { - *thread_argp = (void *)0xea7b3375; - return sample_arg->tid; - } - else - return 0; -} - -/* Just check that the thread id matches the sample. */ -static bool -sample_getthread (Dwfl *dwfl __attribute__ ((unused)), pid_t tid, - void *dwfl_arg, void **thread_argp) -{ - struct __sample_arg *sample_arg = (struct __sample_arg *)dwfl_arg; - *thread_argp = (void *)sample_arg; - if (sample_arg->tid != tid) - { - return false; - } - return true; -} - -#define copy_word_64(result, d) \ - if ((((uintptr_t) (d)) & (sizeof (uint64_t) - 1)) == 0) \ - *(result) = *(uint64_t *)(d); \ - else \ - memcpy ((result), (d), sizeof (uint64_t)); - -#define copy_word_32(result, d) \ - if ((((uintptr_t) (d)) & (sizeof (uint32_t) - 1)) == 0) \ - *(result) = *(uint32_t *)(d); \ - else \ - memcpy ((result), (d), sizeof (uint32_t)); - -#define copy_word(result, d, abi) \ - if ((abi) == PERF_SAMPLE_REGS_ABI_64) \ - { copy_word_64((result), (d)); } \ - else if ((abi) == PERF_SAMPLE_REGS_ABI_32) \ - { copy_word_32((result), (d)); } \ - else \ - *(result) = 0; - -static bool -elf_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg) -{ - struct __sample_arg *sample_arg = (struct __sample_arg *)arg; - Dwfl_Module *mod = dwfl_addrmodule(dwfl, addr); - Dwarf_Addr bias; - Elf_Scn *section = dwfl_module_address_section(mod, &addr, &bias); - - if (!section) - return false; - - Elf_Data *data = elf_getdata(section, NULL); - if (data && data->d_buf && data->d_size > addr) { - uint8_t *d = ((uint8_t *)data->d_buf) + addr; - copy_word(result, d, sample_arg->abi); - return true; - } - return false; -} - -static bool -sample_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg) -{ - struct __sample_arg *sample_arg = (struct __sample_arg *)arg; - if (show_memory_reads) - fprintf(stderr, "* memory_read addr=%lx+(%lx) size=%lx\n", - sample_arg->base_addr, addr - sample_arg->base_addr, sample_arg->size); - /* Imitate read_cached_memory() with the stack sample data as the cache. */ - if (addr < sample_arg->base_addr || addr - sample_arg->base_addr >= sample_arg->size) - return elf_memory_read(dwfl, addr, result, arg); - uint8_t *d = &sample_arg->data[addr - sample_arg->base_addr]; - copy_word(result, d, sample_arg->abi); - return true; -} - -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, - dwfl_set_initial_registers_thread, thread); -} - -static void -sample_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg) -{ - struct __sample_arg *sample_arg = (struct __sample_arg *)dwfl_arg; - free (sample_arg); -} - -static const Dwfl_Thread_Callbacks sample_thread_callbacks = -{ - sample_next_thread, - sample_getthread, - sample_memory_read, - sample_set_initial_registers, - sample_detach, - NULL, /* sample_thread_detach */ -}; - /**************************************************** * Dwfl and statistics table for multiple processes * ****************************************************/ @@ -996,28 +856,25 @@ sysprof_init_dwfl (Dwfl_Process_Tracker *cb_tracker, Dwfl * sysprof_find_dwfl (struct sysprof_unwind_info *sui, SysprofCaptureStackUser *ev, - SysprofCaptureUserRegs *regs) + SysprofCaptureUserRegs *regs, + Elf **out_elf) { pid_t pid = ev->frame.pid; - /* TODO: Need to generalize this code beyond x86 architectures. */ /* XXX: Note that sysprof requesting the x86_64 register file from perf_events will result in an array of 17 regs even for 32-bit applications. */ -#define EXPECTED_REGS 17 - if (regs->n_regs < EXPECTED_REGS) /* XXX expecting everything except FLAGS */ + if (regs->n_regs < ebl_frame_nregs(default_ebl)) /* XXX expecting everything except FLAGS */ { if (show_failures) - fprintf(stderr, N_("sysprof_find_dwfl: n_regs=%d, expected %d\n"), - regs->n_regs, EXPECTED_REGS); + fprintf(stderr, N_("sysprof_find_dwfl: n_regs=%d, expected %ld\n"), + regs->n_regs, ebl_frame_nregs(default_ebl)); return NULL; } Dwfl *dwfl = dwfl_process_tracker_find_pid (tracker, pid, sysprof_init_dwfl, NULL); - struct __sample_arg *sample_arg; bool cached = false; if (dwfl != NULL && dwfl->process != NULL) { - sample_arg = dwfl->process->callbacks_arg; /* XXX requires libdwflP.h */ cached = true; goto reuse; } @@ -1033,53 +890,22 @@ sysprof_find_dwfl (struct sysprof_unwind_info *sui, return NULL; } - sample_arg = malloc (sizeof *sample_arg); - if (sample_arg == NULL) - { - if (elf != NULL) { - elf_end (elf); - close (elf_fd); - } - free (sample_arg); - return NULL; - } - reuse: - sample_arg->tid = ev->tid; - sample_arg->size = ev->size; - sample_arg->data = (uint8_t *)&ev->data; - sample_arg->regs = regs->regs; - sample_arg->n_regs = (uint64_t)regs->n_regs; - sample_arg->abi = (uint64_t)regs->abi; - /* TODO: Need to generalize this code beyond x86 architectures. */ - /* Register ordering cf. linux arch/x86/include/uapi/asm/perf_regs.h enum perf_event_x86_regs: */ - sample_arg->sp = regs->regs[7]; - sample_arg->pc = regs->regs[8]; - sample_arg->base_addr = sample_arg->sp; - sui->last_sp = sample_arg->base_addr; - sui->last_base = sample_arg->base_addr; + /* TODO: Generalize to other architectures than x86_64. */ + sui->last_sp = regs->regs[7]; + sui->last_base = sui->last_sp; if (show_frames) { - bool is_abi32 = (sample_arg->abi == PERF_SAMPLE_REGS_ABI_32); + bool is_abi32 = (regs->abi == PERF_SAMPLE_REGS_ABI_32); fprintf(stderr, "sysprof_find_dwfl pid %lld%s: size=%ld%s pc=%lx sp=%lx+(%lx)\n", (long long) pid, cached ? " (cached)" : "", - sample_arg->size, is_abi32 ? " (32-bit)" : "", - sample_arg->pc, sample_arg->base_addr, - sample_arg->sp - sample_arg->base_addr); + ev->size, is_abi32 ? " (32-bit)" : "", + regs->regs[8], sui->last_base, (long)0); } - if (!cached && ! dwfl_attach_state (dwfl, elf, pid, &sample_thread_callbacks, sample_arg)) - { - if (show_failures) - fprintf(stderr, "dwfl_attach_state pid %lld: %s\n", - (long long)pid, dwfl_errmsg(-1)); - elf_end (elf); - close (elf_fd); - free (sample_arg); - return NULL; - } if (!cached) pid_store_dwfl (pid, dwfl); + *out_elf = elf; return dwfl; } @@ -1222,7 +1048,8 @@ sysprof_unwind_cb (SysprofCaptureFrame *frame, void *arg) SysprofCaptureUserRegs *regs = (SysprofCaptureUserRegs *)tail_ptr; if (show_frames) fprintf(stderr, "\n"); /* extra newline for padding */ - Dwfl *dwfl = sysprof_find_dwfl (sui, ev, regs); + Elf *elf = NULL; + Dwfl *dwfl = sysprof_find_dwfl (sui, ev, regs, &elf); if (dwfl == NULL) { if (show_summary) @@ -1231,7 +1058,10 @@ sysprof_unwind_cb (SysprofCaptureFrame *frame, void *arg) dwfl_ent->total_samples++; dwfl_ent->lost_samples++; } - if (show_failures) + if (elf == NULL && dwfl != NULL) + fprintf(stderr, "sysprof_find_dwfl pid %lld (%s) (failed; elf == NULL, dwfl != NULL)\n", + (long long)frame->pid, comm); + else if (show_failures) fprintf(stderr, "sysprof_find_dwfl pid %lld (%s) (failed)\n", (long long)frame->pid, comm); return SYSPROF_CB_OK; @@ -1242,11 +1072,16 @@ sysprof_unwind_cb (SysprofCaptureFrame *frame, void *arg) sui->last_dwfl = dwfl; #endif sui->last_pid = frame->pid; - int rc = dwfl_getthread_frames (dwfl, ev->tid, sysprof_unwind_frame_cb, sui); + uint64_t regs_mask = ebl_perf_frame_regs_mask (default_ebl); + int rc = dwfl_perf_sample_getframes (dwfl, elf, frame->pid, ev->tid, + (uint8_t *)&ev->data, ev->size, + regs->regs, regs->n_regs, + regs_mask, regs->abi, + sysprof_unwind_frame_cb, sui); if (rc < 0) { if (show_failures) - fprintf(stderr, "dwfl_getthread_frames pid %lld: %s\n", + fprintf(stderr, "dwfl_perf_sample_getframes pid %lld: %s\n", (long long)frame->pid, dwfl_errmsg(-1)); } if (show_samples) @@ -1362,9 +1197,6 @@ parse_opt (int key, char *arg __attribute__ ((unused)), break; case OPT_DEBUG: -#ifdef DEBUG_MEMORY_READ - show_memory_reads = true; -#endif show_frames = true; FALLTHROUGH; case 'v': @@ -1456,9 +1288,6 @@ https://sourceware.org/cgit/elfutils/tree/README.eu-stacktrace?h=users/serhei/eu else if (strcmp(env_verbose, "debug") == 0 || strcmp(env_verbose, "2") == 0) { -#ifdef DEBUG_MEMORY_READ - show_memory_reads = true; -#endif show_frames = true; show_samples = true; show_failures = true; @@ -1524,6 +1353,10 @@ https://sourceware.org/cgit/elfutils/tree/README.eu-stacktrace?h=users/serhei/eu { if (!dwfltab_init()) error (EXIT_BAD, errno, N_("Could not initialize Dwfl table")); + + /* TODO: Generalize to other architectures. */ + default_ebl = ebl_openbackend_machine(EM_X86_64); + struct sysprof_unwind_info sui; sui.output_fd = output_fd; sui.reader = reader; -- 2.47.0