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

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

Turn LLVM 18 Bitcode into Readable IR with llvm-dis

You will finish with a safe way to turn an LLVM bitcode file into human-readable LLVM IR, choose the output destination deliberately, and confirm whether a failure is a missing file or a bad input. The examples use llvm-dis-18 from Ubuntu package llvm-18, version 1:18.1.3-1ubuntu1.

Allow about ten minutes. You need a shell, an installed LLVM 18 toolchain, and a bitcode file that you are allowed to read. This command only disassembles bitcode. It does not execute the module, optimise it, or turn it into native machine code. No example needs sudo.

1. Check the installed tool

Start by confirming that the command in your path is the one you expect. This is an ordinary read-only check:

$ command -v llvm-dis-18
/usr/bin/llvm-dis-18
$ llvm-dis-18 --version
Ubuntu LLVM version 18.1.3
  Optimized build.
$ dpkg-query -W -f='${Package} ${Version}\n' llvm-18
llvm-18 1:18.1.3-1ubuntu1

The binary is named llvm-dis-18 on this installation. Keep the versioned name in scripts when you need LLVM 18 specifically, rather than silently selecting another llvm-dis from a different toolchain.

Checkpoint: if command -v prints nothing, stop and install or enable the appropriate LLVM package through your normal system-management process. Do not work around a missing executable by downloading an unrelated binary into a project directory.

2. Disassemble a bitcode file to the default .ll file

Give the input path as the final argument:

$ llvm-dis-18 /path/to/module.bc

For a regular file, the default destination is derived from the input name. An existing .bc suffix is removed and .ll is added, so the command above writes /path/to/module.ll. The result is text containing LLVM IR, not a native assembly listing.

That default can be inconvenient in a source tree. It can also replace a file at the destination, so check before running a command that writes beside valuable work:

$ test ! -e /path/to/module.ll && echo 'destination is free'
$ llvm-dis-18 /path/to/module.bc
$ test -s /path/to/module.ll && echo 'LLVM IR written'

Do not use > to redirect over a useful .ll file unless that replacement is intentional. If you have overwritten an output and still need the previous version, recover it from version control or your backup system. There is no undo operation in llvm-dis-18.

3. Choose an output path explicitly

Use -o when the destination matters:

$ llvm-dis-18 /path/to/module.bc -o /tmp/module-inspection.ll
$ test -s /tmp/module-inspection.ll && echo 'inspection file is non-empty'
inspection file is non-empty

The output argument belongs to llvm-dis-18, not to the bitcode module. A path such as /tmp/module-inspection.ll is useful for a temporary investigation because it keeps generated text away from the source directory. Do not put sensitive IR in a shared temporary directory without considering its permissions and lifetime.

If you want the text on standard output, set the output filename to a single hyphen:

$ llvm-dis-18 /path/to/module.bc -o - | less

This is a read-only inspection pipeline from the shell's point of view: llvm-dis-18 does not create an output file. The displayed module may contain source paths, symbol names or other build details, so treat captured output as potentially sensitive.

4. Read bitcode from standard input

Omit the input filename, or pass -, when another command supplies the bitcode. Send the result to standard output if you do not want a file:

$ cat /path/to/module.bc | llvm-dis-18 -o - | less

This is the useful distinction to remember: a named input defaults to a derived .ll file, while standard input defaults to standard output. Making both sides explicit, as in the example, prevents an unexpected file from appearing in the current directory.

For a quick machine-checkable probe, select a known symbol in the resulting text with a tool such as grep:

$ llvm-dis-18 -o - < /path/to/module.bc | grep -F 'define i32 @answer'
define i32 @answer() {

The exact line depends on the module. A missing match means that symbol is not present; it is not proof that disassembly failed. Check the exit status of llvm-dis-18 separately when a pipeline is part of automation.

5. Use help for the installed option set

LLVM tools expose more options than the short manpage needs to describe. Ask this exact binary when you need the local interface:

$ llvm-dis-18 -help
OVERVIEW: llvm .bc -> .ll disassembler
USAGE: llvm-dis-18 [options] [input bitcode]...

The documented options relevant to this workflow are -o for the output filename, -help for a command summary, and -f to enable binary output on terminals. Leave -f alone for normal IR inspection. It is a terminal-safety override for raw bitcode output, not a way to make a source listing clearer.

6. Diagnose a failed run

A successful disassembly exits with status 0. An error exits non-zero:

$ llvm-dis-18 /path/to/missing.bc -o - >/tmp/llvm-dis.stdout 2>/tmp/llvm-dis.stderr
$ printf 'status: %s\n' "$?"
status: 1
$ sed -n '1p' /tmp/llvm-dis.stderr
error: /path/to/missing.bc: No such file or directory

Check the path and read permission before changing anything:

$ ls -l /path/to/module.bc
$ test -r /path/to/module.bc && echo readable

If the file exists but is not valid LLVM bitcode, keep the original untouched and capture the diagnostic in a separate file. Do not rename a native executable, object file or arbitrary archive to .bc; the suffix does not convert its contents. If a producer created textual LLVM IR, use the matching assembler such as llvm-as-18 to make bitcode, then run llvm-dis-18 on that bitcode.

Done means

  • You confirmed that llvm-dis-18 is LLVM 18.1.3 from the installed llvm-18 package.
  • You can disassemble a named .bc file and predict its default .ll destination.
  • You use -o when an explicit file or standard output is safer.
  • You know that omitted input reads standard input and that -o - writes standard output.
  • You check the exit status and preserve the original bitcode when diagnosing errors.