Home / Alt manpages / llvm-symbolizer-20(1)

  • llvm-symbolizer-20(1)
  • User command
  • linux

Turn Crash Addresses into Source Locations with llvm-symbolizer-20

You will finish with a repeatable way to map an address or symbol name back to a function and source location, then switch the result to JSON when a script needs it. The examples target Ubuntu's llvm-20 package, installed here as 20.1.8. Allow about fifteen minutes. You need the symbolizer and an ELF object with debug information. No root privileges are needed.

Safety boundary

This tool reads object files and debug data. It does not modify the binary. The sensitive part is the data you give it: crash addresses and source paths can disclose details about a private program, so do not paste its output into a public issue without checking it.

1. Check the installed tool

Confirm that the versioned command is the one on your path. These are ordinary read-only commands:

$ command -v llvm-symbolizer-20
/usr/bin/llvm-symbolizer-20
$ llvm-symbolizer-20 --version
Ubuntu LLVM version 20.1.8
  Optimized build.
$ dpkg-query -W -f='${Package} ${Version}\n' llvm-20
llvm-20 1:20.1.8~++20250804090239+87f0227cb601-1~exp1~20250804210352.139

The package version and the command's version line are worth recording with a crash report. Symbol names, debug formats and output fields can differ between LLVM releases.

Checkpoint

If command -v finds nothing, install the distribution package through your normal change process. Do not work around a missing binary by downloading an unverified executable.

2. Keep the debug binary beside the crash data

Symbolization needs the object file that contains the relevant code and, for file and line results, usable debug information. It can be an executable, shared object or object file. A stripped production binary may need its separate debug file, a build-ID lookup directory or a debuginfod service.

Do not guess the object from the process name. Record the exact build, architecture and deployment revision that produced the address. An address from one build is not reliable when looked up in another. You can inspect a candidate without changing it:

$ file /path/to/program
$ readelf -n /path/to/program | grep -A1 'Build ID'

Those commands may show a different build ID or no debug data at all. That is a diagnosis, not a reason to edit the executable. If debug information is stored separately, use --debug-file-directory, --fallback-debug-path or the build-ID lookup mode described in the installed manual.

3. Symbolize one address or name

Pass the object with --obj, then give an address. Hexadecimal input is a clear convention for crash reports:

$ llvm-symbolizer-20 --obj=/path/to/program 0xADDRESS
function_name
/source/path/file.cpp:LINE:COLUMN

Replace 0xADDRESS with the address from the crash and keep the object path quoted if it contains spaces. The default LLVM output prints the function and source location as separate lines, with a blank line between reports. An address that is outside the relevant image, or a binary without matching debug data, commonly produces ?? and ??:0:0.

You can look up a symbol name instead of an address. This is useful for checking the binary and the demangler before processing a crash log:

$ llvm-symbolizer-20 --obj=/path/to/program main

C++ names are demangled by default. Use --no-demangle when you need the linkage name exactly as stored, or --functions=none when a downstream tool only wants locations.

4. Feed several addresses from standard input

With no positional addresses, the command reads standard input. This keeps a saved list of addresses separate from the command line:

$ llvm-symbolizer-20 --obj=/path/to/program < crash-addresses.txt
function_one
/source/path/one.c:42:7

function_two
/source/path/two.c:18:3

Input lines can also include the object name, which is useful when one report contains frames from several shared objects:

$ llvm-symbolizer-20 < frames.txt
FILE:/path/to/program 0xADDRESS
FILE:/path/to/libmodule.so 0xOTHER_ADDRESS

FILE: explicitly marks a value as an object path. A bare path is treated as an object path too. The BUILDID: prefix selects an object by hexadecimal build ID, provided the debug-file search path is configured.

Common trap: if addresses are supplied on the command line without an object name, the first value can be interpreted as the input name. Make the object explicit with --obj when processing ordinary crash addresses.

5. Choose output for people or programs

For a terminal report, --pretty-print puts the function and location on one readable line. --print-address keeps the address beside it:

$ llvm-symbolizer-20 --obj=/path/to/program \
    --pretty-print --print-address 0xADDRESS
0xADDRESS: function_name at /source/path/file.cpp:LINE:COLUMN

For automation, request JSON and parse the fields rather than splitting the default human-oriented text:

$ llvm-symbolizer-20 --output-style=JSON \
    --obj=/path/to/program 0xADDRESS

When addresses are positional arguments, JSON is one array containing all results. When addresses arrive through standard input, the command emits a series of individual JSON objects. That difference matters if a parser expects one complete JSON document. Use --pretty-print with JSON only when indented output is easier for a person to inspect.

6. Correct the address and path details

Shared libraries and position-independent executables are often reported with a runtime address, while the symbolizer may need an address relative to the image. If the report provides a load bias, apply it deliberately with --adjust-vma or use the version's relative-address option where appropriate. Do not add an offset until you know whether the crash collector already subtracted the image base. Applying the correction twice gives a plausible-looking but wrong result.

Paths can be made easier to share with these read-only presentation options:

  • --basenames removes directory components.
  • --relativenames prints paths relative to the compilation directory.
  • --print-source-context-lines=N adds source lines around each result, if the source file is available.
  • --verbose exposes function start, line, column and address details for investigation.

Use --skip-line-zero only when you accept approximate line information. Its output is labelled approximate because the last line in a line-table sequence may not be the exact source statement for the address.

7. Diagnose an unhelpful result

First verify the binary, then verify the address's coordinate system, then verify debug data. Keep the checks in that order:

  1. Run llvm-symbolizer-20 --version and confirm the expected toolchain.
  2. Compare the object's build ID with the executable or shared object named by the crash report.
  3. Retry with --verbose and --print-address so the lookup can be audited.
  4. Check the image base and any load-bias adjustment before changing flags.

If the output is ??, do not treat it as a source line. It means the supplied object and address did not produce a symbolized location. A missing source file affects context display, but it does not by itself prove that the debug information is absent. Keep the original address, object path, build ID and command line in the report so the lookup can be reproduced.

Done means

  • You recorded the installed llvm-symbolizer-20 and llvm-20 versions.
  • You matched the crash address to the exact executable or shared object build.
  • A single lookup returns a function and source location, or you have documented why it returns ??.
  • You can process standard-input batches without confusing an input name with an address.
  • You use JSON for parsers and human-readable output for terminal investigation.
  • Any load-bias adjustment is based on the crash collector's address convention, not trial and error.