Search code examples
c++linuxstack-tracex86-64backtrace

backtrace function inside shared libraries


I'm trying to obtain and save a stack trace to a file after I get SEGSEGV inside my shared library. The shared library is a plugin for a closed-source product. All this works on production and I don't have a direct access to it.

My code catches SIGSEGV signal, prints stack-trace and exits. I have something like this:

/opt/ecelerity/libexec/site/ec_attachextensions.so [0x2aecc2019f11] /opt/ecelerity/libexec/site/ec_attachextensions.so [0x2aecc2019f11] /opt/ecelerity/libexec/site/ec_attachextensions.so [0x2aecc2019fee] /opt/ecelerity/libexec/site/ec_attachextensions.so [0x2aecc201a587]

/opt/ecelerity/sbin/ecelerity [0x501235]

/opt/ecelerity/sbin/ecelerity(sieve_seng_execute+0x82) [0x506d32] /opt/ecelerity/libexec/validate/sieve.so [0x2aecc2862c9e] /opt/ecelerity/sbin/ecelerity(validate_data+0xa5) [0x4a90d5] /opt/ecelerity/sbin/ecelerity(esmtp_message_factory+0x154e) [0x46eace] /opt/ecelerity/sbin/ecelerity(schedule_event_and_dispatch+0x6a) [0x49c59a]

The problem is that I cannot have the names of functions and offsets inside them for a shared library. As I understand I can find function name/file name for a given address with help of addr2line utility after I will find library offset in /proc/$PID/maps.

After that I'm executing something like that:

addr2line -e /opt/ecelerity/libexec/site/ec_attachextensions.so (LIBRARY_OFFSET_FROM_MAPS_FILE - 0x2aecc2019f11)

Where 0x2aecc2019f11 is the address from the stack trace above. I was wondering is there any way I can get function names in a stack trace without touching maps file? In other words how can I program it? Would dladdr help here (dladdr unable to get function names from addresses provided by backtrace function in my case)?


Solution

  • the backtrace code uses approximately the same mechanism as dladdr to determine function names.

    if your library is built using either a linker map file (that defines what is being exported, and can be used to restrict the visibility of all other items), or the -fvisibility=hidden with explicit visible symbols, then it obscures the symbols so that they will not appear in the backtrace output.

    Workarounds are to compile without using a map file that restricts the visibility of all the symbols in the library, or to build with the -fvisibility=default. That will get backtrace to work without any effort on your behalf.

    To get it to work without doing this, you need to load up the local symbol table from the .so and determine the symbol locations using a mechanism similar to addr2line. The mechanism to do this is to make use of libelf1. to read the local symbol table.

    ... This of course requires that the table has not been stripped from the file. If that is the case, then none of these tricks matter as the .so simply does not come with the information.