1

How can I use the -rdynamic flag to ensure glibc's backtrace functions will report the actual function/symbol names in a backtrace?

I'm trying to use C's backtrace functions to create a backtrace. On my MacOS machine, if I use the program from this question

#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>

static void full_write(int fd, const char *buf, size_t len)
{
        while (len > 0) {
                ssize_t ret = write(fd, buf, len);

                if ((ret == -1) && (errno != EINTR))
                        break;

                buf += (size_t) ret;
                len -= (size_t) ret;
        }
}

void print_backtrace(void)
{
        static const char start[] = "BACKTRACE ------------\n";
        static const char end[] = "----------------------\n";

        void *bt[1024];
        int bt_size;
        char **bt_syms;
        int i;

        bt_size = backtrace(bt, 1024);
        bt_syms = backtrace_symbols(bt, bt_size);
        full_write(STDERR_FILENO, start, strlen(start));
        for (i = 1; i < bt_size; i++) {
                size_t len = strlen(bt_syms[i]);
                full_write(STDERR_FILENO, bt_syms[i], len);
                full_write(STDERR_FILENO, "\n", 1);
        }
        full_write(STDERR_FILENO, end, strlen(end));
    free(bt_syms);
}
void foo()
{
    print_backtrace();
}

int main()
{
    foo();
    return 0;
}

and then compile it, I end up with a program that outputs a stack trace including function names.

$ clang main.c 
$ ./a.out 
BACKTRACE ------------
1   a.out                               0x0000000100c9fec9 foo + 9
2   a.out                               0x0000000100c9fee4 main + 20
3   libdyld.dylib                       0x00007fff9669f235 start + 1
----------------------

However, if I attempt to compile the program on an Ubuntu virtual machine using gcc, I get no function names.

$ gcc-5 main.c 
$ ./a.out 
BACKTRACE ------------
./a.out() [0x4008c3]
./a.out() [0x4008d4]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7fbc9fee2830]
./a.out() [0x400649]
----------------------

The aformentioned previous question says the -rdynamic flag is my savior, but when I try that flag I still don't get function names in my backtrace

$ gcc-5 -rdynamic main.c
$ ./a.out 
BACKTRACE ------------
./a.out(foo+0x9) [0x400b63]
./a.out(main+0xe) [0x400b74]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f8cbbf20830]
./a.out(_start+0x29) [0x4008e9]

I'm a little overwhelmed at what to do next -- am I using the flag wrong? Or am I using it correctly and there's something else that might prevent the symbols from showing up in this simple program.

Alana Storm
  • 164,128
  • 91
  • 395
  • 599
  • 1
    symbol names are looked up in debug sections of the executable. So, you need to allow some '-g' flag, like '-g2'. Also, you might want to turn off optimizations with '-O0' – Serge Jan 03 '18 at 19:09
  • 2
    The stack trace you showed _does_ have function names in it. See where it says `a.out(foo+0x9)`? `foo` is the function name. There is one on each line of the trace. – zwol Jan 03 '18 at 19:24
  • 1
    @zwol Ahem -- please pardon me while I firmly palm my face. the different format of the backtrace (from what MacOS/clang produced) tricked me. Thank you for pointing out the obvious. Happy to mark that as the accepted answer if it's a real answer. Otherwise I'll add the answer myself (tagging you) later today. – Alana Storm Jan 03 '18 at 19:29

2 Answers2

3

Per comments above, the -rdynamic flag was working without issue. The problem was that clang on MacOS produced its output in a different format than GCC on my ubuntu VM.

The function name was there all along.

# notice the function name `foo`
./a.out(foo+0x9) [0x400b63]
Alana Storm
  • 164,128
  • 91
  • 395
  • 599
2

You could consider using Ian Taylor's libbacktrace (which is also part of recent GCC) for your backtracing goals. It wants the libraries and executables to be compiled with DWARF information (so you compile with -g passed to gcc, and that can be mixed with optimization flags like -O2). But it gives more precise output (including line numbers for your call stack frames).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547