This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Hey all, from [1] I got that libdw(fl) can be used for unwinding as an alternative to libunwind, i.e. `dwfl_getthread_frames()`. Apparently, it is even considerably faster in the context of Linux perf. I'd like to try that out and compare it to libunwind in the context of my heaptrack tracer. [1]: https://lwn.net/Articles/579508/ But, so far, I could not find an example for using libdw(fl) for in-process stack unwinding. All examples I can find out there use libunwind for the unwinding and libdw only for the DWARF debug information interpretation. I've tried my shot at implementing a trivial example around `dwfl_getthread_frames` but struggle with the API a lot. It is quite involved, contrary to a simple `unw_backtrace`, or even to the manual stepping with libunwind over the `unw_local_addr_space`. The documentation of libdw(fl) often refers to terms that I have no clue about as I'm not deeply acquainted with the DWARF and ELF specs. Problems I'm facing are: - Am I correct in assuming that in-process is the opposite of "offline use" referred to in the libdwfl API documentation? * If so, what should I set `Dwfl_Callbacks::section_address` to? - How do I attach state in-process? `dwfl_attach_state` sounds like the correct choice, as `dwfl_linux_proc_attach` mentions ptrace which I don't want/need. So, assuming it's `dwfl_attach_state`: What is the correct way to get an `Elf *` for my current executable? Do I really `open("/proc/self/exe")` and pass that to `elf_begin`? What Elf_Cmd should I use? ELF_C_READ? How should the obligatory callbacks of Dwfl_Thread_Callbacks be implemented? * next_thread: I'm only interested in the current thread, so doing something similar to perf should be possible here * memory_read: just cast the address to a pointer and dereference it? * set_initial_registers: no clue, really Is there an easy-to-grasp example out there somewhere for me to follow on how to use libdw(fl) for in-process stack unwinding? For reference, here's my current non-functional attempt, which you can compile with g++ -ldw -lelf -std=c++11 -g -O0 backtrace.cpp -o backtrace ~~~~~~~~~~~~~~~~~~~~~~~ #define PACKAGE #define PACKAGE_VERSION #include <elfutils/libdw.h> #include <elfutils/libdwfl.h> #include <unistd.h> #include <cassert> #include <fcntl.h> namespace dw { static const Dwfl_Callbacks offline_callbacks = { dwfl_build_id_find_elf, dwfl_standard_find_debuginfo, // TODO: we are in-process, not offline, or? dwfl_offline_section_address, nullptr, }; bool set_initial_registers(Dwfl_Thread *thread, void *arg) { // TODO: what to do here? return true; } static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp) { // TODO: what to do here? Code below is copied from perf, probably wrong here /* We want only single thread to be processed. */ if (*thread_argp != NULL) return 0; *thread_argp = arg; return dwfl_pid(dwfl); } static bool memory_read(Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg) { // TODO: what to do here? We are in-process, so can we just do the following? *result = *reinterpret_cast<Dwarf_Word*>(addr); return true; } static const Dwfl_Thread_Callbacks callbacks = { next_thread, nullptr, memory_read, set_initial_registers, nullptr, nullptr }; int frame_callback(Dwfl_Frame* frame, void* data) { return DWARF_CB_OK; } void backtrace() { auto dwfl = dwfl_begin(&offline_callbacks); fprintf(stderr, "%d: %d = %s\n", __LINE__, dwfl_errno(), dwfl_errmsg(dwfl_errno())); assert(dwfl); // TODO: thread specific pid? auto pid = getpid(); // TODO: is this the correct way to get the Elf*? auto fd = open("/proc/self/exe", O_RDONLY); auto elf = elf_begin(fd, ELF_C_READ_MMAP, nullptr); bool attached = dwfl_attach_state(dwfl, elf, pid, &callbacks, nullptr); fprintf(stderr, "%d: %d = %s\n", __LINE__, dwfl_errno(), dwfl_errmsg(dwfl_errno())); assert(attached); auto ret = dwfl_getthread_frames(dwfl, pid, &frame_callback, nullptr); fprintf(stderr, "%d: %d = %s\n", __LINE__, dwfl_errno(), dwfl_errmsg(dwfl_errno())); assert(ret == 0); dwfl_end(dwfl); } } void a() { dw::backtrace(); } void b() { a(); } void c() { b(); } int main() { c(); return 0; } ~~~~~~~~~~~~~~~~~~~~ The output I get is: 62: 0 = (null) 73: 0 = (null) 77: 0 = No DWARF information found backtrace: backtrace.cpp:78: void dw::backtrace(): Assertion `ret == 0' failed. Any help appreciated, thanks. -- Milian Wolff mail@milianw.de http://milianw.de
Attachment:
signature.asc
Description: PGP signature
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |