diff options
Diffstat (limited to 'contrib/llvm/tools')
63 files changed, 4581 insertions, 3197 deletions
diff --git a/contrib/llvm/tools/bugpoint/BugDriver.cpp b/contrib/llvm/tools/bugpoint/BugDriver.cpp index 43f4c29..030749f 100644 --- a/contrib/llvm/tools/bugpoint/BugDriver.cpp +++ b/contrib/llvm/tools/bugpoint/BugDriver.cpp @@ -72,7 +72,7 @@ BugDriver::BugDriver(const char *toolname, bool find_bugs, LLVMContext& ctxt) : Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile), Program(nullptr), Interpreter(nullptr), SafeInterpreter(nullptr), - gcc(nullptr), run_find_bugs(find_bugs), Timeout(timeout), + cc(nullptr), run_find_bugs(find_bugs), Timeout(timeout), MemoryLimit(memlimit), UseValgrind(use_valgrind) {} BugDriver::~BugDriver() { @@ -80,7 +80,7 @@ BugDriver::~BugDriver() { if (Interpreter != SafeInterpreter) delete Interpreter; delete SafeInterpreter; - delete gcc; + delete cc; } std::unique_ptr<Module> llvm::parseInputFile(StringRef Filename, @@ -132,7 +132,7 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { if (!M.get()) return true; outs() << "Linking in input file: '" << Filenames[i] << "'\n"; - if (Linker::LinkModules(Program, M.get())) + if (Linker::linkModules(*Program, std::move(M))) return true; } diff --git a/contrib/llvm/tools/bugpoint/BugDriver.h b/contrib/llvm/tools/bugpoint/BugDriver.h index 5797812..20efff3 100644 --- a/contrib/llvm/tools/bugpoint/BugDriver.h +++ b/contrib/llvm/tools/bugpoint/BugDriver.h @@ -36,7 +36,7 @@ class LLVMContext; class DebugCrashes; -class GCC; +class CC; extern bool DisableSimplifyCFG; @@ -52,7 +52,7 @@ class BugDriver { std::vector<std::string> PassesToRun; AbstractInterpreter *Interpreter; // How to run the program AbstractInterpreter *SafeInterpreter; // To generate reference output, etc. - GCC *gcc; + CC *cc; bool run_find_bugs; unsigned Timeout; unsigned MemoryLimit; @@ -321,16 +321,21 @@ void PrintFunctionList(const std::vector<Function*> &Funcs); /// void PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs); +// DeleteGlobalInitializer - "Remove" the global variable by deleting its +// initializer, making it external. +// +void DeleteGlobalInitializer(GlobalVariable *GV); + // DeleteFunctionBody - "Remove" the function by deleting all of it's basic // blocks, making it external. // void DeleteFunctionBody(Function *F); -/// SplitFunctionsOutOfModule - Given a module and a list of functions in the -/// module, split the functions OUT of the specified module, and place them in -/// the new module. -Module *SplitFunctionsOutOfModule(Module *M, const std::vector<Function*> &F, - ValueToValueMapTy &VMap); +/// Given a module and a list of functions in the module, split the functions +/// OUT of the specified module, and place them in the new module. +std::unique_ptr<Module> +SplitFunctionsOutOfModule(Module *M, const std::vector<Function *> &F, + ValueToValueMapTy &VMap); } // End llvm namespace diff --git a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp index e2aaf6b..6cdc43ab 100644 --- a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp +++ b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp @@ -15,6 +15,7 @@ #include "ListReducer.h" #include "ToolRunner.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringSet.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" @@ -49,6 +50,10 @@ namespace { DontReducePassList("disable-pass-list-reduction", cl::desc("Skip pass list reduction steps"), cl::init(false)); + + cl::opt<bool> NoNamedMDRM("disable-namedmd-remove", + cl::desc("Do not remove global named metadata"), + cl::init(false)); } namespace llvm { @@ -138,7 +143,7 @@ ReduceCrashingGlobalVariables::TestGlobalVariables( std::vector<GlobalVariable*> &GVs) { // Clone the program to try hacking it apart... ValueToValueMapTy VMap; - Module *M = CloneModule(BD.getProgram(), VMap); + Module *M = CloneModule(BD.getProgram(), VMap).release(); // Convert list to set for fast lookup... std::set<GlobalVariable*> GVSet; @@ -155,11 +160,10 @@ ReduceCrashingGlobalVariables::TestGlobalVariables( // Loop over and delete any global variables which we aren't supposed to be // playing with... - for (Module::global_iterator I = M->global_begin(), E = M->global_end(); - I != E; ++I) - if (I->hasInitializer() && !GVSet.count(I)) { - I->setInitializer(nullptr); - I->setLinkage(GlobalValue::ExternalLinkage); + for (GlobalVariable &I : M->globals()) + if (I.hasInitializer() && !GVSet.count(&I)) { + DeleteGlobalInitializer(&I); + I.setLinkage(GlobalValue::ExternalLinkage); } // Try running the hacked up program... @@ -235,7 +239,7 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { // Clone the program to try hacking it apart... ValueToValueMapTy VMap; - Module *M = CloneModule(BD.getProgram(), VMap); + Module *M = CloneModule(BD.getProgram(), VMap).release(); // Convert list to set for fast lookup... std::set<Function*> Functions; @@ -253,9 +257,9 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { if (!ReplaceFuncsWithNull) { // Loop over and delete any functions which we aren't supposed to be playing // with... - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) - if (!I->isDeclaration() && !Functions.count(I)) - DeleteFunctionBody(I); + for (Function &I : *M) + if (!I.isDeclaration() && !Functions.count(&I)) + DeleteFunctionBody(&I); } else { std::vector<GlobalValue*> ToRemove; // First, remove aliases to functions we're about to purge. @@ -280,12 +284,12 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { ToRemove.push_back(&Alias); } - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { - if (!I->isDeclaration() && !Functions.count(I)) { - PointerType *Ty = cast<PointerType>(I->getType()); + for (Function &I : *M) { + if (!I.isDeclaration() && !Functions.count(&I)) { + PointerType *Ty = cast<PointerType>(I.getType()); Constant *Replacement = ConstantPointerNull::get(Ty); - I->replaceAllUsesWith(Replacement); - ToRemove.push_back(I); + I.replaceAllUsesWith(Replacement); + ToRemove.push_back(&I); } } @@ -342,7 +346,7 @@ namespace { bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { // Clone the program to try hacking it apart... ValueToValueMapTy VMap; - Module *M = CloneModule(BD.getProgram(), VMap); + Module *M = CloneModule(BD.getProgram(), VMap).release(); // Convert list to set for fast lookup... SmallPtrSet<BasicBlock*, 8> Blocks; @@ -361,20 +365,22 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { // Loop over and delete any hack up any blocks that are not listed... for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) for (Function::iterator BB = I->begin(), E = I->end(); BB != E; ++BB) - if (!Blocks.count(BB) && BB->getTerminator()->getNumSuccessors()) { + if (!Blocks.count(&*BB) && BB->getTerminator()->getNumSuccessors()) { // Loop over all of the successors of this block, deleting any PHI nodes // that might include it. - for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI) - (*SI)->removePredecessor(BB); + for (succ_iterator SI = succ_begin(&*BB), E = succ_end(&*BB); SI != E; + ++SI) + (*SI)->removePredecessor(&*BB); TerminatorInst *BBTerm = BB->getTerminator(); - - if (!BB->getTerminator()->getType()->isVoidTy()) + if (BBTerm->isEHPad()) + continue; + if (!BBTerm->getType()->isVoidTy() && !BBTerm->getType()->isTokenTy()) BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType())); // Replace the old terminator instruction. BB->getInstList().pop_back(); - new UnreachableInst(BB->getContext(), BB); + new UnreachableInst(BB->getContext(), &*BB); } // The CFG Simplifier pass may delete one of the basic blocks we are @@ -450,7 +456,7 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> &Insts) { // Clone the program to try hacking it apart... ValueToValueMapTy VMap; - Module *M = CloneModule(BD.getProgram(), VMap); + Module *M = CloneModule(BD.getProgram(), VMap).release(); // Convert list to set for fast lookup... SmallPtrSet<Instruction*, 64> Instructions; @@ -468,10 +474,10 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> for (Module::iterator MI = M->begin(), ME = M->end(); MI != ME; ++MI) for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI) for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) { - Instruction *Inst = I++; + Instruction *Inst = &*I++; if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst) && - !isa<LandingPadInst>(Inst)) { - if (!Inst->getType()->isVoidTy()) + !Inst->isEHPad()) { + if (!Inst->getType()->isVoidTy() && !Inst->getType()->isTokenTy()) Inst->replaceAllUsesWith(UndefValue::get(Inst->getType())); Inst->eraseFromParent(); } @@ -497,6 +503,149 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> return false; } +namespace { +// Reduce the list of Named Metadata nodes. We keep this as a list of +// names to avoid having to convert back and forth every time. +class ReduceCrashingNamedMD : public ListReducer<std::string> { + BugDriver &BD; + bool (*TestFn)(const BugDriver &, Module *); + +public: + ReduceCrashingNamedMD(BugDriver &bd, + bool (*testFn)(const BugDriver &, Module *)) + : BD(bd), TestFn(testFn) {} + + TestResult doTest(std::vector<std::string> &Prefix, + std::vector<std::string> &Kept, + std::string &Error) override { + if (!Kept.empty() && TestNamedMDs(Kept)) + return KeepSuffix; + if (!Prefix.empty() && TestNamedMDs(Prefix)) + return KeepPrefix; + return NoFailure; + } + + bool TestNamedMDs(std::vector<std::string> &NamedMDs); +}; +} + +bool ReduceCrashingNamedMD::TestNamedMDs(std::vector<std::string> &NamedMDs) { + + ValueToValueMapTy VMap; + Module *M = CloneModule(BD.getProgram(), VMap).release(); + + outs() << "Checking for crash with only these named metadata nodes:"; + unsigned NumPrint = std::min<size_t>(NamedMDs.size(), 10); + for (unsigned i = 0, e = NumPrint; i != e; ++i) + outs() << " " << NamedMDs[i]; + if (NumPrint < NamedMDs.size()) + outs() << "... <" << NamedMDs.size() << " total>"; + outs() << ": "; + + // Make a StringMap for faster lookup + StringSet<> Names; + for (const std::string &Name : NamedMDs) + Names.insert(Name); + + // First collect all the metadata to delete in a vector, then + // delete them all at once to avoid invalidating the iterator + std::vector<NamedMDNode *> ToDelete; + ToDelete.reserve(M->named_metadata_size() - Names.size()); + for (auto &NamedMD : M->named_metadata()) + if (!Names.count(NamedMD.getName())) + ToDelete.push_back(&NamedMD); + + for (auto *NamedMD : ToDelete) + NamedMD->eraseFromParent(); + + // Verify that this is still valid. + legacy::PassManager Passes; + Passes.add(createVerifierPass()); + Passes.run(*M); + + // Try running on the hacked up program... + if (TestFn(BD, M)) { + BD.setNewProgram(M); // It crashed, keep the trimmed version... + return true; + } + delete M; // It didn't crash, try something else. + return false; +} + +namespace { +// Reduce the list of operands to named metadata nodes +class ReduceCrashingNamedMDOps : public ListReducer<const MDNode *> { + BugDriver &BD; + bool (*TestFn)(const BugDriver &, Module *); + +public: + ReduceCrashingNamedMDOps(BugDriver &bd, + bool (*testFn)(const BugDriver &, Module *)) + : BD(bd), TestFn(testFn) {} + + TestResult doTest(std::vector<const MDNode *> &Prefix, + std::vector<const MDNode *> &Kept, + std::string &Error) override { + if (!Kept.empty() && TestNamedMDOps(Kept)) + return KeepSuffix; + if (!Prefix.empty() && TestNamedMDOps(Prefix)) + return KeepPrefix; + return NoFailure; + } + + bool TestNamedMDOps(std::vector<const MDNode *> &NamedMDOps); +}; +} + +bool ReduceCrashingNamedMDOps::TestNamedMDOps( + std::vector<const MDNode *> &NamedMDOps) { + // Convert list to set for fast lookup... + SmallPtrSet<const MDNode *, 64> OldMDNodeOps; + for (unsigned i = 0, e = NamedMDOps.size(); i != e; ++i) { + OldMDNodeOps.insert(NamedMDOps[i]); + } + + outs() << "Checking for crash with only " << OldMDNodeOps.size(); + if (OldMDNodeOps.size() == 1) + outs() << " named metadata operand: "; + else + outs() << " named metadata operands: "; + + ValueToValueMapTy VMap; + Module *M = CloneModule(BD.getProgram(), VMap).release(); + + // This is a little wasteful. In the future it might be good if we could have + // these dropped during cloning. + for (auto &NamedMD : BD.getProgram()->named_metadata()) { + // Drop the old one and create a new one + M->eraseNamedMetadata(M->getNamedMetadata(NamedMD.getName())); + NamedMDNode *NewNamedMDNode = + M->getOrInsertNamedMetadata(NamedMD.getName()); + for (MDNode *op : NamedMD.operands()) + if (OldMDNodeOps.count(op)) + NewNamedMDNode->addOperand(cast<MDNode>(MapMetadata(op, VMap))); + } + + // Verify that this is still valid. + legacy::PassManager Passes; + Passes.add(createVerifierPass()); + Passes.run(*M); + + // Try running on the hacked up program... + if (TestFn(BD, M)) { + // Make sure to use instruction pointers that point into the now-current + // module, and that they don't include any deleted blocks. + NamedMDOps.clear(); + for (const MDNode *Node : OldMDNodeOps) + NamedMDOps.push_back(cast<MDNode>(VMap.MD()[Node].get())); + + BD.setNewProgram(M); // It crashed, keep the trimmed version... + return true; + } + delete M; // It didn't crash, try something else. + return false; +} + /// DebugACrash - Given a predicate that determines whether a component crashes /// on a program, try to destructively reduce the program while still keeping /// the predicate true. @@ -509,13 +658,13 @@ static bool DebugACrash(BugDriver &BD, BD.getProgram()->global_begin() != BD.getProgram()->global_end()) { // Now try to reduce the number of global variable initializers in the // module to something small. - Module *M = CloneModule(BD.getProgram()); + Module *M = CloneModule(BD.getProgram()).release(); bool DeletedInit = false; for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) if (I->hasInitializer()) { - I->setInitializer(nullptr); + DeleteGlobalInitializer(&*I); I->setLinkage(GlobalValue::ExternalLinkage); DeletedInit = true; } @@ -538,7 +687,7 @@ static bool DebugACrash(BugDriver &BD, for (Module::global_iterator I = BD.getProgram()->global_begin(), E = BD.getProgram()->global_end(); I != E; ++I) if (I->hasInitializer()) - GVs.push_back(I); + GVs.push_back(&*I); if (GVs.size() > 1 && !BugpointIsInterrupted) { outs() << "\n*** Attempting to reduce the number of global " @@ -558,10 +707,9 @@ static bool DebugACrash(BugDriver &BD, // Now try to reduce the number of functions in the module to something small. std::vector<Function*> Functions; - for (Module::iterator I = BD.getProgram()->begin(), - E = BD.getProgram()->end(); I != E; ++I) - if (!I->isDeclaration()) - Functions.push_back(I); + for (Function &F : *BD.getProgram()) + if (!F.isDeclaration()) + Functions.push_back(&F); if (Functions.size() > 1 && !BugpointIsInterrupted) { outs() << "\n*** Attempting to reduce the number of functions " @@ -581,10 +729,9 @@ static bool DebugACrash(BugDriver &BD, // if (!DisableSimplifyCFG && !BugpointIsInterrupted) { std::vector<const BasicBlock*> Blocks; - for (Module::const_iterator I = BD.getProgram()->begin(), - E = BD.getProgram()->end(); I != E; ++I) - for (Function::const_iterator FI = I->begin(), E = I->end(); FI !=E; ++FI) - Blocks.push_back(FI); + for (Function &F : *BD.getProgram()) + for (BasicBlock &BB : F) + Blocks.push_back(&BB); unsigned OldSize = Blocks.size(); ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error); if (Blocks.size() < OldSize) @@ -595,14 +742,11 @@ static bool DebugACrash(BugDriver &BD, // cases with large basic blocks where the problem is at one end. if (!BugpointIsInterrupted) { std::vector<const Instruction*> Insts; - for (Module::const_iterator MI = BD.getProgram()->begin(), - ME = BD.getProgram()->end(); MI != ME; ++MI) - for (Function::const_iterator FI = MI->begin(), FE = MI->end(); FI != FE; - ++FI) - for (BasicBlock::const_iterator I = FI->begin(), E = FI->end(); - I != E; ++I) - if (!isa<TerminatorInst>(I)) - Insts.push_back(I); + for (const Function &F : *BD.getProgram()) + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) + if (!isa<TerminatorInst>(&I)) + Insts.push_back(&I); ReduceCrashingInstructions(BD, TestFn).reduceList(Insts, Error); } @@ -642,12 +786,12 @@ static bool DebugACrash(BugDriver &BD, } else { if (BugpointIsInterrupted) goto ExitLoops; - if (isa<LandingPadInst>(I)) + if (I->isEHPad() || I->getType()->isTokenTy()) continue; outs() << "Checking instruction: " << *I; std::unique_ptr<Module> M = - BD.deleteInstructionFromProgram(I, Simplification); + BD.deleteInstructionFromProgram(&*I, Simplification); // Find out if the pass still crashes on this pass... if (TestFn(BD, M.get())) { @@ -666,12 +810,37 @@ static bool DebugACrash(BugDriver &BD, } } while (Simplification); + + if (!NoNamedMDRM) { + BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions"); + + if (!BugpointIsInterrupted) { + // Try to reduce the amount of global metadata (particularly debug info), + // by dropping global named metadata that anchors them + outs() << "\n*** Attempting to remove named metadata: "; + std::vector<std::string> NamedMDNames; + for (auto &NamedMD : BD.getProgram()->named_metadata()) + NamedMDNames.push_back(NamedMD.getName().str()); + ReduceCrashingNamedMD(BD, TestFn).reduceList(NamedMDNames, Error); + } + + if (!BugpointIsInterrupted) { + // Now that we quickly dropped all the named metadata that doesn't + // contribute to the crash, bisect the operands of the remaining ones + std::vector<const MDNode *> NamedMDOps; + for (auto &NamedMD : BD.getProgram()->named_metadata()) + for (auto op : NamedMD.operands()) + NamedMDOps.push_back(op); + ReduceCrashingNamedMDOps(BD, TestFn).reduceList(NamedMDOps, Error); + } + } + ExitLoops: // Try to clean up the testcase by running funcresolve and globaldce... if (!BugpointIsInterrupted) { outs() << "\n*** Attempting to perform final cleanups: "; - Module *M = CloneModule(BD.getProgram()); + Module *M = CloneModule(BD.getProgram()).release(); M = BD.performFinalCleanups(M, true).release(); // Find out if the pass still crashes on the cleaned up program... diff --git a/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp index 25813b3..41b8ccc 100644 --- a/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp +++ b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp @@ -17,6 +17,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Program.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/raw_ostream.h" #include <fstream> @@ -124,11 +125,10 @@ namespace { cl::ZeroOrMore, cl::PositionalEatsArgs); cl::opt<std::string> - GCCBinary("gcc", cl::init("gcc"), - cl::desc("The gcc binary to use. (default 'gcc')")); + CCBinary("gcc", cl::init(""), cl::desc("The gcc binary to use.")); cl::list<std::string> - GCCToolArgv("gcc-tool-args", cl::Positional, + CCToolArgv("gcc-tool-args", cl::Positional, cl::desc("<gcc-tool arguments>..."), cl::ZeroOrMore, cl::PositionalEatsArgs); } @@ -148,6 +148,13 @@ bool BugDriver::initializeExecutionEnvironment() { SafeInterpreter = nullptr; std::string Message; + if (CCBinary.empty()) { + if (sys::findProgramByName("clang")) + CCBinary = "clang"; + else + CCBinary = "gcc"; + } + switch (InterpreterSel) { case AutoPick: if (!Interpreter) { @@ -158,8 +165,8 @@ bool BugDriver::initializeExecutionEnvironment() { if (!Interpreter) { InterpreterSel = RunLLC; Interpreter = AbstractInterpreter::createLLC(getToolName(), Message, - GCCBinary, &ToolArgv, - &GCCToolArgv); + CCBinary, &ToolArgv, + &CCToolArgv); } if (!Interpreter) { InterpreterSel = RunLLI; @@ -179,8 +186,8 @@ bool BugDriver::initializeExecutionEnvironment() { case RunLLCIA: case LLC_Safe: Interpreter = AbstractInterpreter::createLLC(getToolName(), Message, - GCCBinary, &ToolArgv, - &GCCToolArgv, + CCBinary, &ToolArgv, + &CCToolArgv, InterpreterSel == RunLLCIA); break; case RunJIT: @@ -213,9 +220,9 @@ bool BugDriver::initializeExecutionEnvironment() { SafeInterpreterSel = RunLLC; SafeToolArgs.push_back("--relocation-model=pic"); SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, - GCCBinary, + CCBinary, &SafeToolArgs, - &GCCToolArgv); + &CCToolArgv); } if (!SafeInterpreter && @@ -224,9 +231,9 @@ bool BugDriver::initializeExecutionEnvironment() { SafeInterpreterSel = RunLLC; SafeToolArgs.push_back("--relocation-model=pic"); SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, - GCCBinary, + CCBinary, &SafeToolArgs, - &GCCToolArgv); + &CCToolArgv); } if (!SafeInterpreter) { SafeInterpreterSel = AutoPick; @@ -237,8 +244,8 @@ bool BugDriver::initializeExecutionEnvironment() { case RunLLCIA: SafeToolArgs.push_back("--relocation-model=pic"); SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, - GCCBinary, &SafeToolArgs, - &GCCToolArgv, + CCBinary, &SafeToolArgs, + &CCToolArgv, SafeInterpreterSel == RunLLCIA); break; case Custom: @@ -252,8 +259,8 @@ bool BugDriver::initializeExecutionEnvironment() { } if (!SafeInterpreter) { outs() << Message << "\nExiting.\n"; exit(1); } - gcc = GCC::create(Message, GCCBinary, &GCCToolArgv); - if (!gcc) { outs() << Message << "\nExiting.\n"; exit(1); } + cc = CC::create(Message, CCBinary, &CCToolArgv); + if (!cc) { outs() << Message << "\nExiting.\n"; exit(1); } // If there was an error creating the selected interpreter, quit with error. return Interpreter == nullptr; @@ -388,13 +395,13 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, std::string OutputFile; // Using the known-good backend. - GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile, + CC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile, Error); if (!Error.empty()) return ""; std::string SharedObjectFile; - bool Failure = gcc->MakeSharedObject(OutputFile, FT, SharedObjectFile, + bool Failure = cc->MakeSharedObject(OutputFile, FT, SharedObjectFile, AdditionalLinkerArgs, Error); if (!Error.empty()) return ""; diff --git a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp index 238cbbc..fe0ab69 100644 --- a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp +++ b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp @@ -86,7 +86,7 @@ std::unique_ptr<Module> BugDriver::deleteInstructionFromProgram(const Instruction *I, unsigned Simplification) { // FIXME, use vmap? - Module *Clone = CloneModule(Program); + Module *Clone = CloneModule(Program).release(); const BasicBlock *PBB = I->getParent(); const Function *PF = PBB->getParent(); @@ -100,7 +100,7 @@ BugDriver::deleteInstructionFromProgram(const Instruction *I, BasicBlock::iterator RI = RBI->begin(); // Get iterator to corresponding inst std::advance(RI, std::distance(PBB->begin(), BasicBlock::const_iterator(I))); - Instruction *TheInst = RI; // Got the corresponding instruction! + Instruction *TheInst = &*RI; // Got the corresponding instruction! // If this instruction produces a value, replace any users with null values if (!TheInst->getType()->isVoidTy()) @@ -179,11 +179,43 @@ std::unique_ptr<Module> BugDriver::extractLoop(Module *M) { return NewM; } +static void eliminateAliases(GlobalValue *GV) { + // First, check whether a GlobalAlias references this definition. + // GlobalAlias MAY NOT reference declarations. + for (;;) { + // 1. Find aliases + SmallVector<GlobalAlias*,1> aliases; + Module *M = GV->getParent(); + for (Module::alias_iterator I=M->alias_begin(), E=M->alias_end(); I!=E; ++I) + if (I->getAliasee()->stripPointerCasts() == GV) + aliases.push_back(&*I); + if (aliases.empty()) + break; + // 2. Resolve aliases + for (unsigned i=0, e=aliases.size(); i<e; ++i) { + aliases[i]->replaceAllUsesWith(aliases[i]->getAliasee()); + aliases[i]->eraseFromParent(); + } + // 3. Repeat until no more aliases found; there might + // be an alias to an alias... + } +} + +// +// DeleteGlobalInitializer - "Remove" the global variable by deleting its initializer, +// making it external. +// +void llvm::DeleteGlobalInitializer(GlobalVariable *GV) { + eliminateAliases(GV); + GV->setInitializer(nullptr); +} // DeleteFunctionBody - "Remove" the function by deleting all of its basic // blocks, making it external. // void llvm::DeleteFunctionBody(Function *F) { + eliminateAliases(F); + // delete the body of the function... F->deleteBody(); assert(F->isDeclaration() && "This didn't make the function external!"); @@ -271,13 +303,8 @@ static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2, } } - -/// SplitFunctionsOutOfModule - Given a module and a list of functions in the -/// module, split the functions OUT of the specified module, and place them in -/// the new module. -Module * -llvm::SplitFunctionsOutOfModule(Module *M, - const std::vector<Function*> &F, +std::unique_ptr<Module> +llvm::SplitFunctionsOutOfModule(Module *M, const std::vector<Function *> &F, ValueToValueMapTy &VMap) { // Make sure functions & globals are all external so that linkage // between the two modules will work. @@ -291,7 +318,7 @@ llvm::SplitFunctionsOutOfModule(Module *M, } ValueToValueMapTy NewVMap; - Module *New = CloneModule(M, NewVMap); + std::unique_ptr<Module> New = CloneModule(M, NewVMap); // Remove the Test functions from the Safe module std::set<Function *> TestFunctions; @@ -306,16 +333,14 @@ llvm::SplitFunctionsOutOfModule(Module *M, // Remove the Safe functions from the Test module - for (Module::iterator I = New->begin(), E = New->end(); I != E; ++I) - if (!TestFunctions.count(I)) - DeleteFunctionBody(I); - + for (Function &I : *New) + if (!TestFunctions.count(&I)) + DeleteFunctionBody(&I); // Try to split the global initializers evenly - for (Module::global_iterator I = M->global_begin(), E = M->global_end(); - I != E; ++I) { - GlobalVariable *GV = cast<GlobalVariable>(NewVMap[I]); - if (Function *TestFn = globalInitUsesExternalBA(I)) { + for (GlobalVariable &I : M->globals()) { + GlobalVariable *GV = cast<GlobalVariable>(NewVMap[&I]); + if (Function *TestFn = globalInitUsesExternalBA(&I)) { if (Function *SafeFn = globalInitUsesExternalBA(GV)) { errs() << "*** Error: when reducing functions, encountered " "the global '"; @@ -325,18 +350,18 @@ llvm::SplitFunctionsOutOfModule(Module *M, << "' and from test function '" << TestFn->getName() << "'.\n"; exit(1); } - I->setInitializer(nullptr); // Delete the initializer to make it external + DeleteGlobalInitializer(&I); // Delete the initializer to make it external } else { // If we keep it in the safe module, then delete it in the test module - GV->setInitializer(nullptr); + DeleteGlobalInitializer(GV); } } // Make sure that there is a global ctor/dtor array in both halves of the // module if they both have static ctor/dtor functions. - SplitStaticCtorDtor("llvm.global_ctors", M, New, NewVMap); - SplitStaticCtorDtor("llvm.global_dtors", M, New, NewVMap); - + SplitStaticCtorDtor("llvm.global_ctors", M, New.get(), NewVMap); + SplitStaticCtorDtor("llvm.global_dtors", M, New.get(), NewVMap); + return New; } diff --git a/contrib/llvm/tools/bugpoint/ListReducer.h b/contrib/llvm/tools/bugpoint/ListReducer.h index a0bb570..f08bc97 100644 --- a/contrib/llvm/tools/bugpoint/ListReducer.h +++ b/contrib/llvm/tools/bugpoint/ListReducer.h @@ -75,6 +75,11 @@ struct ListReducer { // Maximal number of allowed splitting iterations, // before the elements are randomly shuffled. const unsigned MaxIterationsWithoutProgress = 3; + + // Maximal number of allowed single-element trim iterations. We add a + // threshhold here as single-element reductions may otherwise take a + // very long time to complete. + const unsigned MaxTrimIterationsWithoutBackJump = 3; bool ShufflingEnabled = true; Backjump: @@ -157,6 +162,7 @@ Backjump: if (TheList.size() > 2) { bool Changed = true; std::vector<ElTy> EmptyList; + unsigned TrimIterations = 0; while (Changed) { // Trimming loop. Changed = false; @@ -186,9 +192,9 @@ Backjump: if (!Error.empty()) return true; } - // This can take a long time if left uncontrolled. For now, don't - // iterate. - break; + if (TrimIterations >= MaxTrimIterationsWithoutBackJump) + break; + TrimIterations++; } } diff --git a/contrib/llvm/tools/bugpoint/Miscompilation.cpp b/contrib/llvm/tools/bugpoint/Miscompilation.cpp index fad1636..16919f5 100644 --- a/contrib/llvm/tools/bugpoint/Miscompilation.cpp +++ b/contrib/llvm/tools/bugpoint/Miscompilation.cpp @@ -176,12 +176,15 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, namespace { class ReduceMiscompilingFunctions : public ListReducer<Function*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *, Module *, std::string &); + bool (*TestFn)(BugDriver &, std::unique_ptr<Module>, + std::unique_ptr<Module>, std::string &); + public: ReduceMiscompilingFunctions(BugDriver &bd, - bool (*F)(BugDriver &, Module *, Module *, + bool (*F)(BugDriver &, std::unique_ptr<Module>, + std::unique_ptr<Module>, std::string &)) - : BD(bd), TestFn(F) {} + : BD(bd), TestFn(F) {} TestResult doTest(std::vector<Function*> &Prefix, std::vector<Function*> &Suffix, @@ -207,32 +210,24 @@ namespace { }; } -/// TestMergedProgram - Given two modules, link them together and run the -/// program, checking to see if the program matches the diff. If there is -/// an error, return NULL. If not, return the merged module. The Broken argument -/// will be set to true if the output is different. If the DeleteInputs -/// argument is set to true then this function deletes both input -/// modules before it returns. +/// Given two modules, link them together and run the program, checking to see +/// if the program matches the diff. If there is an error, return NULL. If not, +/// return the merged module. The Broken argument will be set to true if the +/// output is different. If the DeleteInputs argument is set to true then this +/// function deletes both input modules before it returns. /// -static Module *TestMergedProgram(const BugDriver &BD, Module *M1, Module *M2, - bool DeleteInputs, std::string &Error, - bool &Broken) { - // Link the two portions of the program back to together. - if (!DeleteInputs) { - M1 = CloneModule(M1); - M2 = CloneModule(M2); - } - if (Linker::LinkModules(M1, M2)) +static std::unique_ptr<Module> testMergedProgram(const BugDriver &BD, + std::unique_ptr<Module> M1, + std::unique_ptr<Module> M2, + std::string &Error, + bool &Broken) { + if (Linker::linkModules(*M1, std::move(M2))) exit(1); - delete M2; // We are done with this module. // Execute the program. - Broken = BD.diffProgram(M1, "", "", false, &Error); - if (!Error.empty()) { - // Delete the linked module - delete M1; + Broken = BD.diffProgram(M1.get(), "", "", false, &Error); + if (!Error.empty()) return nullptr; - } return M1; } @@ -259,7 +254,7 @@ bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs, // we can conclude that a function triggers the bug when in fact one // needs a larger set of original functions to do so. ValueToValueMapTy VMap; - Module *Clone = CloneModule(BD.getProgram(), VMap); + Module *Clone = CloneModule(BD.getProgram(), VMap).release(); Module *Orig = BD.swapProgramIn(Clone); std::vector<Function*> FuncsOnClone; @@ -270,12 +265,12 @@ bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs, // Split the module into the two halves of the program we want. VMap.clear(); - Module *ToNotOptimize = CloneModule(BD.getProgram(), VMap); - Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, FuncsOnClone, - VMap); + std::unique_ptr<Module> ToNotOptimize = CloneModule(BD.getProgram(), VMap); + std::unique_ptr<Module> ToOptimize = + SplitFunctionsOutOfModule(ToNotOptimize.get(), FuncsOnClone, VMap); - // Run the predicate, note that the predicate will delete both input modules. - bool Broken = TestFn(BD, ToOptimize, ToNotOptimize, Error); + bool Broken = + TestFn(BD, std::move(ToOptimize), std::move(ToNotOptimize), Error); delete BD.swapProgramIn(Orig); @@ -294,29 +289,29 @@ static void DisambiguateGlobalSymbols(Module *M) { I->setName("anon_fn"); } -/// ExtractLoops - Given a reduced list of functions that still exposed the bug, -/// check to see if we can extract the loops in the region without obscuring the -/// bug. If so, it reduces the amount of code identified. +/// Given a reduced list of functions that still exposed the bug, check to see +/// if we can extract the loops in the region without obscuring the bug. If so, +/// it reduces the amount of code identified. /// static bool ExtractLoops(BugDriver &BD, - bool (*TestFn)(BugDriver &, Module *, Module *, - std::string &), - std::vector<Function*> &MiscompiledFunctions, + bool (*TestFn)(BugDriver &, std::unique_ptr<Module>, + std::unique_ptr<Module>, std::string &), + std::vector<Function *> &MiscompiledFunctions, std::string &Error) { bool MadeChange = false; while (1) { if (BugpointIsInterrupted) return MadeChange; ValueToValueMapTy VMap; - Module *ToNotOptimize = CloneModule(BD.getProgram(), VMap); - Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, - MiscompiledFunctions, - VMap); - Module *ToOptimizeLoopExtracted = BD.extractLoop(ToOptimize).release(); + std::unique_ptr<Module> ToNotOptimize = CloneModule(BD.getProgram(), VMap); + Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize.get(), + MiscompiledFunctions, VMap) + .release(); + std::unique_ptr<Module> ToOptimizeLoopExtracted = + BD.extractLoop(ToOptimize); if (!ToOptimizeLoopExtracted) { // If the loop extractor crashed or if there were no extractible loops, // then this chapter of our odyssey is over with. - delete ToNotOptimize; delete ToOptimize; return MadeChange; } @@ -330,13 +325,14 @@ static bool ExtractLoops(BugDriver &BD, // extraction. AbstractInterpreter *AI = BD.switchToSafeInterpreter(); bool Failure; - Module *New = TestMergedProgram(BD, ToOptimizeLoopExtracted, - ToNotOptimize, false, Error, Failure); + std::unique_ptr<Module> New = + testMergedProgram(BD, std::move(ToOptimizeLoopExtracted), + std::move(ToNotOptimize), Error, Failure); if (!New) return false; // Delete the original and set the new program. - Module *Old = BD.swapProgramIn(New); + Module *Old = BD.swapProgramIn(New.release()); for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); delete Old; @@ -350,16 +346,15 @@ static bool ExtractLoops(BugDriver &BD, errs() << " Continuing on with un-loop-extracted version.\n"; BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-tno.bc", - ToNotOptimize); + ToNotOptimize.get()); BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to.bc", ToOptimize); BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to-le.bc", - ToOptimizeLoopExtracted); + ToOptimizeLoopExtracted.get()); errs() << "Please submit the " << OutputPrefix << "-loop-extract-fail-*.bc files.\n"; delete ToOptimize; - delete ToNotOptimize; return MadeChange; } delete ToOptimize; @@ -367,18 +362,20 @@ static bool ExtractLoops(BugDriver &BD, outs() << " Testing after loop extraction:\n"; // Clone modules, the tester function will free them. - Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted, VMap); - Module *TNOBackup = CloneModule(ToNotOptimize, VMap); + std::unique_ptr<Module> TOLEBackup = + CloneModule(ToOptimizeLoopExtracted.get(), VMap); + std::unique_ptr<Module> TNOBackup = CloneModule(ToNotOptimize.get(), VMap); for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); - Failure = TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize, Error); + Failure = TestFn(BD, std::move(ToOptimizeLoopExtracted), + std::move(ToNotOptimize), Error); if (!Error.empty()) return false; - ToOptimizeLoopExtracted = TOLEBackup; - ToNotOptimize = TNOBackup; + ToOptimizeLoopExtracted = std::move(TOLEBackup); + ToNotOptimize = std::move(TNOBackup); if (!Failure) { outs() << "*** Loop extraction masked the problem. Undoing.\n"; @@ -390,7 +387,8 @@ static bool ExtractLoops(BugDriver &BD, MisCompFunctions.emplace_back(F->getName(), F->getFunctionType()); } - if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted)) + if (Linker::linkModules(*ToNotOptimize, + std::move(ToOptimizeLoopExtracted))) exit(1); MiscompiledFunctions.clear(); @@ -401,8 +399,7 @@ static bool ExtractLoops(BugDriver &BD, MiscompiledFunctions.push_back(NewF); } - delete ToOptimizeLoopExtracted; - BD.setNewProgram(ToNotOptimize); + BD.setNewProgram(ToNotOptimize.release()); return MadeChange; } @@ -418,11 +415,9 @@ static bool ExtractLoops(BugDriver &BD, // extraction both didn't break the program, and didn't mask the problem. // Replace the current program with the loop extracted version, and try to // extract another loop. - if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted)) + if (Linker::linkModules(*ToNotOptimize, std::move(ToOptimizeLoopExtracted))) exit(1); - delete ToOptimizeLoopExtracted; - // All of the Function*'s in the MiscompiledFunctions list are in the old // module. Update this list to include all of the functions in the // optimized and loop extracted module. @@ -434,7 +429,7 @@ static bool ExtractLoops(BugDriver &BD, MiscompiledFunctions.push_back(NewF); } - BD.setNewProgram(ToNotOptimize); + BD.setNewProgram(ToNotOptimize.release()); MadeChange = true; } } @@ -442,14 +437,15 @@ static bool ExtractLoops(BugDriver &BD, namespace { class ReduceMiscompiledBlocks : public ListReducer<BasicBlock*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *, Module *, std::string &); + bool (*TestFn)(BugDriver &, std::unique_ptr<Module>, + std::unique_ptr<Module>, std::string &); std::vector<Function*> FunctionsBeingTested; public: ReduceMiscompiledBlocks(BugDriver &bd, - bool (*F)(BugDriver &, Module *, Module *, - std::string &), - const std::vector<Function*> &Fns) - : BD(bd), TestFn(F), FunctionsBeingTested(Fns) {} + bool (*F)(BugDriver &, std::unique_ptr<Module>, + std::unique_ptr<Module>, std::string &), + const std::vector<Function *> &Fns) + : BD(bd), TestFn(F), FunctionsBeingTested(Fns) {} TestResult doTest(std::vector<BasicBlock*> &Prefix, std::vector<BasicBlock*> &Suffix, @@ -495,7 +491,7 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs, // Split the module into the two halves of the program we want. ValueToValueMapTy VMap; - Module *Clone = CloneModule(BD.getProgram(), VMap); + Module *Clone = CloneModule(BD.getProgram(), VMap).release(); Module *Orig = BD.swapProgramIn(Clone); std::vector<Function*> FuncsOnClone; std::vector<BasicBlock*> BBsOnClone; @@ -509,45 +505,37 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs, } VMap.clear(); - Module *ToNotOptimize = CloneModule(BD.getProgram(), VMap); - Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, - FuncsOnClone, - VMap); + std::unique_ptr<Module> ToNotOptimize = CloneModule(BD.getProgram(), VMap); + std::unique_ptr<Module> ToOptimize = + SplitFunctionsOutOfModule(ToNotOptimize.get(), FuncsOnClone, VMap); // Try the extraction. If it doesn't work, then the block extractor crashed // or something, in which case bugpoint can't chase down this possibility. if (std::unique_ptr<Module> New = - BD.extractMappedBlocksFromModule(BBsOnClone, ToOptimize)) { - delete ToOptimize; - // Run the predicate, - // note that the predicate will delete both input modules. - bool Ret = TestFn(BD, New.get(), ToNotOptimize, Error); + BD.extractMappedBlocksFromModule(BBsOnClone, ToOptimize.get())) { + bool Ret = TestFn(BD, std::move(New), std::move(ToNotOptimize), Error); delete BD.swapProgramIn(Orig); return Ret; } delete BD.swapProgramIn(Orig); - delete ToOptimize; - delete ToNotOptimize; return false; } - -/// ExtractBlocks - Given a reduced list of functions that still expose the bug, -/// extract as many basic blocks from the region as possible without obscuring -/// the bug. +/// Given a reduced list of functions that still expose the bug, extract as many +/// basic blocks from the region as possible without obscuring the bug. /// static bool ExtractBlocks(BugDriver &BD, - bool (*TestFn)(BugDriver &, Module *, Module *, + bool (*TestFn)(BugDriver &, std::unique_ptr<Module>, + std::unique_ptr<Module>, std::string &), - std::vector<Function*> &MiscompiledFunctions, + std::vector<Function *> &MiscompiledFunctions, std::string &Error) { if (BugpointIsInterrupted) return false; std::vector<BasicBlock*> Blocks; for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) - for (Function::iterator I = MiscompiledFunctions[i]->begin(), - E = MiscompiledFunctions[i]->end(); I != E; ++I) - Blocks.push_back(I); + for (BasicBlock &BB : *MiscompiledFunctions[i]) + Blocks.push_back(&BB); // Use the list reducer to identify blocks that can be extracted without // obscuring the bug. The Blocks list will end up containing blocks that must @@ -571,10 +559,10 @@ static bool ExtractBlocks(BugDriver &BD, } ValueToValueMapTy VMap; - Module *ProgClone = CloneModule(BD.getProgram(), VMap); - Module *ToExtract = SplitFunctionsOutOfModule(ProgClone, - MiscompiledFunctions, - VMap); + Module *ProgClone = CloneModule(BD.getProgram(), VMap).release(); + Module *ToExtract = + SplitFunctionsOutOfModule(ProgClone, MiscompiledFunctions, VMap) + .release(); std::unique_ptr<Module> Extracted = BD.extractMappedBlocksFromModule(Blocks, ToExtract); if (!Extracted) { @@ -595,7 +583,7 @@ static bool ExtractBlocks(BugDriver &BD, if (!I->isDeclaration()) MisCompFunctions.emplace_back(I->getName(), I->getFunctionType()); - if (Linker::LinkModules(ProgClone, Extracted.get())) + if (Linker::linkModules(*ProgClone, std::move(Extracted))) exit(1); // Set the new program and delete the old one. @@ -613,14 +601,13 @@ static bool ExtractBlocks(BugDriver &BD, return true; } - -/// DebugAMiscompilation - This is a generic driver to narrow down -/// miscompilations, either in an optimization or a code generator. +/// This is a generic driver to narrow down miscompilations, either in an +/// optimization or a code generator. /// -static std::vector<Function*> +static std::vector<Function *> DebugAMiscompilation(BugDriver &BD, - bool (*TestFn)(BugDriver &, Module *, Module *, - std::string &), + bool (*TestFn)(BugDriver &, std::unique_ptr<Module>, + std::unique_ptr<Module>, std::string &), std::string &Error) { // Okay, now that we have reduced the list of passes which are causing the // failure, see if we can pin down which functions are being @@ -628,9 +615,9 @@ DebugAMiscompilation(BugDriver &BD, // the program. std::vector<Function*> MiscompiledFunctions; Module *Prog = BD.getProgram(); - for (Module::iterator I = Prog->begin(), E = Prog->end(); I != E; ++I) - if (!I->isDeclaration()) - MiscompiledFunctions.push_back(I); + for (Function &F : *Prog) + if (!F.isDeclaration()) + MiscompiledFunctions.push_back(&F); // Do the reduction... if (!BugpointIsInterrupted) @@ -699,28 +686,28 @@ DebugAMiscompilation(BugDriver &BD, return MiscompiledFunctions; } -/// TestOptimizer - This is the predicate function used to check to see if the -/// "Test" portion of the program is misoptimized. If so, return true. In any -/// case, both module arguments are deleted. +/// This is the predicate function used to check to see if the "Test" portion of +/// the program is misoptimized. If so, return true. In any case, both module +/// arguments are deleted. /// -static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe, - std::string &Error) { +static bool TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test, + std::unique_ptr<Module> Safe, std::string &Error) { // Run the optimization passes on ToOptimize, producing a transformed version // of the functions being tested. outs() << " Optimizing functions being tested: "; - std::unique_ptr<Module> Optimized = BD.runPassesOn(Test, BD.getPassesToRun(), - /*AutoDebugCrashes*/ true); + std::unique_ptr<Module> Optimized = + BD.runPassesOn(Test.get(), BD.getPassesToRun(), + /*AutoDebugCrashes*/ true); outs() << "done.\n"; - delete Test; outs() << " Checking to see if the merged program executes correctly: "; bool Broken; - Module *New = - TestMergedProgram(BD, Optimized.get(), Safe, true, Error, Broken); + std::unique_ptr<Module> New = testMergedProgram( + BD, std::move(Optimized), std::move(Safe), Error, Broken); if (New) { outs() << (Broken ? " nope.\n" : " yup.\n"); // Delete the original and set the new program. - delete BD.swapProgramIn(New); + delete BD.swapProgramIn(New.release()); } return Broken; } @@ -753,10 +740,10 @@ void BugDriver::debugMiscompilation(std::string *Error) { // Output a bunch of bitcode files for the user... outs() << "Outputting reduced bitcode files which expose the problem:\n"; ValueToValueMapTy VMap; - Module *ToNotOptimize = CloneModule(getProgram(), VMap); - Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, - MiscompiledFunctions, - VMap); + Module *ToNotOptimize = CloneModule(getProgram(), VMap).release(); + Module *ToOptimize = + SplitFunctionsOutOfModule(ToNotOptimize, MiscompiledFunctions, VMap) + .release(); outs() << " Non-optimized portion: "; EmitProgressBitcode(ToNotOptimize, "tonotoptimize", true); @@ -769,13 +756,13 @@ void BugDriver::debugMiscompilation(std::string *Error) { return; } -/// CleanupAndPrepareModules - Get the specified modules ready for code -/// generator testing. +/// Get the specified modules ready for code generator testing. /// -static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, +static void CleanupAndPrepareModules(BugDriver &BD, + std::unique_ptr<Module> &Test, Module *Safe) { // Clean up the modules, removing extra cruft that we don't need anymore... - Test = BD.performFinalCleanups(Test).release(); + Test = BD.performFinalCleanups(Test.get()); // If we are executing the JIT, we have several nasty issues to take care of. if (!BD.isExecutingJIT()) return; @@ -788,21 +775,21 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, // Rename it oldMain->setName("llvm_bugpoint_old_main"); // Create a NEW `main' function with same type in the test module. - Function *newMain = Function::Create(oldMain->getFunctionType(), - GlobalValue::ExternalLinkage, - "main", Test); + Function *newMain = + Function::Create(oldMain->getFunctionType(), + GlobalValue::ExternalLinkage, "main", Test.get()); // Create an `oldmain' prototype in the test module, which will // corresponds to the real main function in the same module. Function *oldMainProto = Function::Create(oldMain->getFunctionType(), GlobalValue::ExternalLinkage, - oldMain->getName(), Test); + oldMain->getName(), Test.get()); // Set up and remember the argument list for the main function. std::vector<Value*> args; for (Function::arg_iterator I = newMain->arg_begin(), E = newMain->arg_end(), OI = oldMain->arg_begin(); I != E; ++I, ++OI) { I->setName(OI->getName()); // Copy argument names from oldMain - args.push_back(I); + args.push_back(&*I); } // Call the old main function and return its result @@ -905,9 +892,8 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, // Save the argument list. std::vector<Value*> Args; - for (Function::arg_iterator i = FuncWrapper->arg_begin(), - e = FuncWrapper->arg_end(); i != e; ++i) - Args.push_back(i); + for (Argument &A : FuncWrapper->args()) + Args.push_back(&A); // Pass on the arguments to the real function, return its result if (F->getReturnType()->isVoidTy()) { @@ -932,15 +918,14 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, } } - - -/// TestCodeGenerator - This is the predicate function used to check to see if -/// the "Test" portion of the program is miscompiled by the code generator under -/// test. If so, return true. In any case, both module arguments are deleted. +/// This is the predicate function used to check to see if the "Test" portion of +/// the program is miscompiled by the code generator under test. If so, return +/// true. In any case, both module arguments are deleted. /// -static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, +static bool TestCodeGenerator(BugDriver &BD, std::unique_ptr<Module> Test, + std::unique_ptr<Module> Safe, std::string &Error) { - CleanupAndPrepareModules(BD, Test, Safe); + CleanupAndPrepareModules(BD, Test, Safe.get()); SmallString<128> TestModuleBC; int TestModuleFD; @@ -951,12 +936,11 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, << EC.message() << "\n"; exit(1); } - if (BD.writeProgramToFile(TestModuleBC.str(), TestModuleFD, Test)) { + if (BD.writeProgramToFile(TestModuleBC.str(), TestModuleFD, Test.get())) { errs() << "Error writing bitcode to `" << TestModuleBC.str() << "'\nExiting."; exit(1); } - delete Test; FileRemover TestModuleBCRemover(TestModuleBC.str(), !SaveTemps); @@ -971,7 +955,7 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, exit(1); } - if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe)) { + if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe.get())) { errs() << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting."; exit(1); @@ -982,7 +966,6 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, std::string SharedObject = BD.compileSharedObject(SafeModuleBC.str(), Error); if (!Error.empty()) return false; - delete Safe; FileRemover SharedObjectRemover(SharedObject, !SaveTemps); @@ -1030,11 +1013,12 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { // Split the module into the two halves of the program we want. ValueToValueMapTy VMap; - Module *ToNotCodeGen = CloneModule(getProgram(), VMap); - Module *ToCodeGen = SplitFunctionsOutOfModule(ToNotCodeGen, Funcs, VMap); + std::unique_ptr<Module> ToNotCodeGen = CloneModule(getProgram(), VMap); + std::unique_ptr<Module> ToCodeGen = + SplitFunctionsOutOfModule(ToNotCodeGen.get(), Funcs, VMap); // Condition the modules - CleanupAndPrepareModules(*this, ToCodeGen, ToNotCodeGen); + CleanupAndPrepareModules(*this, ToCodeGen, ToNotCodeGen.get()); SmallString<128> TestModuleBC; int TestModuleFD; @@ -1046,12 +1030,11 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { exit(1); } - if (writeProgramToFile(TestModuleBC.str(), TestModuleFD, ToCodeGen)) { + if (writeProgramToFile(TestModuleBC.str(), TestModuleFD, ToCodeGen.get())) { errs() << "Error writing bitcode to `" << TestModuleBC << "'\nExiting."; exit(1); } - delete ToCodeGen; // Make the shared library SmallString<128> SafeModuleBC; @@ -1064,7 +1047,8 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { exit(1); } - if (writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, ToNotCodeGen)) { + if (writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, + ToNotCodeGen.get())) { errs() << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting."; exit(1); @@ -1072,7 +1056,6 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { std::string SharedObject = compileSharedObject(SafeModuleBC.str(), *Error); if (!Error->empty()) return true; - delete ToNotCodeGen; outs() << "You can reproduce the problem with the command line: \n"; if (isExecutingJIT()) { @@ -1080,7 +1063,7 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { } else { outs() << " llc " << TestModuleBC << " -o " << TestModuleBC << ".s\n"; - outs() << " gcc " << SharedObject << " " << TestModuleBC.str() + outs() << " cc " << SharedObject << " " << TestModuleBC.str() << ".s -o " << TestModuleBC << ".exe"; #if defined (HAVE_LINK_R) outs() << " -Wl,-R."; @@ -1093,7 +1076,7 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { outs() << '\n'; outs() << "The shared object was created with:\n llc -march=c " << SafeModuleBC.str() << " -o temporary.c\n" - << " gcc -xc temporary.c -O2 -o " << SharedObject; + << " cc -xc temporary.c -O2 -o " << SharedObject; if (TargetTriple.getArch() == Triple::sparc) outs() << " -G"; // Compile a shared library, `-G' for Sparc else diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.cpp b/contrib/llvm/tools/bugpoint/ToolRunner.cpp index 51091e2..2ccd649 100644 --- a/contrib/llvm/tools/bugpoint/ToolRunner.cpp +++ b/contrib/llvm/tools/bugpoint/ToolRunner.cpp @@ -64,16 +64,6 @@ static int RunProgramWithTimeout(StringRef ProgramPath, unsigned MemoryLimit = 0, std::string *ErrMsg = nullptr) { const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile }; - -#if 0 // For debug purposes - { - errs() << "RUN:"; - for (unsigned i = 0; Args[i]; ++i) - errs() << " " << Args[i]; - errs() << "\n"; - } -#endif - return sys::ExecuteAndWait(ProgramPath, Args, nullptr, Redirects, NumSeconds, MemoryLimit, ErrMsg); } @@ -93,15 +83,6 @@ static int RunProgramRemotelyWithTimeout(StringRef RemoteClientPath, unsigned MemoryLimit = 0) { const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile }; -#if 0 // For debug purposes - { - errs() << "RUN:"; - for (unsigned i = 0; Args[i]; ++i) - errs() << " " << Args[i]; - errs() << "\n"; - } -#endif - // Run the program remotely with the remote client int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, nullptr, Redirects, NumSeconds, MemoryLimit); @@ -152,7 +133,7 @@ static std::string ProcessFailure(StringRef ProgPath, const char** Args, ErrorFilename.str(), Timeout, MemoryLimit); // FIXME: check return code ? - // Print out the error messages generated by GCC if possible... + // Print out the error messages generated by CC if possible... std::ifstream ErrorFile(ErrorFilename.c_str()); if (ErrorFile) { std::copy(std::istreambuf_iterator<char>(ErrorFile), @@ -184,7 +165,7 @@ namespace { const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &CCArgs, const std::vector<std::string> &SharedLibs = std::vector<std::string>(), unsigned Timeout = 0, @@ -197,7 +178,7 @@ int LLI::ExecuteProgram(const std::string &Bitcode, const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &CCArgs, const std::vector<std::string> &SharedLibs, unsigned Timeout, unsigned MemoryLimit) { @@ -305,7 +286,7 @@ namespace { const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &GCCArgs = + const std::vector<std::string> &CCArgs = std::vector<std::string>(), const std::vector<std::string> &SharedLibs = std::vector<std::string>(), @@ -361,7 +342,7 @@ namespace { const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &CCArgs, const std::vector<std::string> &SharedLibs = std::vector<std::string>(), unsigned Timeout = 0, @@ -374,7 +355,7 @@ int CustomExecutor::ExecuteProgram(const std::string &Bitcode, const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &CCArgs, const std::vector<std::string> &SharedLibs, unsigned Timeout, unsigned MemoryLimit) { @@ -473,7 +454,7 @@ AbstractInterpreter *AbstractInterpreter::createCustomExecutor( //===----------------------------------------------------------------------===// // LLC Implementation of AbstractIntepreter interface // -GCC::FileType LLC::OutputCode(const std::string &Bitcode, +CC::FileType LLC::OutputCode(const std::string &Bitcode, std::string &OutputAsmFile, std::string &Error, unsigned Timeout, unsigned MemoryLimit) { const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); @@ -514,7 +495,7 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, Timeout, MemoryLimit)) Error = ProcessFailure(LLCPath, &LLCArgs[0], Timeout, MemoryLimit); - return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; + return UseIntegratedAssembler ? CC::ObjectFile : CC::AsmFile; } void LLC::compileProgram(const std::string &Bitcode, std::string *Error, @@ -529,22 +510,22 @@ int LLC::ExecuteProgram(const std::string &Bitcode, const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &ArgsForGCC, + const std::vector<std::string> &ArgsForCC, const std::vector<std::string> &SharedLibs, unsigned Timeout, unsigned MemoryLimit) { std::string OutputAsmFile; - GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, + CC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit); FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); - std::vector<std::string> GCCArgs(ArgsForGCC); - GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); + std::vector<std::string> CCArgs(ArgsForCC); + CCArgs.insert(CCArgs.end(), SharedLibs.begin(), SharedLibs.end()); - // Assuming LLC worked, compile the result with GCC and run it. - return gcc->ExecuteProgram(OutputAsmFile, Args, FileKind, - InputFile, OutputFile, Error, GCCArgs, + // Assuming LLC worked, compile the result with CC and run it. + return cc->ExecuteProgram(OutputAsmFile, Args, FileKind, + InputFile, OutputFile, Error, CCArgs, Timeout, MemoryLimit); } @@ -552,9 +533,9 @@ int LLC::ExecuteProgram(const std::string &Bitcode, /// LLC *AbstractInterpreter::createLLC(const char *Argv0, std::string &Message, - const std::string &GCCBinary, + const std::string &CCBinary, const std::vector<std::string> *Args, - const std::vector<std::string> *GCCArgs, + const std::vector<std::string> *CCArgs, bool UseIntegratedAssembler) { std::string LLCPath = PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t) & createLLC); @@ -563,13 +544,13 @@ LLC *AbstractInterpreter::createLLC(const char *Argv0, return nullptr; } - GCC *gcc = GCC::create(Message, GCCBinary, GCCArgs); - if (!gcc) { + CC *cc = CC::create(Message, CCBinary, CCArgs); + if (!cc) { errs() << Message << "\n"; exit(1); } Message = "Found llc: " + LLCPath + "\n"; - return new LLC(LLCPath, gcc, Args, UseIntegratedAssembler); + return new LLC(LLCPath, cc, Args, UseIntegratedAssembler); } //===---------------------------------------------------------------------===// @@ -591,7 +572,7 @@ namespace { const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &GCCArgs = + const std::vector<std::string> &CCArgs = std::vector<std::string>(), const std::vector<std::string> &SharedLibs = std::vector<std::string>(), @@ -605,7 +586,7 @@ int JIT::ExecuteProgram(const std::string &Bitcode, const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &CCArgs, const std::vector<std::string> &SharedLibs, unsigned Timeout, unsigned MemoryLimit) { @@ -656,7 +637,7 @@ AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0, } //===---------------------------------------------------------------------===// -// GCC abstraction +// CC abstraction // static bool IsARMArchitecture(std::vector<const char*> Args) { @@ -672,82 +653,82 @@ static bool IsARMArchitecture(std::vector<const char*> Args) { return false; } -int GCC::ExecuteProgram(const std::string &ProgramFile, +int CC::ExecuteProgram(const std::string &ProgramFile, const std::vector<std::string> &Args, FileType fileType, const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &ArgsForGCC, + const std::vector<std::string> &ArgsForCC, unsigned Timeout, unsigned MemoryLimit) { - std::vector<const char*> GCCArgs; + std::vector<const char*> CCArgs; - GCCArgs.push_back(GCCPath.c_str()); + CCArgs.push_back(CCPath.c_str()); if (TargetTriple.getArch() == Triple::x86) - GCCArgs.push_back("-m32"); + CCArgs.push_back("-m32"); for (std::vector<std::string>::const_iterator - I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I) - GCCArgs.push_back(I->c_str()); + I = ccArgs.begin(), E = ccArgs.end(); I != E; ++I) + CCArgs.push_back(I->c_str()); // Specify -x explicitly in case the extension is wonky if (fileType != ObjectFile) { - GCCArgs.push_back("-x"); + CCArgs.push_back("-x"); if (fileType == CFile) { - GCCArgs.push_back("c"); - GCCArgs.push_back("-fno-strict-aliasing"); + CCArgs.push_back("c"); + CCArgs.push_back("-fno-strict-aliasing"); } else { - GCCArgs.push_back("assembler"); + CCArgs.push_back("assembler"); // For ARM architectures we don't want this flag. bugpoint isn't // explicitly told what architecture it is working on, so we get - // it from gcc flags - if (TargetTriple.isOSDarwin() && !IsARMArchitecture(GCCArgs)) - GCCArgs.push_back("-force_cpusubtype_ALL"); + // it from cc flags + if (TargetTriple.isOSDarwin() && !IsARMArchitecture(CCArgs)) + CCArgs.push_back("-force_cpusubtype_ALL"); } } - GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename. + CCArgs.push_back(ProgramFile.c_str()); // Specify the input filename. - GCCArgs.push_back("-x"); - GCCArgs.push_back("none"); - GCCArgs.push_back("-o"); + CCArgs.push_back("-x"); + CCArgs.push_back("none"); + CCArgs.push_back("-o"); SmallString<128> OutputBinary; std::error_code EC = - sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.gcc.exe", OutputBinary); + sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.cc.exe", OutputBinary); if (EC) { errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } - GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file... + CCArgs.push_back(OutputBinary.c_str()); // Output to the right file... - // Add any arguments intended for GCC. We locate them here because this is + // Add any arguments intended for CC. We locate them here because this is // most likely -L and -l options that need to come before other libraries but // after the source. Other options won't be sensitive to placement on the // command line, so this should be safe. - for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i) - GCCArgs.push_back(ArgsForGCC[i].c_str()); + for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i) + CCArgs.push_back(ArgsForCC[i].c_str()); - GCCArgs.push_back("-lm"); // Hard-code the math library... - GCCArgs.push_back("-O2"); // Optimize the program a bit... + CCArgs.push_back("-lm"); // Hard-code the math library... + CCArgs.push_back("-O2"); // Optimize the program a bit... #if defined (HAVE_LINK_R) - GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files + CCArgs.push_back("-Wl,-R."); // Search this dir for .so files #endif if (TargetTriple.getArch() == Triple::sparc) - GCCArgs.push_back("-mcpu=v9"); - GCCArgs.push_back(nullptr); // NULL terminator + CCArgs.push_back("-mcpu=v9"); + CCArgs.push_back(nullptr); // NULL terminator - outs() << "<gcc>"; outs().flush(); + outs() << "<CC>"; outs().flush(); DEBUG(errs() << "\nAbout to run:\t"; - for (unsigned i = 0, e = GCCArgs.size()-1; i != e; ++i) - errs() << " " << GCCArgs[i]; + for (unsigned i = 0, e = CCArgs.size()-1; i != e; ++i) + errs() << " " << CCArgs[i]; errs() << "\n"; ); - if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "", "", "")) { - *Error = ProcessFailure(GCCPath, &GCCArgs[0]); + if (RunProgramWithTimeout(CCPath, &CCArgs[0], "", "", "")) { + *Error = ProcessFailure(CCPath, &CCArgs[0]); return -1; } @@ -821,9 +802,9 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, } } -int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, +int CC::MakeSharedObject(const std::string &InputFile, FileType fileType, std::string &OutputFile, - const std::vector<std::string> &ArgsForGCC, + const std::vector<std::string> &ArgsForCC, std::string &Error) { SmallString<128> UniqueFilename; std::error_code EC = sys::fs::createUniqueFile( @@ -834,84 +815,84 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, } OutputFile = UniqueFilename.str(); - std::vector<const char*> GCCArgs; + std::vector<const char*> CCArgs; - GCCArgs.push_back(GCCPath.c_str()); + CCArgs.push_back(CCPath.c_str()); if (TargetTriple.getArch() == Triple::x86) - GCCArgs.push_back("-m32"); + CCArgs.push_back("-m32"); for (std::vector<std::string>::const_iterator - I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I) - GCCArgs.push_back(I->c_str()); + I = ccArgs.begin(), E = ccArgs.end(); I != E; ++I) + CCArgs.push_back(I->c_str()); // Compile the C/asm file into a shared object if (fileType != ObjectFile) { - GCCArgs.push_back("-x"); - GCCArgs.push_back(fileType == AsmFile ? "assembler" : "c"); + CCArgs.push_back("-x"); + CCArgs.push_back(fileType == AsmFile ? "assembler" : "c"); } - GCCArgs.push_back("-fno-strict-aliasing"); - GCCArgs.push_back(InputFile.c_str()); // Specify the input filename. - GCCArgs.push_back("-x"); - GCCArgs.push_back("none"); + CCArgs.push_back("-fno-strict-aliasing"); + CCArgs.push_back(InputFile.c_str()); // Specify the input filename. + CCArgs.push_back("-x"); + CCArgs.push_back("none"); if (TargetTriple.getArch() == Triple::sparc) - GCCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc + CCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc else if (TargetTriple.isOSDarwin()) { // link all source files into a single module in data segment, rather than // generating blocks. dynamic_lookup requires that you set // MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for - // bugpoint to just pass that in the environment of GCC. - GCCArgs.push_back("-single_module"); - GCCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC - GCCArgs.push_back("-undefined"); - GCCArgs.push_back("dynamic_lookup"); + // bugpoint to just pass that in the environment of CC. + CCArgs.push_back("-single_module"); + CCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC + CCArgs.push_back("-undefined"); + CCArgs.push_back("dynamic_lookup"); } else - GCCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others + CCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others if (TargetTriple.getArch() == Triple::x86_64) - GCCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC + CCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC if (TargetTriple.getArch() == Triple::sparc) - GCCArgs.push_back("-mcpu=v9"); + CCArgs.push_back("-mcpu=v9"); - GCCArgs.push_back("-o"); - GCCArgs.push_back(OutputFile.c_str()); // Output to the right filename. - GCCArgs.push_back("-O2"); // Optimize the program a bit. + CCArgs.push_back("-o"); + CCArgs.push_back(OutputFile.c_str()); // Output to the right filename. + CCArgs.push_back("-O2"); // Optimize the program a bit. - // Add any arguments intended for GCC. We locate them here because this is + // Add any arguments intended for CC. We locate them here because this is // most likely -L and -l options that need to come before other libraries but // after the source. Other options won't be sensitive to placement on the // command line, so this should be safe. - for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i) - GCCArgs.push_back(ArgsForGCC[i].c_str()); - GCCArgs.push_back(nullptr); // NULL terminator + for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i) + CCArgs.push_back(ArgsForCC[i].c_str()); + CCArgs.push_back(nullptr); // NULL terminator - outs() << "<gcc>"; outs().flush(); + outs() << "<CC>"; outs().flush(); DEBUG(errs() << "\nAbout to run:\t"; - for (unsigned i = 0, e = GCCArgs.size()-1; i != e; ++i) - errs() << " " << GCCArgs[i]; + for (unsigned i = 0, e = CCArgs.size()-1; i != e; ++i) + errs() << " " << CCArgs[i]; errs() << "\n"; ); - if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "", "", "")) { - Error = ProcessFailure(GCCPath, &GCCArgs[0]); + if (RunProgramWithTimeout(CCPath, &CCArgs[0], "", "", "")) { + Error = ProcessFailure(CCPath, &CCArgs[0]); return 1; } return 0; } -/// create - Try to find the `gcc' executable +/// create - Try to find the CC executable /// -GCC *GCC::create(std::string &Message, - const std::string &GCCBinary, +CC *CC::create(std::string &Message, + const std::string &CCBinary, const std::vector<std::string> *Args) { - auto GCCPath = sys::findProgramByName(GCCBinary); - if (!GCCPath) { - Message = "Cannot find `" + GCCBinary + "' in PATH: " + - GCCPath.getError().message() + "\n"; + auto CCPath = sys::findProgramByName(CCBinary); + if (!CCPath) { + Message = "Cannot find `" + CCBinary + "' in PATH: " + + CCPath.getError().message() + "\n"; return nullptr; } @@ -926,6 +907,6 @@ GCC *GCC::create(std::string &Message, RemoteClientPath = *Path; } - Message = "Found gcc: " + *GCCPath + "\n"; - return new GCC(*GCCPath, RemoteClientPath, Args); + Message = "Found CC: " + *CCPath + "\n"; + return new CC(*CCPath, RemoteClientPath, Args); } diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.h b/contrib/llvm/tools/bugpoint/ToolRunner.h index 5d67a94..3accd70 100644 --- a/contrib/llvm/tools/bugpoint/ToolRunner.h +++ b/contrib/llvm/tools/bugpoint/ToolRunner.h @@ -33,22 +33,22 @@ extern Triple TargetTriple; class LLC; //===---------------------------------------------------------------------===// -// GCC abstraction +// CC abstraction // -class GCC { - std::string GCCPath; // The path to the gcc executable. +class CC { + std::string CCPath; // The path to the cc executable. std::string RemoteClientPath; // The path to the rsh / ssh executable. - std::vector<std::string> gccArgs; // GCC-specific arguments. - GCC(StringRef gccPath, StringRef RemotePath, - const std::vector<std::string> *GCCArgs) - : GCCPath(gccPath), RemoteClientPath(RemotePath) { - if (GCCArgs) gccArgs = *GCCArgs; + std::vector<std::string> ccArgs; // CC-specific arguments. + CC(StringRef ccPath, StringRef RemotePath, + const std::vector<std::string> *CCArgs) + : CCPath(ccPath), RemoteClientPath(RemotePath) { + if (CCArgs) ccArgs = *CCArgs; } public: enum FileType { AsmFile, ObjectFile, CFile }; - static GCC *create(std::string &Message, - const std::string &GCCBinary, + static CC *create(std::string &Message, + const std::string &CCBinary, const std::vector<std::string> *Args); /// ExecuteProgram - Execute the program specified by "ProgramFile" (which is @@ -64,7 +64,7 @@ public: const std::string &InputFile, const std::string &OutputFile, std::string *Error = nullptr, - const std::vector<std::string> &GCCArgs = + const std::vector<std::string> &CCArgs = std::vector<std::string>(), unsigned Timeout = 0, unsigned MemoryLimit = 0); @@ -74,7 +74,7 @@ public: /// int MakeSharedObject(const std::string &InputFile, FileType fileType, std::string &OutputFile, - const std::vector<std::string> &ArgsForGCC, + const std::vector<std::string> &ArgsForCC, std::string &Error); }; @@ -88,9 +88,9 @@ class AbstractInterpreter { virtual void anchor(); public: static LLC *createLLC(const char *Argv0, std::string &Message, - const std::string &GCCBinary, + const std::string &CCBinary, const std::vector<std::string> *Args = nullptr, - const std::vector<std::string> *GCCArgs = nullptr, + const std::vector<std::string> *CCArgs = nullptr, bool UseIntegratedAssembler = false); static AbstractInterpreter* @@ -119,15 +119,15 @@ public: unsigned Timeout = 0, unsigned MemoryLimit = 0) {} /// OutputCode - Compile the specified program from bitcode to code - /// understood by the GCC driver (either C or asm). If the code generator + /// understood by the CC driver (either C or asm). If the code generator /// fails, it sets Error, otherwise, this function returns the type of code /// emitted. - virtual GCC::FileType OutputCode(const std::string &Bitcode, + virtual CC::FileType OutputCode(const std::string &Bitcode, std::string &OutFile, std::string &Error, unsigned Timeout = 0, unsigned MemoryLimit = 0) { Error = "OutputCode not supported by this AbstractInterpreter!"; - return GCC::AsmFile; + return CC::AsmFile; } /// ExecuteProgram - Run the specified bitcode file, emitting output to the @@ -140,7 +140,7 @@ public: const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &GCCArgs = + const std::vector<std::string> &CCArgs = std::vector<std::string>(), const std::vector<std::string> &SharedLibs = std::vector<std::string>(), @@ -154,18 +154,18 @@ public: class LLC : public AbstractInterpreter { std::string LLCPath; // The path to the LLC executable. std::vector<std::string> ToolArgs; // Extra args to pass to LLC. - GCC *gcc; + CC *cc; bool UseIntegratedAssembler; public: - LLC(const std::string &llcPath, GCC *Gcc, + LLC(const std::string &llcPath, CC *cc, const std::vector<std::string> *Args, bool useIntegratedAssembler) - : LLCPath(llcPath), gcc(Gcc), + : LLCPath(llcPath), cc(cc), UseIntegratedAssembler(useIntegratedAssembler) { ToolArgs.clear(); if (Args) ToolArgs = *Args; } - ~LLC() override { delete gcc; } + ~LLC() override { delete cc; } /// compileProgram - Compile the specified program from bitcode to executable /// code. This does not produce any output, it is only used when debugging @@ -178,7 +178,7 @@ public: const std::string &InputFile, const std::string &OutputFile, std::string *Error, - const std::vector<std::string> &GCCArgs = + const std::vector<std::string> &CCArgs = std::vector<std::string>(), const std::vector<std::string> &SharedLibs = std::vector<std::string>(), @@ -186,10 +186,10 @@ public: unsigned MemoryLimit = 0) override; /// OutputCode - Compile the specified program from bitcode to code - /// understood by the GCC driver (either C or asm). If the code generator + /// understood by the CC driver (either C or asm). If the code generator /// fails, it sets Error, otherwise, this function returns the type of code /// emitted. - GCC::FileType OutputCode(const std::string &Bitcode, + CC::FileType OutputCode(const std::string &Bitcode, std::string &OutFile, std::string &Error, unsigned Timeout = 0, unsigned MemoryLimit = 0) override; diff --git a/contrib/llvm/tools/bugpoint/bugpoint.cpp b/contrib/llvm/tools/bugpoint/bugpoint.cpp index af6d9fc..48f30e6 100644 --- a/contrib/llvm/tools/bugpoint/bugpoint.cpp +++ b/contrib/llvm/tools/bugpoint/bugpoint.cpp @@ -126,7 +126,6 @@ int main(int argc, char **argv) { initializeVectorization(Registry); initializeIPO(Registry); initializeAnalysis(Registry); - initializeIPA(Registry); initializeTransformUtils(Registry); initializeInstCombine(Registry); initializeInstrumentation(Registry); @@ -181,19 +180,12 @@ int main(int argc, char **argv) { Builder.Inliner = createFunctionInliningPass(225); else Builder.Inliner = createFunctionInliningPass(275); - - // Note that although clang/llvm-gcc use two separate passmanagers - // here, it shouldn't normally make a difference. Builder.populateFunctionPassManager(PM); Builder.populateModulePassManager(PM); } - for (std::vector<const PassInfo*>::iterator I = PassList.begin(), - E = PassList.end(); - I != E; ++I) { - const PassInfo* PI = *I; + for (const PassInfo *PI : PassList) D.addPass(PI->getPassArgument()); - } // Bugpoint has the ability of generating a plethora of core files, so to // avoid filling up the disk, we prevent it diff --git a/contrib/llvm/tools/llc/llc.cpp b/contrib/llvm/tools/llc/llc.cpp index e33cd79..bffa39f 100644 --- a/contrib/llvm/tools/llc/llc.cpp +++ b/contrib/llvm/tools/llc/llc.cpp @@ -45,6 +45,7 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetSubtargetInfo.h" +#include "llvm/Transforms/Utils/Cloning.h" #include <memory> using namespace llvm; @@ -96,6 +97,12 @@ static cl::opt<bool> AsmVerbose("asm-verbose", cl::desc("Add comments to directives."), cl::init(true)); +static cl::opt<bool> + CompileTwice("compile-twice", cl::Hidden, + cl::desc("Run everything twice, re-using the same pass " + "manager and verify the result is the same."), + cl::init(false)); + static int compileModule(char **, LLVMContext &); static std::unique_ptr<tool_output_file> @@ -312,8 +319,7 @@ static int compileModule(char **argv, LLVMContext &Context) { PM.add(new TargetLibraryInfoWrapperPass(TLII)); // Add the target data from the target machine, if it exists, or the module. - if (const DataLayout *DL = Target->getDataLayout()) - M->setDataLayout(*DL); + M->setDataLayout(Target->createDataLayout()); // Override function attributes based on CPUStr, FeaturesStr, and command line // flags. @@ -326,10 +332,15 @@ static int compileModule(char **argv, LLVMContext &Context) { { raw_pwrite_stream *OS = &Out->os(); - std::unique_ptr<buffer_ostream> BOS; - if (FileType != TargetMachine::CGFT_AssemblyFile && - !Out->os().supportsSeeking()) { - BOS = make_unique<buffer_ostream>(*OS); + + // Manually do the buffering rather than using buffer_ostream, + // so we can memcmp the contents in CompileTwice mode + SmallVector<char, 0> Buffer; + std::unique_ptr<raw_svector_ostream> BOS; + if ((FileType != TargetMachine::CGFT_AssemblyFile && + !Out->os().supportsSeeking()) || + CompileTwice) { + BOS = make_unique<raw_svector_ostream>(Buffer); OS = BOS.get(); } @@ -379,7 +390,39 @@ static int compileModule(char **argv, LLVMContext &Context) { // Before executing passes, print the final values of the LLVM options. cl::PrintOptionValues(); + // If requested, run the pass manager over the same module again, + // to catch any bugs due to persistent state in the passes. Note that + // opt has the same functionality, so it may be worth abstracting this out + // in the future. + SmallVector<char, 0> CompileTwiceBuffer; + if (CompileTwice) { + std::unique_ptr<Module> M2(llvm::CloneModule(M.get())); + PM.run(*M2); + CompileTwiceBuffer = Buffer; + Buffer.clear(); + } + PM.run(*M); + + // Compare the two outputs and make sure they're the same + if (CompileTwice) { + if (Buffer.size() != CompileTwiceBuffer.size() || + (memcmp(Buffer.data(), CompileTwiceBuffer.data(), Buffer.size()) != + 0)) { + errs() + << "Running the pass manager twice changed the output.\n" + "Writing the result of the second run to the specified output\n" + "To generate the one-run comparison binary, just run without\n" + "the compile-twice option\n"; + Out->os() << Buffer; + Out->keep(); + return 1; + } + } + + if (BOS) { + Out->os() << Buffer; + } } // Declare success. diff --git a/contrib/llvm/tools/lli/OrcLazyJIT.cpp b/contrib/llvm/tools/lli/OrcLazyJIT.cpp index ae276e6..4235145 100644 --- a/contrib/llvm/tools/lli/OrcLazyJIT.cpp +++ b/contrib/llvm/tools/lli/OrcLazyJIT.cpp @@ -38,26 +38,39 @@ namespace { "Dump modules to the current " "working directory. (WARNING: " "will overwrite existing files)."), - clEnumValEnd)); + clEnumValEnd), + cl::Hidden); + + cl::opt<bool> OrcInlineStubs("orc-lazy-inline-stubs", + cl::desc("Try to inline stubs"), + cl::init(true), cl::Hidden); } -OrcLazyJIT::CallbackManagerBuilder -OrcLazyJIT::createCallbackManagerBuilder(Triple T) { +std::unique_ptr<OrcLazyJIT::CompileCallbackMgr> +OrcLazyJIT::createCompileCallbackMgr(Triple T) { switch (T.getArch()) { default: return nullptr; case Triple::x86_64: { - typedef orc::JITCompileCallbackManager<IRDumpLayerT, - orc::OrcX86_64> CCMgrT; - return [](IRDumpLayerT &IRDumpLayer, RuntimeDyld::MemoryManager &MemMgr, - LLVMContext &Context) { - return llvm::make_unique<CCMgrT>(IRDumpLayer, MemMgr, Context, 0, - 64); - }; + typedef orc::LocalJITCompileCallbackManager<orc::OrcX86_64> CCMgrT; + return llvm::make_unique<CCMgrT>(0); } } } +OrcLazyJIT::IndirectStubsManagerBuilder +OrcLazyJIT::createIndirectStubsMgrBuilder(Triple T) { + switch (T.getArch()) { + default: return nullptr; + + case Triple::x86_64: + return [](){ + return llvm::make_unique< + orc::LocalIndirectStubsManager<orc::OrcX86_64>>(); + }; + } +} + OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() { switch (OrcDumpKind) { @@ -111,6 +124,12 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() { // Defined in lli.cpp. CodeGenOpt::Level getOptLevel(); + +template <typename PtrTy> +static PtrTy fromTargetAddress(orc::TargetAddress Addr) { + return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr)); +} + int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) { // Add the program's symbols into the JIT's search space. if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) { @@ -123,20 +142,31 @@ int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) { EngineBuilder EB; EB.setOptLevel(getOptLevel()); auto TM = std::unique_ptr<TargetMachine>(EB.selectTarget()); - auto &Context = getGlobalContext(); - auto CallbackMgrBuilder = - OrcLazyJIT::createCallbackManagerBuilder(Triple(TM->getTargetTriple())); + auto CompileCallbackMgr = + OrcLazyJIT::createCompileCallbackMgr(Triple(TM->getTargetTriple())); // If we couldn't build the factory function then there must not be a callback // manager for this target. Bail out. - if (!CallbackMgrBuilder) { + if (!CompileCallbackMgr) { errs() << "No callback manager available for target '" << TM->getTargetTriple().str() << "'.\n"; return 1; } + auto IndirectStubsMgrBuilder = + OrcLazyJIT::createIndirectStubsMgrBuilder(Triple(TM->getTargetTriple())); + + // If we couldn't build a stubs-manager-builder for this target then bail out. + if (!IndirectStubsMgrBuilder) { + errs() << "No indirect stubs manager available for target '" + << TM->getTargetTriple().str() << "'.\n"; + return 1; + } + // Everything looks good. Build the JIT. - OrcLazyJIT J(std::move(TM), Context, CallbackMgrBuilder); + OrcLazyJIT J(std::move(TM), std::move(CompileCallbackMgr), + std::move(IndirectStubsMgrBuilder), + OrcInlineStubs); // Add the module, look up main and run it. auto MainHandle = J.addModule(std::move(M)); @@ -148,6 +178,6 @@ int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) { } typedef int (*MainFnPtr)(int, char*[]); - auto Main = OrcLazyJIT::fromTargetAddress<MainFnPtr>(MainSym.getAddress()); + auto Main = fromTargetAddress<MainFnPtr>(MainSym.getAddress()); return Main(ArgC, ArgV); } diff --git a/contrib/llvm/tools/lli/OrcLazyJIT.h b/contrib/llvm/tools/lli/OrcLazyJIT.h index fe86adb..bb4da33 100644 --- a/contrib/llvm/tools/lli/OrcLazyJIT.h +++ b/contrib/llvm/tools/lli/OrcLazyJIT.h @@ -23,39 +23,36 @@ #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/IR/LLVMContext.h" namespace llvm { class OrcLazyJIT { public: - typedef orc::JITCompileCallbackManagerBase CompileCallbackMgr; + typedef orc::JITCompileCallbackManager CompileCallbackMgr; typedef orc::ObjectLinkingLayer<> ObjLayerT; typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT; typedef std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)> TransformFtor; typedef orc::IRTransformLayer<CompileLayerT, TransformFtor> IRDumpLayerT; typedef orc::CompileOnDemandLayer<IRDumpLayerT, CompileCallbackMgr> CODLayerT; + typedef CODLayerT::IndirectStubsManagerBuilderT + IndirectStubsManagerBuilder; typedef CODLayerT::ModuleSetHandleT ModuleHandleT; - typedef std::function< - std::unique_ptr<CompileCallbackMgr>(IRDumpLayerT&, - RuntimeDyld::MemoryManager&, - LLVMContext&)> - CallbackManagerBuilder; - - static CallbackManagerBuilder createCallbackManagerBuilder(Triple T); - - OrcLazyJIT(std::unique_ptr<TargetMachine> TM, LLVMContext &Context, - CallbackManagerBuilder &BuildCallbackMgr) - : TM(std::move(TM)), - ObjectLayer(), - CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)), - IRDumpLayer(CompileLayer, createDebugDumper()), - CCMgr(BuildCallbackMgr(IRDumpLayer, CCMgrMemMgr, Context)), - CODLayer(IRDumpLayer, *CCMgr, false), - CXXRuntimeOverrides([this](const std::string &S) { return mangle(S); }) {} + OrcLazyJIT(std::unique_ptr<TargetMachine> TM, + std::unique_ptr<CompileCallbackMgr> CCMgr, + IndirectStubsManagerBuilder IndirectStubsMgrBuilder, + bool InlineStubs) + : TM(std::move(TM)), DL(this->TM->createDataLayout()), + CCMgr(std::move(CCMgr)), + ObjectLayer(), + CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)), + IRDumpLayer(CompileLayer, createDebugDumper()), + CODLayer(IRDumpLayer, extractSingleFunction, *this->CCMgr, + std::move(IndirectStubsMgrBuilder), InlineStubs), + CXXRuntimeOverrides( + [this](const std::string &S) { return mangle(S); }) {} ~OrcLazyJIT() { // Run any destructors registered with __cxa_atexit. @@ -65,15 +62,13 @@ public: DtorRunner.runViaLayer(CODLayer); } - template <typename PtrTy> - static PtrTy fromTargetAddress(orc::TargetAddress Addr) { - return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr)); - } + static std::unique_ptr<CompileCallbackMgr> createCompileCallbackMgr(Triple T); + static IndirectStubsManagerBuilder createIndirectStubsMgrBuilder(Triple T); ModuleHandleT addModule(std::unique_ptr<Module> M) { // Attach a data-layout if one isn't already present. if (M->getDataLayout().isDefault()) - M->setDataLayout(*TM->getDataLayout()); + M->setDataLayout(DL); // Record the static constructors and destructors. We have to do this before // we hand over ownership of the module to the JIT. @@ -136,20 +131,27 @@ private: std::string MangledName; { raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, *TM->getDataLayout()); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); } return MangledName; } + static std::set<Function*> extractSingleFunction(Function &F) { + std::set<Function*> Partition; + Partition.insert(&F); + return Partition; + } + static TransformFtor createDebugDumper(); std::unique_ptr<TargetMachine> TM; + DataLayout DL; SectionMemoryManager CCMgrMemMgr; + std::unique_ptr<CompileCallbackMgr> CCMgr; ObjLayerT ObjectLayer; CompileLayerT CompileLayer; IRDumpLayerT IRDumpLayer; - std::unique_ptr<CompileCallbackMgr> CCMgr; CODLayerT CODLayer; orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides; diff --git a/contrib/llvm/tools/lli/RemoteTarget.cpp b/contrib/llvm/tools/lli/RemoteTarget.cpp index 850fdc5..95e1511 100644 --- a/contrib/llvm/tools/lli/RemoteTarget.cpp +++ b/contrib/llvm/tools/lli/RemoteTarget.cpp @@ -1,4 +1,4 @@ -//===- RemoteTarget.cpp - LLVM Remote process JIT execution --------------===// +//===- RemoteTarget.cpp - LLVM Remote process JIT execution -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -56,7 +56,7 @@ bool RemoteTarget::loadCode(uint64_t Address, const void *Data, size_t Size) { } bool RemoteTarget::executeCode(uint64_t Address, int &RetVal) { - int (*fn)(void) = (int(*)(void))Address; + int (*fn)() = (int(*)())Address; RetVal = fn(); return true; } diff --git a/contrib/llvm/tools/lli/lli.cpp b/contrib/llvm/tools/lli/lli.cpp index 057841f..9f71406 100644 --- a/contrib/llvm/tools/lli/lli.cpp +++ b/contrib/llvm/tools/lli/lli.cpp @@ -262,8 +262,7 @@ public: if (!getCacheFilename(ModuleID, CacheName)) return; if (!CacheDir.empty()) { // Create user-defined cache dir. - SmallString<128> dir(CacheName); - sys::path::remove_filename(dir); + SmallString<128> dir(sys::path::parent_path(CacheName)); sys::fs::create_directories(Twine(dir)); } std::error_code EC; @@ -422,7 +421,7 @@ int main(int argc, char **argv, char * const *envp) { // If not jitting lazily, load the whole bitcode file eagerly too. if (NoLazyCompilation) { - if (std::error_code EC = Mod->materializeAllPermanently()) { + if (std::error_code EC = Mod->materializeAll()) { errs() << argv[0] << ": bitcode didn't read correctly.\n"; errs() << "Reason: " << EC.message() << "\n"; exit(1); diff --git a/contrib/llvm/tools/llvm-ar/llvm-ar.cpp b/contrib/llvm/tools/llvm-ar/llvm-ar.cpp index 2c9668c..ef5fab6 100644 --- a/contrib/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/contrib/llvm/tools/llvm-ar/llvm-ar.cpp @@ -81,7 +81,7 @@ static cl::opt<Format> clEnumValN(GNU, "gnu", "gnu"), clEnumValN(BSD, "bsd", "bsd"), clEnumValEnd)); -std::string Options; +static std::string Options; // Provide additional help output explaining the operations and modifiers of // llvm-ar. This object instructs the CommandLine library to print the text of @@ -130,6 +130,7 @@ static bool OnlyUpdate = false; ///< 'u' modifier static bool Verbose = false; ///< 'v' modifier static bool Symtab = true; ///< 's' modifier static bool Deterministic = true; ///< 'D' and 'U' modifiers +static bool Thin = false; ///< 'T' modifier // Relative Positional Argument (for insert/move). This variable holds // the name of the archive member to which the 'a', 'b' or 'i' modifier @@ -252,6 +253,9 @@ static ArchiveOperation parseCommandLine() { case 'U': Deterministic = false; break; + case 'T': + Thin = true; + break; default: cl::PrintHelpMessage(); } @@ -308,18 +312,9 @@ static void doPrint(StringRef Name, const object::Archive::Child &C) { // Utility function for printing out the file mode when the 't' operation is in // verbose mode. static void printMode(unsigned mode) { - if (mode & 004) - outs() << "r"; - else - outs() << "-"; - if (mode & 002) - outs() << "w"; - else - outs() << "-"; - if (mode & 001) - outs() << "x"; - else - outs() << "-"; + outs() << ((mode & 004) ? "r" : "-"); + outs() << ((mode & 002) ? "w" : "-"); + outs() << ((mode & 001) ? "x" : "-"); } // Implement the 't' operation. This function prints out just @@ -334,7 +329,9 @@ static void doDisplayTable(StringRef Name, const object::Archive::Child &C) { printMode(Mode & 007); outs() << ' ' << C.getUID(); outs() << '/' << C.getGID(); - outs() << ' ' << format("%6llu", C.getSize()); + ErrorOr<uint64_t> Size = C.getSize(); + failIfError(Size.getError()); + outs() << ' ' << format("%6llu", Size.get()); outs() << ' ' << C.getLastModified().str(); outs() << ' '; } @@ -393,13 +390,14 @@ static bool shouldCreateArchive(ArchiveOperation Op) { static void performReadOperation(ArchiveOperation Operation, object::Archive *OldArchive) { - if (Operation == Extract && OldArchive->isThin()) { - errs() << "extracting from a thin archive is not supported\n"; - std::exit(1); - } + if (Operation == Extract && OldArchive->isThin()) + fail("extracting from a thin archive is not supported"); bool Filter = !Members.empty(); - for (const object::Archive::Child &C : OldArchive->children()) { + for (auto &ChildOrErr : OldArchive->children()) { + failIfError(ChildOrErr.getError()); + const object::Archive::Child &C = *ChildOrErr; + ErrorOr<StringRef> NameOrErr = C.getName(); failIfError(NameOrErr.getError()); StringRef Name = NameOrErr.get(); @@ -432,10 +430,21 @@ static void performReadOperation(ArchiveOperation Operation, std::exit(1); } -template <typename T> -void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name, - int Pos = -1) { - NewArchiveIterator NI(I, Name); +static void addMember(std::vector<NewArchiveIterator> &Members, + StringRef FileName, int Pos = -1) { + NewArchiveIterator NI(FileName); + if (Pos == -1) + Members.push_back(NI); + else + Members[Pos] = NI; +} + +static void addMember(std::vector<NewArchiveIterator> &Members, + const object::Archive::Child &M, StringRef Name, + int Pos = -1) { + if (Thin && !M.getParent()->isThin()) + fail("Cannot convert a regular archive to a thin one"); + NewArchiveIterator NI(M, Name); if (Pos == -1) Members.push_back(NI); else @@ -451,7 +460,7 @@ enum InsertAction { }; static InsertAction computeInsertAction(ArchiveOperation Operation, - object::Archive::child_iterator I, + const object::Archive::Child &Member, StringRef Name, std::vector<StringRef>::iterator &Pos) { if (Operation == QuickAppend || Members.empty()) @@ -485,7 +494,7 @@ static InsertAction computeInsertAction(ArchiveOperation Operation, // operation. sys::fs::file_status Status; failIfError(sys::fs::status(*MI, Status), *MI); - if (Status.getLastModificationTime() < I->getLastModified()) { + if (Status.getLastModificationTime() < Member.getLastModified()) { if (PosName.empty()) return IA_AddOldMember; return IA_MoveOldMember; @@ -508,7 +517,9 @@ computeNewArchiveMembers(ArchiveOperation Operation, int InsertPos = -1; StringRef PosName = sys::path::filename(RelPos); if (OldArchive) { - for (auto &Child : OldArchive->children()) { + for (auto &ChildOrErr : OldArchive->children()) { + failIfError(ChildOrErr.getError()); + auto &Child = ChildOrErr.get(); int Pos = Ret.size(); ErrorOr<StringRef> NameOrErr = Child.getName(); failIfError(NameOrErr.getError()); @@ -529,7 +540,7 @@ computeNewArchiveMembers(ArchiveOperation Operation, addMember(Ret, Child, Name); break; case IA_AddNewMeber: - addMember(Ret, *MemberI, Name); + addMember(Ret, *MemberI); break; case IA_Delete: break; @@ -537,7 +548,7 @@ computeNewArchiveMembers(ArchiveOperation Operation, addMember(Moved, Child, Name); break; case IA_MoveNewMember: - addMember(Moved, *MemberI, Name); + addMember(Moved, *MemberI); break; } if (MemberI != Members.end()) @@ -557,12 +568,10 @@ computeNewArchiveMembers(ArchiveOperation Operation, assert(unsigned(InsertPos) <= Ret.size()); Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end()); - Ret.insert(Ret.begin() + InsertPos, Members.size(), - NewArchiveIterator("", "")); + Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator("")); int Pos = InsertPos; for (auto &Member : Members) { - StringRef Name = sys::path::filename(Member); - addMember(Ret, Member, Name, Pos); + addMember(Ret, Member, Pos); ++Pos; } @@ -590,15 +599,15 @@ performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, break; } if (NewMembersP) { - std::pair<StringRef, std::error_code> Result = - writeArchive(ArchiveName, *NewMembersP, Symtab, Kind, Deterministic); + std::pair<StringRef, std::error_code> Result = writeArchive( + ArchiveName, *NewMembersP, Symtab, Kind, Deterministic, Thin); failIfError(Result.second, Result.first); return; } std::vector<NewArchiveIterator> NewMembers = computeNewArchiveMembers(Operation, OldArchive); auto Result = - writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic); + writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic, Thin); failIfError(Result.second, Result.first); } @@ -644,20 +653,13 @@ static int performOperation(ArchiveOperation Operation, ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(ArchiveName, -1, false); std::error_code EC = Buf.getError(); - if (EC && EC != errc::no_such_file_or_directory) { - errs() << ToolName << ": error opening '" << ArchiveName - << "': " << EC.message() << "!\n"; - return 1; - } + if (EC && EC != errc::no_such_file_or_directory) + fail("error opening '" + ArchiveName + "': " + EC.message() + "!"); if (!EC) { object::Archive Archive(Buf.get()->getMemBufferRef(), EC); - - if (EC) { - errs() << ToolName << ": error loading '" << ArchiveName - << "': " << EC.message() << "!\n"; - return 1; - } + failIfError(EC, + "error loading '" + ArchiveName + "': " + EC.message() + "!"); performOperation(Operation, &Archive, NewMembers); return 0; } @@ -713,7 +715,9 @@ static void runMRIScript() { failIfError(LibOrErr.getError(), "Could not parse library"); Archives.push_back(std::move(*LibOrErr)); object::Archive &Lib = *Archives.back(); - for (auto &Member : Lib.children()) { + for (auto &MemberOrErr : Lib.children()) { + failIfError(MemberOrErr.getError()); + auto &Member = MemberOrErr.get(); ErrorOr<StringRef> NameOrErr = Member.getName(); failIfError(NameOrErr.getError()); addMember(NewMembers, Member, *NameOrErr); @@ -721,7 +725,7 @@ static void runMRIScript() { break; } case MRICommand::AddMod: - addMember(NewMembers, Rest, sys::path::filename(Rest)); + addMember(NewMembers, Rest); break; case MRICommand::Create: Create = true; @@ -784,9 +788,9 @@ int main(int argc, char **argv) { " This program archives bitcode files into single libraries\n" ); - if (Stem.find("ar") != StringRef::npos) - return ar_main(); if (Stem.find("ranlib") != StringRef::npos) return ranlib_main(); + if (Stem.find("ar") != StringRef::npos) + return ar_main(); fail("Not ranlib, ar or lib!"); } diff --git a/contrib/llvm/tools/llvm-as/llvm-as.cpp b/contrib/llvm/tools/llvm-as/llvm-as.cpp index 4455d24..d4e4d8d 100644 --- a/contrib/llvm/tools/llvm-as/llvm-as.cpp +++ b/contrib/llvm/tools/llvm-as/llvm-as.cpp @@ -45,6 +45,10 @@ static cl::opt<bool> DisableOutput("disable-output", cl::desc("Disable output"), cl::init(false)); static cl::opt<bool> +EmitFunctionSummary("function-summary", cl::desc("Emit function summary index"), + cl::init(false)); + +static cl::opt<bool> DumpAsm("d", cl::desc("Print assembly as parsed"), cl::Hidden); static cl::opt<bool> @@ -77,7 +81,8 @@ static void WriteOutputFile(const Module *M) { } if (Force || !CheckBitcodeOutputToConsole(Out->os(), true)) - WriteBitcodeToFile(M, Out->os(), PreserveBitcodeUseListOrder); + WriteBitcodeToFile(M, Out->os(), PreserveBitcodeUseListOrder, + EmitFunctionSummary); // Declare success. Out->keep(); diff --git a/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 7672951..fe68689 100644 --- a/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -110,10 +110,16 @@ static const char *GetBlockName(unsigned BlockID, case bitc::TYPE_BLOCK_ID_NEW: return "TYPE_BLOCK_ID"; case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK"; case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK"; + case bitc::IDENTIFICATION_BLOCK_ID: + return "IDENTIFICATION_BLOCK_ID"; case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB"; case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK"; + case bitc::METADATA_KIND_BLOCK_ID: return "METADATA_KIND_BLOCK"; case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK"; case bitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID"; + case bitc::FUNCTION_SUMMARY_BLOCK_ID: + return "FUNCTION_SUMMARY_BLOCK"; + case bitc::MODULE_STRTAB_BLOCK_ID: return "MODULE_STRTAB_BLOCK"; } } @@ -165,6 +171,15 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, STRINGIFY_CODE(MODULE_CODE, ALIAS) STRINGIFY_CODE(MODULE_CODE, PURGEVALS) STRINGIFY_CODE(MODULE_CODE, GCNAME) + STRINGIFY_CODE(MODULE_CODE, VSTOFFSET) + STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES) + } + case bitc::IDENTIFICATION_BLOCK_ID: + switch (CodeID) { + default: + return nullptr; + STRINGIFY_CODE(IDENTIFICATION_CODE, STRING) + STRINGIFY_CODE(IDENTIFICATION_CODE, EPOCH) } case bitc::PARAMATTR_BLOCK_ID: switch (CodeID) { @@ -241,6 +256,9 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, STRINGIFY_CODE(FUNC_CODE, INST_SWITCH) STRINGIFY_CODE(FUNC_CODE, INST_INVOKE) STRINGIFY_CODE(FUNC_CODE, INST_UNREACHABLE) + STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET) + STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET) + STRINGIFY_CODE(FUNC_CODE, INST_CATCHPAD) STRINGIFY_CODE(FUNC_CODE, INST_PHI) STRINGIFY_CODE(FUNC_CODE, INST_ALLOCA) STRINGIFY_CODE(FUNC_CODE, INST_LOAD) @@ -260,6 +278,21 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, default: return nullptr; STRINGIFY_CODE(VST_CODE, ENTRY) STRINGIFY_CODE(VST_CODE, BBENTRY) + STRINGIFY_CODE(VST_CODE, FNENTRY) + STRINGIFY_CODE(VST_CODE, COMBINED_FNENTRY) + } + case bitc::MODULE_STRTAB_BLOCK_ID: + switch (CodeID) { + default: + return nullptr; + STRINGIFY_CODE(MST_CODE, ENTRY) + } + case bitc::FUNCTION_SUMMARY_BLOCK_ID: + switch (CodeID) { + default: + return nullptr; + STRINGIFY_CODE(FS_CODE, PERMODULE_ENTRY) + STRINGIFY_CODE(FS_CODE, COMBINED_ENTRY) } case bitc::METADATA_ATTACHMENT_ID: switch(CodeID) { @@ -271,7 +304,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, default:return nullptr; STRINGIFY_CODE(METADATA, STRING) STRINGIFY_CODE(METADATA, NAME) - STRINGIFY_CODE(METADATA, KIND) + STRINGIFY_CODE(METADATA, KIND) // Older bitcode has it in a MODULE_BLOCK STRINGIFY_CODE(METADATA, NODE) STRINGIFY_CODE(METADATA, VALUE) STRINGIFY_CODE(METADATA, OLD_NODE) @@ -301,6 +334,12 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, STRINGIFY_CODE(METADATA, IMPORTED_ENTITY) STRINGIFY_CODE(METADATA, MODULE) } + case bitc::METADATA_KIND_BLOCK_ID: + switch (CodeID) { + default: + return nullptr; + STRINGIFY_CODE(METADATA, KIND) + } case bitc::USELIST_BLOCK_ID: switch(CodeID) { default:return nullptr; @@ -476,14 +515,38 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, GetCodeName(Code, BlockID, *Stream.getBitStreamReader(), CurStreamType)) outs() << " codeid=" << Code; - if (Entry.ID != bitc::UNABBREV_RECORD) + const BitCodeAbbrev *Abbv = nullptr; + if (Entry.ID != bitc::UNABBREV_RECORD) { + Abbv = Stream.getAbbrev(Entry.ID); outs() << " abbrevid=" << Entry.ID; + } for (unsigned i = 0, e = Record.size(); i != e; ++i) outs() << " op" << i << "=" << (int64_t)Record[i]; outs() << "/>"; + if (Abbv) { + for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i != e; ++i) { + const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i); + if (!Op.isEncoding() || Op.getEncoding() != BitCodeAbbrevOp::Array) + continue; + assert(i + 2 == e && "Array op not second to last"); + std::string Str; + bool ArrayIsPrintable = true; + for (unsigned j = i - 1, je = Record.size(); j != je; ++j) { + if (!isprint(static_cast<unsigned char>(Record[j]))) { + ArrayIsPrintable = false; + break; + } + Str += (char)Record[j]; + } + if (ArrayIsPrintable) + outs() << " record string = '" << Str << "'"; + break; + } + } + if (Blob.data()) { outs() << " blob data = "; if (ShowBinaryBlobs) { diff --git a/contrib/llvm/tools/llvm-cov/CoverageReport.cpp b/contrib/llvm/tools/llvm-cov/CoverageReport.cpp index 497c2f8..ed01a2e 100644 --- a/contrib/llvm/tools/llvm-cov/CoverageReport.cpp +++ b/contrib/llvm/tools/llvm-cov/CoverageReport.cpp @@ -20,7 +20,7 @@ using namespace llvm; namespace { /// \brief Helper struct which prints trimmed and aligned columns. struct Column { - enum TrimKind { NoTrim, LeftTrim, RightTrim }; + enum TrimKind { NoTrim, WidthTrim, LeftTrim, RightTrim }; enum AlignmentKind { LeftAlignment, RightAlignment }; @@ -30,7 +30,7 @@ struct Column { AlignmentKind Alignment; Column(StringRef Str, unsigned Width) - : Str(Str), Width(Width), Trim(NoTrim), Alignment(LeftAlignment) {} + : Str(Str), Width(Width), Trim(WidthTrim), Alignment(LeftAlignment) {} Column &set(TrimKind Value) { Trim = Value; @@ -44,6 +44,7 @@ struct Column { void render(raw_ostream &OS) const; }; + raw_ostream &operator<<(raw_ostream &OS, const Column &Value) { Value.render(OS); return OS; @@ -64,6 +65,9 @@ void Column::render(raw_ostream &OS) const { switch (Trim) { case NoTrim: + OS << Str; + break; + case WidthTrim: OS << Str.substr(0, Width); break; case LeftTrim: @@ -84,8 +88,19 @@ static Column column(StringRef Str, unsigned Width, const T &Value) { return Column(Str, Width).set(Value); } -static const unsigned FileReportColumns[] = {25, 10, 8, 8, 10, 10}; -static const unsigned FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8}; +static size_t FileReportColumns[] = {25, 10, 8, 8, 10, 10}; +static size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8}; + +/// \brief Adjust column widths to fit long file paths and function names. +static void adjustColumnWidths(coverage::CoverageMapping *CM) { + for (StringRef Filename : CM->getUniqueSourceFiles()) { + FileReportColumns[0] = std::max(FileReportColumns[0], Filename.size()); + for (const auto &F : CM->getCoveredFunctions(Filename)) { + FunctionReportColumns[0] = + std::max(FunctionReportColumns[0], F.Name.size()); + } + } +} /// \brief Prints a horizontal divider which spans across the given columns. template <typename T, size_t N> @@ -108,8 +123,9 @@ static raw_ostream::Colors determineCoveragePercentageColor(const T &Info) { } void CoverageReport::render(const FileCoverageSummary &File, raw_ostream &OS) { - OS << column(File.Name, FileReportColumns[0], Column::LeftTrim) - << format("%*u", FileReportColumns[1], (unsigned)File.RegionCoverage.NumRegions); + OS << column(File.Name, FileReportColumns[0], Column::NoTrim) + << format("%*u", FileReportColumns[1], + (unsigned)File.RegionCoverage.NumRegions); Options.colored_ostream(OS, File.RegionCoverage.isFullyCovered() ? raw_ostream::GREEN : raw_ostream::RED) @@ -157,6 +173,7 @@ void CoverageReport::render(const FunctionCoverageSummary &Function, void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files, raw_ostream &OS) { + adjustColumnWidths(Coverage.get()); bool isFirst = true; for (StringRef Filename : Files) { if (isFirst) @@ -191,6 +208,7 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files, } void CoverageReport::renderFileReports(raw_ostream &OS) { + adjustColumnWidths(Coverage.get()); OS << column("Filename", FileReportColumns[0]) << column("Regions", FileReportColumns[1], Column::RightAlignment) << column("Miss", FileReportColumns[2], Column::RightAlignment) @@ -200,6 +218,7 @@ void CoverageReport::renderFileReports(raw_ostream &OS) { << "\n"; renderDivider(FileReportColumns, OS); OS << "\n"; + FileCoverageSummary Totals("TOTAL"); for (StringRef Filename : Coverage->getUniqueSourceFiles()) { FileCoverageSummary Summary(Filename); diff --git a/contrib/llvm/tools/llvm-cov/CoverageViewOptions.h b/contrib/llvm/tools/llvm-cov/CoverageViewOptions.h index 94b55fe..1208fad 100644 --- a/contrib/llvm/tools/llvm-cov/CoverageViewOptions.h +++ b/contrib/llvm/tools/llvm-cov/CoverageViewOptions.h @@ -24,6 +24,7 @@ struct CoverageViewOptions { bool ShowLineStatsOrRegionMarkers; bool ShowExpandedRegions; bool ShowFunctionInstantiations; + bool ShowFullFilenames; /// \brief Change the output's stream color if the colors are enabled. ColoredRawOstream colored_ostream(raw_ostream &OS, diff --git a/contrib/llvm/tools/llvm-cov/gcov.cpp b/contrib/llvm/tools/llvm-cov/gcov.cpp index 4377a50..a5343fa 100644 --- a/contrib/llvm/tools/llvm-cov/gcov.cpp +++ b/contrib/llvm/tools/llvm-cov/gcov.cpp @@ -26,7 +26,7 @@ using namespace llvm; static void reportCoverage(StringRef SourceFile, StringRef ObjectDir, const std::string &InputGCNO, const std::string &InputGCDA, bool DumpGCOV, - const GCOVOptions &Options) { + const GCOV::Options &Options) { SmallString<128> CoverageFileStem(ObjectDir); if (CoverageFileStem.empty()) { // If no directory was specified with -o, look next to the source file. @@ -143,8 +143,8 @@ int gcovMain(int argc, const char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); - GCOVOptions Options(AllBlocks, BranchProb, BranchCount, FuncSummary, - PreservePaths, UncondBranch, LongNames, NoOutput); + GCOV::Options Options(AllBlocks, BranchProb, BranchCount, FuncSummary, + PreservePaths, UncondBranch, LongNames, NoOutput); for (const auto &SourceFile : SourceFiles) reportCoverage(SourceFile, ObjectDir, InputGCNO, InputGCDA, DumpGCOV, diff --git a/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp b/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp index 4e06be9e..3dda692 100644 --- a/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp +++ b/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp @@ -40,18 +40,14 @@ cl::list<std::string> InputFilenames(cl::Positional, cl::ZeroOrMore); } // namespace opts -static int ReturnValue = EXIT_SUCCESS; - namespace llvm { -static bool error(std::error_code EC) { +static void error(std::error_code EC) { if (!EC) - return false; - - ReturnValue = EXIT_FAILURE; + return; outs() << "\nError reading file: " << EC.message() << ".\n"; outs().flush(); - return true; + exit(1); } } // namespace llvm @@ -59,38 +55,24 @@ static bool error(std::error_code EC) { static void reportError(StringRef Input, StringRef Message) { if (Input == "-") Input = "<stdin>"; - errs() << Input << ": " << Message << "\n"; errs().flush(); - ReturnValue = EXIT_FAILURE; + exit(1); } static void reportError(StringRef Input, std::error_code EC) { reportError(Input, EC.message()); } -static SmallVectorImpl<SectionRef> &getRelocSections(const ObjectFile *Obj, - const SectionRef &Sec) { - static bool MappingDone = false; - static std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap; - if (!MappingDone) { - for (const SectionRef &Section : Obj->sections()) { - section_iterator Sec2 = Section.getRelocatedSection(); - if (Sec2 != Obj->section_end()) - SectionRelocMap[*Sec2].push_back(Section); - } - MappingDone = true; - } - return SectionRelocMap[Sec]; -} +static std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap; -static bool collectRelocatedSymbols(const ObjectFile *Obj, +static void collectRelocatedSymbols(const ObjectFile *Obj, const SectionRef &Sec, uint64_t SecAddress, uint64_t SymAddress, uint64_t SymSize, StringRef *I, StringRef *E) { uint64_t SymOffset = SymAddress - SecAddress; uint64_t SymEnd = SymOffset + SymSize; - for (const SectionRef &SR : getRelocSections(Obj, Sec)) { + for (const SectionRef &SR : SectionRelocMap[Sec]) { for (const object::RelocationRef &Reloc : SR.relocations()) { if (I == E) break; @@ -98,8 +80,7 @@ static bool collectRelocatedSymbols(const ObjectFile *Obj, if (RelocSymI == Obj->symbol_end()) continue; ErrorOr<StringRef> RelocSymName = RelocSymI->getName(); - if (error(RelocSymName.getError())) - return true; + error(RelocSymName.getError()); uint64_t Offset = Reloc.getOffset(); if (Offset >= SymOffset && Offset < SymEnd) { *I = *RelocSymName; @@ -107,29 +88,26 @@ static bool collectRelocatedSymbols(const ObjectFile *Obj, } } } - return false; } -static bool collectRelocationOffsets( +static void collectRelocationOffsets( const ObjectFile *Obj, const SectionRef &Sec, uint64_t SecAddress, uint64_t SymAddress, uint64_t SymSize, StringRef SymName, std::map<std::pair<StringRef, uint64_t>, StringRef> &Collection) { uint64_t SymOffset = SymAddress - SecAddress; uint64_t SymEnd = SymOffset + SymSize; - for (const SectionRef &SR : getRelocSections(Obj, Sec)) { + for (const SectionRef &SR : SectionRelocMap[Sec]) { for (const object::RelocationRef &Reloc : SR.relocations()) { const object::symbol_iterator RelocSymI = Reloc.getSymbol(); if (RelocSymI == Obj->symbol_end()) continue; ErrorOr<StringRef> RelocSymName = RelocSymI->getName(); - if (error(RelocSymName.getError())) - return true; + error(RelocSymName.getError()); uint64_t Offset = Reloc.getOffset(); if (Offset >= SymOffset && Offset < SymEnd) Collection[std::make_pair(SymName, Offset - SymOffset)] = *RelocSymName; } } - return false; } static void dumpCXXData(const ObjectFile *Obj) { @@ -182,6 +160,13 @@ static void dumpCXXData(const ObjectFile *Obj) { std::map<std::pair<StringRef, uint64_t>, StringRef> VTTEntries; std::map<StringRef, StringRef> TINames; + SectionRelocMap.clear(); + for (const SectionRef &Section : Obj->sections()) { + section_iterator Sec2 = Section.getRelocatedSection(); + if (Sec2 != Obj->section_end()) + SectionRelocMap[*Sec2].push_back(Section); + } + uint8_t BytesInAddress = Obj->getBytesInAddress(); std::vector<std::pair<SymbolRef, uint64_t>> SymAddr = @@ -191,12 +176,11 @@ static void dumpCXXData(const ObjectFile *Obj) { object::SymbolRef Sym = P.first; uint64_t SymSize = P.second; ErrorOr<StringRef> SymNameOrErr = Sym.getName(); - if (error(SymNameOrErr.getError())) - return; + error(SymNameOrErr.getError()); StringRef SymName = *SymNameOrErr; - object::section_iterator SecI(Obj->section_begin()); - if (error(Sym.getSection(SecI))) - return; + ErrorOr<object::section_iterator> SecIOrErr = Sym.getSection(); + error(SecIOrErr.getError()); + object::section_iterator SecI = *SecIOrErr; // Skip external symbols. if (SecI == Obj->section_end()) continue; @@ -205,11 +189,9 @@ static void dumpCXXData(const ObjectFile *Obj) { if (Sec.isBSS() || Sec.isVirtual()) continue; StringRef SecContents; - if (error(Sec.getContents(SecContents))) - return; + error(Sec.getContents(SecContents)); ErrorOr<uint64_t> SymAddressOrErr = Sym.getAddress(); - if (error(SymAddressOrErr.getError())) - return; + error(SymAddressOrErr.getError()); uint64_t SymAddress = *SymAddressOrErr; uint64_t SecAddress = Sec.getAddress(); uint64_t SecSize = Sec.getSize(); @@ -236,23 +218,19 @@ static void dumpCXXData(const ObjectFile *Obj) { // Complete object locators in the MS-ABI start with '??_R4' else if (SymName.startswith("??_R4")) { CompleteObjectLocator COL; - COL.Data = ArrayRef<little32_t>( + COL.Data = makeArrayRef( reinterpret_cast<const little32_t *>(SymContents.data()), 3); StringRef *I = std::begin(COL.Symbols), *E = std::end(COL.Symbols); - if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, - E)) - return; + collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); COLs[SymName] = COL; } // Class hierarchy descriptors in the MS-ABI start with '??_R3' else if (SymName.startswith("??_R3")) { ClassHierarchyDescriptor CHD; - CHD.Data = ArrayRef<little32_t>( + CHD.Data = makeArrayRef( reinterpret_cast<const little32_t *>(SymContents.data()), 3); StringRef *I = std::begin(CHD.Symbols), *E = std::end(CHD.Symbols); - if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, - E)) - return; + collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); CHDs[SymName] = CHD; } // Class hierarchy descriptors in the MS-ABI start with '??_R2' @@ -265,12 +243,10 @@ static void dumpCXXData(const ObjectFile *Obj) { // Base class descriptors in the MS-ABI start with '??_R1' else if (SymName.startswith("??_R1")) { BaseClassDescriptor BCD; - BCD.Data = ArrayRef<little32_t>( + BCD.Data = makeArrayRef( reinterpret_cast<const little32_t *>(SymContents.data()) + 1, 5); StringRef *I = std::begin(BCD.Symbols), *E = std::end(BCD.Symbols); - if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, - E)) - return; + collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); BCDs[SymName] = BCD; } // Type descriptors in the MS-ABI start with '??_R0' @@ -283,9 +259,7 @@ static void dumpCXXData(const ObjectFile *Obj) { TD.AlwaysZero = *reinterpret_cast<const little32_t *>(DataPtr); TD.MangledName = SymContents.drop_front(BytesInAddress * 2); StringRef *I = std::begin(TD.Symbols), *E = std::end(TD.Symbols); - if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, - E)) - return; + collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); TDs[SymName] = TD; } // Throw descriptors in the MS-ABI start with '_TI' @@ -316,9 +290,7 @@ static void dumpCXXData(const ObjectFile *Obj) { CT.VirtualBaseAdjustmentOffset = DataPtr[4]; CT.Size = DataPtr[5]; StringRef *I = std::begin(CT.Symbols), *E = std::end(CT.Symbols); - if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, - E)) - return; + collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); CTs[SymName] = CT; } // Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'. @@ -510,7 +482,9 @@ static void dumpCXXData(const ObjectFile *Obj) { } static void dumpArchive(const Archive *Arc) { - for (const Archive::Child &ArcC : Arc->children()) { + for (auto &ErrorOrChild : Arc->children()) { + error(ErrorOrChild.getError()); + const Archive::Child &ArcC = *ErrorOrChild; ErrorOr<std::unique_ptr<Binary>> ChildOrErr = ArcC.getAsBinary(); if (std::error_code EC = ChildOrErr.getError()) { // Ignore non-object files. @@ -527,12 +501,6 @@ static void dumpArchive(const Archive *Arc) { } static void dumpInput(StringRef File) { - // If file isn't stdin, check that it exists. - if (File != "-" && !sys::fs::exists(File)) { - reportError(File, cxxdump_error::file_not_found); - return; - } - // Attempt to open the binary. ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(File); if (std::error_code EC = BinaryOrErr.getError()) { @@ -569,5 +537,5 @@ int main(int argc, const char *argv[]) { std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), dumpInput); - return ReturnValue; + return EXIT_SUCCESS; } diff --git a/contrib/llvm/tools/llvm-diff/DiffLog.cpp b/contrib/llvm/tools/llvm-diff/DiffLog.cpp index 24a1b08..ed86058 100644 --- a/contrib/llvm/tools/llvm-diff/DiffLog.cpp +++ b/contrib/llvm/tools/llvm-diff/DiffLog.cpp @@ -20,7 +20,8 @@ using namespace llvm; LogBuilder::~LogBuilder() { - consumer.logf(*this); + if (consumer) + consumer->logf(*this); } StringRef LogBuilder::getFormat() const { return Format; } diff --git a/contrib/llvm/tools/llvm-diff/DiffLog.h b/contrib/llvm/tools/llvm-diff/DiffLog.h index 8eb53ff..8f28461 100644 --- a/contrib/llvm/tools/llvm-diff/DiffLog.h +++ b/contrib/llvm/tools/llvm-diff/DiffLog.h @@ -27,7 +27,7 @@ namespace llvm { /// A temporary-object class for building up log messages. class LogBuilder { - Consumer &consumer; + Consumer *consumer; /// The use of a stored StringRef here is okay because /// LogBuilder should be used only as a temporary, and as a @@ -38,8 +38,12 @@ namespace llvm { SmallVector<Value*, 4> Arguments; public: - LogBuilder(Consumer &c, StringRef Format) - : consumer(c), Format(Format) {} + LogBuilder(Consumer &c, StringRef Format) : consumer(&c), Format(Format) {} + LogBuilder(LogBuilder &&L) + : consumer(L.consumer), Format(L.Format), + Arguments(std::move(L.Arguments)) { + L.consumer = nullptr; + } LogBuilder &operator<<(Value *V) { Arguments.push_back(V); diff --git a/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp b/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp index 7d379ef..456560b 100644 --- a/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp +++ b/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp @@ -599,7 +599,7 @@ void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart, TerminatorInst *RTerm = RStart->getParent()->getTerminator(); if (isa<BranchInst>(LTerm) && isa<InvokeInst>(RTerm)) { if (cast<BranchInst>(LTerm)->isConditional()) return; - BasicBlock::iterator I = LTerm; + BasicBlock::iterator I = LTerm->getIterator(); if (I == LStart->getParent()->begin()) return; --I; if (!isa<CallInst>(*I)) return; @@ -612,7 +612,7 @@ void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart, tryUnify(LTerm->getSuccessor(0), RInvoke->getNormalDest()); } else if (isa<InvokeInst>(LTerm) && isa<BranchInst>(RTerm)) { if (cast<BranchInst>(RTerm)->isConditional()) return; - BasicBlock::iterator I = RTerm; + BasicBlock::iterator I = RTerm->getIterator(); if (I == RStart->getParent()->begin()) return; --I; if (!isa<CallInst>(*I)) return; diff --git a/contrib/llvm/tools/llvm-dis/llvm-dis.cpp b/contrib/llvm/tools/llvm-dis/llvm-dis.cpp index 4b7d94d..9fdfcd4 100644 --- a/contrib/llvm/tools/llvm-dis/llvm-dis.cpp +++ b/contrib/llvm/tools/llvm-dis/llvm-dis.cpp @@ -159,7 +159,7 @@ int main(int argc, char **argv) { ErrorOr<std::unique_ptr<Module>> MOrErr = getStreamedBitcodeModule(DisplayFilename, std::move(Streamer), Context); M = std::move(*MOrErr); - M->materializeAllPermanently(); + M->materializeAll(); } else { errs() << argv[0] << ": " << ErrorMessage << '\n'; return 1; diff --git a/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index db3fcf6..eaacc7c 100644 --- a/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/RelocVisitor.h" #include "llvm/Support/CommandLine.h" @@ -22,6 +23,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" @@ -35,19 +37,19 @@ using namespace llvm; using namespace object; static cl::list<std::string> -InputFilenames(cl::Positional, cl::desc("<input object files>"), +InputFilenames(cl::Positional, cl::desc("<input object files or .dSYM bundles>"), cl::ZeroOrMore); -static cl::opt<DIDumpType> -DumpType("debug-dump", cl::init(DIDT_All), - cl::desc("Dump of debug sections:"), - cl::values( +static cl::opt<DIDumpType> DumpType( + "debug-dump", cl::init(DIDT_All), cl::desc("Dump of debug sections:"), + cl::values( clEnumValN(DIDT_All, "all", "Dump all debug sections"), clEnumValN(DIDT_Abbrev, "abbrev", ".debug_abbrev"), clEnumValN(DIDT_AbbrevDwo, "abbrev.dwo", ".debug_abbrev.dwo"), clEnumValN(DIDT_AppleNames, "apple_names", ".apple_names"), clEnumValN(DIDT_AppleTypes, "apple_types", ".apple_types"), - clEnumValN(DIDT_AppleNamespaces, "apple_namespaces", ".apple_namespaces"), + clEnumValN(DIDT_AppleNamespaces, "apple_namespaces", + ".apple_namespaces"), clEnumValN(DIDT_AppleObjC, "apple_objc", ".apple_objc"), clEnumValN(DIDT_Aranges, "aranges", ".debug_aranges"), clEnumValN(DIDT_Info, "info", ".debug_info"), @@ -59,6 +61,7 @@ DumpType("debug-dump", cl::init(DIDT_All), clEnumValN(DIDT_Loc, "loc", ".debug_loc"), clEnumValN(DIDT_LocDwo, "loc.dwo", ".debug_loc.dwo"), clEnumValN(DIDT_Frames, "frames", ".debug_frame"), + clEnumValN(DIDT_Macro, "macro", ".debug_macinfo"), clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"), clEnumValN(DIDT_Pubnames, "pubnames", ".debug_pubnames"), clEnumValN(DIDT_Pubtypes, "pubtypes", ".debug_pubtypes"), @@ -66,38 +69,79 @@ DumpType("debug-dump", cl::init(DIDT_All), clEnumValN(DIDT_GnuPubtypes, "gnu_pubtypes", ".debug_gnu_pubtypes"), clEnumValN(DIDT_Str, "str", ".debug_str"), clEnumValN(DIDT_StrDwo, "str.dwo", ".debug_str.dwo"), - clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo", ".debug_str_offsets.dwo"), - clEnumValEnd)); + clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo", + ".debug_str_offsets.dwo"), + clEnumValN(DIDT_CUIndex, "cu_index", ".debug_cu_index"), + clEnumValN(DIDT_TUIndex, "tu_index", ".debug_tu_index"), clEnumValEnd)); -static int ReturnValue = EXIT_SUCCESS; - -static bool error(StringRef Filename, std::error_code EC) { +static void error(StringRef Filename, std::error_code EC) { if (!EC) - return false; + return; errs() << Filename << ": " << EC.message() << "\n"; - ReturnValue = EXIT_FAILURE; - return true; + exit(1); +} + +static void DumpObjectFile(ObjectFile &Obj, Twine Filename) { + std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(Obj)); + + outs() << Filename.str() << ":\tfile format " << Obj.getFileFormatName() + << "\n\n"; + // Dump the complete DWARF structure. + DICtx->dump(outs(), DumpType); } static void DumpInput(StringRef Filename) { ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = MemoryBuffer::getFileOrSTDIN(Filename); - if (error(Filename, BuffOrErr.getError())) - return; + error(Filename, BuffOrErr.getError()); std::unique_ptr<MemoryBuffer> Buff = std::move(BuffOrErr.get()); - ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = - ObjectFile::createObjectFile(Buff->getMemBufferRef()); - if (error(Filename, ObjOrErr.getError())) - return; - ObjectFile &Obj = *ObjOrErr.get(); + ErrorOr<std::unique_ptr<Binary>> BinOrErr = + object::createBinary(Buff->getMemBufferRef()); + error(Filename, BinOrErr.getError()); - std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(Obj)); + if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) + DumpObjectFile(*Obj, Filename); + else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get())) + for (auto &ObjForArch : Fat->objects()) { + auto MachOOrErr = ObjForArch.getAsObjectFile(); + error(Filename, MachOOrErr.getError()); + DumpObjectFile(**MachOOrErr, + Filename + " (" + ObjForArch.getArchTypeName() + ")"); + } +} - outs() << Filename - << ":\tfile format " << Obj.getFileFormatName() << "\n\n"; - // Dump the complete DWARF structure. - DICtx->dump(outs(), DumpType); +/// If the input path is a .dSYM bundle (as created by the dsymutil tool), +/// replace it with individual entries for each of the object files inside the +/// bundle otherwise return the input path. +static std::vector<std::string> expandBundle(std::string InputPath) { + std::vector<std::string> BundlePaths; + SmallString<256> BundlePath(InputPath); + // Manually open up the bundle to avoid introducing additional dependencies. + if (sys::fs::is_directory(BundlePath) && + sys::path::extension(BundlePath) == ".dSYM") { + std::error_code EC; + sys::path::append(BundlePath, "Contents", "Resources", "DWARF"); + for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + const std::string &Path = Dir->path(); + sys::fs::file_status Status; + EC = sys::fs::status(Path, Status); + error(Path, EC); + switch (Status.type()) { + case sys::fs::file_type::regular_file: + case sys::fs::file_type::symlink_file: + case sys::fs::file_type::type_unknown: + BundlePaths.push_back(Path); + break; + default: /*ignore*/; + } + } + error(BundlePath, EC); + } + if (!BundlePaths.size()) + BundlePaths.push_back(InputPath); + return BundlePaths; } int main(int argc, char **argv) { @@ -112,7 +156,14 @@ int main(int argc, char **argv) { if (InputFilenames.size() == 0) InputFilenames.push_back("a.out"); - std::for_each(InputFilenames.begin(), InputFilenames.end(), DumpInput); + // Expand any .dSYM bundles to the individual object files contained therein. + std::vector<std::string> Objects; + for (auto F : InputFilenames) { + auto Objs = expandBundle(F); + Objects.insert(Objects.end(), Objs.begin(), Objs.end()); + } + + std::for_each(Objects.begin(), Objects.end(), DumpInput); - return ReturnValue; + return EXIT_SUCCESS; } diff --git a/contrib/llvm/tools/llvm-extract/llvm-extract.cpp b/contrib/llvm/tools/llvm-extract/llvm-extract.cpp index 936496c..1da456d 100644 --- a/contrib/llvm/tools/llvm-extract/llvm-extract.cpp +++ b/contrib/llvm/tools/llvm-extract/llvm-extract.cpp @@ -222,45 +222,42 @@ int main(int argc, char **argv) { } } - // Materialize requisite global values. - if (!DeleteFn) - for (size_t i = 0, e = GVs.size(); i != e; ++i) { - GlobalValue *GV = GVs[i]; - if (std::error_code EC = GV->materialize()) { - errs() << argv[0] << ": error reading input: " << EC.message() << "\n"; - return 1; - } + auto Materialize = [&](GlobalValue &GV) { + if (std::error_code EC = GV.materialize()) { + errs() << argv[0] << ": error reading input: " << EC.message() << "\n"; + exit(1); } - else { + }; + + // Materialize requisite global values. + if (!DeleteFn) { + for (size_t i = 0, e = GVs.size(); i != e; ++i) + Materialize(*GVs[i]); + } else { // Deleting. Materialize every GV that's *not* in GVs. SmallPtrSet<GlobalValue *, 8> GVSet(GVs.begin(), GVs.end()); - for (auto &G : M->globals()) { - if (!GVSet.count(&G)) { - if (std::error_code EC = G.materialize()) { - errs() << argv[0] << ": error reading input: " << EC.message() - << "\n"; - return 1; - } - } - } for (auto &F : *M) { - if (!GVSet.count(&F)) { - if (std::error_code EC = F.materialize()) { - errs() << argv[0] << ": error reading input: " << EC.message() - << "\n"; - return 1; - } - } + if (!GVSet.count(&F)) + Materialize(F); } } + { + std::vector<GlobalValue *> Gvs(GVs.begin(), GVs.end()); + legacy::PassManager Extract; + Extract.add(createGVExtractionPass(Gvs, DeleteFn)); + Extract.run(*M); + + // Now that we have all the GVs we want, mark the module as fully + // materialized. + // FIXME: should the GVExtractionPass handle this? + M->materializeAll(); + } + // In addition to deleting all other functions, we also want to spiff it // up a little bit. Do this now. legacy::PassManager Passes; - std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end()); - - Passes.add(createGVExtractionPass(Gvs, DeleteFn)); if (!DeleteFn) Passes.add(createGlobalDCEPass()); // Delete unreachable globals Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info diff --git a/contrib/llvm/tools/llvm-link/llvm-link.cpp b/contrib/llvm/tools/llvm-link/llvm-link.cpp index 369f347..a3238302 100644 --- a/contrib/llvm/tools/llvm-link/llvm-link.cpp +++ b/contrib/llvm/tools/llvm-link/llvm-link.cpp @@ -18,10 +18,12 @@ #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/FunctionInfo.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" +#include "llvm/Object/FunctionIndexObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" @@ -43,11 +45,34 @@ static cl::list<std::string> OverridingInputs( cl::desc( "input bitcode file which can override previously defined symbol(s)")); +// Option to simulate function importing for testing. This enables using +// llvm-link to simulate ThinLTO backend processes. +static cl::list<std::string> Imports( + "import", cl::ZeroOrMore, cl::value_desc("function:filename"), + cl::desc("Pair of function name and filename, where function should be " + "imported from bitcode in filename")); + +// Option to support testing of function importing. The function index +// must be specified in the case were we request imports via the -import +// option, as well as when compiling any module with functions that may be +// exported (imported by a different llvm-link -import invocation), to ensure +// consistent promotion and renaming of locals. +static cl::opt<std::string> FunctionIndex("functionindex", + cl::desc("Function index filename"), + cl::init(""), + cl::value_desc("filename")); + static cl::opt<std::string> OutputFilename("o", cl::desc("Override output filename"), cl::init("-"), cl::value_desc("filename")); static cl::opt<bool> +Internalize("internalize", cl::desc("Internalize linked symbols")); + +static cl::opt<bool> +OnlyNeeded("only-needed", cl::desc("Link only needed symbols")); + +static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals")); static cl::opt<bool> @@ -64,6 +89,10 @@ static cl::opt<bool> SuppressWarnings("suppress-warnings", cl::desc("Suppress all linking warnings"), cl::init(false)); +static cl::opt<bool> + PreserveModules("preserve-modules", + cl::desc("Preserve linked modules for testing")); + static cl::opt<bool> PreserveBitcodeUseListOrder( "preserve-bc-uselistorder", cl::desc("Preserve use-list order when writing LLVM bitcode."), @@ -77,16 +106,21 @@ static cl::opt<bool> PreserveAssemblyUseListOrder( // Read the specified bitcode file in and return it. This routine searches the // link path for the specified file to try to find it... // -static std::unique_ptr<Module> -loadFile(const char *argv0, const std::string &FN, LLVMContext &Context) { +static std::unique_ptr<Module> loadFile(const char *argv0, + const std::string &FN, + LLVMContext &Context, + bool MaterializeMetadata = true) { SMDiagnostic Err; if (Verbose) errs() << "Loading '" << FN << "'\n"; - std::unique_ptr<Module> Result = getLazyIRFileModule(FN, Err, Context); + std::unique_ptr<Module> Result = + getLazyIRFileModule(FN, Err, Context, !MaterializeMetadata); if (!Result) Err.print(argv0, errs()); - Result->materializeMetadata(); - UpgradeDebugInfo(*Result); + if (MaterializeMetadata) { + Result->materializeMetadata(); + UpgradeDebugInfo(*Result); + } return Result; } @@ -112,9 +146,111 @@ static void diagnosticHandler(const DiagnosticInfo &DI) { errs() << '\n'; } +static void diagnosticHandlerWithContext(const DiagnosticInfo &DI, void *C) { + diagnosticHandler(DI); +} + +/// Import any functions requested via the -import option. +static bool importFunctions(const char *argv0, LLVMContext &Context, + Linker &L) { + StringMap<std::unique_ptr<DenseMap<unsigned, MDNode *>>> + ModuleToTempMDValsMap; + for (const auto &Import : Imports) { + // Identify the requested function and its bitcode source file. + size_t Idx = Import.find(':'); + if (Idx == std::string::npos) { + errs() << "Import parameter bad format: " << Import << "\n"; + return false; + } + std::string FunctionName = Import.substr(0, Idx); + std::string FileName = Import.substr(Idx + 1, std::string::npos); + + // Load the specified source module. + std::unique_ptr<Module> M = loadFile(argv0, FileName, Context, false); + if (!M.get()) { + errs() << argv0 << ": error loading file '" << FileName << "'\n"; + return false; + } + + if (verifyModule(*M, &errs())) { + errs() << argv0 << ": " << FileName + << ": error: input module is broken!\n"; + return false; + } + + Function *F = M->getFunction(FunctionName); + if (!F) { + errs() << "Ignoring import request for non-existent function " + << FunctionName << " from " << FileName << "\n"; + continue; + } + // We cannot import weak_any functions without possibly affecting the + // order they are seen and selected by the linker, changing program + // semantics. + if (F->hasWeakAnyLinkage()) { + errs() << "Ignoring import request for weak-any function " << FunctionName + << " from " << FileName << "\n"; + continue; + } + + if (Verbose) + errs() << "Importing " << FunctionName << " from " << FileName << "\n"; + + std::unique_ptr<FunctionInfoIndex> Index; + if (!FunctionIndex.empty()) { + ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr = + llvm::getFunctionIndexForFile(FunctionIndex, diagnosticHandler); + std::error_code EC = IndexOrErr.getError(); + if (EC) { + errs() << EC.message() << '\n'; + return false; + } + Index = std::move(IndexOrErr.get()); + } + + // Save the mapping of value ids to temporary metadata created when + // importing this function. If we have already imported from this module, + // add new temporary metadata to the existing mapping. + auto &TempMDVals = ModuleToTempMDValsMap[FileName]; + if (!TempMDVals) + TempMDVals = llvm::make_unique<DenseMap<unsigned, MDNode *>>(); + + // Link in the specified function. + DenseSet<const GlobalValue *> FunctionsToImport; + FunctionsToImport.insert(F); + if (L.linkInModule(std::move(M), Linker::Flags::None, Index.get(), + &FunctionsToImport, TempMDVals.get())) + return false; + } + + // Now link in metadata for all modules from which we imported functions. + for (StringMapEntry<std::unique_ptr<DenseMap<unsigned, MDNode *>>> &SME : + ModuleToTempMDValsMap) { + // Load the specified source module. + std::unique_ptr<Module> M = loadFile(argv0, SME.getKey(), Context, true); + if (!M.get()) { + errs() << argv0 << ": error loading file '" << SME.getKey() << "'\n"; + return false; + } + + if (verifyModule(*M, &errs())) { + errs() << argv0 << ": " << SME.getKey() + << ": error: input module is broken!\n"; + return false; + } + + // Link in all necessary metadata from this module. + if (L.linkInMetadata(*M, SME.getValue().get())) + return false; + } + return true; +} + static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L, const cl::list<std::string> &Files, - bool OverrideDuplicateSymbols) { + unsigned Flags) { + // Filter out flags that don't apply to the first file we load. + unsigned ApplicableFlags = Flags & Linker::Flags::OverrideFromSrc; for (const auto &File : Files) { std::unique_ptr<Module> M = loadFile(argv0, File, Context); if (!M.get()) { @@ -127,11 +263,36 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L, return false; } + // If a function index is supplied, load it so linkInModule can treat + // local functions/variables as exported and promote if necessary. + std::unique_ptr<FunctionInfoIndex> Index; + if (!FunctionIndex.empty()) { + ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr = + llvm::getFunctionIndexForFile(FunctionIndex, diagnosticHandler); + std::error_code EC = IndexOrErr.getError(); + if (EC) { + errs() << EC.message() << '\n'; + return false; + } + Index = std::move(IndexOrErr.get()); + } + if (Verbose) errs() << "Linking in '" << File << "'\n"; - if (L.linkInModule(M.get(), OverrideDuplicateSymbols)) + if (L.linkInModule(std::move(M), ApplicableFlags, Index.get())) return false; + // All linker flags apply to linking of subsequent files. + ApplicableFlags = Flags; + + // If requested for testing, preserve modules by releasing them from + // the unique_ptr before the are freed. This can help catch any + // cross-module references from e.g. unneeded metadata references + // that aren't properly set to null but instead mapped to the source + // module version. The bitcode writer will assert if it finds any such + // cross-module references. + if (PreserveModules) + M.release(); } return true; @@ -143,18 +304,31 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); LLVMContext &Context = getGlobalContext(); + Context.setDiagnosticHandler(diagnosticHandlerWithContext, nullptr, true); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm linker\n"); auto Composite = make_unique<Module>("llvm-link", Context); - Linker L(Composite.get(), diagnosticHandler); + Linker L(*Composite); + + unsigned Flags = Linker::Flags::None; + if (Internalize) + Flags |= Linker::Flags::InternalizeLinkedSymbols; + if (OnlyNeeded) + Flags |= Linker::Flags::LinkOnlyNeeded; // First add all the regular input files - if (!linkFiles(argv[0], Context, L, InputFilenames, false)) + if (!linkFiles(argv[0], Context, L, InputFilenames, Flags)) return 1; // Next the -override ones. - if (!linkFiles(argv[0], Context, L, OverridingInputs, true)) + if (!linkFiles(argv[0], Context, L, OverridingInputs, + Flags | Linker::Flags::OverrideFromSrc)) + return 1; + + // Import any functions requested via -import + if (!importFunctions(argv[0], Context, L)) return 1; if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite; diff --git a/contrib/llvm/tools/llvm-lto/llvm-lto.cpp b/contrib/llvm/tools/llvm-lto/llvm-lto.cpp index 0821898..4bc6922 100644 --- a/contrib/llvm/tools/llvm-lto/llvm-lto.cpp +++ b/contrib/llvm/tools/llvm-lto/llvm-lto.cpp @@ -13,16 +13,22 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringSet.h" +#include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/CommandFlags.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/LTO/LTOCodeGenerator.h" #include "llvm/LTO/LTOModule.h" +#include "llvm/Object/FunctionIndexObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" +#include <list> using namespace llvm; @@ -34,6 +40,10 @@ OptLevel("O", cl::ZeroOrMore, cl::init('2')); +static cl::opt<bool> DisableVerify( + "disable-verify", cl::init(false), + cl::desc("Do not run the verifier during the optimization pipeline")); + static cl::opt<bool> DisableInline("disable-inlining", cl::init(false), cl::desc("Do not run the inliner pass")); @@ -50,6 +60,14 @@ static cl::opt<bool> UseDiagnosticHandler("use-diagnostic-handler", cl::init(false), cl::desc("Use a diagnostic handler to test the handler interface")); +static cl::opt<bool> + ThinLTO("thinlto", cl::init(false), + cl::desc("Only write combined global index for ThinLTO backends")); + +static cl::opt<bool> +SaveModuleFile("save-merged-module", cl::init(false), + cl::desc("Write merged LTO module to file before CodeGen")); + static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore, cl::desc("<input bitcode files>")); @@ -77,6 +95,9 @@ static cl::opt<bool> SetMergedModule( "set-merged-module", cl::init(false), cl::desc("Use the first input module as the merged module")); +static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1), + cl::desc("Number of backend threads")); + namespace { struct ModuleInfo { std::vector<bool> CanBeHidden; @@ -85,6 +106,7 @@ struct ModuleInfo { static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity, const char *Msg, void *) { + errs() << "llvm-lto: "; switch (Severity) { case LTO_DS_NOTE: errs() << "note: "; @@ -102,18 +124,68 @@ static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity, errs() << Msg << "\n"; } +static std::string CurrentActivity; +static void diagnosticHandler(const DiagnosticInfo &DI) { + raw_ostream &OS = errs(); + OS << "llvm-lto: "; + 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; + } + if (!CurrentActivity.empty()) + OS << ' ' << CurrentActivity; + OS << ": "; + + DiagnosticPrinterRawOStream DP(OS); + DI.print(DP); + OS << '\n'; + + if (DI.getSeverity() == DS_Error) + exit(1); +} + +static void diagnosticHandlerWithContenxt(const DiagnosticInfo &DI, + void *Context) { + diagnosticHandler(DI); +} + +static void error(const Twine &Msg) { + errs() << "llvm-lto: " << Msg << '\n'; + exit(1); +} + +static void error(std::error_code EC, const Twine &Prefix) { + if (EC) + error(Prefix + ": " + EC.message()); +} + +template <typename T> +static void error(const ErrorOr<T> &V, const Twine &Prefix) { + error(V.getError(), Prefix); +} + static std::unique_ptr<LTOModule> getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer, - const TargetOptions &Options, std::string &Error) { + const TargetOptions &Options) { ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getFile(Path); - if (std::error_code EC = BufferOrErr.getError()) { - Error = EC.message(); - return nullptr; - } + error(BufferOrErr, "error loading file '" + Path + "'"); Buffer = std::move(BufferOrErr.get()); - return std::unique_ptr<LTOModule>(LTOModule::createInLocalContext( - Buffer->getBufferStart(), Buffer->getBufferSize(), Options, Error, Path)); + CurrentActivity = ("loading file '" + Path + "'").str(); + ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext( + Buffer->getBufferStart(), Buffer->getBufferSize(), Options, Path); + CurrentActivity = ""; + return std::move(*Ret); } /// \brief List symbols in each IR file. @@ -122,24 +194,44 @@ getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer, /// functionality that's exposed by the C API to list symbols. Moreover, this /// provides testing coverage for modules that have been created in their own /// contexts. -static int listSymbols(StringRef Command, const TargetOptions &Options) { +static void listSymbols(const TargetOptions &Options) { for (auto &Filename : InputFilenames) { - std::string Error; std::unique_ptr<MemoryBuffer> Buffer; std::unique_ptr<LTOModule> Module = - getLocalLTOModule(Filename, Buffer, Options, Error); - if (!Module) { - errs() << Command << ": error loading file '" << Filename - << "': " << Error << "\n"; - return 1; - } + getLocalLTOModule(Filename, Buffer, Options); // List the symbols. outs() << Filename << ":\n"; for (int I = 0, E = Module->getSymbolCount(); I != E; ++I) outs() << Module->getSymbolName(I) << "\n"; } - return 0; +} + +/// Create a combined index file from the input IR files and write it. +/// +/// This is meant to enable testing of ThinLTO combined index generation, +/// currently available via the gold plugin via -thinlto. +static void createCombinedFunctionIndex() { + FunctionInfoIndex CombinedIndex; + uint64_t NextModuleId = 0; + for (auto &Filename : InputFilenames) { + CurrentActivity = "loading file '" + Filename + "'"; + ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr = + llvm::getFunctionIndexForFile(Filename, diagnosticHandler); + std::unique_ptr<FunctionInfoIndex> Index = std::move(IndexOrErr.get()); + CurrentActivity = ""; + // Skip files without a function summary. + if (!Index) + continue; + CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId); + } + std::error_code EC; + assert(!OutputFilename.empty()); + raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC, + sys::fs::OpenFlags::F_None); + error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'"); + WriteFunctionSummaryToFile(CombinedIndex, OS); + OS.close(); } int main(int argc, char **argv) { @@ -150,10 +242,8 @@ int main(int argc, char **argv) { llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n"); - if (OptLevel < '0' || OptLevel > '3') { - errs() << argv[0] << ": optimization level must be between 0 and 3\n"; - return 1; - } + if (OptLevel < '0' || OptLevel > '3') + error("optimization level must be between 0 and 3"); // Initialize the configured targets. InitializeAllTargets(); @@ -164,29 +254,27 @@ int main(int argc, char **argv) { // set up the TargetOptions for the machine TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); - if (ListSymbolsOnly) - return listSymbols(argv[0], Options); + if (ListSymbolsOnly) { + listSymbols(Options); + return 0; + } + + if (ThinLTO) { + createCombinedFunctionIndex(); + return 0; + } unsigned BaseArg = 0; - LTOCodeGenerator CodeGen; + LLVMContext Context; + Context.setDiagnosticHandler(diagnosticHandlerWithContenxt, nullptr, true); + + LTOCodeGenerator CodeGen(Context); if (UseDiagnosticHandler) CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr); - switch (RelocModel) { - case Reloc::Static: - CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_STATIC); - break; - case Reloc::PIC_: - CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC); - break; - case Reloc::DynamicNoPIC: - CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC); - break; - default: - CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DEFAULT); - } + CodeGen.setCodePICModel(RelocModel); CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF); CodeGen.setTargetOptions(Options); @@ -198,38 +286,33 @@ int main(int argc, char **argv) { std::vector<std::string> KeptDSOSyms; for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) { - std::string error; - std::unique_ptr<LTOModule> Module( - LTOModule::createFromFile(InputFilenames[i].c_str(), Options, error)); - if (!error.empty()) { - errs() << argv[0] << ": error loading file '" << InputFilenames[i] - << "': " << error << "\n"; - return 1; - } + CurrentActivity = "loading file '" + InputFilenames[i] + "'"; + ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr = + LTOModule::createFromFile(Context, InputFilenames[i].c_str(), Options); + std::unique_ptr<LTOModule> &Module = *ModuleOrErr; + CurrentActivity = ""; - LTOModule *LTOMod = Module.get(); + unsigned NumSyms = Module->getSymbolCount(); + for (unsigned I = 0; I < NumSyms; ++I) { + StringRef Name = Module->getSymbolName(I); + if (!DSOSymbolsSet.count(Name)) + continue; + lto_symbol_attributes Attrs = Module->getSymbolAttributes(I); + unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK; + if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN) + KeptDSOSyms.push_back(Name); + } // We use the first input module as the destination module when // SetMergedModule is true. if (SetMergedModule && i == BaseArg) { // Transfer ownership to the code generator. - CodeGen.setModule(Module.release()); + CodeGen.setModule(std::move(Module)); } else if (!CodeGen.addModule(Module.get())) { // Print a message here so that we know addModule() did not abort. errs() << argv[0] << ": error adding file '" << InputFilenames[i] << "'\n"; return 1; } - - unsigned NumSyms = LTOMod->getSymbolCount(); - for (unsigned I = 0; I < NumSyms; ++I) { - StringRef Name = LTOMod->getSymbolName(I); - if (!DSOSymbolsSet.count(Name)) - continue; - lto_symbol_attributes Attrs = LTOMod->getSymbolAttributes(I); - unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK; - if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN) - KeptDSOSyms.push_back(Name); - } } // Add all the exported symbols to the table of symbols to preserve. @@ -255,34 +338,68 @@ int main(int argc, char **argv) { if (!attrs.empty()) CodeGen.setAttr(attrs.c_str()); + if (FileType.getNumOccurrences()) + CodeGen.setFileType(FileType); + if (!OutputFilename.empty()) { - std::string ErrorInfo; - std::unique_ptr<MemoryBuffer> Code = CodeGen.compile( - DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, ErrorInfo); - if (!Code) { - errs() << argv[0] - << ": error compiling the code: " << ErrorInfo << "\n"; + if (!CodeGen.optimize(DisableVerify, DisableInline, DisableGVNLoadPRE, + DisableLTOVectorization)) { + // Diagnostic messages should have been printed by the handler. + errs() << argv[0] << ": error optimizing the code\n"; return 1; } - std::error_code EC; - raw_fd_ostream FileStream(OutputFilename, EC, sys::fs::F_None); - if (EC) { - errs() << argv[0] << ": error opening the file '" << OutputFilename - << "': " << EC.message() << "\n"; + if (SaveModuleFile) { + std::string ModuleFilename = OutputFilename; + ModuleFilename += ".merged.bc"; + std::string ErrMsg; + + if (!CodeGen.writeMergedModules(ModuleFilename.c_str())) { + errs() << argv[0] << ": writing merged module failed.\n"; + return 1; + } + } + + std::list<tool_output_file> OSs; + std::vector<raw_pwrite_stream *> OSPtrs; + for (unsigned I = 0; I != Parallelism; ++I) { + std::string PartFilename = OutputFilename; + if (Parallelism != 1) + PartFilename += "." + utostr(I); + std::error_code EC; + OSs.emplace_back(PartFilename, EC, sys::fs::F_None); + if (EC) { + errs() << argv[0] << ": error opening the file '" << PartFilename + << "': " << EC.message() << "\n"; + return 1; + } + OSPtrs.push_back(&OSs.back().os()); + } + + if (!CodeGen.compileOptimized(OSPtrs)) { + // Diagnostic messages should have been printed by the handler. + errs() << argv[0] << ": error compiling the code\n"; return 1; } - FileStream.write(Code->getBufferStart(), Code->getBufferSize()); + for (tool_output_file &OS : OSs) + OS.keep(); } else { - std::string ErrorInfo; + if (Parallelism != 1) { + errs() << argv[0] << ": -j must be specified together with -o\n"; + return 1; + } + + if (SaveModuleFile) { + errs() << argv[0] << ": -save-merged-module must be specified with -o\n"; + return 1; + } + const char *OutputName = nullptr; - if (!CodeGen.compile_to_file(&OutputName, DisableInline, - DisableGVNLoadPRE, DisableLTOVectorization, - ErrorInfo)) { - errs() << argv[0] - << ": error compiling the code: " << ErrorInfo - << "\n"; + if (!CodeGen.compile_to_file(&OutputName, DisableVerify, DisableInline, + DisableGVNLoadPRE, DisableLTOVectorization)) { + // Diagnostic messages should have been printed by the handler. + errs() << argv[0] << ": error compiling the code\n"; return 1; } diff --git a/contrib/llvm/tools/llvm-mc/llvm-mc.cpp b/contrib/llvm/tools/llvm-mc/llvm-mc.cpp index 6ecdb2e..96e3f7c 100644 --- a/contrib/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/contrib/llvm/tools/llvm-mc/llvm-mc.cpp @@ -1,4 +1,4 @@ -//===-- llvm-mc.cpp - Machine Code Hacking Driver -------------------------===// +//===-- llvm-mc.cpp - Machine Code Hacking Driver ---------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -39,6 +39,7 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" + using namespace llvm; static cl::opt<std::string> @@ -234,7 +235,7 @@ static void setDwarfDebugFlags(int argc, char **argv) { } static std::string DwarfDebugProducer; -static void setDwarfDebugProducer(void) { +static void setDwarfDebugProducer() { if(!getenv("DEBUG_PRODUCER")) return; DwarfDebugProducer += getenv("DEBUG_PRODUCER"); @@ -398,7 +399,7 @@ int main(int argc, char **argv) { ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr = MemoryBuffer::getFileOrSTDIN(InputFilename); if (std::error_code EC = BufferPtr.getError()) { - errs() << ProgName << ": " << EC.message() << '\n'; + errs() << InputFilename << ": " << EC.message() << '\n'; return 1; } MemoryBuffer *Buffer = BufferPtr->get(); @@ -510,9 +511,10 @@ int main(int argc, char **argv) { MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); - Str.reset(TheTarget->createMCObjectStreamer(TheTriple, Ctx, *MAB, *OS, CE, - *STI, RelaxAll, - /*DWARFMustBeAtTheEnd*/ false)); + Str.reset(TheTarget->createMCObjectStreamer( + TheTriple, Ctx, *MAB, *OS, CE, *STI, MCOptions.MCRelaxAll, + MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false)); if (NoExecStack) Str->InitSections(true); } diff --git a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp index e7ee312..b812233 100644 --- a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ELFObjectFile.h" @@ -44,6 +45,7 @@ #include <cstring> #include <system_error> #include <vector> + using namespace llvm; using namespace object; @@ -64,27 +66,30 @@ cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"), cl::opt<bool> UndefinedOnly("undefined-only", cl::desc("Show only undefined symbols")); cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"), - cl::aliasopt(UndefinedOnly)); + cl::aliasopt(UndefinedOnly), cl::Grouping); cl::opt<bool> DynamicSyms("dynamic", cl::desc("Display the dynamic symbols instead " "of normal symbols.")); cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"), - cl::aliasopt(DynamicSyms)); + cl::aliasopt(DynamicSyms), cl::Grouping); cl::opt<bool> DefinedOnly("defined-only", cl::desc("Show only defined symbols")); cl::alias DefinedOnly2("U", cl::desc("Alias for --defined-only"), - cl::aliasopt(DefinedOnly)); + cl::aliasopt(DefinedOnly), cl::Grouping); cl::opt<bool> ExternalOnly("extern-only", cl::desc("Show only external symbols")); cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"), - cl::aliasopt(ExternalOnly)); + cl::aliasopt(ExternalOnly), cl::Grouping); -cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd")); -cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix")); -cl::opt<bool> DarwinFormat("m", cl::desc("Alias for --format=darwin")); +cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"), + cl::Grouping); +cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix"), + cl::Grouping); +cl::opt<bool> DarwinFormat("m", cl::desc("Alias for --format=darwin"), + cl::Grouping); static cl::list<std::string> ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), @@ -96,32 +101,33 @@ cl::opt<bool> PrintFileName( cl::desc("Precede each symbol with the object file it came from")); cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"), - cl::aliasopt(PrintFileName)); + cl::aliasopt(PrintFileName), cl::Grouping); cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"), - cl::aliasopt(PrintFileName)); + cl::aliasopt(PrintFileName), cl::Grouping); cl::opt<bool> DebugSyms("debug-syms", cl::desc("Show all symbols, even debugger only")); cl::alias DebugSymsa("a", cl::desc("Alias for --debug-syms"), - cl::aliasopt(DebugSyms)); + cl::aliasopt(DebugSyms), cl::Grouping); cl::opt<bool> NumericSort("numeric-sort", cl::desc("Sort symbols by address")); cl::alias NumericSortn("n", cl::desc("Alias for --numeric-sort"), - cl::aliasopt(NumericSort)); + cl::aliasopt(NumericSort), cl::Grouping); cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"), - cl::aliasopt(NumericSort)); + cl::aliasopt(NumericSort), cl::Grouping); cl::opt<bool> NoSort("no-sort", cl::desc("Show symbols in order encountered")); -cl::alias NoSortp("p", cl::desc("Alias for --no-sort"), cl::aliasopt(NoSort)); +cl::alias NoSortp("p", cl::desc("Alias for --no-sort"), cl::aliasopt(NoSort), + cl::Grouping); cl::opt<bool> ReverseSort("reverse-sort", cl::desc("Sort in reverse order")); cl::alias ReverseSortr("r", cl::desc("Alias for --reverse-sort"), - cl::aliasopt(ReverseSort)); + cl::aliasopt(ReverseSort), cl::Grouping); cl::opt<bool> PrintSize("print-size", cl::desc("Show symbol size instead of address")); cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"), - cl::aliasopt(PrintSize)); + cl::aliasopt(PrintSize), cl::Grouping); cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size")); @@ -130,12 +136,12 @@ cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden, cl::opt<bool> ArchiveMap("print-armap", cl::desc("Print the archive map")); cl::alias ArchiveMaps("M", cl::desc("Alias for --print-armap"), - cl::aliasopt(ArchiveMap)); + cl::aliasopt(ArchiveMap), cl::Grouping); cl::opt<bool> JustSymbolName("just-symbol-name", cl::desc("Print just the symbol's name")); cl::alias JustSymbolNames("j", cl::desc("Alias for --just-symbol-name"), - cl::aliasopt(JustSymbolName)); + cl::aliasopt(JustSymbolName), cl::Grouping); // FIXME: This option takes exactly two strings and should be allowed anywhere // on the command line. Such that "llvm-nm -s __TEXT __text foo.o" would work. @@ -147,7 +153,7 @@ cl::list<std::string> SegSect("s", cl::Positional, cl::ZeroOrMore, "and section name, Mach-O only")); cl::opt<bool> FormatMachOasHex("x", cl::desc("Print symbol entry in hex, " - "Mach-O only")); + "Mach-O only"), cl::Grouping); cl::opt<bool> NoLLVMBitcode("no-llvm-bc", cl::desc("Disable LLVM bitcode reader")); @@ -159,7 +165,7 @@ bool MultipleFiles = false; bool HadError = false; std::string ToolName; -} +} // anonymous namespace static void error(Twine Message, Twine Path = Twine()) { HadError = true; @@ -182,7 +188,7 @@ struct NMSymbol { StringRef Name; BasicSymbolRef Sym; }; -} +} // anonymous namespace static bool compareSymbolAddress(const NMSymbol &A, const NMSymbol &B) { bool ADefined = !(A.Sym.getFlags() & SymbolRef::SF_Undefined); @@ -202,8 +208,14 @@ static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) { } static char isSymbolList64Bit(SymbolicFile &Obj) { - if (isa<IRObjectFile>(Obj)) - return false; + if (isa<IRObjectFile>(Obj)) { + IRObjectFile *IRobj = dyn_cast<IRObjectFile>(&Obj); + Module &M = IRobj->getModule(); + if (M.getTargetTriple().empty()) + return false; + Triple T(M.getTargetTriple()); + return T.isArch64Bit(); + } if (isa<COFFObjectFile>(Obj)) return false; if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj)) @@ -215,54 +227,80 @@ static StringRef CurrentFilename; typedef std::vector<NMSymbol> SymbolListT; static SymbolListT SymbolList; +static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I); + // darwinPrintSymbol() is used to print a symbol from a Mach-O file when the // the OutputFormat is darwin or we are printing Mach-O symbols in hex. For // the darwin format it produces the same output as darwin's nm(1) -m output // and when printing Mach-O symbols in hex it produces the same output as // darwin's nm(1) -x format. -static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I, - char *SymbolAddrStr, const char *printBlanks) { +static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I, + char *SymbolAddrStr, const char *printBlanks, + const char *printDashes, const char *printFormat) { MachO::mach_header H; MachO::mach_header_64 H_64; - uint32_t Filetype, Flags; - MachO::nlist_64 STE_64; - MachO::nlist STE; - uint8_t NType; - uint8_t NSect; - uint16_t NDesc; - uint32_t NStrx; - uint64_t NValue; - DataRefImpl SymDRI = I->Sym.getRawDataRefImpl(); - if (MachO->is64Bit()) { - H_64 = MachO->MachOObjectFile::getHeader64(); - Filetype = H_64.filetype; - Flags = H_64.flags; - STE_64 = MachO->getSymbol64TableEntry(SymDRI); - NType = STE_64.n_type; - NSect = STE_64.n_sect; - NDesc = STE_64.n_desc; - NStrx = STE_64.n_strx; - NValue = STE_64.n_value; + uint32_t Filetype = MachO::MH_OBJECT; + uint32_t Flags = 0; + uint8_t NType = 0; + uint8_t NSect = 0; + uint16_t NDesc = 0; + uint32_t NStrx = 0; + uint64_t NValue = 0; + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj); + if (Obj.isIR()) { + uint32_t SymFlags = I->Sym.getFlags(); + if (SymFlags & SymbolRef::SF_Global) + NType |= MachO::N_EXT; + if (SymFlags & SymbolRef::SF_Hidden) + NType |= MachO::N_PEXT; + if (SymFlags & SymbolRef::SF_Undefined) + NType |= MachO::N_EXT | MachO::N_UNDF; + else { + // Here we have a symbol definition. So to fake out a section name we + // use 1, 2 and 3 for section numbers. See below where they are used to + // print out fake section names. + NType |= MachO::N_SECT; + if(SymFlags & SymbolRef::SF_Const) + NSect = 3; + else { + IRObjectFile *IRobj = dyn_cast<IRObjectFile>(&Obj); + char c = getSymbolNMTypeChar(*IRobj, I->Sym); + if (c == 't') + NSect = 1; + else + NSect = 2; + } + } + if (SymFlags & SymbolRef::SF_Weak) + NDesc |= MachO::N_WEAK_DEF; } else { - H = MachO->MachOObjectFile::getHeader(); - Filetype = H.filetype; - Flags = H.flags; - STE = MachO->getSymbolTableEntry(SymDRI); - NType = STE.n_type; - NSect = STE.n_sect; - NDesc = STE.n_desc; - NStrx = STE.n_strx; - NValue = STE.n_value; + DataRefImpl SymDRI = I->Sym.getRawDataRefImpl(); + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + Filetype = H_64.filetype; + Flags = H_64.flags; + MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI); + NType = STE_64.n_type; + NSect = STE_64.n_sect; + NDesc = STE_64.n_desc; + NStrx = STE_64.n_strx; + NValue = STE_64.n_value; + } else { + H = MachO->MachOObjectFile::getHeader(); + Filetype = H.filetype; + Flags = H.flags; + MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI); + NType = STE.n_type; + NSect = STE.n_sect; + NDesc = STE.n_desc; + NStrx = STE.n_strx; + NValue = STE.n_value; + } } // If we are printing Mach-O symbols in hex do that and return. if (FormatMachOasHex) { char Str[18] = ""; - const char *printFormat; - if (MachO->is64Bit()) - printFormat = "%016" PRIx64; - else - printFormat = "%08" PRIx64; format(printFormat, NValue).print(Str, sizeof(Str)); outs() << Str << ' '; format("%02x", NType).print(Str, sizeof(Str)); @@ -280,6 +318,8 @@ static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I, if (PrintAddress) { if ((NType & MachO::N_TYPE) == MachO::N_INDR) strcpy(SymbolAddrStr, printBlanks); + if (Obj.isIR() && (NType & MachO::N_TYPE) == MachO::N_TYPE) + strcpy(SymbolAddrStr, printDashes); outs() << SymbolAddrStr << ' '; } @@ -314,8 +354,20 @@ static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I, outs() << "(indirect) "; break; case MachO::N_SECT: { - section_iterator Sec = MachO->section_end(); - MachO->getSymbolSection(I->Sym.getRawDataRefImpl(), Sec); + if (Obj.isIR()) { + // For llvm bitcode files print out a fake section name using the values + // use 1, 2 and 3 for section numbers as set above. + if (NSect == 1) + outs() << "(LTO,CODE) "; + else if (NSect == 2) + outs() << "(LTO,DATA) "; + else if (NSect == 3) + outs() << "(LTO,RODATA) "; + else + outs() << "(?,?) "; + break; + } + section_iterator Sec = *MachO->getSymbolSection(I->Sym.getRawDataRefImpl()); DataRefImpl Ref = Sec->getRawDataRefImpl(); StringRef SectionName; MachO->getSectionName(Ref, SectionName); @@ -374,7 +426,8 @@ static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I, if ((NType & MachO::N_TYPE) == MachO::N_INDR) { outs() << I->Name << " (for "; StringRef IndirectName; - if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName)) + if (!MachO || + MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName)) outs() << "?)"; else outs() << IndirectName << ")"; @@ -392,7 +445,8 @@ static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I, outs() << " (dynamically looked up)"; else { StringRef LibraryName; - if (MachO->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName)) + if (!MachO || + MachO->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName)) outs() << " (from bad library ordinal " << LibraryOrdinal << ")"; else outs() << " (from " << LibraryName << ")"; @@ -440,13 +494,14 @@ static const struct DarwinStabName DarwinStabNames[] = { {MachO::N_ECOMM, "ECOMM"}, {MachO::N_ECOML, "ECOML"}, {MachO::N_LENG, "LENG"}, - {0, 0}}; + {0, nullptr}}; + static const char *getDarwinStabString(uint8_t NType) { for (unsigned i = 0; DarwinStabNames[i].Name; i++) { if (DarwinStabNames[i].NType == NType) return DarwinStabNames[i].Name; } - return 0; + return nullptr; } // darwinPrintStab() prints the n_sect, n_desc along with a symbolic name of @@ -511,12 +566,14 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, } } - const char *printBlanks, *printFormat; + const char *printBlanks, *printDashes, *printFormat; if (isSymbolList64Bit(Obj)) { printBlanks = " "; + printDashes = "----------------"; printFormat = "%016" PRIx64; } else { printBlanks = " "; + printDashes = "--------"; printFormat = "%08" PRIx64; } @@ -528,6 +585,9 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, continue; if (Undefined && DefinedOnly) continue; + bool Global = SymFlags & SymbolRef::SF_Global; + if (!Global && ExternalOnly) + continue; if (SizeSort && !PrintAddress) continue; if (PrintFileName) { @@ -537,7 +597,8 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, outs() << ArchiveName << ":"; outs() << CurrentFilename << ": "; } - if (JustSymbolName || (UndefinedOnly && isa<MachOObjectFile>(Obj))) { + if ((JustSymbolName || (UndefinedOnly && isa<MachOObjectFile>(Obj) && + OutputFormat != darwin)) && OutputFormat != posix) { outs() << I->Name << "\n"; continue; } @@ -550,9 +611,13 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, if (OutputFormat == sysv) strcpy(SymbolSizeStr, printBlanks); - if (I->TypeChar != 'U') - format(printFormat, I->Address) + if (I->TypeChar != 'U') { + if (Obj.isIR()) + strcpy(SymbolAddrStr, printDashes); + else + format(printFormat, I->Address) .print(SymbolAddrStr, sizeof(SymbolAddrStr)); + } format(printFormat, I->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr)); // If OutputFormat is darwin or we are printing Mach-O symbols in hex and @@ -561,11 +626,15 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, // printing Mach-O symbols in hex and not a Mach-O object fall back to // OutputFormat bsd (see below). MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj); - if ((OutputFormat == darwin || FormatMachOasHex) && MachO) { - darwinPrintSymbol(MachO, I, SymbolAddrStr, printBlanks); + if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) { + darwinPrintSymbol(Obj, I, SymbolAddrStr, printBlanks, printDashes, + printFormat); } else if (OutputFormat == posix) { - outs() << I->Name << " " << I->TypeChar << " " << SymbolAddrStr - << SymbolSizeStr << "\n"; + outs() << I->Name << " " << I->TypeChar << " "; + if (MachO) + outs() << I->Address << " " << "0" /* SymbolSizeStr */ << "\n"; + else + outs() << SymbolAddrStr << SymbolSizeStr << "\n"; } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) { if (PrintAddress) outs() << SymbolAddrStr << ' '; @@ -594,10 +663,11 @@ static char getSymbolNMTypeChar(ELFObjectFileBase &Obj, // OK, this is ELF elf_symbol_iterator SymI(I); - elf_section_iterator SecI = Obj.section_end(); - if (error(SymI->getSection(SecI))) + ErrorOr<elf_section_iterator> SecIOrErr = SymI->getSection(); + if (error(SecIOrErr.getError())) return '?'; + elf_section_iterator SecI = *SecIOrErr; if (SecI != Obj.section_end()) { switch (SecI->getType()) { case ELF::SHT_PROGBITS: @@ -651,9 +721,10 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) { uint32_t Characteristics = 0; if (!COFF::isReservedSectionNumber(Symb.getSectionNumber())) { - section_iterator SecI = Obj.section_end(); - if (error(SymI->getSection(SecI))) + ErrorOr<section_iterator> SecIOrErr = SymI->getSection(); + if (error(SecIOrErr.getError())) return '?'; + section_iterator SecI = *SecIOrErr; const coff_section *Section = Obj.getCOFFSection(*SecI); Characteristics = Section->Characteristics; } @@ -701,8 +772,7 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { case MachO::N_INDR: return 'i'; case MachO::N_SECT: { - section_iterator Sec = Obj.section_end(); - Obj.getSymbolSection(Symb, Sec); + section_iterator Sec = *Obj.getSymbolSection(Symb); DataRefImpl Ref = Sec->getRawDataRefImpl(); StringRef SectionName; Obj.getSectionName(Ref, SectionName); @@ -762,8 +832,14 @@ static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) { char Ret = '?'; if (Symflags & object::SymbolRef::SF_Absolute) Ret = 'a'; - else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj)) + else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj)) { Ret = getSymbolNMTypeChar(*IR, I); + Triple Host(sys::getDefaultTargetTriple()); + if (Ret == 'd' && Host.isOSDarwin()) { + if(Symflags & SymbolRef::SF_Const) + Ret = 's'; + } + } else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(&Obj)) Ret = getSymbolNMTypeChar(*COFF, I); else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj)) @@ -943,10 +1019,10 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { if (I != E) { outs() << "Archive map\n"; for (; I != E; ++I) { - ErrorOr<Archive::child_iterator> C = I->getMember(); + ErrorOr<Archive::Child> C = I->getMember(); if (error(C.getError())) return; - ErrorOr<StringRef> FileNameOrErr = C.get()->getName(); + ErrorOr<StringRef> FileNameOrErr = C->getName(); if (error(FileNameOrErr.getError())) return; StringRef SymName = I->getName(); @@ -958,7 +1034,10 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); I != E; ++I) { - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = I->getAsBinary(&Context); + if (error(I->getError())) + return; + auto &C = I->get(); + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(&Context); if (ChildOrErr.getError()) continue; if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { @@ -1013,8 +1092,11 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { + if (error(AI->getError())) + return; + auto &C = AI->get(); ErrorOr<std::unique_ptr<Binary>> ChildOrErr = - AI->getAsBinary(&Context); + C.getAsBinary(&Context); if (ChildOrErr.getError()) continue; if (SymbolicFile *O = @@ -1067,8 +1149,11 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { + if (error(AI->getError())) + return; + auto &C = AI->get(); ErrorOr<std::unique_ptr<Binary>> ChildOrErr = - AI->getAsBinary(&Context); + C.getAsBinary(&Context); if (ChildOrErr.getError()) continue; if (SymbolicFile *O = @@ -1116,8 +1201,10 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { std::unique_ptr<Archive> &A = *AOrErr; for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = - AI->getAsBinary(&Context); + if (error(AI->getError())) + return; + auto &C = AI->get(); + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(&Context); if (ChildOrErr.getError()) continue; if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { @@ -1150,7 +1237,6 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { return; } error("unrecognizable file type", Filename); - return; } int main(int argc, char **argv) { diff --git a/contrib/llvm/tools/llvm-objdump/COFFDump.cpp b/contrib/llvm/tools/llvm-objdump/COFFDump.cpp index 8b94a50..f286351 100644 --- a/contrib/llvm/tools/llvm-objdump/COFFDump.cpp +++ b/contrib/llvm/tools/llvm-objdump/COFFDump.cpp @@ -151,7 +151,7 @@ static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) { << " remaining in buffer"; return ; } - printUnwindCode(ArrayRef<UnwindCode>(I, E)); + printUnwindCode(makeArrayRef(I, E)); I += UsedSlots; } } @@ -165,10 +165,10 @@ resolveSectionAndAddress(const COFFObjectFile *Obj, const SymbolRef &Sym, if (std::error_code EC = ResolvedAddrOrErr.getError()) return EC; ResolvedAddr = *ResolvedAddrOrErr; - section_iterator iter(Obj->section_begin()); - if (std::error_code EC = Sym.getSection(iter)) + ErrorOr<section_iterator> Iter = Sym.getSection(); + if (std::error_code EC = Iter.getError()) return EC; - ResolvedSection = Obj->getCOFFSection(*iter); + ResolvedSection = Obj->getCOFFSection(**Iter); return std::error_code(); } @@ -241,12 +241,10 @@ printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) { return; const pe32_header *PE32Header; - if (error(Obj->getPE32Header(PE32Header))) - return; + error(Obj->getPE32Header(PE32Header)); uint32_t ImageBase = PE32Header->ImageBase; uintptr_t IntPtr = 0; - if (error(Obj->getVaPtr(TableVA, IntPtr))) - return; + error(Obj->getVaPtr(TableVA, IntPtr)); const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr; outs() << "SEH Table:"; for (int I = 0; I < Count; ++I) @@ -257,8 +255,7 @@ printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) { static void printLoadConfiguration(const COFFObjectFile *Obj) { // Skip if it's not executable. const pe32_header *PE32Header; - if (error(Obj->getPE32Header(PE32Header))) - return; + error(Obj->getPE32Header(PE32Header)); if (!PE32Header) return; @@ -267,13 +264,11 @@ static void printLoadConfiguration(const COFFObjectFile *Obj) { return; const data_directory *DataDir; - if (error(Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir))) - return; + error(Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir)); uintptr_t IntPtr = 0; if (DataDir->RelativeVirtualAddress == 0) return; - if (error(Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))) - return; + error(Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr)); auto *LoadConf = reinterpret_cast<const coff_load_configuration32 *>(IntPtr); outs() << "Load configuration:" @@ -381,8 +376,7 @@ static bool getPDataSection(const COFFObjectFile *Obj, const RuntimeFunction *&RFStart, int &NumRFs) { for (const SectionRef &Section : Obj->sections()) { StringRef Name; - if (error(Section.getName(Name))) - continue; + error(Section.getName(Name)); if (Name != ".pdata") continue; @@ -394,8 +388,7 @@ static bool getPDataSection(const COFFObjectFile *Obj, std::sort(Rels.begin(), Rels.end(), RelocAddressLess); ArrayRef<uint8_t> Contents; - if (error(Obj->getSectionContents(Pdata, Contents))) - continue; + error(Obj->getSectionContents(Pdata, Contents)); if (Contents.empty()) continue; @@ -440,7 +433,7 @@ static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) { if (UI->NumCodes) outs() << " Unwind Codes:\n"; - printAllUnwindCodes(ArrayRef<UnwindCode>(&UI->UnwindCodes[0], UI->NumCodes)); + printAllUnwindCodes(makeArrayRef(&UI->UnwindCodes[0], UI->NumCodes)); outs() << "\n"; outs().flush(); @@ -499,11 +492,10 @@ static void printRuntimeFunctionRels(const COFFObjectFile *Obj, ArrayRef<uint8_t> XContents; uint64_t UnwindInfoOffset = 0; - if (error(getSectionContents( + error(getSectionContents( Obj, Rels, SectionOffset + /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, - XContents, UnwindInfoOffset))) - return; + XContents, UnwindInfoOffset)); if (XContents.empty()) return; @@ -550,3 +542,52 @@ void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) { printImportTables(file); printExportTable(file); } + +void llvm::printCOFFSymbolTable(const COFFObjectFile *coff) { + for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) { + ErrorOr<COFFSymbolRef> Symbol = coff->getSymbol(SI); + StringRef Name; + error(Symbol.getError()); + error(coff->getSymbolName(*Symbol, Name)); + + outs() << "[" << format("%2d", SI) << "]" + << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")" + << "(fl 0x00)" // Flag bits, which COFF doesn't have. + << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")" + << "(scl " << format("%3x", unsigned(Symbol->getStorageClass())) << ") " + << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") " + << "0x" << format("%08x", unsigned(Symbol->getValue())) << " " + << Name << "\n"; + + for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) { + if (Symbol->isSectionDefinition()) { + const coff_aux_section_definition *asd; + error(coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd)); + + int32_t AuxNumber = asd->getNumber(Symbol->isBigObj()); + + outs() << "AUX " + << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x " + , unsigned(asd->Length) + , unsigned(asd->NumberOfRelocations) + , unsigned(asd->NumberOfLinenumbers) + , unsigned(asd->CheckSum)) + << format("assoc %d comdat %d\n" + , unsigned(AuxNumber) + , unsigned(asd->Selection)); + } else if (Symbol->isFileRecord()) { + const char *FileName; + error(coff->getAuxSymbol<char>(SI + 1, FileName)); + + StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() * + coff->getSymbolTableEntrySize()); + outs() << "AUX " << Name.rtrim(StringRef("\0", 1)) << '\n'; + + SI = SI + Symbol->getNumberOfAuxSymbols(); + break; + } else { + outs() << "AUX Unknown\n"; + } + } + } +} diff --git a/contrib/llvm/tools/llvm-objdump/ELFDump.cpp b/contrib/llvm/tools/llvm-objdump/ELFDump.cpp index 2d0d7d7..7b44e39 100644 --- a/contrib/llvm/tools/llvm-objdump/ELFDump.cpp +++ b/contrib/llvm/tools/llvm-objdump/ELFDump.cpp @@ -24,10 +24,8 @@ using namespace llvm::object; template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) { typedef ELFFile<ELFT> ELFO; outs() << "Program Header:\n"; - for (typename ELFO::Elf_Phdr_Iter pi = o->program_header_begin(), - pe = o->program_header_end(); - pi != pe; ++pi) { - switch (pi->p_type) { + for (const typename ELFO::Elf_Phdr &Phdr : o->program_headers()) { + switch (Phdr.p_type) { case ELF::PT_LOAD: outs() << " LOAD "; break; @@ -55,22 +53,16 @@ template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) { const char *Fmt = ELFT::Is64Bits ? "0x%016" PRIx64 " " : "0x%08" PRIx64 " "; - outs() << "off " - << format(Fmt, (uint64_t)pi->p_offset) - << "vaddr " - << format(Fmt, (uint64_t)pi->p_vaddr) - << "paddr " - << format(Fmt, (uint64_t)pi->p_paddr) - << format("align 2**%u\n", countTrailingZeros<uint64_t>(pi->p_align)) - << " filesz " - << format(Fmt, (uint64_t)pi->p_filesz) - << "memsz " - << format(Fmt, (uint64_t)pi->p_memsz) - << "flags " - << ((pi->p_flags & ELF::PF_R) ? "r" : "-") - << ((pi->p_flags & ELF::PF_W) ? "w" : "-") - << ((pi->p_flags & ELF::PF_X) ? "x" : "-") - << "\n"; + outs() << "off " << format(Fmt, (uint64_t)Phdr.p_offset) << "vaddr " + << format(Fmt, (uint64_t)Phdr.p_vaddr) << "paddr " + << format(Fmt, (uint64_t)Phdr.p_paddr) + << format("align 2**%u\n", + countTrailingZeros<uint64_t>(Phdr.p_align)) + << " filesz " << format(Fmt, (uint64_t)Phdr.p_filesz) + << "memsz " << format(Fmt, (uint64_t)Phdr.p_memsz) << "flags " + << ((Phdr.p_flags & ELF::PF_R) ? "r" : "-") + << ((Phdr.p_flags & ELF::PF_W) ? "w" : "-") + << ((Phdr.p_flags & ELF::PF_X) ? "x" : "-") << "\n"; } outs() << "\n"; } diff --git a/contrib/llvm/tools/llvm-objdump/MachODump.cpp b/contrib/llvm/tools/llvm-objdump/MachODump.cpp index 04c72f48..a2f3bc8 100644 --- a/contrib/llvm/tools/llvm-objdump/MachODump.cpp +++ b/contrib/llvm/tools/llvm-objdump/MachODump.cpp @@ -13,6 +13,7 @@ #include "llvm-objdump.h" #include "llvm-c/Disassembler.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" @@ -97,11 +98,6 @@ cl::opt<bool> cl::desc("Print the linker optimization hints for " "Mach-O objects (requires -macho)")); -cl::list<std::string> - llvm::DumpSections("section", - cl::desc("Prints the specified segment,section for " - "Mach-O objects (requires -macho)")); - cl::opt<bool> llvm::InfoPlist("info-plist", cl::desc("Print the info plist section as strings for " @@ -138,6 +134,7 @@ static cl::opt<bool> NoSymbolicOperands( static cl::list<std::string> ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), cl::ZeroOrMore); + bool ArchAll = false; static std::string ThumbTripleName; @@ -210,19 +207,19 @@ static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length, case MachO::DICE_KIND_DATA: if (Length >= 4) { if (!NoShowRawInsn) - dumpBytes(ArrayRef<uint8_t>(bytes, 4), outs()); + dumpBytes(makeArrayRef(bytes, 4), outs()); Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0]; outs() << "\t.long " << Value; Size = 4; } else if (Length >= 2) { if (!NoShowRawInsn) - dumpBytes(ArrayRef<uint8_t>(bytes, 2), outs()); + dumpBytes(makeArrayRef(bytes, 2), outs()); Value = bytes[1] << 8 | bytes[0]; outs() << "\t.short " << Value; Size = 2; } else { if (!NoShowRawInsn) - dumpBytes(ArrayRef<uint8_t>(bytes, 2), outs()); + dumpBytes(makeArrayRef(bytes, 2), outs()); Value = bytes[0]; outs() << "\t.byte " << Value; Size = 1; @@ -234,14 +231,14 @@ static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length, break; case MachO::DICE_KIND_JUMP_TABLE8: if (!NoShowRawInsn) - dumpBytes(ArrayRef<uint8_t>(bytes, 1), outs()); + dumpBytes(makeArrayRef(bytes, 1), outs()); Value = bytes[0]; outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n"; Size = 1; break; case MachO::DICE_KIND_JUMP_TABLE16: if (!NoShowRawInsn) - dumpBytes(ArrayRef<uint8_t>(bytes, 2), outs()); + dumpBytes(makeArrayRef(bytes, 2), outs()); Value = bytes[1] << 8 | bytes[0]; outs() << "\t.short " << format("%5u", Value & 0xffff) << "\t@ KIND_JUMP_TABLE16\n"; @@ -250,7 +247,7 @@ static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length, case MachO::DICE_KIND_JUMP_TABLE32: case MachO::DICE_KIND_ABS_JUMP_TABLE32: if (!NoShowRawInsn) - dumpBytes(ArrayRef<uint8_t>(bytes, 4), outs()); + dumpBytes(makeArrayRef(bytes, 4), outs()); Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0]; outs() << "\t.long " << Value; if (Kind == MachO::DICE_KIND_JUMP_TABLE32) @@ -670,13 +667,9 @@ static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1, double d) { outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1); uint32_t Hi, Lo; - if (O->isLittleEndian()) { - Hi = l1; - Lo = l0; - } else { - Hi = l0; - Lo = l1; - } + Hi = (O->isLittleEndian()) ? l1 : l0; + Lo = (O->isLittleEndian()) ? l0 : l1; + // Hi is the high word, so this is equivalent to if(isfinite(d)) if ((Hi & 0x7ff00000) != 0x7ff00000) outs() << format(" (%.16e)\n", d); @@ -921,10 +914,7 @@ static void DumpInitTermPointerSection(MachOObjectFile *O, const char *sect, SymbolAddressMap *AddrMap, bool verbose) { uint32_t stride; - if (O->is64Bit()) - stride = sizeof(uint64_t); - else - stride = sizeof(uint32_t); + stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t); for (uint32_t i = 0; i < sect_size; i += stride) { const char *SymbolName = nullptr; if (O->is64Bit()) { @@ -1006,8 +996,8 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, if (verbose) CreateSymbolAddressMap(O, &AddrMap); - for (unsigned i = 0; i < DumpSections.size(); ++i) { - StringRef DumpSection = DumpSections[i]; + for (unsigned i = 0; i < FilterSections.size(); ++i) { + StringRef DumpSection = FilterSections[i]; std::pair<StringRef, StringRef> DumpSegSectName; DumpSegSectName = DumpSection.split(','); StringRef DumpSegName, DumpSectName; @@ -1171,7 +1161,7 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, // UniversalHeaders or ArchiveHeaders. if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind || LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints || - DylibsUsed || DylibId || ObjcMetaData || (DumpSections.size() != 0)) { + DylibsUsed || DylibId || ObjcMetaData || (FilterSections.size() != 0)) { outs() << Filename; if (!ArchiveMemberName.empty()) outs() << '(' << ArchiveMemberName << ')'; @@ -1194,7 +1184,7 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, PrintSectionHeaders(MachOOF); if (SectionContents) PrintSectionContents(MachOOF); - if (DumpSections.size() != 0) + if (FilterSections.size() != 0) DumpSectionContents(Filename, MachOOF, !NonVerbose); if (InfoPlist) DumpInfoPlistSectionContents(Filename, MachOOF); @@ -1395,7 +1385,7 @@ static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB, } } -static void printArchiveChild(Archive::Child &C, bool verbose, +static void printArchiveChild(const Archive::Child &C, bool verbose, bool print_offset) { if (print_offset) outs() << C.getChildOffset() << "\t"; @@ -1404,42 +1394,15 @@ static void printArchiveChild(Archive::Child &C, bool verbose, // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG. // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG. outs() << "-"; - if (Mode & sys::fs::owner_read) - outs() << "r"; - else - outs() << "-"; - if (Mode & sys::fs::owner_write) - outs() << "w"; - else - outs() << "-"; - if (Mode & sys::fs::owner_exe) - outs() << "x"; - else - outs() << "-"; - if (Mode & sys::fs::group_read) - outs() << "r"; - else - outs() << "-"; - if (Mode & sys::fs::group_write) - outs() << "w"; - else - outs() << "-"; - if (Mode & sys::fs::group_exe) - outs() << "x"; - else - outs() << "-"; - if (Mode & sys::fs::others_read) - outs() << "r"; - else - outs() << "-"; - if (Mode & sys::fs::others_write) - outs() << "w"; - else - outs() << "-"; - if (Mode & sys::fs::others_exe) - outs() << "x"; - else - outs() << "-"; + outs() << ((Mode & sys::fs::owner_read) ? "r" : "-"); + outs() << ((Mode & sys::fs::owner_write) ? "w" : "-"); + outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-"); + outs() << ((Mode & sys::fs::group_read) ? "r" : "-"); + outs() << ((Mode & sys::fs::group_write) ? "w" : "-"); + outs() << ((Mode & sys::fs::group_exe) ? "x" : "-"); + outs() << ((Mode & sys::fs::others_read) ? "r" : "-"); + outs() << ((Mode & sys::fs::others_write) ? "w" : "-"); + outs() << ((Mode & sys::fs::others_exe) ? "x" : "-"); } else { outs() << format("0%o ", Mode); } @@ -1448,8 +1411,10 @@ static void printArchiveChild(Archive::Child &C, bool verbose, outs() << format("%3d/", UID); unsigned GID = C.getGID(); outs() << format("%-3d ", GID); - uint64_t Size = C.getRawSize(); - outs() << format("%5" PRId64, Size) << " "; + ErrorOr<uint64_t> Size = C.getRawSize(); + if (std::error_code EC = Size.getError()) + report_fatal_error(EC.message()); + outs() << format("%5" PRId64, Size.get()) << " "; StringRef RawLastModified = C.getRawLastModified(); if (verbose) { @@ -1483,14 +1448,11 @@ static void printArchiveChild(Archive::Child &C, bool verbose, } static void printArchiveHeaders(Archive *A, bool verbose, bool print_offset) { - if (A->hasSymbolTable()) { - Archive::child_iterator S = A->getSymbolTableChild(); - Archive::Child C = *S; - printArchiveChild(C, verbose, print_offset); - } - for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); I != E; - ++I) { - Archive::Child C = *I; + for (Archive::child_iterator I = A->child_begin(false), E = A->child_end(); + I != E; ++I) { + if (std::error_code EC = I->getError()) + report_fatal_error(EC.message()); + const Archive::Child &C = **I; printArchiveChild(C, verbose, print_offset); } } @@ -1527,7 +1489,10 @@ void llvm::ParseInputMachO(StringRef Filename) { printArchiveHeaders(A, !NonVerbose, ArchiveMemberOffsets); for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); I != E; ++I) { - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = I->getAsBinary(); + if (std::error_code EC = I->getError()) + report_error(Filename, EC); + auto &C = I->get(); + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); if (ChildOrErr.getError()) continue; if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) { @@ -1575,7 +1540,10 @@ void llvm::ParseInputMachO(StringRef Filename) { for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary(); + if (std::error_code EC = AI->getError()) + report_error(Filename, EC); + auto &C = AI->get(); + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); if (ChildOrErr.getError()) continue; if (MachOObjectFile *O = @@ -1617,7 +1585,10 @@ void llvm::ParseInputMachO(StringRef Filename) { for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary(); + if (std::error_code EC = AI->getError()) + report_error(Filename, EC); + auto &C = AI->get(); + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); if (ChildOrErr.getError()) continue; if (MachOObjectFile *O = @@ -1653,7 +1624,10 @@ void llvm::ParseInputMachO(StringRef Filename) { printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets); for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary(); + if (std::error_code EC = AI->getError()) + report_error(Filename, EC); + auto &C = AI->get(); + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); if (ChildOrErr.getError()) continue; if (MachOObjectFile *O = @@ -1676,8 +1650,7 @@ void llvm::ParseInputMachO(StringRef Filename) { errs() << "llvm-objdump: '" << Filename << "': " << "Object is not a Mach-O file type.\n"; } else - errs() << "llvm-objdump: '" << Filename << "': " - << "Unrecognized file type.\n"; + report_error(Filename, object_error::invalid_file_type); } typedef std::pair<uint64_t, const char *> BindInfoEntry; @@ -1698,6 +1671,7 @@ struct DisassembleInfo { uint64_t adrp_addr; uint32_t adrp_inst; BindTable *bindtable; + uint32_t depth; }; // SymbolizerGetOpInfo() is the operand information call back function. @@ -1735,8 +1709,15 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, if (Arch == Triple::x86) { if (Size != 1 && Size != 2 && Size != 4 && Size != 0) return 0; - // First search the section's relocation entries (if any) for an entry - // for this section offset. + if (info->O->getHeader().filetype != MachO::MH_OBJECT) { + // TODO: + // Search the external relocation entries of a fully linked image + // (if any) for an entry that matches this segment offset. + // uint32_t seg_offset = (Pc + Offset); + return 0; + } + // In MH_OBJECT filetypes search the section's relocation entries (if any) + // for an entry for this section offset. uint32_t sect_addr = info->S.getAddress(); uint32_t sect_offset = (Pc + Offset) - sect_addr; bool reloc_found = false; @@ -1806,17 +1787,20 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, op_info->Value = offset; return 1; } - // TODO: - // Second search the external relocation entries of a fully linked image - // (if any) for an entry that matches this segment offset. - // uint32_t seg_offset = (Pc + Offset); return 0; } if (Arch == Triple::x86_64) { if (Size != 1 && Size != 2 && Size != 4 && Size != 0) return 0; - // First search the section's relocation entries (if any) for an entry - // for this section offset. + if (info->O->getHeader().filetype != MachO::MH_OBJECT) { + // TODO: + // Search the external relocation entries of a fully linked image + // (if any) for an entry that matches this segment offset. + // uint64_t seg_offset = (Pc + Offset); + return 0; + } + // In MH_OBJECT filetypes search the section's relocation entries (if any) + // for an entry for this section offset. uint64_t sect_addr = info->S.getAddress(); uint64_t sect_offset = (Pc + Offset) - sect_addr; bool reloc_found = false; @@ -1874,17 +1858,20 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, op_info->AddSymbol.Name = name; return 1; } - // TODO: - // Second search the external relocation entries of a fully linked image - // (if any) for an entry that matches this segment offset. - // uint64_t seg_offset = (Pc + Offset); return 0; } if (Arch == Triple::arm) { if (Offset != 0 || (Size != 4 && Size != 2)) return 0; - // First search the section's relocation entries (if any) for an entry - // for this section offset. + if (info->O->getHeader().filetype != MachO::MH_OBJECT) { + // TODO: + // Search the external relocation entries of a fully linked image + // (if any) for an entry that matches this segment offset. + // uint32_t seg_offset = (Pc + Offset); + return 0; + } + // In MH_OBJECT filetypes search the section's relocation entries (if any) + // for an entry for this section offset. uint32_t sect_addr = info->S.getAddress(); uint32_t sect_offset = (Pc + Offset) - sect_addr; DataRefImpl Rel; @@ -2016,8 +2003,15 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, if (Arch == Triple::aarch64) { if (Offset != 0 || Size != 4) return 0; - // First search the section's relocation entries (if any) for an entry - // for this section offset. + if (info->O->getHeader().filetype != MachO::MH_OBJECT) { + // TODO: + // Search the external relocation entries of a fully linked image + // (if any) for an entry that matches this segment offset. + // uint64_t seg_offset = (Pc + Offset); + return 0; + } + // In MH_OBJECT filetypes search the section's relocation entries (if any) + // for an entry for this section offset. uint64_t sect_addr = info->S.getAddress(); uint64_t sect_offset = (Pc + Offset) - sect_addr; auto Reloc = @@ -2370,6 +2364,8 @@ static const char *get_pointer_64(uint64_t Address, uint32_t &offset, for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) { uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress(); uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize(); + if (SectSize == 0) + continue; if (objc_only) { StringRef SectName; ((*(info->Sections))[SectIdx]).getName(SectName); @@ -3267,6 +3263,8 @@ walk_pointer_list_32(const char *listname, const SectionRef S, } static void print_layout_map(const char *layout_map, uint32_t left) { + if (layout_map == nullptr) + return; outs() << " layout map: "; do { outs() << format("0x%02" PRIx32, (*layout_map) & 0xff) << " "; @@ -3330,8 +3328,8 @@ static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info, return; memset(&m, '\0', sizeof(struct method64_t)); if (left < sizeof(struct method64_t)) { - memcpy(&ml, r, left); - outs() << indent << " (method_t entends past the end of the section)\n"; + memcpy(&m, r, left); + outs() << indent << " (method_t extends past the end of the section)\n"; } else memcpy(&m, r, sizeof(struct method64_t)); if (info->O->isLittleEndian() != sys::IsLittleEndianHost) @@ -4222,7 +4220,7 @@ static void print_objc_property_list32(uint32_t p, } } -static void print_class_ro64_t(uint64_t p, struct DisassembleInfo *info, +static bool print_class_ro64_t(uint64_t p, struct DisassembleInfo *info, bool &is_meta_class) { struct class_ro64_t cro; const char *r; @@ -4233,7 +4231,7 @@ static void print_class_ro64_t(uint64_t p, struct DisassembleInfo *info, r = get_pointer_64(p, offset, left, S, info); if (r == nullptr || left < sizeof(struct class_ro64_t)) - return; + return false; memset(&cro, '\0', sizeof(struct class_ro64_t)); if (left < sizeof(struct class_ro64_t)) { memcpy(&cro, r, left); @@ -4357,10 +4355,11 @@ static void print_class_ro64_t(uint64_t p, struct DisassembleInfo *info, if (cro.baseProperties + n_value != 0) print_objc_property_list64(cro.baseProperties + n_value, info); - is_meta_class = (cro.flags & RO_META) ? true : false; + is_meta_class = (cro.flags & RO_META) != 0; + return true; } -static void print_class_ro32_t(uint32_t p, struct DisassembleInfo *info, +static bool print_class_ro32_t(uint32_t p, struct DisassembleInfo *info, bool &is_meta_class) { struct class_ro32_t cro; const char *r; @@ -4370,7 +4369,7 @@ static void print_class_ro32_t(uint32_t p, struct DisassembleInfo *info, r = get_pointer_32(p, offset, left, S, info); if (r == nullptr) - return; + return false; memset(&cro, '\0', sizeof(struct class_ro32_t)); if (left < sizeof(struct class_ro32_t)) { memcpy(&cro, r, left); @@ -4420,7 +4419,8 @@ static void print_class_ro32_t(uint32_t p, struct DisassembleInfo *info, << format("0x%" PRIx32, cro.baseProperties) << "\n"; if (cro.baseProperties != 0) print_objc_property_list32(cro.baseProperties, info); - is_meta_class = (cro.flags & RO_META) ? true : false; + is_meta_class = (cro.flags & RO_META) != 0; + return true; } static void print_class64_t(uint64_t p, struct DisassembleInfo *info) { @@ -4490,11 +4490,16 @@ static void print_class64_t(uint64_t p, struct DisassembleInfo *info) { outs() << " Swift class"; outs() << "\n"; bool is_meta_class; - print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class); + if (!print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class)) + return; - if (is_meta_class == false) { - outs() << "Meta Class\n"; - print_class64_t(c.isa + isa_n_value, info); + if (!is_meta_class && + c.isa + isa_n_value != p && + c.isa + isa_n_value != 0 && + info->depth < 100) { + info->depth++; + outs() << "Meta Class\n"; + print_class64_t(c.isa + isa_n_value, info); } } @@ -4555,9 +4560,10 @@ static void print_class32_t(uint32_t p, struct DisassembleInfo *info) { outs() << " Swift class"; outs() << "\n"; bool is_meta_class; - print_class_ro32_t(c.data & ~0x3, info, is_meta_class); + if (!print_class_ro32_t(c.data & ~0x3, info, is_meta_class)) + return; - if (is_meta_class == false) { + if (!is_meta_class) { outs() << "Meta Class\n"; print_class32_t(c.isa, info); } @@ -4865,7 +4871,7 @@ static void print_category32_t(uint32_t p, struct DisassembleInfo *info) { outs() << " name " << format("0x%" PRIx32, c.name); name = get_symbol_32(offset + offsetof(struct category32_t, name), S, info, c.name); - if (name != NULL) + if (name) outs() << " " << name; outs() << "\n"; @@ -5006,6 +5012,9 @@ static void print_image_info64(SectionRef S, struct DisassembleInfo *info) { struct objc_image_info64 o; const char *r; + if (S == SectionRef()) + return; + StringRef SectName; S.getName(SectName); DataRefImpl Ref = S.getRawDataRefImpl(); @@ -5142,75 +5151,48 @@ static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) { info.adrp_addr = 0; info.adrp_inst = 0; - const SectionRef CL = get_section(O, "__OBJC2", "__class_list"); - if (CL != SectionRef()) { - info.S = CL; - walk_pointer_list_64("class", CL, O, &info, print_class64_t); - } else { - const SectionRef CL = get_section(O, "__DATA", "__objc_classlist"); - info.S = CL; - walk_pointer_list_64("class", CL, O, &info, print_class64_t); - } - - const SectionRef CR = get_section(O, "__OBJC2", "__class_refs"); - if (CR != SectionRef()) { - info.S = CR; - walk_pointer_list_64("class refs", CR, O, &info, nullptr); - } else { - const SectionRef CR = get_section(O, "__DATA", "__objc_classrefs"); - info.S = CR; - walk_pointer_list_64("class refs", CR, O, &info, nullptr); - } - - const SectionRef SR = get_section(O, "__OBJC2", "__super_refs"); - if (SR != SectionRef()) { - info.S = SR; - walk_pointer_list_64("super refs", SR, O, &info, nullptr); - } else { - const SectionRef SR = get_section(O, "__DATA", "__objc_superrefs"); - info.S = SR; - walk_pointer_list_64("super refs", SR, O, &info, nullptr); - } - - const SectionRef CA = get_section(O, "__OBJC2", "__category_list"); - if (CA != SectionRef()) { - info.S = CA; - walk_pointer_list_64("category", CA, O, &info, print_category64_t); - } else { - const SectionRef CA = get_section(O, "__DATA", "__objc_catlist"); - info.S = CA; - walk_pointer_list_64("category", CA, O, &info, print_category64_t); - } - - const SectionRef PL = get_section(O, "__OBJC2", "__protocol_list"); - if (PL != SectionRef()) { - info.S = PL; - walk_pointer_list_64("protocol", PL, O, &info, nullptr); - } else { - const SectionRef PL = get_section(O, "__DATA", "__objc_protolist"); - info.S = PL; - walk_pointer_list_64("protocol", PL, O, &info, nullptr); - } - - const SectionRef MR = get_section(O, "__OBJC2", "__message_refs"); - if (MR != SectionRef()) { - info.S = MR; - print_message_refs64(MR, &info); - } else { - const SectionRef MR = get_section(O, "__DATA", "__objc_msgrefs"); - info.S = MR; - print_message_refs64(MR, &info); - } - - const SectionRef II = get_section(O, "__OBJC2", "__image_info"); - if (II != SectionRef()) { - info.S = II; - print_image_info64(II, &info); - } else { - const SectionRef II = get_section(O, "__DATA", "__objc_imageinfo"); - info.S = II; - print_image_info64(II, &info); - } + info.depth = 0; + SectionRef CL = get_section(O, "__OBJC2", "__class_list"); + if (CL == SectionRef()) + CL = get_section(O, "__DATA", "__objc_classlist"); + info.S = CL; + walk_pointer_list_64("class", CL, O, &info, print_class64_t); + + SectionRef CR = get_section(O, "__OBJC2", "__class_refs"); + if (CR == SectionRef()) + CR = get_section(O, "__DATA", "__objc_classrefs"); + info.S = CR; + walk_pointer_list_64("class refs", CR, O, &info, nullptr); + + SectionRef SR = get_section(O, "__OBJC2", "__super_refs"); + if (SR == SectionRef()) + SR = get_section(O, "__DATA", "__objc_superrefs"); + info.S = SR; + walk_pointer_list_64("super refs", SR, O, &info, nullptr); + + SectionRef CA = get_section(O, "__OBJC2", "__category_list"); + if (CA == SectionRef()) + CA = get_section(O, "__DATA", "__objc_catlist"); + info.S = CA; + walk_pointer_list_64("category", CA, O, &info, print_category64_t); + + SectionRef PL = get_section(O, "__OBJC2", "__protocol_list"); + if (PL == SectionRef()) + PL = get_section(O, "__DATA", "__objc_protolist"); + info.S = PL; + walk_pointer_list_64("protocol", PL, O, &info, nullptr); + + SectionRef MR = get_section(O, "__OBJC2", "__message_refs"); + if (MR == SectionRef()) + MR = get_section(O, "__DATA", "__objc_msgrefs"); + info.S = MR; + print_message_refs64(MR, &info); + + SectionRef II = get_section(O, "__OBJC2", "__image_info"); + if (II == SectionRef()) + II = get_section(O, "__DATA", "__objc_imageinfo"); + info.S = II; + print_image_info64(II, &info); if (info.bindtable != nullptr) delete info.bindtable; @@ -5559,7 +5541,7 @@ static void printObjcMetaData(MachOObjectFile *O, bool verbose) { // binary for the iOS simulator which is the second Objective-C // ABI. In that case printObjc1_32bit_MetaData() will determine that // and return false. - if (printObjc1_32bit_MetaData(O, verbose) == false) + if (!printObjc1_32bit_MetaData(O, verbose)) printObjc2_32bit_MetaData(O, verbose); } } @@ -5588,36 +5570,38 @@ static const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t *ReferenceType, struct DisassembleInfo *info) { // First see if there is an external relocation entry at the ReferencePC. - uint64_t sect_addr = info->S.getAddress(); - uint64_t sect_offset = ReferencePC - sect_addr; - bool reloc_found = false; - DataRefImpl Rel; - MachO::any_relocation_info RE; - bool isExtern = false; - SymbolRef Symbol; - for (const RelocationRef &Reloc : info->S.relocations()) { - uint64_t RelocOffset = Reloc.getOffset(); - if (RelocOffset == sect_offset) { - Rel = Reloc.getRawDataRefImpl(); - RE = info->O->getRelocation(Rel); - if (info->O->isRelocationScattered(RE)) - continue; - isExtern = info->O->getPlainRelocationExternal(RE); - if (isExtern) { - symbol_iterator RelocSym = Reloc.getSymbol(); - Symbol = *RelocSym; + if (info->O->getHeader().filetype == MachO::MH_OBJECT) { + uint64_t sect_addr = info->S.getAddress(); + uint64_t sect_offset = ReferencePC - sect_addr; + bool reloc_found = false; + DataRefImpl Rel; + MachO::any_relocation_info RE; + bool isExtern = false; + SymbolRef Symbol; + for (const RelocationRef &Reloc : info->S.relocations()) { + uint64_t RelocOffset = Reloc.getOffset(); + if (RelocOffset == sect_offset) { + Rel = Reloc.getRawDataRefImpl(); + RE = info->O->getRelocation(Rel); + if (info->O->isRelocationScattered(RE)) + continue; + isExtern = info->O->getPlainRelocationExternal(RE); + if (isExtern) { + symbol_iterator RelocSym = Reloc.getSymbol(); + Symbol = *RelocSym; + } + reloc_found = true; + break; } - reloc_found = true; - break; } - } - // If there is an external relocation entry for a symbol in a section - // then used that symbol's value for the value of the reference. - if (reloc_found && isExtern) { - if (info->O->getAnyRelocationPCRel(RE)) { - unsigned Type = info->O->getAnyRelocationType(RE); - if (Type == MachO::X86_64_RELOC_SIGNED) { - ReferenceValue = Symbol.getValue(); + // If there is an external relocation entry for a symbol in a section + // then used that symbol's value for the value of the reference. + if (reloc_found && isExtern) { + if (info->O->getAnyRelocationPCRel(RE)) { + unsigned Type = info->O->getAnyRelocationType(RE); + if (Type == MachO::X86_64_RELOC_SIGNED) { + ReferenceValue = Symbol.getValue(); + } } } } @@ -5872,7 +5856,6 @@ static void emitComments(raw_svector_ostream &CommentStream, formatted_raw_ostream &FormattedOS, const MCAsmInfo &MAI) { // Flush the stream before taking its content. - CommentStream.flush(); StringRef Comments = CommentsToEmit.str(); // Get the default information for printing a comment. const char *CommentBegin = MAI.getCommentString(); @@ -5893,7 +5876,6 @@ static void emitComments(raw_svector_ostream &CommentStream, // Tell the comment stream that the vector changed underneath it. CommentsToEmit.clear(); - CommentStream.resync(); } static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, @@ -6065,7 +6047,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, diContext.reset(new DWARFContextInMemory(*DbgObj)); } - if (DumpSections.size() == 0) + if (FilterSections.size() == 0) outs() << "(" << DisSegName << "," << DisSectName << ") section\n"; for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { @@ -6087,19 +6069,6 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, bool symbolTableWorked = false; - // Parse relocations. - std::vector<std::pair<uint64_t, SymbolRef>> Relocs; - for (const RelocationRef &Reloc : Sections[SectIdx].relocations()) { - uint64_t RelocOffset = Reloc.getOffset(); - uint64_t SectionAddress = Sections[SectIdx].getAddress(); - RelocOffset -= SectionAddress; - - symbol_iterator RelocSym = Reloc.getSymbol(); - - Relocs.push_back(std::make_pair(RelocOffset, *RelocSym)); - } - array_pod_sort(Relocs.begin(), Relocs.end()); - // Create a map of symbol addresses to symbol names for use by // the SymbolizerSymbolLookUp() routine. SymbolAddressMap AddrMap; @@ -6157,7 +6126,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, StringRef SymName = *SymNameOrErr; SymbolRef::Type ST = Symbols[SymIdx].getType(); - if (ST != SymbolRef::ST_Function) + if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data) continue; // Make sure the symbol is defined in this section. @@ -6251,10 +6220,9 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, DebugOut, Annotations); if (gotInst) { if (!NoShowRawInsn) { - dumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, Size), outs()); + dumpBytes(makeArrayRef(Bytes.data() + Index, Size), outs()); } formatted_raw_ostream FormattedOS(outs()); - Annotations.flush(); StringRef AnnotationsStr = Annotations.str(); if (isThumb) ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr, *ThumbSTI); @@ -6316,7 +6284,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, } if (!NoShowRawInsn) { outs() << "\t"; - dumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, InstSize), outs()); + dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs()); } IP->printInst(&Inst, outs(), "", *STI); outs() << "\n"; @@ -6441,8 +6409,7 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj, // Go back one so that SymbolAddress <= Addr. --Sym; - section_iterator SymSection = Obj->section_end(); - Sym->second.getSection(SymSection); + section_iterator SymSection = *Sym->second.getSection(); if (RelocSection == *SymSection) { // There's a valid symbol in the same section before this reference. ErrorOr<StringRef> NameOrErr = Sym->second.getName(); @@ -6780,13 +6747,268 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, } } +static unsigned getSizeForEncoding(bool is64Bit, + unsigned symbolEncoding) { + unsigned format = symbolEncoding & 0x0f; + switch (format) { + default: llvm_unreachable("Unknown Encoding"); + case dwarf::DW_EH_PE_absptr: + case dwarf::DW_EH_PE_signed: + return is64Bit ? 8 : 4; + case dwarf::DW_EH_PE_udata2: + case dwarf::DW_EH_PE_sdata2: + return 2; + case dwarf::DW_EH_PE_udata4: + case dwarf::DW_EH_PE_sdata4: + return 4; + case dwarf::DW_EH_PE_udata8: + case dwarf::DW_EH_PE_sdata8: + return 8; + } +} + +static uint64_t readPointer(const char *&Pos, bool is64Bit, unsigned Encoding) { + switch (getSizeForEncoding(is64Bit, Encoding)) { + case 2: + return readNext<uint16_t>(Pos); + break; + case 4: + return readNext<uint32_t>(Pos); + break; + case 8: + return readNext<uint64_t>(Pos); + break; + default: + llvm_unreachable("Illegal data size"); + } +} + +static void printMachOEHFrameSection(const MachOObjectFile *Obj, + std::map<uint64_t, SymbolRef> &Symbols, + const SectionRef &EHFrame) { + if (!Obj->isLittleEndian()) { + outs() << "warning: cannot handle big endian __eh_frame section\n"; + return; + } + + bool is64Bit = Obj->is64Bit(); + + outs() << "Contents of __eh_frame section:\n"; + + StringRef Contents; + EHFrame.getContents(Contents); + + /// A few fields of the CIE are used when decoding the FDE's. This struct + /// will cache those fields we need so that we don't have to decode it + /// repeatedly for each FDE that references it. + struct DecodedCIE { + Optional<uint32_t> FDEPointerEncoding; + Optional<uint32_t> LSDAPointerEncoding; + bool hasAugmentationLength; + }; + + // Map from the start offset of the CIE to the cached data for that CIE. + DenseMap<uint64_t, DecodedCIE> CachedCIEs; + + for (const char *Pos = Contents.data(), *End = Contents.end(); Pos != End; ) { + + const char *EntryStartPos = Pos; + + uint64_t Length = readNext<uint32_t>(Pos); + if (Length == 0xffffffff) + Length = readNext<uint64_t>(Pos); + + // Save the Pos so that we can check the length we encoded against what we + // end up decoding. + const char *PosAfterLength = Pos; + const char *EntryEndPos = PosAfterLength + Length; + + assert(EntryEndPos <= End && + "__eh_frame entry length exceeds section size"); + + uint32_t ID = readNext<uint32_t>(Pos); + if (ID == 0) { + // This is a CIE. + + uint32_t Version = readNext<uint8_t>(Pos); + + // Parse a null terminated augmentation string + SmallString<8> AugmentationString; + for (uint8_t Char = readNext<uint8_t>(Pos); Char; + Char = readNext<uint8_t>(Pos)) + AugmentationString.push_back(Char); + + // Optionally parse the EH data if the augmentation string says it's there. + Optional<uint64_t> EHData; + if (StringRef(AugmentationString).count("eh")) + EHData = is64Bit ? readNext<uint64_t>(Pos) : readNext<uint32_t>(Pos); + + unsigned ULEBByteCount; + uint64_t CodeAlignmentFactor = decodeULEB128((const uint8_t *)Pos, + &ULEBByteCount); + Pos += ULEBByteCount; + + int64_t DataAlignmentFactor = decodeSLEB128((const uint8_t *)Pos, + &ULEBByteCount); + Pos += ULEBByteCount; + + uint32_t ReturnAddressRegister = readNext<uint8_t>(Pos); + + Optional<uint64_t> AugmentationLength; + Optional<uint32_t> LSDAPointerEncoding; + Optional<uint32_t> PersonalityEncoding; + Optional<uint64_t> Personality; + Optional<uint32_t> FDEPointerEncoding; + if (!AugmentationString.empty() && AugmentationString.front() == 'z') { + AugmentationLength = decodeULEB128((const uint8_t *)Pos, + &ULEBByteCount); + Pos += ULEBByteCount; + + // Walk the augmentation string to get all the augmentation data. + for (unsigned i = 1, e = AugmentationString.size(); i != e; ++i) { + char Char = AugmentationString[i]; + switch (Char) { + case 'e': + assert((i + 1) != e && AugmentationString[i + 1] == 'h' && + "Expected 'eh' in augmentation string"); + break; + case 'L': + assert(!LSDAPointerEncoding && "Duplicate LSDA encoding"); + LSDAPointerEncoding = readNext<uint8_t>(Pos); + break; + case 'P': { + assert(!Personality && "Duplicate personality"); + PersonalityEncoding = readNext<uint8_t>(Pos); + Personality = readPointer(Pos, is64Bit, *PersonalityEncoding); + break; + } + case 'R': + assert(!FDEPointerEncoding && "Duplicate FDE encoding"); + FDEPointerEncoding = readNext<uint8_t>(Pos); + break; + case 'z': + llvm_unreachable("'z' must be first in the augmentation string"); + } + } + } + + outs() << "CIE:\n"; + outs() << " Length: " << Length << "\n"; + outs() << " CIE ID: " << ID << "\n"; + outs() << " Version: " << Version << "\n"; + outs() << " Augmentation String: " << AugmentationString << "\n"; + if (EHData) + outs() << " EHData: " << *EHData << "\n"; + outs() << " Code Alignment Factor: " << CodeAlignmentFactor << "\n"; + outs() << " Data Alignment Factor: " << DataAlignmentFactor << "\n"; + outs() << " Return Address Register: " << ReturnAddressRegister << "\n"; + if (AugmentationLength) { + outs() << " Augmentation Data Length: " << *AugmentationLength << "\n"; + if (LSDAPointerEncoding) { + outs() << " FDE LSDA Pointer Encoding: " + << *LSDAPointerEncoding << "\n"; + } + if (Personality) { + outs() << " Personality Encoding: " << *PersonalityEncoding << "\n"; + outs() << " Personality: " << *Personality << "\n"; + } + if (FDEPointerEncoding) { + outs() << " FDE Address Pointer Encoding: " + << *FDEPointerEncoding << "\n"; + } + } + // FIXME: Handle instructions. + // For now just emit some bytes + outs() << " Instructions:\n "; + dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos), + outs()); + outs() << "\n"; + Pos = EntryEndPos; + + // Cache this entry. + uint64_t Offset = EntryStartPos - Contents.data(); + CachedCIEs[Offset] = { FDEPointerEncoding, LSDAPointerEncoding, + AugmentationLength.hasValue() }; + continue; + } + + // This is an FDE. + // The CIE pointer for an FDE is the same location as the ID which we + // already read. + uint32_t CIEPointer = ID; + + const char *CIEStart = PosAfterLength - CIEPointer; + assert(CIEStart >= Contents.data() && + "FDE points to CIE before the __eh_frame start"); + + uint64_t CIEOffset = CIEStart - Contents.data(); + auto CIEIt = CachedCIEs.find(CIEOffset); + if (CIEIt == CachedCIEs.end()) + llvm_unreachable("Couldn't find CIE at offset in to __eh_frame section"); + + const DecodedCIE &CIE = CIEIt->getSecond(); + assert(CIE.FDEPointerEncoding && + "FDE references CIE which did not set pointer encoding"); + + uint64_t PCPointerSize = getSizeForEncoding(is64Bit, + *CIE.FDEPointerEncoding); + + uint64_t PCBegin = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding); + uint64_t PCRange = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding); + + Optional<uint64_t> AugmentationLength; + uint32_t LSDAPointerSize; + Optional<uint64_t> LSDAPointer; + if (CIE.hasAugmentationLength) { + unsigned ULEBByteCount; + AugmentationLength = decodeULEB128((const uint8_t *)Pos, + &ULEBByteCount); + Pos += ULEBByteCount; + + // Decode the LSDA if the CIE augmentation string said we should. + if (CIE.LSDAPointerEncoding) { + LSDAPointerSize = getSizeForEncoding(is64Bit, *CIE.LSDAPointerEncoding); + LSDAPointer = readPointer(Pos, is64Bit, *CIE.LSDAPointerEncoding); + } + } + + outs() << "FDE:\n"; + outs() << " Length: " << Length << "\n"; + outs() << " CIE Offset: " << CIEOffset << "\n"; + + if (PCPointerSize == 8) { + outs() << format(" PC Begin: %016" PRIx64, PCBegin) << "\n"; + outs() << format(" PC Range: %016" PRIx64, PCRange) << "\n"; + } else { + outs() << format(" PC Begin: %08" PRIx64, PCBegin) << "\n"; + outs() << format(" PC Range: %08" PRIx64, PCRange) << "\n"; + } + if (AugmentationLength) { + outs() << " Augmentation Data Length: " << *AugmentationLength << "\n"; + if (LSDAPointer) { + if (LSDAPointerSize == 8) + outs() << format(" LSDA Pointer: %016\n" PRIx64, *LSDAPointer); + else + outs() << format(" LSDA Pointer: %08\n" PRIx64, *LSDAPointer); + } + } + + // FIXME: Handle instructions. + // For now just emit some bytes + outs() << " Instructions:\n "; + dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos), + outs()); + outs() << "\n"; + Pos = EntryEndPos; + } +} + void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) { std::map<uint64_t, SymbolRef> Symbols; for (const SymbolRef &SymRef : Obj->symbols()) { // Discard any undefined or absolute symbols. They're not going to take part // in the convenience lookup for unwind info and just take up resources. - section_iterator Section = Obj->section_end(); - SymRef.getSection(Section); + section_iterator Section = *SymRef.getSection(); if (Section == Obj->section_end()) continue; @@ -6802,7 +7024,7 @@ void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) { else if (SectName == "__unwind_info") printMachOUnwindInfoSection(Obj, Symbols, Section); else if (SectName == "__eh_frame") - outs() << "llvm-objdump: warning: unhandled __eh_frame section\n"; + printMachOEHFrameSection(Obj, Symbols, Section); } } @@ -7128,36 +7350,20 @@ static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize, MachO::VM_PROT_EXECUTE)) != 0) outs() << " maxprot ?" << format("0x%08" PRIx32, maxprot) << "\n"; else { - if (maxprot & MachO::VM_PROT_READ) - outs() << " maxprot r"; - else - outs() << " maxprot -"; - if (maxprot & MachO::VM_PROT_WRITE) - outs() << "w"; - else - outs() << "-"; - if (maxprot & MachO::VM_PROT_EXECUTE) - outs() << "x\n"; - else - outs() << "-\n"; + outs() << " maxprot "; + outs() << ((maxprot & MachO::VM_PROT_READ) ? "r" : "-"); + outs() << ((maxprot & MachO::VM_PROT_WRITE) ? "w" : "-"); + outs() << ((maxprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n"); } if ((initprot & ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE)) != 0) outs() << " initprot ?" << format("0x%08" PRIx32, initprot) << "\n"; else { - if (initprot & MachO::VM_PROT_READ) - outs() << " initprot r"; - else - outs() << " initprot -"; - if (initprot & MachO::VM_PROT_WRITE) - outs() << "w"; - else - outs() << "-"; - if (initprot & MachO::VM_PROT_EXECUTE) - outs() << "x\n"; - else - outs() << "-\n"; + outs() << " initprot "; + outs() << ((initprot & MachO::VM_PROT_READ) ? "r" : "-"); + outs() << ((initprot & MachO::VM_PROT_WRITE) ? "w" : "-"); + outs() << ((initprot & MachO::VM_PROT_EXECUTE) ? "x\n" : "-\n"); } } else { outs() << " maxprot " << format("0x%08" PRIx32, maxprot) << "\n"; @@ -7611,26 +7817,11 @@ static void PrintUuidLoadCommand(MachO::uuid_command uuid) { else outs() << "\n"; outs() << " uuid "; - outs() << format("%02" PRIX32, uuid.uuid[0]); - outs() << format("%02" PRIX32, uuid.uuid[1]); - outs() << format("%02" PRIX32, uuid.uuid[2]); - outs() << format("%02" PRIX32, uuid.uuid[3]); - outs() << "-"; - outs() << format("%02" PRIX32, uuid.uuid[4]); - outs() << format("%02" PRIX32, uuid.uuid[5]); - outs() << "-"; - outs() << format("%02" PRIX32, uuid.uuid[6]); - outs() << format("%02" PRIX32, uuid.uuid[7]); - outs() << "-"; - outs() << format("%02" PRIX32, uuid.uuid[8]); - outs() << format("%02" PRIX32, uuid.uuid[9]); - outs() << "-"; - outs() << format("%02" PRIX32, uuid.uuid[10]); - outs() << format("%02" PRIX32, uuid.uuid[11]); - outs() << format("%02" PRIX32, uuid.uuid[12]); - outs() << format("%02" PRIX32, uuid.uuid[13]); - outs() << format("%02" PRIX32, uuid.uuid[14]); - outs() << format("%02" PRIX32, uuid.uuid[15]); + for (int i = 0; i < 16; ++i) { + outs() << format("%02" PRIX32, uuid.uuid[i]); + if (i == 3 || i == 5 || i == 7 || i == 9) + outs() << "-"; + } outs() << "\n"; } @@ -7650,30 +7841,47 @@ static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) { } static void PrintVersionMinLoadCommand(MachO::version_min_command vd) { - if (vd.cmd == MachO::LC_VERSION_MIN_MACOSX) - outs() << " cmd LC_VERSION_MIN_MACOSX\n"; - else if (vd.cmd == MachO::LC_VERSION_MIN_IPHONEOS) - outs() << " cmd LC_VERSION_MIN_IPHONEOS\n"; - else - outs() << " cmd " << vd.cmd << " (?)\n"; + StringRef LoadCmdName; + switch (vd.cmd) { + case MachO::LC_VERSION_MIN_MACOSX: + LoadCmdName = "LC_VERSION_MIN_MACOSX"; + break; + case MachO::LC_VERSION_MIN_IPHONEOS: + LoadCmdName = "LC_VERSION_MIN_IPHONEOS"; + break; + case MachO::LC_VERSION_MIN_TVOS: + LoadCmdName = "LC_VERSION_MIN_TVOS"; + break; + case MachO::LC_VERSION_MIN_WATCHOS: + LoadCmdName = "LC_VERSION_MIN_WATCHOS"; + break; + default: + llvm_unreachable("Unknown version min load command"); + } + + outs() << " cmd " << LoadCmdName << '\n'; outs() << " cmdsize " << vd.cmdsize; if (vd.cmdsize != sizeof(struct MachO::version_min_command)) outs() << " Incorrect size\n"; else outs() << "\n"; - outs() << " version " << ((vd.version >> 16) & 0xffff) << "." - << ((vd.version >> 8) & 0xff); - if ((vd.version & 0xff) != 0) - outs() << "." << (vd.version & 0xff); + outs() << " version " + << MachOObjectFile::getVersionMinMajor(vd, false) << "." + << MachOObjectFile::getVersionMinMinor(vd, false); + uint32_t Update = MachOObjectFile::getVersionMinUpdate(vd, false); + if (Update != 0) + outs() << "." << Update; outs() << "\n"; if (vd.sdk == 0) outs() << " sdk n/a"; else { - outs() << " sdk " << ((vd.sdk >> 16) & 0xffff) << "." - << ((vd.sdk >> 8) & 0xff); + outs() << " sdk " + << MachOObjectFile::getVersionMinMajor(vd, true) << "." + << MachOObjectFile::getVersionMinMinor(vd, true); } - if ((vd.sdk & 0xff) != 0) - outs() << "." << (vd.sdk & 0xff); + Update = MachOObjectFile::getVersionMinUpdate(vd, true); + if (Update != 0) + outs() << "." << Update; outs() << "\n"; } @@ -8366,7 +8574,9 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype, MachO::rpath_command Rpath = Obj->getRpathCommand(Command); PrintRpathLoadCommand(Rpath, Command.Ptr); } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX || - Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS) { + Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS || + Command.C.cmd == MachO::LC_VERSION_MIN_TVOS || + Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) { MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command); PrintVersionMinLoadCommand(Vd); } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) { @@ -8536,6 +8746,7 @@ public: StringRef segmentName(uint32_t SegIndex); StringRef sectionName(uint32_t SegIndex, uint64_t SegOffset); uint64_t address(uint32_t SegIndex, uint64_t SegOffset); + bool isValidSegIndexAndOffset(uint32_t SegIndex, uint64_t SegOffset); private: struct SectionInfo { @@ -8559,8 +8770,7 @@ SegInfo::SegInfo(const object::MachOObjectFile *Obj) { uint64_t CurSegAddress; for (const SectionRef &Section : Obj->sections()) { SectionInfo Info; - if (error(Section.getName(Info.SectionName))) - return; + error(Section.getName(Info.SectionName)); Info.Address = Section.getAddress(); Info.Size = Section.getSize(); Info.SegmentName = @@ -8585,6 +8795,20 @@ StringRef SegInfo::segmentName(uint32_t SegIndex) { llvm_unreachable("invalid segIndex"); } +bool SegInfo::isValidSegIndexAndOffset(uint32_t SegIndex, + uint64_t OffsetInSeg) { + for (const SectionInfo &SI : Sections) { + if (SI.SegmentIndex != SegIndex) + continue; + if (SI.OffsetInSegment > OffsetInSeg) + continue; + if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size)) + continue; + return true; + } + return false; +} + const SegInfo::SectionInfo &SegInfo::findSection(uint32_t SegIndex, uint64_t OffsetInSeg) { for (const SectionInfo &SI : Sections) { @@ -8753,6 +8977,8 @@ static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue, for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable()) { uint32_t SegIndex = Entry.segmentIndex(); uint64_t OffsetInSeg = Entry.segmentOffset(); + if (!sectionTable.isValidSegIndexAndOffset(SegIndex, OffsetInSeg)) + continue; uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg); const char *SymbolName = nullptr; StringRef name = Entry.symbolName(); diff --git a/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp b/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp index 275eb9c..22167c7 100644 --- a/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -73,6 +73,13 @@ Disassembled("d", cl::desc("Alias for --disassemble"), cl::aliasopt(Disassemble)); cl::opt<bool> +llvm::DisassembleAll("disassemble-all", + cl::desc("Display assembler mnemonics for the machine instructions")); +static cl::alias +DisassembleAlld("D", cl::desc("Alias for --disassemble-all"), + cl::aliasopt(DisassembleAll)); + +cl::opt<bool> llvm::Relocations("r", cl::desc("Display the relocation entries in the file")); cl::opt<bool> @@ -130,6 +137,13 @@ SectionHeadersShorter("h", cl::desc("Alias for --section-headers"), cl::aliasopt(SectionHeaders)); cl::list<std::string> +llvm::FilterSections("section", cl::desc("Operate on the specified sections only. " + "With -macho dump segment,section")); +cl::alias +static FilterSectionsj("j", cl::desc("Alias for --section"), + cl::aliasopt(llvm::FilterSections)); + +cl::list<std::string> llvm::MAttrs("mattr", cl::CommaSeparated, cl::desc("Target specific attributes"), @@ -163,22 +177,86 @@ cl::opt<bool> PrintFaultMaps("fault-map-section", cl::desc("Display contents of faultmap section")); static StringRef ToolName; -static int ReturnValue = EXIT_SUCCESS; -bool llvm::error(std::error_code EC) { +namespace { +typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate; + +class SectionFilterIterator { +public: + SectionFilterIterator(FilterPredicate P, + llvm::object::section_iterator const &I, + llvm::object::section_iterator const &E) + : Predicate(P), Iterator(I), End(E) { + ScanPredicate(); + } + const llvm::object::SectionRef &operator*() const { return *Iterator; } + SectionFilterIterator &operator++() { + ++Iterator; + ScanPredicate(); + return *this; + } + bool operator!=(SectionFilterIterator const &Other) const { + return Iterator != Other.Iterator; + } + +private: + void ScanPredicate() { + while (Iterator != End && !Predicate(*Iterator)) { + ++Iterator; + } + } + FilterPredicate Predicate; + llvm::object::section_iterator Iterator; + llvm::object::section_iterator End; +}; + +class SectionFilter { +public: + SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O) + : Predicate(P), Object(O) {} + SectionFilterIterator begin() { + return SectionFilterIterator(Predicate, Object.section_begin(), + Object.section_end()); + } + SectionFilterIterator end() { + return SectionFilterIterator(Predicate, Object.section_end(), + Object.section_end()); + } + +private: + FilterPredicate Predicate; + llvm::object::ObjectFile const &Object; +}; +SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O) { + return SectionFilter([](llvm::object::SectionRef const &S) { + if(FilterSections.empty()) + return true; + llvm::StringRef String; + std::error_code error = S.getName(String); + if (error) + return false; + return std::find(FilterSections.begin(), + FilterSections.end(), + String) != FilterSections.end(); + }, + O); +} +} + +void llvm::error(std::error_code EC) { if (!EC) - return false; + return; - outs() << ToolName << ": error reading file: " << EC.message() << ".\n"; - outs().flush(); - ReturnValue = EXIT_FAILURE; - return true; + errs() << ToolName << ": error reading file: " << EC.message() << ".\n"; + errs().flush(); + exit(1); } -static void report_error(StringRef File, std::error_code EC) { +LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File, + std::error_code EC) { assert(EC); errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n"; - ReturnValue = EXIT_FAILURE; + exit(1); } static const Target *getTarget(const ObjectFile *Obj = nullptr) { @@ -205,10 +283,8 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) { std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple, Error); - if (!TheTarget) { - errs() << ToolName << ": " << Error; - return nullptr; - } + if (!TheTarget) + report_fatal_error("can't find target: " + Error); // Update the triple name and return the found target. TripleName = TheTriple.getTriple(); @@ -301,11 +377,12 @@ PrettyPrinter &selectPrettyPrinter(Triple const &Triple) { template <class ELFT> static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj, - DataRefImpl Rel, + const RelocationRef &RelRef, SmallVectorImpl<char> &Result) { + DataRefImpl Rel = RelRef.getRawDataRefImpl(); + typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename ELFObjectFile<ELFT>::Elf_Rel Elf_Rel; typedef typename ELFObjectFile<ELFT>::Elf_Rela Elf_Rela; const ELFFile<ELFT> &EF = *Obj->getELFFile(); @@ -327,36 +404,31 @@ static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj, if (std::error_code EC = StrTabOrErr.getError()) return EC; StringRef StrTab = *StrTabOrErr; - uint8_t type; + uint8_t type = RelRef.getType(); StringRef res; int64_t addend = 0; - uint16_t symbol_index = 0; switch (Sec->sh_type) { default: return object_error::parse_failed; case ELF::SHT_REL: { - const Elf_Rel *ERel = Obj->getRel(Rel); - type = ERel->getType(EF.isMips64EL()); - symbol_index = ERel->getSymbol(EF.isMips64EL()); // TODO: Read implicit addend from section data. break; } case ELF::SHT_RELA: { const Elf_Rela *ERela = Obj->getRela(Rel); - type = ERela->getType(EF.isMips64EL()); - symbol_index = ERela->getSymbol(EF.isMips64EL()); addend = ERela->r_addend; break; } } - const Elf_Sym *symb = - EF.template getEntry<Elf_Sym>(Sec->sh_link, symbol_index); + symbol_iterator SI = RelRef.getSymbol(); + const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl()); StringRef Target; - ErrorOr<const Elf_Shdr *> SymSec = EF.getSection(symb); - if (std::error_code EC = SymSec.getError()) - return EC; if (symb->getType() == ELF::STT_SECTION) { - ErrorOr<StringRef> SecName = EF.getSectionName(*SymSec); + ErrorOr<section_iterator> SymSI = SI->getSection(); + if (std::error_code EC = SymSI.getError()) + return EC; + const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl()); + ErrorOr<StringRef> SecName = EF.getSectionName(SymSec); if (std::error_code EC = SecName.getError()) return EC; Target = *SecName; @@ -404,6 +476,7 @@ static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj, break; } case ELF::EM_386: + case ELF::EM_IAMCU: case ELF::EM_ARM: case ELF::EM_HEXAGON: case ELF::EM_MIPS: @@ -418,9 +491,8 @@ static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj, } static std::error_code getRelocationValueString(const ELFObjectFileBase *Obj, - const RelocationRef &RelRef, + const RelocationRef &Rel, SmallVectorImpl<char> &Result) { - DataRefImpl Rel = RelRef.getRawDataRefImpl(); if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj)) return getRelocationValueString(ELF32LE, Rel, Result); if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj)) @@ -471,7 +543,7 @@ static void printRelocationTargetName(const MachOObjectFile *O, // If we couldn't find a symbol that this relocation refers to, try // to find a section beginning instead. - for (const SectionRef &Section : O->sections()) { + for (const SectionRef &Section : ToolSectionFilter(*O)) { std::error_code ec; StringRef Name; @@ -496,8 +568,8 @@ static void printRelocationTargetName(const MachOObjectFile *O, symbol_iterator SI = O->symbol_begin(); advance(SI, Val); ErrorOr<StringRef> SOrErr = SI->getName(); - if (!error(SOrErr.getError())) - S = *SOrErr; + error(SOrErr.getError()); + S = *SOrErr; } else { section_iterator SI = O->section_begin(); // Adjust for the fact that sections are 1-indexed. @@ -732,10 +804,6 @@ static bool getHidden(RelocationRef RelRef) { static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { const Target *TheTarget = getTarget(Obj); - // getTarget() will have already issued a diagnostic if necessary, so - // just bail here if it failed. - if (!TheTarget) - return; // Package up features to be passed to target/subtarget std::string FeaturesStr; @@ -748,42 +816,28 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { std::unique_ptr<const MCRegisterInfo> MRI( TheTarget->createMCRegInfo(TripleName)); - if (!MRI) { - errs() << "error: no register info for target " << TripleName << "\n"; - return; - } + if (!MRI) + report_fatal_error("error: no register info for target " + TripleName); // Set up disassembler. std::unique_ptr<const MCAsmInfo> AsmInfo( TheTarget->createMCAsmInfo(*MRI, TripleName)); - if (!AsmInfo) { - errs() << "error: no assembly info for target " << TripleName << "\n"; - return; - } - + if (!AsmInfo) + report_fatal_error("error: no assembly info for target " + TripleName); std::unique_ptr<const MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); - if (!STI) { - errs() << "error: no subtarget info for target " << TripleName << "\n"; - return; - } - + if (!STI) + report_fatal_error("error: no subtarget info for target " + TripleName); std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo()); - if (!MII) { - errs() << "error: no instruction info for target " << TripleName << "\n"; - return; - } - + if (!MII) + report_fatal_error("error: no instruction info for target " + TripleName); std::unique_ptr<const MCObjectFileInfo> MOFI(new MCObjectFileInfo); MCContext Ctx(AsmInfo.get(), MRI.get(), MOFI.get()); std::unique_ptr<MCDisassembler> DisAsm( TheTarget->createMCDisassembler(*STI, Ctx)); - - if (!DisAsm) { - errs() << "error: no disassembler for target " << TripleName << "\n"; - return; - } + if (!DisAsm) + report_fatal_error("error: no disassembler for target " + TripleName); std::unique_ptr<const MCInstrAnalysis> MIA( TheTarget->createMCInstrAnalysis(MII.get())); @@ -791,11 +845,9 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI)); - if (!IP) { - errs() << "error: no instruction printer for target " << TripleName - << '\n'; - return; - } + if (!IP) + report_fatal_error("error: no instruction printer for target " + + TripleName); IP->setPrintImmHex(PrintImmHex); PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName)); @@ -806,38 +858,75 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // in RelocSecs contain the relocations for section S. std::error_code EC; std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap; - for (const SectionRef &Section : Obj->sections()) { + for (const SectionRef &Section : ToolSectionFilter(*Obj)) { section_iterator Sec2 = Section.getRelocatedSection(); if (Sec2 != Obj->section_end()) SectionRelocMap[*Sec2].push_back(Section); } // Create a mapping from virtual address to symbol name. This is used to - // pretty print the target of a call. - std::vector<std::pair<uint64_t, StringRef>> AllSymbols; - if (MIA) { - for (const SymbolRef &Symbol : Obj->symbols()) { - if (Symbol.getType() != SymbolRef::ST_Function) - continue; + // pretty print the symbols while disassembling. + typedef std::vector<std::pair<uint64_t, StringRef>> SectionSymbolsTy; + std::map<SectionRef, SectionSymbolsTy> AllSymbols; + for (const SymbolRef &Symbol : Obj->symbols()) { + ErrorOr<uint64_t> AddressOrErr = Symbol.getAddress(); + error(AddressOrErr.getError()); + uint64_t Address = *AddressOrErr; + + ErrorOr<StringRef> Name = Symbol.getName(); + error(Name.getError()); + if (Name->empty()) + continue; - ErrorOr<uint64_t> AddressOrErr = Symbol.getAddress(); - if (error(AddressOrErr.getError())) - break; - uint64_t Address = *AddressOrErr; + ErrorOr<section_iterator> SectionOrErr = Symbol.getSection(); + error(SectionOrErr.getError()); + section_iterator SecI = *SectionOrErr; + if (SecI == Obj->section_end()) + continue; - ErrorOr<StringRef> Name = Symbol.getName(); - if (error(Name.getError())) - break; - if (Name->empty()) + AllSymbols[*SecI].emplace_back(Address, *Name); + } + + // Create a mapping from virtual address to section. + std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses; + for (SectionRef Sec : Obj->sections()) + SectionAddresses.emplace_back(Sec.getAddress(), Sec); + array_pod_sort(SectionAddresses.begin(), SectionAddresses.end()); + + // Linked executables (.exe and .dll files) typically don't include a real + // symbol table but they might contain an export table. + if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) { + for (const auto &ExportEntry : COFFObj->export_directories()) { + StringRef Name; + error(ExportEntry.getSymbolName(Name)); + if (Name.empty()) continue; - AllSymbols.push_back(std::make_pair(Address, *Name)); - } + uint32_t RVA; + error(ExportEntry.getExportRVA(RVA)); + + uint64_t VA = COFFObj->getImageBase() + RVA; + auto Sec = std::upper_bound( + SectionAddresses.begin(), SectionAddresses.end(), VA, + [](uint64_t LHS, const std::pair<uint64_t, SectionRef> &RHS) { + return LHS < RHS.first; + }); + if (Sec != SectionAddresses.begin()) + --Sec; + else + Sec = SectionAddresses.end(); - array_pod_sort(AllSymbols.begin(), AllSymbols.end()); + if (Sec != SectionAddresses.end()) + AllSymbols[Sec->second].emplace_back(VA, Name); + } } - for (const SectionRef &Section : Obj->sections()) { - if (!Section.isText() || Section.isVirtual()) + // Sort all the symbols, this allows us to use a simple binary search to find + // a symbol near an address. + for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) + array_pod_sort(SecSyms.second.begin(), SecSyms.second.end()); + + for (const SectionRef &Section : ToolSectionFilter(*Obj)) { + if (!DisassembleAll && (!Section.isText() || Section.isVirtual())) continue; uint64_t SectionAddr = Section.getAddress(); @@ -845,27 +934,23 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (!SectSize) continue; - // Make a list of all the symbols in this section. - std::vector<std::pair<uint64_t, StringRef>> Symbols; - for (const SymbolRef &Symbol : Obj->symbols()) { - if (Section.containsSymbol(Symbol)) { - ErrorOr<uint64_t> AddressOrErr = Symbol.getAddress(); - if (error(AddressOrErr.getError())) - break; - uint64_t Address = *AddressOrErr; - Address -= SectionAddr; - if (Address >= SectSize) - continue; - - ErrorOr<StringRef> Name = Symbol.getName(); - if (error(Name.getError())) - break; - Symbols.push_back(std::make_pair(Address, *Name)); + // Get the list of all the symbols in this section. + SectionSymbolsTy &Symbols = AllSymbols[Section]; + std::vector<uint64_t> DataMappingSymsAddr; + std::vector<uint64_t> TextMappingSymsAddr; + if (Obj->isELF() && Obj->getArch() == Triple::aarch64) { + for (const auto &Symb : Symbols) { + uint64_t Address = Symb.first; + StringRef Name = Symb.second; + if (Name.startswith("$d")) + DataMappingSymsAddr.push_back(Address - SectionAddr); + if (Name.startswith("$x")) + TextMappingSymsAddr.push_back(Address - SectionAddr); } } - // Sort the symbols by address, just in case they didn't come in that way. - array_pod_sort(Symbols.begin(), Symbols.end()); + std::sort(DataMappingSymsAddr.begin(), DataMappingSymsAddr.end()); + std::sort(TextMappingSymsAddr.begin(), TextMappingSymsAddr.end()); // Make a list of all the relocations for this section. std::vector<RelocationRef> Rels; @@ -886,8 +971,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { SegmentName = MachO->getSectionFinalSegmentName(DR); } StringRef name; - if (error(Section.getName(name))) - break; + error(Section.getName(name)); outs() << "Disassembly of section "; if (!SegmentName.empty()) outs() << SegmentName << ","; @@ -895,14 +979,13 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // If the section has no symbol at the start, just insert a dummy one. if (Symbols.empty() || Symbols[0].first != 0) - Symbols.insert(Symbols.begin(), std::make_pair(0, name)); + Symbols.insert(Symbols.begin(), std::make_pair(SectionAddr, name)); SmallString<40> Comments; raw_svector_ostream CommentStream(Comments); StringRef BytesStr; - if (error(Section.getContents(BytesStr))) - break; + error(Section.getContents(BytesStr)); ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()), BytesStr.size()); @@ -914,11 +997,16 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // Disassemble symbol by symbol. for (unsigned si = 0, se = Symbols.size(); si != se; ++si) { - uint64_t Start = Symbols[si].first; - // The end is either the section end or the beginning of the next symbol. - uint64_t End = (si == se - 1) ? SectSize : Symbols[si + 1].first; + uint64_t Start = Symbols[si].first - SectionAddr; + // The end is either the section end or the beginning of the next + // symbol. + uint64_t End = + (si == se - 1) ? SectSize : Symbols[si + 1].first - SectionAddr; + // Don't try to disassemble beyond the end of section contents. + if (End > SectSize) + End = SectSize; // If this symbol has the same address as the next symbol, then skip it. - if (Start == End) + if (Start >= End) continue; outs() << '\n' << Symbols[si].second << ":\n"; @@ -932,6 +1020,45 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { for (Index = Start; Index < End; Index += Size) { MCInst Inst; + // AArch64 ELF binaries can interleave data and text in the + // same section. We rely on the markers introduced to + // understand what we need to dump. + if (Obj->isELF() && Obj->getArch() == Triple::aarch64) { + uint64_t Stride = 0; + + auto DAI = std::lower_bound(DataMappingSymsAddr.begin(), + DataMappingSymsAddr.end(), Index); + if (DAI != DataMappingSymsAddr.end() && *DAI == Index) { + // Switch to data. + while (Index < End) { + outs() << format("%8" PRIx64 ":", SectionAddr + Index); + outs() << "\t"; + if (Index + 4 <= End) { + Stride = 4; + dumpBytes(Bytes.slice(Index, 4), outs()); + outs() << "\t.word"; + } else if (Index + 2 <= End) { + Stride = 2; + dumpBytes(Bytes.slice(Index, 2), outs()); + outs() << "\t.short"; + } else { + Stride = 1; + dumpBytes(Bytes.slice(Index, 1), outs()); + outs() << "\t.byte"; + } + Index += Stride; + outs() << "\n"; + auto TAI = std::lower_bound(TextMappingSymsAddr.begin(), + TextMappingSymsAddr.end(), Index); + if (TAI != TextMappingSymsAddr.end() && *TAI == Index) + break; + } + } + } + + if (Index >= End) + break; + if (DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), SectionAddr + Index, DebugOut, CommentStream)) { @@ -940,26 +1067,55 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { SectionAddr + Index, outs(), "", *STI); outs() << CommentStream.str(); Comments.clear(); + + // Try to resolve the target of a call, tail call, etc. to a specific + // symbol. if (MIA && (MIA->isCall(Inst) || MIA->isUnconditionalBranch(Inst) || MIA->isConditionalBranch(Inst))) { uint64_t Target; if (MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target)) { - auto TargetSym = std::upper_bound( - AllSymbols.begin(), AllSymbols.end(), Target, - [](uint64_t LHS, const std::pair<uint64_t, StringRef> &RHS) { - return LHS < RHS.first; - }); - if (TargetSym != AllSymbols.begin()) - --TargetSym; - else - TargetSym = AllSymbols.end(); - - if (TargetSym != AllSymbols.end()) { - outs() << " <" << TargetSym->second; - uint64_t Disp = Target - TargetSym->first; - if (Disp) - outs() << '+' << utohexstr(Disp); - outs() << '>'; + // In a relocatable object, the target's section must reside in + // the same section as the call instruction or it is accessed + // through a relocation. + // + // In a non-relocatable object, the target may be in any section. + // + // N.B. We don't walk the relocations in the relocatable case yet. + auto *TargetSectionSymbols = &Symbols; + if (!Obj->isRelocatableObject()) { + auto SectionAddress = std::upper_bound( + SectionAddresses.begin(), SectionAddresses.end(), Target, + [](uint64_t LHS, + const std::pair<uint64_t, SectionRef> &RHS) { + return LHS < RHS.first; + }); + if (SectionAddress != SectionAddresses.begin()) { + --SectionAddress; + TargetSectionSymbols = &AllSymbols[SectionAddress->second]; + } else { + TargetSectionSymbols = nullptr; + } + } + + // Find the first symbol in the section whose offset is less than + // or equal to the target. + if (TargetSectionSymbols) { + auto TargetSym = std::upper_bound( + TargetSectionSymbols->begin(), TargetSectionSymbols->end(), + Target, [](uint64_t LHS, + const std::pair<uint64_t, StringRef> &RHS) { + return LHS < RHS.first; + }); + if (TargetSym != TargetSectionSymbols->begin()) { + --TargetSym; + uint64_t TargetAddress = std::get<0>(*TargetSym); + StringRef TargetName = std::get<1>(*TargetSym); + outs() << " <" << TargetName; + uint64_t Disp = Target - TargetAddress; + if (Disp) + outs() << '+' << utohexstr(Disp); + outs() << '>'; + } } } } @@ -983,8 +1139,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // Stop when rel_cur's address is past the current instruction. if (addr >= Index + Size) break; rel_cur->getTypeName(name); - if (error(getRelocationValueString(*rel_cur, val))) - goto skip_print_rel; + error(getRelocationValueString(*rel_cur, val)); outs() << format(Fmt.data(), SectionAddr + addr) << name << "\t" << val << "\n"; @@ -1004,12 +1159,11 @@ void llvm::PrintRelocations(const ObjectFile *Obj) { if (!Obj->isRelocatableObject()) return; - for (const SectionRef &Section : Obj->sections()) { + for (const SectionRef &Section : ToolSectionFilter(*Obj)) { if (Section.relocation_begin() == Section.relocation_end()) continue; StringRef secname; - if (error(Section.getName(secname))) - continue; + error(Section.getName(secname)); outs() << "RELOCATION RECORDS FOR [" << secname << "]:\n"; for (const RelocationRef &Reloc : Section.relocations()) { bool hidden = getHidden(Reloc); @@ -1019,8 +1173,7 @@ void llvm::PrintRelocations(const ObjectFile *Obj) { if (hidden) continue; Reloc.getTypeName(relocname); - if (error(getRelocationValueString(Reloc, valuestr))) - continue; + error(getRelocationValueString(Reloc, valuestr)); outs() << format(Fmt.data(), address) << " " << relocname << " " << valuestr << "\n"; } @@ -1032,10 +1185,9 @@ void llvm::PrintSectionHeaders(const ObjectFile *Obj) { outs() << "Sections:\n" "Idx Name Size Address Type\n"; unsigned i = 0; - for (const SectionRef &Section : Obj->sections()) { + for (const SectionRef &Section : ToolSectionFilter(*Obj)) { StringRef Name; - if (error(Section.getName(Name))) - return; + error(Section.getName(Name)); uint64_t Address = Section.getAddress(); uint64_t Size = Section.getSize(); bool Text = Section.isText(); @@ -1051,11 +1203,10 @@ void llvm::PrintSectionHeaders(const ObjectFile *Obj) { void llvm::PrintSectionContents(const ObjectFile *Obj) { std::error_code EC; - for (const SectionRef &Section : Obj->sections()) { + for (const SectionRef &Section : ToolSectionFilter(*Obj)) { StringRef Name; StringRef Contents; - if (error(Section.getName(Name))) - continue; + error(Section.getName(Name)); uint64_t BaseAddr = Section.getAddress(); uint64_t Size = Section.getSize(); if (!Size) @@ -1069,8 +1220,7 @@ void llvm::PrintSectionContents(const ObjectFile *Obj) { continue; } - if (error(Section.getContents(Contents))) - continue; + error(Section.getContents(Contents)); // Dump out the content as hex and printable ascii characters. for (std::size_t addr = 0, end = Contents.size(); addr < end; addr += 16) { @@ -1098,84 +1248,28 @@ void llvm::PrintSectionContents(const ObjectFile *Obj) { } } -static void PrintCOFFSymbolTable(const COFFObjectFile *coff) { - for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) { - ErrorOr<COFFSymbolRef> Symbol = coff->getSymbol(SI); - StringRef Name; - if (error(Symbol.getError())) - return; - - if (error(coff->getSymbolName(*Symbol, Name))) - return; - - outs() << "[" << format("%2d", SI) << "]" - << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")" - << "(fl 0x00)" // Flag bits, which COFF doesn't have. - << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")" - << "(scl " << format("%3x", unsigned(Symbol->getStorageClass())) << ") " - << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") " - << "0x" << format("%08x", unsigned(Symbol->getValue())) << " " - << Name << "\n"; - - for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) { - if (Symbol->isSectionDefinition()) { - const coff_aux_section_definition *asd; - if (error(coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd))) - return; - - int32_t AuxNumber = asd->getNumber(Symbol->isBigObj()); - - outs() << "AUX " - << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x " - , unsigned(asd->Length) - , unsigned(asd->NumberOfRelocations) - , unsigned(asd->NumberOfLinenumbers) - , unsigned(asd->CheckSum)) - << format("assoc %d comdat %d\n" - , unsigned(AuxNumber) - , unsigned(asd->Selection)); - } else if (Symbol->isFileRecord()) { - const char *FileName; - if (error(coff->getAuxSymbol<char>(SI + 1, FileName))) - return; - - StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() * - coff->getSymbolTableEntrySize()); - outs() << "AUX " << Name.rtrim(StringRef("\0", 1)) << '\n'; - - SI = SI + Symbol->getNumberOfAuxSymbols(); - break; - } else { - outs() << "AUX Unknown\n"; - } - } - } -} - void llvm::PrintSymbolTable(const ObjectFile *o) { outs() << "SYMBOL TABLE:\n"; if (const COFFObjectFile *coff = dyn_cast<const COFFObjectFile>(o)) { - PrintCOFFSymbolTable(coff); + printCOFFSymbolTable(coff); return; } for (const SymbolRef &Symbol : o->symbols()) { ErrorOr<uint64_t> AddressOrError = Symbol.getAddress(); - if (error(AddressOrError.getError())) - continue; + error(AddressOrError.getError()); uint64_t Address = *AddressOrError; SymbolRef::Type Type = Symbol.getType(); uint32_t Flags = Symbol.getFlags(); - section_iterator Section = o->section_end(); - if (error(Symbol.getSection(Section))) - continue; + ErrorOr<section_iterator> SectionOrErr = Symbol.getSection(); + error(SectionOrErr.getError()); + section_iterator Section = *SectionOrErr; StringRef Name; if (Type == SymbolRef::ST_Debug && Section != o->section_end()) { Section->getName(Name); } else { ErrorOr<StringRef> NameOrErr = Symbol.getName(); - if (error(NameOrErr.getError())) - continue; + error(NameOrErr.getError()); Name = *NameOrErr; } @@ -1222,8 +1316,7 @@ void llvm::PrintSymbolTable(const ObjectFile *o) { outs() << SegmentName << ","; } StringRef SectionName; - if (error(Section->getName(SectionName))) - SectionName = ""; + error(Section->getName(SectionName)); outs() << SectionName; } @@ -1329,7 +1422,7 @@ void llvm::printRawClangAST(const ObjectFile *Obj) { } Optional<object::SectionRef> ClangASTSection; - for (auto Sec : Obj->sections()) { + for (auto Sec : ToolSectionFilter(*Obj)) { StringRef Name; Sec.getName(Name); if (Name == ClangASTSectionName) { @@ -1341,11 +1434,7 @@ void llvm::printRawClangAST(const ObjectFile *Obj) { return; StringRef ClangASTContents; - if (error(ClangASTSection.getValue().getContents(ClangASTContents))) { - errs() << "Could not read the " << ClangASTSectionName << " section!\n"; - return; - } - + error(ClangASTSection.getValue().getContents(ClangASTContents)); outs().write(ClangASTContents.data(), ClangASTContents.size()); } @@ -1364,7 +1453,7 @@ static void printFaultMaps(const ObjectFile *Obj) { Optional<object::SectionRef> FaultMapSection; - for (auto Sec : Obj->sections()) { + for (auto Sec : ToolSectionFilter(*Obj)) { StringRef Name; Sec.getName(Name); if (Name == FaultMapSectionName) { @@ -1381,10 +1470,7 @@ static void printFaultMaps(const ObjectFile *Obj) { } StringRef FaultMapContents; - if (error(FaultMapSection.getValue().getContents(FaultMapContents))) { - errs() << "Could not read the " << FaultMapContents << " section!\n"; - return; - } + error(FaultMapSection.getValue().getContents(FaultMapContents)); FaultMapParser FMP(FaultMapContents.bytes_begin(), FaultMapContents.bytes_end()); @@ -1393,13 +1479,14 @@ static void printFaultMaps(const ObjectFile *Obj) { } static void printPrivateFileHeader(const ObjectFile *o) { - if (o->isELF()) { + if (o->isELF()) printELFFileHeader(o); - } else if (o->isCOFF()) { + else if (o->isCOFF()) printCOFFFileHeader(o); - } else if (o->isMachO()) { + else if (o->isMachO()) printMachOFileHeader(o); - } + else + report_fatal_error("Invalid/Unsupported object file format"); } static void DumpObject(const ObjectFile *o) { @@ -1442,15 +1529,14 @@ static void DumpObject(const ObjectFile *o) { /// @brief Dump each object file in \a a; static void DumpArchive(const Archive *a) { - for (Archive::child_iterator i = a->child_begin(), e = a->child_end(); i != e; - ++i) { - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary(); - if (std::error_code EC = ChildOrErr.getError()) { - // Ignore non-object files. + for (auto &ErrorOrChild : a->children()) { + if (std::error_code EC = ErrorOrChild.getError()) + report_error(a->getFileName(), EC); + const Archive::Child &C = *ErrorOrChild; + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) if (EC != object_error::invalid_file_type) report_error(a->getFileName(), EC); - continue; - } if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) DumpObject(o); else @@ -1460,11 +1546,6 @@ static void DumpArchive(const Archive *a) { /// @brief Open file and figure out how to dump it. static void DumpInput(StringRef file) { - // If file isn't stdin, check that it exists. - if (file != "-" && !sys::fs::exists(file)) { - report_error(file, errc::no_such_file_or_directory); - return; - } // If we are using the Mach-O specific object file parser, then let it parse // the file and process the command line options. So the -arch flags can @@ -1476,10 +1557,8 @@ static void DumpInput(StringRef file) { // Attempt to open the binary. ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(file); - if (std::error_code EC = BinaryOrErr.getError()) { + if (std::error_code EC = BinaryOrErr.getError()) report_error(file, EC); - return; - } Binary &Binary = *BinaryOrErr.get().getBinary(); if (Archive *a = dyn_cast<Archive>(&Binary)) @@ -1499,7 +1578,6 @@ int main(int argc, char **argv) { // Initialize targets and assembly printers/parsers. llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmParsers(); llvm::InitializeAllDisassemblers(); // Register the target printer for --version. @@ -1514,6 +1592,8 @@ int main(int argc, char **argv) { if (InputFilenames.size() == 0) InputFilenames.push_back("a.out"); + if (DisassembleAll) + Disassemble = true; if (!Disassemble && !Relocations && !SectionHeaders @@ -1536,7 +1616,7 @@ int main(int argc, char **argv) { && !(DylibsUsed && MachOOpt) && !(DylibId && MachOOpt) && !(ObjcMetaData && MachOOpt) - && !(DumpSections.size() != 0 && MachOOpt) + && !(FilterSections.size() != 0 && MachOOpt) && !PrintFaultMaps) { cl::PrintHelpMessage(); return 2; @@ -1545,5 +1625,5 @@ int main(int argc, char **argv) { std::for_each(InputFilenames.begin(), InputFilenames.end(), DumpInput); - return ReturnValue; + return EXIT_SUCCESS; } diff --git a/contrib/llvm/tools/llvm-objdump/llvm-objdump.h b/contrib/llvm/tools/llvm-objdump/llvm-objdump.h index eb10d83..6e8ad6b 100644 --- a/contrib/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/contrib/llvm/tools/llvm-objdump/llvm-objdump.h @@ -11,6 +11,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" namespace llvm { @@ -25,8 +26,9 @@ extern cl::opt<std::string> TripleName; extern cl::opt<std::string> ArchName; extern cl::opt<std::string> MCPU; extern cl::list<std::string> MAttrs; -extern cl::list<std::string> DumpSections; +extern cl::list<std::string> FilterSections; extern cl::opt<bool> Disassemble; +extern cl::opt<bool> DisassembleAll; extern cl::opt<bool> NoShowRawInsn; extern cl::opt<bool> PrivateHeaders; extern cl::opt<bool> ExportsTrie; @@ -54,7 +56,7 @@ extern cl::opt<bool> UnwindInfo; extern cl::opt<bool> PrintImmHex; // Various helper functions. -bool error(std::error_code ec); +void error(std::error_code ec); bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b); void ParseInputMachO(StringRef Filename); void printCOFFUnwindInfo(const object::COFFObjectFile* o); @@ -66,6 +68,7 @@ void printMachOLazyBindTable(const object::MachOObjectFile* o); void printMachOWeakBindTable(const object::MachOObjectFile* o); void printELFFileHeader(const object::ObjectFile *o); void printCOFFFileHeader(const object::ObjectFile *o); +void printCOFFSymbolTable(const object::COFFObjectFile *o); void printMachOFileHeader(const object::ObjectFile *o); void printExportsTrie(const object::ObjectFile *o); void printRebaseTable(const object::ObjectFile *o); @@ -77,6 +80,7 @@ void PrintRelocations(const object::ObjectFile *o); void PrintSectionHeaders(const object::ObjectFile *o); void PrintSectionContents(const object::ObjectFile *o); void PrintSymbolTable(const object::ObjectFile *o); +LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, std::error_code EC); } // end namespace llvm diff --git a/contrib/llvm/tools/llvm-pdbdump/BuiltinDumper.cpp b/contrib/llvm/tools/llvm-pdbdump/BuiltinDumper.cpp index d808298..4327054 100644 --- a/contrib/llvm/tools/llvm-pdbdump/BuiltinDumper.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/BuiltinDumper.cpp @@ -19,69 +19,53 @@ BuiltinDumper::BuiltinDumper(LinePrinter &P) : PDBSymDumper(false), Printer(P) {} void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << getTypeName(Symbol); +} + +StringRef BuiltinDumper::getTypeName(const PDBSymbolTypeBuiltin &Symbol) { PDB_BuiltinType Type = Symbol.getBuiltinType(); switch (Type) { case PDB_BuiltinType::Float: if (Symbol.getLength() == 4) - WithColor(Printer, PDB_ColorItem::Type).get() << "float"; - else - WithColor(Printer, PDB_ColorItem::Type).get() << "double"; - break; + return "float"; + return "double"; case PDB_BuiltinType::UInt: - WithColor(Printer, PDB_ColorItem::Type).get() << "unsigned"; if (Symbol.getLength() == 8) - WithColor(Printer, PDB_ColorItem::Type).get() << " __int64"; - break; + return "unsigned __int64"; + return "unsigned"; case PDB_BuiltinType::Int: if (Symbol.getLength() == 4) - WithColor(Printer, PDB_ColorItem::Type).get() << "int"; - else - WithColor(Printer, PDB_ColorItem::Type).get() << "__int64"; - break; + return "int"; + return "__int64"; case PDB_BuiltinType::Char: - WithColor(Printer, PDB_ColorItem::Type).get() << "char"; - break; + return "char"; case PDB_BuiltinType::WCharT: - WithColor(Printer, PDB_ColorItem::Type).get() << "wchar_t"; - break; + return "wchar_t"; case PDB_BuiltinType::Void: - WithColor(Printer, PDB_ColorItem::Type).get() << "void"; - break; + return "void"; case PDB_BuiltinType::Long: - WithColor(Printer, PDB_ColorItem::Type).get() << "long"; - break; + return "long"; case PDB_BuiltinType::ULong: - WithColor(Printer, PDB_ColorItem::Type).get() << "unsigned long"; - break; + return "unsigned long"; case PDB_BuiltinType::Bool: - WithColor(Printer, PDB_ColorItem::Type).get() << "bool"; - break; + return "bool"; case PDB_BuiltinType::Currency: - WithColor(Printer, PDB_ColorItem::Type).get() << "CURRENCY"; - break; + return "CURRENCY"; case PDB_BuiltinType::Date: - WithColor(Printer, PDB_ColorItem::Type).get() << "DATE"; - break; + return "DATE"; case PDB_BuiltinType::Variant: - WithColor(Printer, PDB_ColorItem::Type).get() << "VARIANT"; - break; + return "VARIANT"; case PDB_BuiltinType::Complex: - WithColor(Printer, PDB_ColorItem::Type).get() << "complex"; - break; + return "complex"; case PDB_BuiltinType::Bitfield: - WithColor(Printer, PDB_ColorItem::Type).get() << "bitfield"; - break; + return "bitfield"; case PDB_BuiltinType::BSTR: - WithColor(Printer, PDB_ColorItem::Type).get() << "BSTR"; - break; + return "BSTR"; case PDB_BuiltinType::HResult: - WithColor(Printer, PDB_ColorItem::Type).get() << "HRESULT"; - break; + return "HRESULT"; case PDB_BuiltinType::BCD: - WithColor(Printer, PDB_ColorItem::Type).get() << "HRESULT"; - break; + return "HRESULT"; default: - WithColor(Printer, PDB_ColorItem::Type).get() << "void"; - break; + return "void"; } } diff --git a/contrib/llvm/tools/llvm-pdbdump/BuiltinDumper.h b/contrib/llvm/tools/llvm-pdbdump/BuiltinDumper.h index 8cf984a0..ac666db 100644 --- a/contrib/llvm/tools/llvm-pdbdump/BuiltinDumper.h +++ b/contrib/llvm/tools/llvm-pdbdump/BuiltinDumper.h @@ -23,6 +23,8 @@ public: void start(const PDBSymbolTypeBuiltin &Symbol); private: + StringRef getTypeName(const PDBSymbolTypeBuiltin &Symbol); + LinePrinter &Printer; }; } diff --git a/contrib/llvm/tools/llvm-pdbdump/LinePrinter.cpp b/contrib/llvm/tools/llvm-pdbdump/LinePrinter.cpp index 6bbc403..a43727f 100644 --- a/contrib/llvm/tools/llvm-pdbdump/LinePrinter.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/LinePrinter.cpp @@ -11,19 +11,49 @@ #include "llvm-pdbdump.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Regex.h" #include <algorithm> +namespace { +bool IsItemExcluded(llvm::StringRef Item, + std::list<llvm::Regex> &IncludeFilters, + std::list<llvm::Regex> &ExcludeFilters) { + if (Item.empty()) + return false; + + auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); }; + + // Include takes priority over exclude. If the user specified include + // filters, and none of them include this item, them item is gone. + if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred)) + return true; + + if (any_of(ExcludeFilters, match_pred)) + return true; + + return false; +} +} + using namespace llvm; LinePrinter::LinePrinter(int Indent, llvm::raw_ostream &Stream) : OS(Stream), IndentSpaces(Indent), CurrentIndent(0) { - SetFilters(TypeFilters, opts::ExcludeTypes.begin(), opts::ExcludeTypes.end()); - SetFilters(SymbolFilters, opts::ExcludeSymbols.begin(), + SetFilters(ExcludeTypeFilters, opts::ExcludeTypes.begin(), + opts::ExcludeTypes.end()); + SetFilters(ExcludeSymbolFilters, opts::ExcludeSymbols.begin(), opts::ExcludeSymbols.end()); - SetFilters(CompilandFilters, opts::ExcludeCompilands.begin(), + SetFilters(ExcludeCompilandFilters, opts::ExcludeCompilands.begin(), opts::ExcludeCompilands.end()); + + SetFilters(IncludeTypeFilters, opts::IncludeTypes.begin(), + opts::IncludeTypes.end()); + SetFilters(IncludeSymbolFilters, opts::IncludeSymbols.begin(), + opts::IncludeSymbols.end()); + SetFilters(IncludeCompilandFilters, opts::IncludeCompilands.begin(), + opts::IncludeCompilands.end()); } void LinePrinter::Indent() { CurrentIndent += IndentSpaces; } @@ -38,87 +68,53 @@ void LinePrinter::NewLine() { } bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName) { - if (TypeName.empty()) - return false; - - for (auto &Expr : TypeFilters) { - if (Expr.match(TypeName)) - return true; - } - return false; + return IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters); } bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) { - if (SymbolName.empty()) - return false; - - for (auto &Expr : SymbolFilters) { - if (Expr.match(SymbolName)) - return true; - } - return false; + return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters); } bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) { - if (CompilandName.empty()) - return false; - - for (auto &Expr : CompilandFilters) { - if (Expr.match(CompilandName)) - return true; - } - return false; + return IsItemExcluded(CompilandName, IncludeCompilandFilters, + ExcludeCompilandFilters); } WithColor::WithColor(LinePrinter &P, PDB_ColorItem C) : OS(P.OS) { - if (C == PDB_ColorItem::None) - OS.resetColor(); - else { - raw_ostream::Colors Color; - bool Bold; - translateColor(C, Color, Bold); - OS.changeColor(Color, Bold); - } + applyColor(C); } WithColor::~WithColor() { OS.resetColor(); } -void WithColor::translateColor(PDB_ColorItem C, raw_ostream::Colors &Color, - bool &Bold) const { +void WithColor::applyColor(PDB_ColorItem C) { switch (C) { + case PDB_ColorItem::None: + OS.resetColor(); + return; case PDB_ColorItem::Address: - Color = raw_ostream::YELLOW; - Bold = true; + OS.changeColor(raw_ostream::YELLOW, /*bold=*/true); return; case PDB_ColorItem::Keyword: - Color = raw_ostream::MAGENTA; - Bold = true; + OS.changeColor(raw_ostream::MAGENTA, true); return; case PDB_ColorItem::Register: case PDB_ColorItem::Offset: - Color = raw_ostream::YELLOW; - Bold = false; + OS.changeColor(raw_ostream::YELLOW, false); return; case PDB_ColorItem::Type: - Color = raw_ostream::CYAN; - Bold = true; + OS.changeColor(raw_ostream::CYAN, true); return; case PDB_ColorItem::Identifier: - Color = raw_ostream::CYAN; - Bold = false; + OS.changeColor(raw_ostream::CYAN, false); return; case PDB_ColorItem::Path: - Color = raw_ostream::CYAN; - Bold = false; + OS.changeColor(raw_ostream::CYAN, false); return; case PDB_ColorItem::SectionHeader: - Color = raw_ostream::RED; - Bold = true; + OS.changeColor(raw_ostream::RED, true); return; case PDB_ColorItem::LiteralValue: - Color = raw_ostream::GREEN; - Bold = true; - default: + OS.changeColor(raw_ostream::GREEN, true); return; } } diff --git a/contrib/llvm/tools/llvm-pdbdump/LinePrinter.h b/contrib/llvm/tools/llvm-pdbdump/LinePrinter.h index b985e93..b0a9d2c 100644 --- a/contrib/llvm/tools/llvm-pdbdump/LinePrinter.h +++ b/contrib/llvm/tools/llvm-pdbdump/LinePrinter.h @@ -48,9 +48,13 @@ private: int IndentSpaces; int CurrentIndent; - std::list<Regex> CompilandFilters; - std::list<Regex> TypeFilters; - std::list<Regex> SymbolFilters; + std::list<Regex> ExcludeCompilandFilters; + std::list<Regex> ExcludeTypeFilters; + std::list<Regex> ExcludeSymbolFilters; + + std::list<Regex> IncludeCompilandFilters; + std::list<Regex> IncludeTypeFilters; + std::list<Regex> IncludeSymbolFilters; }; template <class T> @@ -80,8 +84,7 @@ public: raw_ostream &get() { return OS; } private: - void translateColor(PDB_ColorItem C, raw_ostream::Colors &Color, - bool &Bold) const; + void applyColor(PDB_ColorItem C); raw_ostream &OS; }; } diff --git a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp index 4a4c64b..0e3f0b2 100644 --- a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -22,6 +22,8 @@ #include "VariableDumper.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" @@ -38,12 +40,16 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" #if defined(HAVE_DIA_SDK) +#ifndef NOMINMAX +#define NOMINMAX +#endif #include <Windows.h> #endif @@ -79,6 +85,17 @@ cl::opt<uint64_t> LoadAddress( cl::desc("Assume the module is loaded at the specified address"), cl::cat(OtherOptions)); +cl::opt<bool> DumpHeaders("dump-headers", cl::desc("dump PDB headers"), + cl::cat(OtherOptions)); +cl::opt<bool> DumpStreamSizes("dump-stream-sizes", + cl::desc("dump PDB stream sizes"), + cl::cat(OtherOptions)); +cl::opt<bool> DumpStreamBlocks("dump-stream-blocks", + cl::desc("dump PDB stream blocks"), + cl::cat(OtherOptions)); +cl::opt<std::string> DumpStreamData("dump-stream", cl::desc("dump stream data"), + cl::cat(OtherOptions)); + cl::list<std::string> ExcludeTypes("exclude-types", cl::desc("Exclude types by regular expression"), @@ -91,6 +108,20 @@ cl::list<std::string> ExcludeCompilands("exclude-compilands", cl::desc("Exclude compilands by regular expression"), cl::ZeroOrMore, cl::cat(FilterCategory)); + +cl::list<std::string> IncludeTypes( + "include-types", + cl::desc("Include only types which match a regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory)); +cl::list<std::string> IncludeSymbols( + "include-symbols", + cl::desc("Include only symbols which match a regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory)); +cl::list<std::string> IncludeCompilands( + "include-compilands", + cl::desc("Include only compilands those which match a regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory)); + cl::opt<bool> ExcludeCompilerGenerated( "no-compiler-generated", cl::desc("Don't show compiler generated types and symbols"), @@ -107,10 +138,264 @@ cl::opt<bool> NoEnumDefs("no-enum-definitions", cl::cat(FilterCategory)); } + +static void reportError(StringRef Input, StringRef Message) { + if (Input == "-") + Input = "<stdin>"; + errs() << Input << ": " << Message << "\n"; + errs().flush(); + exit(1); +} + +static void reportError(StringRef Input, std::error_code EC) { + reportError(Input, EC.message()); +} + +static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, + const uint64_t Size) { + if (Addr + Size < Addr || Addr + Size < Size || + Addr + Size > uintptr_t(M.getBufferEnd()) || + Addr < uintptr_t(M.getBufferStart())) { + return std::make_error_code(std::errc::bad_address); + } + return std::error_code(); +} + +template <typename T> +static std::error_code checkOffset(MemoryBufferRef M, ArrayRef<T> AR) { + return checkOffset(M, uintptr_t(AR.data()), (uint64_t)AR.size() * sizeof(T)); +} + +static std::error_code checkOffset(MemoryBufferRef M, StringRef SR) { + return checkOffset(M, uintptr_t(SR.data()), SR.size()); +} + +// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. +// Returns unexpected_eof if error. +template <typename T> +static std::error_code getObject(const T *&Obj, MemoryBufferRef M, + const void *Ptr, + const uint64_t Size = sizeof(T)) { + uintptr_t Addr = uintptr_t(Ptr); + if (std::error_code EC = checkOffset(M, Addr, Size)) + return EC; + Obj = reinterpret_cast<const T *>(Addr); + return std::error_code(); +} + +static uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) { + return RoundUpToAlignment(NumBytes, BlockSize) / BlockSize; +} + +static uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) { + return BlockNumber * BlockSize; +} + +static void dumpStructure(MemoryBufferRef M) { + const PDB::SuperBlock *SB; + if (auto EC = getObject(SB, M, M.getBufferStart())) + reportError(M.getBufferIdentifier(), EC); + + if (opts::DumpHeaders) { + outs() << "BlockSize: " << SB->BlockSize << '\n'; + outs() << "Unknown0: " << SB->Unknown0 << '\n'; + outs() << "NumBlocks: " << SB->NumBlocks << '\n'; + outs() << "NumDirectoryBytes: " << SB->NumDirectoryBytes << '\n'; + outs() << "Unknown1: " << SB->Unknown1 << '\n'; + outs() << "BlockMapAddr: " << SB->BlockMapAddr << '\n'; + } + + // We don't support blocksizes which aren't a multiple of four bytes. + if (SB->BlockSize % sizeof(support::ulittle32_t) != 0) + reportError(M.getBufferIdentifier(), + std::make_error_code(std::errc::illegal_byte_sequence)); + + // We don't support directories whose sizes aren't a multiple of four bytes. + if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) + reportError(M.getBufferIdentifier(), + std::make_error_code(std::errc::illegal_byte_sequence)); + + // The number of blocks which comprise the directory is a simple function of + // the number of bytes it contains. + uint64_t NumDirectoryBlocks = + bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize); + if (opts::DumpHeaders) + outs() << "NumDirectoryBlocks: " << NumDirectoryBlocks << '\n'; + + // The block map, as we understand it, is a block which consists of a list of + // block numbers. + // It is unclear what would happen if the number of blocks couldn't fit on a + // single block. + if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t)) + reportError(M.getBufferIdentifier(), + std::make_error_code(std::errc::illegal_byte_sequence)); + + + uint64_t BlockMapOffset = (uint64_t)SB->BlockMapAddr * SB->BlockSize; + if (opts::DumpHeaders) + outs() << "BlockMapOffset: " << BlockMapOffset << '\n'; + + // The directory is not contiguous. Instead, the block map contains a + // contiguous list of block numbers whose contents, when concatenated in + // order, make up the directory. + auto DirectoryBlocks = + makeArrayRef(reinterpret_cast<const support::ulittle32_t *>( + M.getBufferStart() + BlockMapOffset), + NumDirectoryBlocks); + if (auto EC = checkOffset(M, DirectoryBlocks)) + reportError(M.getBufferIdentifier(), EC); + + if (opts::DumpHeaders) { + outs() << "DirectoryBlocks: ["; + for (const support::ulittle32_t &DirectoryBlockAddr : DirectoryBlocks) { + if (&DirectoryBlockAddr != &DirectoryBlocks.front()) + outs() << ", "; + outs() << DirectoryBlockAddr; + } + outs() << "]\n"; + } + + bool SeenNumStreams = false; + uint32_t NumStreams = 0; + std::vector<uint32_t> StreamSizes; + DenseMap<uint32_t, std::vector<uint32_t>> StreamMap; + uint32_t StreamIdx = 0; + uint64_t DirectoryBytesRead = 0; + // The structure of the directory is as follows: + // struct PDBDirectory { + // uint32_t NumStreams; + // uint32_t StreamSizes[NumStreams]; + // uint32_t StreamMap[NumStreams][]; + // }; + // + // Empty streams don't consume entries in the StreamMap. + for (uint32_t DirectoryBlockAddr : DirectoryBlocks) { + uint64_t DirectoryBlockOffset = + blockToOffset(DirectoryBlockAddr, SB->BlockSize); + auto DirectoryBlock = + makeArrayRef(reinterpret_cast<const support::ulittle32_t *>( + M.getBufferStart() + DirectoryBlockOffset), + SB->BlockSize / sizeof(support::ulittle32_t)); + if (auto EC = checkOffset(M, DirectoryBlock)) + reportError(M.getBufferIdentifier(), EC); + + // We read data out of the directory four bytes at a time. Depending on + // where we are in the directory, the contents may be: the number of streams + // in the directory, a stream's size, or a block in the stream map. + for (uint32_t Data : DirectoryBlock) { + // Don't read beyond the end of the directory. + if (DirectoryBytesRead == SB->NumDirectoryBytes) + break; + + DirectoryBytesRead += sizeof(Data); + + // This data must be the number of streams if we haven't seen it yet. + if (!SeenNumStreams) { + NumStreams = Data; + SeenNumStreams = true; + continue; + } + // This data must be a stream size if we have not seen them all yet. + if (StreamSizes.size() < NumStreams) { + // It seems like some streams have their set to -1 when their contents + // are not present. Treat them like empty streams for now. + if (Data == UINT32_MAX) + StreamSizes.push_back(0); + else + StreamSizes.push_back(Data); + continue; + } + + // This data must be a stream block number if we have seen all of the + // stream sizes. + std::vector<uint32_t> *StreamBlocks = nullptr; + // Figure out which stream this block number belongs to. + while (StreamIdx < NumStreams) { + uint64_t NumExpectedStreamBlocks = + bytesToBlocks(StreamSizes[StreamIdx], SB->BlockSize); + StreamBlocks = &StreamMap[StreamIdx]; + if (NumExpectedStreamBlocks > StreamBlocks->size()) + break; + ++StreamIdx; + } + // It seems this block doesn't belong to any stream? The stream is either + // corrupt or something more mysterious is going on. + if (StreamIdx == NumStreams) + reportError(M.getBufferIdentifier(), + std::make_error_code(std::errc::illegal_byte_sequence)); + + StreamBlocks->push_back(Data); + } + } + + // We should have read exactly SB->NumDirectoryBytes bytes. + assert(DirectoryBytesRead == SB->NumDirectoryBytes); + + if (opts::DumpHeaders) + outs() << "NumStreams: " << NumStreams << '\n'; + if (opts::DumpStreamSizes) + for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx) + outs() << "StreamSizes[" << StreamIdx << "]: " << StreamSizes[StreamIdx] + << '\n'; + + if (opts::DumpStreamBlocks) { + for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx) { + outs() << "StreamBlocks[" << StreamIdx << "]: ["; + std::vector<uint32_t> &StreamBlocks = StreamMap[StreamIdx]; + for (uint32_t &StreamBlock : StreamBlocks) { + if (&StreamBlock != &StreamBlocks.front()) + outs() << ", "; + outs() << StreamBlock; + } + outs() << "]\n"; + } + } + + StringRef DumpStreamStr = opts::DumpStreamData; + uint32_t DumpStreamNum; + if (!DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum) && + DumpStreamNum < NumStreams) { + uint32_t StreamBytesRead = 0; + uint32_t StreamSize = StreamSizes[DumpStreamNum]; + std::vector<uint32_t> &StreamBlocks = StreamMap[DumpStreamNum]; + for (uint32_t &StreamBlockAddr : StreamBlocks) { + uint64_t StreamBlockOffset = blockToOffset(StreamBlockAddr, SB->BlockSize); + uint32_t BytesLeftToReadInStream = StreamSize - StreamBytesRead; + if (BytesLeftToReadInStream == 0) + break; + + uint32_t BytesToReadInBlock = std::min( + BytesLeftToReadInStream, static_cast<uint32_t>(SB->BlockSize)); + auto StreamBlockData = + StringRef(M.getBufferStart() + StreamBlockOffset, BytesToReadInBlock); + if (auto EC = checkOffset(M, StreamBlockData)) + reportError(M.getBufferIdentifier(), EC); + + outs() << StreamBlockData; + StreamBytesRead += StreamBlockData.size(); + } + } +} + static void dumpInput(StringRef Path) { + if (opts::DumpHeaders || !opts::DumpStreamData.empty()) { + ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = + MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + + if (std::error_code EC = ErrorOrBuffer.getError()) + reportError(Path, EC); + + std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get(); + + dumpStructure(Buffer->getMemBufferRef()); + + outs().flush(); + return; + } + std::unique_ptr<IPDBSession> Session; - PDB_ErrorCode Error = - llvm::loadDataForPDB(PDB_ReaderType::DIA, Path, Session); + PDB_ErrorCode Error = loadDataForPDB(PDB_ReaderType::DIA, Path, Session); switch (Error) { case PDB_ErrorCode::Success: break; @@ -145,7 +430,7 @@ static void dumpInput(StringRef Path) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size"; - if (!llvm::sys::fs::file_size(FileName, FileSize)) { + if (!sys::fs::file_size(FileName, FileSize)) { Printer << ": " << FileSize << " bytes"; } else { Printer << ": (Unable to obtain file size)"; @@ -242,11 +527,11 @@ int main(int argc_, const char *argv_[]) { PrettyStackTraceProgram X(argc_, argv_); SmallVector<const char *, 256> argv; - llvm::SpecificBumpPtrAllocator<char> ArgAllocator; - std::error_code EC = llvm::sys::Process::GetArgumentVector( - argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator); + SpecificBumpPtrAllocator<char> ArgAllocator; + std::error_code EC = sys::Process::GetArgumentVector( + argv, makeArrayRef(argv_, argc_), ArgAllocator); if (EC) { - llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n'; + errs() << "error: couldn't get arguments: " << EC.message() << '\n'; return 1; } diff --git a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h index 586a9ea..cb5bec6 100644 --- a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h @@ -27,6 +27,9 @@ extern llvm::cl::opt<bool> NoEnumDefs; extern llvm::cl::list<std::string> ExcludeTypes; extern llvm::cl::list<std::string> ExcludeSymbols; extern llvm::cl::list<std::string> ExcludeCompilands; +extern llvm::cl::list<std::string> IncludeTypes; +extern llvm::cl::list<std::string> IncludeSymbols; +extern llvm::cl::list<std::string> IncludeCompilands; } #endif
\ No newline at end of file diff --git a/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp b/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp index 6fb48d8..dc6cd0a 100644 --- a/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/LLVMContext.h" #include "llvm/ProfileData/InstrProfReader.h" @@ -18,6 +20,7 @@ #include "llvm/ProfileData/SampleProfReader.h" #include "llvm/ProfileData/SampleProfWriter.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" @@ -26,67 +29,150 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <tuple> using namespace llvm; -static void exitWithError(const Twine &Message, StringRef Whence = "") { +enum ProfileFormat { PF_None = 0, PF_Text, PF_Binary, PF_GCC }; + +static void exitWithError(const Twine &Message, StringRef Whence = "", + StringRef Hint = "") { errs() << "error: "; if (!Whence.empty()) errs() << Whence << ": "; errs() << Message << "\n"; + if (!Hint.empty()) + errs() << Hint << "\n"; ::exit(1); } +static void exitWithErrorCode(const std::error_code &Error, + StringRef Whence = "") { + if (Error.category() == instrprof_category()) { + instrprof_error instrError = static_cast<instrprof_error>(Error.value()); + if (instrError == instrprof_error::unrecognized_format) { + // Hint for common error of forgetting -sample for sample profiles. + exitWithError(Error.message(), Whence, + "Perhaps you forgot to use the -sample option?"); + } + } + exitWithError(Error.message(), Whence); +} + namespace { enum ProfileKinds { instr, sample }; } -static void mergeInstrProfile(const cl::list<std::string> &Inputs, - StringRef OutputFilename) { +static void handleMergeWriterError(std::error_code &Error, + StringRef WhenceFile = "", + StringRef WhenceFunction = "", + bool ShowHint = true) { + if (!WhenceFile.empty()) + errs() << WhenceFile << ": "; + if (!WhenceFunction.empty()) + errs() << WhenceFunction << ": "; + errs() << Error.message() << "\n"; + + if (ShowHint) { + StringRef Hint = ""; + if (Error.category() == instrprof_category()) { + instrprof_error instrError = static_cast<instrprof_error>(Error.value()); + switch (instrError) { + case instrprof_error::hash_mismatch: + case instrprof_error::count_mismatch: + case instrprof_error::value_site_count_mismatch: + Hint = "Make sure that all profile data to be merged is generated " + "from the same binary."; + break; + default: + break; + } + } + + if (!Hint.empty()) + errs() << Hint << "\n"; + } +} + +struct WeightedFile { + StringRef Filename; + uint64_t Weight; + + WeightedFile() {} + + WeightedFile(StringRef F, uint64_t W) : Filename{F}, Weight{W} {} +}; +typedef SmallVector<WeightedFile, 5> WeightedFileVector; + +static void mergeInstrProfile(const WeightedFileVector &Inputs, + StringRef OutputFilename, + ProfileFormat OutputFormat) { if (OutputFilename.compare("-") == 0) exitWithError("Cannot write indexed profdata format to stdout."); + if (OutputFormat != PF_Binary && OutputFormat != PF_Text) + exitWithError("Unknown format is specified."); + std::error_code EC; raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None); if (EC) - exitWithError(EC.message(), OutputFilename); + exitWithErrorCode(EC, OutputFilename); InstrProfWriter Writer; - for (const auto &Filename : Inputs) { - auto ReaderOrErr = InstrProfReader::create(Filename); + SmallSet<std::error_code, 4> WriterErrorCodes; + for (const auto &Input : Inputs) { + auto ReaderOrErr = InstrProfReader::create(Input.Filename); if (std::error_code ec = ReaderOrErr.getError()) - exitWithError(ec.message(), Filename); + exitWithErrorCode(ec, Input.Filename); auto Reader = std::move(ReaderOrErr.get()); - for (const auto &I : *Reader) - if (std::error_code EC = - Writer.addFunctionCounts(I.Name, I.Hash, I.Counts)) - errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n"; + for (auto &I : *Reader) { + if (std::error_code EC = Writer.addRecord(std::move(I), Input.Weight)) { + // Only show hint the first time an error occurs. + bool firstTime = WriterErrorCodes.insert(EC).second; + handleMergeWriterError(EC, Input.Filename, I.Name, firstTime); + } + } if (Reader->hasError()) - exitWithError(Reader->getError().message(), Filename); + exitWithErrorCode(Reader->getError(), Input.Filename); } - Writer.write(Output); + if (OutputFormat == PF_Text) + Writer.writeText(Output); + else + Writer.write(Output); } -static void mergeSampleProfile(const cl::list<std::string> &Inputs, +static sampleprof::SampleProfileFormat FormatMap[] = { + sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Binary, + sampleprof::SPF_GCC}; + +static void mergeSampleProfile(const WeightedFileVector &Inputs, StringRef OutputFilename, - sampleprof::SampleProfileFormat OutputFormat) { + ProfileFormat OutputFormat) { using namespace sampleprof; - auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat); + auto WriterOrErr = + SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]); if (std::error_code EC = WriterOrErr.getError()) - exitWithError(EC.message(), OutputFilename); + exitWithErrorCode(EC, OutputFilename); auto Writer = std::move(WriterOrErr.get()); StringMap<FunctionSamples> ProfileMap; - for (const auto &Filename : Inputs) { + SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers; + for (const auto &Input : Inputs) { auto ReaderOrErr = - SampleProfileReader::create(Filename, getGlobalContext()); + SampleProfileReader::create(Input.Filename, getGlobalContext()); if (std::error_code EC = ReaderOrErr.getError()) - exitWithError(EC.message(), Filename); - - auto Reader = std::move(ReaderOrErr.get()); + exitWithErrorCode(EC, Input.Filename); + + // We need to keep the readers around until after all the files are + // read so that we do not lose the function names stored in each + // reader's memory. The function names are needed to write out the + // merged profile map. + Readers.push_back(std::move(ReaderOrErr.get())); + const auto Reader = Readers.back().get(); if (std::error_code EC = Reader->read()) - exitWithError(EC.message(), Filename); + exitWithErrorCode(EC, Input.Filename); StringMap<FunctionSamples> &Profiles = Reader->getProfiles(); for (StringMap<FunctionSamples>::iterator I = Profiles.begin(), @@ -94,16 +180,36 @@ static void mergeSampleProfile(const cl::list<std::string> &Inputs, I != E; ++I) { StringRef FName = I->first(); FunctionSamples &Samples = I->second; - ProfileMap[FName].merge(Samples); + sampleprof_error Result = ProfileMap[FName].merge(Samples, Input.Weight); + if (Result != sampleprof_error::success) { + std::error_code EC = make_error_code(Result); + handleMergeWriterError(EC, Input.Filename, FName); + } } } Writer->write(ProfileMap); } -static int merge_main(int argc, const char *argv[]) { - cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore, - cl::desc("<filenames...>")); +static WeightedFile parseWeightedFile(const StringRef &WeightedFilename) { + StringRef WeightStr, FileName; + std::tie(WeightStr, FileName) = WeightedFilename.split(','); + + uint64_t Weight; + if (WeightStr.getAsInteger(10, Weight) || Weight < 1) + exitWithError("Input weight must be a positive integer."); + + if (!sys::fs::exists(FileName)) + exitWithErrorCode(make_error_code(errc::no_such_file_or_directory), + FileName); + return WeightedFile(FileName, Weight); +} + +static int merge_main(int argc, const char *argv[]) { + cl::list<std::string> InputFilenames(cl::Positional, + cl::desc("<filename...>")); + cl::list<std::string> WeightedInputFilenames("weighted-input", + cl::desc("<weight>,<filename>")); cl::opt<std::string> OutputFilename("output", cl::value_desc("output"), cl::init("-"), cl::Required, cl::desc("Output file")); @@ -114,31 +220,41 @@ static int merge_main(int argc, const char *argv[]) { cl::values(clEnumVal(instr, "Instrumentation profile (default)"), clEnumVal(sample, "Sample profile"), clEnumValEnd)); - cl::opt<sampleprof::SampleProfileFormat> OutputFormat( - cl::desc("Format of output profile (only meaningful with --sample)"), - cl::init(sampleprof::SPF_Binary), - cl::values(clEnumValN(sampleprof::SPF_Binary, "binary", - "Binary encoding (default)"), - clEnumValN(sampleprof::SPF_Text, "text", "Text encoding"), - clEnumValN(sampleprof::SPF_GCC, "gcc", "GCC encoding"), + cl::opt<ProfileFormat> OutputFormat( + cl::desc("Format of output profile"), cl::init(PF_Binary), + cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"), + clEnumValN(PF_Text, "text", "Text encoding"), + clEnumValN(PF_GCC, "gcc", + "GCC encoding (only meaningful for -sample)"), clEnumValEnd)); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); + if (InputFilenames.empty() && WeightedInputFilenames.empty()) + exitWithError("No input files specified. See " + + sys::path::filename(argv[0]) + " -help"); + + WeightedFileVector WeightedInputs; + for (StringRef Filename : InputFilenames) + WeightedInputs.push_back(WeightedFile(Filename, 1)); + for (StringRef WeightedFilename : WeightedInputFilenames) + WeightedInputs.push_back(parseWeightedFile(WeightedFilename)); + if (ProfileKind == instr) - mergeInstrProfile(Inputs, OutputFilename); + mergeInstrProfile(WeightedInputs, OutputFilename, OutputFormat); else - mergeSampleProfile(Inputs, OutputFilename, OutputFormat); + mergeSampleProfile(WeightedInputs, OutputFilename, OutputFormat); return 0; } static int showInstrProfile(std::string Filename, bool ShowCounts, - bool ShowAllFunctions, std::string ShowFunction, + bool ShowIndirectCallTargets, bool ShowAllFunctions, + std::string ShowFunction, bool TextFormat, raw_fd_ostream &OS) { auto ReaderOrErr = InstrProfReader::create(Filename); if (std::error_code EC = ReaderOrErr.getError()) - exitWithError(EC.message(), Filename); + exitWithErrorCode(EC, Filename); auto Reader = std::move(ReaderOrErr.get()); uint64_t MaxFunctionCount = 0, MaxBlockCount = 0; @@ -148,35 +264,71 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, ShowAllFunctions || (!ShowFunction.empty() && Func.Name.find(ShowFunction) != Func.Name.npos); + bool doTextFormatDump = (Show && ShowCounts && TextFormat); + + if (doTextFormatDump) { + InstrProfSymtab &Symtab = Reader->getSymtab(); + InstrProfWriter::writeRecordInText(Func, Symtab, OS); + continue; + } + ++TotalFunctions; assert(Func.Counts.size() > 0 && "function missing entry counter"); if (Func.Counts[0] > MaxFunctionCount) MaxFunctionCount = Func.Counts[0]; + for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) { + if (Func.Counts[I] > MaxBlockCount) + MaxBlockCount = Func.Counts[I]; + } + if (Show) { + if (!ShownFunctions) OS << "Counters:\n"; + ++ShownFunctions; OS << " " << Func.Name << ":\n" << " Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n" << " Counters: " << Func.Counts.size() << "\n" << " Function count: " << Func.Counts[0] << "\n"; - } - if (Show && ShowCounts) - OS << " Block counts: ["; - for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) { - if (Func.Counts[I] > MaxBlockCount) - MaxBlockCount = Func.Counts[I]; - if (Show && ShowCounts) - OS << (I == 1 ? "" : ", ") << Func.Counts[I]; + if (ShowIndirectCallTargets) + OS << " Indirect Call Site Count: " + << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n"; + + if (ShowCounts) { + OS << " Block counts: ["; + for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) { + OS << (I == 1 ? "" : ", ") << Func.Counts[I]; + } + OS << "]\n"; + } + + if (ShowIndirectCallTargets) { + InstrProfSymtab &Symtab = Reader->getSymtab(); + uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget); + OS << " Indirect Target Results: \n"; + for (size_t I = 0; I < NS; ++I) { + uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I); + std::unique_ptr<InstrProfValueData[]> VD = + Func.getValueForSite(IPVK_IndirectCallTarget, I); + for (uint32_t V = 0; V < NV; V++) { + OS << "\t[ " << I << ", "; + OS << Symtab.getFuncName(VD[V].Value) << ", " << VD[V].Count + << " ]\n"; + } + } + } } - if (Show && ShowCounts) - OS << "]\n"; } + if (Reader->hasError()) - exitWithError(Reader->getError().message(), Filename); + exitWithErrorCode(Reader->getError(), Filename); + + if (ShowCounts && TextFormat) + return 0; if (ShowAllFunctions || !ShowFunction.empty()) OS << "Functions shown: " << ShownFunctions << "\n"; @@ -192,10 +344,12 @@ static int showSampleProfile(std::string Filename, bool ShowCounts, using namespace sampleprof; auto ReaderOrErr = SampleProfileReader::create(Filename, getGlobalContext()); if (std::error_code EC = ReaderOrErr.getError()) - exitWithError(EC.message(), Filename); + exitWithErrorCode(EC, Filename); auto Reader = std::move(ReaderOrErr.get()); - Reader->read(); + if (std::error_code EC = Reader->read()) + exitWithErrorCode(EC, Filename); + if (ShowAllFunctions || ShowFunction.empty()) Reader->dump(OS); else @@ -210,6 +364,12 @@ static int show_main(int argc, const char *argv[]) { cl::opt<bool> ShowCounts("counts", cl::init(false), cl::desc("Show counter values for shown functions")); + cl::opt<bool> TextFormat( + "text", cl::init(false), + cl::desc("Show instr profile data in text dump format")); + cl::opt<bool> ShowIndirectCallTargets( + "ic-targets", cl::init(false), + cl::desc("Show indirect call site target values for shown functions")); cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false), cl::desc("Details for every function")); cl::opt<std::string> ShowFunction("function", @@ -232,14 +392,14 @@ static int show_main(int argc, const char *argv[]) { std::error_code EC; raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text); if (EC) - exitWithError(EC.message(), OutputFilename); + exitWithErrorCode(EC, OutputFilename); if (ShowAllFunctions && !ShowFunction.empty()) errs() << "warning: -function argument ignored: showing all functions\n"; if (ProfileKind == instr) - return showInstrProfile(Filename, ShowCounts, ShowAllFunctions, - ShowFunction, OS); + return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets, + ShowAllFunctions, ShowFunction, TextFormat, OS); else return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, ShowFunction, OS); @@ -266,8 +426,7 @@ int main(int argc, const char *argv[]) { return func(argc - 1, argv + 1); } - if (strcmp(argv[1], "-h") == 0 || - strcmp(argv[1], "-help") == 0 || + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help") == 0 || strcmp(argv[1], "--help") == 0) { errs() << "OVERVIEW: LLVM profile data tools\n\n" diff --git a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp index e2d7191..688d349 100644 --- a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp +++ b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp @@ -118,7 +118,7 @@ void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value, void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6", "ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M", "ARM v7E-M", "ARM v8" @@ -149,7 +149,7 @@ void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Permitted" }; + static const char *const Strings[] = { "Not Permitted", "Permitted" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -159,7 +159,7 @@ void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" }; + static const char *const Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -169,7 +169,7 @@ void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4", "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16" }; @@ -182,7 +182,7 @@ void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" }; + static const char *const Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -192,8 +192,8 @@ void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { - "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON" + static const char *const Strings[] = { + "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON", "ARMv8.1-a NEON" }; uint64_t Value = ParseInteger(Data, Offset); @@ -204,7 +204,7 @@ void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004", "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)" }; @@ -217,7 +217,7 @@ void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "v6", "Static Base", "TLS", "Unused" }; + static const char *const Strings[] = { "v6", "Static Base", "TLS", "Unused" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -227,7 +227,7 @@ void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Absolute", "PC-relative", "SB-relative", "Not Permitted" }; @@ -239,7 +239,9 @@ void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Absolute", "PC-relative", "Not Permitted" }; + static const char *const Strings[] = { + "Absolute", "PC-relative", "Not Permitted" + }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -249,7 +251,9 @@ void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Direct", "GOT-Indirect" }; + static const char *const Strings[] = { + "Not Permitted", "Direct", "GOT-Indirect" + }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -259,7 +263,7 @@ void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte" }; @@ -271,7 +275,7 @@ void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "IEEE-754", "Runtime" }; + static const char *const Strings[] = { "IEEE-754", "Runtime" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -281,7 +285,9 @@ void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Unsupported", "IEEE-754", "Sign Only" }; + static const char *const Strings[] = { + "Unsupported", "IEEE-754", "Sign Only" + }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -291,7 +297,7 @@ void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "IEEE-754" }; + static const char *const Strings[] = { "Not Permitted", "IEEE-754" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -302,7 +308,7 @@ void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "IEEE-754" }; + static const char *const Strings[] = { "Not Permitted", "IEEE-754" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -312,7 +318,7 @@ void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag, void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "Finite Only", "RTABI", "IEEE-754" }; @@ -324,7 +330,7 @@ void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved" }; @@ -344,7 +350,7 @@ void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Required", "8-byte data alignment", "8-byte data and code alignment", "Reserved" }; @@ -365,7 +371,7 @@ void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "Packed", "Int32", "External Int32" }; @@ -377,7 +383,7 @@ void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)" }; @@ -389,7 +395,7 @@ void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "AAPCS", "AAPCS VFP", "Custom", "Not Permitted" }; @@ -401,7 +407,7 @@ void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "AAPCS", "iWMMX", "Custom" }; + static const char *const Strings[] = { "AAPCS", "iWMMX", "Custom" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -412,7 +418,7 @@ void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_optimization_goals(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging", "Best Debugging" }; @@ -426,7 +432,7 @@ void ARMAttributeParser::ABI_optimization_goals(AttrType Tag, void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Accuracy", "Best Accuracy" }; @@ -461,7 +467,7 @@ void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "v6-style" }; + static const char *const Strings[] = { "Not Permitted", "v6-style" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -471,7 +477,7 @@ void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "If Available", "Permitted" }; + static const char *const Strings[] = { "If Available", "Permitted" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -481,7 +487,7 @@ void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" }; + static const char *const Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -491,7 +497,7 @@ void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Permitted" }; + static const char *const Strings[] = { "Not Permitted", "Permitted" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -501,7 +507,7 @@ void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "If Available", "Not Permitted", "Permitted" }; @@ -513,7 +519,7 @@ void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Permitted" }; + static const char *const Strings[] = { "Not Permitted", "Permitted" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -523,7 +529,7 @@ void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "TrustZone", "Virtualization Extensions", "TrustZone + Virtualization Extensions" }; diff --git a/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h index dd2490d..beb5fd4 100644 --- a/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h +++ b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h @@ -305,13 +305,15 @@ void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, size_t Length) template <typename ET> class PrinterContext { - StreamWriter &SW; - const object::ELFFile<ET> *ELF; - typedef typename object::ELFFile<ET>::Elf_Sym Elf_Sym; typedef typename object::ELFFile<ET>::Elf_Shdr Elf_Shdr; + typedef typename object::ELFFile<ET>::Elf_Rel Elf_Rel; + typedef typename object::ELFFile<ET>::Elf_Word Elf_Word; - typedef typename object::ELFFile<ET>::Elf_Rel_Iter Elf_Rel_iterator; + StreamWriter &SW; + const object::ELFFile<ET> *ELF; + const Elf_Shdr *Symtab; + ArrayRef<Elf_Word> ShndxTable; static const size_t IndexTableEntrySize; @@ -332,8 +334,9 @@ class PrinterContext { void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const; public: - PrinterContext(StreamWriter &Writer, const object::ELFFile<ET> *File) - : SW(Writer), ELF(File) {} + PrinterContext(StreamWriter &SW, const object::ELFFile<ET> *ELF, + const Elf_Shdr *Symtab) + : SW(SW), ELF(ELF), Symtab(Symtab) {} void PrintUnwindInformation() const; }; @@ -345,10 +348,14 @@ template <typename ET> ErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(unsigned Section, uint64_t Address) const { - for (const Elf_Sym &Sym : ELF->symbols()) + ErrorOr<StringRef> StrTableOrErr = ELF->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + + for (const Elf_Sym &Sym : ELF->symbols(Symtab)) if (Sym.st_shndx == Section && Sym.st_value == Address && Sym.getType() == ELF::STT_FUNC) - return ELF->getSymbolName(&Sym, false); + return Sym.getName(StrTable); return readobj_error::unknown_symbol; } @@ -365,24 +372,29 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, /// table. for (const Elf_Shdr &Sec : ELF->sections()) { - if (Sec.sh_type == ELF::SHT_REL && Sec.sh_info == IndexSectionIndex) { - for (Elf_Rel_iterator RI = ELF->rel_begin(&Sec), RE = ELF->rel_end(&Sec); - RI != RE; ++RI) { - if (RI->r_offset == static_cast<unsigned>(IndexTableOffset)) { - typename object::ELFFile<ET>::Elf_Rela RelA; - RelA.r_offset = RI->r_offset; - RelA.r_info = RI->r_info; - RelA.r_addend = 0; - - std::pair<const Elf_Shdr *, const Elf_Sym *> Symbol = - ELF->getRelocationSymbol(&Sec, &RelA); - - ErrorOr<const Elf_Shdr *> Ret = ELF->getSection(Symbol.second); - if (std::error_code EC = Ret.getError()) - report_fatal_error(EC.message()); - return *Ret; - } - } + if (Sec.sh_type != ELF::SHT_REL || Sec.sh_info != IndexSectionIndex) + continue; + + ErrorOr<const Elf_Shdr *> SymTabOrErr = ELF->getSection(Sec.sh_link); + error(SymTabOrErr.getError()); + const Elf_Shdr *SymTab = *SymTabOrErr; + + for (const Elf_Rel &R : ELF->rels(&Sec)) { + if (R.r_offset != static_cast<unsigned>(IndexTableOffset)) + continue; + + typename object::ELFFile<ET>::Elf_Rela RelA; + RelA.r_offset = R.r_offset; + RelA.r_info = R.r_info; + RelA.r_addend = 0; + + const Elf_Sym *Symbol = ELF->getRelocationSymbol(&RelA, SymTab); + + ErrorOr<const Elf_Shdr *> Ret = + ELF->getSection(Symbol, SymTab, ShndxTable); + if (std::error_code EC = Ret.getError()) + report_fatal_error(EC.message()); + return *Ret; } } return nullptr; diff --git a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp index bf5ff8e..650955d 100644 --- a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -630,9 +630,10 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, SW.printString("ExceptionRecord", formatSymbol(*Name, Address)); - section_iterator SI = COFF.section_end(); - if (XDataRecord->getSection(SI)) + ErrorOr<section_iterator> SIOrErr = XDataRecord->getSection(); + if (!SIOrErr) return false; + section_iterator SI = *SIOrErr; return dumpXDataRecord(COFF, *SI, FunctionAddress, Address); } else { diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp index cf897d7..516d1cf 100644 --- a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -60,6 +60,7 @@ public: void printCOFFExports() override; void printCOFFDirectives() override; void printCOFFBaseReloc() override; + void printCodeViewDebugInfo() override; void printStackMap() const override; private: void printSymbol(const SymbolRef &Sym); @@ -71,7 +72,7 @@ private: void printBaseOfDataField(const pe32_header *Hdr); void printBaseOfDataField(const pe32plus_header *Hdr); - void printCodeViewDebugInfo(const SectionRef &Section); + void printCodeViewSection(const SectionRef &Section); void printCodeViewSymbolsSubsection(StringRef Subsection, const SectionRef &Section, @@ -219,6 +220,7 @@ static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = { static const EnumEntry<COFF::SectionCharacteristics> ImageSectionCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ), @@ -385,14 +387,12 @@ void COFFDumper::printFileHeaders() { // Print PE header. This header does not exist if this is an object file and // not an executable. const pe32_header *PEHeader = nullptr; - if (error(Obj->getPE32Header(PEHeader))) - return; + error(Obj->getPE32Header(PEHeader)); if (PEHeader) printPEHeader<pe32_header>(PEHeader); const pe32plus_header *PEPlusHeader = nullptr; - if (error(Obj->getPE32PlusHeader(PEPlusHeader))) - return; + error(Obj->getPE32PlusHeader(PEPlusHeader)); if (PEPlusHeader) printPEHeader<pe32plus_header>(PEPlusHeader); @@ -475,10 +475,18 @@ void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) { void COFFDumper::printBaseOfDataField(const pe32plus_header *) {} -void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { +void COFFDumper::printCodeViewDebugInfo() { + for (const SectionRef &S : Obj->sections()) { + StringRef SecName; + error(S.getName(SecName)); + if (SecName == ".debug$S") + printCodeViewSection(S); + } +} + +void COFFDumper::printCodeViewSection(const SectionRef &Section) { StringRef Data; - if (error(Section.getContents(Data))) - return; + error(Section.getContents(Data)); SmallVector<StringRef, 10> FunctionNames; StringMap<StringRef> FunctionLineTables; @@ -518,8 +526,7 @@ void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { switch (SubSectionType) { case COFF::DEBUG_SYMBOL_SUBSECTION: - if (opts::SectionSymbols) - printCodeViewSymbolsSubsection(Contents, Section, Offset); + printCodeViewSymbolsSubsection(Contents, Section, Offset); break; case COFF::DEBUG_LINE_TABLE_SUBSECTION: { // Holds a PC to file:line table. Some data to parse this subsection is @@ -533,19 +540,18 @@ void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { return; } - StringRef FunctionName; - if (error(resolveSymbolName(Obj->getCOFFSection(Section), Offset, - FunctionName))) - return; - W.printString("FunctionName", FunctionName); - if (FunctionLineTables.count(FunctionName) != 0) { + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), Offset, + LinkageName)); + W.printString("LinkageName", LinkageName); + if (FunctionLineTables.count(LinkageName) != 0) { // Saw debug info for this function already? error(object_error::parse_failed); return; } - FunctionLineTables[FunctionName] = Contents; - FunctionNames.push_back(FunctionName); + FunctionLineTables[LinkageName] = Contents; + FunctionNames.push_back(LinkageName); break; } case COFF::DEBUG_STRING_TABLE_SUBSECTION: @@ -582,7 +588,7 @@ void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) { StringRef Name = FunctionNames[I]; ListScope S(W, "FunctionLineTable"); - W.printString("FunctionName", Name); + W.printString("LinkageName", Name); DataExtractor DE(FunctionLineTables[Name], true, 4); uint32_t Offset = 6; // Skip relocations. @@ -695,9 +701,8 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, uint32_t CodeSize = DE.getU32(&Offset); DE.getU8(&Offset, Unused, 12); StringRef SectionName; - if (error(resolveSymbolName(Obj->getCOFFSection(Section), - OffsetInSection + Offset, SectionName))) - return; + error(resolveSymbolName(Obj->getCOFFSection(Section), + OffsetInSection + Offset, SectionName)); Offset += 4; DE.getU8(&Offset, Unused, 3); StringRef DisplayName = DE.getCStr(&Offset); @@ -748,8 +753,7 @@ void COFFDumper::printSections() { const coff_section *Section = Obj->getCOFFSection(Sec); StringRef Name; - if (error(Sec.getName(Name))) - Name = ""; + error(Sec.getName(Name)); DictScope D(W, "Section"); W.printNumber("Number", SectionNumber); @@ -782,14 +786,10 @@ void COFFDumper::printSections() { } } - if (Name == ".debug$S" && opts::CodeView) - printCodeViewDebugInfo(Sec); - if (opts::SectionData && !(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) { StringRef Data; - if (error(Sec.getContents(Data))) - break; + error(Sec.getContents(Data)); W.printBinaryBlock("SectionData", Data); } @@ -803,8 +803,7 @@ void COFFDumper::printRelocations() { for (const SectionRef &Section : Obj->sections()) { ++SectionNumber; StringRef Name; - if (error(Section.getName(Name))) - continue; + error(Section.getName(Name)); bool PrintedGroup = false; for (const RelocationRef &Reloc : Section.relocations()) { @@ -834,8 +833,7 @@ void COFFDumper::printRelocation(const SectionRef &Section, symbol_iterator Symbol = Reloc.getSymbol(); if (Symbol != Obj->symbol_end()) { ErrorOr<StringRef> SymbolNameOrErr = Symbol->getName(); - if (error(SymbolNameOrErr.getError())) - return; + error(SymbolNameOrErr.getError()); SymbolName = *SymbolNameOrErr; } @@ -914,8 +912,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) { if (Symbol.isFunctionDefinition()) { const coff_aux_function_definition *Aux; - if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); DictScope AS(W, "AuxFunctionDef"); W.printNumber("TagIndex", Aux->TagIndex); @@ -925,8 +922,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { } else if (Symbol.isAnyUndefined()) { const coff_aux_weak_external *Aux; - if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); ErrorOr<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex); StringRef LinkedName; @@ -943,8 +939,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { } else if (Symbol.isFileRecord()) { const char *FileName; - if (error(getSymbolAuxData(Obj, Symbol, I, FileName))) - break; + error(getSymbolAuxData(Obj, Symbol, I, FileName)); DictScope AS(W, "AuxFileRecord"); @@ -954,8 +949,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { break; } else if (Symbol.isSectionDefinition()) { const coff_aux_section_definition *Aux; - if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); int32_t AuxNumber = Aux->getNumber(Symbol.isBigObj()); @@ -986,8 +980,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { } } else if (Symbol.isCLRToken()) { const coff_aux_clr_token *Aux; - if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); ErrorOr<COFFSymbolRef> ReferredSym = Obj->getSymbol(Aux->SymbolTableIndex); @@ -1040,9 +1033,9 @@ void COFFDumper::printImportedSymbols( iterator_range<imported_symbol_iterator> Range) { for (const ImportedSymbolRef &I : Range) { StringRef Sym; - if (error(I.getSymbolName(Sym))) return; + error(I.getSymbolName(Sym)); uint16_t Ordinal; - if (error(I.getOrdinal(Ordinal))) return; + error(I.getOrdinal(Ordinal)); W.printNumber("Symbol", Sym, Ordinal); } } @@ -1054,12 +1047,12 @@ void COFFDumper::printDelayImportedSymbols( for (const ImportedSymbolRef &S : Range) { DictScope Import(W, "Import"); StringRef Sym; - if (error(S.getSymbolName(Sym))) return; + error(S.getSymbolName(Sym)); uint16_t Ordinal; - if (error(S.getOrdinal(Ordinal))) return; + error(S.getOrdinal(Ordinal)); W.printNumber("Symbol", Sym, Ordinal); uint64_t Addr; - if (error(I.getImportAddress(Index++, Addr))) return; + error(I.getImportAddress(Index++, Addr)); W.printHex("Address", Addr); } } @@ -1069,12 +1062,12 @@ void COFFDumper::printCOFFImports() { for (const ImportDirectoryEntryRef &I : Obj->import_directories()) { DictScope Import(W, "Import"); StringRef Name; - if (error(I.getName(Name))) return; + error(I.getName(Name)); W.printString("Name", Name); uint32_t Addr; - if (error(I.getImportLookupTableRVA(Addr))) return; + error(I.getImportLookupTableRVA(Addr)); W.printHex("ImportLookupTableRVA", Addr); - if (error(I.getImportAddressTableRVA(Addr))) return; + error(I.getImportAddressTableRVA(Addr)); W.printHex("ImportAddressTableRVA", Addr); printImportedSymbols(I.imported_symbols()); } @@ -1083,10 +1076,10 @@ void COFFDumper::printCOFFImports() { for (const DelayImportDirectoryEntryRef &I : Obj->delay_import_directories()) { DictScope Import(W, "DelayImport"); StringRef Name; - if (error(I.getName(Name))) return; + error(I.getName(Name)); W.printString("Name", Name); const delay_import_directory_table_entry *Table; - if (error(I.getDelayImportTable(Table))) return; + error(I.getDelayImportTable(Table)); W.printHex("Attributes", Table->Attributes); W.printHex("ModuleHandle", Table->ModuleHandle); W.printHex("ImportAddressTable", Table->DelayImportAddressTable); @@ -1104,12 +1097,9 @@ void COFFDumper::printCOFFExports() { StringRef Name; uint32_t Ordinal, RVA; - if (error(E.getSymbolName(Name))) - continue; - if (error(E.getOrdinal(Ordinal))) - continue; - if (error(E.getExportRVA(RVA))) - continue; + error(E.getSymbolName(Name)); + error(E.getOrdinal(Ordinal)); + error(E.getExportRVA(RVA)); W.printNumber("Ordinal", Ordinal); W.printString("Name", Name); @@ -1122,13 +1112,11 @@ void COFFDumper::printCOFFDirectives() { StringRef Contents; StringRef Name; - if (error(Section.getName(Name))) - continue; + error(Section.getName(Name)); if (Name != ".drectve") continue; - if (error(Section.getContents(Contents))) - return; + error(Section.getContents(Contents)); W.printString("Directive(s)", Contents); } @@ -1152,10 +1140,8 @@ void COFFDumper::printCOFFBaseReloc() { for (const BaseRelocRef &I : Obj->base_relocs()) { uint8_t Type; uint32_t RVA; - if (error(I.getRVA(RVA))) - continue; - if (error(I.getType(Type))) - continue; + error(I.getRVA(RVA)); + error(I.getType(Type)); DictScope Import(W, "Entry"); W.printString("Type", getBaseRelocTypeName(Type)); W.printHex("Address", RVA); diff --git a/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp new file mode 100644 index 0000000..83715e6 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp @@ -0,0 +1,52 @@ +//===-- COFFImportDumper.cpp - COFF import library dumper -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the COFF import library dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "ObjDumper.h" +#include "llvm-readobj.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Support/COFF.h" + +using namespace llvm::object; + +namespace llvm { + +void dumpCOFFImportFile(const COFFImportFile *File) { + outs() << '\n'; + outs() << "File: " << File->getFileName() << "\n"; + outs() << "Format: COFF-import-file\n"; + + const coff_import_header *H = File->getCOFFImportHeader(); + switch (H->getType()) { + case COFF::IMPORT_CODE: outs() << "Type: code\n"; break; + case COFF::IMPORT_DATA: outs() << "Type: data\n"; break; + case COFF::IMPORT_CONST: outs() << "Type: const\n"; break; + } + + switch (H->getNameType()) { + case COFF::IMPORT_ORDINAL: outs() << "Name type: ordinal\n"; break; + case COFF::IMPORT_NAME: outs() << "Name type: name\n"; break; + case COFF::IMPORT_NAME_NOPREFIX: outs() << "Name type: noprefix\n"; break; + case COFF::IMPORT_NAME_UNDECORATE: outs() << "Name type: undecorate\n"; break; + } + + for (const object::BasicSymbolRef &Sym : File->symbols()) { + outs() << "Symbol: "; + Sym.printName(outs()); + outs() << "\n"; + } +} + +} // namespace llvm diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp index 1cdf552..02397f3 100644 --- a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -42,8 +42,7 @@ namespace { template<typename ELFT> class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) - : ObjDumper(Writer), Obj(Obj) {} + ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer); void printFileHeaders() override; void printSections() override; @@ -57,6 +56,9 @@ public: void printNeededLibraries() override; void printProgramHeaders() override; void printHashTable() override; + void printGnuHashTable() override; + void printLoadName() override; + void printVersionInfo() override; void printAttributes() override; void printMipsPLTGOT() override; @@ -69,13 +71,114 @@ private: typedef ELFFile<ELFT> ELFO; typedef typename ELFO::Elf_Shdr Elf_Shdr; typedef typename ELFO::Elf_Sym Elf_Sym; - - void printSymbol(const Elf_Sym *Symbol, bool IsDynamic); + typedef typename ELFO::Elf_Dyn Elf_Dyn; + typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; + typedef typename ELFO::Elf_Rel Elf_Rel; + typedef typename ELFO::Elf_Rela Elf_Rela; + typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range; + typedef typename ELFO::Elf_Phdr Elf_Phdr; + typedef typename ELFO::Elf_Half Elf_Half; + typedef typename ELFO::Elf_Hash Elf_Hash; + typedef typename ELFO::Elf_GnuHash Elf_GnuHash; + typedef typename ELFO::Elf_Ehdr Elf_Ehdr; + typedef typename ELFO::Elf_Word Elf_Word; + typedef typename ELFO::uintX_t uintX_t; + typedef typename ELFO::Elf_Versym Elf_Versym; + typedef typename ELFO::Elf_Verneed Elf_Verneed; + typedef typename ELFO::Elf_Vernaux Elf_Vernaux; + typedef typename ELFO::Elf_Verdef Elf_Verdef; + typedef typename ELFO::Elf_Verdaux Elf_Verdaux; + + /// \brief Represents a region described by entries in the .dynamic table. + struct DynRegionInfo { + DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} + /// \brief Address in current address space. + const void *Addr; + /// \brief Size in bytes of the region. + uintX_t Size; + /// \brief Size of each entity in the region. + uintX_t EntSize; + }; + + void printSymbolsHelper(bool IsDynamic); + void printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, + StringRef StrTable, bool IsDynamic); void printRelocations(const Elf_Shdr *Sec); - void printRelocation(const Elf_Shdr *Sec, typename ELFO::Elf_Rela Rel); + void printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab); + void printValue(uint64_t Type, uint64_t Value); + + const Elf_Rela *dyn_rela_begin() const; + const Elf_Rela *dyn_rela_end() const; + Elf_Rela_Range dyn_relas() const; + StringRef getDynamicString(uint64_t Offset) const; + const Elf_Dyn *dynamic_table_begin() const { + ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_begin(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + const Elf_Dyn *dynamic_table_end() const { + ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_end(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, + bool &IsDefault); + void LoadVersionMap(); + void LoadVersionNeeds(const Elf_Shdr *ec) const; + void LoadVersionDefs(const Elf_Shdr *sec) const; const ELFO *Obj; + DynRegionInfo DynRelaRegion; + const Elf_Phdr *DynamicProgHeader = nullptr; + StringRef DynamicStringTable; + const Elf_Sym *DynSymStart = nullptr; + StringRef SOName; + const Elf_Hash *HashTable = nullptr; + const Elf_GnuHash *GnuHashTable = nullptr; + const Elf_Shdr *DotDynSymSec = nullptr; + const Elf_Shdr *DotSymtabSec = nullptr; + ArrayRef<Elf_Word> ShndxTable; + + const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version + const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r + const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d + + // Records for each version index the corresponding Verdef or Vernaux entry. + // This is filled the first time LoadVersionMap() is called. + class VersionMapEntry : public PointerIntPair<const void *, 1> { + public: + // If the integer is 0, this is an Elf_Verdef*. + // If the integer is 1, this is an Elf_Vernaux*. + VersionMapEntry() : PointerIntPair<const void *, 1>(nullptr, 0) {} + VersionMapEntry(const Elf_Verdef *verdef) + : PointerIntPair<const void *, 1>(verdef, 0) {} + VersionMapEntry(const Elf_Vernaux *vernaux) + : PointerIntPair<const void *, 1>(vernaux, 1) {} + bool isNull() const { return getPointer() == nullptr; } + bool isVerdef() const { return !isNull() && getInt() == 0; } + bool isVernaux() const { return !isNull() && getInt() == 1; } + const Elf_Verdef *getVerdef() const { + return isVerdef() ? (const Elf_Verdef *)getPointer() : nullptr; + } + const Elf_Vernaux *getVernaux() const { + return isVernaux() ? (const Elf_Vernaux *)getPointer() : nullptr; + } + }; + mutable SmallVector<VersionMapEntry, 16> VersionMap; + +public: + Elf_Dyn_Range dynamic_table() const { + ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + + std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, + bool IsDynamic); + const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } + const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } + ArrayRef<Elf_Word> getShndxTable() { return ShndxTable; } }; template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { @@ -122,30 +225,246 @@ std::error_code createELFDumper(const object::ObjectFile *Obj, } // namespace llvm -template <typename ELFO> -static std::string getFullSymbolName(const ELFO &Obj, - const typename ELFO::Elf_Sym *Symbol, - bool IsDynamic) { - StringRef SymbolName = errorOrDefault(Obj.getSymbolName(Symbol, IsDynamic)); +// Iterate through the versions needed section, and place each Elf_Vernaux +// in the VersionMap according to its index. +template <class ELFT> +void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *sec) const { + unsigned vn_size = sec->sh_size; // Size of section in bytes + unsigned vn_count = sec->sh_info; // Number of Verneed entries + const char *sec_start = (const char *)Obj->base() + sec->sh_offset; + const char *sec_end = sec_start + vn_size; + // The first Verneed entry is at the start of the section. + const char *p = sec_start; + for (unsigned i = 0; i < vn_count; i++) { + if (p + sizeof(Elf_Verneed) > sec_end) + report_fatal_error("Section ended unexpectedly while scanning " + "version needed records."); + const Elf_Verneed *vn = reinterpret_cast<const Elf_Verneed *>(p); + if (vn->vn_version != ELF::VER_NEED_CURRENT) + report_fatal_error("Unexpected verneed version"); + // Iterate through the Vernaux entries + const char *paux = p + vn->vn_aux; + for (unsigned j = 0; j < vn->vn_cnt; j++) { + if (paux + sizeof(Elf_Vernaux) > sec_end) + report_fatal_error("Section ended unexpected while scanning auxiliary " + "version needed records."); + const Elf_Vernaux *vna = reinterpret_cast<const Elf_Vernaux *>(paux); + size_t index = vna->vna_other & ELF::VERSYM_VERSION; + if (index >= VersionMap.size()) + VersionMap.resize(index + 1); + VersionMap[index] = VersionMapEntry(vna); + paux += vna->vna_next; + } + p += vn->vn_next; + } +} + +// Iterate through the version definitions, and place each Elf_Verdef +// in the VersionMap according to its index. +template <class ELFT> +void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *sec) const { + unsigned vd_size = sec->sh_size; // Size of section in bytes + unsigned vd_count = sec->sh_info; // Number of Verdef entries + const char *sec_start = (const char *)Obj->base() + sec->sh_offset; + const char *sec_end = sec_start + vd_size; + // The first Verdef entry is at the start of the section. + const char *p = sec_start; + for (unsigned i = 0; i < vd_count; i++) { + if (p + sizeof(Elf_Verdef) > sec_end) + report_fatal_error("Section ended unexpectedly while scanning " + "version definitions."); + const Elf_Verdef *vd = reinterpret_cast<const Elf_Verdef *>(p); + if (vd->vd_version != ELF::VER_DEF_CURRENT) + report_fatal_error("Unexpected verdef version"); + size_t index = vd->vd_ndx & ELF::VERSYM_VERSION; + if (index >= VersionMap.size()) + VersionMap.resize(index + 1); + VersionMap[index] = VersionMapEntry(vd); + p += vd->vd_next; + } +} + +template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() { + // If there is no dynamic symtab or version table, there is nothing to do. + if (!DynSymStart || !dot_gnu_version_sec) + return; + + // Has the VersionMap already been loaded? + if (VersionMap.size() > 0) + return; + + // The first two version indexes are reserved. + // Index 0 is LOCAL, index 1 is GLOBAL. + VersionMap.push_back(VersionMapEntry()); + VersionMap.push_back(VersionMapEntry()); + + if (dot_gnu_version_d_sec) + LoadVersionDefs(dot_gnu_version_d_sec); + + if (dot_gnu_version_r_sec) + LoadVersionNeeds(dot_gnu_version_r_sec); +} + + +template <typename ELFO, class ELFT> +static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper, + const ELFO *Obj, + const typename ELFO::Elf_Shdr *Sec, + StreamWriter &W) { + DictScope SS(W, "Version symbols"); + if (!Sec) + return; + StringRef Name = errorOrDefault(Obj->getSectionName(Sec)); + W.printNumber("Section Name", Name, Sec->sh_name); + W.printHex("Address", Sec->sh_addr); + W.printHex("Offset", Sec->sh_offset); + W.printNumber("Link", Sec->sh_link); + + const typename ELFO::Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); + const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset; + ErrorOr<StringRef> StrTableOrErr = + Obj->getStringTableForSymtab(*DynSymSec); + error(StrTableOrErr.getError()); + + // Same number of entries in the dynamic symbol table (DT_SYMTAB). + ListScope Syms(W, "Symbols"); + for (const typename ELFO::Elf_Sym &Sym : Obj->symbols(DynSymSec)) { + DictScope S(W, "Symbol"); + std::string FullSymbolName = + Dumper->getFullSymbolName(&Sym, *StrTableOrErr, true /* IsDynamic */); + W.printNumber("Version", *P); + W.printString("Name", FullSymbolName); + P += sizeof(typename ELFO::Elf_Half); + } +} + +template <typename ELFO, class ELFT> +static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper, + const ELFO *Obj, + const typename ELFO::Elf_Shdr *Sec, + StreamWriter &W) { + DictScope SD(W, "Version definition"); + if (!Sec) + return; + StringRef Name = errorOrDefault(Obj->getSectionName(Sec)); + W.printNumber("Section Name", Name, Sec->sh_name); + W.printHex("Address", Sec->sh_addr); + W.printHex("Offset", Sec->sh_offset); + W.printNumber("Link", Sec->sh_link); + + unsigned verdef_entries = 0; + // The number of entries in the section SHT_GNU_verdef + // is determined by DT_VERDEFNUM tag. + for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) { + if (Dyn.d_tag == DT_VERDEFNUM) + verdef_entries = Dyn.d_un.d_val; + } + const uint8_t *SecStartAddress = + (const uint8_t *)Obj->base() + Sec->sh_offset; + const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size; + const uint8_t *P = SecStartAddress; + ErrorOr<const typename ELFO::Elf_Shdr *> StrTabOrErr = + Obj->getSection(Sec->sh_link); + error(StrTabOrErr.getError()); + + ListScope Entries(W, "Entries"); + for (unsigned i = 0; i < verdef_entries; ++i) { + if (P + sizeof(typename ELFO::Elf_Verdef) > SecEndAddress) + report_fatal_error("invalid offset in the section"); + auto *VD = reinterpret_cast<const typename ELFO::Elf_Verdef *>(P); + DictScope Entry(W, "Entry"); + W.printHex("Offset", (uintptr_t)P - (uintptr_t)SecStartAddress); + W.printNumber("Rev", VD->vd_version); + // FIXME: print something more readable. + W.printNumber("Flags", VD->vd_flags); + W.printNumber("Index", VD->vd_ndx); + W.printNumber("Cnt", VD->vd_cnt); + W.printString("Name", StringRef((const char *)(Obj->base() + + (*StrTabOrErr)->sh_offset + + VD->getAux()->vda_name))); + P += VD->vd_next; + } +} + +template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() { + // Dump version symbol section. + printVersionSymbolSection(this, Obj, dot_gnu_version_sec, W); + + // Dump version definition section. + printVersionDefinitionSection(this, Obj, dot_gnu_version_d_sec, W); +} + +template <typename ELFT> +StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, + const Elf_Sym *symb, + bool &IsDefault) { + // This is a dynamic symbol. Look in the GNU symbol version table. + if (!dot_gnu_version_sec) { + // No version table. + IsDefault = false; + return StringRef(""); + } + + // Determine the position in the symbol table of this entry. + size_t entry_index = (reinterpret_cast<uintptr_t>(symb) - + reinterpret_cast<uintptr_t>(DynSymStart)) / + sizeof(Elf_Sym); + + // Get the corresponding version index entry + const Elf_Versym *vs = + Obj->template getEntry<Elf_Versym>(dot_gnu_version_sec, entry_index); + size_t version_index = vs->vs_index & ELF::VERSYM_VERSION; + + // Special markers for unversioned symbols. + if (version_index == ELF::VER_NDX_LOCAL || + version_index == ELF::VER_NDX_GLOBAL) { + IsDefault = false; + return StringRef(""); + } + + // Lookup this symbol in the version table + LoadVersionMap(); + if (version_index >= VersionMap.size() || VersionMap[version_index].isNull()) + reportError("Invalid version entry"); + const VersionMapEntry &entry = VersionMap[version_index]; + + // Get the version name string + size_t name_offset; + if (entry.isVerdef()) { + // The first Verdaux entry holds the name. + name_offset = entry.getVerdef()->getAux()->vda_name; + IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN); + } else { + name_offset = entry.getVernaux()->vna_name; + IsDefault = false; + } + if (name_offset >= StrTab.size()) + reportError("Invalid string offset"); + return StringRef(StrTab.data() + name_offset); +} + +template <typename ELFT> +std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, + StringRef StrTable, + bool IsDynamic) { + StringRef SymbolName = errorOrDefault(Symbol->getName(StrTable)); if (!IsDynamic) return SymbolName; std::string FullSymbolName(SymbolName); bool IsDefault; - ErrorOr<StringRef> Version = - Obj.getSymbolVersion(nullptr, &*Symbol, IsDefault); - if (Version) { - FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += *Version; - } else - error(Version.getError()); + StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault); + FullSymbolName += (IsDefault ? "@@" : "@"); + FullSymbolName += Version; return FullSymbolName; } template <typename ELFO> static void getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, + const typename ELFO::Elf_Shdr *SymTab, + ArrayRef<typename ELFO::Elf_Word> ShndxTable, StringRef &SectionName, unsigned &SectionIndex) { SectionIndex = Symbol->st_shndx; if (Symbol->isUndefined()) @@ -162,25 +481,26 @@ getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, SectionName = "Reserved"; else { if (SectionIndex == SHN_XINDEX) - SectionIndex = Obj.getExtendedSymbolTableIndex(&*Symbol); + SectionIndex = + Obj.getExtendedSymbolTableIndex(Symbol, SymTab, ShndxTable); ErrorOr<const typename ELFO::Elf_Shdr *> Sec = Obj.getSection(SectionIndex); - if (!error(Sec.getError())) - SectionName = errorOrDefault(Obj.getSectionName(*Sec)); + error(Sec.getError()); + SectionName = errorOrDefault(Obj.getSectionName(*Sec)); } } -template <class ELFT> -static const typename ELFFile<ELFT>::Elf_Shdr * -findSectionByAddress(const ELFFile<ELFT> *Obj, uint64_t Addr) { +template <class ELFO> +static const typename ELFO::Elf_Shdr *findSectionByAddress(const ELFO *Obj, + uint64_t Addr) { for (const auto &Shdr : Obj->sections()) if (Shdr.sh_addr == Addr) return &Shdr; return nullptr; } -template <class ELFT> -static const typename ELFFile<ELFT>::Elf_Shdr * -findSectionByName(const ELFFile<ELFT> &Obj, StringRef Name) { +template <class ELFO> +static const typename ELFO::Elf_Shdr *findSectionByName(const ELFO &Obj, + StringRef Name) { for (const auto &Shdr : Obj.sections()) { if (Name == errorOrDefault(Obj.getSectionName(&Shdr))) return &Shdr; @@ -409,6 +729,12 @@ static const EnumEntry<unsigned> ElfSymbolTypes[] = { { "GNU_IFunc", ELF::STT_GNU_IFUNC } }; +static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = { + { "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL }, + { "AMDGPU_HSA_INDIRECT_FUNCTION", ELF::STT_AMDGPU_HSA_INDIRECT_FUNCTION }, + { "AMDGPU_HSA_METADATA", ELF::STT_AMDGPU_HSA_METADATA } +}; + static const char *getElfSectionType(unsigned Arch, unsigned Type) { switch (Arch) { case ELF::EM_ARM: @@ -473,13 +799,24 @@ static const EnumEntry<unsigned> ElfSectionFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ), LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION), LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ) + LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_GLOBAL), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_READONLY), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_CODE), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_AGENT) }; static const char *getElfSegmentType(unsigned Arch, unsigned Type) { // Check potentially overlapped processor-specific // program header type. switch (Arch) { + case ELF::EM_AMDGPU: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM); + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT); + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_READONLY_AGENT); + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_CODE_AGENT); + } case ELF::EM_ARM: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); @@ -565,9 +902,138 @@ static const EnumEntry<unsigned> ElfHeaderMipsFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R6) }; +template <typename ELFT> +ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) + : ObjDumper(Writer), Obj(Obj) { + + SmallVector<const Elf_Phdr *, 4> LoadSegments; + for (const Elf_Phdr &Phdr : Obj->program_headers()) { + if (Phdr.p_type == ELF::PT_DYNAMIC) { + DynamicProgHeader = &Phdr; + continue; + } + if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) + continue; + LoadSegments.push_back(&Phdr); + } + + auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { + const Elf_Phdr **I = std::upper_bound( + LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr<ELFT>); + if (I == LoadSegments.begin()) + report_fatal_error("Virtual address is not in any segment"); + --I; + const Elf_Phdr &Phdr = **I; + uint64_t Delta = VAddr - Phdr.p_vaddr; + if (Delta >= Phdr.p_filesz) + report_fatal_error("Virtual address is not in any segment"); + return Obj->base() + Phdr.p_offset + Delta; + }; + + uint64_t SONameOffset = 0; + const char *StringTableBegin = nullptr; + uint64_t StringTableSize = 0; + for (const Elf_Dyn &Dyn : dynamic_table()) { + switch (Dyn.d_tag) { + case ELF::DT_HASH: + HashTable = + reinterpret_cast<const Elf_Hash *>(toMappedAddr(Dyn.getPtr())); + break; + case ELF::DT_GNU_HASH: + GnuHashTable = + reinterpret_cast<const Elf_GnuHash *>(toMappedAddr(Dyn.getPtr())); + break; + case ELF::DT_RELA: + DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_RELASZ: + DynRelaRegion.Size = Dyn.getVal(); + break; + case ELF::DT_RELAENT: + DynRelaRegion.EntSize = Dyn.getVal(); + break; + case ELF::DT_SONAME: + SONameOffset = Dyn.getVal(); + break; + case ELF::DT_STRTAB: + StringTableBegin = (const char *)toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_STRSZ: + StringTableSize = Dyn.getVal(); + break; + case ELF::DT_SYMTAB: + DynSymStart = + reinterpret_cast<const Elf_Sym *>(toMappedAddr(Dyn.getPtr())); + break; + } + } + if (StringTableBegin) + DynamicStringTable = StringRef(StringTableBegin, StringTableSize); + if (SONameOffset) + SOName = getDynamicString(SONameOffset); + + for (const Elf_Shdr &Sec : Obj->sections()) { + switch (Sec.sh_type) { + case ELF::SHT_GNU_versym: + if (dot_gnu_version_sec != nullptr) + reportError("Multiple SHT_GNU_versym"); + dot_gnu_version_sec = &Sec; + break; + case ELF::SHT_GNU_verdef: + if (dot_gnu_version_d_sec != nullptr) + reportError("Multiple SHT_GNU_verdef"); + dot_gnu_version_d_sec = &Sec; + break; + case ELF::SHT_GNU_verneed: + if (dot_gnu_version_r_sec != nullptr) + reportError("Multilpe SHT_GNU_verneed"); + dot_gnu_version_r_sec = &Sec; + break; + case ELF::SHT_DYNSYM: + if (DotDynSymSec != nullptr) + reportError("Multilpe SHT_DYNSYM"); + DotDynSymSec = &Sec; + break; + case ELF::SHT_SYMTAB: + if (DotSymtabSec != nullptr) + reportError("Multilpe SHT_SYMTAB"); + DotSymtabSec = &Sec; + break; + case ELF::SHT_SYMTAB_SHNDX: { + ErrorOr<ArrayRef<Elf_Word>> TableOrErr = Obj->getSHNDXTable(Sec); + error(TableOrErr.getError()); + ShndxTable = *TableOrErr; + break; + } + } + } +} + +template <typename ELFT> +const typename ELFDumper<ELFT>::Elf_Rela * +ELFDumper<ELFT>::dyn_rela_begin() const { + if (DynRelaRegion.Size && DynRelaRegion.EntSize != sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast<const Elf_Rela *>(DynRelaRegion.Addr); +} + +template <typename ELFT> +const typename ELFDumper<ELFT>::Elf_Rela * +ELFDumper<ELFT>::dyn_rela_end() const { + uint64_t Size = DynRelaRegion.Size; + if (Size % sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation table size"); + return dyn_rela_begin() + Size / sizeof(Elf_Rela); +} + +template <typename ELFT> +typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const { + return make_range(dyn_rela_begin(), dyn_rela_end()); +} + template<class ELFT> void ELFDumper<ELFT>::printFileHeaders() { - const typename ELFO::Elf_Ehdr *Header = Obj->getHeader(); + const Elf_Ehdr *Header = Obj->getHeader(); { DictScope D(W, "ElfHeader"); @@ -618,7 +1084,7 @@ void ELFDumper<ELFT>::printSections() { ListScope SectionsD(W, "Sections"); int SectionIndex = -1; - for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { + for (const Elf_Shdr &Sec : Obj->sections()) { ++SectionIndex; StringRef Name = errorOrDefault(Obj->getSectionName(&Sec)); @@ -645,12 +1111,18 @@ void ELFDumper<ELFT>::printSections() { if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (const typename ELFO::Elf_Sym &Sym : Obj->symbols()) { - ErrorOr<const Elf_Shdr *> SymSec = Obj->getSection(&Sym); + const Elf_Shdr *Symtab = DotSymtabSec; + ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + + for (const Elf_Sym &Sym : Obj->symbols(Symtab)) { + ErrorOr<const Elf_Shdr *> SymSec = + Obj->getSection(&Sym, Symtab, ShndxTable); if (!SymSec) continue; if (*SymSec == &Sec) - printSymbol(&Sym, false); + printSymbol(&Sym, Symtab, StrTable, false); } } @@ -667,7 +1139,7 @@ void ELFDumper<ELFT>::printRelocations() { ListScope D(W, "Relocations"); int SectionNumber = -1; - for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { + for (const Elf_Shdr &Sec : Obj->sections()) { ++SectionNumber; if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) @@ -689,29 +1161,25 @@ template<class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() { W.startLine() << "Dynamic Relocations {\n"; W.indent(); - for (typename ELFO::Elf_Rela_Iter RelI = Obj->dyn_rela_begin(), - RelE = Obj->dyn_rela_end(); - RelI != RelE; ++RelI) { + for (const Elf_Rela &Rel : dyn_relas()) { SmallString<32> RelocName; - Obj->getRelocationTypeName(RelI->getType(Obj->isMips64EL()), RelocName); + Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef SymbolName; - uint32_t SymIndex = RelI->getSymbol(Obj->isMips64EL()); - const typename ELFO::Elf_Sym *Sym = Obj->dynamic_symbol_begin() + SymIndex; - SymbolName = errorOrDefault(Obj->getSymbolName(Sym, true)); + uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); + const Elf_Sym *Sym = DynSymStart + SymIndex; + SymbolName = errorOrDefault(Sym->getName(DynamicStringTable)); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); - W.printHex("Offset", RelI->r_offset); - W.printNumber("Type", RelocName, (int)RelI->getType(Obj->isMips64EL())); + W.printHex("Offset", Rel.r_offset); + W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); - W.printHex("Addend", RelI->r_addend); + W.printHex("Addend", Rel.r_addend); } else { raw_ostream& OS = W.startLine(); - OS << W.hex(RelI->r_offset) - << " " << RelocName - << " " << (SymbolName.size() > 0 ? SymbolName : "-") - << " " << W.hex(RelI->r_addend) - << "\n"; + OS << W.hex(Rel.r_offset) << " " << RelocName << " " + << (SymbolName.size() > 0 ? SymbolName : "-") << " " + << W.hex(Rel.r_addend) << "\n"; } } W.unindent(); @@ -720,51 +1188,43 @@ void ELFDumper<ELFT>::printDynamicRelocations() { template <class ELFT> void ELFDumper<ELFT>::printRelocations(const Elf_Shdr *Sec) { + ErrorOr<const Elf_Shdr *> SymTabOrErr = Obj->getSection(Sec->sh_link); + error(SymTabOrErr.getError()); + const Elf_Shdr *SymTab = *SymTabOrErr; + switch (Sec->sh_type) { case ELF::SHT_REL: - for (typename ELFO::Elf_Rel_Iter RI = Obj->rel_begin(Sec), - RE = Obj->rel_end(Sec); - RI != RE; ++RI) { - typename ELFO::Elf_Rela Rela; - Rela.r_offset = RI->r_offset; - Rela.r_info = RI->r_info; + for (const Elf_Rel &R : Obj->rels(Sec)) { + Elf_Rela Rela; + Rela.r_offset = R.r_offset; + Rela.r_info = R.r_info; Rela.r_addend = 0; - printRelocation(Sec, Rela); + printRelocation(Rela, SymTab); } break; case ELF::SHT_RELA: - for (typename ELFO::Elf_Rela_Iter RI = Obj->rela_begin(Sec), - RE = Obj->rela_end(Sec); - RI != RE; ++RI) { - printRelocation(Sec, *RI); - } + for (const Elf_Rela &R : Obj->relas(Sec)) + printRelocation(R, SymTab); break; } } template <class ELFT> -void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec, - typename ELFO::Elf_Rela Rel) { +void ELFDumper<ELFT>::printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab) { SmallString<32> RelocName; Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef TargetName; - std::pair<const Elf_Shdr *, const Elf_Sym *> Sym = - Obj->getRelocationSymbol(Sec, &Rel); - if (Sym.second && Sym.second->getType() == ELF::STT_SECTION) { - ErrorOr<const Elf_Shdr *> Sec = Obj->getSection(Sym.second); - if (!error(Sec.getError())) { - ErrorOr<StringRef> SecName = Obj->getSectionName(*Sec); - if (SecName) - TargetName = SecName.get(); - } - } else if (Sym.first) { - const Elf_Shdr *SymTable = Sym.first; - ErrorOr<const Elf_Shdr *> StrTableSec = Obj->getSection(SymTable->sh_link); - if (!error(StrTableSec.getError())) { - ErrorOr<StringRef> StrTableOrErr = Obj->getStringTable(*StrTableSec); - if (!error(StrTableOrErr.getError())) - TargetName = errorOrDefault(Sym.second->getName(*StrTableOrErr)); - } + const Elf_Sym *Sym = Obj->getRelocationSymbol(&Rel, SymTab); + if (Sym && Sym->getType() == ELF::STT_SECTION) { + ErrorOr<const Elf_Shdr *> Sec = Obj->getSection(Sym, SymTab, ShndxTable); + error(Sec.getError()); + ErrorOr<StringRef> SecName = Obj->getSectionName(*Sec); + if (SecName) + TargetName = SecName.get(); + } else if (Sym) { + ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*SymTab); + error(StrTableOrErr.getError()); + TargetName = errorOrDefault(Sym->getName(*StrTableOrErr)); } if (opts::ExpandRelocs) { @@ -783,27 +1243,38 @@ void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec, } template<class ELFT> +void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) { + const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec; + if (!Symtab) + return; + ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + for (const Elf_Sym &Sym : Obj->symbols(Symtab)) + printSymbol(&Sym, Symtab, StrTable, IsDynamic); +} + +template<class ELFT> void ELFDumper<ELFT>::printSymbols() { ListScope Group(W, "Symbols"); - for (const typename ELFO::Elf_Sym &Sym : Obj->symbols()) - printSymbol(&Sym, false); + printSymbolsHelper(false); } template<class ELFT> void ELFDumper<ELFT>::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); - - for (const typename ELFO::Elf_Sym &Sym : Obj->dynamic_symbols()) - printSymbol(&Sym, true); + printSymbolsHelper(true); } template <class ELFT> -void ELFDumper<ELFT>::printSymbol(const typename ELFO::Elf_Sym *Symbol, - bool IsDynamic) { +void ELFDumper<ELFT>::printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, + StringRef StrTable, bool IsDynamic) { unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex); - std::string FullSymbolName = getFullSymbolName(*Obj, Symbol, IsDynamic); + getSectionNameIndex(*Obj, Symbol, SymTab, ShndxTable, SectionName, + SectionIndex); + std::string FullSymbolName = getFullSymbolName(Symbol, StrTable, IsDynamic); + unsigned char SymbolType = Symbol->getType(); DictScope D(W, "Symbol"); W.printNumber("Name", FullSymbolName, Symbol->st_name); @@ -811,7 +1282,11 @@ void ELFDumper<ELFT>::printSymbol(const typename ELFO::Elf_Sym *Symbol, W.printNumber("Size", Symbol->st_size); W.printEnum ("Binding", Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); - W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes)); + if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU && + SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) + W.printEnum ("Type", SymbolType, makeArrayRef(AMDGPUSymbolTypes)); + else + W.printEnum ("Type", SymbolType, makeArrayRef(ElfSymbolTypes)); W.printNumber("Other", Symbol->st_other); W.printHex("Section", SectionName, SectionIndex); } @@ -855,12 +1330,15 @@ static const char *getTypeString(uint64_t Type) { LLVM_READOBJ_TYPE_CASE(SYMENT); LLVM_READOBJ_TYPE_CASE(SYMTAB); LLVM_READOBJ_TYPE_CASE(TEXTREL); + LLVM_READOBJ_TYPE_CASE(VERDEF); + LLVM_READOBJ_TYPE_CASE(VERDEFNUM); LLVM_READOBJ_TYPE_CASE(VERNEED); LLVM_READOBJ_TYPE_CASE(VERNEEDNUM); LLVM_READOBJ_TYPE_CASE(VERSYM); LLVM_READOBJ_TYPE_CASE(RELCOUNT); LLVM_READOBJ_TYPE_CASE(GNU_HASH); LLVM_READOBJ_TYPE_CASE(MIPS_RLD_VERSION); + LLVM_READOBJ_TYPE_CASE(MIPS_RLD_MAP_REL); LLVM_READOBJ_TYPE_CASE(MIPS_FLAGS); LLVM_READOBJ_TYPE_CASE(MIPS_BASE_ADDRESS); LLVM_READOBJ_TYPE_CASE(MIPS_LOCAL_GOTNO); @@ -956,8 +1434,15 @@ void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) { } template <class ELFT> -static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, - bool Is64, raw_ostream &OS) { +StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const { + if (Value >= DynamicStringTable.size()) + reportError("Invalid dynamic string table reference"); + return StringRef(DynamicStringTable.data() + Value); +} + +template <class ELFT> +void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { + raw_ostream &OS = W.getOStream(); switch (Type) { case DT_PLTREL: if (Value == DT_REL) { @@ -981,6 +1466,7 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: case DT_DEBUG: + case DT_VERDEF: case DT_VERNEED: case DT_VERSYM: case DT_GNU_HASH: @@ -988,11 +1474,13 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_MIPS_BASE_ADDRESS: case DT_MIPS_GOTSYM: case DT_MIPS_RLD_MAP: + case DT_MIPS_RLD_MAP_REL: case DT_MIPS_PLTGOT: case DT_MIPS_OPTIONS: OS << format("0x%" PRIX64, Value); break; case DT_RELCOUNT: + case DT_VERDEFNUM: case DT_VERNEEDNUM: case DT_MIPS_RLD_VERSION: case DT_MIPS_LOCAL_GOTNO: @@ -1013,14 +1501,14 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, OS << Value << " (bytes)"; break; case DT_NEEDED: - OS << "SharedLibrary (" << O->getDynamicString(Value) << ")"; + OS << "SharedLibrary (" << getDynamicString(Value) << ")"; break; case DT_SONAME: - OS << "LibrarySoname (" << O->getDynamicString(Value) << ")"; + OS << "LibrarySoname (" << getDynamicString(Value) << ")"; break; case DT_RPATH: case DT_RUNPATH: - OS << O->getDynamicString(Value); + OS << getDynamicString(Value); break; case DT_MIPS_FLAGS: printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS); @@ -1046,7 +1534,8 @@ namespace { template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() { const unsigned Machine = Obj->getHeader()->e_machine; if (Machine == EM_ARM) { - ARM::EHABI::PrinterContext<ELFType<support::little, false>> Ctx(W, Obj); + ARM::EHABI::PrinterContext<ELFType<support::little, false>> Ctx( + W, Obj, DotSymtabSec); return Ctx.PrintUnwindInformation(); } W.startLine() << "UnwindInfo not implemented.\n"; @@ -1055,9 +1544,20 @@ template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() { template<class ELFT> void ELFDumper<ELFT>::printDynamicTable() { - auto DynTable = Obj->dynamic_table(true); + auto I = dynamic_table_begin(); + auto E = dynamic_table_end(); - ptrdiff_t Total = std::distance(DynTable.begin(), DynTable.end()); + if (I == E) + return; + + --E; + while (I != E && E->getTag() == ELF::DT_NULL) + --E; + if (E->getTag() != ELF::DT_NULL) + ++E; + ++E; + + ptrdiff_t Total = std::distance(I, E); if (Total == 0) return; @@ -1069,12 +1569,13 @@ void ELFDumper<ELFT>::printDynamicTable() { W.startLine() << " Tag" << (Is64 ? " " : " ") << "Type" << " " << "Name/Value\n"; - for (const auto &Entry : DynTable) { - W.startLine() - << " " - << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Entry.getTag()) - << " " << format("%-21s", getTypeString(Entry.getTag())); - printValue(Obj, Entry.getTag(), Entry.getVal(), Is64, OS); + while (I != E) { + const Elf_Dyn &Entry = *I; + uintX_t Tag = Entry.getTag(); + ++I; + W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " " + << format("%-21s", getTypeString(Tag)); + printValue(Tag, Entry.getVal()); OS << "\n"; } @@ -1088,14 +1589,14 @@ void ELFDumper<ELFT>::printNeededLibraries() { typedef std::vector<StringRef> LibsTy; LibsTy Libs; - for (const auto &Entry : Obj->dynamic_table()) + for (const auto &Entry : dynamic_table()) if (Entry.d_tag == ELF::DT_NEEDED) - Libs.push_back(Obj->getDynamicString(Entry.d_un.d_val)); + Libs.push_back(getDynamicString(Entry.d_un.d_val)); std::stable_sort(Libs.begin(), Libs.end()); - for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); I != E; ++I) { - outs() << " " << *I << "\n"; + for (const auto &L : Libs) { + outs() << " " << L << "\n"; } } @@ -1103,33 +1604,51 @@ template<class ELFT> void ELFDumper<ELFT>::printProgramHeaders() { ListScope L(W, "ProgramHeaders"); - for (typename ELFO::Elf_Phdr_Iter PI = Obj->program_header_begin(), - PE = Obj->program_header_end(); - PI != PE; ++PI) { + for (const Elf_Phdr &Phdr : Obj->program_headers()) { DictScope P(W, "ProgramHeader"); - W.printHex ("Type", - getElfSegmentType(Obj->getHeader()->e_machine, PI->p_type), - PI->p_type); - W.printHex ("Offset", PI->p_offset); - W.printHex ("VirtualAddress", PI->p_vaddr); - W.printHex ("PhysicalAddress", PI->p_paddr); - W.printNumber("FileSize", PI->p_filesz); - W.printNumber("MemSize", PI->p_memsz); - W.printFlags ("Flags", PI->p_flags, makeArrayRef(ElfSegmentFlags)); - W.printNumber("Alignment", PI->p_align); + W.printHex("Type", + getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type), + Phdr.p_type); + W.printHex("Offset", Phdr.p_offset); + W.printHex("VirtualAddress", Phdr.p_vaddr); + W.printHex("PhysicalAddress", Phdr.p_paddr); + W.printNumber("FileSize", Phdr.p_filesz); + W.printNumber("MemSize", Phdr.p_memsz); + W.printFlags("Flags", Phdr.p_flags, makeArrayRef(ElfSegmentFlags)); + W.printNumber("Alignment", Phdr.p_align); } } template <typename ELFT> void ELFDumper<ELFT>::printHashTable() { DictScope D(W, "HashTable"); - auto HT = Obj->getHashTable(); - if (!HT) + if (!HashTable) + return; + W.printNumber("Num Buckets", HashTable->nbucket); + W.printNumber("Num Chains", HashTable->nchain); + W.printList("Buckets", HashTable->buckets()); + W.printList("Chains", HashTable->chains()); +} + +template <typename ELFT> +void ELFDumper<ELFT>::printGnuHashTable() { + DictScope D(W, "GnuHashTable"); + if (!GnuHashTable) return; - W.printNumber("Num Buckets", HT->nbucket); - W.printNumber("Num Chains", HT->nchain); - W.printList("Buckets", HT->buckets()); - W.printList("Chains", HT->chains()); + W.printNumber("Num Buckets", GnuHashTable->nbuckets); + W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx); + W.printNumber("Num Mask Words", GnuHashTable->maskwords); + W.printNumber("Shift Count", GnuHashTable->shift2); + W.printHexList("Bloom Filter", GnuHashTable->filter()); + W.printList("Buckets", GnuHashTable->buckets()); + if (!DotDynSymSec) + reportError("No dynamic symbol section"); + W.printHexList("Values", + GnuHashTable->values(DotDynSymSec->getEntityCount())); +} + +template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { + outs() << "LoadName: " << SOName << '\n'; } template <class ELFT> @@ -1171,21 +1690,23 @@ template <> void ELFDumper<ELFType<support::little, false>>::printAttributes() { namespace { template <class ELFT> class MipsGOTParser { public: - typedef object::ELFFile<ELFT> ObjectFile; - typedef typename ObjectFile::Elf_Shdr Elf_Shdr; - typedef typename ObjectFile::Elf_Sym Elf_Sym; + typedef object::ELFFile<ELFT> ELFO; + typedef typename ELFO::Elf_Shdr Elf_Shdr; + typedef typename ELFO::Elf_Sym Elf_Sym; + typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; + typedef typename ELFO::Elf_Addr GOTEntry; + typedef typename ELFO::Elf_Rel Elf_Rel; + typedef typename ELFO::Elf_Rela Elf_Rela; - MipsGOTParser(const ObjectFile *Obj, StreamWriter &W); + MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, + Elf_Dyn_Range DynTable, StreamWriter &W); void parseGOT(); void parsePLT(); private: - typedef typename ObjectFile::Elf_Addr GOTEntry; - typedef typename ObjectFile::template ELFEntityIterator<const GOTEntry> - GOTIter; - - const ObjectFile *Obj; + ELFDumper<ELFT> *Dumper; + const ELFO *Obj; StreamWriter &W; llvm::Optional<uint64_t> DtPltGot; llvm::Optional<uint64_t> DtLocalGotNum; @@ -1194,22 +1715,26 @@ private: llvm::Optional<uint64_t> DtJmpRel; std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const; - GOTIter makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); - - void printGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It); - void printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It, - const Elf_Sym *Sym, bool IsDynamic); - void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It, - StringRef Purpose); - void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It, + const GOTEntry *makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); + + void printGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, + const GOTEntry *It); + void printGlobalGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, + const GOTEntry *It, const Elf_Sym *Sym, + StringRef StrTable, bool IsDynamic); + void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, + const GOTEntry *It, StringRef Purpose); + void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, + const GOTEntry *It, StringRef StrTable, const Elf_Sym *Sym); }; } template <class ELFT> -MipsGOTParser<ELFT>::MipsGOTParser(const ObjectFile *Obj, StreamWriter &W) - : Obj(Obj), W(W) { - for (const auto &Entry : Obj->dynamic_table()) { +MipsGOTParser<ELFT>::MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, + Elf_Dyn_Range DynTable, StreamWriter &W) + : Dumper(Dumper), Obj(Obj), W(W) { + for (const auto &Entry : DynTable) { switch (Entry.getTag()) { case ELF::DT_PLTGOT: DtPltGot = Entry.getVal(); @@ -1264,8 +1789,11 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { return; } - const Elf_Sym *DynSymBegin = Obj->dynamic_symbol_begin(); - const Elf_Sym *DynSymEnd = Obj->dynamic_symbol_end(); + const Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); + ErrorOr<StringRef> StrTable = Obj->getStringTableForSymtab(*DynSymSec); + error(StrTable.getError()); + const Elf_Sym *DynSymBegin = Obj->symbol_begin(DynSymSec); + const Elf_Sym *DynSymEnd = Obj->symbol_end(DynSymSec); std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); if (*DtGotSym > DynSymTotal) { @@ -1280,9 +1808,9 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { return; } - GOTIter GotBegin = makeGOTIter(*GOT, 0); - GOTIter GotLocalEnd = makeGOTIter(*GOT, *DtLocalGotNum); - GOTIter It = GotBegin; + const GOTEntry *GotBegin = makeGOTIter(*GOT, 0); + const GOTEntry *GotLocalEnd = makeGOTIter(*GOT, *DtLocalGotNum); + const GOTEntry *It = GotBegin; DictScope GS(W, "Primary GOT"); @@ -1312,11 +1840,13 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { { ListScope GS(W, "Global entries"); - GOTIter GotGlobalEnd = makeGOTIter(*GOT, *DtLocalGotNum + GlobalGotNum); + const GOTEntry *GotGlobalEnd = + makeGOTIter(*GOT, *DtLocalGotNum + GlobalGotNum); const Elf_Sym *GotDynSym = DynSymBegin + *DtGotSym; for (; It != GotGlobalEnd; ++It) { DictScope D(W, "Entry"); - printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, true); + printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, + *StrTable, true); } } @@ -1350,10 +1880,16 @@ template <class ELFT> void MipsGOTParser<ELFT>::parsePLT() { W.startLine() << "There is no .rel.plt section in the file.\n"; return; } + ErrorOr<const Elf_Shdr *> SymTableOrErr = + Obj->getSection(PLTRelShdr->sh_link); + error(SymTableOrErr.getError()); + const Elf_Shdr *SymTable = *SymTableOrErr; + ErrorOr<StringRef> StrTable = Obj->getStringTableForSymtab(*SymTable); + error(StrTable.getError()); - GOTIter PLTBegin = makeGOTIter(*PLT, 0); - GOTIter PLTEnd = makeGOTIter(*PLT, getGOTTotal(*PLT)); - GOTIter It = PLTBegin; + const GOTEntry *PLTBegin = makeGOTIter(*PLT, 0); + const GOTEntry *PLTEnd = makeGOTIter(*PLT, getGOTTotal(*PLT)); + const GOTEntry *It = PLTBegin; DictScope GS(W, "PLT GOT"); { @@ -1367,21 +1903,19 @@ template <class ELFT> void MipsGOTParser<ELFT>::parsePLT() { switch (PLTRelShdr->sh_type) { case ELF::SHT_REL: - for (typename ObjectFile::Elf_Rel_Iter RI = Obj->rel_begin(PLTRelShdr), - RE = Obj->rel_end(PLTRelShdr); + for (const Elf_Rel *RI = Obj->rel_begin(PLTRelShdr), + *RE = Obj->rel_end(PLTRelShdr); RI != RE && It != PLTEnd; ++RI, ++It) { - const Elf_Sym *Sym = - Obj->getRelocationSymbol(&*PLTRelShdr, &*RI).second; - printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, Sym); + const Elf_Sym *Sym = Obj->getRelocationSymbol(&*RI, SymTable); + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, *StrTable, Sym); } break; case ELF::SHT_RELA: - for (typename ObjectFile::Elf_Rela_Iter RI = Obj->rela_begin(PLTRelShdr), - RE = Obj->rela_end(PLTRelShdr); + for (const Elf_Rela *RI = Obj->rela_begin(PLTRelShdr), + *RE = Obj->rela_end(PLTRelShdr); RI != RE && It != PLTEnd; ++RI, ++It) { - const Elf_Sym *Sym = - Obj->getRelocationSymbol(&*PLTRelShdr, &*RI).second; - printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, Sym); + const Elf_Sym *Sym = Obj->getRelocationSymbol(&*RI, SymTable); + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, *StrTable, Sym); } break; } @@ -1394,15 +1928,16 @@ std::size_t MipsGOTParser<ELFT>::getGOTTotal(ArrayRef<uint8_t> GOT) const { } template <class ELFT> -typename MipsGOTParser<ELFT>::GOTIter +const typename MipsGOTParser<ELFT>::GOTEntry * MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) { const char *Data = reinterpret_cast<const char *>(GOT.data()); - return GOTIter(sizeof(GOTEntry), Data + EntryNum * sizeof(GOTEntry)); + return reinterpret_cast<const GOTEntry *>(Data + EntryNum * sizeof(GOTEntry)); } template <class ELFT> -void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt, - GOTIter It) { +void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, + const GOTEntry *BeginIt, + const GOTEntry *It) { int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); W.printHex("Address", GotAddr + Offset); W.printNumber("Access", Offset - 0x7ff0); @@ -1410,9 +1945,9 @@ void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt, } template <class ELFT> -void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, - GOTIter It, const Elf_Sym *Sym, - bool IsDynamic) { +void MipsGOTParser<ELFT>::printGlobalGotEntry( + uint64_t GotAddr, const GOTEntry *BeginIt, const GOTEntry *It, + const Elf_Sym *Sym, StringRef StrTable, bool IsDynamic) { printGotEntry(GotAddr, BeginIt, It); W.printHex("Value", Sym->st_value); @@ -1420,16 +1955,19 @@ void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); - std::string FullSymbolName = getFullSymbolName(*Obj, Sym, IsDynamic); + std::string FullSymbolName = + Dumper->getFullSymbolName(Sym, StrTable, IsDynamic); W.printNumber("Name", FullSymbolName, Sym->st_name); } template <class ELFT> -void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, - GOTIter It, StringRef Purpose) { +void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, + const GOTEntry *BeginIt, + const GOTEntry *It, StringRef Purpose) { DictScope D(W, "Entry"); int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); W.printHex("Address", PLTAddr + Offset); @@ -1438,8 +1976,10 @@ void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, } template <class ELFT> -void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, - GOTIter It, const Elf_Sym *Sym) { +void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, + const GOTEntry *BeginIt, + const GOTEntry *It, StringRef StrTable, + const Elf_Sym *Sym) { DictScope D(W, "Entry"); int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); W.printHex("Address", PLTAddr + Offset); @@ -1449,10 +1989,11 @@ void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); - std::string FullSymbolName = getFullSymbolName(*Obj, Sym, true); + std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true); W.printNumber("Name", FullSymbolName, Sym->st_name); } @@ -1462,7 +2003,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { return; } - MipsGOTParser<ELFT> GOTParser(Obj, W); + MipsGOTParser<ELFT> GOTParser(this, Obj, dynamic_table(), W); GOTParser.parseGOT(); GOTParser.parsePLT(); } @@ -1604,7 +2145,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsReginfo() { } template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { - const typename ELFFile<ELFT>::Elf_Shdr *StackMapSection = nullptr; + const Elf_Shdr *StackMapSection = nullptr; for (const auto &Sec : Obj->sections()) { ErrorOr<StringRef> Name = Obj->getSectionName(&Sec); if (*Name == ".llvm_stackmaps") { diff --git a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp index adb99b0..58d2c9f 100644 --- a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp @@ -40,6 +40,14 @@ public: void printUnwindInfo() override; void printStackMap() const override; + // MachO-specific. + void printMachODataInCode() override; + void printMachOVersionMin() override; + void printMachODysymtab() override; + void printMachOSegment() override; + void printMachOIndirectSymbols() override; + void printMachOLinkerOptions () override; + private: template<class MachHeader> void printFileHeaders(const MachHeader &Header); @@ -255,6 +263,21 @@ namespace { uint32_t Flags; uint32_t Reserved1; uint32_t Reserved2; + uint32_t Reserved3; + }; + + struct MachOSegment { + std::string CmdName; + std::string SegName; + uint64_t cmdsize; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; }; struct MachOSymbol { @@ -266,6 +289,18 @@ namespace { }; } +static std::string getMask(uint32_t prot) +{ + // TODO (davide): This always assumes prot is valid. + // Catch mistakes and report if needed. + std::string Prot; + Prot = ""; + Prot += (prot & MachO::VM_PROT_READ) ? "r" : "-"; + Prot += (prot & MachO::VM_PROT_WRITE) ? "w" : "-"; + Prot += (prot & MachO::VM_PROT_EXECUTE) ? "x" : "-"; + return Prot; +} + static void getSection(const MachOObjectFile *Obj, DataRefImpl Sec, MachOSection &Section) { @@ -292,8 +327,40 @@ static void getSection(const MachOObjectFile *Obj, Section.Flags = Sect.flags; Section.Reserved1 = Sect.reserved1; Section.Reserved2 = Sect.reserved2; + Section.Reserved3 = Sect.reserved3; } +static void getSegment(const MachOObjectFile *Obj, + const MachOObjectFile::LoadCommandInfo &L, + MachOSegment &Segment) { + if (!Obj->is64Bit()) { + MachO::segment_command SC = Obj->getSegmentLoadCommand(L); + Segment.CmdName = "LC_SEGMENT"; + Segment.SegName = SC.segname; + Segment.cmdsize = SC.cmdsize; + Segment.vmaddr = SC.vmaddr; + Segment.vmsize = SC.vmsize; + Segment.fileoff = SC.fileoff; + Segment.filesize = SC.filesize; + Segment.maxprot = SC.maxprot; + Segment.initprot = SC.initprot; + Segment.nsects = SC.nsects; + Segment.flags = SC.flags; + return; + } + MachO::segment_command_64 SC = Obj->getSegment64LoadCommand(L); + Segment.CmdName = "LC_SEGMENT_64"; + Segment.SegName = SC.segname; + Segment.cmdsize = SC.cmdsize; + Segment.vmaddr = SC.vmaddr; + Segment.vmsize = SC.vmsize; + Segment.fileoff = SC.fileoff; + Segment.filesize = SC.filesize; + Segment.maxprot = SC.maxprot; + Segment.initprot = SC.initprot; + Segment.nsects = SC.nsects; + Segment.flags = SC.flags; +} static void getSymbol(const MachOObjectFile *Obj, DataRefImpl DRI, @@ -375,8 +442,7 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { DataRefImpl DR = Section.getRawDataRefImpl(); StringRef Name; - if (error(Section.getName(Name))) - Name = ""; + error(Section.getName(Name)); ArrayRef<char> RawName = Obj->getSectionRawName(DR); StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); @@ -398,6 +464,8 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { makeArrayRef(MachOSectionAttributes)); W.printHex("Reserved1", MOSection.Reserved1); W.printHex("Reserved2", MOSection.Reserved2); + if (Obj->is64Bit()) + W.printHex("Reserved3", MOSection.Reserved3); if (opts::SectionRelocations) { ListScope D(W, "Relocations"); @@ -419,8 +487,7 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { bool IsBSS = Section.isBSS(); if (!IsBSS) { StringRef Data; - if (error(Section.getContents(Data))) - break; + error(Section.getContents(Data)); W.printBinaryBlock("SectionData", Data); } @@ -434,8 +501,7 @@ void MachODumper::printRelocations() { std::error_code EC; for (const SectionRef &Section : Obj->sections()) { StringRef Name; - if (error(Section.getName(Name))) - continue; + error(Section.getName(Name)); bool PrintedGroup = false; for (const RelocationRef &Reloc : Section.relocations()) { @@ -475,15 +541,13 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, symbol_iterator Symbol = Reloc.getSymbol(); if (Symbol != Obj->symbol_end()) { ErrorOr<StringRef> TargetNameOrErr = Symbol->getName(); - if (error(TargetNameOrErr.getError())) - return; + error(TargetNameOrErr.getError()); TargetName = *TargetNameOrErr; } } else if (!IsScattered) { section_iterator SecI = Obj->getRelocationSection(DR); if (SecI != Obj->section_end()) { - if (error(SecI->getName(TargetName))) - return; + error(SecI->getName(TargetName)); } } if (TargetName.empty()) @@ -547,8 +611,10 @@ void MachODumper::printSymbol(const SymbolRef &Symbol) { getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol); StringRef SectionName = ""; - section_iterator SecI(Obj->section_begin()); - if (!error(Symbol.getSection(SecI)) && SecI != Obj->section_end()) + ErrorOr<section_iterator> SecIOrErr = Symbol.getSection(); + error(SecIOrErr.getError()); + section_iterator SecI = *SecIOrErr; + if (SecI != Obj->section_end()) error(SecI->getName(SectionName)); DictScope D(W, "Symbol"); @@ -603,3 +669,153 @@ void MachODumper::printStackMap() const { prettyPrintStackMap(llvm::outs(), StackMapV1Parser<support::big>(StackMapContentsArray)); } + +void MachODumper::printMachODataInCode() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { + MachO::linkedit_data_command LLC = Obj->getLinkeditDataLoadCommand(Load); + DictScope Group(W, "DataInCode"); + W.printNumber("Data offset", LLC.dataoff); + W.printNumber("Data size", LLC.datasize); + ListScope D(W, "Data entries"); + unsigned NumRegions = LLC.datasize / sizeof(MachO::data_in_code_entry); + for (unsigned i = 0; i < NumRegions; ++i) { + MachO::data_in_code_entry DICE = Obj->getDataInCodeTableEntry( + LLC.dataoff, i); + DictScope Group(W, "Entry"); + W.printNumber("Index", i); + W.printNumber("Offset", DICE.offset); + W.printNumber("Length", DICE.length); + W.printNumber("Kind", DICE.kind); + } + } + } +} + +void MachODumper::printMachOVersionMin() { + for (const auto &Load : Obj->load_commands()) { + StringRef Cmd; + switch (Load.C.cmd) { + case MachO::LC_VERSION_MIN_MACOSX: + Cmd = "LC_VERSION_MIN_MACOSX"; + break; + case MachO::LC_VERSION_MIN_IPHONEOS: + Cmd = "LC_VERSION_MIN_IPHONEOS"; + break; + case MachO::LC_VERSION_MIN_TVOS: + Cmd = "LC_VERSION_MIN_TVOS"; + break; + case MachO::LC_VERSION_MIN_WATCHOS: + Cmd = "LC_VERSION_MIN_WATCHOS"; + break; + default: + continue; + } + + MachO::version_min_command VMC = Obj->getVersionMinLoadCommand(Load); + DictScope Group(W, "MinVersion"); + W.printString("Cmd", Cmd); + W.printNumber("Size", VMC.cmdsize); + SmallString<32> Version; + Version = utostr(MachOObjectFile::getVersionMinMajor(VMC, false)) + "." + + utostr(MachOObjectFile::getVersionMinMinor(VMC, false)); + uint32_t Update = MachOObjectFile::getVersionMinUpdate(VMC, false); + if (Update != 0) + Version += "." + utostr(MachOObjectFile::getVersionMinUpdate(VMC, false)); + W.printString("Version", Version); + SmallString<32> SDK; + if (VMC.sdk == 0) + SDK = "n/a"; + else { + SDK = utostr(MachOObjectFile::getVersionMinMajor(VMC, true)) + "." + + utostr(MachOObjectFile::getVersionMinMinor(VMC, true)); + uint32_t Update = MachOObjectFile::getVersionMinUpdate(VMC, true); + if (Update != 0) + SDK += "." + utostr(MachOObjectFile::getVersionMinUpdate(VMC, true)); + } + W.printString("SDK", SDK); + } +} + +void MachODumper::printMachODysymtab() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_DYSYMTAB) { + MachO::dysymtab_command DLC = Obj->getDysymtabLoadCommand(); + DictScope Group(W, "Dysymtab"); + W.printNumber("ilocalsym", DLC.ilocalsym); + W.printNumber("nlocalsym", DLC.nlocalsym); + W.printNumber("iextdefsym", DLC.iextdefsym); + W.printNumber("nextdefsym", DLC.nextdefsym); + W.printNumber("iundefsym", DLC.iundefsym); + W.printNumber("nundefsym", DLC.nundefsym); + W.printNumber("tocoff", DLC.tocoff); + W.printNumber("ntoc", DLC.ntoc); + W.printNumber("modtaboff", DLC.modtaboff); + W.printNumber("nmodtab", DLC.nmodtab); + W.printNumber("extrefsymoff", DLC.extrefsymoff); + W.printNumber("nextrefsyms", DLC.nextrefsyms); + W.printNumber("indirectsymoff", DLC.indirectsymoff); + W.printNumber("nindirectsyms", DLC.nindirectsyms); + W.printNumber("extreloff", DLC.extreloff); + W.printNumber("nextrel", DLC.nextrel); + W.printNumber("locreloff", DLC.locreloff); + W.printNumber("nlocrel", DLC.nlocrel); + } + } +} + +void MachODumper::printMachOSegment() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_SEGMENT || Load.C.cmd == MachO::LC_SEGMENT_64) { + MachOSegment MOSegment; + getSegment(Obj, Load, MOSegment); + DictScope Group(W, "Segment"); + W.printString("Cmd", MOSegment.CmdName); + W.printString("Name", MOSegment.SegName); + W.printNumber("Size", MOSegment.cmdsize); + W.printHex("vmaddr", MOSegment.vmaddr); + W.printHex("vmsize", MOSegment.vmsize); + W.printNumber("fileoff", MOSegment.fileoff); + W.printNumber("filesize", MOSegment.filesize); + W.printString("maxprot", getMask(MOSegment.maxprot)); + W.printString("initprot", getMask(MOSegment.initprot)); + W.printNumber("nsects", MOSegment.nsects); + W.printHex("flags", MOSegment.flags); + } + } +} + +void MachODumper::printMachOIndirectSymbols() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_DYSYMTAB) { + MachO::dysymtab_command DLC = Obj->getDysymtabLoadCommand(); + DictScope Group(W, "Indirect Symbols"); + W.printNumber("Number", DLC.nindirectsyms); + ListScope D(W, "Symbols"); + for (unsigned i = 0; i < DLC.nindirectsyms; ++i) { + DictScope Group(W, "Entry"); + W.printNumber("Entry Index", i); + W.printHex("Symbol Index", Obj->getIndirectSymbolTableEntry(DLC, i)); + } + } + } +} + +void MachODumper::printMachOLinkerOptions() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_LINKER_OPTION) { + MachO::linker_option_command LOLC = Obj->getLinkerOptionLoadCommand(Load); + DictScope Group(W, "Linker Options"); + W.printNumber("Size", LOLC.cmdsize); + ListScope D(W, "Strings"); + uint64_t DataSize = LOLC.cmdsize - sizeof(MachO::linker_option_command); + const char *P = Load.Ptr + sizeof(MachO::linker_option_command); + StringRef Data(P, DataSize); + for (unsigned i = 0; i < LOLC.count; ++i) { + std::pair<StringRef,StringRef> Split = Data.split('\0'); + W.printString("Value", Split.first); + Data = Split.second; + } + } + } +} diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h index 5ecf0ec..db26d69 100644 --- a/contrib/llvm/tools/llvm-readobj/ObjDumper.h +++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h @@ -1,4 +1,4 @@ -//===-- ObjDumper.h -------------------------------------------------------===// +//===-- ObjDumper.h ---------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,7 +15,8 @@ namespace llvm { namespace object { - class ObjectFile; +class COFFImportFile; +class ObjectFile; } class StreamWriter; @@ -38,6 +39,9 @@ public: virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } virtual void printHashTable() { } + virtual void printGnuHashTable() { } + virtual void printLoadName() {} + virtual void printVersionInfo() {} // Only implemented for ARM ELF at this time. virtual void printAttributes() { } @@ -52,6 +56,15 @@ public: virtual void printCOFFExports() { } virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } + virtual void printCodeViewDebugInfo() { } + + // Only implemented for MachO. + virtual void printMachODataInCode() { } + virtual void printMachOVersionMin() { } + virtual void printMachODysymtab() { } + virtual void printMachOSegment() { } + virtual void printMachOIndirectSymbols() { } + virtual void printMachOLinkerOptions() { } virtual void printStackMap() const = 0; @@ -71,6 +84,8 @@ std::error_code createMachODumper(const object::ObjectFile *Obj, StreamWriter &Writer, std::unique_ptr<ObjDumper> &Result); +void dumpCOFFImportFile(const object::COFFImportFile *File); + } // namespace llvm #endif diff --git a/contrib/llvm/tools/llvm-readobj/StreamWriter.h b/contrib/llvm/tools/llvm-readobj/StreamWriter.h index f3cc57e..d2dbb07 100644 --- a/contrib/llvm/tools/llvm-readobj/StreamWriter.h +++ b/contrib/llvm/tools/llvm-readobj/StreamWriter.h @@ -34,14 +34,17 @@ struct HexNumber { // unsigned type. The overloads are here so that every type that is implicitly // convertible to an integer (including enums and endian helpers) can be used // without requiring type traits or call-site changes. - HexNumber(int8_t Value) : Value(static_cast<uint8_t >(Value)) { } - HexNumber(int16_t Value) : Value(static_cast<uint16_t>(Value)) { } - HexNumber(int32_t Value) : Value(static_cast<uint32_t>(Value)) { } - HexNumber(int64_t Value) : Value(static_cast<uint64_t>(Value)) { } - HexNumber(uint8_t Value) : Value(Value) { } - HexNumber(uint16_t Value) : Value(Value) { } - HexNumber(uint32_t Value) : Value(Value) { } - HexNumber(uint64_t Value) : Value(Value) { } + HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) { } + HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) { } + HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) { } + HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) { } + HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) { } + HexNumber(signed long long Value) : Value(static_cast<unsigned long long>(Value)) { } + HexNumber(unsigned char Value) : Value(Value) { } + HexNumber(unsigned short Value) : Value(Value) { } + HexNumber(unsigned int Value) : Value(Value) { } + HexNumber(unsigned long Value) : Value(Value) { } + HexNumber(unsigned long long Value) : Value(Value) { } uint64_t Value; }; @@ -194,6 +197,19 @@ public: OS << "]\n"; } + template <typename T> + void printHexList(StringRef Label, const T &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + OS << hex(Item); + Comma = true; + } + OS << "]\n"; + } + template<typename T> void printHex(StringRef Label, T Value) { startLine() << Label << ": " << hex(Value) << "\n"; diff --git a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp index f57eea2..2da5ae3 100644 --- a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp @@ -149,11 +149,8 @@ static std::error_code resolveRelocation(const Dumper::Context &Ctx, return EC; ResolvedAddress = *ResolvedAddressOrErr; - section_iterator SI = Ctx.COFF.section_begin(); - if (std::error_code EC = Symbol.getSection(SI)) - return EC; - - ResolvedSection = Ctx.COFF.getCOFFSection(*SI); + ErrorOr<section_iterator> SI = Symbol.getSection(); + ResolvedSection = Ctx.COFF.getCOFFSection(**SI); return std::error_code(); } @@ -257,7 +254,7 @@ void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section, return; } - printUnwindCode(UI, ArrayRef<UnwindCode>(UCI, UCE)); + printUnwindCode(UI, makeArrayRef(UCI, UCE)); UCI = UCI + UsedSlots - 1; } } @@ -284,11 +281,11 @@ void Dumper::printRuntimeFunction(const Context &Ctx, const coff_section *XData; uint64_t Offset; - if (error(resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset))) - return; + resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset); ArrayRef<uint8_t> Contents; - if (error(Ctx.COFF.getSectionContents(XData, Contents)) || Contents.empty()) + error(Ctx.COFF.getSectionContents(XData, Contents)); + if (Contents.empty()) return; Offset = Offset + RF.UnwindInfoOffset; @@ -302,15 +299,15 @@ void Dumper::printRuntimeFunction(const Context &Ctx, void Dumper::printData(const Context &Ctx) { for (const auto &Section : Ctx.COFF.sections()) { StringRef Name; - if (error(Section.getName(Name))) - continue; + Section.getName(Name); if (Name != ".pdata" && !Name.startswith(".pdata$")) continue; const coff_section *PData = Ctx.COFF.getCOFFSection(Section); ArrayRef<uint8_t> Contents; - if (error(Ctx.COFF.getSectionContents(PData, Contents)) || Contents.empty()) + error(Ctx.COFF.getSectionContents(PData, Contents)); + if (Contents.empty()) continue; const RuntimeFunction *Entries = diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp index 12afacb..fa8fee2 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -24,6 +24,7 @@ #include "ObjDumper.h" #include "StreamWriter.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" @@ -131,6 +132,10 @@ namespace opts { cl::opt<bool> HashTable("hash-table", cl::desc("Display ELF hash table")); + // -gnu-hash-table + cl::opt<bool> GnuHashTable("gnu-hash-table", + cl::desc("Display ELF .gnu.hash section")); + // -expand-relocs cl::opt<bool> ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); @@ -181,25 +186,62 @@ namespace opts { COFFBaseRelocs("coff-basereloc", cl::desc("Display the PE/COFF .reloc section")); + // -macho-data-in-code + cl::opt<bool> + MachODataInCode("macho-data-in-code", + cl::desc("Display MachO Data in Code command")); + + // -macho-indirect-symbols + cl::opt<bool> + MachOIndirectSymbols("macho-indirect-symbols", + cl::desc("Display MachO indirect symbols")); + + // -macho-linker-options + cl::opt<bool> + MachOLinkerOptions("macho-linker-options", + cl::desc("Display MachO linker options")); + + // -macho-segment + cl::opt<bool> + MachOSegment("macho-segment", + cl::desc("Display MachO Segment command")); + + // -macho-version-min + cl::opt<bool> + MachOVersionMin("macho-version-min", + cl::desc("Display MachO version min command")); + + // -macho-dysymtab + cl::opt<bool> + MachODysymtab("macho-dysymtab", + cl::desc("Display MachO Dysymtab command")); + // -stackmap cl::opt<bool> PrintStackMap("stackmap", cl::desc("Display contents of stackmap section")); + // -version-info + cl::opt<bool> + VersionInfo("version-info", + cl::desc("Display ELF version sections (if present)")); + cl::alias VersionInfoShort("V", cl::desc("Alias for -version-info"), + cl::aliasopt(VersionInfo)); } // namespace opts -static int ReturnValue = EXIT_SUCCESS; - namespace llvm { -bool error(std::error_code EC) { +LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) { + errs() << "\nError reading file: " << Msg << ".\n"; + errs().flush(); + exit(1); +} + +void error(std::error_code EC) { if (!EC) - return false; + return; - ReturnValue = EXIT_FAILURE; - outs() << "\nError reading file: " << EC.message() << ".\n"; - outs().flush(); - return true; + reportError(EC.message()); } bool relocAddressLess(RelocationRef a, RelocationRef b) { @@ -212,17 +254,14 @@ static void reportError(StringRef Input, std::error_code EC) { if (Input == "-") Input = "<stdin>"; - errs() << Input << ": " << EC.message() << "\n"; - errs().flush(); - ReturnValue = EXIT_FAILURE; + reportError(Twine(Input) + ": " + EC.message()); } static void reportError(StringRef Input, StringRef Message) { if (Input == "-") Input = "<stdin>"; - errs() << Input << ": " << Message << "\n"; - ReturnValue = EXIT_FAILURE; + reportError(Twine(Input) + ": " + Message); } static bool isMipsArch(unsigned Arch) { @@ -253,26 +292,12 @@ static std::error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, return readobj_error::unsupported_obj_file_format; } -static StringRef getLoadName(const ObjectFile *Obj) { - if (auto *ELF = dyn_cast<ELF32LEObjectFile>(Obj)) - return ELF->getLoadName(); - if (auto *ELF = dyn_cast<ELF64LEObjectFile>(Obj)) - return ELF->getLoadName(); - if (auto *ELF = dyn_cast<ELF32BEObjectFile>(Obj)) - return ELF->getLoadName(); - if (auto *ELF = dyn_cast<ELF64BEObjectFile>(Obj)) - return ELF->getLoadName(); - llvm_unreachable("Not ELF"); -} - /// @brief Dumps the specified object file. static void dumpObject(const ObjectFile *Obj) { StreamWriter Writer(outs()); std::unique_ptr<ObjDumper> Dumper; - if (std::error_code EC = createDumper(Obj, Writer, Dumper)) { + if (std::error_code EC = createDumper(Obj, Writer, Dumper)) reportError(Obj->getFileName(), EC); - return; - } outs() << '\n'; outs() << "File: " << Obj->getFileName() << "\n"; @@ -281,8 +306,7 @@ static void dumpObject(const ObjectFile *Obj) { << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch()) << "\n"; outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n"; - if (Obj->isELF()) - outs() << "LoadName: " << getLoadName(Obj) << "\n"; + Dumper->printLoadName(); if (opts::FileHeaders) Dumper->printFileHeaders(); @@ -306,6 +330,10 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printProgramHeaders(); if (opts::HashTable) Dumper->printHashTable(); + if (opts::GnuHashTable) + Dumper->printGnuHashTable(); + if (opts::VersionInfo) + Dumper->printVersionInfo(); if (Obj->getArch() == llvm::Triple::arm && Obj->isELF()) if (opts::ARMAttributes) Dumper->printAttributes(); @@ -317,25 +345,43 @@ static void dumpObject(const ObjectFile *Obj) { if (opts::MipsReginfo) Dumper->printMipsReginfo(); } - if (opts::COFFImports) - Dumper->printCOFFImports(); - if (opts::COFFExports) - Dumper->printCOFFExports(); - if (opts::COFFDirectives) - Dumper->printCOFFDirectives(); - if (opts::COFFBaseRelocs) - Dumper->printCOFFBaseReloc(); - + if (Obj->isCOFF()) { + if (opts::COFFImports) + Dumper->printCOFFImports(); + if (opts::COFFExports) + Dumper->printCOFFExports(); + if (opts::COFFDirectives) + Dumper->printCOFFDirectives(); + if (opts::COFFBaseRelocs) + Dumper->printCOFFBaseReloc(); + if (opts::CodeView) + Dumper->printCodeViewDebugInfo(); + } + if (Obj->isMachO()) { + if (opts::MachODataInCode) + Dumper->printMachODataInCode(); + if (opts::MachOIndirectSymbols) + Dumper->printMachOIndirectSymbols(); + if (opts::MachOLinkerOptions) + Dumper->printMachOLinkerOptions(); + if (opts::MachOSegment) + Dumper->printMachOSegment(); + if (opts::MachOVersionMin) + Dumper->printMachOVersionMin(); + if (opts::MachODysymtab) + Dumper->printMachODysymtab(); + } if (opts::PrintStackMap) Dumper->printStackMap(); } /// @brief Dumps each object file in \a Arc; static void dumpArchive(const Archive *Arc) { - for (Archive::child_iterator ArcI = Arc->child_begin(), - ArcE = Arc->child_end(); - ArcI != ArcE; ++ArcI) { - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = ArcI->getAsBinary(); + for (auto &ErrorOrChild : Arc->children()) { + if (std::error_code EC = ErrorOrChild.getError()) + reportError(Arc->getFileName(), EC.message()); + const auto &Child = *ErrorOrChild; + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); if (std::error_code EC = ChildOrErr.getError()) { // Ignore non-object files. if (EC != object_error::invalid_file_type) @@ -365,18 +411,11 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) { /// @brief Opens \a File and dumps it. static void dumpInput(StringRef File) { - // If file isn't stdin, check that it exists. - if (File != "-" && !sys::fs::exists(File)) { - reportError(File, readobj_error::file_not_found); - return; - } // Attempt to open the binary. ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(File); - if (std::error_code EC = BinaryOrErr.getError()) { + if (std::error_code EC = BinaryOrErr.getError()) reportError(File, EC); - return; - } Binary &Binary = *BinaryOrErr.get().getBinary(); if (Archive *Arc = dyn_cast<Archive>(&Binary)) @@ -386,6 +425,8 @@ static void dumpInput(StringRef File) { dumpMachOUniversalBinary(UBinary); else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) dumpObject(Obj); + else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary)) + dumpCOFFImportFile(Import); else reportError(File, readobj_error::unrecognized_file_format); } @@ -407,5 +448,5 @@ int main(int argc, const char *argv[]) { std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), dumpInput); - return ReturnValue; + return 0; } diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h index 74b9a60..5a10392 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h @@ -11,6 +11,7 @@ #define LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" #include <string> namespace llvm { @@ -19,7 +20,8 @@ namespace llvm { } // Various helper functions. - bool error(std::error_code ec); + LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg); + void error(std::error_code ec); bool relocAddressLess(object::RelocationRef A, object::RelocationRef B); } // namespace llvm diff --git a/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp index 86f66f8..6ee3a44 100644 --- a/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -94,6 +94,11 @@ CheckFiles("check", cl::ZeroOrMore); static cl::opt<uint64_t> +PreallocMemory("preallocate", + cl::desc("Allocate memory upfront rather than on-demand"), + cl::init(0)); + +static cl::opt<uint64_t> TargetAddrStart("target-addr-start", cl::desc("For -verify only: start of phony target address " "range."), @@ -127,6 +132,12 @@ DummySymbolMappings("dummy-extern", cl::ZeroOrMore, cl::Hidden); +static cl::opt<bool> +PrintAllocationRequests("print-alloc-requests", + cl::desc("Print allocation requests made to the memory " + "manager by RuntimeDyld"), + cl::Hidden); + /* *** */ // A trivial memory manager that doesn't do anything fancy, just uses the @@ -150,12 +161,6 @@ public: bool finalizeMemory(std::string *ErrMsg) override { return false; } - // Invalidate instruction cache for sections with execute permissions. - // Some platforms with separate data cache and instruction cache require - // explicit cache flush, otherwise JIT code manipulations (like resolved - // relocations) will get to the data cache but not to the instruction cache. - virtual void invalidateInstructionCache(); - void addDummySymbol(const std::string &Name, uint64_t Addr) { DummyExterns[Name] = Addr; } @@ -173,15 +178,56 @@ public: size_t Size) override {} void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override {} + + void preallocateSlab(uint64_t Size) { + std::string Err; + sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, &Err); + if (!MB.base()) + report_fatal_error("Can't allocate enough memory: " + Err); + + PreallocSlab = MB; + UsePreallocation = true; + SlabSize = Size; + } + + uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode) { + Size = RoundUpToAlignment(Size, Alignment); + if (CurrentSlabOffset + Size > SlabSize) + report_fatal_error("Can't allocate enough memory. Tune --preallocate"); + + uintptr_t OldSlabOffset = CurrentSlabOffset; + sys::MemoryBlock MB((void *)OldSlabOffset, Size); + if (isCode) + FunctionMemory.push_back(MB); + else + DataMemory.push_back(MB); + CurrentSlabOffset += Size; + return (uint8_t*)OldSlabOffset; + } + private: std::map<std::string, uint64_t> DummyExterns; + sys::MemoryBlock PreallocSlab; + bool UsePreallocation = false; + uintptr_t SlabSize = 0; + uintptr_t CurrentSlabOffset = 0; }; uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) { - sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, nullptr); + if (PrintAllocationRequests) + outs() << "allocateCodeSection(Size = " << Size << ", Alignment = " + << Alignment << ", SectionName = " << SectionName << ")\n"; + + if (UsePreallocation) + return allocateFromSlab(Size, Alignment, true /* isCode */); + + std::string Err; + sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, &Err); + if (!MB.base()) + report_fatal_error("MemoryManager allocation failed: " + Err); FunctionMemory.push_back(MB); return (uint8_t*)MB.base(); } @@ -191,41 +237,35 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, unsigned SectionID, StringRef SectionName, bool IsReadOnly) { - sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, nullptr); - DataMemory.push_back(MB); - return (uint8_t*)MB.base(); -} + if (PrintAllocationRequests) + outs() << "allocateDataSection(Size = " << Size << ", Alignment = " + << Alignment << ", SectionName = " << SectionName << ")\n"; -void TrivialMemoryManager::invalidateInstructionCache() { - for (int i = 0, e = FunctionMemory.size(); i != e; ++i) - sys::Memory::InvalidateInstructionCache(FunctionMemory[i].base(), - FunctionMemory[i].size()); + if (UsePreallocation) + return allocateFromSlab(Size, Alignment, false /* isCode */); - for (int i = 0, e = DataMemory.size(); i != e; ++i) - sys::Memory::InvalidateInstructionCache(DataMemory[i].base(), - DataMemory[i].size()); + std::string Err; + sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, &Err); + if (!MB.base()) + report_fatal_error("MemoryManager allocation failed: " + Err); + DataMemory.push_back(MB); + return (uint8_t*)MB.base(); } static const char *ProgramName; -static void Message(const char *Type, const Twine &Msg) { - errs() << ProgramName << ": " << Type << ": " << Msg << "\n"; -} - static int Error(const Twine &Msg) { - Message("error", Msg); + errs() << ProgramName << ": error: " << Msg << "\n"; return 1; } static void loadDylibs() { for (const std::string &Dylib : Dylibs) { - if (sys::fs::is_regular_file(Dylib)) { - std::string ErrMsg; - if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg)) - llvm::errs() << "Error loading '" << Dylib << "': " - << ErrMsg << "\n"; - } else - llvm::errs() << "Dylib not found: '" << Dylib << "'.\n"; + if (!sys::fs::is_regular_file(Dylib)) + report_fatal_error("Dylib not found: '" + Dylib + "'."); + std::string ErrMsg; + if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg)) + report_fatal_error("Error loading '" + Dylib + "': " + ErrMsg); } } @@ -240,7 +280,7 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); - for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { + for (auto &File : InputFileList) { // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; RuntimeDyld Dyld(MemMgr, MemMgr); @@ -248,7 +288,7 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { // Load the input memory buffer. ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = - MemoryBuffer::getFileOrSTDIN(InputFileList[i]); + MemoryBuffer::getFileOrSTDIN(File); if (std::error_code EC = InputBuffer.getError()) return Error("unable to read input: '" + EC.message() + "'"); @@ -277,6 +317,7 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { if (UseDebugObj) { DebugObj = LoadedObjInfo->getObjectForDebug(Obj); SymbolObj = DebugObj.getBinary(); + LoadedObjInfo.reset(); } } @@ -303,12 +344,11 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { // symbol in memory (rather than that in the unrelocated object file) // and use that to query the DWARFContext. if (!UseDebugObj && LoadObjects) { - object::section_iterator Sec(SymbolObj->section_end()); - Sym.getSection(Sec); + object::section_iterator Sec = *Sym.getSection(); StringRef SecName; Sec->getName(SecName); uint64_t SectionLoadAddress = - LoadedObjInfo->getSectionLoadAddress(SecName); + LoadedObjInfo->getSectionLoadAddress(*Sec); if (SectionLoadAddress != 0) Addr += SectionLoadAddress - Sec->getAddress(); } @@ -317,11 +357,9 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { << ", Addr = " << Addr << "\n"; DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); - DILineInfoTable::iterator Begin = Lines.begin(); - DILineInfoTable::iterator End = Lines.end(); - for (DILineInfoTable::iterator It = Begin; It != End; ++It) { - outs() << " Line info @ " << It->first - Addr << ": " - << It->second.FileName << ", line:" << It->second.Line << "\n"; + for (auto &D : Lines) { + outs() << " Line info @ " << D.first - Addr << ": " + << D.second.FileName << ", line:" << D.second.Line << "\n"; } } } @@ -330,26 +368,33 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { return 0; } +static void doPreallocation(TrivialMemoryManager &MemMgr) { + // Allocate a slab of memory upfront, if required. This is used if + // we want to test small code models. + if (static_cast<intptr_t>(PreallocMemory) < 0) + report_fatal_error("Pre-allocated bytes of memory must be a positive integer."); + + // FIXME: Limit the amount of memory that can be preallocated? + if (PreallocMemory != 0) + MemMgr.preallocateSlab(PreallocMemory); +} + static int executeInput() { // Load any dylibs requested on the command line. loadDylibs(); // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; + doPreallocation(MemMgr); RuntimeDyld Dyld(MemMgr, MemMgr); - // FIXME: Preserve buffers until resolveRelocations time to work around a bug - // in RuntimeDyldELF. - // This fixme should be fixed ASAP. This is a very brittle workaround. - std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers; - // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); - for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { + for (auto &File : InputFileList) { // Load the input memory buffer. ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = - MemoryBuffer::getFileOrSTDIN(InputFileList[i]); + MemoryBuffer::getFileOrSTDIN(File); if (std::error_code EC = InputBuffer.getError()) return Error("unable to read input: '" + EC.message() + "'"); ErrorOr<std::unique_ptr<ObjectFile>> MaybeObj( @@ -359,7 +404,6 @@ static int executeInput() { return Error("unable to create object file: '" + EC.message() + "'"); ObjectFile &Obj = **MaybeObj; - InputBuffers.push_back(std::move(*InputBuffer)); // Load the object file Dyld.loadObject(Obj); @@ -368,12 +412,9 @@ static int executeInput() { } } - // Resolve all the relocations we can. - Dyld.resolveRelocations(); - // Clear instruction cache before code will be executed. - MemMgr.invalidateInstructionCache(); - + // Resove all the relocations we can. // FIXME: Error out if there are unresolved relocations. + Dyld.resolveRelocations(); // Get the address of the entry point (_main by default). void *MainAddress = Dyld.getSymbolLocalAddress(EntryPoint); @@ -381,12 +422,12 @@ static int executeInput() { return Error("no definition for '" + EntryPoint + "'"); // Invalidate the instruction cache for each loaded function. - for (unsigned i = 0, e = MemMgr.FunctionMemory.size(); i != e; ++i) { - sys::MemoryBlock &Data = MemMgr.FunctionMemory[i]; + for (auto &FM : MemMgr.FunctionMemory) { + // Make sure the memory is executable. + // setExecutable will call InvalidateInstructionCache. std::string ErrorStr; - sys::Memory::InvalidateInstructionCache(Data.base(), Data.size()); - if (!sys::Memory::setExecutable(Data, &ErrorStr)) + if (!sys::Memory::setExecutable(FM, &ErrorStr)) return Error("unable to mark function executable: '" + ErrorStr + "'"); } @@ -428,11 +469,9 @@ applySpecificSectionMappings(RuntimeDyldChecker &Checker) { std::string SectionIDStr = Mapping.substr(0, EqualsIdx); size_t ComaIdx = Mapping.find_first_of(","); - if (ComaIdx == StringRef::npos) { - errs() << "Invalid section specification '" << Mapping - << "'. Should be '<file name>,<section name>=<addr>'\n"; - exit(1); - } + if (ComaIdx == StringRef::npos) + report_fatal_error("Invalid section specification '" + Mapping + + "'. Should be '<file name>,<section name>=<addr>'"); std::string FileName = SectionIDStr.substr(0, ComaIdx); std::string SectionName = SectionIDStr.substr(ComaIdx + 1); @@ -442,20 +481,17 @@ applySpecificSectionMappings(RuntimeDyldChecker &Checker) { std::tie(OldAddrInt, ErrorMsg) = Checker.getSectionAddr(FileName, SectionName, true); - if (ErrorMsg != "") { - errs() << ErrorMsg; - exit(1); - } + if (ErrorMsg != "") + report_fatal_error(ErrorMsg); void* OldAddr = reinterpret_cast<void*>(static_cast<uintptr_t>(OldAddrInt)); std::string NewAddrStr = Mapping.substr(EqualsIdx + 1); uint64_t NewAddr; - if (StringRef(NewAddrStr).getAsInteger(0, NewAddr)) { - errs() << "Invalid section address in mapping '" << Mapping << "'.\n"; - exit(1); - } + if (StringRef(NewAddrStr).getAsInteger(0, NewAddr)) + report_fatal_error("Invalid section address in mapping '" + Mapping + + "'."); Checker.getRTDyld().mapSectionAddress(OldAddr, NewAddr); SpecificMappings[OldAddr] = NewAddr; @@ -544,20 +580,16 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple, for (const auto &Mapping : DummySymbolMappings) { size_t EqualsIdx = Mapping.find_first_of("="); - if (EqualsIdx == StringRef::npos) { - errs() << "Invalid dummy symbol specification '" << Mapping - << "'. Should be '<symbol name>=<addr>'\n"; - exit(1); - } + if (EqualsIdx == StringRef::npos) + report_fatal_error("Invalid dummy symbol specification '" + Mapping + + "'. Should be '<symbol name>=<addr>'"); std::string Symbol = Mapping.substr(0, EqualsIdx); std::string AddrStr = Mapping.substr(EqualsIdx + 1); uint64_t Addr; - if (StringRef(AddrStr).getAsInteger(0, Addr)) { - errs() << "Invalid symbol mapping '" << Mapping << "'.\n"; - exit(1); - } + if (StringRef(AddrStr).getAsInteger(0, Addr)) + report_fatal_error("Invalid symbol mapping '" + Mapping + "'."); MemMgr.addDummySymbol(Symbol, Addr); } @@ -569,38 +601,38 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple, static int linkAndVerify() { // Check for missing triple. - if (TripleName == "") { - llvm::errs() << "Error: -triple required when running in -verify mode.\n"; - return 1; - } + if (TripleName == "") + return Error("-triple required when running in -verify mode."); // Look up the target and build the disassembler. Triple TheTriple(Triple::normalize(TripleName)); std::string ErrorStr; const Target *TheTarget = TargetRegistry::lookupTarget("", TheTriple, ErrorStr); - if (!TheTarget) { - llvm::errs() << "Error accessing target '" << TripleName << "': " - << ErrorStr << "\n"; - return 1; - } + if (!TheTarget) + return Error("Error accessing target '" + TripleName + "': " + ErrorStr); + TripleName = TheTriple.getTriple(); std::unique_ptr<MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TripleName, MCPU, "")); - assert(STI && "Unable to create subtarget info!"); + if (!STI) + return Error("Unable to create subtarget info!"); std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); - assert(MRI && "Unable to create target register info!"); + if (!MRI) + return Error("Unable to create target register info!"); std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); - assert(MAI && "Unable to create target asm info!"); + if (!MAI) + return Error("Unable to create target asm info!"); MCContext Ctx(MAI.get(), MRI.get(), nullptr); std::unique_ptr<MCDisassembler> Disassembler( TheTarget->createMCDisassembler(*STI, Ctx)); - assert(Disassembler && "Unable to create disassembler!"); + if (!Disassembler) + return Error("Unable to create disassembler!"); std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo()); @@ -612,23 +644,19 @@ static int linkAndVerify() { // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; + doPreallocation(MemMgr); RuntimeDyld Dyld(MemMgr, MemMgr); Dyld.setProcessAllSections(true); RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(), llvm::dbgs()); - // FIXME: Preserve buffers until resolveRelocations time to work around a bug - // in RuntimeDyldELF. - // This fixme should be fixed ASAP. This is a very brittle workaround. - std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers; - // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); - for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { + for (auto &Filename : InputFileList) { // Load the input memory buffer. ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = - MemoryBuffer::getFileOrSTDIN(InputFileList[i]); + MemoryBuffer::getFileOrSTDIN(Filename); if (std::error_code EC = InputBuffer.getError()) return Error("unable to read input: '" + EC.message() + "'"); @@ -640,7 +668,6 @@ static int linkAndVerify() { return Error("unable to create object file: '" + EC.message() + "'"); ObjectFile &Obj = **MaybeObj; - InputBuffers.push_back(std::move(*InputBuffer)); // Load the object file Dyld.loadObject(Obj); @@ -660,11 +687,9 @@ static int linkAndVerify() { Dyld.registerEHFrames(); int ErrorCode = checkAllExpressions(Checker); - if (Dyld.hasError()) { - errs() << "RTDyld reported an error applying relocations:\n " - << Dyld.getErrorString() << "\n"; - ErrorCode = 1; - } + if (Dyld.hasError()) + return Error("RTDyld reported an error applying relocations:\n " + + Dyld.getErrorString()); return ErrorCode; } diff --git a/contrib/llvm/tools/llvm-stress/llvm-stress.cpp b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp index 6a1a248..99d2afd 100644 --- a/contrib/llvm/tools/llvm-stress/llvm-stress.cpp +++ b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp @@ -612,7 +612,8 @@ struct CmpModifier: public Modifier { } Value *V = CmpInst::Create(fp ? Instruction::FCmp : Instruction::ICmp, - op, Val0, Val1, "Cmp", BB->getTerminator()); + (CmpInst::Predicate)op, Val0, Val1, "Cmp", + BB->getTerminator()); return PT->push_back(V); } }; @@ -666,7 +667,7 @@ static void IntroduceControlFlow(Function *F, Random &R) { for (auto *Instr : BoolInst) { BasicBlock *Curr = Instr->getParent(); - BasicBlock::iterator Loc = Instr; + BasicBlock::iterator Loc = Instr->getIterator(); BasicBlock *Next = Curr->splitBasicBlock(Loc, "CF"); Instr->moveBefore(Curr->getTerminator()); if (Curr != &F->getEntryBlock()) { diff --git a/contrib/llvm/tools/llvm-symbolizer/LLVMSymbolize.cpp b/contrib/llvm/tools/llvm-symbolizer/LLVMSymbolize.cpp deleted file mode 100644 index c57c219..0000000 --- a/contrib/llvm/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ /dev/null @@ -1,532 +0,0 @@ -//===-- LLVMSymbolize.cpp -------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implementation for LLVM symbolization library. -// -//===----------------------------------------------------------------------===// - -#include "LLVMSymbolize.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Config/config.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/PDB/PDB.h" -#include "llvm/DebugInfo/PDB/PDBContext.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/SymbolSize.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Compression.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include <sstream> -#include <stdlib.h> - -#if defined(_MSC_VER) -#include <Windows.h> -#include <DbgHelp.h> -#pragma comment(lib, "dbghelp.lib") -#endif - -namespace llvm { -namespace symbolize { - -static bool error(std::error_code ec) { - if (!ec) - return false; - errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; - return true; -} - -static DILineInfoSpecifier -getDILineInfoSpecifier(const LLVMSymbolizer::Options &Opts) { - return DILineInfoSpecifier( - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, - Opts.PrintFunctions); -} - -ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx) - : Module(Obj), DebugInfoContext(DICtx) { - std::unique_ptr<DataExtractor> OpdExtractor; - uint64_t OpdAddress = 0; - // Find the .opd (function descriptor) section if any, for big-endian - // PowerPC64 ELF. - if (Module->getArch() == Triple::ppc64) { - for (section_iterator Section : Module->sections()) { - StringRef Name; - if (!error(Section->getName(Name)) && Name == ".opd") { - StringRef Data; - if (!error(Section->getContents(Data))) { - OpdExtractor.reset(new DataExtractor(Data, Module->isLittleEndian(), - Module->getBytesInAddress())); - OpdAddress = Section->getAddress(); - } - break; - } - } - } - std::vector<std::pair<SymbolRef, uint64_t>> Symbols = - computeSymbolSizes(*Module); - for (auto &P : Symbols) - addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress); -} - -void ModuleInfo::addSymbol(const SymbolRef &Symbol, uint64_t SymbolSize, - DataExtractor *OpdExtractor, uint64_t OpdAddress) { - SymbolRef::Type SymbolType = Symbol.getType(); - if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data) - return; - ErrorOr<uint64_t> SymbolAddressOrErr = Symbol.getAddress(); - if (error(SymbolAddressOrErr.getError())) - return; - uint64_t SymbolAddress = *SymbolAddressOrErr; - if (OpdExtractor) { - // For big-endian PowerPC64 ELF, symbols in the .opd section refer to - // function descriptors. The first word of the descriptor is a pointer to - // the function's code. - // For the purposes of symbolization, pretend the symbol's address is that - // of the function's code, not the descriptor. - uint64_t OpdOffset = SymbolAddress - OpdAddress; - uint32_t OpdOffset32 = OpdOffset; - if (OpdOffset == OpdOffset32 && - OpdExtractor->isValidOffsetForAddress(OpdOffset32)) - SymbolAddress = OpdExtractor->getAddress(&OpdOffset32); - } - ErrorOr<StringRef> SymbolNameOrErr = Symbol.getName(); - if (error(SymbolNameOrErr.getError())) - return; - StringRef SymbolName = *SymbolNameOrErr; - // Mach-O symbol table names have leading underscore, skip it. - if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_') - SymbolName = SymbolName.drop_front(); - // FIXME: If a function has alias, there are two entries in symbol table - // with same address size. Make sure we choose the correct one. - auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; - SymbolDesc SD = { SymbolAddress, SymbolSize }; - M.insert(std::make_pair(SD, SymbolName)); -} - -bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, - std::string &Name, uint64_t &Addr, - uint64_t &Size) const { - const auto &SymbolMap = Type == SymbolRef::ST_Function ? Functions : Objects; - if (SymbolMap.empty()) - return false; - SymbolDesc SD = { Address, Address }; - auto SymbolIterator = SymbolMap.upper_bound(SD); - if (SymbolIterator == SymbolMap.begin()) - return false; - --SymbolIterator; - if (SymbolIterator->first.Size != 0 && - SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address) - return false; - Name = SymbolIterator->second.str(); - Addr = SymbolIterator->first.Addr; - Size = SymbolIterator->first.Size; - return true; -} - -DILineInfo ModuleInfo::symbolizeCode( - uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const { - DILineInfo LineInfo; - if (DebugInfoContext) { - LineInfo = DebugInfoContext->getLineInfoForAddress( - ModuleOffset, getDILineInfoSpecifier(Opts)); - } - // Override function name from symbol table if necessary. - if (Opts.PrintFunctions != FunctionNameKind::None && Opts.UseSymbolTable) { - std::string FunctionName; - uint64_t Start, Size; - if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, - FunctionName, Start, Size)) { - LineInfo.FunctionName = FunctionName; - } - } - return LineInfo; -} - -DIInliningInfo ModuleInfo::symbolizeInlinedCode( - uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const { - DIInliningInfo InlinedContext; - - if (DebugInfoContext) { - InlinedContext = DebugInfoContext->getInliningInfoForAddress( - ModuleOffset, getDILineInfoSpecifier(Opts)); - } - // Make sure there is at least one frame in context. - if (InlinedContext.getNumberOfFrames() == 0) { - InlinedContext.addFrame(DILineInfo()); - } - // Override the function name in lower frame with name from symbol table. - if (Opts.PrintFunctions != FunctionNameKind::None && Opts.UseSymbolTable) { - DIInliningInfo PatchedInlinedContext; - for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { - DILineInfo LineInfo = InlinedContext.getFrame(i); - if (i == n - 1) { - std::string FunctionName; - uint64_t Start, Size; - if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, - FunctionName, Start, Size)) { - LineInfo.FunctionName = FunctionName; - } - } - PatchedInlinedContext.addFrame(LineInfo); - } - InlinedContext = PatchedInlinedContext; - } - return InlinedContext; -} - -bool ModuleInfo::symbolizeData(uint64_t ModuleOffset, std::string &Name, - uint64_t &Start, uint64_t &Size) const { - return getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Name, Start, - Size); -} - -const char LLVMSymbolizer::kBadString[] = "??"; - -std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, - uint64_t ModuleOffset) { - ModuleInfo *Info = getOrCreateModuleInfo(ModuleName); - if (!Info) - return printDILineInfo(DILineInfo()); - if (Opts.PrintInlining) { - DIInliningInfo InlinedContext = - Info->symbolizeInlinedCode(ModuleOffset, Opts); - uint32_t FramesNum = InlinedContext.getNumberOfFrames(); - assert(FramesNum > 0); - std::string Result; - for (uint32_t i = 0; i < FramesNum; i++) { - DILineInfo LineInfo = InlinedContext.getFrame(i); - Result += printDILineInfo(LineInfo); - } - return Result; - } - DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts); - return printDILineInfo(LineInfo); -} - -std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, - uint64_t ModuleOffset) { - std::string Name = kBadString; - uint64_t Start = 0; - uint64_t Size = 0; - if (Opts.UseSymbolTable) { - if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) { - if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle) - Name = DemangleName(Name); - } - } - std::stringstream ss; - ss << Name << "\n" << Start << " " << Size << "\n"; - return ss.str(); -} - -void LLVMSymbolizer::flush() { - DeleteContainerSeconds(Modules); - ObjectPairForPathArch.clear(); - ObjectFileForArch.clear(); -} - -// For Path="/path/to/foo" and Basename="foo" assume that debug info is in -// /path/to/foo.dSYM/Contents/Resources/DWARF/foo. -// For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in -// /path/to/bar.dSYM/Contents/Resources/DWARF/foo. -static -std::string getDarwinDWARFResourceForPath( - const std::string &Path, const std::string &Basename) { - SmallString<16> ResourceName = StringRef(Path); - if (sys::path::extension(Path) != ".dSYM") { - ResourceName += ".dSYM"; - } - sys::path::append(ResourceName, "Contents", "Resources", "DWARF"); - sys::path::append(ResourceName, Basename); - return ResourceName.str(); -} - -static bool checkFileCRC(StringRef Path, uint32_t CRCHash) { - ErrorOr<std::unique_ptr<MemoryBuffer>> MB = - MemoryBuffer::getFileOrSTDIN(Path); - if (!MB) - return false; - return !zlib::isAvailable() || CRCHash == zlib::crc32(MB.get()->getBuffer()); -} - -static bool findDebugBinary(const std::string &OrigPath, - const std::string &DebuglinkName, uint32_t CRCHash, - std::string &Result) { - std::string OrigRealPath = OrigPath; -#if defined(HAVE_REALPATH) - if (char *RP = realpath(OrigPath.c_str(), nullptr)) { - OrigRealPath = RP; - free(RP); - } -#endif - SmallString<16> OrigDir(OrigRealPath); - llvm::sys::path::remove_filename(OrigDir); - SmallString<16> DebugPath = OrigDir; - // Try /path/to/original_binary/debuglink_name - llvm::sys::path::append(DebugPath, DebuglinkName); - if (checkFileCRC(DebugPath, CRCHash)) { - Result = DebugPath.str(); - return true; - } - // Try /path/to/original_binary/.debug/debuglink_name - DebugPath = OrigRealPath; - llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); - if (checkFileCRC(DebugPath, CRCHash)) { - Result = DebugPath.str(); - return true; - } - // Try /usr/lib/debug/path/to/original_binary/debuglink_name - DebugPath = "/usr/lib/debug"; - llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), - DebuglinkName); - if (checkFileCRC(DebugPath, CRCHash)) { - Result = DebugPath.str(); - return true; - } - return false; -} - -static bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName, - uint32_t &CRCHash) { - if (!Obj) - return false; - for (const SectionRef &Section : Obj->sections()) { - StringRef Name; - Section.getName(Name); - Name = Name.substr(Name.find_first_not_of("._")); - if (Name == "gnu_debuglink") { - StringRef Data; - Section.getContents(Data); - DataExtractor DE(Data, Obj->isLittleEndian(), 0); - uint32_t Offset = 0; - if (const char *DebugNameStr = DE.getCStr(&Offset)) { - // 4-byte align the offset. - Offset = (Offset + 3) & ~0x3; - if (DE.isValidOffsetForDataOfSize(Offset, 4)) { - DebugName = DebugNameStr; - CRCHash = DE.getU32(&Offset); - return true; - } - } - break; - } - } - return false; -} - -static -bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj, - const MachOObjectFile *Obj) { - ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid(); - ArrayRef<uint8_t> bin_uuid = Obj->getUuid(); - if (dbg_uuid.empty() || bin_uuid.empty()) - return false; - return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size()); -} - -ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, - const MachOObjectFile *MachExeObj, const std::string &ArchName) { - // On Darwin we may find DWARF in separate object file in - // resource directory. - std::vector<std::string> DsymPaths; - StringRef Filename = sys::path::filename(ExePath); - DsymPaths.push_back(getDarwinDWARFResourceForPath(ExePath, Filename)); - for (const auto &Path : Opts.DsymHints) { - DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename)); - } - for (const auto &path : DsymPaths) { - ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(path); - std::error_code EC = BinaryOrErr.getError(); - if (EC != errc::no_such_file_or_directory && !error(EC)) { - OwningBinary<Binary> B = std::move(BinaryOrErr.get()); - ObjectFile *DbgObj = - getObjectFileFromBinary(B.getBinary(), ArchName); - const MachOObjectFile *MachDbgObj = - dyn_cast<const MachOObjectFile>(DbgObj); - if (!MachDbgObj) continue; - if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) { - addOwningBinary(std::move(B)); - return DbgObj; - } - } - } - return nullptr; -} - -LLVMSymbolizer::ObjectPair -LLVMSymbolizer::getOrCreateObjects(const std::string &Path, - const std::string &ArchName) { - const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName)); - if (I != ObjectPairForPathArch.end()) - return I->second; - ObjectFile *Obj = nullptr; - ObjectFile *DbgObj = nullptr; - ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(Path); - if (!error(BinaryOrErr.getError())) { - OwningBinary<Binary> &B = BinaryOrErr.get(); - Obj = getObjectFileFromBinary(B.getBinary(), ArchName); - if (!Obj) { - ObjectPair Res = std::make_pair(nullptr, nullptr); - ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res; - return Res; - } - addOwningBinary(std::move(B)); - if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj)) - DbgObj = lookUpDsymFile(Path, MachObj, ArchName); - // Try to locate the debug binary using .gnu_debuglink section. - if (!DbgObj) { - std::string DebuglinkName; - uint32_t CRCHash; - std::string DebugBinaryPath; - if (getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash) && - findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) { - BinaryOrErr = createBinary(DebugBinaryPath); - if (!error(BinaryOrErr.getError())) { - OwningBinary<Binary> B = std::move(BinaryOrErr.get()); - DbgObj = getObjectFileFromBinary(B.getBinary(), ArchName); - addOwningBinary(std::move(B)); - } - } - } - } - if (!DbgObj) - DbgObj = Obj; - ObjectPair Res = std::make_pair(Obj, DbgObj); - ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res; - return Res; -} - -ObjectFile * -LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, - const std::string &ArchName) { - if (!Bin) - return nullptr; - ObjectFile *Res = nullptr; - if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) { - const auto &I = ObjectFileForArch.find( - std::make_pair(UB, ArchName)); - if (I != ObjectFileForArch.end()) - return I->second; - ErrorOr<std::unique_ptr<ObjectFile>> ParsedObj = - UB->getObjectForArch(ArchName); - if (ParsedObj) { - Res = ParsedObj.get().get(); - ParsedBinariesAndObjects.push_back(std::move(ParsedObj.get())); - } - ObjectFileForArch[std::make_pair(UB, ArchName)] = Res; - } else if (Bin->isObject()) { - Res = cast<ObjectFile>(Bin); - } - return Res; -} - -ModuleInfo * -LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { - const auto &I = Modules.find(ModuleName); - if (I != Modules.end()) - return I->second; - std::string BinaryName = ModuleName; - std::string ArchName = Opts.DefaultArch; - size_t ColonPos = ModuleName.find_last_of(':'); - // Verify that substring after colon form a valid arch name. - if (ColonPos != std::string::npos) { - std::string ArchStr = ModuleName.substr(ColonPos + 1); - if (Triple(ArchStr).getArch() != Triple::UnknownArch) { - BinaryName = ModuleName.substr(0, ColonPos); - ArchName = ArchStr; - } - } - ObjectPair Objects = getOrCreateObjects(BinaryName, ArchName); - - if (!Objects.first) { - // Failed to find valid object file. - Modules.insert(make_pair(ModuleName, (ModuleInfo *)nullptr)); - return nullptr; - } - DIContext *Context = nullptr; - if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) { - // If this is a COFF object, assume it contains PDB debug information. If - // we don't find any we will fall back to the DWARF case. - std::unique_ptr<IPDBSession> Session; - PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA, - Objects.first->getFileName(), Session); - if (Error == PDB_ErrorCode::Success) { - Context = new PDBContext(*CoffObject, std::move(Session), - Opts.RelativeAddresses); - } - } - if (!Context) - Context = new DWARFContextInMemory(*Objects.second); - assert(Context); - ModuleInfo *Info = new ModuleInfo(Objects.first, Context); - Modules.insert(make_pair(ModuleName, Info)); - return Info; -} - -std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const { - // By default, DILineInfo contains "<invalid>" for function/filename it - // cannot fetch. We replace it to "??" to make our output closer to addr2line. - static const std::string kDILineInfoBadString = "<invalid>"; - std::stringstream Result; - if (Opts.PrintFunctions != FunctionNameKind::None) { - std::string FunctionName = LineInfo.FunctionName; - if (FunctionName == kDILineInfoBadString) - FunctionName = kBadString; - else if (Opts.Demangle) - FunctionName = DemangleName(FunctionName); - Result << FunctionName << "\n"; - } - std::string Filename = LineInfo.FileName; - if (Filename == kDILineInfoBadString) - Filename = kBadString; - Result << Filename << ":" << LineInfo.Line << ":" << LineInfo.Column << "\n"; - return Result.str(); -} - -#if !defined(_MSC_VER) -// Assume that __cxa_demangle is provided by libcxxabi (except for Windows). -extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, - size_t *length, int *status); -#endif - -std::string LLVMSymbolizer::DemangleName(const std::string &Name) { -#if !defined(_MSC_VER) - // We can spoil names of symbols with C linkage, so use an heuristic - // approach to check if the name should be demangled. - if (Name.substr(0, 2) != "_Z") - return Name; - int status = 0; - char *DemangledName = __cxa_demangle(Name.c_str(), nullptr, nullptr, &status); - if (status != 0) - return Name; - std::string Result = DemangledName; - free(DemangledName); - return Result; -#else - char DemangledName[1024] = {0}; - DWORD result = ::UnDecorateSymbolName( - Name.c_str(), DemangledName, 1023, - UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected - UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc - UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications - UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers - UNDNAME_NO_MS_KEYWORDS | // Strip all MS extension keywords - UNDNAME_NO_FUNCTION_RETURNS); // Strip function return types - - return (result == 0) ? Name : std::string(DemangledName); -#endif -} - -} // namespace symbolize -} // namespace llvm diff --git a/contrib/llvm/tools/llvm-symbolizer/LLVMSymbolize.h b/contrib/llvm/tools/llvm-symbolizer/LLVMSymbolize.h deleted file mode 100644 index be246c3..0000000 --- a/contrib/llvm/tools/llvm-symbolizer/LLVMSymbolize.h +++ /dev/null @@ -1,144 +0,0 @@ -//===-- LLVMSymbolize.h ----------------------------------------- C++ -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Header for LLVM symbolization library. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVM_SYMBOLIZER_LLVMSYMBOLIZE_H -#define LLVM_TOOLS_LLVM_SYMBOLIZER_LLVMSYMBOLIZE_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/DIContext.h" -#include "llvm/Object/MachOUniversal.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/MemoryBuffer.h" -#include <map> -#include <memory> -#include <string> - -namespace llvm { - -typedef DILineInfoSpecifier::FunctionNameKind FunctionNameKind; -using namespace object; - -namespace symbolize { - -class ModuleInfo; - -class LLVMSymbolizer { -public: - struct Options { - FunctionNameKind PrintFunctions; - bool UseSymbolTable : 1; - bool PrintInlining : 1; - bool Demangle : 1; - bool RelativeAddresses : 1; - std::string DefaultArch; - std::vector<std::string> DsymHints; - Options(FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName, - bool UseSymbolTable = true, bool PrintInlining = true, - bool Demangle = true, bool RelativeAddresses = false, - std::string DefaultArch = "") - : PrintFunctions(PrintFunctions), UseSymbolTable(UseSymbolTable), - PrintInlining(PrintInlining), Demangle(Demangle), - RelativeAddresses(RelativeAddresses), DefaultArch(DefaultArch) {} - }; - - LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {} - ~LLVMSymbolizer() { - flush(); - } - - // Returns the result of symbolization for module name/offset as - // a string (possibly containing newlines). - std::string - symbolizeCode(const std::string &ModuleName, uint64_t ModuleOffset); - std::string - symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset); - void flush(); - static std::string DemangleName(const std::string &Name); -private: - typedef std::pair<ObjectFile*, ObjectFile*> ObjectPair; - - ModuleInfo *getOrCreateModuleInfo(const std::string &ModuleName); - ObjectFile *lookUpDsymFile(const std::string &Path, const MachOObjectFile *ExeObj, - const std::string &ArchName); - - /// \brief Returns pair of pointers to object and debug object. - ObjectPair getOrCreateObjects(const std::string &Path, - const std::string &ArchName); - /// \brief Returns a parsed object file for a given architecture in a - /// universal binary (or the binary itself if it is an object file). - ObjectFile *getObjectFileFromBinary(Binary *Bin, const std::string &ArchName); - - std::string printDILineInfo(DILineInfo LineInfo) const; - - // Owns all the parsed binaries and object files. - SmallVector<std::unique_ptr<Binary>, 4> ParsedBinariesAndObjects; - SmallVector<std::unique_ptr<MemoryBuffer>, 4> MemoryBuffers; - void addOwningBinary(OwningBinary<Binary> OwningBin) { - std::unique_ptr<Binary> Bin; - std::unique_ptr<MemoryBuffer> MemBuf; - std::tie(Bin, MemBuf) = OwningBin.takeBinary(); - ParsedBinariesAndObjects.push_back(std::move(Bin)); - MemoryBuffers.push_back(std::move(MemBuf)); - } - - // Owns module info objects. - std::map<std::string, ModuleInfo *> Modules; - std::map<std::pair<MachOUniversalBinary *, std::string>, ObjectFile *> - ObjectFileForArch; - std::map<std::pair<std::string, std::string>, ObjectPair> - ObjectPairForPathArch; - - Options Opts; - static const char kBadString[]; -}; - -class ModuleInfo { -public: - ModuleInfo(ObjectFile *Obj, DIContext *DICtx); - - DILineInfo symbolizeCode(uint64_t ModuleOffset, - const LLVMSymbolizer::Options &Opts) const; - DIInliningInfo symbolizeInlinedCode( - uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const; - bool symbolizeData(uint64_t ModuleOffset, std::string &Name, uint64_t &Start, - uint64_t &Size) const; - -private: - bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, - std::string &Name, uint64_t &Addr, - uint64_t &Size) const; - // For big-endian PowerPC64 ELF, OpdAddress is the address of the .opd - // (function descriptor) section and OpdExtractor refers to its contents. - void addSymbol(const SymbolRef &Symbol, uint64_t SymbolSize, - DataExtractor *OpdExtractor = nullptr, - uint64_t OpdAddress = 0); - ObjectFile *Module; - std::unique_ptr<DIContext> DebugInfoContext; - - struct SymbolDesc { - uint64_t Addr; - // If size is 0, assume that symbol occupies the whole memory range up to - // the following symbol. - uint64_t Size; - friend bool operator<(const SymbolDesc &s1, const SymbolDesc &s2) { - return s1.Addr < s2.Addr; - } - }; - std::map<SymbolDesc, StringRef> Functions; - std::map<SymbolDesc, StringRef> Objects; -}; - -} // namespace symbolize -} // namespace llvm - -#endif diff --git a/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp index 9c9f3ad..e45660c 100644 --- a/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -15,8 +15,9 @@ // //===----------------------------------------------------------------------===// -#include "LLVMSymbolize.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/Symbolize/DIPrinter.h" +#include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/Support/COM.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -73,6 +74,20 @@ static cl::list<std::string> ClDsymHint("dsym-hint", cl::ZeroOrMore, cl::desc("Path to .dSYM bundles to search for debug info for the " "object files")); +static cl::opt<bool> + ClPrintAddress("print-address", cl::init(false), + cl::desc("Show address before line information")); + +static cl::opt<bool> + ClPrettyPrint("pretty-print", cl::init(false), + cl::desc("Make the output more human friendly")); + +static bool error(std::error_code ec) { + if (!ec) + return false; + errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; + return true; +} static bool parseCommand(bool &IsData, std::string &ModuleName, uint64_t &ModuleOffset) { @@ -118,9 +133,7 @@ static bool parseCommand(bool &IsData, std::string &ModuleName, // Skip delimiters and parse module offset. pos += strspn(pos, kDelimiters); int offset_length = strcspn(pos, kDelimiters); - if (StringRef(pos, offset_length).getAsInteger(0, ModuleOffset)) - return false; - return true; + return !StringRef(pos, offset_length).getAsInteger(0, ModuleOffset); } int main(int argc, char **argv) { @@ -132,9 +145,9 @@ int main(int argc, char **argv) { llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n"); - LLVMSymbolizer::Options Opts(ClPrintFunctions, ClUseSymbolTable, - ClPrintInlining, ClDemangle, + LLVMSymbolizer::Options Opts(ClPrintFunctions, ClUseSymbolTable, ClDemangle, ClUseRelativeAddress, ClDefaultArch); + for (const auto &hint : ClDsymHint) { if (sys::path::extension(hint) == ".dSYM") { Opts.DsymHints.push_back(hint); @@ -148,11 +161,28 @@ int main(int argc, char **argv) { bool IsData = false; std::string ModuleName; uint64_t ModuleOffset; + DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None, + ClPrettyPrint); + while (parseCommand(IsData, ModuleName, ModuleOffset)) { - std::string Result = - IsData ? Symbolizer.symbolizeData(ModuleName, ModuleOffset) - : Symbolizer.symbolizeCode(ModuleName, ModuleOffset); - outs() << Result << "\n"; + if (ClPrintAddress) { + outs() << "0x"; + outs().write_hex(ModuleOffset); + StringRef Delimiter = (ClPrettyPrint == true) ? ": " : "\n"; + outs() << Delimiter; + } + if (IsData) { + auto ResOrErr = Symbolizer.symbolizeData(ModuleName, ModuleOffset); + Printer << (error(ResOrErr.getError()) ? DIGlobal() : ResOrErr.get()); + } else if (ClPrintInlining) { + auto ResOrErr = Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset); + Printer << (error(ResOrErr.getError()) ? DIInliningInfo() + : ResOrErr.get()); + } else { + auto ResOrErr = Symbolizer.symbolizeCode(ModuleName, ModuleOffset); + Printer << (error(ResOrErr.getError()) ? DILineInfo() : ResOrErr.get()); + } + outs() << "\n"; outs().flush(); } diff --git a/contrib/llvm/tools/macho-dump/macho-dump.cpp b/contrib/llvm/tools/macho-dump/macho-dump.cpp deleted file mode 100644 index 39c2860..0000000 --- a/contrib/llvm/tools/macho-dump/macho-dump.cpp +++ /dev/null @@ -1,434 +0,0 @@ -//===-- macho-dump.cpp - Mach Object Dumping Tool -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a testing tool for use with the MC/Mach-O LLVM components. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Object/MachO.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include <system_error> -using namespace llvm; -using namespace llvm::object; - -static cl::opt<std::string> -InputFile(cl::Positional, cl::desc("<input file>"), cl::init("-")); - -static cl::opt<bool> -ShowSectionData("dump-section-data", cl::desc("Dump the contents of sections"), - cl::init(false)); - -/// - -static const char *ProgramName; - -static void Message(const char *Type, const Twine &Msg) { - errs() << ProgramName << ": " << Type << ": " << Msg << "\n"; -} - -static int Error(const Twine &Msg) { - Message("error", Msg); - return 1; -} - -static void Warning(const Twine &Msg) { - Message("warning", Msg); -} - -/// - -static void DumpSegmentCommandData(StringRef Name, - uint64_t VMAddr, uint64_t VMSize, - uint64_t FileOffset, uint64_t FileSize, - uint32_t MaxProt, uint32_t InitProt, - uint32_t NumSections, uint32_t Flags) { - outs() << " ('segment_name', '"; - outs().write_escaped(Name, /*UseHexEscapes=*/true) << "')\n"; - outs() << " ('vm_addr', " << VMAddr << ")\n"; - outs() << " ('vm_size', " << VMSize << ")\n"; - outs() << " ('file_offset', " << FileOffset << ")\n"; - outs() << " ('file_size', " << FileSize << ")\n"; - outs() << " ('maxprot', " << MaxProt << ")\n"; - outs() << " ('initprot', " << InitProt << ")\n"; - outs() << " ('num_sections', " << NumSections << ")\n"; - outs() << " ('flags', " << Flags << ")\n"; -} - -static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index, - StringRef Name, - StringRef SegmentName, uint64_t Address, - uint64_t Size, uint32_t Offset, - uint32_t Align, uint32_t RelocationTableOffset, - uint32_t NumRelocationTableEntries, - uint32_t Flags, uint32_t Reserved1, - uint32_t Reserved2, uint64_t Reserved3 = ~0ULL) { - outs() << " # Section " << Index << "\n"; - outs() << " (('section_name', '"; - outs().write_escaped(Name, /*UseHexEscapes=*/true) << "')\n"; - outs() << " ('segment_name', '"; - outs().write_escaped(SegmentName, /*UseHexEscapes=*/true) << "')\n"; - outs() << " ('address', " << Address << ")\n"; - outs() << " ('size', " << Size << ")\n"; - outs() << " ('offset', " << Offset << ")\n"; - outs() << " ('alignment', " << Align << ")\n"; - outs() << " ('reloc_offset', " << RelocationTableOffset << ")\n"; - outs() << " ('num_reloc', " << NumRelocationTableEntries << ")\n"; - outs() << " ('flags', " << format("0x%x", Flags) << ")\n"; - outs() << " ('reserved1', " << Reserved1 << ")\n"; - outs() << " ('reserved2', " << Reserved2 << ")\n"; - if (Reserved3 != ~0ULL) - outs() << " ('reserved3', " << Reserved3 << ")\n"; - outs() << " ),\n"; - - // Dump the relocation entries. - outs() << " ('_relocations', [\n"; - unsigned RelNum = 0; - for (relocation_iterator I = Obj.section_rel_begin(Index), - E = Obj.section_rel_end(Index); - I != E; ++I, ++RelNum) { - MachO::any_relocation_info RE = Obj.getRelocation(I->getRawDataRefImpl()); - outs() << " # Relocation " << RelNum << "\n"; - outs() << " (('word-0', " << format("0x%x", RE.r_word0) << "),\n"; - outs() << " ('word-1', " << format("0x%x", RE.r_word1) << ")),\n"; - } - outs() << " ])\n"; - - // Dump the section data, if requested. - if (ShowSectionData) { - outs() << " ('_section_data', '"; - StringRef Data = Obj.getData().substr(Offset, Size); - for (unsigned i = 0; i != Data.size(); ++i) { - if (i && (i % 4) == 0) - outs() << ' '; - outs() << hexdigit((Data[i] >> 4) & 0xF, /*LowerCase=*/true); - outs() << hexdigit((Data[i] >> 0) & 0xF, /*LowerCase=*/true); - } - outs() << "')\n"; - } - - return 0; -} - -static int DumpSegmentCommand(const MachOObjectFile &Obj, - const MachOObjectFile::LoadCommandInfo &LCI) { - MachO::segment_command SLC = Obj.getSegmentLoadCommand(LCI); - - DumpSegmentCommandData(StringRef(SLC.segname, 16), SLC.vmaddr, - SLC.vmsize, SLC.fileoff, SLC.filesize, - SLC.maxprot, SLC.initprot, SLC.nsects, SLC.flags); - - // Dump the sections. - outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC.nsects; ++i) { - MachO::section Sect = Obj.getSection(LCI, i); - DumpSectionData(Obj, i, StringRef(Sect.sectname, 16), - StringRef(Sect.segname, 16), Sect.addr, - Sect.size, Sect.offset, Sect.align, - Sect.reloff, Sect.nreloc, Sect.flags, - Sect.reserved1, Sect.reserved2); - } - outs() << " ])\n"; - - return 0; -} - -static int DumpSegment64Command(const MachOObjectFile &Obj, - const MachOObjectFile::LoadCommandInfo &LCI) { - MachO::segment_command_64 SLC = Obj.getSegment64LoadCommand(LCI); - DumpSegmentCommandData(StringRef(SLC.segname, 16), SLC.vmaddr, - SLC.vmsize, SLC.fileoff, SLC.filesize, - SLC.maxprot, SLC.initprot, SLC.nsects, SLC.flags); - - // Dump the sections. - outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC.nsects; ++i) { - MachO::section_64 Sect = Obj.getSection64(LCI, i); - - DumpSectionData(Obj, i, StringRef(Sect.sectname, 16), - StringRef(Sect.segname, 16), Sect.addr, - Sect.size, Sect.offset, Sect.align, - Sect.reloff, Sect.nreloc, Sect.flags, - Sect.reserved1, Sect.reserved2, - Sect.reserved3); - } - outs() << " ])\n"; - - return 0; -} - -static void DumpSymbolTableEntryData(const MachOObjectFile &Obj, - unsigned Index, uint32_t StringIndex, - uint8_t Type, uint8_t SectionIndex, - uint16_t Flags, uint64_t Value, - StringRef StringTable) { - const char *Name = &StringTable.data()[StringIndex]; - outs() << " # Symbol " << Index << "\n"; - outs() << " (('n_strx', " << StringIndex << ")\n"; - outs() << " ('n_type', " << format("0x%x", Type) << ")\n"; - outs() << " ('n_sect', " << uint32_t(SectionIndex) << ")\n"; - outs() << " ('n_desc', " << Flags << ")\n"; - outs() << " ('n_value', " << Value << ")\n"; - outs() << " ('_string', '" << Name << "')\n"; - outs() << " ),\n"; -} - -static int DumpSymtabCommand(const MachOObjectFile &Obj) { - MachO::symtab_command SLC = Obj.getSymtabLoadCommand(); - - outs() << " ('symoff', " << SLC.symoff << ")\n"; - outs() << " ('nsyms', " << SLC.nsyms << ")\n"; - outs() << " ('stroff', " << SLC.stroff << ")\n"; - outs() << " ('strsize', " << SLC.strsize << ")\n"; - - // Dump the string data. - outs() << " ('_string_data', '"; - StringRef StringTable = Obj.getStringTableData(); - outs().write_escaped(StringTable, - /*UseHexEscapes=*/true) << "')\n"; - - // Dump the symbol table. - outs() << " ('_symbols', [\n"; - unsigned SymNum = 0; - for (const SymbolRef &Symbol : Obj.symbols()) { - DataRefImpl DRI = Symbol.getRawDataRefImpl(); - if (Obj.is64Bit()) { - MachO::nlist_64 STE = Obj.getSymbol64TableEntry(DRI); - DumpSymbolTableEntryData(Obj, SymNum, STE.n_strx, STE.n_type, - STE.n_sect, STE.n_desc, STE.n_value, - StringTable); - } else { - MachO::nlist STE = Obj.getSymbolTableEntry(DRI); - DumpSymbolTableEntryData(Obj, SymNum, STE.n_strx, STE.n_type, - STE.n_sect, STE.n_desc, STE.n_value, - StringTable); - } - SymNum++; - } - outs() << " ])\n"; - - return 0; -} - -static int DumpDysymtabCommand(const MachOObjectFile &Obj) { - MachO::dysymtab_command DLC = Obj.getDysymtabLoadCommand(); - - outs() << " ('ilocalsym', " << DLC.ilocalsym << ")\n"; - outs() << " ('nlocalsym', " << DLC.nlocalsym << ")\n"; - outs() << " ('iextdefsym', " << DLC.iextdefsym << ")\n"; - outs() << " ('nextdefsym', " << DLC.nextdefsym << ")\n"; - outs() << " ('iundefsym', " << DLC.iundefsym << ")\n"; - outs() << " ('nundefsym', " << DLC.nundefsym << ")\n"; - outs() << " ('tocoff', " << DLC.tocoff << ")\n"; - outs() << " ('ntoc', " << DLC.ntoc << ")\n"; - outs() << " ('modtaboff', " << DLC.modtaboff << ")\n"; - outs() << " ('nmodtab', " << DLC.nmodtab << ")\n"; - outs() << " ('extrefsymoff', " << DLC.extrefsymoff << ")\n"; - outs() << " ('nextrefsyms', " << DLC.nextrefsyms << ")\n"; - outs() << " ('indirectsymoff', " << DLC.indirectsymoff << ")\n"; - outs() << " ('nindirectsyms', " << DLC.nindirectsyms << ")\n"; - outs() << " ('extreloff', " << DLC.extreloff << ")\n"; - outs() << " ('nextrel', " << DLC.nextrel << ")\n"; - outs() << " ('locreloff', " << DLC.locreloff << ")\n"; - outs() << " ('nlocrel', " << DLC.nlocrel << ")\n"; - - // Dump the indirect symbol table. - outs() << " ('_indirect_symbols', [\n"; - for (unsigned i = 0; i != DLC.nindirectsyms; ++i) { - uint32_t ISTE = Obj.getIndirectSymbolTableEntry(DLC, i); - outs() << " # Indirect Symbol " << i << "\n"; - outs() << " (('symbol_index', " << format("0x%x", ISTE) << "),),\n"; - } - outs() << " ])\n"; - - return 0; -} - -static int -DumpLinkeditDataCommand(const MachOObjectFile &Obj, - const MachOObjectFile::LoadCommandInfo &LCI) { - MachO::linkedit_data_command LLC = Obj.getLinkeditDataLoadCommand(LCI); - outs() << " ('dataoff', " << LLC.dataoff << ")\n" - << " ('datasize', " << LLC.datasize << ")\n" - << " ('_addresses', [\n"; - - SmallVector<uint64_t, 8> Addresses; - Obj.ReadULEB128s(LLC.dataoff, Addresses); - for (unsigned i = 0, e = Addresses.size(); i != e; ++i) - outs() << " # Address " << i << '\n' - << " ('address', " << format("0x%x", Addresses[i]) << "),\n"; - - outs() << " ])\n"; - - return 0; -} - -static int -DumpDataInCodeDataCommand(const MachOObjectFile &Obj, - const MachOObjectFile::LoadCommandInfo &LCI) { - MachO::linkedit_data_command LLC = Obj.getLinkeditDataLoadCommand(LCI); - outs() << " ('dataoff', " << LLC.dataoff << ")\n" - << " ('datasize', " << LLC.datasize << ")\n" - << " ('_data_regions', [\n"; - - unsigned NumRegions = LLC.datasize / sizeof(MachO::data_in_code_entry); - for (unsigned i = 0; i < NumRegions; ++i) { - MachO::data_in_code_entry DICE= Obj.getDataInCodeTableEntry(LLC.dataoff, i); - outs() << " # DICE " << i << "\n" - << " ('offset', " << DICE.offset << ")\n" - << " ('length', " << DICE.length << ")\n" - << " ('kind', " << DICE.kind << ")\n"; - } - - outs() <<" ])\n"; - - return 0; -} - -static int -DumpLinkerOptionsCommand(const MachOObjectFile &Obj, - const MachOObjectFile::LoadCommandInfo &LCI) { - MachO::linker_option_command LOLC = Obj.getLinkerOptionLoadCommand(LCI); - outs() << " ('count', " << LOLC.count << ")\n" - << " ('_strings', [\n"; - - uint64_t DataSize = LOLC.cmdsize - sizeof(MachO::linker_option_command); - const char *P = LCI.Ptr + sizeof(MachO::linker_option_command); - StringRef Data(P, DataSize); - for (unsigned i = 0; i != LOLC.count; ++i) { - std::pair<StringRef,StringRef> Split = Data.split('\0'); - outs() << "\t\""; - outs().write_escaped(Split.first); - outs() << "\",\n"; - Data = Split.second; - } - outs() <<" ])\n"; - - return 0; -} - -static int -DumpVersionMin(const MachOObjectFile &Obj, - const MachOObjectFile::LoadCommandInfo &LCI) { - MachO::version_min_command VMLC = Obj.getVersionMinLoadCommand(LCI); - outs() << " ('version, " << VMLC.version << ")\n" - << " ('sdk, " << VMLC.sdk << ")\n"; - return 0; -} - -static int -DumpDylibID(const MachOObjectFile &Obj, - const MachOObjectFile::LoadCommandInfo &LCI) { - MachO::dylib_command DLLC = Obj.getDylibIDLoadCommand(LCI); - outs() << " ('install_name', '" << LCI.Ptr + DLLC.dylib.name << "')\n" - << " ('timestamp, " << DLLC.dylib.timestamp << ")\n" - << " ('cur_version, " << DLLC.dylib.current_version << ")\n" - << " ('compat_version, " << DLLC.dylib.compatibility_version << ")\n"; - return 0; -} - -static int DumpLoadCommand(const MachOObjectFile &Obj, - const MachOObjectFile::LoadCommandInfo &LCI) { - switch (LCI.C.cmd) { - case MachO::LC_SEGMENT: - return DumpSegmentCommand(Obj, LCI); - case MachO::LC_SEGMENT_64: - return DumpSegment64Command(Obj, LCI); - case MachO::LC_SYMTAB: - return DumpSymtabCommand(Obj); - case MachO::LC_DYSYMTAB: - return DumpDysymtabCommand(Obj); - case MachO::LC_CODE_SIGNATURE: - case MachO::LC_SEGMENT_SPLIT_INFO: - case MachO::LC_FUNCTION_STARTS: - return DumpLinkeditDataCommand(Obj, LCI); - case MachO::LC_DATA_IN_CODE: - return DumpDataInCodeDataCommand(Obj, LCI); - case MachO::LC_LINKER_OPTION: - return DumpLinkerOptionsCommand(Obj, LCI); - case MachO::LC_VERSION_MIN_IPHONEOS: - case MachO::LC_VERSION_MIN_MACOSX: - return DumpVersionMin(Obj, LCI); - case MachO::LC_ID_DYLIB: - return DumpDylibID(Obj, LCI); - default: - Warning("unknown load command: " + Twine(LCI.C.cmd)); - return 0; - } -} - -static int DumpLoadCommand(const MachOObjectFile &Obj, unsigned Index, - const MachOObjectFile::LoadCommandInfo &LCI) { - outs() << " # Load Command " << Index << "\n" - << " (('command', " << LCI.C.cmd << ")\n" - << " ('size', " << LCI.C.cmdsize << ")\n"; - int Res = DumpLoadCommand(Obj, LCI); - outs() << " ),\n"; - return Res; -} - -static void printHeader(const MachOObjectFile *Obj, - const MachO::mach_header &Header) { - outs() << "('cputype', " << Header.cputype << ")\n"; - outs() << "('cpusubtype', " << Header.cpusubtype << ")\n"; - outs() << "('filetype', " << Header.filetype << ")\n"; - outs() << "('num_load_commands', " << Header.ncmds << ")\n"; - outs() << "('load_commands_size', " << Header.sizeofcmds << ")\n"; - outs() << "('flag', " << Header.flags << ")\n"; - - // Print extended header if 64-bit. - if (Obj->is64Bit()) { - const MachO::mach_header_64 *Header64 = - reinterpret_cast<const MachO::mach_header_64 *>(&Header); - outs() << "('reserved', " << Header64->reserved << ")\n"; - } -} - -int main(int argc, char **argv) { - ProgramName = argv[0]; - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - - cl::ParseCommandLineOptions(argc, argv, "llvm Mach-O dumping tool\n"); - - ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFile); - if (std::error_code EC = BinaryOrErr.getError()) - return Error("unable to read input: '" + EC.message() + "'"); - Binary &Binary = *BinaryOrErr.get().getBinary(); - - const MachOObjectFile *InputObject = dyn_cast<MachOObjectFile>(&Binary); - if (!InputObject) - return Error("Not a MachO object"); - - // Print the header - MachO::mach_header_64 Header64; - MachO::mach_header *Header = reinterpret_cast<MachO::mach_header*>(&Header64); - if (InputObject->is64Bit()) - Header64 = InputObject->getHeader64(); - else - *Header = InputObject->getHeader(); - printHeader(InputObject, *Header); - - // Print the load commands. - int Res = 0; - unsigned Index = 0; - outs() << "('load_commands', [\n"; - for (const auto &Load : InputObject->load_commands()) { - if (DumpLoadCommand(*InputObject, Index++, Load)) - break; - } - outs() << "])\n"; - - return Res; -} diff --git a/contrib/llvm/tools/opt/opt.cpp b/contrib/llvm/tools/opt/opt.cpp index 0db60d1..fe1605a 100644 --- a/contrib/llvm/tools/opt/opt.cpp +++ b/contrib/llvm/tools/opt/opt.cpp @@ -28,6 +28,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" @@ -36,7 +37,6 @@ #include "llvm/LinkAllIR.h" #include "llvm/LinkAllPasses.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -51,6 +51,7 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Utils/Cloning.h" #include <algorithm> #include <memory> using namespace llvm; @@ -190,6 +191,11 @@ static cl::opt<bool> PreserveAssemblyUseListOrder( cl::desc("Preserve use-list order when writing LLVM assembly."), cl::init(false), cl::Hidden); +static cl::opt<bool> + RunTwice("run-twice", + cl::desc("Run all passes twice, re-using the same pass manager."), + cl::init(false), cl::Hidden); + static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { // Add the pass to the pass manager... PM.add(P); @@ -312,7 +318,6 @@ int main(int argc, char **argv) { initializeVectorization(Registry); initializeIPO(Registry); initializeAnalysis(Registry); - initializeIPA(Registry); initializeTransformUtils(Registry); initializeInstCombine(Registry); initializeInstrumentation(Registry); @@ -583,22 +588,61 @@ int main(int argc, char **argv) { if (!NoVerify && !VerifyEach) Passes.add(createVerifierPass()); + // In run twice mode, we want to make sure the output is bit-by-bit + // equivalent if we run the pass manager again, so setup two buffers and + // a stream to write to them. Note that llc does something similar and it + // may be worth to abstract this out in the future. + SmallVector<char, 0> Buffer; + SmallVector<char, 0> CompileTwiceBuffer; + std::unique_ptr<raw_svector_ostream> BOS; + raw_ostream *OS = nullptr; + // Write bitcode or assembly to the output as the last step... if (!NoOutput && !AnalyzeOnly) { + assert(Out); + OS = &Out->os(); + if (RunTwice) { + BOS = make_unique<raw_svector_ostream>(Buffer); + OS = BOS.get(); + } if (OutputAssembly) - Passes.add( - createPrintModulePass(Out->os(), "", PreserveAssemblyUseListOrder)); + Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder)); else - Passes.add( - createBitcodeWriterPass(Out->os(), PreserveBitcodeUseListOrder)); + Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder)); } // Before executing passes, print the final values of the LLVM options. cl::PrintOptionValues(); + // If requested, run all passes again with the same pass manager to catch + // bugs caused by persistent state in the passes + if (RunTwice) { + std::unique_ptr<Module> M2(CloneModule(M.get())); + Passes.run(*M2); + CompileTwiceBuffer = Buffer; + Buffer.clear(); + } + // Now that we have all of the passes ready, run them. Passes.run(*M); + // Compare the two outputs and make sure they're the same + if (RunTwice) { + assert(Out); + if (Buffer.size() != CompileTwiceBuffer.size() || + (memcmp(Buffer.data(), CompileTwiceBuffer.data(), Buffer.size()) != + 0)) { + errs() << "Running the pass manager twice changed the output.\n" + "Writing the result of the second run to the specified output.\n" + "To generate the one-run comparison binary, just run without\n" + "the compile-twice option\n"; + Out->os() << BOS->str(); + Out->keep(); + return 1; + } + Out->os() << BOS->str(); + } + // Declare success. if (!NoOutput || PrintBreakpoints) Out->keep(); |