From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: multipart/mixed; boundary="===============5649202067257057315==" MIME-Version: 1.0 From: Milian Wolff To: elfutils-devel@lists.fedorahosted.org Subject: example for using libdw(fl) for in-process stack unwinding? Date: Thu, 09 Jun 2016 17:54:52 +0200 Message-ID: <1728920.tHNnYtAtWt@agathebauer> --===============5649202067257057315== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Hey all, from [1] I got that libdw(fl) can be used for unwinding as an alternative t= o = libunwind, i.e. `dwfl_getthread_frames()`. Apparently, it is even considera= bly = faster in the context of Linux perf. I'd like to try that out and compare i= t = 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 involv= ed, = 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 acquainte= d = 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 someth= ing = 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 h= ow = 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=3Dc++11 -g -O0 backtrace.cpp -o backtrace ~~~~~~~~~~~~~~~~~~~~~~~ #define PACKAGE #define PACKAGE_VERSION #include #include #include #include #include namespace dw { static const Dwfl_Callbacks offline_callbacks =3D { 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 !=3D NULL) return 0; *thread_argp =3D 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 =3D *reinterpret_cast(addr); return true; } static const Dwfl_Thread_Callbacks callbacks =3D { 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 =3D dwfl_begin(&offline_callbacks); fprintf(stderr, "%d: %d =3D %s\n", __LINE__, dwfl_errno(), = dwfl_errmsg(dwfl_errno())); assert(dwfl); // TODO: thread specific pid? auto pid =3D getpid(); // TODO: is this the correct way to get the Elf*? auto fd =3D open("/proc/self/exe", O_RDONLY); auto elf =3D elf_begin(fd, ELF_C_READ_MMAP, nullptr); bool attached =3D dwfl_attach_state(dwfl, elf, pid, &callbacks, = nullptr); fprintf(stderr, "%d: %d =3D %s\n", __LINE__, dwfl_errno(), = dwfl_errmsg(dwfl_errno())); assert(attached); auto ret =3D dwfl_getthread_frames(dwfl, pid, &frame_callback, null= ptr); fprintf(stderr, "%d: %d =3D %s\n", __LINE__, dwfl_errno(), = dwfl_errmsg(dwfl_errno())); assert(ret =3D=3D 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 =3D (null) 73: 0 =3D (null) 77: 0 =3D No DWARF information found backtrace: backtrace.cpp:78: void dw::backtrace(): Assertion `ret =3D=3D 0' = failed. Any help appreciated, thanks. -- = Milian Wolff mail@milianw.de http://milianw.de --===============5649202067257057315== Content-Type: application/pgp-signature MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="signature.asc" LS0tLS1CRUdJTiBQR1AgU0lHTkFUVVJFLS0tLS0KVmVyc2lvbjogR251UEcgdjIKCmlFWUVBQkVD QUFZRkFsZFprVXdBQ2drUURBNnlFczBkRTVPNFJBQ2RGZ2RQbHBiWmNPd1hqWTdPYWlMa1dRK1kK VVk0QW13VnpoNlBqTVpDZUlqaFZwczJ3WjBPSzR4ZDUKPW1IbHkKLS0tLS1FTkQgUEdQIFNJR05B VFVSRS0tLS0tCg== --===============5649202067257057315==--