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

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

Trace Crash Addresses Back to C and C++ Source with llvm-symbolizer-18

You will turn a machine address from a native crash, backtrace or profiler into a function name and source location. This guide uses the llvm-symbolizer-18 package installed on Ubuntu, reported here as LLVM 18.1.3. Allow about 10 minutes if you already have the executable and its debug information, or longer if you need to find a matching debug file.

Before you start

  1. Have the exact object file that was running when the address was recorded. A rebuilt binary, a different shared library or a different architecture can make an address point somewhere else.
  2. Keep debug information available. Compile your own test program with -g, or obtain the unstripped executable or separate debug package for a deployed binary.
  3. Have one address in hexadecimal, such as 0x0000000000001170. A raw address from a shared library or position-independent executable may need the load offset corrected first.

No elevated privileges are needed. The command reads files and writes only to standard output. Do not paste sensitive crash logs into a remote service merely to symbolise them; local symbolisation keeps paths and function names on the machine where you run it.

Checkpoint 1: confirm the installed tool

Check that the versioned executable is the one you intend to use:

llvm-symbolizer-18 --version

On the system used for this guide, the result begins:

llvm-symbolizer
Ubuntu LLVM version 18.1.3

The package is llvm-18. If your shell says the command is not found, install the package using your normal package-management process. That is a system change, so check your distribution's repository and maintenance policy before doing it.

Step 1: symbolise one address

Pass the executable with --obj and put the address after it. This example uses a deliberately obvious placeholder path:

llvm-symbolizer-18 --obj=/path/to/my-program 0x0000000000400490

With usable debug data, the default LLVM output has the function first and the source location on the next line:

some_function()
/path/to/source.c:42:7

The exact function, path, line and column depend on your binary. If the address cannot be matched, the tool reports that source information was not found. That normally means the object, address, load adjustment or debug data does not match, not that the source line is necessarily invalid.

For a quick local check, this command uses the executable itself. It does not modify it:

llvm-symbolizer-18 --obj=/usr/bin/llvm-symbolizer-18 0x0000000000000000

An arbitrary address such as zero is expected not to resolve. Use a real address from a crash report for useful output.

Step 2: process addresses from a file or pipe

If you omit positional addresses, llvm-symbolizer-18 reads them from standard input. This is useful when a crash handler or another command already produces one address per line:

printf '%s\n' 0x0000000000400490 0x00000000004004d0 |
  llvm-symbolizer-18 --obj=/path/to/my-program

By default, each result is separated in the readable LLVM format. If your input contains addresses from several files, include the object name on each input line instead of using one global --obj:

cat addresses.txt
FILE:/path/to/first-program 0x0000000000400490
FILE:/path/to/plugin.so 0x0000000000001234

Then run:

llvm-symbolizer-18 < addresses.txt

FILE: makes the meaning explicit; an unprefixed input name is also treated as an object-file path. A BUILDID: prefix instead asks for lookup by hexadecimal build ID. The latter needs a matching debug-binary search setup, so use an explicit object path when you have one.

Step 3: choose output for people or programs

Use pretty output while investigating a single crash:

llvm-symbolizer-18 --obj=/path/to/my-program \
  --pretty-print 0x0000000000400490

The result is compact, for example some_function() at /path/to/source.c:42:7. Inlined calls are included by default. Add --no-inlines when you need only the outer frame, or --verbose when you need function-start and line metadata.

For a script, request JSON rather than parsing human-readable lines:

llvm-symbolizer-18 --output-style=JSON \
  --obj=/path/to/my-program 0x0000000000400490

With command-line addresses, the result is a JSON array. With addresses supplied through standard input, the tool emits a series of JSON objects. That distinction matters if your consumer expects one document rather than a stream.

Step 4: make paths and addresses comparable

Absolute source paths can be noisy in logs. --basenames prints only the source filename, while --relativenames prints the path relative to the compilation directory:

llvm-symbolizer-18 --obj=/path/to/my-program \
  --relativenames 0x0000000000400490

Do not use either option as a repair for missing debug data. They change how a resolved path is displayed.

When the recorded address is relative to a loaded image rather than the address range expected by the object file, use --adjust-vma with the verified offset:

llvm-symbolizer-18 --obj=/path/to/my-program \
  --adjust-vma=0x1000 0x0000000000400490

Work out the offset from the crash report and the process's memory map. Do not guess it. An incorrect adjustment silently sends the lookup to the wrong place.

Common failure checks

  • No source information: confirm that the object is the exact build that produced the address and that its debug information is present. A stripped executable may need its separate debug file and --debug-file-directory or --fallback-debug-path.
  • Unexpected function names: demangling is enabled by default. Use --no-demangle to inspect the linker-level name, or --functions=short and --functions=none to control function-name detail.
  • Addresses from a shared object: check whether the logged value is an absolute process address or an offset inside the module. Apply --adjust-vma only after confirming the arithmetic.
  • Different columns or frames: optimisation and inlining change the mapping. Compare the compiler flags and build ID, not only the filename.
  • Remote debug lookup: --debuginfod can search servers named by DEBUGINFOD_URLS when the build supports it. Treat those servers as an information boundary and prefer local debug files for confidential binaries.

Done means

  • llvm-symbolizer-18 --version reports the expected LLVM 18 installation.
  • The exact object file and matching debug information are identified.
  • A test address resolves to the expected function and source location, or the unresolved result has a documented address, build or debug-data explanation.
  • Your chosen output mode is deliberate: readable LLVM or pretty output for investigation, JSON for automation.
  • Any VMA adjustment and path shortening option is recorded alongside the command that produced the result.