This is the mail archive of the 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]

example for using libdw(fl) for in-process stack unwinding?

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.


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

#include <elfutils/libdw.h>
#include <elfutils/libdwfl.h>
#include <unistd.h>
#include <cassert>
#include <fcntl.h>

namespace dw {

    static const Dwfl_Callbacks offline_callbacks = {
        // TODO: we are in-process, not offline, or?

    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 
        *result = *reinterpret_cast<Dwarf_Word*>(addr);
        return true;

    static const Dwfl_Thread_Callbacks callbacks = {

    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(), 

        // 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, 
        fprintf(stderr, "%d: %d = %s\n", __LINE__, dwfl_errno(), 

        auto ret = dwfl_getthread_frames(dwfl, pid, &frame_callback, nullptr);
        fprintf(stderr, "%d: %d = %s\n", __LINE__, dwfl_errno(), 
        assert(ret == 0);

void a()

void b()

void c()

int main()
    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' 

Any help appreciated, thanks.

Milian Wolff

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]