Turn LLVM Bitcode into Readable IR with llvm-dis-20
You will finish with a repeatable way to turn an LLVM bitcode file into human-readable LLVM IR, send the result to a chosen file or a pipeline, and recognise the most common input error. The examples use llvm-dis-20 from Debian package llvm-20, version 20.1.8, installed on this machine.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need a shell and an existing LLVM bitcode file, usually ending in .bc. The command only reads its input; it does not compile, optimise, execute or rewrite that source file. No elevated privileges are needed unless your input or output path is not readable or writable by your account.
1. Check the installed command
Confirm that the command on your path is the LLVM 20 build you expect:
$ command -v llvm-dis-20
/usr/bin/llvm-dis-20
$ llvm-dis-20 --version
Ubuntu LLVM version 20.1.8
Optimized build.
The manpage calls the tool llvm-dis, while this package installs the versioned executable llvm-dis-20. Keep the suffix when several LLVM releases are installed. The available options in this installed version are -f, -help and -o.
Checkpoint
The version output should identify LLVM 20. If the command is missing, install or enable the package through your normal system administration process; this guide does not change package state.
2. Disassemble a bitcode file to the default path
Run the command with a bitcode path as its only argument:
$ llvm-dis-20 /path/to/module.bc
For a file input, llvm-dis-20 removes an existing .bc suffix and adds .ll. The example therefore writes /path/to/module.ll. If the input has another name or no .bc suffix, the output name follows that input name with .ll appended.
This default is convenient, but check the destination before running it on valuable work. A generated file can replace an existing output with the same name. Use a new directory or an explicit, unused output path when you need a non-destructive inspection.
$ test ! -e /path/to/module.ll && llvm-dis-20 /path/to/module.bc
$ test -s /path/to/module.ll
$ printf 'disassembly written: %s\n' /path/to/module.ll
disassembly written: /path/to/module.ll
Checkpoint
The final test returns status 0 when the output exists and is non-empty. It is an ordinary command sequence and does not require sudo.
3. Choose the output file explicitly
Use -o when the default name is inconvenient or when the result belongs in a separate working directory:
$ llvm-dis-20 -o /tmp/module-inspection.ll /path/to/module.bc
$ test -s /tmp/module-inspection.ll
$ sed -n '1,12p' /tmp/module-inspection.ll
The output argument is a complete filename, not a directory. Use -o - to send the textual IR to standard output instead:
$ llvm-dis-20 -o - /path/to/module.bc | sed -n '1,12p'
; ModuleID = '/path/to/module.bc'
Safety boundary
Treat an output path as a state-changing choice. Before using a path in a script, decide whether replacement is acceptable. To recover from an unwanted output, remove only that generated .ll file or restore it from your own backup. The input bitcode is not modified by llvm-dis-20.
4. Disassemble standard input in a pipeline
Omit the filename, or pass -, to read bitcode from standard input. Standard output is then the default destination:
$ cat /path/to/module.bc | llvm-dis-20 - | sed -n '1,12p'
; ModuleID = '<stdin>'
source_filename = "/path/to/source.ll"
This is useful when another tool produces bitcode or when you do not want a temporary output file. The <stdin> module label describes how llvm-dis-20 received the bitcode; it does not mean the module is empty. The embedded source filename, when present, is metadata from the bitcode.
For a script, prefer a pipeline that preserves the failure status you care about. A simple direct check is:
$ llvm-dis-20 -o /tmp/module-inspection.ll < /path/to/module.bc
$ printf 'exit status: %s\n' "$?"
exit status: 0
5. Diagnose invalid input
llvm-dis-20 expects LLVM bitcode, not textual .ll IR, an object file or an arbitrary binary. Passing the wrong format produces a non-zero exit status and an error on standard error:
$ llvm-dis-20 /path/to/not-bitcode.ll
llvm-dis-20: error: Invalid bitcode signature
$ printf 'exit status: %s\n' "$?"
exit status: 1
Do not treat a file extension as proof of its format. Check the producer and the file itself, then use llvm-as-20 when you need to assemble textual LLVM IR into bitcode. If the file is truncated or was produced by an incompatible toolchain, keep the original and investigate that producer rather than editing the input in place.
For a compact shell check, capture the status before running another command:
if llvm-dis-20 -o /tmp/module-inspection.ll /path/to/module.bc; then
printf '%s\n' 'LLVM bitcode disassembled'
else
status=$?
printf 'llvm-dis-20 failed with status %s\n' "$status" >&2
exit "$status"
fi
6. Keep the unusual option in context
The -f option enables binary output on terminals. It is not needed for ordinary bitcode disassembly, which produces textual LLVM IR. Avoid it unless you have a specific reason to write raw bitcode to the selected output device; sending binary data to a terminal can make the session unreadable. Use -help to display the installed command's short option summary:
$ llvm-dis-20 -help | sed -n '1,20p'
There is no service to restart and no persistent configuration to undo. The only state introduced by the examples is an output file you deliberately choose.
Done means
llvm-dis-20 --versionreports the intended LLVM release.- A known-good
.bcfile produces readable.lloutput with exit status 0. - You can direct output with
-oor stream it with-o -. - You understand that
.llinput is textual IR, not bitcode accepted by this command. - You have checked the output path before allowing a script to replace a file.