llvm-dis.cpp revision 360784
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//      --help   - Output information about command line switches
15//
16//===----------------------------------------------------------------------===//
17
18#include "llvm/Bitcode/BitcodeReader.h"
19#include "llvm/IR/AssemblyAnnotationWriter.h"
20#include "llvm/IR/DebugInfo.h"
21#include "llvm/IR/DiagnosticInfo.h"
22#include "llvm/IR/DiagnosticPrinter.h"
23#include "llvm/IR/IntrinsicInst.h"
24#include "llvm/IR/LLVMContext.h"
25#include "llvm/IR/Module.h"
26#include "llvm/IR/Type.h"
27#include "llvm/Support/CommandLine.h"
28#include "llvm/Support/Error.h"
29#include "llvm/Support/FileSystem.h"
30#include "llvm/Support/FormattedStream.h"
31#include "llvm/Support/InitLLVM.h"
32#include "llvm/Support/MemoryBuffer.h"
33#include "llvm/Support/ToolOutputFile.h"
34#include "llvm/Support/WithColor.h"
35#include <system_error>
36using namespace llvm;
37
38static cl::opt<std::string>
39InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
40
41static cl::opt<std::string>
42OutputFilename("o", cl::desc("Override output filename"),
43               cl::value_desc("filename"));
44
45static cl::opt<bool>
46Force("f", cl::desc("Enable binary output on terminals"));
47
48static cl::opt<bool>
49DontPrint("disable-output", cl::desc("Don't output the .ll file"), cl::Hidden);
50
51static cl::opt<bool>
52    SetImporting("set-importing",
53                 cl::desc("Set lazy loading to pretend to import a module"),
54                 cl::Hidden);
55
56static cl::opt<bool>
57    ShowAnnotations("show-annotations",
58                    cl::desc("Add informational comments to the .ll file"));
59
60static cl::opt<bool> PreserveAssemblyUseListOrder(
61    "preserve-ll-uselistorder",
62    cl::desc("Preserve use-list order when writing LLVM assembly."),
63    cl::init(false), cl::Hidden);
64
65static cl::opt<bool>
66    MaterializeMetadata("materialize-metadata",
67                        cl::desc("Load module without materializing metadata, "
68                                 "then materialize only the metadata"));
69
70namespace {
71
72static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {
73  OS << DL.getLine() << ":" << DL.getCol();
74  if (DILocation *IDL = DL.getInlinedAt()) {
75    OS << "@";
76    printDebugLoc(IDL, OS);
77  }
78}
79class CommentWriter : public AssemblyAnnotationWriter {
80public:
81  void emitFunctionAnnot(const Function *F,
82                         formatted_raw_ostream &OS) override {
83    OS << "; [#uses=" << F->getNumUses() << ']';  // Output # uses
84    OS << '\n';
85  }
86  void printInfoComment(const Value &V, formatted_raw_ostream &OS) override {
87    bool Padded = false;
88    if (!V.getType()->isVoidTy()) {
89      OS.PadToColumn(50);
90      Padded = true;
91      // Output # uses and type
92      OS << "; [#uses=" << V.getNumUses() << " type=" << *V.getType() << "]";
93    }
94    if (const Instruction *I = dyn_cast<Instruction>(&V)) {
95      if (const DebugLoc &DL = I->getDebugLoc()) {
96        if (!Padded) {
97          OS.PadToColumn(50);
98          Padded = true;
99          OS << ";";
100        }
101        OS << " [debug line = ";
102        printDebugLoc(DL,OS);
103        OS << "]";
104      }
105      if (const DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(I)) {
106        if (!Padded) {
107          OS.PadToColumn(50);
108          OS << ";";
109        }
110        OS << " [debug variable = " << DDI->getVariable()->getName() << "]";
111      }
112      else if (const DbgValueInst *DVI = dyn_cast<DbgValueInst>(I)) {
113        if (!Padded) {
114          OS.PadToColumn(50);
115          OS << ";";
116        }
117        OS << " [debug variable = " << DVI->getVariable()->getName() << "]";
118      }
119    }
120  }
121};
122
123struct LLVMDisDiagnosticHandler : public DiagnosticHandler {
124  char *Prefix;
125  LLVMDisDiagnosticHandler(char *PrefixPtr) : Prefix(PrefixPtr) {}
126  bool handleDiagnostics(const DiagnosticInfo &DI) override {
127    raw_ostream &OS = errs();
128    OS << Prefix << ": ";
129    switch (DI.getSeverity()) {
130      case DS_Error: WithColor::error(OS); break;
131      case DS_Warning: WithColor::warning(OS); break;
132      case DS_Remark: OS << "remark: "; break;
133      case DS_Note: WithColor::note(OS); break;
134    }
135
136    DiagnosticPrinterRawOStream DP(OS);
137    DI.print(DP);
138    OS << '\n';
139
140    if (DI.getSeverity() == DS_Error)
141      exit(1);
142    return true;
143  }
144};
145} // end anon namespace
146
147static ExitOnError ExitOnErr;
148
149int main(int argc, char **argv) {
150  InitLLVM X(argc, argv);
151
152  ExitOnErr.setBanner(std::string(argv[0]) + ": error: ");
153
154  LLVMContext Context;
155  Context.setDiagnosticHandler(
156      std::make_unique<LLVMDisDiagnosticHandler>(argv[0]));
157  cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n");
158
159  std::unique_ptr<MemoryBuffer> MB =
160      ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFilename)));
161
162  BitcodeFileContents IF = ExitOnErr(llvm::getBitcodeFileContents(*MB));
163
164  const size_t N = IF.Mods.size();
165
166  if (OutputFilename == "-" && N > 1)
167      errs() << "only single module bitcode files can be written to stdout\n";
168
169  for (size_t i = 0; i < N; ++i) {
170    BitcodeModule MB = IF.Mods[i];
171    std::unique_ptr<Module> M = ExitOnErr(MB.getLazyModule(Context, MaterializeMetadata,
172                                          SetImporting));
173    if (MaterializeMetadata)
174      ExitOnErr(M->materializeMetadata());
175    else
176      ExitOnErr(M->materializeAll());
177
178    BitcodeLTOInfo LTOInfo = ExitOnErr(MB.getLTOInfo());
179    std::unique_ptr<ModuleSummaryIndex> Index;
180    if (LTOInfo.HasSummary)
181      Index = ExitOnErr(MB.getSummary());
182
183    std::string FinalFilename(OutputFilename);
184
185    // Just use stdout.  We won't actually print anything on it.
186    if (DontPrint)
187      FinalFilename = "-";
188
189    if (FinalFilename.empty()) { // Unspecified output, infer it.
190      if (InputFilename == "-") {
191        FinalFilename = "-";
192      } else {
193        StringRef IFN = InputFilename;
194        FinalFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str();
195        if (N > 1)
196          FinalFilename += std::string(".") + std::to_string(i);
197        FinalFilename += ".ll";
198      }
199    } else {
200      if (N > 1)
201        FinalFilename += std::string(".") + std::to_string(i);
202    }
203
204    std::error_code EC;
205    std::unique_ptr<ToolOutputFile> Out(
206        new ToolOutputFile(FinalFilename, EC, sys::fs::OF_Text));
207    if (EC) {
208      errs() << EC.message() << '\n';
209      return 1;
210    }
211
212    std::unique_ptr<AssemblyAnnotationWriter> Annotator;
213    if (ShowAnnotations)
214      Annotator.reset(new CommentWriter());
215
216    // All that llvm-dis does is write the assembly to a file.
217    if (!DontPrint) {
218      M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder);
219      if (Index)
220        Index->print(Out->os());
221    }
222
223    // Declare success.
224    Out->keep();
225  }
226
227  return 0;
228}
229