2

I created a simple code in c++ that need to be crashed. I am getting back a backtrace with this error:

/prbsft/bins/Main(_Z5FuncCv+0x14)[0x5571ea64dd80]

Now I'm trying to use addr2line to get the error line in the function.

So I used:

addr2line -e /prbsft/bins/prbMain 0x5594262a8d80

But all I got is 0:??.

I have also tried to use 0x14 address instead of 0x5594262a8d80 but it returns the same result.

I'm using Ubuntu. addr2line version is:

GNU addr2line (GNU Binutils for Ubuntu) 2.30

Any idea?


Here is the output:

Program received signal SIGSEGV, Segmentation fault. 0x0000555555554d80 in FuncC () at main.cpp:34
warning: Source file is more recent than executable.
34 std::cout << k->n << std::endl;
(gdb) bt
#0 0x0000555555554d80 in FuncC () at main.cpp:34
#1 0x0000555555554db1 in FuncB () at main.cpp:39
#2 0x0000555555554dbd in FuncA () at main.cpp:44
#3 0x0000555555554dda in main () at main.cpp:53
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Yaron Israeli
  • 321
  • 3
  • 13
  • Did you compile your code with debug information? Do you have a core dump? – accdias May 08 '19 at 17:26
  • 1. Yes (using -rdynamic -g) 2. Yes (but I'm running on VM) – Yaron Israeli May 08 '19 at 17:30
  • I found something very weird.. I called to objdump on my bin file, and when I searched for address 14 or 5594262a8d80 I haven't found any mention of these addresses. But when I tried to call addr2line with address that mentioned on objdump, the output was OK (and not 0:??) – Yaron Israeli May 08 '19 at 17:31
  • Do you have gdb installed? You can do a backtrace using it on the core dump by issuing a 'bt' command. – accdias May 08 '19 at 17:34
  • So there you go... ```main.cpp``` line 53 is the point where you are going to look for in your code. – accdias May 08 '19 at 18:34
  • 2
    Yes I know, but my question was why addr2line isn't working? – Yaron Israeli May 08 '19 at 18:37
  • I think your executable may be PIE, making things harder to symbolicate. You may have to manually add 0x14 to the address of `_Z5FuncCv` (use nm to get it) and pass that to addr2line. – Mark Plotnick May 09 '19 at 01:29

1 Answers1

3

The 0x55XXXXXXXXXX address you got is most likely the memory address of the function after the EXE is loaded from disk. addr2line only recognizes VMA addresses like the ones that you got from disassembling with objdump.

enter image description here

Let's call your function Foo. addr2line expects FooVMA or if you're using --section=.text, then Foofile - textfile. Functions like backtrace returns Foomem. One easy way that works most of the time is to calculate FooVMA = Foofile = Foomem - ELFmem. But that assumes VMAbase = 0, which is not true for all linkers (i.e. linker scripts). Examples would be the GCC 5.4 on Ubuntu 16 (0x400000) and clang 11 on MacOS (0x100000000). Here's an example that uses dladdr & dladdr1 to translate it to the VMA address.

#include <execinfo.h>
#include <link.h>
#include <stdlib.h>
#include <stdio.h>

// converts a function's address in memory to its VMA address in the executable file. VMA is what addr2line expects
size_t ConvertToVMA(size_t addr)
{
  Dl_info info;
  link_map* link_map;
  dladdr1((void*)addr,&info,(void**)&link_map,RTLD_DL_LINKMAP);
  return addr-link_map->l_addr;
}

void PrintCallStack()
{
  void *callstack[128];
  int frame_count = backtrace(callstack, sizeof(callstack)/sizeof(callstack[0]));
  for (int i = 0; i < frame_count; i++)
  {
    char location[1024];
    Dl_info info;
    if(dladdr(callstack[i],&info))
    {
      // use addr2line; dladdr itself is rarely useful (see doc)
      char command[256];
      size_t VMA_addr=ConvertToVMA((size_t)callstack[i]);
      //if(i!=crash_depth)
        VMA_addr-=1;    // https://stackoverflow.com/questions/11579509/wrong-line-numbers-from-addr2line/63841497#63841497
      snprintf(command,sizeof(command),"addr2line -e %s -Ci %zx",info.dli_fname,VMA_addr);
      system(command);
    }
  }
}

void Foo()
{
  PrintCallStack();
}

int main()
{
  Foo();
  return 0;
}
Yale Zhang
  • 1,447
  • 12
  • 30