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

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

Demangle C++ symbols from binaries with llvm-cxxfilt-18

You will turn names such as _Z3foov into readable C++ names such as foo(), either as command-line arguments or in a pipeline. This is useful when reading linker errors, symbol tables and crash reports. The examples use Ubuntu's llvm-18 package, version 18.1.3, and take about five minutes to try. No elevated privileges are needed.

What you need

Install or otherwise obtain the llvm-cxxfilt-18 executable before starting. On the machine used for these examples, it is provided by the llvm-18 package:

command -v llvm-cxxfilt-18
llvm-cxxfilt-18 --version

Expected output includes:

/usr/bin/llvm-cxxfilt-18
llvm-cxxfilt-18
Ubuntu LLVM version 18.1.3

If the first command prints nothing, stop at this checkpoint. The command is not available on your PATH; changing the shell configuration or installing packages is separate from demangling.

1. Demangle named symbols

Pass one or more symbol names after the command. Each result is printed on its own line, in the same order as the arguments.

llvm-cxxfilt-18 _Z3foov _Z3bari not_mangled

The output is:

foo()
bar(int)
not_mangled

An input that is not recognised is printed unchanged. That is a useful property when processing mixed symbol lists: an unchanged line means "no demangling was applied", not necessarily that the command failed.

2. Demangle a stream from standard input

With no names on the command line, llvm-cxxfilt-18 reads names interactively from standard input. In a script, make the input explicit with a pipe:

printf '%s\n' '| _Z3foov *** _Z3bari *** not_mangled |' | llvm-cxxfilt-18

Expected output:

| foo() *** bar(int) *** not_mangled |

Input lines are split around characters that cannot belong to an Itanium mangled name. Letters, numbers, full stops, dollar signs and underscores are retained as possible name characters; separators are copied to the output. This lets you feed text containing punctuation, but it does not parse arbitrary compiler diagnostics or identify which words are definitely symbols.

For a real symbol table, keep the producer and consumer in one pipeline. For example, if symbols.txt contains one mixed line per record:

llvm-cxxfilt-18 < symbols.txt > symbols-readable.txt

This creates or replaces symbols-readable.txt. The command does not alter symbols.txt, but shell redirection can overwrite an existing destination without asking. Check the destination name before pressing Enter, or choose a new output file. To undo this example, remove only the output file if it is disposable:

rm -- symbols-readable.txt

That removal is irreversible unless another copy exists. Do not use it for a file you need to keep.

3. Choose how much detail to show

The default auto format detects the mangling style. You can request the GNU/Itanium style explicitly:

llvm-cxxfilt-18 --format=gnu _Z3foov

It prints foo(). The short form is -s gnu. Use this when a script has already established the format; otherwise, leave detection enabled.

To omit function parameters and return types, use --no-params or -p:

llvm-cxxfilt-18 --no-params _Z3foov _Z3bari
foo
bar

This shorter form is convenient for a quick list, but it throws away information that can distinguish overloaded functions. Keep the default output when investigating a compile or link failure.

Use --types or -t when the input may contain encoded type names as well as function names. Use --help or -h to inspect the options provided by this installed executable.

4. Handle leading underscores deliberately

--strip-underscore (short form -_) removes one leading underscore before demangling. --no-strip-underscore (short form -n) preserves it. On ordinary non-Mach-O hosts, preserving the underscore is the default; Mach-O based hosts default to stripping it.

Do not add one of these switches just because a symbol looks unfamiliar. First check how the producer recorded the name and whether the target is Mach-O. Stripping the wrong underscore can turn valid input into a name that cannot be demangled. You can check the local default without changing any files:

llvm-cxxfilt-18 --no-strip-underscore _Z3foov

The expected result on this Linux machine is foo(). The option controls preprocessing of each input name; it does not rename anything in the binary.

Common traps and failure checks

  • Nothing changes: the input may already be readable, may use a mangling scheme this tool does not recognise, or may have been damaged by an earlier text filter. Try one known value such as _Z3foov before diagnosing the larger pipeline.
  • Arguments and files look different: command-line arguments produce one output line per argument. Standard input preserves separators and can demangle several candidates within one line.
  • Shell expansion changes a name: quote names containing $, spaces or wildcard characters. For example, use llvm-cxxfilt-18 'name$part', not an unquoted value.
  • A script continues after a bad invocation: the program returns zero unless it encounters a usage error. Capture its status when the distinction matters: llvm-cxxfilt-18 --bad-option; printf 'status=%s\n' "$?".

Done means

  • llvm-cxxfilt-18 --version reports the executable you intended to use.
  • A known symbol such as _Z3foov becomes foo().
  • Your pipeline preserves separators and leaves unrecognised text visible.
  • You selected parameter and underscore behaviour knowingly, rather than treating an unchanged name as a fatal error.