1//===-- llvm-dis.cpp - The low-level LLVM disassembler --------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This utility may be invoked in the following manner:
10// llvm-dis [options] - Read LLVM bitcode from stdin, write asm to stdout
11// llvm-dis [options] x.bc - Read LLVM bitcode from the x.bc file, write asm
12// to the x.ll file.
13// Options:
14//
15// Color Options:
16// --color - Use colors in output (default=autodetect)
17//
18// Disassembler Options:
19// -f - Enable binary output on terminals
20// --materialize-metadata - Load module without materializing metadata,
21// then materialize only the metadata
22// -o <filename> - Override output filename
23// --show-annotations - Add informational comments to the .ll file
24//
25// Generic Options:
26// --help - Display available options
27// (--help-hidden for more)
28// --help-list - Display list of available options
29// (--help-list-hidden for more)
30// --version - Display the version of this program
31//
32//===----------------------------------------------------------------------===//
33
34#include "llvm/Bitcode/BitcodeReader.h"
35#include "llvm/IR/AssemblyAnnotationWriter.h"
36#include "llvm/IR/DebugInfo.h"
37#include "llvm/IR/DiagnosticInfo.h"
38#include "llvm/IR/DiagnosticPrinter.h"
39#include "llvm/IR/IntrinsicInst.h"
40#include "llvm/IR/LLVMContext.h"
41#include "llvm/IR/Module.h"
42#include "llvm/IR/ModuleSummaryIndex.h"
43#include "llvm/IR/Type.h"
44#include "llvm/Support/CommandLine.h"
45#include "llvm/Support/Error.h"
46#include "llvm/Support/FileSystem.h"
47#include "llvm/Support/FormattedStream.h"
48#include "llvm/Support/InitLLVM.h"
49#include "llvm/Support/MemoryBuffer.h"
50#include "llvm/Support/ToolOutputFile.h"
51#include "llvm/Support/WithColor.h"
52#include <system_error>
53using namespace llvm;
54
55static cl::OptionCategory DisCategory("Disassembler Options");
56
57static cl::list<std::string> InputFilenames(cl::Positional,
58 cl::desc("[input bitcode]..."),
59 cl::cat(DisCategory));
60
61static cl::opt<std::string> OutputFilename("o",
62 cl::desc("Override output filename"),
63 cl::value_desc("filename"),
64 cl::cat(DisCategory));
65
66static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals"),
67 cl::cat(DisCategory));
68
69static cl::opt<bool> DontPrint("disable-output",
70 cl::desc("Don't output the .ll file"),
71 cl::Hidden, cl::cat(DisCategory));
72
73static cl::opt<bool>
74 SetImporting("set-importing",
75 cl::desc("Set lazy loading to pretend to import a module"),
76 cl::Hidden, cl::cat(DisCategory));
77
78static cl::opt<bool>
79 ShowAnnotations("show-annotations",
80 cl::desc("Add informational comments to the .ll file"),
81 cl::cat(DisCategory));
82
83static cl::opt<bool> PreserveAssemblyUseListOrder(
84 "preserve-ll-uselistorder",
85 cl::desc("Preserve use-list order when writing LLVM assembly."),
86 cl::init(Val: false), cl::Hidden, cl::cat(DisCategory));
87
88static cl::opt<bool>
89 MaterializeMetadata("materialize-metadata",
90 cl::desc("Load module without materializing metadata, "
91 "then materialize only the metadata"),
92 cl::cat(DisCategory));
93
94static cl::opt<bool> PrintThinLTOIndexOnly(
95 "print-thinlto-index-only",
96 cl::desc("Only read thinlto index and print the index as LLVM assembly."),
97 cl::init(Val: false), cl::Hidden, cl::cat(DisCategory));
98
99namespace {
100
101static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {
102 OS << DL.getLine() << ":" << DL.getCol();
103 if (DILocation *IDL = DL.getInlinedAt()) {
104 OS << "@";
105 printDebugLoc(DL: IDL, OS);
106 }
107}
108class CommentWriter : public AssemblyAnnotationWriter {
109public:
110 void emitFunctionAnnot(const Function *F,
111 formatted_raw_ostream &OS) override {
112 OS << "; [#uses=" << F->getNumUses() << ']'; // Output # uses
113 OS << '\n';
114 }
115 void printInfoComment(const Value &V, formatted_raw_ostream &OS) override {
116 bool Padded = false;
117 if (!V.getType()->isVoidTy()) {
118 OS.PadToColumn(NewCol: 50);
119 Padded = true;
120 // Output # uses and type
121 OS << "; [#uses=" << V.getNumUses() << " type=" << *V.getType() << "]";
122 }
123 if (const Instruction *I = dyn_cast<Instruction>(Val: &V)) {
124 if (const DebugLoc &DL = I->getDebugLoc()) {
125 if (!Padded) {
126 OS.PadToColumn(NewCol: 50);
127 Padded = true;
128 OS << ";";
129 }
130 OS << " [debug line = ";
131 printDebugLoc(DL,OS);
132 OS << "]";
133 }
134 if (const DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(Val: I)) {
135 if (!Padded) {
136 OS.PadToColumn(NewCol: 50);
137 OS << ";";
138 }
139 OS << " [debug variable = " << DDI->getVariable()->getName() << "]";
140 }
141 else if (const DbgValueInst *DVI = dyn_cast<DbgValueInst>(Val: I)) {
142 if (!Padded) {
143 OS.PadToColumn(NewCol: 50);
144 OS << ";";
145 }
146 OS << " [debug variable = " << DVI->getVariable()->getName() << "]";
147 }
148 }
149 }
150};
151
152struct LLVMDisDiagnosticHandler : public DiagnosticHandler {
153 char *Prefix;
154 LLVMDisDiagnosticHandler(char *PrefixPtr) : Prefix(PrefixPtr) {}
155 bool handleDiagnostics(const DiagnosticInfo &DI) override {
156 raw_ostream &OS = errs();
157 OS << Prefix << ": ";
158 switch (DI.getSeverity()) {
159 case DS_Error: WithColor::error(OS); break;
160 case DS_Warning: WithColor::warning(OS); break;
161 case DS_Remark: OS << "remark: "; break;
162 case DS_Note: WithColor::note(OS); break;
163 }
164
165 DiagnosticPrinterRawOStream DP(OS);
166 DI.print(DP);
167 OS << '\n';
168
169 if (DI.getSeverity() == DS_Error)
170 exit(status: 1);
171 return true;
172 }
173};
174} // end anon namespace
175
176static ExitOnError ExitOnErr;
177
178int main(int argc, char **argv) {
179 InitLLVM X(argc, argv);
180
181 ExitOnErr.setBanner(std::string(argv[0]) + ": error: ");
182
183 cl::HideUnrelatedOptions(Categories: {&DisCategory, &getColorCategory()});
184 cl::ParseCommandLineOptions(argc, argv, Overview: "llvm .bc -> .ll disassembler\n");
185
186 if (InputFilenames.size() < 1) {
187 InputFilenames.push_back(value: "-");
188 } else if (InputFilenames.size() > 1 && !OutputFilename.empty()) {
189 errs()
190 << "error: output file name cannot be set for multiple input files\n";
191 return 1;
192 }
193
194 for (const auto &InputFilename : InputFilenames) {
195 // Use a fresh context for each input to avoid state
196 // cross-contamination across inputs (e.g. type name collisions).
197 LLVMContext Context;
198 Context.setDiagnosticHandler(
199 DH: std::make_unique<LLVMDisDiagnosticHandler>(args&: argv[0]));
200
201 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
202 MemoryBuffer::getFileOrSTDIN(Filename: InputFilename);
203 if (std::error_code EC = BufferOrErr.getError()) {
204 WithColor::error() << InputFilename << ": " << EC.message() << '\n';
205 return 1;
206 }
207 std::unique_ptr<MemoryBuffer> MB = std::move(BufferOrErr.get());
208
209 BitcodeFileContents IF = ExitOnErr(llvm::getBitcodeFileContents(Buffer: *MB));
210
211 const size_t N = IF.Mods.size();
212
213 if (OutputFilename == "-" && N > 1)
214 errs() << "only single module bitcode files can be written to stdout\n";
215
216 for (size_t I = 0; I < N; ++I) {
217 BitcodeModule MB = IF.Mods[I];
218
219 std::unique_ptr<Module> M;
220
221 if (!PrintThinLTOIndexOnly) {
222 M = ExitOnErr(
223 MB.getLazyModule(Context, ShouldLazyLoadMetadata: MaterializeMetadata, IsImporting: SetImporting));
224 if (MaterializeMetadata)
225 ExitOnErr(M->materializeMetadata());
226 else
227 ExitOnErr(M->materializeAll());
228 }
229
230 BitcodeLTOInfo LTOInfo = ExitOnErr(MB.getLTOInfo());
231 std::unique_ptr<ModuleSummaryIndex> Index;
232 if (LTOInfo.HasSummary)
233 Index = ExitOnErr(MB.getSummary());
234
235 std::string FinalFilename(OutputFilename);
236
237 // Just use stdout. We won't actually print anything on it.
238 if (DontPrint)
239 FinalFilename = "-";
240
241 if (FinalFilename.empty()) { // Unspecified output, infer it.
242 if (InputFilename == "-") {
243 FinalFilename = "-";
244 } else {
245 StringRef IFN = InputFilename;
246 FinalFilename = (IFN.ends_with(Suffix: ".bc") ? IFN.drop_back(N: 3) : IFN).str();
247 if (N > 1)
248 FinalFilename += std::string(".") + std::to_string(val: I);
249 FinalFilename += ".ll";
250 }
251 } else {
252 if (N > 1)
253 FinalFilename += std::string(".") + std::to_string(val: I);
254 }
255
256 std::error_code EC;
257 std::unique_ptr<ToolOutputFile> Out(
258 new ToolOutputFile(FinalFilename, EC, sys::fs::OF_TextWithCRLF));
259 if (EC) {
260 errs() << EC.message() << '\n';
261 return 1;
262 }
263
264 std::unique_ptr<AssemblyAnnotationWriter> Annotator;
265 if (ShowAnnotations)
266 Annotator.reset(p: new CommentWriter());
267
268 // All that llvm-dis does is write the assembly to a file.
269 if (!DontPrint) {
270 if (M) {
271 M->removeDebugIntrinsicDeclarations();
272 M->print(OS&: Out->os(), AAW: Annotator.get(), ShouldPreserveUseListOrder: PreserveAssemblyUseListOrder);
273 }
274 if (Index)
275 Index->print(OS&: Out->os());
276 }
277
278 // Declare success.
279 Out->keep();
280 }
281 }
282
283 return 0;
284}
285