A hex address from a crash log is useless until llvm-addr2line-18 turns it into a file and line number. You will finish with a repeatable way to do that, then add the function name when you need it. The examples use llvm-addr2line-18 from Ubuntu package llvm-18, version 18.1.3. This is an ordinary, read-only diagnostic job: it does not need elevated privileges unless the executable or debug files are unreadable to your own user.
Allow about fifteen minutes. You need the executable that produced the address and its debug information. A compiler-built binary should normally be compiled with debug information, commonly via -g. Keep the exact binary that was running: a rebuilt or stripped replacement can have different addresses even when the source has not changed.
Check the command before feeding it a crash address:
$ command -v llvm-addr2line-18
/usr/bin/llvm-addr2line-18
$ llvm-addr2line-18 --version
Ubuntu LLVM version 18.1.3
Optimized build.
Checkpoint: the command should resolve to the LLVM 18 binary you intend to use. The manpage describes it as an alias for llvm-symbolizer with addr2line-compatible defaults: it treats input addresses as hexadecimal, accepts an optional 0x prefix, and does not print function names, demangle them or show inline frames unless you ask.
Pass the executable with -e and send an address on standard input. Replace the example path and address with values from your own crash report:
$ printf '%s\n' 000000000000115b | llvm-addr2line-18 -e ./sample
./sample.c:5
The output is a source path followed by a line number. This particular address came from a small unoptimised program compiled with debug information; your path and line will differ. It is read as hexadecimal even without the 0x prefix, so do not convert it to decimal first.
For a position-independent executable or shared library, use the address form that suits the image and its load bias. If your debugger or crash collector reports a relocated process address, feeding it in directly can produce ??:0. Get the module-relative address from the same debugging workflow, or use --adjust-vma=<offset> once you have verified the required offset.
Use -a to echo the address and -f to print the function name. Add -C when the name is C++ and you want it demangled:
$ printf '%s\n' 000000000000115b | llvm-addr2line-18 -a -f -C -e ./sample
0x115b
main
./sample.c:5
This three-line shape is easier to match against a list of addresses from a crash report. The short options have long equivalents: --addresses, --functions and --demangle. -C does not discover missing debug information, it only changes how a function name is displayed once one is available.
One address per line lets you process a stack trace without starting the tool over and over:
$ cat crash-addresses.txt
000000000000115b
0000000000001140
$ llvm-addr2line-18 -a -f -C -e ./sample < crash-addresses.txt
0x115b
main
./sample.c:5
0x1140
twice
./sample.c:2
Do not include punctuation copied straight from a log, such as a trailing comma or closing parenthesis. Strip the module name and other text before you pass the address. When several modules appear in a trace, process each module's addresses against its own matching executable or shared object: one -e file cannot symbolise addresses belonging to a different image.
An optimised compiler can inline one function into another. Add -i, or --inlines, to ask for every inline frame at that location:
$ printf '%s\n' ADDRESS | llvm-addr2line-18 -a -f -C -i -e ./sample
Replace ADDRESS with a real hexadecimal value. The number of frames you get back depends on the compiler, optimisation settings and available debug information. The default is one location without inline frames, so a result that only names the outer function is not necessarily a missing crash frame.
For an unknown address, LLVM prints placeholders rather than inventing a location:
$ printf '%s\n' 0x0 | llvm-addr2line-18 -a -f -e ./sample
0x0
??
??:0
Work through these causes in order:
The command also accepts --debug-file-directory=<dir> and --fallback-debug-path=<dir> for debug-file lookup. Keep those directories trusted and read-only for this investigation.
Warning: do not enable --debuginfod on a sensitive system without first checking your organisation's policy, because it can pull debug data from a network service.
The environment variable LLVM_ADDR2LINE_OPTS supplies options for this command. For a controlled shell session, this can set the output shape once:
$ export LLVM_ADDR2LINE_OPTS='-a -f -C'
$ printf '%s\n' 000000000000115b | llvm-addr2line-18 -e ./sample
0x115b
main
./sample.c:5
$ unset LLVM_ADDR2LINE_OPTS
Unset the variable once the investigation is done, or set it explicitly inside a script. A hidden environment option is a classic source of confusion when two apparently identical commands give different output. If a script needs stable, machine-readable data, look at --output-style=JSON and test its output against the LLVM version that script will actually run against.
llvm-addr2line-18 --version reports the expected installed LLVM version.-a -f -C gives you a traceable address, function and source location.LLVM_ADDR2LINE_OPTS setting was removed once the check finished.