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.
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.
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.
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.
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.
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.
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.
Test an address that is not in the sample program:
$ addr2line -e /tmp/addr2line-demo -f -p 0xdeadbeef
?? at ??:0
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.
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.
-e pointed at the exact binary that produced the address.??:0.