280 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This utility may be invoked in the following manner:10// llvm-dis [options] - Read LLVM bitcode from stdin, write asm to stdout11// llvm-dis [options] x.bc - Read LLVM bitcode from the x.bc file, write asm12// 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 terminals20// --materialize-metadata - Load module without materializing metadata,21// then materialize only the metadata22// -o <filename> - Override output filename23// --show-annotations - Add informational comments to the .ll file24//25// Generic Options:26// --help - Display available options27// (--help-hidden for more)28// --help-list - Display list of available options29// (--help-list-hidden for more)30// --version - Display the version of this program31//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>84 MaterializeMetadata("materialize-metadata",85 cl::desc("Load module without materializing metadata, "86 "then materialize only the metadata"),87 cl::cat(DisCategory));88 89static cl::opt<bool> PrintThinLTOIndexOnly(90 "print-thinlto-index-only",91 cl::desc("Only read thinlto index and print the index as LLVM assembly."),92 cl::init(false), cl::Hidden, cl::cat(DisCategory));93 94namespace {95 96static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {97 OS << DL.getLine() << ":" << DL.getCol();98 if (DILocation *IDL = DL.getInlinedAt()) {99 OS << "@";100 printDebugLoc(IDL, OS);101 }102}103class CommentWriter : public AssemblyAnnotationWriter {104private:105 bool canSafelyAccessUses(const Value &V) {106 // Can't safely access uses, if module not materialized.107 const GlobalValue *GV = dyn_cast<GlobalValue>(&V);108 return !GV || (GV->getParent() && GV->getParent()->isMaterialized());109 }110 111public:112 void emitFunctionAnnot(const Function *F,113 formatted_raw_ostream &OS) override {114 if (!canSafelyAccessUses(*F))115 return;116 117 OS << "; [#uses=" << F->getNumUses() << ']'; // Output # uses118 OS << '\n';119 }120 void printInfoComment(const Value &V, formatted_raw_ostream &OS) override {121 if (!canSafelyAccessUses(V))122 return;123 124 bool Padded = false;125 if (!V.getType()->isVoidTy()) {126 OS.PadToColumn(50);127 Padded = true;128 // Output # uses and type129 OS << "; [#uses=" << V.getNumUses() << " type=" << *V.getType() << "]";130 }131 if (const Instruction *I = dyn_cast<Instruction>(&V)) {132 if (const DebugLoc &DL = I->getDebugLoc()) {133 if (!Padded) {134 OS.PadToColumn(50);135 Padded = true;136 OS << ";";137 }138 OS << " [debug line = ";139 printDebugLoc(DL,OS);140 OS << "]";141 }142 }143 }144};145 146struct LLVMDisDiagnosticHandler : public DiagnosticHandler {147 char *Prefix;148 LLVMDisDiagnosticHandler(char *PrefixPtr) : Prefix(PrefixPtr) {}149 bool handleDiagnostics(const DiagnosticInfo &DI) override {150 raw_ostream &OS = errs();151 OS << Prefix << ": ";152 switch (DI.getSeverity()) {153 case DS_Error: WithColor::error(OS); break;154 case DS_Warning: WithColor::warning(OS); break;155 case DS_Remark: OS << "remark: "; break;156 case DS_Note: WithColor::note(OS); break;157 }158 159 DiagnosticPrinterRawOStream DP(OS);160 DI.print(DP);161 OS << '\n';162 163 if (DI.getSeverity() == DS_Error)164 exit(1);165 return true;166 }167};168} // end anon namespace169 170static ExitOnError ExitOnErr;171 172int main(int argc, char **argv) {173 InitLLVM X(argc, argv);174 175 ExitOnErr.setBanner(std::string(argv[0]) + ": error: ");176 177 cl::HideUnrelatedOptions({&DisCategory, &getColorCategory()});178 cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n");179 180 if (InputFilenames.size() < 1) {181 InputFilenames.push_back("-");182 } else if (InputFilenames.size() > 1 && !OutputFilename.empty()) {183 errs()184 << "error: output file name cannot be set for multiple input files\n";185 return 1;186 }187 188 for (const auto &InputFilename : InputFilenames) {189 // Use a fresh context for each input to avoid state190 // cross-contamination across inputs (e.g. type name collisions).191 LLVMContext Context;192 Context.setDiagnosticHandler(193 std::make_unique<LLVMDisDiagnosticHandler>(argv[0]));194 195 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =196 MemoryBuffer::getFileOrSTDIN(InputFilename);197 if (std::error_code EC = BufferOrErr.getError()) {198 WithColor::error() << InputFilename << ": " << EC.message() << '\n';199 return 1;200 }201 std::unique_ptr<MemoryBuffer> MB = std::move(BufferOrErr.get());202 203 BitcodeFileContents IF = ExitOnErr(llvm::getBitcodeFileContents(*MB));204 205 const size_t N = IF.Mods.size();206 207 if (OutputFilename == "-" && N > 1)208 errs() << "only single module bitcode files can be written to stdout\n";209 210 for (size_t I = 0; I < N; ++I) {211 BitcodeModule MB = IF.Mods[I];212 213 std::unique_ptr<Module> M;214 215 if (!PrintThinLTOIndexOnly) {216 M = ExitOnErr(217 MB.getLazyModule(Context, MaterializeMetadata, SetImporting));218 if (MaterializeMetadata)219 ExitOnErr(M->materializeMetadata());220 else221 ExitOnErr(M->materializeAll());222 }223 224 BitcodeLTOInfo LTOInfo = ExitOnErr(MB.getLTOInfo());225 std::unique_ptr<ModuleSummaryIndex> Index;226 if (LTOInfo.HasSummary)227 Index = ExitOnErr(MB.getSummary());228 229 std::string FinalFilename(OutputFilename);230 231 // Just use stdout. We won't actually print anything on it.232 if (DontPrint)233 FinalFilename = "-";234 235 if (FinalFilename.empty()) { // Unspecified output, infer it.236 if (InputFilename == "-") {237 FinalFilename = "-";238 } else {239 StringRef IFN = InputFilename;240 FinalFilename = (IFN.ends_with(".bc") ? IFN.drop_back(3) : IFN).str();241 if (N > 1)242 FinalFilename += std::string(".") + std::to_string(I);243 FinalFilename += ".ll";244 }245 } else {246 if (N > 1)247 FinalFilename += std::string(".") + std::to_string(I);248 }249 250 std::error_code EC;251 std::unique_ptr<ToolOutputFile> Out(252 new ToolOutputFile(FinalFilename, EC, sys::fs::OF_TextWithCRLF));253 if (EC) {254 errs() << EC.message() << '\n';255 return 1;256 }257 258 std::unique_ptr<AssemblyAnnotationWriter> Annotator;259 if (ShowAnnotations)260 Annotator.reset(new CommentWriter());261 262 // All that llvm-dis does is write the assembly to a file.263 if (!DontPrint) {264 if (M) {265 M->removeDebugIntrinsicDeclarations();266 M->print(Out->os(), Annotator.get(),267 /* ShouldPreserveUseListOrder */ false);268 }269 if (Index)270 Index->print(Out->os());271 }272 273 // Declare success.274 Out->keep();275 }276 }277 278 return 0;279}280