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/LibraryOptionsContext.h"
50#include "llvm/Support/MemoryBuffer.h"
51#include "llvm/Support/ToolOutputFile.h"
52#include "llvm/Support/WithColor.h"
53#include <system_error>
54using namespace llvm;
55
56static cl::OptionCategory DisCategory("Disassembler Options");
57
58static cl::list<std::string> InputFilenames(cl::Positional,
59 cl::desc("[input bitcode]..."),
60 cl::cat(DisCategory));
61
62static cl::opt<std::string> OutputFilename("o",
63 cl::desc("Override output filename"),
64 cl::value_desc("filename"),
65 cl::cat(DisCategory));
66
67static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals"),
68 cl::cat(DisCategory));
69
70static cl::opt<bool> DontPrint("disable-output",
71 cl::desc("Don't output the .ll file"),
72 cl::Hidden, cl::cat(DisCategory));
73
74static cl::opt<bool>
75 SetImporting("set-importing",
76 cl::desc("Set lazy loading to pretend to import a module"),
77 cl::Hidden, cl::cat(DisCategory));
78
79static cl::opt<bool>
80 ShowAnnotations("show-annotations",
81 cl::desc("Add informational comments to the .ll file"),
82 cl::cat(DisCategory));
83
84static cl::opt<bool>
85 MaterializeMetadata("materialize-metadata",
86 cl::desc("Load module without materializing metadata, "
87 "then materialize only the metadata"),
88 cl::cat(DisCategory));
89
90static cl::opt<bool> PrintThinLTOIndexOnly(
91 "print-thinlto-index-only",
92 cl::desc("Only read thinlto index and print the index as LLVM assembly."),
93 cl::init(Val: false), cl::Hidden, cl::cat(DisCategory));
94
95static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {
96 OS << DL.getLine() << ":" << DL.getCol();
97 if (DILocation *IDL = DL.getInlinedAt()) {
98 OS << "@";
99 printDebugLoc(DL: IDL, OS);
100 }
101}
102
103namespace {
104class CommentWriter : public AssemblyAnnotationWriter {
105private:
106 bool canSafelyAccessUses(const Value &V) {
107 // Can't safely access uses, if module not materialized.
108 const GlobalValue *GV = dyn_cast<GlobalValue>(Val: &V);
109 return !GV || (GV->getParent() && GV->getParent()->isMaterialized());
110 }
111
112public:
113 void emitFunctionAnnot(const Function *F,
114 formatted_raw_ostream &OS) override {
115 if (!canSafelyAccessUses(V: *F))
116 return;
117
118 OS << "; [#uses=" << F->getNumUses() << ']'; // Output # uses
119 OS << '\n';
120 }
121
122 void printInfoComment(const Value &V, formatted_raw_ostream &OS) override {
123 if (!canSafelyAccessUses(V))
124 return;
125
126 bool Padded = false;
127 if (!V.getType()->isVoidTy()) {
128 OS.PadToColumn(NewCol: 50);
129 Padded = true;
130 // Output # uses and type
131 OS << "; [#uses=" << V.getNumUses() << " type=" << *V.getType() << "]";
132 }
133 if (const Instruction *I = dyn_cast<Instruction>(Val: &V)) {
134 if (const DebugLoc &DL = I->getDebugLoc()) {
135 if (!Padded) {
136 OS.PadToColumn(NewCol: 50);
137 Padded = true;
138 OS << ";";
139 }
140 OS << " [debug line = ";
141 printDebugLoc(DL,OS);
142 OS << "]";
143 }
144 }
145 }
146};
147
148struct LLVMDisDiagnosticHandler : public DiagnosticHandler {
149 char *Prefix;
150 LLVMDisDiagnosticHandler(char *PrefixPtr) : Prefix(PrefixPtr) {}
151 bool handleDiagnostics(const DiagnosticInfo &DI) override {
152 raw_ostream &OS = errs();
153 OS << Prefix << ": ";
154 switch (DI.getSeverity()) {
155 case DS_Error: WithColor::error(OS); break;
156 case DS_Warning: WithColor::warning(OS); break;
157 case DS_Remark: OS << "remark: "; break;
158 case DS_Note: WithColor::note(OS); break;
159 }
160
161 DiagnosticPrinterRawOStream DP(OS);
162 DI.print(DP);
163 OS << '\n';
164
165 if (DI.getSeverity() == DS_Error)
166 exit(status: 1);
167 return true;
168 }
169};
170} // namespace
171
172static ExitOnError ExitOnErr;
173
174int main(int argc, char **argv) {
175 InitLLVM X(argc, argv);
176
177 ExitOnErr.setBanner(std::string(argv[0]) + ": error: ");
178
179 cl::HideUnrelatedOptions(Categories: {&DisCategory, &getColorCategory()});
180 cl::LibraryOptionsContext LibraryOptions;
181 cl::parseCommandLineOptions(Context&: LibraryOptions, Args: ArrayRef(argv, argc),
182 Overview: "llvm .bc -> .ll disassembler\n");
183
184 if (InputFilenames.size() < 1) {
185 InputFilenames.push_back(value: "-");
186 } else if (InputFilenames.size() > 1 && !OutputFilename.empty()) {
187 errs()
188 << "error: output file name cannot be set for multiple input files\n";
189 return 1;
190 }
191
192 for (const auto &InputFilename : InputFilenames) {
193 // Use a fresh context for each input to avoid state
194 // cross-contamination across inputs (e.g. type name collisions).
195 LLVMContext Context;
196 Context.getLibraryOptions().assign(Other: LibraryOptions);
197 Context.setDiagnosticHandler(
198 DH: std::make_unique<LLVMDisDiagnosticHandler>(args&: argv[0]));
199
200 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
201 MemoryBuffer::getFileOrSTDIN(Filename: InputFilename);
202 if (std::error_code EC = BufferOrErr.getError()) {
203 WithColor::error() << InputFilename << ": " << EC.message() << '\n';
204 return 1;
205 }
206 std::unique_ptr<MemoryBuffer> MB = std::move(BufferOrErr.get());
207
208 BitcodeFileContents IF = ExitOnErr(llvm::getBitcodeFileContents(Buffer: *MB));
209
210 const size_t N = IF.Mods.size();
211
212 if (OutputFilename == "-" && N > 1)
213 errs() << "only single module bitcode files can be written to stdout\n";
214
215 for (size_t I = 0; I < N; ++I) {
216 BitcodeModule MB = IF.Mods[I];
217
218 std::unique_ptr<Module> M;
219
220 if (!PrintThinLTOIndexOnly) {
221 M = ExitOnErr(
222 MB.getLazyModule(Context, ShouldLazyLoadMetadata: MaterializeMetadata, IsImporting: SetImporting));
223 if (MaterializeMetadata)
224 ExitOnErr(M->materializeMetadata());
225 else
226 ExitOnErr(M->materializeAll());
227 }
228
229 BitcodeLTOInfo LTOInfo = ExitOnErr(MB.getLTOInfo());
230 std::unique_ptr<ModuleSummaryIndex> Index;
231 if (LTOInfo.HasSummary)
232 Index = ExitOnErr(MB.getSummary());
233
234 std::string FinalFilename(OutputFilename);
235
236 // Just use stdout. We won't actually print anything on it.
237 if (DontPrint)
238 FinalFilename = "-";
239
240 if (FinalFilename.empty()) { // Unspecified output, infer it.
241 if (InputFilename == "-") {
242 FinalFilename = "-";
243 } else {
244 StringRef IFN = InputFilename;
245 FinalFilename = (IFN.ends_with(Suffix: ".bc") ? IFN.drop_back(N: 3) : IFN).str();
246 if (N > 1)
247 FinalFilename += std::string(".") + std::to_string(val: I);
248 FinalFilename += ".ll";
249 }
250 } else {
251 if (N > 1)
252 FinalFilename += std::string(".") + std::to_string(val: I);
253 }
254
255 std::error_code EC;
256 std::unique_ptr<ToolOutputFile> Out(
257 new ToolOutputFile(FinalFilename, EC, sys::fs::OF_TextWithCRLF));
258 if (EC) {
259 errs() << EC.message() << '\n';
260 return 1;
261 }
262
263 std::unique_ptr<AssemblyAnnotationWriter> Annotator;
264 if (ShowAnnotations)
265 Annotator.reset(p: new CommentWriter());
266
267 // All that llvm-dis does is write the assembly to a file.
268 if (!DontPrint) {
269 if (M) {
270 M->renumberMetadataForAssembly();
271 M->print(OS&: Out->os(), AAW: Annotator.get(),
272 /* ShouldPreserveUseListOrder */ false);
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