Trace a Crash Address Back to C Source with addr2line
A crash log hands you a bare hex address like 0x401136 and nothing else useful, and addr2line turns that into a source file and line number. This also covers making it useful for real logs: function names, demangling, standard input and inline-frame output. Allow about fifteen minutes.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need GNU addr2line, an executable or relocatable object, and matching debugging information. The examples were checked with GNU Binutils 2.42, package version 2.42-4ubuntu2.10, on this machine. This is a read-only workflow: it does not modify the binary, source tree or core dump, and no command below needs sudo. The cross-prefixed commands aarch64-linux-gnu-addr2line and x86_64-linux-gnu-addr2line expose the same installed manual and are useful when you need to choose a target format explicitly.
1. Check the installed command
Confirm which binary your shell will run and record its version:
$ command -v addr2line
/usr/bin/addr2line
$ addr2line --version
GNU addr2line (GNU Binutils for Ubuntu) 2.42
Checkpoint
If the command is missing, install the distribution's Binutils package through your normal system-management process. Do not copy a random executable into a production debugging environment, and keep the tool version in your incident notes because output details can vary between releases.
2. Build or locate a binary with debug information
addr2line can only report useful source locations when the object contains, or can find, debugging information. For a small reproducible test, create this source file:
#include <stdio.h>
static int add_one(int value)
{
return value + 1;
}
int main(void)
{
printf("%d\n", add_one(41));
return 0;
}
Compile it with symbols and without position-independent executable layout, so the demonstration address stays stable for this build:
$ gcc -g -O0 -fno-pie -no-pie -o /tmp/addr2line-demo /tmp/addr2line-demo.c
$ nm -n /tmp/addr2line-demo | grep -E ' add_one$| main$'
0000000000401136 t add_one
0000000000401149 T main
The address is not universal. Optimisation, compiler version, link order and PIE can all change it: treat 0x401136 as a value from this particular build, not one to paste into a different executable.
3. Translate one address
Pass the executable with -e, followed by the hexadecimal address:
$ addr2line -e /tmp/addr2line-demo 0x401136
/tmp/addr2line-demo.c:4
The normal output shape is FILENAME:LINENO. The address points into add_one, so the result identifies the return statement's source line in this build. You can pass several addresses and get one result per input:
$ addr2line -e /tmp/addr2line-demo 0x401136 0x401149
/tmp/addr2line-demo.c:4
/tmp/addr2line-demo.c:9
Checkpoint
Compare the file path and line with the exact source revision used to build the crashing program. A matching line number from a different checkout is not proof you have the right source.
4. Add the function name and keep the address visible
Use -f for the containing function and -a to print the input address before the other fields:
$ addr2line -e /tmp/addr2line-demo -a -f 0x401136
0x0000000000401136
add_one
/tmp/addr2line-demo.c:4
For logs and terminals, -p is often easier to scan because it puts each result on one line:
$ addr2line -e /tmp/addr2line-demo -p -f 0x401136
add_one at /tmp/addr2line-demo.c:4
Add -s when long build paths are distracting and only the source basename matters:
$ addr2line -e /tmp/addr2line-demo -s -p 0x401136
addr2line-demo.c:4
Do not use -s when two different directories hold files with the same name: the removed path may be exactly the clue that distinguishes generated code from the real source.
5. Feed crash addresses through standard input
If addresses arrive from a log parser or another command, omit them from the command line and send them on standard input:
$ printf '%s\n' 0x401136 0x401149 | addr2line -e /tmp/addr2line-demo -f -p
add_one at /tmp/addr2line-demo.c:4
main at /tmp/addr2line-demo.c:9
This mode also handles symbol-plus-offset input, useful when a log identifies a symbol and a position within it:
$ addr2line -e /tmp/addr2line-demo -a -f -p 'add_one+0x4'
0x000000000040113a: add_one at /tmp/addr2line-demo.c:4
Quote an input containing + when it comes from a shell variable or external text, and validate log data before passing it into a larger command. addr2line interprets its own options; do not concatenate untrusted input into the option area.
6. Interpret missing or incomplete results
Test an address that is not in the sample program:
$ addr2line -e /tmp/addr2line-demo -f -p 0xdeadbeef
?? at ??:0
- Question marks mean the function or file could not be determined.
- Line number 0 means no line information was found.
- Common causes: a wrong executable, an address from a shared library rather than the main executable, stripped debug sections, or an address that was not adjusted for the process's load address.
For a PIE executable or shared library, the address in a crash report may be a runtime address. Establish the module's load mapping and calculate the address relative to the file before using addr2line; do not guess an offset. If the crash log names a module, use the matching build of that module with -e.
The default executable is a.out if you omit -e, which is an easy distraction: always name the file explicitly in incident commands. For a relocatable object, use -j SECTION when the value is an offset relative to a named section rather than an absolute address, and confirm the section and offset with objdump -h before translating.
7. Inspect C++ names and inline frames
Use -C to demangle compiler-generated C++ function names. It only affects demangling, so it cannot restore source information already removed from the binary:
$ addr2line -C -f -p -e /path/to/program 0xADDRESS
Use -i when optimisation has inlined one function into another: the tool prints the direct location and then the enclosing inline scopes. With -p, inline entries print on separate lines marked as inlined. Keep the compiler's debug settings consistent with the binary under investigation.
Warning
Demangling has a recursion limit enabled by default. The manual documents -R as the explicit limited form and -r as the unlimited form. Avoid -r unless you have a specific, trusted symbol that needs it: disabling the limit can allow stack exhaustion while processing a crafted or unusually deep name.
Done means
- Version confirmed. You identified the installed Binutils version and selected the matching executable.
- Right binary used.
-epointed at the exact binary that produced the address. - Result is meaningful. Your output includes a source path and line, or you recorded why it returned
??:0. - Address adjustment checked. PIE or shared-library address adjustment was checked before trusting a runtime address.
- Build consistency kept. Debug and source files came from the same build when investigating a real crash.