In the man page, the backtrace()
function on Linux says:
Note that names of "static" functions are not exposed, and won't be available in the backtrace.
However, with debugging symbols enabled (-g
), programs like addr2line
and gdb
can still get the names of static functions. Is there a way to get the names of static functions programmatically from within the process itself?
Yes, by examining its own executable (
/proc/self/exe
) using e.g.libbfd
or an ELF file parsing library, to parse the actual symbols themselves. Essentially, you'd write C code that does the equivalent of something likeAs far as I know, the dynamic linker interface in Linux (
<dlfcn.h>
) does not return addresses for static (local) symbols.A simple and pretty robust approach is to execute
readelf
orobjdump
from your program. Note that you cannot give the/proc/self/exe
pseudo-file path to those, since it always refers to the process' own executable. Instead, you have to use eg.realpath("/proc/self/exe", NULL)
to obtain a dynamically allocated absolute path to the current executable you can supply to the command. You also definitely want to ensure the environment containsLANG=C
andLC_ALL=C
, so that the output of the command is easily parseable (and not localized to whatever language the current user prefers). This may feel a bit kludgy, but it only requires thebinutils
package to be installed to work, and you don't need to update your program or library to keep up with the latest developments, so I think it is overall a pretty good approach.Would you like an example?
One way to make it easier, is to generate separate arrays with the symbol information at compile time. Basically, after the object files are generated, a separate source file is dynamically generated by running
objdump
orreadelf
over the related object files, generating an array of names and pointers similar toperhaps with a simple search function exported in a header file, so that when the final executable is linked, it can easily and efficiently access the array of local symbols.
It does duplicate some data, since the same information is already in the executable file, and if I remember correctly, you have to first link the final executable with a stub array to obtain the actual addresses for the symbols, and then relink with the symbol array, making it a bit of a hassle at a compile time.. But it avoids having a run-time dependence on
binutils
.