1//===-- llvm-dis.cpp - The low-level LLVM disassembler --------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This utility may be invoked in the following manner:
11//  llvm-dis [options]      - Read LLVM bitcode from stdin, write asm to stdout
12//  llvm-dis [options] x.bc - Read LLVM bitcode from the x.bc file, write asm
13//                            to the x.ll file.
14//  Options:
15//      --help   - Output information about command line switches
16//
17//===----------------------------------------------------------------------===//
18
19#include "llvm/IR/LLVMContext.h"
20#include "llvm/Bitcode/ReaderWriter.h"
21#include "llvm/IR/AssemblyAnnotationWriter.h"
22#include "llvm/IR/DebugInfo.h"
23#include "llvm/IR/DiagnosticInfo.h"
24#include "llvm/IR/DiagnosticPrinter.h"
25#include "llvm/IR/IntrinsicInst.h"
26#include "llvm/IR/Module.h"
27#include "llvm/IR/Type.h"
28#include "llvm/Support/CommandLine.h"
29#include "llvm/Support/DataStream.h"
30#include "llvm/Support/Error.h"
31#include "llvm/Support/FileSystem.h"
32#include "llvm/Support/FormattedStream.h"
33#include "llvm/Support/ManagedStatic.h"
34#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/PrettyStackTrace.h"
36#include "llvm/Support/Signals.h"
37#include "llvm/Support/ToolOutputFile.h"
38#include <system_error>
39using namespace llvm;
40
41static cl::opt<std::string>
42InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
43
44static cl::opt<std::string>
45OutputFilename("o", cl::desc("Override output filename"),
46               cl::value_desc("filename"));
47
48static cl::opt<bool>
49Force("f", cl::desc("Enable binary output on terminals"));
50
51static cl::opt<bool>
52DontPrint("disable-output", cl::desc("Don't output the .ll file"), cl::Hidden);
53
54static cl::opt<bool>
55ShowAnnotations("show-annotations",
56                cl::desc("Add informational comments to the .ll file"));
57
58static cl::opt<bool> PreserveAssemblyUseListOrder(
59    "preserve-ll-uselistorder",
60    cl::desc("Preserve use-list order when writing LLVM assembly."),
61    cl::init(false), cl::Hidden);
62
63static cl::opt<bool>
64    MaterializeMetadata("materialize-metadata",
65                        cl::desc("Load module without materializing metadata, "
66                                 "then materialize only the metadata"));
67
68namespace {
69
70static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {
71  OS << DL.getLine() << ":" << DL.getCol();
72  if (DILocation *IDL = DL.getInlinedAt()) {
73    OS << "@";
74    printDebugLoc(IDL, OS);
75  }
76}
77class CommentWriter : public AssemblyAnnotationWriter {
78public:
79  void emitFunctionAnnot(const Function *F,
80                         formatted_raw_ostream &OS) override {
81    OS << "; [#uses=" << F->getNumUses() << ']';  // Output # uses
82    OS << '\n';
83  }
84  void printInfoComment(const Value &V, formatted_raw_ostream &OS) override {
85    bool Padded = false;
86    if (!V.getType()->isVoidTy()) {
87      OS.PadToColumn(50);
88      Padded = true;
89      // Output # uses and type
90      OS << "; [#uses=" << V.getNumUses() << " type=" << *V.getType() << "]";
91    }
92    if (const Instruction *I = dyn_cast<Instruction>(&V)) {
93      if (const DebugLoc &DL = I->getDebugLoc()) {
94        if (!Padded) {
95          OS.PadToColumn(50);
96          Padded = true;
97          OS << ";";
98        }
99        OS << " [debug line = ";
100        printDebugLoc(DL,OS);
101        OS << "]";
102      }
103      if (const DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(I)) {
104        if (!Padded) {
105          OS.PadToColumn(50);
106          OS << ";";
107        }
108        OS << " [debug variable = " << DDI->getVariable()->getName() << "]";
109      }
110      else if (const DbgValueInst *DVI = dyn_cast<DbgValueInst>(I)) {
111        if (!Padded) {
112          OS.PadToColumn(50);
113          OS << ";";
114        }
115        OS << " [debug variable = " << DVI->getVariable()->getName() << "]";
116      }
117    }
118  }
119};
120
121} // end anon namespace
122
123static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) {
124  raw_ostream &OS = errs();
125  OS << (char *)Context << ": ";
126  switch (DI.getSeverity()) {
127  case DS_Error: OS << "error: "; break;
128  case DS_Warning: OS << "warning: "; break;
129  case DS_Remark: OS << "remark: "; break;
130  case DS_Note: OS << "note: "; break;
131  }
132
133  DiagnosticPrinterRawOStream DP(OS);
134  DI.print(DP);
135  OS << '\n';
136
137  if (DI.getSeverity() == DS_Error)
138    exit(1);
139}
140
141static Expected<std::unique_ptr<Module>> openInputFile(LLVMContext &Context) {
142  if (MaterializeMetadata) {
143    ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
144        MemoryBuffer::getFileOrSTDIN(InputFilename);
145    if (!MBOrErr)
146      return errorCodeToError(MBOrErr.getError());
147    ErrorOr<std::unique_ptr<Module>> MOrErr =
148        getLazyBitcodeModule(std::move(*MBOrErr), Context,
149                             /*ShouldLazyLoadMetadata=*/true);
150    if (!MOrErr)
151      return errorCodeToError(MOrErr.getError());
152    (*MOrErr)->materializeMetadata();
153    return std::move(*MOrErr);
154  } else {
155    std::string ErrorMessage;
156    std::unique_ptr<DataStreamer> Streamer =
157        getDataFileStreamer(InputFilename, &ErrorMessage);
158    if (!Streamer)
159      return make_error<StringError>(ErrorMessage, inconvertibleErrorCode());
160    std::string DisplayFilename;
161    if (InputFilename == "-")
162      DisplayFilename = "<stdin>";
163    else
164      DisplayFilename = InputFilename;
165    ErrorOr<std::unique_ptr<Module>> MOrErr =
166        getStreamedBitcodeModule(DisplayFilename, std::move(Streamer), Context);
167    (*MOrErr)->materializeAll();
168    return std::move(*MOrErr);
169  }
170}
171
172int main(int argc, char **argv) {
173  // Print a stack trace if we signal out.
174  sys::PrintStackTraceOnErrorSignal(argv[0]);
175  PrettyStackTraceProgram X(argc, argv);
176
177  LLVMContext Context;
178  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
179
180  Context.setDiagnosticHandler(diagnosticHandler, argv[0]);
181
182  cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n");
183
184  Expected<std::unique_ptr<Module>> MOrErr = openInputFile(Context);
185  if (!MOrErr) {
186    handleAllErrors(MOrErr.takeError(), [&](ErrorInfoBase &EIB) {
187      errs() << argv[0] << ": ";
188      EIB.log(errs());
189      errs() << '\n';
190    });
191    return 1;
192  }
193  std::unique_ptr<Module> M = std::move(*MOrErr);
194
195  // Just use stdout.  We won't actually print anything on it.
196  if (DontPrint)
197    OutputFilename = "-";
198
199  if (OutputFilename.empty()) { // Unspecified output, infer it.
200    if (InputFilename == "-") {
201      OutputFilename = "-";
202    } else {
203      StringRef IFN = InputFilename;
204      OutputFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str();
205      OutputFilename += ".ll";
206    }
207  }
208
209  std::error_code EC;
210  std::unique_ptr<tool_output_file> Out(
211      new tool_output_file(OutputFilename, EC, sys::fs::F_None));
212  if (EC) {
213    errs() << EC.message() << '\n';
214    return 1;
215  }
216
217  std::unique_ptr<AssemblyAnnotationWriter> Annotator;
218  if (ShowAnnotations)
219    Annotator.reset(new CommentWriter());
220
221  // All that llvm-dis does is write the assembly to a file.
222  if (!DontPrint)
223    M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder);
224
225  // Declare success.
226  Out->keep();
227
228  return 0;
229}
230