mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-26 14:15:53 +00:00
99e2e27b37
This change is motivated by an upcoming change to the metadata representation used for CFI. The indirect function call checker needs type information for external function declarations in order to correctly generate jump table entries for such declarations. We currently associate such type information with declarations using a global metadata node, but I plan [1] to move all such metadata to global object attachments. In bitcode, metadata attachments for function declarations appear in the global metadata block. This seems reasonable to me because I expect metadata attachments on declarations to be uncommon. In the long term I'd also expect this to be the case for CFI, because we'd want to use some specialized bitcode format for this metadata that could be read as part of the ThinLTO thin-link phase, which would mean that it would not appear in the global metadata block. To solve the lazy loaded metadata issue I was seeing with D20147, I use the same bitcode representation for metadata attachments for global variables as I do for function declarations. Since there's a use case for metadata attachments in the global metadata block, we might as well use that representation for global variables as well, at least until we have a mechanism for lazy loading global variables. In the assembly format, the metadata attachments appear after the "declare" keyword in order to avoid a parsing ambiguity. [1] http://lists.llvm.org/pipermail/llvm-dev/2016-June/100462.html Differential Revision: http://reviews.llvm.org/D21052 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273336 91177308-0d34-0410-b5e6-96231b3b80d8
230 lines
7.2 KiB
C++
230 lines
7.2 KiB
C++
//===-- llvm-dis.cpp - The low-level LLVM disassembler --------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This utility may be invoked in the following manner:
|
|
// llvm-dis [options] - Read LLVM bitcode from stdin, write asm to stdout
|
|
// llvm-dis [options] x.bc - Read LLVM bitcode from the x.bc file, write asm
|
|
// to the x.ll file.
|
|
// Options:
|
|
// --help - Output information about command line switches
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/Bitcode/ReaderWriter.h"
|
|
#include "llvm/IR/AssemblyAnnotationWriter.h"
|
|
#include "llvm/IR/DebugInfo.h"
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Type.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/DataStream.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/FormattedStream.h"
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
|
#include "llvm/Support/Signals.h"
|
|
#include "llvm/Support/ToolOutputFile.h"
|
|
#include <system_error>
|
|
using namespace llvm;
|
|
|
|
static cl::opt<std::string>
|
|
InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
|
|
|
|
static cl::opt<std::string>
|
|
OutputFilename("o", cl::desc("Override output filename"),
|
|
cl::value_desc("filename"));
|
|
|
|
static cl::opt<bool>
|
|
Force("f", cl::desc("Enable binary output on terminals"));
|
|
|
|
static cl::opt<bool>
|
|
DontPrint("disable-output", cl::desc("Don't output the .ll file"), cl::Hidden);
|
|
|
|
static cl::opt<bool>
|
|
ShowAnnotations("show-annotations",
|
|
cl::desc("Add informational comments to the .ll file"));
|
|
|
|
static cl::opt<bool> PreserveAssemblyUseListOrder(
|
|
"preserve-ll-uselistorder",
|
|
cl::desc("Preserve use-list order when writing LLVM assembly."),
|
|
cl::init(false), cl::Hidden);
|
|
|
|
static cl::opt<bool>
|
|
MaterializeMetadata("materialize-metadata",
|
|
cl::desc("Load module without materializing metadata, "
|
|
"then materialize only the metadata"));
|
|
|
|
namespace {
|
|
|
|
static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {
|
|
OS << DL.getLine() << ":" << DL.getCol();
|
|
if (DILocation *IDL = DL.getInlinedAt()) {
|
|
OS << "@";
|
|
printDebugLoc(IDL, OS);
|
|
}
|
|
}
|
|
class CommentWriter : public AssemblyAnnotationWriter {
|
|
public:
|
|
void emitFunctionAnnot(const Function *F,
|
|
formatted_raw_ostream &OS) override {
|
|
OS << "; [#uses=" << F->getNumUses() << ']'; // Output # uses
|
|
OS << '\n';
|
|
}
|
|
void printInfoComment(const Value &V, formatted_raw_ostream &OS) override {
|
|
bool Padded = false;
|
|
if (!V.getType()->isVoidTy()) {
|
|
OS.PadToColumn(50);
|
|
Padded = true;
|
|
// Output # uses and type
|
|
OS << "; [#uses=" << V.getNumUses() << " type=" << *V.getType() << "]";
|
|
}
|
|
if (const Instruction *I = dyn_cast<Instruction>(&V)) {
|
|
if (const DebugLoc &DL = I->getDebugLoc()) {
|
|
if (!Padded) {
|
|
OS.PadToColumn(50);
|
|
Padded = true;
|
|
OS << ";";
|
|
}
|
|
OS << " [debug line = ";
|
|
printDebugLoc(DL,OS);
|
|
OS << "]";
|
|
}
|
|
if (const DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(I)) {
|
|
if (!Padded) {
|
|
OS.PadToColumn(50);
|
|
OS << ";";
|
|
}
|
|
OS << " [debug variable = " << DDI->getVariable()->getName() << "]";
|
|
}
|
|
else if (const DbgValueInst *DVI = dyn_cast<DbgValueInst>(I)) {
|
|
if (!Padded) {
|
|
OS.PadToColumn(50);
|
|
OS << ";";
|
|
}
|
|
OS << " [debug variable = " << DVI->getVariable()->getName() << "]";
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
} // end anon namespace
|
|
|
|
static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) {
|
|
raw_ostream &OS = errs();
|
|
OS << (char *)Context << ": ";
|
|
switch (DI.getSeverity()) {
|
|
case DS_Error: OS << "error: "; break;
|
|
case DS_Warning: OS << "warning: "; break;
|
|
case DS_Remark: OS << "remark: "; break;
|
|
case DS_Note: OS << "note: "; break;
|
|
}
|
|
|
|
DiagnosticPrinterRawOStream DP(OS);
|
|
DI.print(DP);
|
|
OS << '\n';
|
|
|
|
if (DI.getSeverity() == DS_Error)
|
|
exit(1);
|
|
}
|
|
|
|
static Expected<std::unique_ptr<Module>> openInputFile(LLVMContext &Context) {
|
|
if (MaterializeMetadata) {
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
|
|
MemoryBuffer::getFileOrSTDIN(InputFilename);
|
|
if (!MBOrErr)
|
|
return errorCodeToError(MBOrErr.getError());
|
|
ErrorOr<std::unique_ptr<Module>> MOrErr =
|
|
getLazyBitcodeModule(std::move(*MBOrErr), Context,
|
|
/*ShouldLazyLoadMetadata=*/true);
|
|
if (!MOrErr)
|
|
return errorCodeToError(MOrErr.getError());
|
|
(*MOrErr)->materializeMetadata();
|
|
return std::move(*MOrErr);
|
|
} else {
|
|
std::string ErrorMessage;
|
|
std::unique_ptr<DataStreamer> Streamer =
|
|
getDataFileStreamer(InputFilename, &ErrorMessage);
|
|
if (!Streamer)
|
|
return make_error<StringError>(ErrorMessage, inconvertibleErrorCode());
|
|
std::string DisplayFilename;
|
|
if (InputFilename == "-")
|
|
DisplayFilename = "<stdin>";
|
|
else
|
|
DisplayFilename = InputFilename;
|
|
ErrorOr<std::unique_ptr<Module>> MOrErr =
|
|
getStreamedBitcodeModule(DisplayFilename, std::move(Streamer), Context);
|
|
(*MOrErr)->materializeAll();
|
|
return std::move(*MOrErr);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
// Print a stack trace if we signal out.
|
|
sys::PrintStackTraceOnErrorSignal(argv[0]);
|
|
PrettyStackTraceProgram X(argc, argv);
|
|
|
|
LLVMContext Context;
|
|
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
|
|
|
Context.setDiagnosticHandler(diagnosticHandler, argv[0]);
|
|
|
|
cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n");
|
|
|
|
Expected<std::unique_ptr<Module>> MOrErr = openInputFile(Context);
|
|
if (!MOrErr) {
|
|
handleAllErrors(MOrErr.takeError(), [&](ErrorInfoBase &EIB) {
|
|
errs() << argv[0] << ": ";
|
|
EIB.log(errs());
|
|
errs() << '\n';
|
|
});
|
|
return 1;
|
|
}
|
|
std::unique_ptr<Module> M = std::move(*MOrErr);
|
|
|
|
// Just use stdout. We won't actually print anything on it.
|
|
if (DontPrint)
|
|
OutputFilename = "-";
|
|
|
|
if (OutputFilename.empty()) { // Unspecified output, infer it.
|
|
if (InputFilename == "-") {
|
|
OutputFilename = "-";
|
|
} else {
|
|
StringRef IFN = InputFilename;
|
|
OutputFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str();
|
|
OutputFilename += ".ll";
|
|
}
|
|
}
|
|
|
|
std::error_code EC;
|
|
std::unique_ptr<tool_output_file> Out(
|
|
new tool_output_file(OutputFilename, EC, sys::fs::F_None));
|
|
if (EC) {
|
|
errs() << EC.message() << '\n';
|
|
return 1;
|
|
}
|
|
|
|
std::unique_ptr<AssemblyAnnotationWriter> Annotator;
|
|
if (ShowAnnotations)
|
|
Annotator.reset(new CommentWriter());
|
|
|
|
// All that llvm-dis does is write the assembly to a file.
|
|
if (!DontPrint)
|
|
M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder);
|
|
|
|
// Declare success.
|
|
Out->keep();
|
|
|
|
return 0;
|
|
}
|