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?
To print a backtrace of the entire stack, use the backtrace command, or its alias bt . This command will print one line per frame for frames in the stack. By default, all stack frames are printed. You can stop the backtrace at any time by typing the system interrupt character, normally Ctrl-c .
A backtrace is a summary of how your program got where it is. It shows one line per frame, for many frames, starting with the currently executing frame (frame zero), followed by its caller (frame one), and on up the stack. Print a backtrace of the entire stack: one line per frame for all frames in the stack.
A backtrace is a list of the function calls that are currently active in a thread. The usual way to inspect a backtrace of a program is to use an external debugger such as gdb. However, sometimes it is useful to obtain a backtrace programmatically from within a program, e.g., for the purposes of logging or diagnostics.
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 like
env LANG=C LC_ALL=C readelf -s executable | awk '($5 == "LOCAL" && $8 ~ /^[^_]/ && $8 !~ /\./)'
As 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
or objdump
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 contains LANG=C
and LC_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 the binutils
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
or readelf
over the related object files, generating an array of names and pointers similar to
const struct {
const char *const name;
const void *const addr;
} local_symbol_names[] = {
/* Filled in using objdump or readelf and awk, for example */
{ NULL, NULL }
};
perhaps 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
.
If your executable (and linked libraries) are compiled with debugging information (i.e. with -g
flag to gcc
or g++
) then you could use Ian Taylor's libbacktrace
(announced here) from inside GCC - see its code here
That library (BSD licensed free software) is using DWARF debug information from executables and shared libraries linked by the process. See its README file.
Beware that if you compile with optimizations, some functions could be inlined (even without being explicitly tagged inline
in the source code, and static
inlined functions might not have any proper own code). Then backtracing won't tell much about them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With