diff options
Diffstat (limited to 'tools')
142 files changed, 6216 insertions, 3103 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 12e10fd..13b7f5a 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,9 +1,13 @@ -# NOTE: The tools are organized into groups of four consisting of one large and -# three small executables. This is done to minimize memory load in parallel -# builds. Please retain this ordering. - add_llvm_tool_subdirectory(llvm-config) +# Build polly before the tools: the tools link against polly when +# LINK_POLLY_INTO_TOOLS is set. +if(WITH_POLLY) + add_llvm_external_project(polly) +else(WITH_POLLY) + list(APPEND LLVM_IMPLICIT_PROJECT_IGNORE "${LLVM_MAIN_SRC_DIR}/tools/polly") +endif(WITH_POLLY) + add_llvm_tool_subdirectory(opt) add_llvm_tool_subdirectory(llvm-as) add_llvm_tool_subdirectory(llvm-dis) @@ -15,6 +19,7 @@ add_llvm_tool_subdirectory(llvm-nm) add_llvm_tool_subdirectory(llvm-size) add_llvm_tool_subdirectory(llvm-cov) +add_llvm_tool_subdirectory(llvm-profdata) add_llvm_tool_subdirectory(llvm-link) add_llvm_tool_subdirectory(lli) @@ -69,7 +74,6 @@ add_llvm_external_project(clang) if( NOT LLVM_INCLUDE_TOOLS STREQUAL "bootstrap-only" ) add_llvm_external_project(lld) add_llvm_external_project(lldb) - add_llvm_external_project(polly) # Automatically add remaining sub-directories containing a 'CMakeLists.txt' # file as external projects. diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index 93b8d98..1b537a3 100644 --- a/tools/LLVMBuild.txt +++ b/tools/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup +subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup [component_0] type = Group diff --git a/tools/Makefile b/tools/Makefile index be87254..2b8c32e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -31,7 +31,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \ lli llvm-extract llvm-mc bugpoint llvm-bcanalyzer llvm-diff \ macho-dump llvm-objdump llvm-readobj llvm-rtdyld \ llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \ - llvm-symbolizer obj2yaml yaml2obj llvm-c-test + llvm-profdata llvm-symbolizer obj2yaml yaml2obj llvm-c-test # If Intel JIT Events support is configured, build an extra tool to test it. ifeq ($(USE_INTEL_JITEVENTS), 1) diff --git a/tools/bugpoint-passes/CMakeLists.txt b/tools/bugpoint-passes/CMakeLists.txt index 05f190a..b7ee626 100644 --- a/tools/bugpoint-passes/CMakeLists.txt +++ b/tools/bugpoint-passes/CMakeLists.txt @@ -2,6 +2,14 @@ if( NOT LLVM_BUILD_TOOLS ) set(EXCLUDE_FROM_ALL ON) endif() +# If we don't need RTTI or EH, there's no reason to export anything +# from this plugin. +if( NOT LLVM_REQUIRES_RTTI ) + if( NOT LLVM_REQUIRES_EH ) + set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/bugpoint.exports) + endif() +endif() + add_llvm_loadable_module( BugpointPasses TestPasses.cpp ) diff --git a/tools/bugpoint-passes/TestPasses.cpp b/tools/bugpoint-passes/TestPasses.cpp index 118c98a..ed54e9f 100644 --- a/tools/bugpoint-passes/TestPasses.cpp +++ b/tools/bugpoint-passes/TestPasses.cpp @@ -14,9 +14,9 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" +#include "llvm/IR/InstVisitor.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Type.h" -#include "llvm/InstVisitor.h" #include "llvm/Pass.h" using namespace llvm; @@ -29,11 +29,11 @@ namespace { static char ID; // Pass ID, replacement for typeid CrashOnCalls() : BasicBlockPass(ID) {} private: - virtual void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); } - bool runOnBasicBlock(BasicBlock &BB) { + bool runOnBasicBlock(BasicBlock &BB) override { for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) if (isa<CallInst>(*I)) abort(); @@ -56,7 +56,7 @@ namespace { static char ID; // Pass ID, replacement for typeid DeleteCalls() : BasicBlockPass(ID) {} private: - bool runOnBasicBlock(BasicBlock &BB) { + bool runOnBasicBlock(BasicBlock &BB) override { for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) if (CallInst *CI = dyn_cast<CallInst>(I)) { if (!CI->use_empty()) diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index a5436ba..2d1b903 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -17,7 +17,7 @@ #include "ToolRunner.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" -#include "llvm/Linker.h" +#include "llvm/Linker/Linker.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" @@ -122,7 +122,7 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { outs() << "Read input file : '" << Filenames[0] << "'\n"; for (unsigned i = 1, e = Filenames.size(); i != e; ++i) { - OwningPtr<Module> M(ParseInputFile(Filenames[i], Context)); + std::unique_ptr<Module> M(ParseInputFile(Filenames[i], Context)); if (M.get() == 0) return true; outs() << "Linking in input file: '" << Filenames[i] << "'\n"; diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index 27b37f4..c01bbe5 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -16,7 +16,7 @@ #ifndef BUGDRIVER_H #define BUGDRIVER_H -#include "llvm/ADT/ValueMap.h" +#include "llvm/IR/ValueMap.h" #include "llvm/Transforms/Utils/ValueMapper.h" #include <string> #include <vector> diff --git a/tools/bugpoint/CMakeLists.txt b/tools/bugpoint/CMakeLists.txt index 0000d97..d71e097 100644 --- a/tools/bugpoint/CMakeLists.txt +++ b/tools/bugpoint/CMakeLists.txt @@ -1,5 +1,24 @@ -set(LLVM_LINK_COMPONENTS asmparser instrumentation scalaropts ipo - linker bitreader bitwriter irreader vectorize objcarcopts) +set(LLVM_LINK_COMPONENTS + Analysis + BitWriter + CodeGen + Core + IPA + IPO + IRReader + InstCombine + Instrumentation + Linker + ObjCARCOpts + ScalarOpts + Support + Target + TransformUtils + Vectorize + ) + +# Support plugins. +set(LLVM_NO_DEAD_STRIP 1) add_llvm_tool(bugpoint BugDriver.cpp @@ -13,3 +32,12 @@ add_llvm_tool(bugpoint bugpoint.cpp ) set_target_properties(bugpoint PROPERTIES ENABLE_EXPORTS 1) + +if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS) + target_link_libraries(bugpoint Polly) + if(POLLY_LINK_LIBS) + foreach(lib ${POLLY_LINK_LIBS}) + target_link_libraries(bugpoint ${lib}) + endforeach(lib) + endif(POLLY_LINK_LIBS) +endif(WITH_POLLY AND LINK_POLLY_INTO_TOOLS) diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index b90fc61..bdaa6c9 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -15,15 +15,15 @@ #include "ListReducer.h" #include "ToolRunner.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Analysis/Verifier.h" +#include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueSymbolTable.h" +#include "llvm/IR/Verifier.h" #include "llvm/Pass.h" #include "llvm/PassManager.h" -#include "llvm/Support/CFG.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Transforms/Scalar.h" @@ -52,9 +52,9 @@ namespace llvm { // running the "Kept" passes fail when run on the output of the "removed" // passes. If we return true, we update the current module of bugpoint. // - virtual TestResult doTest(std::vector<std::string> &Removed, - std::vector<std::string> &Kept, - std::string &Error); + TestResult doTest(std::vector<std::string> &Removed, + std::vector<std::string> &Kept, + std::string &Error) override; }; } @@ -110,9 +110,9 @@ namespace { bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} - virtual TestResult doTest(std::vector<GlobalVariable*> &Prefix, - std::vector<GlobalVariable*> &Kept, - std::string &Error) { + TestResult doTest(std::vector<GlobalVariable*> &Prefix, + std::vector<GlobalVariable*> &Kept, + std::string &Error) override { if (!Kept.empty() && TestGlobalVariables(Kept)) return KeepSuffix; if (!Prefix.empty() && TestGlobalVariables(Prefix)) @@ -180,9 +180,9 @@ namespace { bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} - virtual TestResult doTest(std::vector<Function*> &Prefix, - std::vector<Function*> &Kept, - std::string &Error) { + TestResult doTest(std::vector<Function*> &Prefix, + std::vector<Function*> &Kept, + std::string &Error) override { if (!Kept.empty() && TestFuncs(Kept)) return KeepSuffix; if (!Prefix.empty() && TestFuncs(Prefix)) @@ -253,9 +253,9 @@ namespace { bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} - virtual TestResult doTest(std::vector<const BasicBlock*> &Prefix, - std::vector<const BasicBlock*> &Kept, - std::string &Error) { + TestResult doTest(std::vector<const BasicBlock*> &Prefix, + std::vector<const BasicBlock*> &Kept, + std::string &Error) override { if (!Kept.empty() && TestBlocks(Kept)) return KeepSuffix; if (!Prefix.empty() && TestBlocks(Prefix)) @@ -362,9 +362,9 @@ namespace { bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} - virtual TestResult doTest(std::vector<const Instruction*> &Prefix, - std::vector<const Instruction*> &Kept, - std::string &Error) { + TestResult doTest(std::vector<const Instruction*> &Prefix, + std::vector<const Instruction*> &Kept, + std::string &Error) override { if (!Kept.empty() && TestInsts(Kept)) return KeepSuffix; if (!Prefix.empty() && TestInsts(Prefix)) diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index c05c8d7..609de03 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -404,7 +404,7 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, // Remove the intermediate C file sys::fs::remove(OutputFile); - return "./" + SharedObjectFile; + return SharedObjectFile; } /// createReferenceFile - calls compileProgram and then records the output diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index 2098928..8bcae8a 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -13,13 +13,12 @@ //===----------------------------------------------------------------------===// #include "BugDriver.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Assembly/Writer.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/Pass.h" #include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" @@ -309,7 +308,7 @@ llvm::SplitFunctionsOutOfModule(Module *M, for (unsigned i = 0, e = F.size(); i != e; ++i) { Function *TNOF = cast<Function>(VMap[F[i]]); DEBUG(errs() << "Removing function "); - DEBUG(WriteAsOperand(errs(), TNOF, false)); + DEBUG(TNOF->printAsOperand(errs(), false)); DEBUG(errs() << "\n"); TestFunctions.insert(cast<Function>(NewVMap[TNOF])); DeleteFunctionBody(TNOF); // Function is now external in this module! @@ -330,7 +329,7 @@ llvm::SplitFunctionsOutOfModule(Module *M, if (Function *SafeFn = globalInitUsesExternalBA(GV)) { errs() << "*** Error: when reducing functions, encountered " "the global '"; - WriteAsOperand(errs(), GV, false); + GV->printAsOperand(errs(), false); errs() << "' with an initializer that references blockaddresses " "from safe function '" << SafeFn->getName() << "' and from test function '" << TestFn->getName() << "'.\n"; diff --git a/tools/bugpoint/LLVMBuild.txt b/tools/bugpoint/LLVMBuild.txt index 0164355..dda8d62 100644 --- a/tools/bugpoint/LLVMBuild.txt +++ b/tools/bugpoint/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = bugpoint parent = Tools -required_libraries = AsmParser BitReader BitWriter IRReader IPO Instrumentation Linker Scalar ObjCARC +required_libraries = AsmParser BitReader BitWriter CodeGen IRReader IPO Instrumentation Linker Scalar ObjCARC diff --git a/tools/bugpoint/Makefile b/tools/bugpoint/Makefile index 2049321..174f8d2 100644 --- a/tools/bugpoint/Makefile +++ b/tools/bugpoint/Makefile @@ -10,6 +10,9 @@ LEVEL := ../.. TOOLNAME := bugpoint LINK_COMPONENTS := asmparser instrumentation scalaropts ipo linker bitreader \ - bitwriter irreader vectorize objcarcopts + bitwriter irreader vectorize objcarcopts codegen + +# Support plugins. +NO_DEAD_STRIP := 1 include $(LEVEL)/Makefile.common diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index 771ec34..fecae60 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -15,13 +15,13 @@ #include "BugDriver.h" #include "ListReducer.h" #include "ToolRunner.h" -#include "llvm/Analysis/Verifier.h" #include "llvm/Config/config.h" // for HAVE_LINK_R #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" -#include "llvm/Linker.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Linker/Linker.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" @@ -48,9 +48,9 @@ namespace { public: ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {} - virtual TestResult doTest(std::vector<std::string> &Prefix, - std::vector<std::string> &Suffix, - std::string &Error); + TestResult doTest(std::vector<std::string> &Prefix, + std::vector<std::string> &Suffix, + std::string &Error) override; }; } @@ -128,8 +128,8 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, // Ok, so now we know that the prefix passes work, try running the suffix // passes on the result of the prefix passes. // - OwningPtr<Module> PrefixOutput(ParseInputFile(BitcodeResult, - BD.getContext())); + std::unique_ptr<Module> PrefixOutput( + ParseInputFile(BitcodeResult, BD.getContext())); if (!PrefixOutput) { errs() << BD.getToolName() << ": Error reading bitcode file '" << BitcodeResult << "'!\n"; @@ -145,7 +145,8 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, << "' passes compile correctly after the '" << getPassesString(Prefix) << "' passes: "; - OwningPtr<Module> OriginalInput(BD.swapProgramIn(PrefixOutput.take())); + std::unique_ptr<Module> OriginalInput( + BD.swapProgramIn(PrefixOutput.release())); if (BD.runPasses(BD.getProgram(), Suffix, BitcodeResult, false/*delete*/, true/*quiet*/)) { errs() << " Error running this sequence of passes" @@ -168,7 +169,7 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, // Otherwise, we must not be running the bad pass anymore. outs() << " yup.\n"; // No miscompilation! // Restore orig program & free test. - delete BD.swapProgramIn(OriginalInput.take()); + delete BD.swapProgramIn(OriginalInput.release()); return NoFailure; } @@ -182,9 +183,9 @@ namespace { std::string &)) : BD(bd), TestFn(F) {} - virtual TestResult doTest(std::vector<Function*> &Prefix, - std::vector<Function*> &Suffix, - std::string &Error) { + TestResult doTest(std::vector<Function*> &Prefix, + std::vector<Function*> &Suffix, + std::string &Error) override { if (!Suffix.empty()) { bool Ret = TestFuncs(Suffix, Error); if (!Error.empty()) @@ -467,9 +468,9 @@ namespace { const std::vector<Function*> &Fns) : BD(bd), TestFn(F), FunctionsBeingTested(Fns) {} - virtual TestResult doTest(std::vector<BasicBlock*> &Prefix, - std::vector<BasicBlock*> &Suffix, - std::string &Error) { + TestResult doTest(std::vector<BasicBlock*> &Prefix, + std::vector<BasicBlock*> &Suffix, + std::string &Error) override { if (!Suffix.empty()) { bool Ret = TestFuncs(Suffix, Error); if (!Error.empty()) diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index 20c609c..f91f493 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -16,10 +16,10 @@ //===----------------------------------------------------------------------===// #include "BugDriver.h" -#include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -71,7 +71,7 @@ bool BugDriver::writeProgramToFile(const std::string &Filename, int FD, bool BugDriver::writeProgramToFile(const std::string &Filename, const Module *M) const { std::string ErrInfo; - tool_output_file Out(Filename.c_str(), ErrInfo, sys::fs::F_Binary); + tool_output_file Out(Filename.c_str(), ErrInfo, sys::fs::F_None); if (ErrInfo.empty()) return writeProgramToFileAux(Out, M); return true; diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 254d997..f0fb4bf 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -178,16 +178,16 @@ namespace { if (Args) { ToolArgs = *Args; } } - virtual int ExecuteProgram(const std::string &Bitcode, - const std::vector<std::string> &Args, - const std::string &InputFile, - const std::string &OutputFile, - std::string *Error, - const std::vector<std::string> &GCCArgs, - const std::vector<std::string> &SharedLibs = - std::vector<std::string>(), - unsigned Timeout = 0, - unsigned MemoryLimit = 0); + int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0) override; }; } @@ -294,22 +294,22 @@ namespace { const std::string &CompilerCmd, std::vector<std::string> CompArgs) : CompilerCommand(CompilerCmd), CompilerArgs(CompArgs) {} - virtual void compileProgram(const std::string &Bitcode, - std::string *Error, - unsigned Timeout = 0, - unsigned MemoryLimit = 0); - - virtual int ExecuteProgram(const std::string &Bitcode, - const std::vector<std::string> &Args, - const std::string &InputFile, - const std::string &OutputFile, - std::string *Error, - const std::vector<std::string> &GCCArgs = - std::vector<std::string>(), - const std::vector<std::string> &SharedLibs = - std::vector<std::string>(), - unsigned Timeout = 0, - unsigned MemoryLimit = 0) { + void compileProgram(const std::string &Bitcode, + std::string *Error, + unsigned Timeout = 0, + unsigned MemoryLimit = 0) override; + + int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs = + std::vector<std::string>(), + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0) override { *Error = "Execution not supported with -compile-custom"; return -1; } @@ -355,16 +355,16 @@ namespace { const std::string &ExecutionCmd, std::vector<std::string> ExecArgs) : ExecutionCommand(ExecutionCmd), ExecutorArgs(ExecArgs) {} - virtual int ExecuteProgram(const std::string &Bitcode, - const std::vector<std::string> &Args, - const std::string &InputFile, - const std::string &OutputFile, - std::string *Error, - const std::vector<std::string> &GCCArgs, - const std::vector<std::string> &SharedLibs = - std::vector<std::string>(), - unsigned Timeout = 0, - unsigned MemoryLimit = 0); + int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0) override; }; } @@ -406,7 +406,7 @@ int CustomExecutor::ExecuteProgram(const std::string &Bitcode, // code borrowed from: // http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html static void lexCommand(std::string &Message, const std::string &CommandLine, - std::string &CmdPath, std::vector<std::string> Args) { + std::string &CmdPath, std::vector<std::string> &Args) { std::string Command = ""; std::string delimiters = " "; @@ -584,17 +584,17 @@ namespace { if (Args) { ToolArgs = *Args; } } - virtual int ExecuteProgram(const std::string &Bitcode, - const std::vector<std::string> &Args, - const std::string &InputFile, - const std::string &OutputFile, - std::string *Error, - const std::vector<std::string> &GCCArgs = - std::vector<std::string>(), - const std::vector<std::string> &SharedLibs = - std::vector<std::string>(), - unsigned Timeout = 0, - unsigned MemoryLimit = 0); + int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs = + std::vector<std::string>(), + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0) override; }; } diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h index bc2be46..38a5835 100644 --- a/tools/bugpoint/ToolRunner.h +++ b/tools/bugpoint/ToolRunner.h @@ -168,29 +168,29 @@ public: /// compileProgram - Compile the specified program from bitcode to executable /// code. This does not produce any output, it is only used when debugging /// the code generator. Returns false if the code generator fails. - virtual void compileProgram(const std::string &Bitcode, std::string *Error, - unsigned Timeout = 0, unsigned MemoryLimit = 0); + void compileProgram(const std::string &Bitcode, std::string *Error, + unsigned Timeout = 0, unsigned MemoryLimit = 0) override; - virtual int ExecuteProgram(const std::string &Bitcode, - const std::vector<std::string> &Args, - const std::string &InputFile, - const std::string &OutputFile, - std::string *Error, - const std::vector<std::string> &GCCArgs = - std::vector<std::string>(), - const std::vector<std::string> &SharedLibs = - std::vector<std::string>(), - unsigned Timeout = 0, - unsigned MemoryLimit = 0); + int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs = + std::vector<std::string>(), + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + 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 /// fails, it sets Error, otherwise, this function returns the type of code /// emitted. - virtual GCC::FileType OutputCode(const std::string &Bitcode, - std::string &OutFile, std::string &Error, - unsigned Timeout = 0, - unsigned MemoryLimit = 0); + GCC::FileType OutputCode(const std::string &Bitcode, + std::string &OutFile, std::string &Error, + unsigned Timeout = 0, + unsigned MemoryLimit = 0) override; }; } // End llvm namespace diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index 9bc592e..5c03b41 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -16,12 +16,12 @@ #include "BugDriver.h" #include "ToolRunner.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassNameParser.h" #include "llvm/LinkAllIR.h" #include "llvm/LinkAllPasses.h" #include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" @@ -34,7 +34,7 @@ using namespace llvm; -static cl::opt<bool> +static cl::opt<bool> FindBugs("find-bugs", cl::desc("Run many different optimization sequences " "on program to find bugs"), cl::init(false)); @@ -63,24 +63,24 @@ static cl::list<const PassInfo*, bool, PassNameParser> PassList(cl::desc("Passes available:"), cl::ZeroOrMore); static cl::opt<bool> -StandardCompileOpts("std-compile-opts", +StandardCompileOpts("std-compile-opts", cl::desc("Include the standard compile time optimizations")); static cl::opt<bool> -StandardLinkOpts("std-link-opts", +StandardLinkOpts("std-link-opts", cl::desc("Include the standard link time optimizations")); static cl::opt<bool> OptLevelO1("O1", - cl::desc("Optimization level 1. Similar to llvm-gcc -O1")); + cl::desc("Optimization level 1. Identical to 'opt -O1'")); static cl::opt<bool> OptLevelO2("O2", - cl::desc("Optimization level 2. Similar to llvm-gcc -O2")); + cl::desc("Optimization level 2. Identical to 'opt -O2'")); static cl::opt<bool> OptLevelO3("O3", - cl::desc("Optimization level 3. Similar to llvm-gcc -O3")); + cl::desc("Optimization level 3. Identical to 'opt -O3'")); static cl::opt<std::string> OverrideTriple("mtriple", cl::desc("Override target triple for module")); @@ -100,8 +100,8 @@ namespace { BugDriver &D; public: AddToDriver(BugDriver &_D) : FunctionPassManager(0), D(_D) {} - - virtual void add(Pass *P) { + + void add(Pass *P) override { const void *ID = P->getPassID(); const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID); D.addPass(PI->getPassArgument()); @@ -109,13 +109,19 @@ namespace { }; } +#ifdef LINK_POLLY_INTO_TOOLS +namespace polly { +void initializePollyPasses(llvm::PassRegistry &Registry); +} +#endif + int main(int argc, char **argv) { #ifndef DEBUG_BUGPOINT llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. #endif - + // Initialize passes PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); @@ -129,7 +135,11 @@ int main(int argc, char **argv) { initializeInstCombine(Registry); initializeInstrumentation(Registry); initializeTarget(Registry); - + +#ifdef LINK_POLLY_INTO_TOOLS + polly::initializePollyPasses(Registry); +#endif + cl::ParseCommandLineOptions(argc, argv, "LLVM automatic testcase reducer. See\nhttp://" "llvm.org/cmds/bugpoint.html" @@ -158,7 +168,7 @@ int main(int argc, char **argv) { BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit, UseValgrind, Context); if (D.addSources(InputFilenames)) return 1; - + AddToDriver PM(D); if (StandardCompileOpts) { PassManagerBuilder Builder; @@ -166,7 +176,7 @@ int main(int argc, char **argv) { Builder.Inliner = createFunctionInliningPass(); Builder.populateModulePassManager(PM); } - + if (StandardLinkOpts) { PassManagerBuilder Builder; Builder.populateLTOPassManager(PM, /*Internalize=*/true, diff --git a/tools/gold/CMakeLists.txt b/tools/gold/CMakeLists.txt index 2cc132f..07a1e28 100644 --- a/tools/gold/CMakeLists.txt +++ b/tools/gold/CMakeLists.txt @@ -1,6 +1,8 @@ set(LLVM_BINUTILS_INCDIR "" CACHE PATH "PATH to binutils/include containing plugin-api.h for gold plugin.") +set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/gold.exports) + if( NOT LLVM_BINUTILS_INCDIR ) # Nothing to say. elseif( NOT EXISTS "${LLVM_BINUTILS_INCDIR}/plugin-api.h" ) @@ -18,29 +20,7 @@ else() gold-plugin.cpp ) - # Makefile.rules contains a special cases for OpenBSD, Darwin and - # Windows. We restrict ourselves to Linux for the time being. - set(srcexp ${CMAKE_CURRENT_SOURCE_DIR}/gold.exports) - add_custom_command(OUTPUT exportsfile - COMMAND echo "{" > exportsfile - COMMAND grep -q "\\<" ${srcexp} && echo " global:" >> exportsfile || : - COMMAND sed -e "s/$/;/" -e "s/^/ /" < ${srcexp} >> exportsfile - COMMAND echo " local: *;" >> exportsfile - COMMAND echo "};" >> exportsfile - DEPENDS ${srcexp} - VERBATIM - COMMENT "Creating export file for gold plugin") - add_custom_target(gold_exports DEPENDS exportsfile) - set_property(DIRECTORY APPEND - PROPERTY ADDITIONAL_MAKE_CLEAN_FILES exportsfile) - - # Force re-linking when the exports file changes. Actually, it - # forces recompilation of gold-plugin.cpp. The LINK_DEPENDS target - # property only works for makefile-based generators. - set_property(SOURCE gold-plugin.cpp APPEND PROPERTY - OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/exportsfile) - - target_link_libraries(LLVMgold LTO - -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/exportsfile) - add_dependencies(LLVMgold gold_exports) + target_link_libraries(LLVMgold ${cmake_2_8_12_PRIVATE} LTO) + endif() + diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 0e3bad2..4726d82 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -13,10 +13,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H -#include "plugin-api.h" #include "llvm-c/lto.h" #include "llvm/ADT/StringSet.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -29,6 +27,7 @@ #include <cstring> #include <fstream> #include <list> +#include <plugin-api.h> #include <vector> // Support Windows/MinGW crazyness. @@ -38,6 +37,12 @@ # define read _read #endif +#ifndef LDPO_PIE +// FIXME: remove this declaration when we stop maintaining Ubuntu Quantal and +// Precise and Debian Wheezy (binutils 2.23 is required) +# define LDPO_PIE 3 +#endif + using namespace llvm; namespace { @@ -153,8 +158,7 @@ ld_plugin_status onload(ld_plugin_tv *tv) { switch (tv->tv_u.tv_val) { case LDPO_REL: // .o case LDPO_DYN: // .so - // FIXME: Replace 3 with LDPO_PIE once that is in a released binutils. - case 3: // position independent executable + case LDPO_PIE: // position independent executable output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC; break; case LDPO_EXEC: // .exe @@ -241,7 +245,7 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, int *claimed) { lto_module_t M; const void *view; - OwningPtr<MemoryBuffer> buffer; + std::unique_ptr<MemoryBuffer> buffer; if (get_view) { if (get_view(file->handle, &view) != LDPS_OK) { (*message)(LDPL_ERROR, "Failed to get a view of %s", file->name); diff --git a/tools/llc/Android.mk b/tools/llc/Android.mk index 0d44444..2167fe3 100644 --- a/tools/llc/Android.mk +++ b/tools/llc/Android.mk @@ -106,6 +106,7 @@ ifeq (,$(filter $(TARGET_ARCH),$(LLVM_SUPPORTED_ARCH))) $(warning TODO $(TARGET_ARCH): Enable llc build) endif +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) LOCAL_MODULE := llc @@ -126,9 +127,10 @@ LOCAL_STATIC_LIBRARIES += $(llvm_llc_STATIC_LIBRARIES) LOCAL_SHARED_LIBRARIES := \ libcutils \ libdl \ - libstlport + libc++ include $(LLVM_ROOT_PATH)/llvm.mk include $(LLVM_DEVICE_BUILD_MK) include $(LLVM_GEN_INTRINSICS_MK) include $(BUILD_EXECUTABLE) +endif diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt index e5a5550..393d64c 100644 --- a/tools/llc/CMakeLists.txt +++ b/tools/llc/CMakeLists.txt @@ -1,5 +1,20 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser irreader) +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + AsmPrinter + CodeGen + Core + IRReader + MC + ScalarOpts + SelectionDAG + Support + Target + ) + +# Support plugins. +set(LLVM_NO_DEAD_STRIP 1) add_llvm_tool(llc llc.cpp ) +set_target_properties(llc PROPERTIES ENABLE_EXPORTS 1) diff --git a/tools/llc/Makefile b/tools/llc/Makefile index c24f378..71bce4d 100644 --- a/tools/llc/Makefile +++ b/tools/llc/Makefile @@ -11,5 +11,8 @@ LEVEL := ../.. TOOLNAME := llc LINK_COMPONENTS := all-targets bitreader asmparser irreader +# Support plugins. +NO_DEAD_STRIP := 1 + include $(LEVEL)/Makefile.common diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 6aac8ff..8fbdc49 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -14,13 +14,13 @@ //===----------------------------------------------------------------------===// -#include "llvm/IR/LLVMContext.h" #include "llvm/ADT/Triple.h" -#include "llvm/Assembly/PrintModulePass.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/LinkAllAsmWriterComponents.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/MC/SubtargetFeature.h" @@ -58,6 +58,10 @@ TimeCompilations("time-compilations", cl::Hidden, cl::init(1u), cl::value_desc("N"), cl::desc("Repeat compilation N times for timing")); +static cl::opt<bool> +NoIntegratedAssembler("no-integrated-as", cl::Hidden, + cl::desc("Disable integrated assembler")); + // Determine optimization level. static cl::opt<char> OptLevel("O", @@ -146,8 +150,8 @@ static tool_output_file *GetOutputStream(const char *TargetName, // Open the file. std::string error; sys::fs::OpenFlags OpenFlags = sys::fs::F_None; - if (Binary) - OpenFlags |= sys::fs::F_Binary; + if (!Binary) + OpenFlags |= sys::fs::F_Text; tool_output_file *FDOut = new tool_output_file(OutputFilename.c_str(), error, OpenFlags); if (!error.empty()) { @@ -202,7 +206,7 @@ int main(int argc, char **argv) { static int compileModule(char **argv, LLVMContext &Context) { // Load the module to be compiled... SMDiagnostic Err; - OwningPtr<Module> M; + std::unique_ptr<Module> M; Module *mod = 0; Triple TheTriple; @@ -259,38 +263,16 @@ static int compileModule(char **argv, LLVMContext &Context) { case '3': OLvl = CodeGenOpt::Aggressive; break; } - TargetOptions Options; - Options.LessPreciseFPMADOption = EnableFPMAD; - Options.NoFramePointerElim = DisableFPElim; - Options.AllowFPOpFusion = FuseFPOps; - Options.UnsafeFPMath = EnableUnsafeFPMath; - Options.NoInfsFPMath = EnableNoInfsFPMath; - Options.NoNaNsFPMath = EnableNoNaNsFPMath; - Options.HonorSignDependentRoundingFPMathOption = - EnableHonorSignDependentRoundingFPMath; - Options.UseSoftFloat = GenerateSoftFloatCalls; - if (FloatABIForCalls != FloatABI::Default) - Options.FloatABIType = FloatABIForCalls; - Options.NoZerosInBSS = DontPlaceZerosInBSS; - Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; - Options.DisableTailCalls = DisableTailCalls; - Options.StackAlignmentOverride = OverrideStackAlignment; - Options.TrapFuncName = TrapFuncName; - Options.PositionIndependentExecutable = EnablePIE; - Options.EnableSegmentedStacks = SegmentedStacks; - Options.UseInitArray = UseInitArray; - - OwningPtr<TargetMachine> - target(TheTarget->createTargetMachine(TheTriple.getTriple(), - MCPU, FeaturesStr, Options, - RelocModel, CMModel, OLvl)); + TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + Options.DisableIntegratedAS = NoIntegratedAssembler; + + std::unique_ptr<TargetMachine> target( + TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, FeaturesStr, + Options, RelocModel, CMModel, OLvl)); assert(target.get() && "Could not allocate target machine!"); assert(mod && "Should have exited after outputting help!"); TargetMachine &Target = *target.get(); - if (DisableDotLoc) - Target.setMCUseLoc(false); - if (DisableCFI) Target.setMCUseCFI(false); @@ -300,14 +282,9 @@ static int compileModule(char **argv, LLVMContext &Context) { if (GenerateSoftFloatCalls) FloatABIForCalls = FloatABI::Soft; - // Disable .loc support for older OS X versions. - if (TheTriple.isMacOSX() && - TheTriple.isMacOSXVersionLT(10, 6)) - Target.setMCUseLoc(false); - // Figure out where we are going to send the output. - OwningPtr<tool_output_file> Out - (GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0])); + std::unique_ptr<tool_output_file> Out( + GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0])); if (!Out) return 1; // Build up all of the passes that we want to do to the module. @@ -319,14 +296,10 @@ static int compileModule(char **argv, LLVMContext &Context) { TLI->disableAllFunctions(); PM.add(TLI); - // Add intenal analysis passes from the target machine. - Target.addAnalysisPasses(PM); - // Add the target data from the target machine, if it exists, or the module. - if (const DataLayout *TD = Target.getDataLayout()) - PM.add(new DataLayout(*TD)); - else - PM.add(new DataLayout(mod)); + if (const DataLayout *DL = Target.getDataLayout()) + mod->setDataLayout(DL); + PM.add(new DataLayoutPass(mod)); // Override default to generate verbose assembly. Target.setAsmVerbosityDefault(true); diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt index 5f8c7c9..731b61a 100644 --- a/tools/lli/CMakeLists.txt +++ b/tools/lli/CMakeLists.txt @@ -1,8 +1,19 @@ - -set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native instrumentation) - add_subdirectory(ChildTarget) +set(LLVM_LINK_COMPONENTS + CodeGen + Core + ExecutionEngine + IRReader + Instrumentation + Interpreter + JIT + MCJIT + SelectionDAG + Support + native + ) + if( LLVM_USE_OPROFILE ) set(LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS} @@ -25,3 +36,4 @@ add_llvm_tool(lli RemoteTarget.cpp RemoteTargetExternal.cpp ) +set_target_properties(lli PROPERTIES ENABLE_EXPORTS 1) diff --git a/tools/lli/ChildTarget/CMakeLists.txt b/tools/lli/ChildTarget/CMakeLists.txt index fd1ac24..9f88b2c 100644 --- a/tools/lli/ChildTarget/CMakeLists.txt +++ b/tools/lli/ChildTarget/CMakeLists.txt @@ -1,3 +1,8 @@ -add_llvm_tool(lli-child-target +set(LLVM_LINK_COMPONENTS support) + +add_llvm_executable(lli-child-target ChildTarget.cpp - ) + ../RemoteTarget.cpp +) + +set_target_properties(lli-child-target PROPERTIES FOLDER "Misc") diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp index 55fcae9..0d71b17 100644 --- a/tools/lli/ChildTarget/ChildTarget.cpp +++ b/tools/lli/ChildTarget/ChildTarget.cpp @@ -1,6 +1,8 @@ #include "llvm/Config/config.h" - +#include "../RPCChannel.h" +#include "../RemoteTarget.h" #include "../RemoteTargetMessage.h" +#include "llvm/Support/Memory.h" #include <assert.h> #include <map> #include <stdint.h> @@ -11,36 +13,32 @@ using namespace llvm; class LLIChildTarget { public: - ~LLIChildTarget(); // OS-specific destructor void initialize(); LLIMessageType waitForIncomingMessage(); void handleMessage(LLIMessageType messageType); + RemoteTarget *RT; + RPCChannel RPC; private: // Incoming message handlers void handleAllocateSpace(); void handleLoadSection(bool IsCode); void handleExecute(); - void handleTerminate(); // Outgoing message handlers void sendChildActive(); void sendAllocationResult(uint64_t Addr); - void sendLoadComplete(); - void sendExecutionComplete(uint64_t Result); + void sendLoadStatus(uint32_t Status); + void sendExecutionComplete(int Result); // OS-specific functions void initializeConnection(); - int WriteBytes(const void *Data, size_t Size); - int ReadBytes(void *Data, size_t Size); - uint64_t allocate(uint32_t Alignment, uint32_t Size); - void makeSectionExecutable(uint64_t Addr, uint32_t Size); - void InvalidateInstructionCache(const void *Addr, size_t Len); - void releaseMemory(uint64_t Addr, uint32_t Size); - - // Store a map of allocated buffers to sizes. - typedef std::map<uint64_t, uint32_t> AllocMapType; - AllocMapType m_AllocatedBufferMap; + int WriteBytes(const void *Data, size_t Size) { + return RPC.WriteBytes(Data, Size) ? Size : -1; + } + int ReadBytes(void *Data, size_t Size) { + return RPC.ReadBytes(Data, Size) ? Size : -1; + } // Communication handles (OS-specific) void *ConnectionData; @@ -48,6 +46,7 @@ private: int main() { LLIChildTarget ThisChild; + ThisChild.RT = new RemoteTarget(); ThisChild.initialize(); LLIMessageType MsgType; do { @@ -55,12 +54,13 @@ int main() { ThisChild.handleMessage(MsgType); } while (MsgType != LLI_Terminate && MsgType != LLI_Error); + delete ThisChild.RT; return 0; } // Public methods void LLIChildTarget::initialize() { - initializeConnection(); + RPC.createClient(); sendChildActive(); } @@ -86,7 +86,7 @@ void LLIChildTarget::handleMessage(LLIMessageType messageType) { handleExecute(); break; case LLI_Terminate: - handleTerminate(); + RT->stop(); break; default: // FIXME: Handle error! @@ -99,6 +99,7 @@ void LLIChildTarget::handleAllocateSpace() { // Read and verify the message data size. uint32_t DataSize; int rc = ReadBytes(&DataSize, 4); + (void)rc; assert(rc == 4); assert(DataSize == 8); @@ -111,7 +112,8 @@ void LLIChildTarget::handleAllocateSpace() { assert(rc == 4); // Allocate the memory. - uint64_t Addr = allocate(Alignment, AllocSize); + uint64_t Addr; + RT->allocateSpace(AllocSize, Alignment, Addr); // Send AllocationResult message. sendAllocationResult(Addr); @@ -121,33 +123,36 @@ void LLIChildTarget::handleLoadSection(bool IsCode) { // Read the message data size. uint32_t DataSize; int rc = ReadBytes(&DataSize, 4); + (void)rc; assert(rc == 4); // Read the target load address. uint64_t Addr; rc = ReadBytes(&Addr, 8); assert(rc == 8); - size_t BufferSize = DataSize - 8; - // FIXME: Verify that this is in allocated space + if (!RT->isAllocatedMemory(Addr, BufferSize)) + return sendLoadStatus(LLI_Status_NotAllocated); // Read section data into previously allocated buffer - rc = ReadBytes((void*)Addr, DataSize - 8); - assert(rc == (int)(BufferSize)); + rc = ReadBytes((void*)Addr, BufferSize); + if (rc != (int)(BufferSize)) + return sendLoadStatus(LLI_Status_IncompleteMsg); // If IsCode, mark memory executable if (IsCode) - makeSectionExecutable(Addr, BufferSize); + sys::Memory::InvalidateInstructionCache((void *)Addr, BufferSize); // Send MarkLoadComplete message. - sendLoadComplete(); + sendLoadStatus(LLI_Status_Success); } void LLIChildTarget::handleExecute() { // Read the message data size. uint32_t DataSize; int rc = ReadBytes(&DataSize, 4); + (void)rc; assert(rc == 4); assert(DataSize == 8); @@ -157,22 +162,11 @@ void LLIChildTarget::handleExecute() { assert(rc == 8); // Call function - int Result; - int (*fn)(void) = (int(*)(void))Addr; - Result = fn(); + int32_t Result = -1; + RT->executeCode(Addr, Result); // Send ExecutionResult message. - sendExecutionComplete((int64_t)Result); -} - -void LLIChildTarget::handleTerminate() { - // Release all allocated memory - AllocMapType::iterator Begin = m_AllocatedBufferMap.begin(); - AllocMapType::iterator End = m_AllocatedBufferMap.end(); - for (AllocMapType::iterator It = Begin; It != End; ++It) { - releaseMemory(It->first, It->second); - } - m_AllocatedBufferMap.clear(); + sendExecutionComplete(Result); } // Outgoing message handlers @@ -180,6 +174,7 @@ void LLIChildTarget::sendChildActive() { // Write the message type. uint32_t MsgType = (uint32_t)LLI_ChildActive; int rc = WriteBytes(&MsgType, 4); + (void)rc; assert(rc == 4); // Write the data size. @@ -192,6 +187,7 @@ void LLIChildTarget::sendAllocationResult(uint64_t Addr) { // Write the message type. uint32_t MsgType = (uint32_t)LLI_AllocationResult; int rc = WriteBytes(&MsgType, 4); + (void)rc; assert(rc == 4); // Write the data size. @@ -204,39 +200,45 @@ void LLIChildTarget::sendAllocationResult(uint64_t Addr) { assert(rc == 8); } -void LLIChildTarget::sendLoadComplete() { +void LLIChildTarget::sendLoadStatus(uint32_t Status) { // Write the message type. - uint32_t MsgType = (uint32_t)LLI_LoadComplete; + uint32_t MsgType = (uint32_t)LLI_LoadResult; int rc = WriteBytes(&MsgType, 4); + (void)rc; assert(rc == 4); // Write the data size. - uint32_t DataSize = 0; + uint32_t DataSize = 4; rc = WriteBytes(&DataSize, 4); assert(rc == 4); + + // Write the result. + rc = WriteBytes(&Status, 4); + assert(rc == 4); } -void LLIChildTarget::sendExecutionComplete(uint64_t Result) { +void LLIChildTarget::sendExecutionComplete(int Result) { // Write the message type. uint32_t MsgType = (uint32_t)LLI_ExecutionResult; int rc = WriteBytes(&MsgType, 4); + (void)rc; assert(rc == 4); // Write the data size. - uint32_t DataSize = 8; + uint32_t DataSize = 4; rc = WriteBytes(&DataSize, 4); assert(rc == 4); // Write the result. - rc = WriteBytes(&Result, 8); - assert(rc == 8); + rc = WriteBytes(&Result, 4); + assert(rc == 4); } #ifdef LLVM_ON_UNIX -#include "Unix/ChildTarget.inc" +#include "../Unix/RPCChannel.inc" #endif #ifdef LLVM_ON_WIN32 -#include "Windows/ChildTarget.inc" +#include "../Windows/RPCChannel.inc" #endif diff --git a/tools/lli/ChildTarget/Makefile b/tools/lli/ChildTarget/Makefile index f77b144..6f4ddef 100644 --- a/tools/lli/ChildTarget/Makefile +++ b/tools/lli/ChildTarget/Makefile @@ -12,6 +12,8 @@ TOOLNAME := lli-child-target include $(LEVEL)/Makefile.config -LINK_COMPONENTS := +LINK_COMPONENTS := support + +SOURCES := ChildTarget.cpp ../RemoteTarget.cpp include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/tools/lli/ChildTarget/Unix/ChildTarget.inc b/tools/lli/ChildTarget/Unix/ChildTarget.inc deleted file mode 100644 index cc95810..0000000 --- a/tools/lli/ChildTarget/Unix/ChildTarget.inc +++ /dev/null @@ -1,166 +0,0 @@ -//===- ChildTarget.inc - Child process for external JIT execution for Unix -==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implementation of the Unix-specific parts of the ChildTarget class -// which executes JITed code in a separate process from where it was built. -// -//===----------------------------------------------------------------------===// - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> - -#ifdef HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif - -#ifdef __APPLE__ -#include <mach/mach.h> -#endif - -#if defined(__mips__) -# if defined(__OpenBSD__) -# include <mips64/sysarch.h> -# else -# include <sys/cachectl.h> -# endif -#endif - -#ifdef __APPLE__ -extern "C" void sys_icache_invalidate(const void *Addr, size_t len); -#else -extern "C" void __clear_cache(void *, void*); -#endif - -namespace { - -struct ConnectionData_t { - int InputPipe; - int OutputPipe; - - ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {} -}; - -} // namespace - -LLIChildTarget::~LLIChildTarget() { - delete static_cast<ConnectionData_t *>(ConnectionData); -} - -// OS-specific methods -void LLIChildTarget::initializeConnection() { - // Store the parent ends of the pipes - ConnectionData = (void*)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO); -} - -int LLIChildTarget::WriteBytes(const void *Data, size_t Size) { - return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size); -} - -int LLIChildTarget::ReadBytes(void *Data, size_t Size) { - return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size); -} - -// The functions below duplicate functionality that is implemented in -// Support/Memory.cpp with the goal of avoiding a dependency on any -// llvm libraries. - -uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) { - if (!Alignment) - Alignment = 16; - - static const size_t PageSize = getpagesize(); - const size_t NumPages = (Size+PageSize-1)/PageSize; - Size = NumPages*PageSize; - - int fd = -1; -#ifdef NEED_DEV_ZERO_FOR_MMAP - static int zero_fd = open("/dev/zero", O_RDWR); - if (zero_fd == -1) - return 0; - fd = zero_fd; -#endif - - int MMFlags = MAP_PRIVATE | -#ifdef HAVE_MMAP_ANONYMOUS - MAP_ANONYMOUS -#else - MAP_ANON -#endif - ; // Ends statement above - - uint64_t Addr = (uint64_t)::mmap(0, Size, PROT_READ | PROT_WRITE, MMFlags, fd, 0); - if (Addr == (uint64_t)MAP_FAILED) - return 0; - - // Align the address. - Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - - m_AllocatedBufferMap[Addr] = Size; - - // Return aligned address - return Addr; -} - -void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) { - // FIXME: We have to mark the memory as RWX because multiple code chunks may - // be on the same page. The RemoteTarget interface should be changed to - // work around that. - int Result = ::mprotect((void*)Addr, Size, PROT_READ | PROT_WRITE | PROT_EXEC); - if (Result != 0) - InvalidateInstructionCache((const void *)Addr, Size); -} - -/// InvalidateInstructionCache - Before the JIT can run a block of code -/// that has been emitted it must invalidate the instruction cache on some -/// platforms. -void LLIChildTarget::InvalidateInstructionCache(const void *Addr, - size_t Len) { - -// icache invalidation for PPC and ARM. -#if defined(__APPLE__) - -# if (defined(__POWERPC__) || defined (__ppc__) || \ - defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) - sys_icache_invalidate(const_cast<void *>(Addr), Len); -# endif - -#else - -# if (defined(__POWERPC__) || defined (__ppc__) || \ - defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) - const size_t LineSize = 32; - - const intptr_t Mask = ~(LineSize - 1); - const intptr_t StartLine = ((intptr_t) Addr) & Mask; - const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; - - for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) - asm volatile("dcbf 0, %0" : : "r"(Line)); - asm volatile("sync"); - - for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) - asm volatile("icbi 0, %0" : : "r"(Line)); - asm volatile("isync"); -# elif defined(__arm__) && defined(__GNUC__) - // FIXME: Can we safely always call this for __GNUC__ everywhere? - const char *Start = static_cast<const char *>(Addr); - const char *End = Start + Len; - __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); -# elif defined(__mips__) - const char *Start = static_cast<const char *>(Addr); - cacheflush(const_cast<char *>(Start), Len, BCACHE); -# endif - -#endif // end apple -} - -void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) { - ::munmap((void*)Addr, Size); -} diff --git a/tools/lli/ChildTarget/Windows/ChildTarget.inc b/tools/lli/ChildTarget/Windows/ChildTarget.inc deleted file mode 100644 index 45db2b0..0000000 --- a/tools/lli/ChildTarget/Windows/ChildTarget.inc +++ /dev/null @@ -1,44 +0,0 @@ -//=- ChildTarget.inc - Child process for external JIT execution for Windows -=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Non-implementation of the Windows-specific parts of the ChildTarget class -// which executes JITed code in a separate process from where it was built. -// -//===----------------------------------------------------------------------===// - -LLIChildTarget::~LLIChildTarget() { -} - -// The RemoteTargetExternal implementation should prevent us from ever getting -// here on Windows, but nothing prevents a user from running this directly. -void LLIChildTarget::initializeConnection() { - assert(0 && "lli-child-target is not implemented for Windows"); -} - -int LLIChildTarget::WriteBytes(const void *Data, size_t Size) { - return 0; -} - -int LLIChildTarget::ReadBytes(void *Data, size_t Size) { - return 0; -} - -uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) { - return 0; -} - -void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) { -} - -void LLIChildTarget::InvalidateInstructionCache(const void *Addr, - size_t Len) { -} - -void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) { -} diff --git a/tools/lli/RPCChannel.h b/tools/lli/RPCChannel.h new file mode 100644 index 0000000..2d8c708 --- /dev/null +++ b/tools/lli/RPCChannel.h @@ -0,0 +1,49 @@ +//===---------- RPCChannel.h - LLVM out-of-process JIT execution ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Definition of the RemoteTargetExternal class which executes JITed code in a +// separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +#ifndef LLI_RPCCHANNEL_H +#define LLI_RPCCHANNEL_H + +#include <stdlib.h> +#include <string> + +namespace llvm { + +class RPCChannel { +public: + std::string ChildName; + + RPCChannel() {} + ~RPCChannel(); + + /// Start the remote process. + /// + /// @returns True on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + bool createServer(); + + bool createClient(); + + // This will get filled in as a point to an OS-specific structure. + void *ConnectionData; + + bool WriteBytes(const void *Data, size_t Size); + bool ReadBytes(void *Data, size_t Size); + + void Wait(); +}; + +} // end namespace llvm + +#endif // LLI_RPCCHANNEL_H diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp index 04fc40e..e9f4d53 100644 --- a/tools/lli/RemoteMemoryManager.cpp +++ b/tools/lli/RemoteMemoryManager.cpp @@ -109,7 +109,7 @@ void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, CurOffset += Size; } } - // Adjust to keep code and data aligned on seperate pages. + // Adjust to keep code and data aligned on separate pages. CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; for (size_t i = 0, e = NumSections; i != e; ++i) { Allocation &Section = UnmappedSections[i]; @@ -129,7 +129,7 @@ void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, // Allocate space in the remote target. uint64_t RemoteAddr; - if (Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) + if (!Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) report_fatal_error(Target->getErrorMsg()); // Map the section addresses so relocations will get updated in the local @@ -155,13 +155,13 @@ bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) { uint64_t RemoteAddr = I->first; const Allocation &Section = I->second; if (Section.IsCode) { - Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()); - + if (!Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size())) + report_fatal_error(Target->getErrorMsg()); DEBUG(dbgs() << " loading code: " << Section.MB.base() << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); } else { - Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()); - + if (!Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size())) + report_fatal_error(Target->getErrorMsg()); DEBUG(dbgs() << " loading data: " << Section.MB.base() << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); } diff --git a/tools/lli/RemoteMemoryManager.h b/tools/lli/RemoteMemoryManager.h index 5d0456f..11f600f 100644 --- a/tools/lli/RemoteMemoryManager.h +++ b/tools/lli/RemoteMemoryManager.h @@ -15,6 +15,7 @@ #ifndef REMOTEMEMORYMANAGER_H #define REMOTEMEMORYMANAGER_H +#include "RemoteTarget.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ExecutionEngine/JITMemoryManager.h" @@ -22,8 +23,6 @@ #include "llvm/Support/Memory.h" #include <utility> -#include "RemoteTarget.h" - namespace llvm { class RemoteMemoryManager : public JITMemoryManager { @@ -68,45 +67,48 @@ public: virtual ~RemoteMemoryManager(); uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, StringRef SectionName); + unsigned SectionID, + StringRef SectionName) override; uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, - bool IsReadOnly); + bool IsReadOnly) override; // For now, remote symbol resolution is not support in lli. The MCJIT // interface does support this, but clients must provide their own // mechanism for finding remote symbol addresses. MCJIT will resolve // symbols from Modules it contains. - uint64_t getSymbolAddress(const std::string &Name) { return 0; } + uint64_t getSymbolAddress(const std::string &Name) override { return 0; } - void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj); + void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj) override; - bool finalizeMemory(std::string *ErrMsg); + bool finalizeMemory(std::string *ErrMsg) override; // For now, remote EH frame registration isn't supported. Remote symbol // resolution is a prerequisite to supporting remote EH frame registration. - void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {} - void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {} + void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, + size_t Size) override {} + void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, + size_t Size) override {} // This is a non-interface function used by lli void setRemoteTarget(RemoteTarget *T) { Target = T; } // The following obsolete JITMemoryManager calls are stubbed out for // this model. - void setMemoryWritable(); - void setMemoryExecutable(); - void setPoisonMemory(bool poison); - void AllocateGOT(); - uint8_t *getGOTBase() const; - uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize); + void setMemoryWritable() override; + void setMemoryExecutable() override; + void setPoisonMemory(bool poison) override; + void AllocateGOT() override; + uint8_t *getGOTBase() const override; + uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize) override; uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, - unsigned Alignment); + unsigned Alignment) override; void endFunctionBody(const Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd); - uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); - uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); - void deallocateFunctionBody(void *Body); + uint8_t *FunctionEnd) override; + uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) override; + uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) override; + void deallocateFunctionBody(void *Body) override; }; } // end namespace llvm diff --git a/tools/lli/RemoteTarget.cpp b/tools/lli/RemoteTarget.cpp index 5c74e6e..55fc064 100644 --- a/tools/lli/RemoteTarget.cpp +++ b/tools/lli/RemoteTarget.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "RemoteTarget.h" -#include "RemoteTargetExternal.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Memory.h" @@ -22,28 +21,6 @@ using namespace llvm; -// Static methods -RemoteTarget *RemoteTarget::createRemoteTarget() { - return new RemoteTarget; -} - -RemoteTarget *RemoteTarget::createExternalRemoteTarget(std::string &ChildName) { -#ifdef LLVM_ON_UNIX - return new RemoteTargetExternal(ChildName); -#else - return 0; -#endif -} - -bool RemoteTarget::hostSupportsExternalRemoteTarget() { -#ifdef LLVM_ON_UNIX - return true; -#else - return false; -#endif -} - - //////////////////////////////////////////////////////////////////////////////// // Simulated remote execution // @@ -56,34 +33,36 @@ bool RemoteTarget::allocateSpace(size_t Size, unsigned Alignment, sys::MemoryBlock *Prev = Allocations.size() ? &Allocations.back() : NULL; sys::MemoryBlock Mem = sys::Memory::AllocateRWX(Size, Prev, &ErrorMsg); if (Mem.base() == NULL) - return true; + return false; if ((uintptr_t)Mem.base() % Alignment) { ErrorMsg = "unable to allocate sufficiently aligned memory"; - return true; + return false; } Address = reinterpret_cast<uint64_t>(Mem.base()); - return false; + Allocations.push_back(Mem); + return true; } bool RemoteTarget::loadData(uint64_t Address, const void *Data, size_t Size) { memcpy ((void*)Address, Data, Size); - return false; + return true; } bool RemoteTarget::loadCode(uint64_t Address, const void *Data, size_t Size) { memcpy ((void*)Address, Data, Size); sys::MemoryBlock Mem((void*)Address, Size); sys::Memory::setExecutable(Mem, &ErrorMsg); - return false; + return true; } bool RemoteTarget::executeCode(uint64_t Address, int &RetVal) { int (*fn)(void) = (int(*)(void))Address; RetVal = fn(); - return false; + return true; } -void RemoteTarget::create() { +bool RemoteTarget::create() { + return true; } void RemoteTarget::stop() { diff --git a/tools/lli/RemoteTarget.h b/tools/lli/RemoteTarget.h index c95fbd1..73e8ae2 100644 --- a/tools/lli/RemoteTarget.h +++ b/tools/lli/RemoteTarget.h @@ -25,10 +25,13 @@ namespace llvm { class RemoteTarget { - std::string ErrorMsg; bool IsRunning; - SmallVector<sys::MemoryBlock, 16> Allocations; + typedef SmallVector<sys::MemoryBlock, 16> AllocMapType; + AllocMapType Allocations; + +protected: + std::string ErrorMsg; public: StringRef getErrorMsg() const { return ErrorMsg; } @@ -39,19 +42,31 @@ public: /// @param Alignment Required minimum alignment for allocated space. /// @param[out] Address Remote address of the allocated memory. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool allocateSpace(size_t Size, unsigned Alignment, uint64_t &Address); + bool isAllocatedMemory(uint64_t Address, uint32_t Size) { + uint64_t AddressEnd = Address + Size; + for (AllocMapType::const_iterator I = Allocations.begin(), + E = Allocations.end(); + I != E; ++I) { + if (Address >= (uint64_t)I->base() && + AddressEnd <= (uint64_t)I->base() + I->size()) + return true; + } + return false; + } + /// Load data into the target address space. /// /// @param Address Destination address in the target process. /// @param Data Source address in the host process. /// @param Size Number of bytes to copy. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool loadData(uint64_t Address, const void *Data, @@ -63,7 +78,7 @@ public: /// @param Data Source address in the host process. /// @param Size Number of bytes to copy. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool loadCode(uint64_t Address, const void *Data, @@ -76,12 +91,12 @@ public: /// process. /// @param[out] RetVal The integer return value of the called function. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool executeCode(uint64_t Address, int &RetVal); - /// Minimum alignment for memory permissions. Used to seperate code and + /// Minimum alignment for memory permissions. Used to separate code and /// data regions to make sure data doesn't get marked as code or vice /// versa. /// @@ -89,18 +104,13 @@ public: virtual unsigned getPageAlignment() { return 4096; } /// Start the remote process. - virtual void create(); + virtual bool create(); /// Terminate the remote process. virtual void stop(); - RemoteTarget() : ErrorMsg(""), IsRunning(false) {} + RemoteTarget() : IsRunning(false), ErrorMsg("") {} virtual ~RemoteTarget() { if (IsRunning) stop(); } - - // Create an instance of the system-specific remote target class. - static RemoteTarget *createRemoteTarget(); - static RemoteTarget *createExternalRemoteTarget(std::string &ChildName); - static bool hostSupportsExternalRemoteTarget(); private: // Main processing function for the remote target process. Command messages // are received on file descriptor CmdFD and responses come back on OutFD. diff --git a/tools/lli/RemoteTargetExternal.cpp b/tools/lli/RemoteTargetExternal.cpp index 742a948..c1bc8df 100644 --- a/tools/lli/RemoteTargetExternal.cpp +++ b/tools/lli/RemoteTargetExternal.cpp @@ -13,12 +13,12 @@ //===----------------------------------------------------------------------===// #include "llvm/Config/config.h" - #include "RemoteTarget.h" #include "RemoteTargetExternal.h" - #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/Support/Memory.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" @@ -28,135 +28,298 @@ using namespace llvm; bool RemoteTargetExternal::allocateSpace(size_t Size, unsigned Alignment, uint64_t &Address) { - SendAllocateSpace(Alignment, Size); - Receive(LLI_AllocationResult, Address); - return false; + DEBUG(dbgs() << "Message [allocate space] size: " << Size << + ", align: " << Alignment << "\n"); + if (!SendAllocateSpace(Alignment, Size)) { + ErrorMsg += ", (RemoteTargetExternal::allocateSpace)"; + return false; + } + if (!Receive(LLI_AllocationResult, Address)) { + ErrorMsg += ", (RemoteTargetExternal::allocateSpace)"; + return false; + } + if (Address == 0) { + ErrorMsg += "failed allocation, (RemoteTargetExternal::allocateSpace)"; + return false; + } + DEBUG(dbgs() << "Message [allocate space] addr: 0x" << + format("%llx", Address) << "\n"); + return true; } bool RemoteTargetExternal::loadData(uint64_t Address, const void *Data, size_t Size) { - SendLoadSection(Address, Data, (uint32_t)Size, false); - Receive(LLI_LoadComplete); - return false; + DEBUG(dbgs() << "Message [load data] addr: 0x" << format("%llx", Address) << + ", size: " << Size << "\n"); + if (!SendLoadSection(Address, Data, (uint32_t)Size, false)) { + ErrorMsg += ", (RemoteTargetExternal::loadData)"; + return false; + } + int Status = LLI_Status_Success; + if (!Receive(LLI_LoadResult, Status)) { + ErrorMsg += ", (RemoteTargetExternal::loadData)"; + return false; + } + if (Status == LLI_Status_IncompleteMsg) { + ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)"; + return false; + } + if (Status == LLI_Status_NotAllocated) { + ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)"; + return false; + } + DEBUG(dbgs() << "Message [load data] complete\n"); + return true; } bool RemoteTargetExternal::loadCode(uint64_t Address, const void *Data, size_t Size) { - SendLoadSection(Address, Data, (uint32_t)Size, true); - Receive(LLI_LoadComplete); - return false; + DEBUG(dbgs() << "Message [load code] addr: 0x" << format("%llx", Address) << + ", size: " << Size << "\n"); + if (!SendLoadSection(Address, Data, (uint32_t)Size, true)) { + ErrorMsg += ", (RemoteTargetExternal::loadCode)"; + return false; + } + int Status = LLI_Status_Success; + if (!Receive(LLI_LoadResult, Status)) { + ErrorMsg += ", (RemoteTargetExternal::loadCode)"; + return false; + } + if (Status == LLI_Status_IncompleteMsg) { + ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)"; + return false; + } + if (Status == LLI_Status_NotAllocated) { + ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)"; + return false; + } + DEBUG(dbgs() << "Message [load code] complete\n"); + return true; } -bool RemoteTargetExternal::executeCode(uint64_t Address, int &RetVal) { - SendExecute(Address); - - Receive(LLI_ExecutionResult, RetVal); - return false; +bool RemoteTargetExternal::executeCode(uint64_t Address, int32_t &RetVal) { + DEBUG(dbgs() << "Message [exectue code] addr: " << Address << "\n"); + if (!SendExecute(Address)) { + ErrorMsg += ", (RemoteTargetExternal::executeCode)"; + return false; + } + if (!Receive(LLI_ExecutionResult, RetVal)) { + ErrorMsg += ", (RemoteTargetExternal::executeCode)"; + return false; + } + DEBUG(dbgs() << "Message [exectue code] return: " << RetVal << "\n"); + return true; } void RemoteTargetExternal::stop() { SendTerminate(); - Wait(); + RPC.Wait(); } -void RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) { - int rc; - uint32_t MsgType = (uint32_t)LLI_AllocateSpace; - rc = WriteBytes(&MsgType, 4); - assert(rc == 4 && "Error writing message type."); +bool RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) { + if (!SendHeader(LLI_AllocateSpace)) { + ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)"; + return false; + } - uint32_t DataSize = 8; - rc = WriteBytes(&DataSize, 4); - assert(rc == 4 && "Error writing data size."); + AppendWrite((const void *)&Alignment, 4); + AppendWrite((const void *)&Size, 4); - rc = WriteBytes(&Alignment, 4); - assert(rc == 4 && "Error writing alignment data."); - - rc = WriteBytes(&Size, 4); - assert(rc == 4 && "Error writing size data."); + if (!SendPayload()) { + ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)"; + return false; + } + return true; } -void RemoteTargetExternal::SendLoadSection(uint64_t Addr, +bool RemoteTargetExternal::SendLoadSection(uint64_t Addr, const void *Data, uint32_t Size, bool IsCode) { - int rc; - uint32_t MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection; - rc = WriteBytes(&MsgType, 4); - assert(rc == 4 && "Error writing message type."); + LLIMessageType MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection; + if (!SendHeader(MsgType)) { + ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)"; + return false; + } + + AppendWrite((const void *)&Addr, 8); + AppendWrite(Data, Size); + + if (!SendPayload()) { + ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)"; + return false; + } + return true; +} - uint32_t DataSize = Size + 8; - rc = WriteBytes(&DataSize, 4); - assert(rc == 4 && "Error writing data size."); +bool RemoteTargetExternal::SendExecute(uint64_t Addr) { + if (!SendHeader(LLI_Execute)) { + ErrorMsg += ", (RemoteTargetExternal::SendExecute)"; + return false; + } - rc = WriteBytes(&Addr, 8); - assert(rc == 8 && "Error writing data."); + AppendWrite((const void *)&Addr, 8); - rc = WriteBytes(Data, Size); - assert(rc == (int)Size && "Error writing data."); + if (!SendPayload()) { + ErrorMsg += ", (RemoteTargetExternal::SendExecute)"; + return false; + } + return true; } -void RemoteTargetExternal::SendExecute(uint64_t Addr) { - int rc; - uint32_t MsgType = (uint32_t)LLI_Execute; - rc = WriteBytes(&MsgType, 4); - assert(rc == 4 && "Error writing message type."); - - uint32_t DataSize = 8; - rc = WriteBytes(&DataSize, 4); - assert(rc == 4 && "Error writing data size."); +bool RemoteTargetExternal::SendTerminate() { + return SendHeader(LLI_Terminate); + // No data or data size is sent with Terminate +} - rc = WriteBytes(&Addr, 8); - assert(rc == 8 && "Error writing data."); +bool RemoteTargetExternal::Receive(LLIMessageType Msg) { + if (!ReceiveHeader(Msg)) + return false; + int Unused; + AppendRead(&Unused, 0); + if (!ReceivePayload()) + return false; + ReceiveData.clear(); + Sizes.clear(); + return true; } -void RemoteTargetExternal::SendTerminate() { - int rc; - uint32_t MsgType = (uint32_t)LLI_Terminate; - rc = WriteBytes(&MsgType, 4); - assert(rc == 4 && "Error writing message type."); +bool RemoteTargetExternal::Receive(LLIMessageType Msg, int32_t &Data) { + if (!ReceiveHeader(Msg)) + return false; + AppendRead(&Data, 4); + if (!ReceivePayload()) + return false; + ReceiveData.clear(); + Sizes.clear(); + return true; +} - // No data or data size is sent with Terminate +bool RemoteTargetExternal::Receive(LLIMessageType Msg, uint64_t &Data) { + if (!ReceiveHeader(Msg)) + return false; + AppendRead(&Data, 8); + if (!ReceivePayload()) + return false; + ReceiveData.clear(); + Sizes.clear(); + return true; } +bool RemoteTargetExternal::ReceiveHeader(LLIMessageType ExpectedMsgType) { + assert(ReceiveData.empty() && Sizes.empty() && + "Payload vector not empty to receive header"); -void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType) { - int rc; + // Message header, with type to follow uint32_t MsgType; - rc = ReadBytes(&MsgType, 4); - assert(rc == 4 && "Error reading message type."); - assert(MsgType == (uint32_t)ExpectedMsgType && "Error: received unexpected message type."); + if (!ReadBytes(&MsgType, 4)) { + ErrorMsg += ", (RemoteTargetExternal::ReceiveHeader)"; + return false; + } + if (MsgType != (uint32_t)ExpectedMsgType) { + ErrorMsg = "received unexpected message type"; + ErrorMsg += ". Expecting: "; + ErrorMsg += ExpectedMsgType; + ErrorMsg += ", Got: "; + ErrorMsg += MsgType; + return false; + } + return true; +} + +bool RemoteTargetExternal::ReceivePayload() { + assert(!ReceiveData.empty() && + "Payload vector empty to receive"); + assert(ReceiveData.size() == Sizes.size() && + "Unexpected mismatch between data and size"); + uint32_t TotalSize = 0; + for (int I=0, E=Sizes.size(); I < E; I++) + TotalSize += Sizes[I]; + + // Payload size header uint32_t DataSize; - rc = ReadBytes(&DataSize, 4); - assert(rc == 4 && "Error reading data size."); - assert(DataSize == 0 && "Error: unexpected data size."); + if (!ReadBytes(&DataSize, 4)) { + ErrorMsg += ", invalid data size"; + return false; + } + if (DataSize != TotalSize) { + ErrorMsg = "unexpected data size"; + ErrorMsg += ". Expecting: "; + ErrorMsg += TotalSize; + ErrorMsg += ", Got: "; + ErrorMsg += DataSize; + return false; + } + if (DataSize == 0) + return true; + + // Payload itself + for (int I=0, E=Sizes.size(); I < E; I++) { + if (!ReadBytes(ReceiveData[I], Sizes[I])) { + ErrorMsg = "unexpected data while reading message"; + return false; + } + } + + return true; } -void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, int &Data) { - uint64_t Temp; - Receive(ExpectedMsgType, Temp); - Data = (int)(int64_t)Temp; +bool RemoteTargetExternal::SendHeader(LLIMessageType MsgType) { + assert(SendData.empty() && Sizes.empty() && + "Payload vector not empty to send header"); + + // Message header, with type to follow + if (!WriteBytes(&MsgType, 4)) { + ErrorMsg += ", (RemoteTargetExternal::SendHeader)"; + return false; + } + return true; } -void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, uint64_t &Data) { - int rc; - uint32_t MsgType; - rc = ReadBytes(&MsgType, 4); - assert(rc == 4 && "Error reading message type."); - assert(MsgType == (uint32_t)ExpectedMsgType && "Error: received unexpected message type."); +bool RemoteTargetExternal::SendPayload() { + assert(!SendData.empty() && !Sizes.empty() && + "Payload vector empty to send"); + assert(SendData.size() == Sizes.size() && + "Unexpected mismatch between data and size"); + + uint32_t TotalSize = 0; + for (int I=0, E=Sizes.size(); I < E; I++) + TotalSize += Sizes[I]; + + // Payload size header + if (!WriteBytes(&TotalSize, 4)) { + ErrorMsg += ", invalid data size"; + return false; + } + if (TotalSize == 0) + return true; + + // Payload itself + for (int I=0, E=Sizes.size(); I < E; I++) { + if (!WriteBytes(SendData[I], Sizes[I])) { + ErrorMsg = "unexpected data while writing message"; + return false; + } + } + + SendData.clear(); + Sizes.clear(); + return true; +} - uint32_t DataSize; - rc = ReadBytes(&DataSize, 4); - assert(rc == 4 && "Error reading data size."); - assert(DataSize == 8 && "Error: unexpected data size."); +void RemoteTargetExternal::AppendWrite(const void *Data, uint32_t Size) { + SendData.push_back(Data); + Sizes.push_back(Size); +} - rc = ReadBytes(&Data, 8); - assert(DataSize == 8 && "Error: unexpected data."); +void RemoteTargetExternal::AppendRead(void *Data, uint32_t Size) { + ReceiveData.push_back(Data); + Sizes.push_back(Size); } #ifdef LLVM_ON_UNIX -#include "Unix/RemoteTargetExternal.inc" +#include "Unix/RPCChannel.inc" #endif #ifdef LLVM_ON_WIN32 -#include "Windows/RemoteTargetExternal.inc" +#include "Windows/RPCChannel.inc" #endif diff --git a/tools/lli/RemoteTargetExternal.h b/tools/lli/RemoteTargetExternal.h index a4bfad2..f87fc61 100644 --- a/tools/lli/RemoteTargetExternal.h +++ b/tools/lli/RemoteTargetExternal.h @@ -15,21 +15,28 @@ #ifndef LLI_REMOTETARGETEXTERNAL_H #define LLI_REMOTETARGETEXTERNAL_H -#include "llvm/Config/config.h" - +#include "RPCChannel.h" +#include "RemoteTarget.h" +#include "RemoteTargetMessage.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Memory.h" #include <stdlib.h> #include <string> -#include "RemoteTarget.h" -#include "RemoteTargetMessage.h" - namespace llvm { class RemoteTargetExternal : public RemoteTarget { + RPCChannel RPC; + + bool WriteBytes(const void *Data, size_t Size) { + return RPC.WriteBytes(Data, Size); + } + + bool ReadBytes(void *Data, size_t Size) { return RPC.ReadBytes(Data, Size); } + public: /// Allocate space in the remote target address space. /// @@ -37,11 +44,10 @@ public: /// @param Alignment Required minimum alignment for allocated space. /// @param[out] Address Remote address of the allocated memory. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - virtual bool allocateSpace(size_t Size, - unsigned Alignment, - uint64_t &Address); + bool allocateSpace(size_t Size, unsigned Alignment, + uint64_t &Address) override; /// Load data into the target address space. /// @@ -49,9 +55,9 @@ public: /// @param Data Source address in the host process. /// @param Size Number of bytes to copy. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - virtual bool loadData(uint64_t Address, const void *Data, size_t Size); + bool loadData(uint64_t Address, const void *Data, size_t Size) override; /// Load code into the target address space and prepare it for execution. /// @@ -59,9 +65,9 @@ public: /// @param Data Source address in the host process. /// @param Size Number of bytes to copy. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - virtual bool loadCode(uint64_t Address, const void *Data, size_t Size); + bool loadCode(uint64_t Address, const void *Data, size_t Size) override; /// Execute code in the target process. The called function is required /// to be of signature int "(*)(void)". @@ -70,47 +76,66 @@ public: /// process. /// @param[out] RetVal The integer return value of the called function. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - virtual bool executeCode(uint64_t Address, int &RetVal); + bool executeCode(uint64_t Address, int &RetVal) override; - /// Minimum alignment for memory permissions. Used to seperate code and + /// Minimum alignment for memory permissions. Used to separate code and /// data regions to make sure data doesn't get marked as code or vice /// versa. /// /// @returns Page alignment return value. Default of 4k. - virtual unsigned getPageAlignment() { return 4096; } + unsigned getPageAlignment() override { return 4096; } + + bool create() override { + RPC.ChildName = ChildName; + if (!RPC.createServer()) + return true; - /// Start the remote process. - virtual void create(); + // We must get Ack from the client (blocking read) + if (!Receive(LLI_ChildActive)) { + ErrorMsg += ", (RPCChannel::create) - Stopping process!"; + stop(); + return false; + } + + return true; + } /// Terminate the remote process. - virtual void stop(); + void stop() override; RemoteTargetExternal(std::string &Name) : RemoteTarget(), ChildName(Name) {} - virtual ~RemoteTargetExternal(); + virtual ~RemoteTargetExternal() {} private: std::string ChildName; - // This will get filled in as a point to an OS-specific structure. - void *ConnectionData; - - void SendAllocateSpace(uint32_t Alignment, uint32_t Size); - void SendLoadSection(uint64_t Addr, + bool SendAllocateSpace(uint32_t Alignment, uint32_t Size); + bool SendLoadSection(uint64_t Addr, const void *Data, uint32_t Size, bool IsCode); - void SendExecute(uint64_t Addr); - void SendTerminate(); - - void Receive(LLIMessageType Msg); - void Receive(LLIMessageType Msg, int &Data); - void Receive(LLIMessageType Msg, uint64_t &Data); - - int WriteBytes(const void *Data, size_t Size); - int ReadBytes(void *Data, size_t Size); - void Wait(); + bool SendExecute(uint64_t Addr); + bool SendTerminate(); + + // High-level wrappers for receiving data + bool Receive(LLIMessageType Msg); + bool Receive(LLIMessageType Msg, int32_t &Data); + bool Receive(LLIMessageType Msg, uint64_t &Data); + + // Lower level target-independent read/write to deal with errors + bool ReceiveHeader(LLIMessageType Msg); + bool ReceivePayload(); + bool SendHeader(LLIMessageType Msg); + bool SendPayload(); + + // Functions to append/retrieve data from the payload + SmallVector<const void *, 2> SendData; + SmallVector<void *, 1> ReceiveData; // Future proof + SmallVector<int, 2> Sizes; + void AppendWrite(const void *Data, uint32_t Size); + void AppendRead(void *Data, uint32_t Size); }; } // end namespace llvm diff --git a/tools/lli/RemoteTargetMessage.h b/tools/lli/RemoteTargetMessage.h index 12cfa9a..cb934a1 100644 --- a/tools/lli/RemoteTargetMessage.h +++ b/tools/lli/RemoteTargetMessage.h @@ -26,20 +26,60 @@ namespace llvm { // only here for testing purposes and is therefore intended to be the simplest // implementation that will work. It is assumed that the parent and child // share characteristics like endianness. +// +// Quick description of the protocol: +// +// { Header + Payload Size + Payload } +// +// The protocol message consist of a header, the payload size (which can be +// zero), and the payload itself. The payload can contain any number of items, +// and the size has to be the sum of them all. Each end is responsible for +// reading/writing the correct number of items with the correct sizes. +// +// The current four known exchanges are: +// +// * Allocate Space: +// Parent: { LLI_AllocateSpace, 8, Alignment, Size } +// Child: { LLI_AllocationResult, 8, Address } +// +// * Load Data: +// Parent: { LLI_LoadDataSection, 8+Size, Address, Data } +// Child: { LLI_LoadComplete, 4, StatusCode } +// +// * Load Code: +// Parent: { LLI_LoadCodeSection, 8+Size, Address, Code } +// Child: { LLI_LoadComplete, 4, StatusCode } +// +// * Execute Code: +// Parent: { LLI_Execute, 8, Address } +// Child: { LLI_ExecutionResult, 4, Result } +// +// It is the responsibility of either side to check for correct headers, +// sizes and payloads, since any inconsistency would misalign the pipe, and +// result in data corruption. enum LLIMessageType { LLI_Error = -1, LLI_ChildActive = 0, // Data = not used - LLI_AllocateSpace, // Data = struct { uint_32t Align, uint_32t Size } - LLI_AllocationResult, // Data = uint64_t AllocAddress (in Child memory space) - LLI_LoadCodeSection, // Data = uint32_t Addr, followed by section contests - LLI_LoadDataSection, // Data = uint32_t Addr, followed by section contents - LLI_LoadComplete, // Data = not used - LLI_Execute, // Data = Address of function to execute - LLI_ExecutionResult, // Data = uint64_t Result + LLI_AllocateSpace, // Data = struct { uint32_t Align, uint_32t Size } + LLI_AllocationResult, // Data = uint64_t Address (child memory space) + + LLI_LoadCodeSection, // Data = uint64_t Address, void * SectionData + LLI_LoadDataSection, // Data = uint64_t Address, void * SectionData + LLI_LoadResult, // Data = uint32_t LLIMessageStatus + + LLI_Execute, // Data = uint64_t Address + LLI_ExecutionResult, // Data = uint32_t Result + LLI_Terminate // Data = not used }; +enum LLIMessageStatus { + LLI_Status_Success = 0, // Operation succeeded + LLI_Status_NotAllocated, // Address+Size not allocated in child space + LLI_Status_IncompleteMsg // Size received doesn't match request +}; + } // end namespace llvm #endif diff --git a/tools/lli/Unix/RemoteTargetExternal.inc b/tools/lli/Unix/RPCChannel.inc index 9c1a4cc..4d245d6 100644 --- a/tools/lli/Unix/RemoteTargetExternal.inc +++ b/tools/lli/Unix/RPCChannel.inc @@ -1,4 +1,4 @@ -//=- RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Unix --=// +//=- RPCChannel.inc - LLVM out-of-process JIT execution for Unix --=// // // The LLVM Compiler Infrastructure // @@ -7,15 +7,17 @@ // //===----------------------------------------------------------------------===// // -// Implementation of the Unix-specific parts of the RemoteTargetExternal class +// Implementation of the Unix-specific parts of the RPCChannel class // which executes JITed code in a separate process from where it was built. // //===----------------------------------------------------------------------===// -#include <unistd.h> +#include "llvm/Support/Errno.h" +#include "llvm/Support/raw_ostream.h" #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> +#include <unistd.h> namespace { @@ -30,7 +32,7 @@ struct ConnectionData_t { namespace llvm { -void RemoteTargetExternal::create() { +bool RPCChannel::createServer() { int PipeFD[2][2]; pid_t ChildPID; @@ -62,8 +64,7 @@ void RemoteTargetExternal::create() { int rc = execv(ChildName.c_str(), args); if (rc != 0) perror("Error executing child process: "); - } - else { + } else { // In the parent... // Close the child ends of the pipes @@ -71,25 +72,50 @@ void RemoteTargetExternal::create() { close(PipeFD[1][1]); // Store the parent ends of the pipes - ConnectionData = (void*)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]); - - Receive(LLI_ChildActive); + ConnectionData = (void *)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]); + return true; } + return false; } -int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) { - return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size); +bool RPCChannel::createClient() { + // Store the parent ends of the pipes + ConnectionData = (void *)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO); + return true; +} + +void RPCChannel::Wait() { wait(NULL); } + +static bool CheckError(int rc, size_t Size, const char *Desc) { + if (rc < 0) { + llvm::errs() << "IO Error: " << Desc << ": " << sys::StrError() << '\n'; + return false; + } else if ((size_t)rc != Size) { + std::string ErrorMsg; + char Number[10] = { 0 }; + ErrorMsg += "Expecting "; + sprintf(Number, "%d", (uint32_t)Size); + ErrorMsg += Number; + ErrorMsg += " bytes, Got "; + sprintf(Number, "%d", rc); + ErrorMsg += Number; + llvm::errs() << "RPC Error: " << Desc << ": " << ErrorMsg << '\n'; + return false; + } + return true; } -int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) { - return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size); +bool RPCChannel::WriteBytes(const void *Data, size_t Size) { + int rc = write(((ConnectionData_t *)ConnectionData)->OutputPipe, Data, Size); + return CheckError(rc, Size, "WriteBytes"); } -void RemoteTargetExternal::Wait() { - wait(NULL); +bool RPCChannel::ReadBytes(void *Data, size_t Size) { + int rc = read(((ConnectionData_t *)ConnectionData)->InputPipe, Data, Size); + return CheckError(rc, Size, "ReadBytes"); } -RemoteTargetExternal::~RemoteTargetExternal() { +RPCChannel::~RPCChannel() { delete static_cast<ConnectionData_t *>(ConnectionData); } diff --git a/tools/lli/Windows/RPCChannel.inc b/tools/lli/Windows/RPCChannel.inc new file mode 100644 index 0000000..82f2acb --- /dev/null +++ b/tools/lli/Windows/RPCChannel.inc @@ -0,0 +1,29 @@ +//=- RPCChannel.inc - LLVM out-of-process JIT execution for Windows --=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the Windows-specific parts of the RPCChannel class +// which executes JITed code in a separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +namespace llvm { + +bool RPCChannel::createServer() { return false; } + +bool RPCChannel::createClient() { return false; } + +bool RPCChannel::WriteBytes(const void *Data, size_t Size) { return false; } + +bool RPCChannel::ReadBytes(void *Data, size_t Size) { return false; } + +void RPCChannel::Wait() {} + +RPCChannel::~RPCChannel() {} + +} // namespace llvm diff --git a/tools/lli/Windows/RemoteTargetExternal.inc b/tools/lli/Windows/RemoteTargetExternal.inc deleted file mode 100644 index aef4627..0000000 --- a/tools/lli/Windows/RemoteTargetExternal.inc +++ /dev/null @@ -1,35 +0,0 @@ -//= RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Windows =// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Definition of the Windows-specific parts of the RemoteTargetExternal class -// which is meant to execute JITed code in a separate process from where it was -// built. To support this functionality on Windows, implement these functions. -// -//===----------------------------------------------------------------------===// - -namespace llvm { - -void RemoteTargetExternal::create() { -} - -int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) { - return 0; -} - -int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) { - return 0; -} - -void RemoteTargetExternal::Wait() { -} - -RemoteTargetExternal::~RemoteTargetExternal() { -} - -} // namespace llvm diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index f317566..c0c0f9d 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -17,6 +17,7 @@ #include "llvm/IR/LLVMContext.h" #include "RemoteMemoryManager.h" #include "RemoteTarget.h" +#include "RemoteTargetExternal.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" @@ -26,12 +27,15 @@ #include "llvm/ExecutionEngine/JITEventListener.h" #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/IR/TypeBuilder.h" #include "llvm/IRReader/IRReader.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/DynamicLibrary.h" @@ -91,12 +95,11 @@ namespace { // execution. The child process will be executed and will communicate with // lli via stdin/stdout pipes. cl::opt<std::string> - MCJITRemoteProcess("mcjit-remote-process", - cl::desc("Specify the filename of the process to launch " - "for remote MCJIT execution. If none is specified," - "\n\tremote execution will be simulated in-process."), - cl::value_desc("filename"), - cl::init("")); + ChildExecPath("mcjit-remote-process", + cl::desc("Specify the filename of the process to launch " + "for remote MCJIT execution. If none is specified," + "\n\tremote execution will be simulated in-process."), + cl::value_desc("filename"), cl::init("")); // Determine optimization level. cl::opt<char> @@ -138,6 +141,27 @@ namespace { cl::desc("Extra modules to be loaded"), cl::value_desc("input bitcode")); + cl::list<std::string> + ExtraObjects("extra-object", + cl::desc("Extra object files to be loaded"), + cl::value_desc("input object")); + + cl::list<std::string> + ExtraArchives("extra-archive", + cl::desc("Extra archive files to be loaded"), + cl::value_desc("input archive")); + + cl::opt<bool> + EnableCacheManager("enable-cache-manager", + cl::desc("Use cache manager to save/load mdoules"), + cl::init(false)); + + cl::opt<std::string> + ObjectCacheDir("object-cache-dir", + cl::desc("Directory to store cached object files " + "(must be user writable)"), + cl::init("")); + cl::opt<std::string> FakeArgv0("fake-argv0", cl::desc("Override the 'argv[0]' value passed into the executing" @@ -219,12 +243,91 @@ namespace { cl::init(false)); } +//===----------------------------------------------------------------------===// +// Object cache +// +// This object cache implementation writes cached objects to disk to the +// directory specified by CacheDir, using a filename provided in the module +// descriptor. The cache tries to load a saved object using that path if the +// file exists. CacheDir defaults to "", in which case objects are cached +// alongside their originating bitcodes. +// +class LLIObjectCache : public ObjectCache { +public: + LLIObjectCache(const std::string& CacheDir) : CacheDir(CacheDir) { + // Add trailing '/' to cache dir if necessary. + if (!this->CacheDir.empty() && + this->CacheDir[this->CacheDir.size() - 1] != '/') + this->CacheDir += '/'; + } + virtual ~LLIObjectCache() {} + + void notifyObjectCompiled(const Module *M, const MemoryBuffer *Obj) override { + const std::string ModuleID = M->getModuleIdentifier(); + std::string CacheName; + if (!getCacheFilename(ModuleID, CacheName)) + return; + std::string errStr; + if (!CacheDir.empty()) { // Create user-defined cache dir. + SmallString<128> dir(CacheName); + sys::path::remove_filename(dir); + sys::fs::create_directories(Twine(dir)); + } + raw_fd_ostream outfile(CacheName.c_str(), errStr, sys::fs::F_None); + outfile.write(Obj->getBufferStart(), Obj->getBufferSize()); + outfile.close(); + } + + MemoryBuffer* getObject(const Module* M) override { + const std::string ModuleID = M->getModuleIdentifier(); + std::string CacheName; + if (!getCacheFilename(ModuleID, CacheName)) + return NULL; + // Load the object from the cache filename + std::unique_ptr<MemoryBuffer> IRObjectBuffer; + MemoryBuffer::getFile(CacheName.c_str(), IRObjectBuffer, -1, false); + // If the file isn't there, that's OK. + if (!IRObjectBuffer) + return NULL; + // MCJIT will want to write into this buffer, and we don't want that + // because the file has probably just been mmapped. Instead we make + // a copy. The filed-based buffer will be released when it goes + // out of scope. + return MemoryBuffer::getMemBufferCopy(IRObjectBuffer->getBuffer()); + } + +private: + std::string CacheDir; + + bool getCacheFilename(const std::string &ModID, std::string &CacheName) { + std::string Prefix("file:"); + size_t PrefixLength = Prefix.length(); + if (ModID.substr(0, PrefixLength) != Prefix) + return false; + std::string CacheSubdir = ModID.substr(PrefixLength); +#if defined(_WIN32) + // Transform "X:\foo" => "/X\foo" for convenience. + if (isalpha(CacheSubdir[0]) && CacheSubdir[1] == ':') { + CacheSubdir[1] = CacheSubdir[0]; + CacheSubdir[0] = '/'; + } +#endif + CacheName = CacheDir + CacheSubdir; + size_t pos = CacheName.rfind('.'); + CacheName.replace(pos, CacheName.length() - pos, ".o"); + return true; + } +}; + static ExecutionEngine *EE = 0; +static LLIObjectCache *CacheManager = 0; static void do_shutdown() { // Cygwin-1.5 invokes DLL's dtors before atexit handler. #ifndef DO_NOTHING_ATEXIT delete EE; + if (CacheManager) + delete CacheManager; llvm_shutdown(); #endif } @@ -300,12 +403,20 @@ int main(int argc, char **argv, char * const *envp) { return 1; } + if (EnableCacheManager) { + if (UseMCJIT) { + std::string CacheName("file:"); + CacheName.append(InputFile); + Mod->setModuleIdentifier(CacheName); + } else + errs() << "warning: -enable-cache-manager can only be used with MCJIT."; + } + // If not jitting lazily, load the whole bitcode file eagerly too. - std::string ErrorMsg; if (NoLazyCompilation) { - if (Mod->MaterializeAllPermanently(&ErrorMsg)) { + if (error_code EC = Mod->materializeAllPermanently()) { errs() << argv[0] << ": bitcode didn't read correctly.\n"; - errs() << "Reason: " << ErrorMsg << "\n"; + errs() << "Reason: " << EC.message() << "\n"; exit(1); } } @@ -321,6 +432,7 @@ int main(int argc, char **argv, char * const *envp) { DebugIRPass->runOnModule(*Mod); } + std::string ErrorMsg; EngineBuilder builder(Mod); builder.setMArch(MArch); builder.setMCPU(MCPU); @@ -391,6 +503,11 @@ int main(int argc, char **argv, char * const *envp) { exit(1); } + if (EnableCacheManager) { + CacheManager = new LLIObjectCache(ObjectCacheDir); + EE->setObjectCache(CacheManager); + } + // Load any additional modules specified on the command line. for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) { Module *XMod = ParseIRFile(ExtraModules[i], Err, Context); @@ -398,9 +515,43 @@ int main(int argc, char **argv, char * const *envp) { Err.print(argv[0], errs()); return 1; } + if (EnableCacheManager) { + if (UseMCJIT) { + std::string CacheName("file:"); + CacheName.append(ExtraModules[i]); + XMod->setModuleIdentifier(CacheName); + } + // else, we already printed a warning above. + } EE->addModule(XMod); } + for (unsigned i = 0, e = ExtraObjects.size(); i != e; ++i) { + ErrorOr<object::ObjectFile *> Obj = + object::ObjectFile::createObjectFile(ExtraObjects[i]); + if (!Obj) { + Err.print(argv[0], errs()); + return 1; + } + EE->addObjectFile(Obj.get()); + } + + for (unsigned i = 0, e = ExtraArchives.size(); i != e; ++i) { + std::unique_ptr<MemoryBuffer> ArBuf; + error_code ec; + ec = MemoryBuffer::getFileOrSTDIN(ExtraArchives[i], ArBuf); + if (ec) { + Err.print(argv[0], errs()); + return 1; + } + object::Archive *Ar = new object::Archive(ArBuf.release(), ec); + if (ec || !Ar) { + Err.print(argv[0], errs()); + return 1; + } + EE->addArchive(Ar); + } + // If the target is Cygwin/MingW and we are generating remote code, we // need an extra module to help out with linking. if (RemoteMCJIT && Triple(Mod->getTargetTriple()).isOSCygMing()) { @@ -472,7 +623,7 @@ int main(int argc, char **argv, char * const *envp) { } } - // Trigger compilation separately so code regions that need to be + // Trigger compilation separately so code regions that need to be // invalidated will be known. (void)EE->getPointerToFunction(EntryFn); // Clear instruction cache before code will be executed. @@ -511,30 +662,35 @@ int main(int argc, char **argv, char * const *envp) { // address space, assign the section addresses to resolve any relocations, // and send it to the target. - OwningPtr<RemoteTarget> Target; - if (!MCJITRemoteProcess.empty()) { // Remote execution on a child process - if (!RemoteTarget::hostSupportsExternalRemoteTarget()) { - errs() << "Warning: host does not support external remote targets.\n" - << " Defaulting to simulated remote execution\n"; - Target.reset(RemoteTarget::createRemoteTarget()); - } else { - std::string ChildEXE = sys::FindProgramByName(MCJITRemoteProcess); - if (ChildEXE == "") { - errs() << "Unable to find child target: '\''" << MCJITRemoteProcess << "\'\n"; - return -1; - } - Target.reset(RemoteTarget::createExternalRemoteTarget(ChildEXE)); + std::unique_ptr<RemoteTarget> Target; + if (!ChildExecPath.empty()) { // Remote execution on a child process +#ifndef LLVM_ON_UNIX + // FIXME: Remove this pointless fallback mode which causes tests to "pass" + // on platforms where they should XFAIL. + errs() << "Warning: host does not support external remote targets.\n" + << " Defaulting to simulated remote execution\n"; + Target.reset(new RemoteTarget); +#else + if (!sys::fs::can_execute(ChildExecPath)) { + errs() << "Unable to find usable child executable: '" << ChildExecPath + << "'\n"; + return -1; } + Target.reset(new RemoteTargetExternal(ChildExecPath)); +#endif } else { // No child process name provided, use simulated remote execution. - Target.reset(RemoteTarget::createRemoteTarget()); + Target.reset(new RemoteTarget); } // Give the memory manager a pointer to our remote target interface object. MM->setRemoteTarget(Target.get()); // Create the remote target. - Target->create(); + if (!Target->create()) { + errs() << "ERROR: " << Target->getErrorMsg() << "\n"; + return EXIT_FAILURE; + } // Since we're executing in a (at least simulated) remote address space, // we can't use the ExecutionEngine::runFunctionAsMain(). We have to @@ -551,7 +707,7 @@ int main(int argc, char **argv, char * const *envp) { DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x" << format("%llx", Entry) << "\n"); - if (Target->executeCode(Entry, Result)) + if (!Target->executeCode(Entry, Result)) errs() << "ERROR: " << Target->getErrorMsg() << "\n"; // Like static constructors, the remote target MCJIT support doesn't handle diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index f15a1e2..9295efe 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -1,4 +1,7 @@ -set(LLVM_LINK_COMPONENTS support object bitreader) +set(LLVM_LINK_COMPONENTS + Object + Support + ) add_llvm_tool(llvm-ar llvm-ar.cpp @@ -12,10 +15,10 @@ if(UNIX) set(llvm_ar_binary "llvm-ar${CMAKE_EXECUTABLE_SUFFIX}") else() set(LLVM_LINK_OR_COPY copy) - set(llvm_ar_binary "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/llvm-ar${CMAKE_EXECUTABLE_SUFFIX}") + set(llvm_ar_binary "${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ar${CMAKE_EXECUTABLE_SUFFIX}") endif() -set(llvm_ranlib "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/llvm-ranlib${CMAKE_EXECUTABLE_SUFFIX}") +set(llvm_ranlib "${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ranlib${CMAKE_EXECUTABLE_SUFFIX}") add_custom_command(TARGET llvm-ar POST_BUILD COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${llvm_ar_binary}" "${llvm_ranlib}") diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index d70db72..047f54e 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -322,7 +322,7 @@ static void doExtract(StringRef Name, object::Archive::child_iterator I) { int FD; failIfError( - sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_Binary, Mode), + sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_None, Mode), Storage.c_str()); { @@ -365,8 +365,8 @@ static bool shouldCreateArchive(ArchiveOperation Op) { static void performReadOperation(ArchiveOperation Operation, object::Archive *OldArchive) { - for (object::Archive::child_iterator I = OldArchive->begin_children(), - E = OldArchive->end_children(); + for (object::Archive::child_iterator I = OldArchive->child_begin(), + E = OldArchive->child_end(); I != E; ++I) { StringRef Name; failIfError(I->getName(Name)); @@ -395,17 +395,25 @@ namespace { class NewArchiveIterator { bool IsNewMember; StringRef Name; + object::Archive::child_iterator OldI; + std::string NewFilename; + mutable int NewFD; + mutable sys::fs::file_status NewStatus; public: NewArchiveIterator(object::Archive::child_iterator I, StringRef Name); NewArchiveIterator(std::string *I, StringRef Name); NewArchiveIterator(); bool isNewMember() const; + StringRef getName() const; + object::Archive::child_iterator getOld() const; + const char *getNew() const; - StringRef getName() const; + int getFD() const; + const sys::fs::file_status &getStatus() const; }; } @@ -416,7 +424,7 @@ NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, : IsNewMember(false), Name(Name), OldI(I) {} NewArchiveIterator::NewArchiveIterator(std::string *NewFilename, StringRef Name) - : IsNewMember(true), Name(Name), NewFilename(*NewFilename) {} + : IsNewMember(true), Name(Name), NewFilename(*NewFilename), NewFD(-1) {} StringRef NewArchiveIterator::getName() const { return Name; } @@ -432,6 +440,31 @@ const char *NewArchiveIterator::getNew() const { return NewFilename.c_str(); } +int NewArchiveIterator::getFD() const { + assert(IsNewMember); + if (NewFD != -1) + return NewFD; + failIfError(sys::fs::openFileForRead(NewFilename, NewFD), NewFilename); + assert(NewFD != -1); + + failIfError(sys::fs::status(NewFD, NewStatus), NewFilename); + + // Opening a directory doesn't make sense. Let it fail. + // Linux cannot open directories with open(2), although + // cygwin and *bsd can. + if (NewStatus.type() == sys::fs::file_type::directory_file) + failIfError(error_code(errc::is_a_directory, posix_category()), + NewFilename); + + return NewFD; +} + +const sys::fs::file_status &NewArchiveIterator::getStatus() const { + assert(IsNewMember); + assert(NewFD != -1 && "Must call getFD first"); + return NewStatus; +} + template <typename T> void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name, int Pos = -1) { @@ -442,16 +475,6 @@ void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name, Members[Pos] = NI; } -namespace { -class HasName { - StringRef Name; - -public: - HasName(StringRef Name) : Name(Name) {} - bool operator()(StringRef Path) { return Name == sys::path::filename(Path); } -}; -} - enum InsertAction { IA_AddOldMember, IA_AddNewMeber, @@ -467,8 +490,9 @@ computeInsertAction(ArchiveOperation Operation, if (Operation == QuickAppend || Members.empty()) return IA_AddOldMember; - std::vector<std::string>::iterator MI = - std::find_if(Members.begin(), Members.end(), HasName(Name)); + std::vector<std::string>::iterator MI = std::find_if( + Members.begin(), Members.end(), + [Name](StringRef Path) { return Name == sys::path::filename(Path); }); if (MI == Members.end()) return IA_AddOldMember; @@ -516,8 +540,8 @@ computeNewArchiveMembers(ArchiveOperation Operation, int InsertPos = -1; StringRef PosName = sys::path::filename(RelPos); if (OldArchive) { - for (object::Archive::child_iterator I = OldArchive->begin_children(), - E = OldArchive->end_children(); + for (object::Archive::child_iterator I = OldArchive->child_begin(), + E = OldArchive->child_end(); I != E; ++I) { int Pos = Ret.size(); StringRef Name; @@ -578,14 +602,21 @@ computeNewArchiveMembers(ArchiveOperation Operation, } template <typename T> -static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { +static void printWithSpacePadding(raw_fd_ostream &OS, T Data, unsigned Size, + bool MayTruncate = false) { uint64_t OldPos = OS.tell(); OS << Data; unsigned SizeSoFar = OS.tell() - OldPos; - assert(Size >= SizeSoFar && "Data doesn't fit in Size"); - unsigned Remaining = Size - SizeSoFar; - for (unsigned I = 0; I < Remaining; ++I) - OS << ' '; + if (Size > SizeSoFar) { + unsigned Remaining = Size - SizeSoFar; + for (unsigned I = 0; I < Remaining; ++I) + OS << ' '; + } else if (Size < SizeSoFar) { + assert(MayTruncate && "Data doesn't fit in Size"); + // Some of the data this is used for (like UID) can be larger than the + // space available in the archive format. Truncate in that case. + OS.seek(OldPos + Size); + } } static void print32BE(raw_fd_ostream &Out, unsigned Val) { @@ -600,8 +631,8 @@ static void printRestOfMemberHeader(raw_fd_ostream &Out, unsigned GID, unsigned Perms, unsigned Size) { printWithSpacePadding(Out, ModTime.toEpochTime(), 12); - printWithSpacePadding(Out, UID, 6); - printWithSpacePadding(Out, GID, 6); + printWithSpacePadding(Out, UID, 6, true); + printWithSpacePadding(Out, GID, 6, true); printWithSpacePadding(Out, format("%o", Perms), 8); printWithSpacePadding(Out, Size, 10); Out << "`\n"; @@ -652,32 +683,26 @@ static void writeStringTable(raw_fd_ostream &Out, static void writeSymbolTable( raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, + ArrayRef<MemoryBuffer *> Buffers, std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; - std::vector<StringRef> SymNames; - std::vector<object::ObjectFile *> DeleteIt; + std::string NameBuf; + raw_string_ostream NameOS(NameBuf); + unsigned NumSyms = 0; + std::vector<object::SymbolicFile *> DeleteIt; + LLVMContext &Context = getGlobalContext(); for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I, ++MemberNum) { - object::ObjectFile *Obj; - if (I->isNewMember()) { - const char *Filename = I->getNew(); - Obj = object::ObjectFile::createObjectFile(Filename); - } else { - object::Archive::child_iterator OldMember = I->getOld(); - OwningPtr<object::Binary> Binary; - error_code EC = OldMember->getAsBinary(Binary); - if (EC) { // FIXME: check only for "not an object file" errors. - Obj = NULL; - } else { - Obj = dyn_cast<object::ObjectFile>(Binary.get()); - if (Obj) - Binary.take(); - } - } - if (!Obj) - continue; + MemoryBuffer *MemberBuffer = Buffers[MemberNum]; + ErrorOr<object::SymbolicFile *> ObjOrErr = + object::SymbolicFile::createSymbolicFile( + MemberBuffer, false, sys::fs::file_magic::unknown, &Context); + if (!ObjOrErr) + continue; // FIXME: check only for "not an object file" errors. + object::SymbolicFile *Obj = ObjOrErr.get(); + DeleteIt.push_back(Obj); if (!StartOffset) { printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); @@ -685,36 +710,29 @@ static void writeSymbolTable( print32BE(Out, 0); } - error_code Err; - for (object::symbol_iterator I = Obj->begin_symbols(), - E = Obj->end_symbols(); - I != E; I.increment(Err), failIfError(Err)) { - uint32_t Symflags; - failIfError(I->getFlags(Symflags)); + for (object::basic_symbol_iterator I = Obj->symbol_begin(), + E = Obj->symbol_end(); + I != E; ++I) { + uint32_t Symflags = I->getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; - StringRef Name; - failIfError(I->getName(Name)); - SymNames.push_back(Name); + failIfError(I->printName(NameOS)); + NameOS << '\0'; + ++NumSyms; MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); print32BE(Out, 0); } } - for (std::vector<StringRef>::iterator I = SymNames.begin(), - E = SymNames.end(); - I != E; ++I) { - Out << *I; - Out << '\0'; - } + Out << NameOS.str(); - for (std::vector<object::ObjectFile *>::iterator I = DeleteIt.begin(), - E = DeleteIt.end(); + for (std::vector<object::SymbolicFile *>::iterator I = DeleteIt.begin(), + E = DeleteIt.end(); I != E; ++I) { - object::ObjectFile *O = *I; + object::SymbolicFile *O = *I; delete O; } @@ -728,7 +746,7 @@ static void writeSymbolTable( Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(StartOffset); - print32BE(Out, SymNames.size()); + print32BE(Out, NumSyms); Out.seek(Pos); } @@ -748,8 +766,30 @@ static void performWriteOperation(ArchiveOperation Operation, std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs; + std::vector<MemoryBuffer *> MemberBuffers; + MemberBuffers.resize(NewMembers.size()); + + for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { + std::unique_ptr<MemoryBuffer> MemberBuffer; + NewArchiveIterator &Member = NewMembers[I]; + + if (Member.isNewMember()) { + const char *Filename = Member.getNew(); + int FD = Member.getFD(); + const sys::fs::file_status &Status = Member.getStatus(); + failIfError(MemoryBuffer::getOpenFile(FD, Filename, MemberBuffer, + Status.getSize(), false), + Filename); + + } else { + object::Archive::child_iterator OldMember = Member.getOld(); + failIfError(OldMember->getMemoryBuffer(MemberBuffer)); + } + MemberBuffers[I] = MemberBuffer.release(); + } + if (Symtab) { - writeSymbolTable(Out, NewMembers, MemberOffsetRefs); + writeSymbolTable(Out, NewMembers, MemberBuffers, MemberOffsetRefs); } std::vector<unsigned> StringMapIndexes; @@ -773,26 +813,10 @@ static void performWriteOperation(ArchiveOperation Operation, } Out.seek(Pos); + const MemoryBuffer *File = MemberBuffers[MemberNum]; if (I->isNewMember()) { const char *FileName = I->getNew(); - - int FD; - failIfError(sys::fs::openFileForRead(FileName, FD), FileName); - - sys::fs::file_status Status; - failIfError(sys::fs::status(FD, Status), FileName); - - // Opening a directory doesn't make sense. Let it failed. - // Linux cannot open directories with open(2), although - // cygwin and *bsd can. - if (Status.type() == sys::fs::file_type::directory_file) - failIfError(error_code(errc::is_a_directory, posix_category()), - FileName); - - OwningPtr<MemoryBuffer> File; - failIfError(MemoryBuffer::getOpenFile(FD, FileName, File, - Status.getSize(), false), - FileName); + const sys::fs::file_status &Status = I->getStatus(); StringRef Name = sys::path::filename(FileName); if (Name.size() < 16) @@ -804,7 +828,6 @@ static void performWriteOperation(ArchiveOperation Operation, Status.getLastModificationTime(), Status.getUser(), Status.getGroup(), Status.permissions(), Status.getSize()); - Out << File->getBuffer(); } else { object::Archive::child_iterator OldMember = I->getOld(); StringRef Name = I->getName(); @@ -818,12 +841,18 @@ static void performWriteOperation(ArchiveOperation Operation, OldMember->getLastModified(), OldMember->getUID(), OldMember->getGID(), OldMember->getAccessMode(), OldMember->getSize()); - Out << OldMember->getBuffer(); } + Out << File->getBuffer(); + if (Out.tell() % 2) Out << '\n'; } + + for (unsigned I = 0, N = MemberBuffers.size(); I < N; ++I) { + delete MemberBuffers[I]; + } + Output.keep(); Out.close(); sys::fs::rename(TemporaryOutput, ArchiveName); @@ -909,7 +938,7 @@ int ar_main(char **argv) { static int performOperation(ArchiveOperation Operation) { // Create or open the archive object. - OwningPtr<MemoryBuffer> Buf; + std::unique_ptr<MemoryBuffer> Buf; error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); if (EC && EC != llvm::errc::no_such_file_or_directory) { errs() << ToolName << ": error opening '" << ArchiveName @@ -918,7 +947,7 @@ static int performOperation(ArchiveOperation Operation) { } if (!EC) { - object::Archive Archive(Buf.take(), EC); + object::Archive Archive(Buf.release(), EC); if (EC) { errs() << ToolName << ": error loading '" << ArchiveName diff --git a/tools/llvm-as/CMakeLists.txt b/tools/llvm-as/CMakeLists.txt index d5620e7..1b2789a 100644 --- a/tools/llvm-as/CMakeLists.txt +++ b/tools/llvm-as/CMakeLists.txt @@ -1,4 +1,9 @@ -set(LLVM_LINK_COMPONENTS asmparser bitwriter) +set(LLVM_LINK_COMPONENTS + AsmParser + BitWriter + Core + Support + ) add_llvm_tool(llvm-as llvm-as.cpp diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp index b2e44ef..7583b12 100644 --- a/tools/llvm-as/llvm-as.cpp +++ b/tools/llvm-as/llvm-as.cpp @@ -16,10 +16,10 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Assembly/Parser.h" +#include "llvm/AsmParser/Parser.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" @@ -69,8 +69,8 @@ static void WriteOutputFile(const Module *M) { } std::string ErrorInfo; - OwningPtr<tool_output_file> Out(new tool_output_file( - OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary)); + std::unique_ptr<tool_output_file> Out( + new tool_output_file(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; exit(1); @@ -93,18 +93,19 @@ int main(int argc, char **argv) { // Parse the file now... SMDiagnostic Err; - OwningPtr<Module> M(ParseAssemblyFile(InputFilename, Err, Context)); + std::unique_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context)); if (M.get() == 0) { Err.print(argv[0], errs()); return 1; } if (!DisableVerify) { - std::string Err; - if (verifyModule(*M.get(), ReturnStatusAction, &Err)) { + std::string ErrorStr; + raw_string_ostream OS(ErrorStr); + if (verifyModule(*M.get(), &OS)) { errs() << argv[0] << ": assembly parsed, but does not verify as correct!\n"; - errs() << Err; + errs() << OS.str(); return 1; } } diff --git a/tools/llvm-bcanalyzer/CMakeLists.txt b/tools/llvm-bcanalyzer/CMakeLists.txt index 0151ea9..369f469 100644 --- a/tools/llvm-bcanalyzer/CMakeLists.txt +++ b/tools/llvm-bcanalyzer/CMakeLists.txt @@ -1,4 +1,7 @@ -set(LLVM_LINK_COMPONENTS bitreader) +set(LLVM_LINK_COMPONENTS + BitReader + Support + ) add_llvm_tool(llvm-bcanalyzer llvm-bcanalyzer.cpp diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index da40da2..9e17783 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -27,11 +27,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/OwningPtr.h" -#include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Verifier.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" @@ -479,7 +478,7 @@ static void PrintSize(uint64_t Bits) { /// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename. static int AnalyzeBitcode() { // Read the input file. - OwningPtr<MemoryBuffer> MemBuf; + std::unique_ptr<MemoryBuffer> MemBuf; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, MemBuf)) diff --git a/tools/llvm-c-test/CMakeLists.txt b/tools/llvm-c-test/CMakeLists.txt index 2926d9d..34fea3d 100644 --- a/tools/llvm-c-test/CMakeLists.txt +++ b/tools/llvm-c-test/CMakeLists.txt @@ -1,7 +1,14 @@ -set(LLVM_LINK_COMPONENTS all) +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + BitReader + Core + MCDisassembler + Object + Target + ) if (LLVM_COMPILER_IS_GCC_COMPATIBLE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wstrict-prototypes") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wstrict-prototypes") endif () add_llvm_tool(llvm-c-test diff --git a/tools/llvm-config/BuildVariables.inc.in b/tools/llvm-config/BuildVariables.inc.in index fe87afb..2ec019b 100644 --- a/tools/llvm-config/BuildVariables.inc.in +++ b/tools/llvm-config/BuildVariables.inc.in @@ -11,8 +11,8 @@ // llvm-config wants to report to the user, but which can only be determined at // build time. // -// The non .in variant of this file has been autogenerated by the LLVM build. Do -// not edit! +// The variant of this file not ending with .in has been autogenerated by the +// LLVM build. Do not edit! // //===----------------------------------------------------------------------===// diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index c651833..6f29a82 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -4,7 +4,7 @@ set(BUILDVARIABLES_SRCPATH ${CMAKE_CURRENT_SOURCE_DIR}/BuildVariables.inc.in) set(BUILDVARIABLES_OBJPATH ${CMAKE_CURRENT_BINARY_DIR}/BuildVariables.inc) # Compute the substitution values for various items. -get_system_libs(LLVM_SYSTEM_LIBS_LIST) +get_property(LLVM_SYSTEM_LIBS_LIST TARGET LLVMSupport PROPERTY LLVM_SYSTEM_LIBS) foreach(l ${LLVM_SYSTEM_LIBS_LIST}) set(SYSTEM_LIBS ${SYSTEM_LIBS} "-l${l}") endforeach() @@ -22,6 +22,9 @@ set(LLVM_SYSTEM_LIBS ${SYSTEM_LIBS}) string(REPLACE ";" " " LLVM_TARGETS_BUILT "${LLVM_TARGETS_TO_BUILD}") configure_file(${BUILDVARIABLES_SRCPATH} ${BUILDVARIABLES_OBJPATH} @ONLY) +# Set build-time environment(s). +add_definitions(-DCMAKE_CFG_INTDIR="${CMAKE_CFG_INTDIR}") + # Add the llvm-config tool. add_llvm_tool(llvm-config llvm-config.cpp diff --git a/tools/llvm-config/Makefile b/tools/llvm-config/Makefile index b20b6bf..b78551e 100644 --- a/tools/llvm-config/Makefile +++ b/tools/llvm-config/Makefile @@ -30,6 +30,14 @@ SUB_CPPFLAGS := ${CPP.BaseFlags} SUB_CFLAGS := ${CPP.BaseFlags} ${C.Flags} SUB_CXXFLAGS := ${CPP.BaseFlags} ${CXX.Flags} +# Override LIBS with TARGET's LIBS for cross compilation. +# FIXME: Host's llvm-config is not generated. It's for target's. +ifneq ($(TARGET_LIBS), ) + LLVM_SYSTEM_LIBS := $(TARGET_LIBS) +else + LLVM_SYSTEM_LIBS := $(LIBS) +endif + # This is blank for now. We need to be careful about adding stuff here: # LDFLAGS tend not to be portable, and we don't currently require the # user to use libtool when linking against LLVM. @@ -51,7 +59,7 @@ $(ObjDir)/BuildVariables.inc: $(BUILDVARIABLES_SRCPATH) Makefile $(ObjDir)/.dir >> temp.sed $(Verb) $(ECHO) 's/@LLVM_BUILDMODE@/$(subst /,\/,$(BuildMode))/' \ >> temp.sed - $(Verb) $(ECHO) 's/@LLVM_SYSTEM_LIBS@/$(subst /,\/,$(LIBS))/' \ + $(Verb) $(ECHO) 's/@LLVM_SYSTEM_LIBS@/$(subst /,\/,$(LLVM_SYSTEM_LIBS))/' \ >> temp.sed $(Verb) $(ECHO) 's/@LLVM_TARGETS_BUILT@/$(subst /,\/,$(TARGETS_TO_BUILD))/' \ >> temp.sed diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp index 3924e2e..ed1c8c3 100644 --- a/tools/llvm-config/llvm-config.cpp +++ b/tools/llvm-config/llvm-config.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/config.h" #include "llvm/Config/llvm-config.h" @@ -147,6 +148,7 @@ Options:\n\ --cflags C compiler flags for files that include LLVM headers.\n\ --cxxflags C++ compiler flags for files that include LLVM headers.\n\ --ldflags Print Linker flags.\n\ + --system-libs System Libraries needed to link against LLVM components.\n\ --libs Libraries needed to link against LLVM components.\n\ --libnames Bare library names for in-tree builds.\n\ --libfiles Fully qualified library filenames for makefile depends.\n\ @@ -154,6 +156,7 @@ Options:\n\ --targets-built List of all targets currently built.\n\ --host-target Target triple used to configure LLVM.\n\ --build-mode Print build mode of LLVM tree (e.g. Debug or Release).\n\ + --assertion-mode Print assertion mode of LLVM tree (ON or OFF).\n\ Typical components:\n\ all All LLVM libraries (default).\n\ engine Either a native JIT or a bitcode interpreter.\n"; @@ -171,6 +174,7 @@ std::string GetExecutablePath(const char *Argv0) { int main(int argc, char **argv) { std::vector<StringRef> Components; bool PrintLibs = false, PrintLibNames = false, PrintLibFiles = false; + bool PrintSystemLibs = false; bool HasAnyOption = false; // llvm-config is designed to support being run both from a development tree @@ -183,6 +187,13 @@ int main(int argc, char **argv) { std::string CurrentExecPrefix; std::string ActiveObjRoot; + // If CMAKE_CFG_INTDIR is given, honor it as build mode. + char const *build_mode = LLVM_BUILDMODE; +#if defined(CMAKE_CFG_INTDIR) + if (!(CMAKE_CFG_INTDIR[0] == '.' && CMAKE_CFG_INTDIR[1] == '\0')) + build_mode = CMAKE_CFG_INTDIR; +#endif + // Create an absolute path, and pop up one directory (we expect to be inside a // bin dir). sys::fs::make_absolute(CurrentPath); @@ -192,7 +203,7 @@ int main(int argc, char **argv) { // Check to see if we are inside a development tree by comparing to possible // locations (prefix style or CMake style). if (sys::fs::equivalent(CurrentExecPrefix, - Twine(LLVM_OBJ_ROOT) + "/" + LLVM_BUILDMODE)) { + Twine(LLVM_OBJ_ROOT) + "/" + build_mode)) { IsInDevelopmentTree = true; DevelopmentTreeLayout = MakefileStyle; @@ -230,16 +241,18 @@ int main(int argc, char **argv) { // layout. switch (DevelopmentTreeLayout) { case MakefileStyle: - ActiveBinDir = ActiveObjRoot + "/" + LLVM_BUILDMODE + "/bin"; - ActiveLibDir = ActiveObjRoot + "/" + LLVM_BUILDMODE + "/lib"; + ActivePrefix = ActiveObjRoot; + ActiveBinDir = ActiveObjRoot + "/" + build_mode + "/bin"; + ActiveLibDir = ActiveObjRoot + "/" + build_mode + "/lib"; break; case CMakeStyle: ActiveBinDir = ActiveObjRoot + "/bin"; ActiveLibDir = ActiveObjRoot + "/lib"; break; case CMakeBuildModeStyle: - ActiveBinDir = ActiveObjRoot + "/bin/" + LLVM_BUILDMODE; - ActiveLibDir = ActiveObjRoot + "/lib/" + LLVM_BUILDMODE; + ActivePrefix = ActiveObjRoot; + ActiveBinDir = ActiveObjRoot + "/bin/" + build_mode; + ActiveLibDir = ActiveObjRoot + "/lib/" + build_mode; break; } @@ -277,8 +290,9 @@ int main(int argc, char **argv) { } else if (Arg == "--cxxflags") { OS << ActiveIncludeOption << ' ' << LLVM_CXXFLAGS << '\n'; } else if (Arg == "--ldflags") { - OS << "-L" << ActiveLibDir << ' ' << LLVM_LDFLAGS - << ' ' << LLVM_SYSTEM_LIBS << '\n'; + OS << "-L" << ActiveLibDir << ' ' << LLVM_LDFLAGS << '\n'; + } else if (Arg == "--system-libs") { + PrintSystemLibs = true; } else if (Arg == "--libs") { PrintLibs = true; } else if (Arg == "--libnames") { @@ -298,11 +312,17 @@ int main(int argc, char **argv) { } else if (Arg == "--targets-built") { OS << LLVM_TARGETS_BUILT << '\n'; } else if (Arg == "--host-target") { - OS << LLVM_DEFAULT_TARGET_TRIPLE << '\n'; + OS << Triple::normalize(LLVM_DEFAULT_TARGET_TRIPLE) << '\n'; } else if (Arg == "--build-mode") { - OS << LLVM_BUILDMODE << '\n'; + OS << build_mode << '\n'; + } else if (Arg == "--assertion-mode") { +#if defined(NDEBUG) + OS << "OFF\n"; +#else + OS << "ON\n"; +#endif } else if (Arg == "--obj-root") { - OS << LLVM_OBJ_ROOT << '\n'; + OS << ActivePrefix << '\n'; } else if (Arg == "--src-root") { OS << LLVM_SRC_ROOT << '\n'; } else { @@ -316,7 +336,7 @@ int main(int argc, char **argv) { if (!HasAnyOption) usage(); - if (PrintLibs || PrintLibNames || PrintLibFiles) { + if (PrintLibs || PrintLibNames || PrintLibFiles || PrintSystemLibs) { // If no components were specified, default to "all". if (Components.empty()) Components.push_back("all"); @@ -326,27 +346,34 @@ int main(int argc, char **argv) { ComputeLibsForComponents(Components, RequiredLibs, /*IncludeNonInstalled=*/IsInDevelopmentTree); - for (unsigned i = 0, e = RequiredLibs.size(); i != e; ++i) { - StringRef Lib = RequiredLibs[i]; - if (i) - OS << ' '; - - if (PrintLibNames) { - OS << Lib; - } else if (PrintLibFiles) { - OS << ActiveLibDir << '/' << Lib; - } else if (PrintLibs) { - // If this is a typical library name, include it using -l. - if (Lib.startswith("lib") && Lib.endswith(".a")) { - OS << "-l" << Lib.slice(3, Lib.size()-2); - continue; - } + if (PrintLibs || PrintLibNames || PrintLibFiles) { + for (unsigned i = 0, e = RequiredLibs.size(); i != e; ++i) { + StringRef Lib = RequiredLibs[i]; + if (i) + OS << ' '; - // Otherwise, print the full path. - OS << ActiveLibDir << '/' << Lib; + if (PrintLibNames) { + OS << Lib; + } else if (PrintLibFiles) { + OS << ActiveLibDir << '/' << Lib; + } else if (PrintLibs) { + // If this is a typical library name, include it using -l. + if (Lib.startswith("lib") && Lib.endswith(".a")) { + OS << "-l" << Lib.slice(3, Lib.size()-2); + continue; + } + + // Otherwise, print the full path. + OS << ActiveLibDir << '/' << Lib; + } } + OS << '\n'; } - OS << '\n'; + + // Print SYSTEM_LIBS after --libs. + // FIXME: Each LLVM component may have its dependent system libs. + if (PrintSystemLibs) + OS << LLVM_SYSTEM_LIBS << '\n'; } else if (!Components.empty()) { errs() << "llvm-config: error: components given, but unused\n\n"; usage(); diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp index 5f6999e..587ee11 100644 --- a/tools/llvm-cov/llvm-cov.cpp +++ b/tools/llvm-cov/llvm-cov.cpp @@ -1,4 +1,4 @@ -//===- tools/llvm-cov/llvm-cov.cpp - LLVM coverage tool -------------------===// +//===- llvm-cov.cpp - LLVM coverage tool ----------------------------------===// // // The LLVM Compiler Infrastructure // @@ -11,29 +11,61 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/GCOV.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryObject.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" #include "llvm/Support/system_error.h" using namespace llvm; -static cl::opt<bool> -DumpGCOV("dump", cl::init(false), cl::desc("dump gcov file")); +static cl::opt<std::string> SourceFile(cl::Positional, cl::Required, + cl::desc("SOURCEFILE")); -static cl::opt<std::string> -InputGCNO("gcno", cl::desc("<input gcno file>"), cl::init("")); +static cl::opt<bool> AllBlocks("a", cl::init(false), + cl::desc("Display all basic blocks")); +static cl::alias AllBlocksA("all-blocks", cl::aliasopt(AllBlocks)); -static cl::opt<std::string> -InputGCDA("gcda", cl::desc("<input gcda file>"), cl::init("")); +static cl::opt<bool> BranchProb("b", cl::init(false), + cl::desc("Display branch probabilities")); +static cl::alias BranchProbA("branch-probabilities", cl::aliasopt(BranchProb)); + +static cl::opt<bool> BranchCount("c", cl::init(false), + cl::desc("Display branch counts instead " + "of percentages (requires -b)")); +static cl::alias BranchCountA("branch-counts", cl::aliasopt(BranchCount)); + +static cl::opt<bool> FuncSummary("f", cl::init(false), + cl::desc("Show coverage for each function")); +static cl::alias FuncSummaryA("function-summaries", cl::aliasopt(FuncSummary)); static cl::opt<std::string> -OutputFile("o", cl::desc("<output llvm-cov file>"), cl::init("-")); +ObjectDir("o", cl::value_desc("DIR|FILE"), cl::init(""), + cl::desc("Find objects in DIR or based on FILE's path")); +static cl::alias ObjectDirA("object-directory", cl::aliasopt(ObjectDir)); +static cl::alias ObjectDirB("object-file", cl::aliasopt(ObjectDir)); + +static cl::opt<bool> PreservePaths("p", cl::init(false), + cl::desc("Preserve path components")); +static cl::alias PreservePathsA("preserve-paths", cl::aliasopt(PreservePaths)); +static cl::opt<bool> UncondBranch("u", cl::init(false), + cl::desc("Display unconditional branch info " + "(requires -b)")); +static cl::alias UncondBranchA("unconditional-branches", + cl::aliasopt(UncondBranch)); + +static cl::OptionCategory DebugCat("Internal and debugging options"); +static cl::opt<bool> DumpGCOV("dump", cl::init(false), cl::cat(DebugCat), + cl::desc("Dump the gcov file to stderr")); +static cl::opt<std::string> InputGCNO("gcno", cl::cat(DebugCat), cl::init(""), + cl::desc("Override inferred gcno file")); +static cl::opt<std::string> InputGCDA("gcda", cl::cat(DebugCat), cl::init(""), + cl::desc("Override inferred gcda file")); //===----------------------------------------------------------------------===// int main(int argc, char **argv) { @@ -42,47 +74,61 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - cl::ParseCommandLineOptions(argc, argv, "llvm coverage tool\n"); + cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); - std::string ErrorInfo; - raw_fd_ostream OS(OutputFile.c_str(), ErrorInfo); - if (!ErrorInfo.empty()) - errs() << ErrorInfo << "\n"; + SmallString<128> CoverageFileStem(ObjectDir); + if (CoverageFileStem.empty()) { + // If no directory was specified with -o, look next to the source file. + CoverageFileStem = sys::path::parent_path(SourceFile); + sys::path::append(CoverageFileStem, sys::path::stem(SourceFile)); + } else if (sys::fs::is_directory(ObjectDir)) + // A directory name was given. Use it and the source file name. + sys::path::append(CoverageFileStem, sys::path::stem(SourceFile)); + else + // A file was given. Ignore the source file and look next to this file. + sys::path::replace_extension(CoverageFileStem, ""); - GCOVFile GF; if (InputGCNO.empty()) - errs() << " " << argv[0] << ": No gcov input file!\n"; + InputGCNO = (CoverageFileStem.str() + ".gcno").str(); + if (InputGCDA.empty()) + InputGCDA = (CoverageFileStem.str() + ".gcda").str(); - OwningPtr<MemoryBuffer> GCNO_Buff; + GCOVFile GF; + + std::unique_ptr<MemoryBuffer> GCNO_Buff; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCNO, GCNO_Buff)) { errs() << InputGCNO << ": " << ec.message() << "\n"; return 1; } GCOVBuffer GCNO_GB(GCNO_Buff.get()); - if (!GF.read(GCNO_GB)) { + if (!GF.readGCNO(GCNO_GB)) { errs() << "Invalid .gcno File!\n"; return 1; } - if (!InputGCDA.empty()) { - OwningPtr<MemoryBuffer> GCDA_Buff; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCDA, GCDA_Buff)) { + std::unique_ptr<MemoryBuffer> GCDA_Buff; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCDA, GCDA_Buff)) { + if (ec != errc::no_such_file_or_directory) { errs() << InputGCDA << ": " << ec.message() << "\n"; return 1; } + // Clear the filename to make it clear we didn't read anything. + InputGCDA = "-"; + } else { GCOVBuffer GCDA_GB(GCDA_Buff.get()); - if (!GF.read(GCDA_GB)) { + if (!GF.readGCDA(GCDA_GB)) { errs() << "Invalid .gcda File!\n"; return 1; } } - if (DumpGCOV) GF.dump(); - FileInfo FI; + GCOVOptions Options(AllBlocks, BranchProb, BranchCount, FuncSummary, + PreservePaths, UncondBranch); + FileInfo FI(Options); GF.collectLineCounts(FI); - FI.print(OS, InputGCNO, InputGCDA); + FI.print(InputGCNO, InputGCDA); return 0; } diff --git a/tools/llvm-diff/CMakeLists.txt b/tools/llvm-diff/CMakeLists.txt index 0df8b9e..4407a86 100644 --- a/tools/llvm-diff/CMakeLists.txt +++ b/tools/llvm-diff/CMakeLists.txt @@ -1,4 +1,8 @@ -set(LLVM_LINK_COMPONENTS support asmparser bitreader irreader) +set(LLVM_LINK_COMPONENTS + Core + IRReader + Support + ) add_llvm_tool(llvm-diff llvm-diff.cpp diff --git a/tools/llvm-diff/DiffConsumer.h b/tools/llvm-diff/DiffConsumer.h index 6c2209f..ac13a5e 100644 --- a/tools/llvm-diff/DiffConsumer.h +++ b/tools/llvm-diff/DiffConsumer.h @@ -79,11 +79,11 @@ namespace llvm { : out(errs()), Differences(false), Indent(0) {} bool hadDifferences() const; - void enterContext(Value *L, Value *R); - void exitContext(); - void log(StringRef text); - void logf(const LogBuilder &Log); - void logd(const DiffLogBuilder &Log); + void enterContext(Value *L, Value *R) override; + void exitContext() override; + void log(StringRef text) override; + void logf(const LogBuilder &Log) override; + void logd(const DiffLogBuilder &Log) override; }; } diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp index 768b94b..7d379ef 100644 --- a/tools/llvm-diff/DifferenceEngine.cpp +++ b/tools/llvm-diff/DifferenceEngine.cpp @@ -18,12 +18,12 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" -#include "llvm/Support/CFG.h" -#include "llvm/Support/CallSite.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/type_traits.h" diff --git a/tools/llvm-dis/CMakeLists.txt b/tools/llvm-dis/CMakeLists.txt index 9f12ecb..06ac051 100644 --- a/tools/llvm-dis/CMakeLists.txt +++ b/tools/llvm-dis/CMakeLists.txt @@ -1,4 +1,8 @@ -set(LLVM_LINK_COMPONENTS bitreader analysis) +set(LLVM_LINK_COMPONENTS + BitReader + Core + Support + ) add_llvm_tool(llvm-dis llvm-dis.cpp diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index 87eb347..c6f0dcf 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -17,9 +17,9 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" -#include "llvm/Assembly/AssemblyAnnotationWriter.h" #include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/DebugInfo.h" +#include "llvm/IR/AssemblyAnnotationWriter.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" @@ -66,11 +66,11 @@ static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) { class CommentWriter : public AssemblyAnnotationWriter { public: void emitFunctionAnnot(const Function *F, - formatted_raw_ostream &OS) { + formatted_raw_ostream &OS) override { OS << "; [#uses=" << F->getNumUses() << ']'; // Output # uses OS << '\n'; } - void printInfoComment(const Value &V, formatted_raw_ostream &OS) { + void printInfoComment(const Value &V, formatted_raw_ostream &OS) override { bool Padded = false; if (!V.getType()->isVoidTy()) { OS.PadToColumn(50); @@ -123,7 +123,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n"); std::string ErrorMessage; - OwningPtr<Module> M; + std::unique_ptr<Module> M; // Use the bitcode streaming interface DataStreamer *streamer = getDataFileStreamer(InputFilename, &ErrorMessage); @@ -135,8 +135,11 @@ int main(int argc, char **argv) { DisplayFilename = InputFilename; M.reset(getStreamedBitcodeModule(DisplayFilename, streamer, Context, &ErrorMessage)); - if(M.get() != 0 && M->MaterializeAllPermanently(&ErrorMessage)) { - M.reset(); + if(M.get() != 0) { + if (error_code EC = M->materializeAllPermanently()) { + ErrorMessage = EC.message(); + M.reset(); + } } } @@ -168,14 +171,14 @@ int main(int argc, char **argv) { } std::string ErrorInfo; - OwningPtr<tool_output_file> Out(new tool_output_file( - OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary)); + std::unique_ptr<tool_output_file> Out( + new tool_output_file(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; } - OwningPtr<AssemblyAnnotationWriter> Annotator; + std::unique_ptr<AssemblyAnnotationWriter> Annotator; if (ShowAnnotations) Annotator.reset(new CommentWriter()); diff --git a/tools/llvm-dwarfdump/CMakeLists.txt b/tools/llvm-dwarfdump/CMakeLists.txt index 05aad3f..288b323 100644 --- a/tools/llvm-dwarfdump/CMakeLists.txt +++ b/tools/llvm-dwarfdump/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS DebugInfo Object + Support ) add_llvm_tool(llvm-dwarfdump diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index 413a50b..f4a9ae8 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/DebugInfo/DIContext.h" @@ -63,8 +62,11 @@ DumpType("debug-dump", cl::init(DIDT_All), clEnumValN(DIDT_Info, "info", ".debug_info"), clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"), clEnumValN(DIDT_Types, "types", ".debug_types"), + clEnumValN(DIDT_TypesDwo, "types.dwo", ".debug_types.dwo"), clEnumValN(DIDT_Line, "line", ".debug_line"), + clEnumValN(DIDT_LineDwo, "line.dwo", ".debug_line.dwo"), clEnumValN(DIDT_Loc, "loc", ".debug_loc"), + clEnumValN(DIDT_LocDwo, "loc.dwo", ".debug_loc.dwo"), clEnumValN(DIDT_Frames, "frames", ".debug_frame"), clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"), clEnumValN(DIDT_Pubnames, "pubnames", ".debug_pubnames"), @@ -85,20 +87,21 @@ static void PrintDILineInfo(DILineInfo dli) { } static void DumpInput(const StringRef &Filename) { - OwningPtr<MemoryBuffer> Buff; + std::unique_ptr<MemoryBuffer> Buff; if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { errs() << Filename << ": " << ec.message() << "\n"; return; } - OwningPtr<ObjectFile> Obj(ObjectFile::createObjectFile(Buff.take())); - if (!Obj) { - errs() << Filename << ": Unknown object file format\n"; + ErrorOr<ObjectFile*> ObjOrErr(ObjectFile::createObjectFile(Buff.release())); + if (error_code EC = ObjOrErr.getError()) { + errs() << Filename << ": " << EC.message() << '\n'; return; } + std::unique_ptr<ObjectFile> Obj(ObjOrErr.get()); - OwningPtr<DIContext> DICtx(DIContext::getDWARFContext(Obj.get())); + std::unique_ptr<DIContext> DICtx(DIContext::getDWARFContext(Obj.get())); if (Address == -1ULL) { outs() << Filename diff --git a/tools/llvm-extract/CMakeLists.txt b/tools/llvm-extract/CMakeLists.txt index 3163c4b..c984f01 100644 --- a/tools/llvm-extract/CMakeLists.txt +++ b/tools/llvm-extract/CMakeLists.txt @@ -1,4 +1,10 @@ -set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter irreader) +set(LLVM_LINK_COMPONENTS + BitWriter + Core + IPO + IRReader + Support + ) add_llvm_tool(llvm-extract llvm-extract.cpp diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index dc1a410..2e5a2af 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -12,12 +12,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/LLVMContext.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Assembly/PrintModulePass.h" -#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/PassManager.h" @@ -100,7 +100,7 @@ int main(int argc, char **argv) { // Use lazy loading, since we only care about selected global values. SMDiagnostic Err; - OwningPtr<Module> M; + std::unique_ptr<Module> M; M.reset(getLazyIRFileModule(InputFilename, Err, Context)); if (M.get() == 0) { @@ -254,7 +254,7 @@ int main(int argc, char **argv) { // In addition to deleting all other functions, we also want to spiff it // up a little bit. Do this now. PassManager Passes; - Passes.add(new DataLayout(M.get())); // Use correct DataLayout + Passes.add(new DataLayoutPass(M.get())); // Use correct DataLayout std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end()); @@ -265,14 +265,14 @@ int main(int argc, char **argv) { Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls std::string ErrorInfo; - tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary); + tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; } if (OutputAssembly) - Passes.add(createPrintModulePass(&Out.os())); + Passes.add(createPrintModulePass(Out.os())); else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true)) Passes.add(createBitcodeWriterPass(Out.os())); diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp index dbaf075..c159aa5 100644 --- a/tools/llvm-jitlistener/llvm-jitlistener.cpp +++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp @@ -15,7 +15,6 @@ #include "llvm/IR/LLVMContext.h" #include "../../lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Triple.h" #include "llvm/ExecutionEngine/JITEventListener.h" #include "llvm/ExecutionEngine/JITMemoryManager.h" @@ -139,8 +138,8 @@ protected: if (Tuple.getTriple().empty()) Tuple.setTriple(sys::getProcessTriple()); - if (Tuple.isOSWindows() && Triple::ELF != Tuple.getEnvironment()) { - Tuple.setEnvironment(Triple::ELF); + if (Tuple.isOSWindows() && !Tuple.isOSBinFormatELF()) { + Tuple.setObjectFormat(Triple::ELF); TheModule->setTargetTriple(Tuple.getTriple()); } @@ -163,16 +162,15 @@ protected: LLVMContext Context; // Global ownership Module *TheModule; // Owned by ExecutionEngine. JITMemoryManager *JMM; // Owned by ExecutionEngine. - OwningPtr<ExecutionEngine> TheJIT; + std::unique_ptr<ExecutionEngine> TheJIT; public: void ProcessInput(const std::string &Filename) { InitEE(Filename); - llvm::OwningPtr<llvm::JITEventListener> Listener(JITEventListener::createIntelJITEventListener( - new IntelJITEventsWrapper(NotifyEvent, 0, - IsProfilingActive, 0, 0, - GetNewMethodID))); + std::unique_ptr<llvm::JITEventListener> Listener( + JITEventListener::createIntelJITEventListener(new IntelJITEventsWrapper( + NotifyEvent, 0, IsProfilingActive, 0, 0, GetNewMethodID))); TheJIT->RegisterJITEventListener(Listener.get()); diff --git a/tools/llvm-link/Android.mk b/tools/llvm-link/Android.mk index db8f2af..cbcd0af 100644 --- a/tools/llvm-link/Android.mk +++ b/tools/llvm-link/Android.mk @@ -34,6 +34,7 @@ include $(BUILD_HOST_EXECUTABLE) # llvm-link command line tool (target) #===---------------------------------------------------------------=== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) LOCAL_MODULE := llvm-link @@ -42,7 +43,8 @@ LOCAL_SRC_FILES := $(llvm_link_SRC_FILES) LOCAL_STATIC_LIBRARIES := $(llvm_link_STATIC_LIBRARIES) LOCAL_SHARED_LIBRARIES := \ libcutils \ - libstlport + libc++ include $(LLVM_DEVICE_BUILD_MK) include $(BUILD_EXECUTABLE) +endif diff --git a/tools/llvm-link/CMakeLists.txt b/tools/llvm-link/CMakeLists.txt index 4df5356..d4f5be7 100644 --- a/tools/llvm-link/CMakeLists.txt +++ b/tools/llvm-link/CMakeLists.txt @@ -1,4 +1,10 @@ -set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser irreader) +set(LLVM_LINK_COMPONENTS + BitWriter + Core + IRReader + Linker + Support + ) add_llvm_tool(llvm-link llvm-link.cpp diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index 99cca23..1f0e224 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Linker.h" -#include "llvm/Analysis/Verifier.h" +#include "llvm/Linker/Linker.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" @@ -50,6 +50,10 @@ Verbose("v", cl::desc("Print information about actions taken")); static cl::opt<bool> DumpAsm("d", cl::desc("Print assembly as linked"), cl::Hidden); +static cl::opt<bool> +SuppressWarnings("suppress-warnings", cl::desc("Suppress all linking warnings"), + cl::init(false)); + // LoadFile - Read the specified bitcode file in and return it. This routine // searches the link path for the specified file to try to find it... // @@ -78,17 +82,17 @@ int main(int argc, char **argv) { unsigned BaseArg = 0; std::string ErrorMessage; - OwningPtr<Module> Composite(LoadFile(argv[0], - InputFilenames[BaseArg], Context)); + std::unique_ptr<Module> Composite( + LoadFile(argv[0], InputFilenames[BaseArg], Context)); if (Composite.get() == 0) { errs() << argv[0] << ": error loading file '" << InputFilenames[BaseArg] << "'\n"; return 1; } - Linker L(Composite.get()); + Linker L(Composite.get(), SuppressWarnings); for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) { - OwningPtr<Module> M(LoadFile(argv[0], InputFilenames[i], Context)); + std::unique_ptr<Module> M(LoadFile(argv[0], InputFilenames[i], Context)); if (M.get() == 0) { errs() << argv[0] << ": error loading file '" <<InputFilenames[i]<< "'\n"; return 1; @@ -106,7 +110,7 @@ int main(int argc, char **argv) { if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite; std::string ErrorInfo; - tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary); + tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; diff --git a/tools/llvm-lto/CMakeLists.txt b/tools/llvm-lto/CMakeLists.txt index 348976c..485b03d 100644 --- a/tools/llvm-lto/CMakeLists.txt +++ b/tools/llvm-lto/CMakeLists.txt @@ -1,4 +1,10 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} lto support) +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + Core + LTO + MC + Support + ) add_llvm_tool(llvm-lto llvm-lto.cpp diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp index 0fc68ae..ec3f0fa 100644 --- a/tools/llvm-lto/llvm-lto.cpp +++ b/tools/llvm-lto/llvm-lto.cpp @@ -20,8 +20,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -77,26 +77,7 @@ int main(int argc, char **argv) { InitializeAllAsmParsers(); // set up the TargetOptions for the machine - TargetOptions Options; - Options.LessPreciseFPMADOption = EnableFPMAD; - Options.NoFramePointerElim = DisableFPElim; - Options.AllowFPOpFusion = FuseFPOps; - Options.UnsafeFPMath = EnableUnsafeFPMath; - Options.NoInfsFPMath = EnableNoInfsFPMath; - Options.NoNaNsFPMath = EnableNoNaNsFPMath; - Options.HonorSignDependentRoundingFPMathOption = - EnableHonorSignDependentRoundingFPMath; - Options.UseSoftFloat = GenerateSoftFloatCalls; - if (FloatABIForCalls != FloatABI::Default) - Options.FloatABIType = FloatABIForCalls; - Options.NoZerosInBSS = DontPlaceZerosInBSS; - Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; - Options.DisableTailCalls = DisableTailCalls; - Options.StackAlignmentOverride = OverrideStackAlignment; - Options.TrapFuncName = TrapFuncName; - Options.PositionIndependentExecutable = EnablePIE; - Options.EnableSegmentedStacks = SegmentedStacks; - Options.UseInitArray = UseInitArray; + TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); unsigned BaseArg = 0; @@ -114,8 +95,8 @@ int main(int argc, char **argv) { for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) { std::string error; - OwningPtr<LTOModule> Module(LTOModule::makeLTOModule(InputFilenames[i].c_str(), - Options, error)); + std::unique_ptr<LTOModule> Module( + LTOModule::makeLTOModule(InputFilenames[i].c_str(), Options, error)); if (!error.empty()) { errs() << argv[0] << ": error loading file '" << InputFilenames[i] << "': " << error << "\n"; @@ -161,7 +142,7 @@ int main(int argc, char **argv) { } raw_fd_ostream FileStream(OutputFilename.c_str(), ErrorInfo, - sys::fs::F_Binary); + sys::fs::F_None); if (!ErrorInfo.empty()) { errs() << argv[0] << ": error opening the file '" << OutputFilename << "': " << ErrorInfo << "\n"; diff --git a/tools/llvm-mc/CMakeLists.txt b/tools/llvm-mc/CMakeLists.txt index 805caf4..6f8e9e5 100644 --- a/tools/llvm-mc/CMakeLists.txt +++ b/tools/llvm-mc/CMakeLists.txt @@ -1,4 +1,9 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC MCParser MCDisassembler) +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + MC + MCParser + Support + ) add_llvm_tool(llvm-mc llvm-mc.cpp diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp index 81a0045..9c402f2 100644 --- a/tools/llvm-mc/Disassembler.cpp +++ b/tools/llvm-mc/Disassembler.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "Disassembler.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" @@ -36,10 +35,10 @@ private: public: VectorMemoryObject(const ByteArrayTy &bytes) : Bytes(bytes) {} - uint64_t getBase() const { return 0; } - uint64_t getExtent() const { return Bytes.size(); } + uint64_t getBase() const override { return 0; } + uint64_t getExtent() const override { return Bytes.size(); } - int readByte(uint64_t Addr, uint8_t *Byte) const { + int readByte(uint64_t Addr, uint8_t *Byte) const override { if (Addr >= getExtent()) return -1; *Byte = Bytes[Addr].first; @@ -51,7 +50,8 @@ public: static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes, SourceMgr &SM, raw_ostream &Out, - MCStreamer &Streamer, bool InAtomicBlock) { + MCStreamer &Streamer, bool InAtomicBlock, + const MCSubtargetInfo &STI) { // Wrap the vector in a MemoryObject. VectorMemoryObject memoryObject(Bytes); @@ -86,7 +86,7 @@ static bool PrintInsts(const MCDisassembler &DisAsm, // Fall through case MCDisassembler::Success: - Streamer.EmitInstruction(Inst); + Streamer.EmitInstruction(Inst, STI); break; } } @@ -158,7 +158,7 @@ int Disassembler::disassemble(const Target &T, MemoryBuffer &Buffer, SourceMgr &SM, raw_ostream &Out) { - OwningPtr<const MCDisassembler> DisAsm(T.createMCDisassembler(STI)); + std::unique_ptr<const MCDisassembler> DisAsm(T.createMCDisassembler(STI)); if (!DisAsm) { errs() << "error: no disassembler for target " << Triple << "\n"; return -1; @@ -202,7 +202,7 @@ int Disassembler::disassemble(const Target &T, if (!ByteArray.empty()) ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer, - InAtomicBlock); + InAtomicBlock, STI); } if (InAtomicBlock) { diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index 7ec2bba..61fd2c4 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "Disassembler.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" @@ -27,6 +26,7 @@ #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetAsmParser.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" @@ -51,6 +51,9 @@ static cl::opt<bool> ShowEncoding("show-encoding", cl::desc("Show instruction encodings")); static cl::opt<bool> +CompressDebugSections("compress-debug-sections", cl::desc("Compress DWARF debug sections")); + +static cl::opt<bool> ShowInst("show-inst", cl::desc("Show internal instruction representation")); static cl::opt<bool> @@ -65,9 +68,6 @@ static cl::opt<bool> RelaxAll("mc-relax-all", cl::desc("Relax all fixups")); static cl::opt<bool> -DisableCFI("disable-cfi", cl::desc("Do not use .cfi_* directives")); - -static cl::opt<bool> NoExecStack("mc-no-exec-stack", cl::desc("File doesn't need an exec stack")); enum OutputFileType { @@ -211,7 +211,7 @@ static tool_output_file *GetOutputStream() { std::string Err; tool_output_file *Out = - new tool_output_file(OutputFilename.c_str(), Err, sys::fs::F_Binary); + new tool_output_file(OutputFilename.c_str(), Err, sys::fs::F_None); if (!Err.empty()) { errs() << Err << '\n'; delete Out; @@ -317,12 +317,12 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, tool_output_file *Out) return Error; } -static int AssembleInput(const char *ProgName, const Target *TheTarget, +static int AssembleInput(const char *ProgName, const Target *TheTarget, SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str, MCAsmInfo &MAI, MCSubtargetInfo &STI, MCInstrInfo &MCII) { - OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, - Str, MAI)); - OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(STI, *Parser, MCII)); + std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, Str, MAI)); + std::unique_ptr<MCTargetAsmParser> TAP( + TheTarget->createMCAsmParser(STI, *Parser, MCII)); if (!TAP) { errs() << ProgName << ": error: this target does not support assembly parsing.\n"; @@ -363,12 +363,12 @@ int main(int argc, char **argv) { if (!TheTarget) return 1; - OwningPtr<MemoryBuffer> BufferPtr; + std::unique_ptr<MemoryBuffer> BufferPtr; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) { errs() << ProgName << ": " << ec.message() << '\n'; return 1; } - MemoryBuffer *Buffer = BufferPtr.take(); + MemoryBuffer *Buffer = BufferPtr.release(); SourceMgr SrcMgr; @@ -379,15 +379,23 @@ int main(int argc, char **argv) { // it later. SrcMgr.setIncludeDirs(IncludeDirs); - llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); + std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); - llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); + std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); assert(MAI && "Unable to create target asm info!"); + if (CompressDebugSections) { + if (!zlib::isAvailable()) { + errs() << ProgName << ": build tools with zlib to enable -compress-debug-sections"; + return 1; + } + MAI->setCompressDebugSections(true); + } + // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and // MCObjectFileInfo needs a MCContext reference in order to initialize itself. - OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); + std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx); @@ -413,16 +421,16 @@ int main(int argc, char **argv) { FeaturesStr = Features.getString(); } - OwningPtr<tool_output_file> Out(GetOutputStream()); + std::unique_ptr<tool_output_file> Out(GetOutputStream()); if (!Out) return 1; formatted_raw_ostream FOS(Out->os()); - OwningPtr<MCStreamer> Str; + std::unique_ptr<MCStreamer> Str; - OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); - OwningPtr<MCSubtargetInfo> - STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); + std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); + std::unique_ptr<MCSubtargetInfo> STI( + TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); MCInstPrinter *IP = NULL; if (FileType == OFT_AssemblyFile) { @@ -434,12 +442,10 @@ int main(int argc, char **argv) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); } - bool UseCFI = !DisableCFI; - Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true, - /*useLoc*/ true, - UseCFI, - /*useDwarfDirectory*/ true, - IP, CE, MAB, ShowInst)); + Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/ true, + /*UseCFI*/ true, + /*useDwarfDirectory*/ + true, IP, CE, MAB, ShowInst)); } else if (FileType == OFT_Null) { Str.reset(createNullStreamer(Ctx)); @@ -448,7 +454,7 @@ int main(int argc, char **argv) { MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB, - FOS, CE, RelaxAll, + FOS, CE, *STI, RelaxAll, NoExecStack)); } diff --git a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp index 888761f..f3a3e45 100644 --- a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp +++ b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" @@ -136,12 +135,12 @@ MarkupTag MarkupParser::parseTag() { } static void parseMCMarkup(StringRef Filename) { - OwningPtr<MemoryBuffer> BufferPtr; + std::unique_ptr<MemoryBuffer> BufferPtr; if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, BufferPtr)) { errs() << ToolName << ": " << ec.message() << '\n'; return; } - MemoryBuffer *Buffer = BufferPtr.take(); + MemoryBuffer *Buffer = BufferPtr.release(); SourceMgr SrcMgr; diff --git a/tools/llvm-nm/CMakeLists.txt b/tools/llvm-nm/CMakeLists.txt index b1672ff..6128bf9 100644 --- a/tools/llvm-nm/CMakeLists.txt +++ b/tools/llvm-nm/CMakeLists.txt @@ -1,4 +1,7 @@ -set(LLVM_LINK_COMPONENTS bitreader object) +set(LLVM_LINK_COMPONENTS + Object + Support + ) add_llvm_tool(llvm-nm llvm-nm.cpp diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 8449c29..22e019a 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -16,15 +16,18 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/COFF.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" @@ -44,160 +47,152 @@ using namespace llvm; using namespace object; namespace { - enum OutputFormatTy { bsd, sysv, posix }; - cl::opt<OutputFormatTy> - OutputFormat("format", - cl::desc("Specify output format"), - cl::values(clEnumVal(bsd, "BSD format"), - clEnumVal(sysv, "System V format"), - clEnumVal(posix, "POSIX.2 format"), - clEnumValEnd), cl::init(bsd)); - cl::alias OutputFormat2("f", cl::desc("Alias for --format"), - cl::aliasopt(OutputFormat)); - - cl::list<std::string> - InputFilenames(cl::Positional, cl::desc("<input bitcode files>"), - cl::ZeroOrMore); - - 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::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::opt<bool> DefinedOnly("defined-only", - cl::desc("Show only defined symbols")); - - 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::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd")); - cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix")); - - cl::opt<bool> PrintFileName("print-file-name", +enum OutputFormatTy { bsd, sysv, posix }; +cl::opt<OutputFormatTy> OutputFormat( + "format", cl::desc("Specify output format"), + cl::values(clEnumVal(bsd, "BSD format"), clEnumVal(sysv, "System V format"), + clEnumVal(posix, "POSIX.2 format"), clEnumValEnd), + cl::init(bsd)); +cl::alias OutputFormat2("f", cl::desc("Alias for --format"), + cl::aliasopt(OutputFormat)); + +cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"), + cl::ZeroOrMore); + +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::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::opt<bool> DefinedOnly("defined-only", + cl::desc("Show only defined symbols")); + +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::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd")); +cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix")); + +cl::opt<bool> PrintFileName( + "print-file-name", 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::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"), - cl::aliasopt(PrintFileName)); +cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"), + cl::aliasopt(PrintFileName)); +cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"), + cl::aliasopt(PrintFileName)); - 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::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::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::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"), - cl::aliasopt(NumericSort)); +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::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"), + cl::aliasopt(NumericSort)); - 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::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::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::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::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size")); +cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size")); - cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden, - cl::desc("Exclude aliases from output")); +cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden, + cl::desc("Exclude aliases from output")); - cl::opt<bool> ArchiveMap("print-armap", - cl::desc("Print the archive map")); - cl::alias ArchiveMaps("s", cl::desc("Alias for --print-armap"), - cl::aliasopt(ArchiveMap)); - bool PrintAddress = true; +cl::opt<bool> ArchiveMap("print-armap", cl::desc("Print the archive map")); +cl::alias ArchiveMaps("s", cl::desc("Alias for --print-armap"), + cl::aliasopt(ArchiveMap)); +bool PrintAddress = true; - bool MultipleFiles = false; +bool MultipleFiles = false; - bool HadError = false; +bool HadError = false; - std::string ToolName; +std::string ToolName; } - -static void error(Twine message, Twine path = Twine()) { - errs() << ToolName << ": " << path << ": " << message << ".\n"; +static void error(Twine Message, Twine Path = Twine()) { + HadError = true; + errs() << ToolName << ": " << Path << ": " << Message << ".\n"; } -static bool error(error_code ec, Twine path = Twine()) { - if (ec) { - error(ec.message(), path); - HadError = true; +static bool error(error_code EC, Twine Path = Twine()) { + if (EC) { + error(EC.message(), Path); return true; } return false; } namespace { - struct NMSymbol { - uint64_t Address; - uint64_t Size; - char TypeChar; - StringRef Name; - }; - - static bool CompareSymbolAddress(const NMSymbol &a, const NMSymbol &b) { - if (a.Address < b.Address) - return true; - else if (a.Address == b.Address && a.Name < b.Name) - return true; - else if (a.Address == b.Address && a.Name == b.Name && a.Size < b.Size) - return true; - else - return false; - - } +struct NMSymbol { + uint64_t Address; + uint64_t Size; + char TypeChar; + StringRef Name; +}; +} - static bool CompareSymbolSize(const NMSymbol &a, const NMSymbol &b) { - if (a.Size < b.Size) - return true; - else if (a.Size == b.Size && a.Name < b.Name) - return true; - else if (a.Size == b.Size && a.Name == b.Name && a.Address < b.Address) - return true; - else - return false; - } +static bool compareSymbolAddress(const NMSymbol &A, const NMSymbol &B) { + if (A.Address < B.Address) + return true; + else if (A.Address == B.Address && A.Name < B.Name) + return true; + else if (A.Address == B.Address && A.Name == B.Name && A.Size < B.Size) + return true; + else + return false; +} - static bool CompareSymbolName(const NMSymbol &a, const NMSymbol &b) { - if (a.Name < b.Name) - return true; - else if (a.Name == b.Name && a.Size < b.Size) - return true; - else if (a.Name == b.Name && a.Size == b.Size && a.Address < b.Address) - return true; - else - return false; - } +static bool compareSymbolSize(const NMSymbol &A, const NMSymbol &B) { + if (A.Size < B.Size) + return true; + else if (A.Size == B.Size && A.Name < B.Name) + return true; + else if (A.Size == B.Size && A.Name == B.Name && A.Address < B.Address) + return true; + else + return false; +} - StringRef CurrentFilename; - typedef std::vector<NMSymbol> SymbolListT; - SymbolListT SymbolList; +static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) { + if (A.Name < B.Name) + return true; + else if (A.Name == B.Name && A.Size < B.Size) + return true; + else if (A.Name == B.Name && A.Size == B.Size && A.Address < B.Address) + return true; + else + return false; } -static void SortAndPrintSymbolList() { +static StringRef CurrentFilename; +typedef std::vector<NMSymbol> SymbolListT; +static SymbolListT SymbolList; + +static void sortAndPrintSymbolList() { if (!NoSort) { if (NumericSort) - std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolAddress); + std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolAddress); else if (SizeSort) - std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolSize); + std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolSize); else - std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolName); + std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolName); } if (OutputFormat == posix && MultipleFiles) { @@ -210,47 +205,46 @@ static void SortAndPrintSymbolList() { << " Size Line Section\n"; } - for (SymbolListT::iterator i = SymbolList.begin(), - e = SymbolList.end(); i != e; ++i) { - if ((i->TypeChar != 'U') && UndefinedOnly) + for (SymbolListT::iterator I = SymbolList.begin(), E = SymbolList.end(); + I != E; ++I) { + if ((I->TypeChar != 'U') && UndefinedOnly) continue; - if ((i->TypeChar == 'U') && DefinedOnly) + if ((I->TypeChar == 'U') && DefinedOnly) continue; - if (SizeSort && !PrintAddress && i->Size == UnknownAddressOrSize) + if (SizeSort && !PrintAddress && I->Size == UnknownAddressOrSize) continue; char SymbolAddrStr[10] = ""; char SymbolSizeStr[10] = ""; - if (OutputFormat == sysv || i->Address == object::UnknownAddressOrSize) + if (OutputFormat == sysv || I->Address == UnknownAddressOrSize) strcpy(SymbolAddrStr, " "); if (OutputFormat == sysv) strcpy(SymbolSizeStr, " "); - if (i->Address != object::UnknownAddressOrSize) - format("%08" PRIx64, i->Address).print(SymbolAddrStr, - sizeof(SymbolAddrStr)); - if (i->Size != object::UnknownAddressOrSize) - format("%08" PRIx64, i->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr)); + if (I->Address != UnknownAddressOrSize) + format("%08" PRIx64, I->Address) + .print(SymbolAddrStr, sizeof(SymbolAddrStr)); + if (I->Size != UnknownAddressOrSize) + format("%08" PRIx64, I->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr)); if (OutputFormat == posix) { - outs() << i->Name << " " << i->TypeChar << " " - << SymbolAddrStr << SymbolSizeStr << "\n"; + outs() << I->Name << " " << I->TypeChar << " " << SymbolAddrStr + << SymbolSizeStr << "\n"; } else if (OutputFormat == bsd) { if (PrintAddress) outs() << SymbolAddrStr << ' '; if (PrintSize) { outs() << SymbolSizeStr; - if (i->Size != object::UnknownAddressOrSize) + if (I->Size != UnknownAddressOrSize) outs() << ' '; } - outs() << i->TypeChar << " " << i->Name << "\n"; + outs() << I->TypeChar << " " << I->Name << "\n"; } else if (OutputFormat == sysv) { - std::string PaddedName (i->Name); - while (PaddedName.length () < 20) + std::string PaddedName(I->Name); + while (PaddedName.length() < 20) PaddedName += " "; - outs() << PaddedName << "|" << SymbolAddrStr << "| " - << i->TypeChar + outs() << PaddedName << "|" << SymbolAddrStr << "| " << I->TypeChar << " | |" << SymbolSizeStr << "| |\n"; } } @@ -258,199 +252,103 @@ static void SortAndPrintSymbolList() { SymbolList.clear(); } -static char TypeCharForSymbol(GlobalValue &GV) { - if (GV.isDeclaration()) return 'U'; - if (GV.hasLinkOnceLinkage()) return 'C'; - if (GV.hasCommonLinkage()) return 'C'; - if (GV.hasWeakLinkage()) return 'W'; - if (isa<Function>(GV) && GV.hasInternalLinkage()) return 't'; - if (isa<Function>(GV)) return 'T'; - if (isa<GlobalVariable>(GV) && GV.hasInternalLinkage()) return 'd'; - if (isa<GlobalVariable>(GV)) return 'D'; - if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(&GV)) { - const GlobalValue *AliasedGV = GA->getAliasedGlobal(); - if (isa<Function>(AliasedGV)) return 'T'; - if (isa<GlobalVariable>(AliasedGV)) return 'D'; - } - return '?'; -} - -static void DumpSymbolNameForGlobalValue(GlobalValue &GV) { - // Private linkage and available_externally linkage don't exist in symtab. - if (GV.hasPrivateLinkage() || - GV.hasLinkerPrivateLinkage() || - GV.hasLinkerPrivateWeakLinkage() || - GV.hasAvailableExternallyLinkage()) - return; - char TypeChar = TypeCharForSymbol(GV); - if (GV.hasLocalLinkage () && ExternalOnly) - return; - - NMSymbol s; - s.Address = object::UnknownAddressOrSize; - s.Size = object::UnknownAddressOrSize; - s.TypeChar = TypeChar; - s.Name = GV.getName(); - SymbolList.push_back(s); -} - -static void DumpSymbolNamesFromModule(Module *M) { - CurrentFilename = M->getModuleIdentifier(); - std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue); - std::for_each (M->global_begin(), M->global_end(), - DumpSymbolNameForGlobalValue); - if (!WithoutAliases) - std::for_each (M->alias_begin(), M->alias_end(), - DumpSymbolNameForGlobalValue); - - SortAndPrintSymbolList(); -} - template <class ELFT> -error_code getSymbolNMTypeChar(ELFObjectFile<ELFT> &Obj, symbol_iterator I, - char &Result) { +static char getSymbolNMTypeChar(ELFObjectFile<ELFT> &Obj, + basic_symbol_iterator I) { typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr; + // OK, this is ELF + symbol_iterator SymI(I); + DataRefImpl Symb = I->getRawDataRefImpl(); const Elf_Sym *ESym = Obj.getSymbol(Symb); const ELFFile<ELFT> &EF = *Obj.getELFFile(); const Elf_Shdr *ESec = EF.getSection(ESym); - char ret = '?'; - if (ESec) { switch (ESec->sh_type) { case ELF::SHT_PROGBITS: case ELF::SHT_DYNAMIC: switch (ESec->sh_flags) { case(ELF::SHF_ALLOC | ELF::SHF_EXECINSTR) : - ret = 't'; - break; + return 't'; + case(ELF::SHF_TLS | ELF::SHF_ALLOC | ELF::SHF_WRITE) : case(ELF::SHF_ALLOC | ELF::SHF_WRITE) : - ret = 'd'; - break; + return 'd'; case ELF::SHF_ALLOC: case(ELF::SHF_ALLOC | ELF::SHF_MERGE) : case(ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS) : - ret = 'r'; - break; + return 'r'; } break; case ELF::SHT_NOBITS: - ret = 'b'; + return 'b'; } } - switch (EF.getSymbolTableIndex(ESym)) { - case ELF::SHN_UNDEF: - if (ret == '?') - ret = 'U'; - break; - case ELF::SHN_ABS: - ret = 'a'; - break; - case ELF::SHN_COMMON: - ret = 'c'; - break; - } - - switch (ESym->getBinding()) { - case ELF::STB_GLOBAL: - ret = ::toupper(ret); - break; - case ELF::STB_WEAK: - if (EF.getSymbolTableIndex(ESym) == ELF::SHN_UNDEF) - ret = 'w'; - else if (ESym->getType() == ELF::STT_OBJECT) - ret = 'V'; - else - ret = 'W'; - } - - if (ret == '?' && ESym->getType() == ELF::STT_SECTION) { + if (ESym->getType() == ELF::STT_SECTION) { StringRef Name; - error_code EC = I->getName(Name); - if (EC) - return EC; - Result = StringSwitch<char>(Name) - .StartsWith(".debug", 'N') - .StartsWith(".note", 'n') - .Default('?'); - return object_error::success; + if (error(SymI->getName(Name))) + return '?'; + return StringSwitch<char>(Name) + .StartsWith(".debug", 'N') + .StartsWith(".note", 'n') + .Default('?'); } - Result = ret; - return object_error::success; + return '?'; } -static error_code getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I, - char &Result) { - const coff_symbol *symb = Obj.getCOFFSymbol(I); - StringRef name; - if (error_code ec = I->getName(name)) - return ec; - char ret = StringSwitch<char>(name) +static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) { + const coff_symbol *Symb = Obj.getCOFFSymbol(*I); + // OK, this is COFF. + symbol_iterator SymI(I); + + StringRef Name; + if (error(SymI->getName(Name))) + return '?'; + + char Ret = StringSwitch<char>(Name) .StartsWith(".debug", 'N') .StartsWith(".sxdata", 'N') .Default('?'); - if (ret != '?') { - Result = ret; - return object_error::success; - } + if (Ret != '?') + return Ret; uint32_t Characteristics = 0; - if (symb->SectionNumber > 0) { - section_iterator SecI = Obj.end_sections(); - if (error_code ec = I->getSection(SecI)) - return ec; - const coff_section *Section = Obj.getCOFFSection(SecI); + if (!COFF::isReservedSectionNumber(Symb->SectionNumber)) { + section_iterator SecI = Obj.section_end(); + if (error(SymI->getSection(SecI))) + return '?'; + const coff_section *Section = Obj.getCOFFSection(*SecI); Characteristics = Section->Characteristics; } - switch (symb->SectionNumber) { - case COFF::IMAGE_SYM_UNDEFINED: - // Check storage classes. - if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) { - Result = 'w'; - return object_error::success; // Don't do ::toupper. - } else if (symb->Value != 0) // Check for common symbols. - ret = 'c'; - else - ret = 'u'; - break; - case COFF::IMAGE_SYM_ABSOLUTE: - ret = 'a'; - break; + switch (Symb->SectionNumber) { case COFF::IMAGE_SYM_DEBUG: - ret = 'n'; - break; + return 'n'; default: // Check section type. if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) - ret = 't'; + return 't'; else if (Characteristics & COFF::IMAGE_SCN_MEM_READ && ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. - ret = 'r'; + return 'r'; else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) - ret = 'd'; + return 'd'; else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) - ret = 'b'; + return 'b'; else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) - ret = 'i'; + return 'i'; // Check for section symbol. - else if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC && - symb->Value == 0) - ret = 's'; + else if (Symb->isSectionDefinition()) + return 's'; } - if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) - ret = ::toupper(static_cast<unsigned char>(ret)); - - Result = ret; - return object_error::success; + return '?'; } static uint8_t getNType(MachOObjectFile &Obj, DataRefImpl Symb) { @@ -462,205 +360,226 @@ static uint8_t getNType(MachOObjectFile &Obj, DataRefImpl Symb) { return STE.n_type; } -static error_code getSymbolNMTypeChar(MachOObjectFile &Obj, symbol_iterator I, - char &Res) { +static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { DataRefImpl Symb = I->getRawDataRefImpl(); uint8_t NType = getNType(Obj, Symb); - char Char; switch (NType & MachO::N_TYPE) { - case MachO::N_UNDF: - Char = 'u'; - break; case MachO::N_ABS: - Char = 's'; - break; + return 's'; case MachO::N_SECT: { - section_iterator Sec = Obj.end_sections(); + section_iterator Sec = Obj.section_end(); Obj.getSymbolSection(Symb, Sec); DataRefImpl Ref = Sec->getRawDataRefImpl(); StringRef SectionName; Obj.getSectionName(Ref, SectionName); StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref); if (SegmentName == "__TEXT" && SectionName == "__text") - Char = 't'; + return 't'; else - Char = 's'; - } break; - default: - Char = '?'; - break; + return 's'; + } } - if (NType & (MachO::N_EXT | MachO::N_PEXT)) - Char = toupper(static_cast<unsigned char>(Char)); - Res = Char; - return object_error::success; + return '?'; } -static char getNMTypeChar(ObjectFile *Obj, symbol_iterator I) { - char Res = '?'; - if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(Obj)) { - error(getSymbolNMTypeChar(*COFF, I, Res)); - return Res; - } - if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj)) { - error(getSymbolNMTypeChar(*MachO, I, Res)); - return Res; - } +static char getSymbolNMTypeChar(const GlobalValue &GV) { + if (isa<Function>(GV)) + return 't'; + // FIXME: should we print 'b'? At the IR level we cannot be sure if this + // will be in bss or not, but we could approximate. + if (isa<GlobalVariable>(GV)) + return 'd'; + const GlobalAlias *GA = cast<GlobalAlias>(&GV); + const GlobalValue *AliasedGV = GA->getAliasedGlobal(); + return getSymbolNMTypeChar(*AliasedGV); +} - if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(Obj)) { - error(getSymbolNMTypeChar(*ELF, I, Res)); - return Res; - } - if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(Obj)) { - error(getSymbolNMTypeChar(*ELF, I, Res)); - return Res; - } - if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(Obj)) { - error(getSymbolNMTypeChar(*ELF, I, Res)); - return Res; +static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) { + const GlobalValue &GV = Obj.getSymbolGV(I->getRawDataRefImpl()); + return getSymbolNMTypeChar(GV); +} + +template <class ELFT> +static bool isObject(ELFObjectFile<ELFT> &Obj, symbol_iterator I) { + typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + + DataRefImpl Symb = I->getRawDataRefImpl(); + const Elf_Sym *ESym = Obj.getSymbol(Symb); + + return ESym->getType() == ELF::STT_OBJECT; +} + +static bool isObject(SymbolicFile *Obj, basic_symbol_iterator I) { + if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(Obj)) + return isObject(*ELF, I); + if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(Obj)) + return isObject(*ELF, I); + if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(Obj)) + return isObject(*ELF, I); + if (ELF64BEObjectFile *ELF = dyn_cast<ELF64BEObjectFile>(Obj)) + return isObject(*ELF, I); + return false; +} + +static char getNMTypeChar(SymbolicFile *Obj, basic_symbol_iterator I) { + uint32_t Symflags = I->getFlags(); + if ((Symflags & object::SymbolRef::SF_Weak) && !isa<MachOObjectFile>(Obj)) { + char Ret = isObject(Obj, I) ? 'v' : 'w'; + if (!(Symflags & object::SymbolRef::SF_Undefined)) + Ret = toupper(Ret); + return Ret; } - ELF64BEObjectFile *ELF = cast<ELF64BEObjectFile>(Obj); - error(getSymbolNMTypeChar(*ELF, I, Res)); - return Res; + + if (Symflags & object::SymbolRef::SF_Undefined) + return 'U'; + + if (Symflags & object::SymbolRef::SF_Common) + return 'C'; + + char Ret = '?'; + if (Symflags & object::SymbolRef::SF_Absolute) + Ret = 'a'; + else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(Obj)) + Ret = getSymbolNMTypeChar(*IR, I); + else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(Obj)) + Ret = getSymbolNMTypeChar(*COFF, I); + else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj)) + Ret = getSymbolNMTypeChar(*MachO, I); + else if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(Obj)) + Ret = getSymbolNMTypeChar(*ELF, I); + else if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(Obj)) + Ret = getSymbolNMTypeChar(*ELF, I); + else if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(Obj)) + Ret = getSymbolNMTypeChar(*ELF, I); + else + Ret = getSymbolNMTypeChar(*cast<ELF64BEObjectFile>(Obj), I); + + if (Symflags & object::SymbolRef::SF_Global) + Ret = toupper(Ret); + + return Ret; } -static void DumpSymbolNamesFromObject(ObjectFile *obj) { - error_code ec; - symbol_iterator ibegin = obj->begin_symbols(); - symbol_iterator iend = obj->end_symbols(); +static void dumpSymbolNamesFromObject(SymbolicFile *Obj) { + basic_symbol_iterator IBegin = Obj->symbol_begin(); + basic_symbol_iterator IEnd = Obj->symbol_end(); if (DynamicSyms) { - ibegin = obj->begin_dynamic_symbols(); - iend = obj->end_dynamic_symbols(); + if (!Obj->isELF()) { + error("File format has no dynamic symbol table", Obj->getFileName()); + return; + } + std::pair<symbol_iterator, symbol_iterator> IDyn = + getELFDynamicSymbolIterators(Obj); + IBegin = IDyn.first; + IEnd = IDyn.second; } - for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) { - if (error(ec)) break; - uint32_t symflags; - if (error(i->getFlags(symflags))) break; - if (!DebugSyms && (symflags & SymbolRef::SF_FormatSpecific)) + std::string NameBuffer; + raw_string_ostream OS(NameBuffer); + for (basic_symbol_iterator I = IBegin; I != IEnd; ++I) { + uint32_t SymFlags = I->getFlags(); + if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific)) continue; - NMSymbol s; - s.Size = object::UnknownAddressOrSize; - s.Address = object::UnknownAddressOrSize; - if (PrintSize || SizeSort) { - if (error(i->getSize(s.Size))) break; + if (WithoutAliases) { + if (IRObjectFile *IR = dyn_cast<IRObjectFile>(Obj)) { + const GlobalValue &GV = IR->getSymbolGV(I->getRawDataRefImpl()); + if(isa<GlobalAlias>(GV)) + continue; + } } - if (PrintAddress) - if (error(i->getAddress(s.Address))) break; - s.TypeChar = getNMTypeChar(obj, i); - if (error(i->getName(s.Name))) break; - SymbolList.push_back(s); + NMSymbol S; + S.Size = UnknownAddressOrSize; + S.Address = UnknownAddressOrSize; + if ((PrintSize || SizeSort) && isa<ObjectFile>(Obj)) { + symbol_iterator SymI = I; + if (error(SymI->getSize(S.Size))) + break; + } + if (PrintAddress && isa<ObjectFile>(Obj)) + if (error(symbol_iterator(I)->getAddress(S.Address))) + break; + S.TypeChar = getNMTypeChar(Obj, I); + if (error(I->printName(OS))) + break; + OS << '\0'; + SymbolList.push_back(S); } - CurrentFilename = obj->getFileName(); - SortAndPrintSymbolList(); -} - -static void DumpSymbolNamesFromFile(std::string &Filename) { - if (Filename != "-" && !sys::fs::exists(Filename)) { - errs() << ToolName << ": '" << Filename << "': " << "No such file\n"; - return; + OS.flush(); + const char *P = NameBuffer.c_str(); + for (unsigned I = 0; I < SymbolList.size(); ++I) { + SymbolList[I].Name = P; + P += strlen(P) + 1; } - OwningPtr<MemoryBuffer> Buffer; + CurrentFilename = Obj->getFileName(); + sortAndPrintSymbolList(); +} + +static void dumpSymbolNamesFromFile(std::string &Filename) { + std::unique_ptr<MemoryBuffer> Buffer; if (error(MemoryBuffer::getFileOrSTDIN(Filename, Buffer), Filename)) return; - sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer()); - LLVMContext &Context = getGlobalContext(); - std::string ErrorMessage; - if (magic == sys::fs::file_magic::bitcode) { - Module *Result = 0; - Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); - if (Result) { - DumpSymbolNamesFromModule(Result); - delete Result; - } else { - error(ErrorMessage, Filename); - return; - } - } else if (magic == sys::fs::file_magic::archive) { - OwningPtr<Binary> arch; - if (error(object::createBinary(Buffer.take(), arch), Filename)) - return; - - if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { - if (ArchiveMap) { - object::Archive::symbol_iterator I = a->begin_symbols(); - object::Archive::symbol_iterator E = a->end_symbols(); - if (I !=E) { - outs() << "Archive map" << "\n"; - for (; I != E; ++I) { - object::Archive::child_iterator c; - StringRef symname; - StringRef filename; - if (error(I->getMember(c))) - return; - if (error(I->getName(symname))) - return; - if (error(c->getName(filename))) - return; - outs() << symname << " in " << filename << "\n"; - } - outs() << "\n"; - } - } - - for (object::Archive::child_iterator i = a->begin_children(), - e = a->end_children(); i != e; ++i) { - OwningPtr<Binary> child; - if (i->getAsBinary(child)) { - // Try opening it as a bitcode file. - OwningPtr<MemoryBuffer> buff; - if (error(i->getMemoryBuffer(buff))) + ErrorOr<Binary *> BinaryOrErr = createBinary(Buffer.release(), &Context); + if (error(BinaryOrErr.getError(), Filename)) + return; + std::unique_ptr<Binary> Bin(BinaryOrErr.get()); + + if (Archive *A = dyn_cast<Archive>(Bin.get())) { + if (ArchiveMap) { + Archive::symbol_iterator I = A->symbol_begin(); + Archive::symbol_iterator E = A->symbol_end(); + if (I != E) { + outs() << "Archive map\n"; + for (; I != E; ++I) { + Archive::child_iterator C; + StringRef SymName; + StringRef FileName; + if (error(I->getMember(C))) return; - Module *Result = 0; - if (buff) - Result = ParseBitcodeFile(buff.get(), Context, &ErrorMessage); - - if (Result) { - DumpSymbolNamesFromModule(Result); - delete Result; - } - continue; - } - if (object::ObjectFile *o = dyn_cast<ObjectFile>(child.get())) { - outs() << o->getFileName() << ":\n"; - DumpSymbolNamesFromObject(o); + if (error(I->getName(SymName))) + return; + if (error(C->getName(FileName))) + return; + outs() << SymName << " in " << FileName << "\n"; } + outs() << "\n"; } } - } else if (magic == sys::fs::file_magic::macho_universal_binary) { - OwningPtr<Binary> Bin; - if (error(object::createBinary(Buffer.take(), Bin), Filename)) - return; - object::MachOUniversalBinary *UB = - cast<object::MachOUniversalBinary>(Bin.get()); - for (object::MachOUniversalBinary::object_iterator - I = UB->begin_objects(), - E = UB->end_objects(); + for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); + I != E; ++I) { + std::unique_ptr<Binary> Child; + if (I->getAsBinary(Child, &Context)) + continue; + if (SymbolicFile *O = dyn_cast<SymbolicFile>(Child.get())) { + outs() << O->getFileName() << ":\n"; + dumpSymbolNamesFromObject(O); + } + } + return; + } + if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin.get())) { + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); I != E; ++I) { - OwningPtr<ObjectFile> Obj; + std::unique_ptr<ObjectFile> Obj; if (!I->getAsObjectFile(Obj)) { outs() << Obj->getFileName() << ":\n"; - DumpSymbolNamesFromObject(Obj.get()); + dumpSymbolNamesFromObject(Obj.get()); } } - } else if (magic.is_object()) { - OwningPtr<Binary> obj; - if (error(object::createBinary(Buffer.take(), obj), Filename)) - return; - if (object::ObjectFile *o = dyn_cast<ObjectFile>(obj.get())) - DumpSymbolNamesFromObject(o); - } else { - errs() << ToolName << ": " << Filename << ": " - << "unrecognizable file type\n"; - HadError = true; return; } + if (SymbolicFile *O = dyn_cast<SymbolicFile>(Bin.get())) { + dumpSymbolNamesFromObject(O); + return; + } + error("unrecognizable file type", Filename); + return; } int main(int argc, char **argv) { @@ -668,7 +587,7 @@ int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n"); // llvm-nm only reads binary files. @@ -676,23 +595,30 @@ int main(int argc, char **argv) { return 1; ToolName = argv[0]; - if (BSDFormat) OutputFormat = bsd; - if (POSIXFormat) OutputFormat = posix; + if (BSDFormat) + OutputFormat = bsd; + if (POSIXFormat) + OutputFormat = posix; // The relative order of these is important. If you pass --size-sort it should // only print out the size. However, if you pass -S --size-sort, it should // print out both the size and address. - if (SizeSort && !PrintSize) PrintAddress = false; - if (OutputFormat == sysv || SizeSort) PrintSize = true; + if (SizeSort && !PrintSize) + PrintAddress = false; + if (OutputFormat == sysv || SizeSort) + PrintSize = true; switch (InputFilenames.size()) { - case 0: InputFilenames.push_back("-"); - case 1: break; - default: MultipleFiles = true; + case 0: + InputFilenames.push_back("-"); + case 1: + break; + default: + MultipleFiles = true; } std::for_each(InputFilenames.begin(), InputFilenames.end(), - DumpSymbolNamesFromFile); + dumpSymbolNamesFromFile); if (HadError) return 1; diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index e983ec9..413cb9b 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -2,9 +2,8 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} DebugInfo MC - MCParser - MCDisassembler Object + Support ) add_llvm_tool(llvm-objdump diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp index 5f0bcbb..49f2755 100644 --- a/tools/llvm-objdump/COFFDump.cpp +++ b/tools/llvm-objdump/COFFDump.cpp @@ -10,7 +10,7 @@ /// \file /// \brief This file implements the COFF-specific dumper for llvm-objdump. /// It outputs the Win64 EH data structures as plain text. -/// The encoding of the unwind codes is decribed in MSDN: +/// The encoding of the unwind codes is described in MSDN: /// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx /// //===----------------------------------------------------------------------===// @@ -94,7 +94,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { // slots is provided. static void printUnwindCode(ArrayRef<UnwindCode> UCs) { assert(UCs.size() >= getNumUsedSlots(UCs[0])); - outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset)) + outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset)) << getUnwindCodeTypeName(UCs[0].getUnwindOp()); switch (UCs[0].getUnwindOp()) { case UOP_PushNonVol: @@ -161,10 +161,12 @@ static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, const SymbolRef &Sym, const coff_section *&ResolvedSection, uint64_t &ResolvedAddr) { - if (error_code ec = Sym.getAddress(ResolvedAddr)) return ec; - section_iterator iter(Obj->begin_sections()); - if (error_code ec = Sym.getSection(iter)) return ec; - ResolvedSection = Obj->getCOFFSection(iter); + if (error_code EC = Sym.getAddress(ResolvedAddr)) + return EC; + section_iterator iter(Obj->section_begin()); + if (error_code EC = Sym.getSection(iter)) + return EC; + ResolvedSection = Obj->getCOFFSection(*iter); return object_error::success; } @@ -176,13 +178,14 @@ static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, E = Rels.end(); I != E; ++I) { uint64_t Ofs; - if (error_code ec = I->getOffset(Ofs)) return ec; + if (error_code EC = I->getOffset(Ofs)) + return EC; if (Ofs == Offset) { Sym = *I->getSymbol(); - break; + return object_error::success; } } - return object_error::success; + return object_error::parse_failed; } // Given a vector of relocations for a section and an offset into this section @@ -195,11 +198,13 @@ static error_code getSectionContents(const COFFObjectFile *Obj, ArrayRef<uint8_t> &Contents, uint64_t &Addr) { SymbolRef Sym; - if (error_code ec = resolveSymbol(Rels, Offset, Sym)) return ec; + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; const coff_section *Section; - if (error_code ec = resolveSectionAndAddress(Obj, Sym, Section, Addr)) - return ec; - if (error_code ec = Obj->getSectionContents(Section, Contents)) return ec; + if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + return EC; + if (error_code EC = Obj->getSectionContents(Section, Contents)) + return EC; return object_error::success; } @@ -209,8 +214,10 @@ static error_code getSectionContents(const COFFObjectFile *Obj, static error_code resolveSymbolName(const std::vector<RelocationRef> &Rels, uint64_t Offset, StringRef &Name) { SymbolRef Sym; - if (error_code ec = resolveSymbol(Rels, Offset, Sym)) return ec; - if (error_code ec = Sym.getName(Name)) return ec; + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; + if (error_code EC = Sym.getName(Name)) + return EC; return object_error::success; } @@ -218,30 +225,95 @@ static void printCOFFSymbolAddress(llvm::raw_ostream &Out, const std::vector<RelocationRef> &Rels, uint64_t Offset, uint32_t Disp) { StringRef Sym; - if (error_code ec = resolveSymbolName(Rels, Offset, Sym)) { - error(ec); - return ; + if (!resolveSymbolName(Rels, Offset, Sym)) { + Out << Sym; + if (Disp > 0) + Out << format(" + 0x%04x", Disp); + } else { + Out << format("0x%04x", Disp); } - Out << Sym; - if (Disp > 0) - Out << format(" + 0x%04x", Disp); +} + +static void +printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) { + if (Count == 0) + return; + + const pe32_header *PE32Header; + if (error(Obj->getPE32Header(PE32Header))) + return; + uint32_t ImageBase = PE32Header->ImageBase; + uintptr_t IntPtr = 0; + if (error(Obj->getVaPtr(TableVA, IntPtr))) + return; + const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr; + outs() << "SEH Table:"; + for (int I = 0; I < Count; ++I) + outs() << format(" 0x%x", P[I] + ImageBase); + outs() << "\n\n"; +} + +static void printLoadConfiguration(const COFFObjectFile *Obj) { + // Skip if it's not executable. + const pe32_header *PE32Header; + if (error(Obj->getPE32Header(PE32Header))) + return; + if (!PE32Header) + return; + + const coff_file_header *Header; + if (error(Obj->getCOFFHeader(Header))) + return; + // Currently only x86 is supported + if (Header->Machine != COFF::IMAGE_FILE_MACHINE_I386) + return; + + const data_directory *DataDir; + if (error(Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir))) + return; + uintptr_t IntPtr = 0; + if (DataDir->RelativeVirtualAddress == 0) + return; + if (error(Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))) + return; + + auto *LoadConf = reinterpret_cast<const coff_load_configuration32 *>(IntPtr); + outs() << "Load configuration:" + << "\n Timestamp: " << LoadConf->TimeDateStamp + << "\n Major Version: " << LoadConf->MajorVersion + << "\n Minor Version: " << LoadConf->MinorVersion + << "\n GlobalFlags Clear: " << LoadConf->GlobalFlagsClear + << "\n GlobalFlags Set: " << LoadConf->GlobalFlagsSet + << "\n Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout + << "\n Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold + << "\n Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold + << "\n Lock Prefix Table: " << LoadConf->LockPrefixTable + << "\n Maximum Allocation Size: " << LoadConf->MaximumAllocationSize + << "\n Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold + << "\n Process Affinity Mask: " << LoadConf->ProcessAffinityMask + << "\n Process Heap Flags: " << LoadConf->ProcessHeapFlags + << "\n CSD Version: " << LoadConf->CSDVersion + << "\n Security Cookie: " << LoadConf->SecurityCookie + << "\n SEH Table: " << LoadConf->SEHandlerTable + << "\n SEH Count: " << LoadConf->SEHandlerCount + << "\n\n"; + printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount); + outs() << "\n"; } // Prints import tables. The import table is a table containing the list of // DLL name and symbol names which will be linked by the loader. static void printImportTables(const COFFObjectFile *Obj) { + import_directory_iterator I = Obj->import_directory_begin(); + import_directory_iterator E = Obj->import_directory_end(); + if (I == E) + return; outs() << "The Import Tables:\n"; - error_code ec; - for (import_directory_iterator i = Obj->import_directory_begin(), - e = Obj->import_directory_end(); - i != e; i = i.increment(ec)) { - if (ec) - return; - + for (; I != E; I = ++I) { const import_directory_table_entry *Dir; StringRef Name; - if (i->getImportTableEntry(Dir)) return; - if (i->getName(Name)) return; + if (I->getImportTableEntry(Dir)) return; + if (I->getName(Name)) return; outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n", static_cast<uint32_t>(Dir->ImportLookupTableRVA), @@ -252,7 +324,7 @@ static void printImportTables(const COFFObjectFile *Obj) { outs() << " DLL Name: " << Name << "\n"; outs() << " Hint/Ord Name\n"; const import_lookup_table_entry32 *entry; - if (i->getImportLookupEntry(entry)) + if (I->getImportLookupEntry(entry)) return; for (; entry->data; ++entry) { if (entry->isOrdinal()) { @@ -269,133 +341,218 @@ static void printImportTables(const COFFObjectFile *Obj) { } } -void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { - const coff_file_header *Header; - if (error(Obj->getCOFFHeader(Header))) return; - - if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { - errs() << "Unsupported image machine type " - "(currently only AMD64 is supported).\n"; +// Prints export tables. The export table is a table containing the list of +// exported symbol from the DLL. +static void printExportTable(const COFFObjectFile *Obj) { + outs() << "Export Table:\n"; + export_directory_iterator I = Obj->export_directory_begin(); + export_directory_iterator E = Obj->export_directory_end(); + if (I == E) return; - } - - const coff_section *Pdata = 0; - - error_code ec; - for (section_iterator SI = Obj->begin_sections(), - SE = Obj->end_sections(); - SI != SE; SI.increment(ec)) { - if (error(ec)) return; + StringRef DllName; + uint32_t OrdinalBase; + if (I->getDllName(DllName)) + return; + if (I->getOrdinalBase(OrdinalBase)) + return; + outs() << " DLL name: " << DllName << "\n"; + outs() << " Ordinal base: " << OrdinalBase << "\n"; + outs() << " Ordinal RVA Name\n"; + for (; I != E; I = ++I) { + uint32_t Ordinal; + if (I->getOrdinal(Ordinal)) + return; + uint32_t RVA; + if (I->getExportRVA(RVA)) + return; + outs() << format(" % 4d %# 8x", Ordinal, RVA); StringRef Name; - if (error(SI->getName(Name))) continue; + if (I->getSymbolName(Name)) + continue; + if (!Name.empty()) + outs() << " " << Name; + outs() << "\n"; + } +} - if (Name != ".pdata") continue; +// Given the COFF object file, this function returns the relocations for .pdata +// and the pointer to "runtime function" structs. +static bool getPDataSection(const COFFObjectFile *Obj, + std::vector<RelocationRef> &Rels, + const RuntimeFunction *&RFStart, int &NumRFs) { + for (const SectionRef &Section : Obj->sections()) { + StringRef Name; + if (error(Section.getName(Name))) + continue; + if (Name != ".pdata") + continue; - Pdata = Obj->getCOFFSection(SI); - std::vector<RelocationRef> Rels; - for (relocation_iterator RI = SI->begin_relocations(), - RE = SI->end_relocations(); - RI != RE; RI.increment(ec)) { - if (error(ec)) break; - Rels.push_back(*RI); - } + const coff_section *Pdata = Obj->getCOFFSection(Section); + for (const RelocationRef &Reloc : Section.relocations()) + Rels.push_back(Reloc); // Sort relocations by address. std::sort(Rels.begin(), Rels.end(), RelocAddressLess); ArrayRef<uint8_t> Contents; - if (error(Obj->getSectionContents(Pdata, Contents))) continue; - if (Contents.empty()) continue; + if (error(Obj->getSectionContents(Pdata, Contents))) + continue; + if (Contents.empty()) + continue; + + RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data()); + NumRFs = Contents.size() / sizeof(RuntimeFunction); + return true; + } + return false; +} - ArrayRef<RuntimeFunction> RFs( - reinterpret_cast<const RuntimeFunction *>(Contents.data()), - Contents.size() / sizeof(RuntimeFunction)); - for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) { - const uint64_t SectionOffset = std::distance(RFs.begin(), I) - * sizeof(RuntimeFunction); +static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) { + // The casts to int are required in order to output the value as number. + // Without the casts the value would be interpreted as char data (which + // results in garbage output). + outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n"; + outs() << " Flags: " << static_cast<int>(UI->getFlags()); + if (UI->getFlags()) { + if (UI->getFlags() & UNW_ExceptionHandler) + outs() << " UNW_ExceptionHandler"; + if (UI->getFlags() & UNW_TerminateHandler) + outs() << " UNW_TerminateHandler"; + if (UI->getFlags() & UNW_ChainInfo) + outs() << " UNW_ChainInfo"; + } + outs() << "\n"; + outs() << " Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n"; + outs() << " Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n"; + // Maybe this should move to output of UOP_SetFPReg? + if (UI->getFrameRegister()) { + outs() << " Frame register: " + << getUnwindRegisterName(UI->getFrameRegister()) << "\n"; + outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n"; + } else { + outs() << " No frame pointer used\n"; + } + if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { + // FIXME: Output exception handler data + } else if (UI->getFlags() & UNW_ChainInfo) { + // FIXME: Output chained unwind info + } - outs() << "Function Table:\n"; + if (UI->NumCodes) + outs() << " Unwind Codes:\n"; - outs() << " Start Address: "; - printCOFFSymbolAddress(outs(), Rels, SectionOffset + + printAllUnwindCodes(ArrayRef<UnwindCode>(&UI->UnwindCodes[0], UI->NumCodes)); + + outs() << "\n"; + outs().flush(); +} + +/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is +/// pointing to an executable file. +static void printRuntimeFunction(const COFFObjectFile *Obj, + const RuntimeFunction &RF) { + if (!RF.StartAddress) + return; + outs() << "Function Table:\n" + << format(" Start Address: 0x%04x\n", + static_cast<uint32_t>(RF.StartAddress)) + << format(" End Address: 0x%04x\n", + static_cast<uint32_t>(RF.EndAddress)) + << format(" Unwind Info Address: 0x%04x\n", + static_cast<uint32_t>(RF.UnwindInfoOffset)); + uintptr_t addr; + if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr)) + return; + printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr)); +} + +/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is +/// pointing to an object file. Unlike executable, fields in RuntimeFunction +/// struct are filled with zeros, but instead there are relocations pointing to +/// them so that the linker will fill targets' RVAs to the fields at link +/// time. This function interprets the relocations to find the data to be used +/// in the resulting executable. +static void printRuntimeFunctionRels(const COFFObjectFile *Obj, + const RuntimeFunction &RF, + uint64_t SectionOffset, + const std::vector<RelocationRef> &Rels) { + outs() << "Function Table:\n"; + outs() << " Start Address: "; + printCOFFSymbolAddress(outs(), Rels, + SectionOffset + /*offsetof(RuntimeFunction, StartAddress)*/ 0, - I->StartAddress); - outs() << "\n"; + RF.StartAddress); + outs() << "\n"; - outs() << " End Address: "; - printCOFFSymbolAddress(outs(), Rels, SectionOffset + + outs() << " End Address: "; + printCOFFSymbolAddress(outs(), Rels, + SectionOffset + /*offsetof(RuntimeFunction, EndAddress)*/ 4, - I->EndAddress); - outs() << "\n"; + RF.EndAddress); + outs() << "\n"; - outs() << " Unwind Info Address: "; - printCOFFSymbolAddress(outs(), Rels, SectionOffset + + outs() << " Unwind Info Address: "; + printCOFFSymbolAddress(outs(), Rels, + SectionOffset + /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, - I->UnwindInfoOffset); - outs() << "\n"; - - ArrayRef<uint8_t> XContents; - uint64_t UnwindInfoOffset = 0; - if (error(getSectionContents(Obj, Rels, SectionOffset + - /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, - XContents, UnwindInfoOffset))) continue; - if (XContents.empty()) continue; - - UnwindInfoOffset += I->UnwindInfoOffset; - if (UnwindInfoOffset > XContents.size()) continue; - - const Win64EH::UnwindInfo *UI = - reinterpret_cast<const Win64EH::UnwindInfo *> - (XContents.data() + UnwindInfoOffset); - - // The casts to int are required in order to output the value as number. - // Without the casts the value would be interpreted as char data (which - // results in garbage output). - outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n"; - outs() << " Flags: " << static_cast<int>(UI->getFlags()); - if (UI->getFlags()) { - if (UI->getFlags() & UNW_ExceptionHandler) - outs() << " UNW_ExceptionHandler"; - if (UI->getFlags() & UNW_TerminateHandler) - outs() << " UNW_TerminateHandler"; - if (UI->getFlags() & UNW_ChainInfo) - outs() << " UNW_ChainInfo"; - } - outs() << "\n"; - outs() << " Size of prolog: " - << static_cast<int>(UI->PrologSize) << "\n"; - outs() << " Number of Codes: " - << static_cast<int>(UI->NumCodes) << "\n"; - // Maybe this should move to output of UOP_SetFPReg? - if (UI->getFrameRegister()) { - outs() << " Frame register: " - << getUnwindRegisterName(UI->getFrameRegister()) - << "\n"; - outs() << " Frame offset: " - << 16 * UI->getFrameOffset() - << "\n"; - } else { - outs() << " No frame pointer used\n"; - } - if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { - // FIXME: Output exception handler data - } else if (UI->getFlags() & UNW_ChainInfo) { - // FIXME: Output chained unwind info - } + RF.UnwindInfoOffset); + outs() << "\n"; - if (UI->NumCodes) - outs() << " Unwind Codes:\n"; + ArrayRef<uint8_t> XContents; + uint64_t UnwindInfoOffset = 0; + if (error(getSectionContents( + Obj, Rels, SectionOffset + + /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, + XContents, UnwindInfoOffset))) + return; + if (XContents.empty()) + return; - printAllUnwindCodes(ArrayRef<UnwindCode>(&UI->UnwindCodes[0], - UI->NumCodes)); + UnwindInfoOffset += RF.UnwindInfoOffset; + if (UnwindInfoOffset > XContents.size()) + return; - outs() << "\n\n"; - outs().flush(); - } + auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() + + UnwindInfoOffset); + printWin64EHUnwindInfo(UI); +} + +void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { + const coff_file_header *Header; + if (error(Obj->getCOFFHeader(Header))) + return; + + if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { + errs() << "Unsupported image machine type " + "(currently only AMD64 is supported).\n"; + return; + } + + std::vector<RelocationRef> Rels; + const RuntimeFunction *RFStart; + int NumRFs; + if (!getPDataSection(Obj, Rels, RFStart, NumRFs)) + return; + ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs); + + bool IsExecutable = Rels.empty(); + if (IsExecutable) { + for (const RuntimeFunction &RF : RFs) + printRuntimeFunction(Obj, RF); + return; + } + + for (const RuntimeFunction &RF : RFs) { + uint64_t SectionOffset = + std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction); + printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels); } } void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) { - printImportTables(dyn_cast<const COFFObjectFile>(Obj)); + const COFFObjectFile *file = dyn_cast<const COFFObjectFile>(Obj); + printLoadConfiguration(file); + printImportTables(file); + printExportTable(file); } diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 86923fd..89b038f 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "llvm-objdump.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" @@ -147,28 +146,23 @@ static void DumpDataInCode(const char *bytes, uint64_t Size, } } -static void -getSectionsAndSymbols(const MachO::mach_header Header, - MachOObjectFile *MachOObj, - std::vector<SectionRef> &Sections, - std::vector<SymbolRef> &Symbols, - SmallVectorImpl<uint64_t> &FoundFns, - uint64_t &BaseSegmentAddress) { - error_code ec; - for (symbol_iterator SI = MachOObj->begin_symbols(), - SE = MachOObj->end_symbols(); SI != SE; SI.increment(ec)) - Symbols.push_back(*SI); - - for (section_iterator SI = MachOObj->begin_sections(), - SE = MachOObj->end_sections(); SI != SE; SI.increment(ec)) { - SectionRef SR = *SI; +static void getSectionsAndSymbols(const MachO::mach_header Header, + MachOObjectFile *MachOObj, + std::vector<SectionRef> &Sections, + std::vector<SymbolRef> &Symbols, + SmallVectorImpl<uint64_t> &FoundFns, + uint64_t &BaseSegmentAddress) { + for (const SymbolRef &Symbol : MachOObj->symbols()) + Symbols.push_back(Symbol); + + for (const SectionRef &Section : MachOObj->sections()) { StringRef SectName; - SR.getName(SectName); - Sections.push_back(*SI); + Section.getName(SectName); + Sections.push_back(Section); } MachOObjectFile::LoadCommandInfo Command = - MachOObj->getFirstLoadCommandInfo(); + MachOObj->getFirstLoadCommandInfo(); bool BaseSegmentAddressSet = false; for (unsigned i = 0; ; ++i) { if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) { @@ -200,15 +194,15 @@ static void DisassembleInputMachO2(StringRef Filename, MachOObjectFile *MachOOF); void llvm::DisassembleInputMachO(StringRef Filename) { - OwningPtr<MemoryBuffer> Buff; + std::unique_ptr<MemoryBuffer> Buff; if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { errs() << "llvm-objdump: " << Filename << ": " << ec.message() << "\n"; return; } - OwningPtr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile*>( - ObjectFile::createMachOObjectFile(Buff.take()))); + std::unique_ptr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile *>( + ObjectFile::createMachOObjectFile(Buff.release()).get())); DisassembleInputMachO2(Filename, MachOOF.get()); } @@ -220,21 +214,22 @@ static void DisassembleInputMachO2(StringRef Filename, // GetTarget prints out stuff. return; } - OwningPtr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo()); - OwningPtr<MCInstrAnalysis> - InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo.get())); + std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo()); + std::unique_ptr<MCInstrAnalysis> InstrAnalysis( + TheTarget->createMCInstrAnalysis(InstrInfo.get())); // Set up disassembler. - OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); - OwningPtr<const MCAsmInfo> AsmInfo( + std::unique_ptr<const MCRegisterInfo> MRI( + TheTarget->createMCRegInfo(TripleName)); + std::unique_ptr<const MCAsmInfo> AsmInfo( TheTarget->createMCAsmInfo(*MRI, TripleName)); - OwningPtr<const MCSubtargetInfo> - STI(TheTarget->createMCSubtargetInfo(TripleName, "", "")); - OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); + std::unique_ptr<const MCSubtargetInfo> STI( + TheTarget->createMCSubtargetInfo(TripleName, "", "")); + std::unique_ptr<const MCDisassembler> DisAsm( + TheTarget->createMCDisassembler(*STI)); int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); - OwningPtr<MCInstPrinter> - IP(TheTarget->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *InstrInfo, - *MRI, *STI)); + std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( + AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI, *STI)); if (!InstrAnalysis || !AsmInfo || !STI || !DisAsm || !IP) { errs() << "error: couldn't initialize disassembler for target " @@ -270,9 +265,8 @@ static void DisassembleInputMachO2(StringRef Filename, else BaseAddress = BaseSegmentAddress; DiceTable Dices; - error_code ec; for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices(); - DI != DE; DI.increment(ec)){ + DI != DE; ++DI) { uint32_t Offset; DI->getOffset(Offset); Dices.push_back(std::make_pair(BaseAddress + Offset, *DI)); @@ -285,19 +279,19 @@ static void DisassembleInputMachO2(StringRef Filename, raw_ostream &DebugOut = nulls(); #endif - OwningPtr<DIContext> diContext; + std::unique_ptr<DIContext> diContext; ObjectFile *DbgObj = MachOOF; // Try to find debug info and set up the DIContext for it. if (UseDbg) { // A separate DSym file path was specified, parse it as a macho file, // get the sections and supply it to the section name parsing machinery. if (!DSYMFile.empty()) { - OwningPtr<MemoryBuffer> Buf; + std::unique_ptr<MemoryBuffer> Buf; if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile, Buf)) { errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n'; return; } - DbgObj = ObjectFile::createMachOObjectFile(Buf.take()); + DbgObj = ObjectFile::createMachOObjectFile(Buf.release()).get(); } // Setup the DIContext @@ -328,16 +322,14 @@ static void DisassembleInputMachO2(StringRef Filename, bool symbolTableWorked = false; // Parse relocations. - std::vector<std::pair<uint64_t, SymbolRef> > Relocs; - error_code ec; - for (relocation_iterator RI = Sections[SectIdx].begin_relocations(), - RE = Sections[SectIdx].end_relocations(); RI != RE; RI.increment(ec)) { + std::vector<std::pair<uint64_t, SymbolRef>> Relocs; + for (const RelocationRef &Reloc : Sections[SectIdx].relocations()) { uint64_t RelocOffset, SectionAddress; - RI->getOffset(RelocOffset); + Reloc.getOffset(RelocOffset); Sections[SectIdx].getAddress(SectionAddress); RelocOffset -= SectionAddress; - symbol_iterator RelocSym = RI->getSymbol(); + symbol_iterator RelocSym = Reloc.getSymbol(); Relocs.push_back(std::make_pair(RelocOffset, *RelocSym)); } diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 9bc092e..729fcba 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -17,7 +17,6 @@ //===----------------------------------------------------------------------===// #include "llvm-objdump.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" @@ -149,10 +148,11 @@ YAMLCFG("yaml-cfg", static StringRef ToolName; -bool llvm::error(error_code ec) { - if (!ec) return false; +bool llvm::error(error_code EC) { + if (!EC) + return false; - outs() << ToolName << ": error reading file: " << ec.message() << ".\n"; + outs() << ToolName << ": error reading file: " << EC.message() << ".\n"; outs().flush(); return true; } @@ -166,7 +166,7 @@ static const Target *getTarget(const ObjectFile *Obj = NULL) { // TheTriple defaults to ELF, and COFF doesn't have an environment: // the best we can do here is indicate that it is mach-o. if (Obj->isMachO()) - TheTriple.setEnvironment(Triple::MachO); + TheTriple.setObjectFormat(Triple::MachO); } } else TheTriple.setTriple(Triple::normalize(TripleName)); @@ -191,7 +191,7 @@ static void emitDOTFile(const char *FileName, const MCFunction &f, MCInstPrinter *IP) { // Start a new dot file. std::string Error; - raw_fd_ostream Out(FileName, Error); + raw_fd_ostream Out(FileName, Error, sys::fs::F_Text); if (!Error.empty()) { errs() << "llvm-objdump: warning: " << Error << '\n'; return; @@ -281,60 +281,62 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { FeaturesStr = Features.getString(); } - OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); + std::unique_ptr<const MCRegisterInfo> MRI( + TheTarget->createMCRegInfo(TripleName)); if (!MRI) { errs() << "error: no register info for target " << TripleName << "\n"; return; } // Set up disassembler. - OwningPtr<const MCAsmInfo> AsmInfo( - TheTarget->createMCAsmInfo(*MRI, TripleName)); + std::unique_ptr<const MCAsmInfo> AsmInfo( + TheTarget->createMCAsmInfo(*MRI, TripleName)); if (!AsmInfo) { errs() << "error: no assembly info for target " << TripleName << "\n"; return; } - OwningPtr<const MCSubtargetInfo> STI( - TheTarget->createMCSubtargetInfo(TripleName, "", FeaturesStr)); + std::unique_ptr<const MCSubtargetInfo> STI( + TheTarget->createMCSubtargetInfo(TripleName, "", FeaturesStr)); if (!STI) { errs() << "error: no subtarget info for target " << TripleName << "\n"; return; } - OwningPtr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo()); + std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo()); if (!MII) { errs() << "error: no instruction info for target " << TripleName << "\n"; return; } - OwningPtr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); + std::unique_ptr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); if (!DisAsm) { errs() << "error: no disassembler for target " << TripleName << "\n"; return; } - OwningPtr<const MCObjectFileInfo> MOFI; - OwningPtr<MCContext> Ctx; + std::unique_ptr<const MCObjectFileInfo> MOFI; + std::unique_ptr<MCContext> Ctx; if (Symbolize) { MOFI.reset(new MCObjectFileInfo); Ctx.reset(new MCContext(AsmInfo.get(), MRI.get(), MOFI.get())); - OwningPtr<MCRelocationInfo> RelInfo( - TheTarget->createMCRelocationInfo(TripleName, *Ctx.get())); + std::unique_ptr<MCRelocationInfo> RelInfo( + TheTarget->createMCRelocationInfo(TripleName, *Ctx.get())); if (RelInfo) { - OwningPtr<MCSymbolizer> Symzer( - MCObjectSymbolizer::createObjectSymbolizer(*Ctx.get(), RelInfo, Obj)); + std::unique_ptr<MCSymbolizer> Symzer( + MCObjectSymbolizer::createObjectSymbolizer(*Ctx.get(), + std::move(RelInfo), Obj)); if (Symzer) - DisAsm->setSymbolizer(Symzer); + DisAsm->setSymbolizer(std::move(Symzer)); } } - OwningPtr<const MCInstrAnalysis> - MIA(TheTarget->createMCInstrAnalysis(MII.get())); + std::unique_ptr<const MCInstrAnalysis> MIA( + TheTarget->createMCInstrAnalysis(MII.get())); int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); - OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( + std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI)); if (!IP) { errs() << "error: no instruction printer for target " << TripleName @@ -343,9 +345,9 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { } if (CFG || !YAMLCFG.empty()) { - OwningPtr<MCObjectDisassembler> OD( - new MCObjectDisassembler(*Obj, *DisAsm, *MIA)); - OwningPtr<MCModule> Mod(OD->buildModule(/* withCFG */ true)); + std::unique_ptr<MCObjectDisassembler> OD( + new MCObjectDisassembler(*Obj, *DisAsm, *MIA)); + std::unique_ptr<MCModule> Mod(OD->buildModule(/* withCFG */ true)); for (MCModule::const_atom_iterator AI = Mod->atom_begin(), AE = Mod->atom_end(); AI != AE; ++AI) { @@ -372,7 +374,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { } if (!YAMLCFG.empty()) { std::string Error; - raw_fd_ostream YAMLOut(YAMLCFG.c_str(), Error); + raw_fd_ostream YAMLOut(YAMLCFG.c_str(), Error, sys::fs::F_Text); if (!Error.empty()) { errs() << ToolName << ": warning: " << Error << '\n'; return; @@ -381,33 +383,51 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { } } + StringRef Fmt = Obj->getBytesInAddress() > 4 ? "\t\t%016" PRIx64 ": " : + "\t\t\t%08" PRIx64 ": "; + + // Create a mapping, RelocSecs = SectionRelocMap[S], where sections + // in RelocSecs contain the relocations for section S. + error_code EC; + std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap; + for (const SectionRef &Section : Obj->sections()) { + section_iterator Sec2 = Section.getRelocatedSection(); + if (Sec2 != Obj->section_end()) + SectionRelocMap[*Sec2].push_back(Section); + } - error_code ec; - for (section_iterator i = Obj->begin_sections(), - e = Obj->end_sections(); - i != e; i.increment(ec)) { - if (error(ec)) break; - bool text; - if (error(i->isText(text))) break; - if (!text) continue; + for (const SectionRef &Section : Obj->sections()) { + bool Text; + if (error(Section.isText(Text))) + break; + if (!Text) + continue; uint64_t SectionAddr; - if (error(i->getAddress(SectionAddr))) break; + if (error(Section.getAddress(SectionAddr))) + break; + + uint64_t SectSize; + if (error(Section.getSize(SectSize))) + break; // Make a list of all the symbols in this section. - std::vector<std::pair<uint64_t, StringRef> > Symbols; - for (symbol_iterator si = Obj->begin_symbols(), - se = Obj->end_symbols(); - si != se; si.increment(ec)) { + std::vector<std::pair<uint64_t, StringRef>> Symbols; + for (const SymbolRef &Symbol : Obj->symbols()) { bool contains; - if (!error(i->containsSymbol(*si, contains)) && contains) { + if (!error(Section.containsSymbol(Symbol, contains)) && contains) { uint64_t Address; - if (error(si->getAddress(Address))) break; - if (Address == UnknownAddressOrSize) continue; + if (error(Symbol.getAddress(Address))) + break; + if (Address == UnknownAddressOrSize) + continue; Address -= SectionAddr; + if (Address >= SectSize) + continue; StringRef Name; - if (error(si->getName(Name))) break; + if (error(Symbol.getName(Name))) + break; Symbols.push_back(std::make_pair(Address, Name)); } } @@ -418,11 +438,10 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // Make a list of all the relocations for this section. std::vector<RelocationRef> Rels; if (InlineRelocs) { - for (relocation_iterator ri = i->begin_relocations(), - re = i->end_relocations(); - ri != re; ri.increment(ec)) { - if (error(ec)) break; - Rels.push_back(*ri); + for (const SectionRef &RelocSec : SectionRelocMap[Section]) { + for (const RelocationRef &Reloc : RelocSec.relocations()) { + Rels.push_back(Reloc); + } } } @@ -430,13 +449,13 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { std::sort(Rels.begin(), Rels.end(), RelocAddressLess); StringRef SegmentName = ""; - if (const MachOObjectFile *MachO = - dyn_cast<const MachOObjectFile>(Obj)) { - DataRefImpl DR = i->getRawDataRefImpl(); + if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj)) { + DataRefImpl DR = Section.getRawDataRefImpl(); SegmentName = MachO->getSectionFinalSegmentName(DR); } StringRef name; - if (error(i->getName(name))) break; + if (error(Section.getName(name))) + break; outs() << "Disassembly of section "; if (!SegmentName.empty()) outs() << SegmentName << ","; @@ -452,12 +471,11 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { raw_svector_ostream CommentStream(Comments); StringRef Bytes; - if (error(i->getContents(Bytes))) break; + if (error(Section.getContents(Bytes))) + break; StringRefMemoryObject memoryObject(Bytes, SectionAddr); uint64_t Size; uint64_t Index; - uint64_t SectSize; - if (error(i->getSize(SectSize))) break; std::vector<RelocationRef>::const_iterator rel_cur = Rels.begin(); std::vector<RelocationRef>::const_iterator rel_end = Rels.end(); @@ -479,9 +497,9 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { outs() << '\n' << Symbols[si].second << ":\n"; #ifndef NDEBUG - raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); + raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); #else - raw_ostream &DebugOut = nulls(); + raw_ostream &DebugOut = nulls(); #endif for (Index = Start; Index < End; Index += Size) { @@ -522,7 +540,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (error(rel_cur->getTypeName(name))) goto skip_print_rel; if (error(rel_cur->getValueString(val))) goto skip_print_rel; - outs() << format("\t\t\t%8" PRIx64 ": ", SectionAddr + addr) << name + outs() << format(Fmt.data(), SectionAddr + addr) << name << "\t" << val << "\n"; skip_print_rel: @@ -533,76 +551,82 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { } } -static void PrintRelocations(const ObjectFile *o) { - error_code ec; - for (section_iterator si = o->begin_sections(), se = o->end_sections(); - si != se; si.increment(ec)){ - if (error(ec)) return; - if (si->begin_relocations() == si->end_relocations()) +static void PrintRelocations(const ObjectFile *Obj) { + StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : + "%08" PRIx64; + for (const SectionRef &Section : Obj->sections()) { + if (Section.relocation_begin() == Section.relocation_end()) continue; StringRef secname; - if (error(si->getName(secname))) continue; + if (error(Section.getName(secname))) + continue; outs() << "RELOCATION RECORDS FOR [" << secname << "]:\n"; - for (relocation_iterator ri = si->begin_relocations(), - re = si->end_relocations(); - ri != re; ri.increment(ec)) { - if (error(ec)) return; - + for (const RelocationRef &Reloc : Section.relocations()) { bool hidden; uint64_t address; SmallString<32> relocname; SmallString<32> valuestr; - if (error(ri->getHidden(hidden))) continue; - if (hidden) continue; - if (error(ri->getTypeName(relocname))) continue; - if (error(ri->getOffset(address))) continue; - if (error(ri->getValueString(valuestr))) continue; - outs() << address << " " << relocname << " " << valuestr << "\n"; + if (error(Reloc.getHidden(hidden))) + continue; + if (hidden) + continue; + if (error(Reloc.getTypeName(relocname))) + continue; + if (error(Reloc.getOffset(address))) + continue; + if (error(Reloc.getValueString(valuestr))) + continue; + outs() << format(Fmt.data(), address) << " " << relocname << " " + << valuestr << "\n"; } outs() << "\n"; } } -static void PrintSectionHeaders(const ObjectFile *o) { +static void PrintSectionHeaders(const ObjectFile *Obj) { outs() << "Sections:\n" "Idx Name Size Address Type\n"; - error_code ec; unsigned i = 0; - for (section_iterator si = o->begin_sections(), se = o->end_sections(); - si != se; si.increment(ec)) { - if (error(ec)) return; + for (const SectionRef &Section : Obj->sections()) { StringRef Name; - if (error(si->getName(Name))) return; + if (error(Section.getName(Name))) + return; uint64_t Address; - if (error(si->getAddress(Address))) return; + if (error(Section.getAddress(Address))) + return; uint64_t Size; - if (error(si->getSize(Size))) return; + if (error(Section.getSize(Size))) + return; bool Text, Data, BSS; - if (error(si->isText(Text))) return; - if (error(si->isData(Data))) return; - if (error(si->isBSS(BSS))) return; + if (error(Section.isText(Text))) + return; + if (error(Section.isData(Data))) + return; + if (error(Section.isBSS(BSS))) + return; std::string Type = (std::string(Text ? "TEXT " : "") + (Data ? "DATA " : "") + (BSS ? "BSS" : "")); - outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n", - i, Name.str().c_str(), Size, Address, Type.c_str()); + outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n", i, + Name.str().c_str(), Size, Address, Type.c_str()); ++i; } } -static void PrintSectionContents(const ObjectFile *o) { - error_code ec; - for (section_iterator si = o->begin_sections(), - se = o->end_sections(); - si != se; si.increment(ec)) { - if (error(ec)) return; +static void PrintSectionContents(const ObjectFile *Obj) { + error_code EC; + for (const SectionRef &Section : Obj->sections()) { StringRef Name; StringRef Contents; uint64_t BaseAddr; bool BSS; - if (error(si->getName(Name))) continue; - if (error(si->getContents(Contents))) continue; - if (error(si->getAddress(BaseAddr))) continue; - if (error(si->isBSS(BSS))) continue; + if (error(Section.getName(Name))) + continue; + if (error(Section.getContents(Contents))) + continue; + if (error(Section.getAddress(BaseAddr))) + continue; + if (error(Section.isBSS(BSS))) + continue; outs() << "Contents of section " << Name << ":\n"; if (BSS) { @@ -646,8 +670,7 @@ static void PrintCOFFSymbolTable(const COFFObjectFile *coff) { for (int i = 0, e = header->NumberOfSymbols; i != e; ++i) { if (aux_count--) { // Figure out which type of aux this is. - if (symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC - && symbol->Value == 0) { // Section definition. + if (symbol->isSectionDefinition()) { // Section definition. const coff_aux_section_definition *asd; if (error(coff->getAuxSymbol<coff_aux_section_definition>(i, asd))) return; @@ -682,78 +705,79 @@ static void PrintCOFFSymbolTable(const COFFObjectFile *coff) { static void PrintSymbolTable(const ObjectFile *o) { outs() << "SYMBOL TABLE:\n"; - if (const COFFObjectFile *coff = dyn_cast<const COFFObjectFile>(o)) + if (const COFFObjectFile *coff = dyn_cast<const COFFObjectFile>(o)) { PrintCOFFSymbolTable(coff); - else { - error_code ec; - for (symbol_iterator si = o->begin_symbols(), - se = o->end_symbols(); si != se; si.increment(ec)) { - if (error(ec)) return; - StringRef Name; - uint64_t Address; - SymbolRef::Type Type; - uint64_t Size; - uint32_t Flags; - section_iterator Section = o->end_sections(); - if (error(si->getName(Name))) continue; - if (error(si->getAddress(Address))) continue; - if (error(si->getFlags(Flags))) continue; - if (error(si->getType(Type))) continue; - if (error(si->getSize(Size))) continue; - if (error(si->getSection(Section))) continue; - - bool Global = Flags & SymbolRef::SF_Global; - bool Weak = Flags & SymbolRef::SF_Weak; - bool Absolute = Flags & SymbolRef::SF_Absolute; - - if (Address == UnknownAddressOrSize) - Address = 0; - if (Size == UnknownAddressOrSize) - Size = 0; - char GlobLoc = ' '; - if (Type != SymbolRef::ST_Unknown) - GlobLoc = Global ? 'g' : 'l'; - char Debug = (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File) - ? 'd' : ' '; - char FileFunc = ' '; - if (Type == SymbolRef::ST_File) - FileFunc = 'f'; - else if (Type == SymbolRef::ST_Function) - FileFunc = 'F'; - - const char *Fmt = o->getBytesInAddress() > 4 ? "%016" PRIx64 : - "%08" PRIx64; - - outs() << format(Fmt, Address) << " " - << GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' ' - << (Weak ? 'w' : ' ') // Weak? - << ' ' // Constructor. Not supported yet. - << ' ' // Warning. Not supported yet. - << ' ' // Indirect reference to another symbol. - << Debug // Debugging (d) or dynamic (D) symbol. - << FileFunc // Name of function (F), file (f) or object (O). - << ' '; - if (Absolute) - outs() << "*ABS*"; - else if (Section == o->end_sections()) - outs() << "*UND*"; - else { - if (const MachOObjectFile *MachO = - dyn_cast<const MachOObjectFile>(o)) { - DataRefImpl DR = Section->getRawDataRefImpl(); - StringRef SegmentName = MachO->getSectionFinalSegmentName(DR); - outs() << SegmentName << ","; - } - StringRef SectionName; - if (error(Section->getName(SectionName))) - SectionName = ""; - outs() << SectionName; + return; + } + for (const SymbolRef &Symbol : o->symbols()) { + StringRef Name; + uint64_t Address; + SymbolRef::Type Type; + uint64_t Size; + uint32_t Flags = Symbol.getFlags(); + section_iterator Section = o->section_end(); + if (error(Symbol.getName(Name))) + continue; + if (error(Symbol.getAddress(Address))) + continue; + if (error(Symbol.getType(Type))) + continue; + if (error(Symbol.getSize(Size))) + continue; + if (error(Symbol.getSection(Section))) + continue; + + bool Global = Flags & SymbolRef::SF_Global; + bool Weak = Flags & SymbolRef::SF_Weak; + bool Absolute = Flags & SymbolRef::SF_Absolute; + + if (Address == UnknownAddressOrSize) + Address = 0; + if (Size == UnknownAddressOrSize) + Size = 0; + char GlobLoc = ' '; + if (Type != SymbolRef::ST_Unknown) + GlobLoc = Global ? 'g' : 'l'; + char Debug = (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File) + ? 'd' : ' '; + char FileFunc = ' '; + if (Type == SymbolRef::ST_File) + FileFunc = 'f'; + else if (Type == SymbolRef::ST_Function) + FileFunc = 'F'; + + const char *Fmt = o->getBytesInAddress() > 4 ? "%016" PRIx64 : + "%08" PRIx64; + + outs() << format(Fmt, Address) << " " + << GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' ' + << (Weak ? 'w' : ' ') // Weak? + << ' ' // Constructor. Not supported yet. + << ' ' // Warning. Not supported yet. + << ' ' // Indirect reference to another symbol. + << Debug // Debugging (d) or dynamic (D) symbol. + << FileFunc // Name of function (F), file (f) or object (O). + << ' '; + if (Absolute) { + outs() << "*ABS*"; + } else if (Section == o->section_end()) { + outs() << "*UND*"; + } else { + if (const MachOObjectFile *MachO = + dyn_cast<const MachOObjectFile>(o)) { + DataRefImpl DR = Section->getRawDataRefImpl(); + StringRef SegmentName = MachO->getSectionFinalSegmentName(DR); + outs() << SegmentName << ","; } - outs() << '\t' - << format("%08" PRIx64 " ", Size) - << Name - << '\n'; + StringRef SectionName; + if (error(Section->getName(SectionName))) + SectionName = ""; + outs() << SectionName; } + outs() << '\t' + << format("%08" PRIx64 " ", Size) + << Name + << '\n'; } } @@ -801,13 +825,13 @@ 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->begin_children(), - e = a->end_children(); i != e; ++i) { - OwningPtr<Binary> child; - if (error_code ec = i->getAsBinary(child)) { + for (Archive::child_iterator i = a->child_begin(), e = a->child_end(); i != e; + ++i) { + std::unique_ptr<Binary> child; + if (error_code EC = i->getAsBinary(child)) { // Ignore non-object files. - if (ec != object_error::invalid_file_type) - errs() << ToolName << ": '" << a->getFileName() << "': " << ec.message() + if (EC != object_error::invalid_file_type) + errs() << ToolName << ": '" << a->getFileName() << "': " << EC.message() << ".\n"; continue; } @@ -833,11 +857,12 @@ static void DumpInput(StringRef file) { } // Attempt to open the binary. - OwningPtr<Binary> binary; - if (error_code ec = createBinary(file, binary)) { - errs() << ToolName << ": '" << file << "': " << ec.message() << ".\n"; + ErrorOr<Binary *> BinaryOrErr = createBinary(file); + if (error_code EC = BinaryOrErr.getError()) { + errs() << ToolName << ": '" << file << "': " << EC.message() << ".\n"; return; } + std::unique_ptr<Binary> binary(BinaryOrErr.get()); if (Archive *a = dyn_cast<Archive>(binary.get())) DumpArchive(a); diff --git a/tools/llvm-profdata/CMakeLists.txt b/tools/llvm-profdata/CMakeLists.txt new file mode 100644 index 0000000..3529114 --- /dev/null +++ b/tools/llvm-profdata/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_LINK_COMPONENTS profiledata support) + +add_llvm_tool(llvm-profdata + llvm-profdata.cpp + ) diff --git a/tools/llvm-profdata/LLVMBuild.txt b/tools/llvm-profdata/LLVMBuild.txt new file mode 100644 index 0000000..bbc1ea6 --- /dev/null +++ b/tools/llvm-profdata/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/llvm-profdata/LLVMBuild.txt ----------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-profdata +parent = Tools +required_libraries = ProfileData Support diff --git a/tools/llvm-profdata/Makefile b/tools/llvm-profdata/Makefile new file mode 100644 index 0000000..6f8c162 --- /dev/null +++ b/tools/llvm-profdata/Makefile @@ -0,0 +1,17 @@ +##===- tools/llvm-profdata/Makefile ------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := llvm-profdata +LINK_COMPONENTS := profiledata support + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS := 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp new file mode 100644 index 0000000..397b523 --- /dev/null +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -0,0 +1,191 @@ +//===- llvm-profdata.cpp - LLVM profile data tool -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// llvm-profdata merges .profdata files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/ProfileData/InstrProfReader.h" +#include "llvm/ProfileData/InstrProfWriter.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static void exitWithError(const Twine &Message, StringRef Whence = "") { + errs() << "error: "; + if (!Whence.empty()) + errs() << Whence << ": "; + errs() << Message << "\n"; + ::exit(1); +} + +int merge_main(int argc, const char *argv[]) { + cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore, + cl::desc("<filenames...>")); + + cl::opt<std::string> OutputFilename("output", cl::value_desc("output"), + cl::init("-"), + cl::desc("Output file")); + cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), + cl::aliasopt(OutputFilename)); + + cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); + + if (OutputFilename.empty()) + OutputFilename = "-"; + + std::string ErrorInfo; + // FIXME: F_Text would be available if line_iterator could accept CRLF. + raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_None); + if (!ErrorInfo.empty()) + exitWithError(ErrorInfo, OutputFilename); + + InstrProfWriter Writer; + for (const auto &Filename : Inputs) { + std::unique_ptr<InstrProfReader> Reader; + if (error_code ec = InstrProfReader::create(Filename, Reader)) + exitWithError(ec.message(), Filename); + + for (const auto &I : *Reader) + if (error_code EC = Writer.addFunctionCounts(I.Name, I.Hash, I.Counts)) + errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n"; + if (Reader->hasError()) + exitWithError(Reader->getError().message(), Filename); + } + Writer.write(Output); + + return 0; +} + +int show_main(int argc, const char *argv[]) { + cl::opt<std::string> Filename(cl::Positional, cl::Required, + cl::desc("<profdata-file>")); + + cl::opt<bool> ShowCounts("counts", cl::init(false), + cl::desc("Show counter 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", + cl::desc("Details for matching functions")); + + cl::opt<std::string> OutputFilename("output", cl::value_desc("output"), + cl::init("-"), + cl::desc("Output file")); + cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), + cl::aliasopt(OutputFilename)); + + cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); + + std::unique_ptr<InstrProfReader> Reader; + if (error_code EC = InstrProfReader::create(Filename, Reader)) + exitWithError(EC.message(), Filename); + + if (OutputFilename.empty()) + OutputFilename = "-"; + + std::string ErrorInfo; + raw_fd_ostream OS(OutputFilename.data(), ErrorInfo, sys::fs::F_Text); + if (!ErrorInfo.empty()) + exitWithError(ErrorInfo, OutputFilename); + + if (ShowAllFunctions && !ShowFunction.empty()) + errs() << "warning: -function argument ignored: showing all functions\n"; + + uint64_t MaxFunctionCount = 0, MaxBlockCount = 0; + size_t ShownFunctions = 0, TotalFunctions = 0; + for (const auto &Func : *Reader) { + bool Show = ShowAllFunctions || + (!ShowFunction.empty() && + Func.Name.find(ShowFunction) != Func.Name.npos); + + ++TotalFunctions; + if (Func.Counts[0] > MaxFunctionCount) + MaxFunctionCount = Func.Counts[0]; + + 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 (Show && ShowCounts) + OS << "]\n"; + } + if (Reader->hasError()) + exitWithError(Reader->getError().message(), Filename); + + if (ShowAllFunctions || !ShowFunction.empty()) + OS << "Functions shown: " << ShownFunctions << "\n"; + OS << "Total functions: " << TotalFunctions << "\n"; + OS << "Maximum function count: " << MaxFunctionCount << "\n"; + OS << "Maximum internal block count: " << MaxBlockCount << "\n"; + return 0; +} + +int main(int argc, const char *argv[]) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + StringRef ProgName(sys::path::filename(argv[0])); + if (argc > 1) { + int (*func)(int, const char *[]) = 0; + + if (strcmp(argv[1], "merge") == 0) + func = merge_main; + else if (strcmp(argv[1], "show") == 0) + func = show_main; + + if (func) { + std::string Invocation(ProgName.str() + " " + argv[1]); + argv[1] = Invocation.c_str(); + return func(argc - 1, argv + 1); + } + + if (strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "-help") == 0 || + strcmp(argv[1], "--help") == 0) { + + errs() << "OVERVIEW: LLVM profile data tools\n\n" + << "USAGE: " << ProgName << " <command> [args...]\n" + << "USAGE: " << ProgName << " <command> -help\n\n" + << "Available commands: merge, show\n"; + return 0; + } + } + + if (argc < 2) + errs() << ProgName << ": No command specified!\n"; + else + errs() << ProgName << ": Unknown command!\n"; + + errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n"; + return 1; +} diff --git a/tools/llvm-readobj/ARMAttributeParser.cpp b/tools/llvm-readobj/ARMAttributeParser.cpp new file mode 100644 index 0000000..5857547 --- /dev/null +++ b/tools/llvm-readobj/ARMAttributeParser.cpp @@ -0,0 +1,639 @@ +//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ARMAttributeParser.h" +#include "StreamWriter.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/LEB128.h" + +using namespace llvm; +using namespace llvm::ARMBuildAttrs; + + +static const EnumEntry<unsigned> TagNames[] = { + { "Tag_File", ARMBuildAttrs::File }, + { "Tag_Section", ARMBuildAttrs::Section }, + { "Tag_Symbol", ARMBuildAttrs::Symbol }, +}; + +template <typename type_, size_t size_> +size_t countof(const type_ (&)[size_]) { + return size_; +} + +namespace llvm { +#define ATTRIBUTE_HANDLER(Attr_) \ + { ARMBuildAttrs::Attr_, &ARMAttributeParser::Attr_ } + +const ARMAttributeParser::DisplayHandler +ARMAttributeParser::DisplayRoutines[] = { + { ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::StringAttribute, }, + { ARMBuildAttrs::CPU_name, &ARMAttributeParser::StringAttribute }, + ATTRIBUTE_HANDLER(CPU_arch), + ATTRIBUTE_HANDLER(CPU_arch_profile), + ATTRIBUTE_HANDLER(ARM_ISA_use), + ATTRIBUTE_HANDLER(THUMB_ISA_use), + ATTRIBUTE_HANDLER(FP_arch), + ATTRIBUTE_HANDLER(WMMX_arch), + ATTRIBUTE_HANDLER(Advanced_SIMD_arch), + ATTRIBUTE_HANDLER(PCS_config), + ATTRIBUTE_HANDLER(ABI_PCS_R9_use), + ATTRIBUTE_HANDLER(ABI_PCS_RW_data), + ATTRIBUTE_HANDLER(ABI_PCS_RO_data), + ATTRIBUTE_HANDLER(ABI_PCS_GOT_use), + ATTRIBUTE_HANDLER(ABI_PCS_wchar_t), + ATTRIBUTE_HANDLER(ABI_FP_rounding), + ATTRIBUTE_HANDLER(ABI_FP_denormal), + ATTRIBUTE_HANDLER(ABI_FP_exceptions), + ATTRIBUTE_HANDLER(ABI_FP_user_exceptions), + ATTRIBUTE_HANDLER(ABI_FP_number_model), + ATTRIBUTE_HANDLER(ABI_align_needed), + ATTRIBUTE_HANDLER(ABI_align_preserved), + ATTRIBUTE_HANDLER(ABI_enum_size), + ATTRIBUTE_HANDLER(ABI_HardFP_use), + ATTRIBUTE_HANDLER(ABI_VFP_args), + ATTRIBUTE_HANDLER(ABI_WMMX_args), + ATTRIBUTE_HANDLER(ABI_optimization_goals), + ATTRIBUTE_HANDLER(ABI_FP_optimization_goals), + ATTRIBUTE_HANDLER(compatibility), + ATTRIBUTE_HANDLER(CPU_unaligned_access), + ATTRIBUTE_HANDLER(FP_HP_extension), + ATTRIBUTE_HANDLER(ABI_FP_16bit_format), + ATTRIBUTE_HANDLER(MPextension_use), + ATTRIBUTE_HANDLER(DIV_use), + ATTRIBUTE_HANDLER(T2EE_use), + ATTRIBUTE_HANDLER(Virtualization_use), + ATTRIBUTE_HANDLER(nodefaults) +}; + +#undef ATTRIBUTE_HANDLER + +uint64_t ARMAttributeParser::ParseInteger(const uint8_t *Data, + uint32_t &Offset) { + unsigned Length; + uint64_t Value = decodeULEB128(Data + Offset, &Length); + Offset = Offset + Length; + return Value; +} + +StringRef ARMAttributeParser::ParseString(const uint8_t *Data, + uint32_t &Offset) { + const char *String = reinterpret_cast<const char*>(Data + Offset); + size_t Length = std::strlen(String); + Offset = Offset + Length + 1; + return StringRef(String, Length); +} + +void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + SW.printNumber(ARMBuildAttrs::AttrTypeAsString(Tag), + ParseInteger(Data, Offset)); +} + +void ARMAttributeParser::StringAttribute(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false); + + DictScope AS(SW, "Attribute"); + SW.printNumber("Tag", Tag); + if (!TagName.empty()) + SW.printString("TagName", TagName); + SW.printString("Value", ParseString(Data, Offset)); +} + +void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value, + StringRef ValueDesc) { + StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false); + + DictScope AS(SW, "Attribute"); + SW.printNumber("Tag", Tag); + SW.printNumber("Value", Value); + if (!TagName.empty()) + SW.printString("TagName", TagName); + if (!ValueDesc.empty()) + SW.printString("Description", ValueDesc); +} + +void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *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" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + uint64_t Encoded = ParseInteger(Data, Offset); + + StringRef Profile; + switch (Encoded) { + default: Profile = "Unknown"; break; + case 'A': Profile = "Application"; break; + case 'R': Profile = "Real-time"; break; + case 'M': Profile = "Microcontroller"; break; + case 'S': Profile = "Classic"; break; + case '0': Profile = "None"; break; + } + + PrintAttribute(Tag, Encoded, Profile); +} + +void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4", + "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +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" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004", + "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "v6", "Static Base", "TLS", "Unused" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Absolute", "PC-relative", "SB-relative", "Not Permitted" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Absolute", "PC-relative", "Not Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Direct", "GOT-Indirect" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "IEEE-754", "Runtime" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Unsupported", "IEEE-754", "Sign Only" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "IEEE-754" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag, + const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "IEEE-754" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "Finite Only", "RTABI", "IEEE-754" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved" + }; + + uint64_t Value = ParseInteger(Data, Offset); + + std::string Description; + if (Value < countof(Strings)) + Description = std::string(Strings[Value]); + else if (Value <= 12) + Description = std::string("8-byte alignment, ") + utostr(1 << Value) + + std::string("-byte extended alignment"); + else + Description = "Invalid"; + + PrintAttribute(Tag, Value, Description); +} + +void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Required", "8-byte data alignment", "8-byte data and code alignment", + "Reserved" + }; + + uint64_t Value = ParseInteger(Data, Offset); + + std::string Description; + if (Value < countof(Strings)) + Description = std::string(Strings[Value]); + else if (Value <= 12) + Description = std::string("8-byte stack alignment, ") + utostr(1 << Value) + + std::string("-byte data alignment"); + else + Description = "Invalid"; + + PrintAttribute(Tag, Value, Description); +} + +void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "Packed", "Int32", "External Int32" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "AAPCS", "AAPCS VFP", "Custom", "Not Permitted" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "AAPCS", "iWMMX", "Custom" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_optimization_goals(AttrType Tag, + const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging", + "Best Debugging" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag, + const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Accuracy", + "Best Accuracy" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + uint64_t Integer = ParseInteger(Data, Offset); + StringRef String = ParseString(Data, Offset); + + DictScope AS(SW, "Attribute"); + SW.printNumber("Tag", Tag); + SW.startLine() << "Value: " << Integer << ", " << String << '\n'; + SW.printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false)); + switch (Integer) { + case 0: + SW.printString("Description", StringRef("No Specific Requirements")); + break; + case 1: + SW.printString("Description", StringRef("AEABI Conformant")); + break; + default: + SW.printString("Description", StringRef("AEABI Non-Conformant")); + break; + } +} + +void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "v6-style" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "If Available", "Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "If Available", "Not Permitted", "Permitted" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { "Not Permitted", "Permitted" }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *Strings[] = { + "Not Permitted", "TrustZone", "Virtualization Extensions", + "TrustZone + Virtualization Extensions" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = (Value < countof(Strings)) ? Strings[Value] : NULL; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::nodefaults(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + uint64_t Value = ParseInteger(Data, Offset); + PrintAttribute(Tag, Value, "Unspecified Tags UNDEFINED"); +} + +void ARMAttributeParser::ParseIndexList(const uint8_t *Data, uint32_t &Offset, + SmallVectorImpl<uint8_t> &IndexList) { + for (;;) { + unsigned Length; + uint64_t Value = decodeULEB128(Data + Offset, &Length); + Offset = Offset + Length; + if (Value == 0) + break; + IndexList.push_back(Value); + } +} + +void ARMAttributeParser::ParseAttributeList(const uint8_t *Data, + uint32_t &Offset, uint32_t Length) { + while (Offset < Length) { + unsigned Length; + uint64_t Tag = decodeULEB128(Data + Offset, &Length); + Offset += Length; + + bool Handled = false; + for (unsigned AHI = 0, AHE = countof(DisplayRoutines); + AHI != AHE && !Handled; ++AHI) { + if (DisplayRoutines[AHI].Attribute == Tag) { + (this->*DisplayRoutines[AHI].Routine)(ARMBuildAttrs::AttrType(Tag), + Data, Offset); + Handled = true; + break; + } + } + if (!Handled) { + if (Tag < 32) { + errs() << "unhandled AEABI Tag " << Tag + << " (" << ARMBuildAttrs::AttrTypeAsString(Tag) << ")\n"; + continue; + } + + if (Tag % 2 == 0) + IntegerAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset); + else + StringAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset); + } + } +} + +void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) { + uint32_t Offset = sizeof(uint32_t); /* SectionLength */ + + SW.printNumber("SectionLength", Length); + + const char *VendorName = reinterpret_cast<const char*>(Data + Offset); + size_t VendorNameLength = std::strlen(VendorName); + SW.printString("Vendor", StringRef(VendorName, VendorNameLength)); + Offset = Offset + VendorNameLength + 1; + + if (StringRef(VendorName, VendorNameLength).lower() != "aeabi") + return; + + while (Offset < Length) { + /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size + uint8_t Tag = Data[Offset]; + SW.printEnum("Tag", Tag, makeArrayRef(TagNames)); + Offset = Offset + sizeof(Tag); + + uint32_t Size = + *reinterpret_cast<const support::ulittle32_t*>(Data + Offset); + SW.printNumber("Size", Size); + Offset = Offset + sizeof(Size); + + if (Size > Length) { + errs() << "subsection length greater than section length\n"; + return; + } + + StringRef ScopeName, IndexName; + SmallVector<uint8_t, 8> Indicies; + switch (Tag) { + case ARMBuildAttrs::File: + ScopeName = "FileAttributes"; + break; + case ARMBuildAttrs::Section: + ScopeName = "SectionAttributes"; + IndexName = "Sections"; + ParseIndexList(Data, Offset, Indicies); + break; + case ARMBuildAttrs::Symbol: + ScopeName = "SymbolAttributes"; + IndexName = "Symbols"; + ParseIndexList(Data, Offset, Indicies); + break; + default: + errs() << "unrecognised tag: 0x" << utohexstr(Tag) << '\n'; + return; + } + + DictScope ASS(SW, ScopeName); + + if (!Indicies.empty()) + SW.printList(IndexName, Indicies); + + ParseAttributeList(Data, Offset, Length); + } +} + +void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section) { + size_t Offset = 1; + unsigned SectionNumber = 0; + + while (Offset < Section.size()) { + uint32_t SectionLength = + *reinterpret_cast<const support::ulittle32_t*>(Section.data() + Offset); + + SW.startLine() << "Section " << ++SectionNumber << " {\n"; + SW.indent(); + + ParseSubsection(Section.data() + Offset, SectionLength); + Offset = Offset + SectionLength; + + SW.unindent(); + SW.startLine() << "}\n"; + } +} +} + diff --git a/tools/llvm-readobj/ARMAttributeParser.h b/tools/llvm-readobj/ARMAttributeParser.h new file mode 100644 index 0000000..c286251 --- /dev/null +++ b/tools/llvm-readobj/ARMAttributeParser.h @@ -0,0 +1,124 @@ +//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ARMATTRIBUTE_PARSER_H +#define LLVM_READOBJ_ARMATTRIBUTE_PARSER_H + +#include "StreamWriter.h" +#include "llvm/Support/ARMBuildAttributes.h" + +namespace llvm { +class StringRef; + +class ARMAttributeParser { + StreamWriter &SW; + + struct DisplayHandler { + ARMBuildAttrs::AttrType Attribute; + void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType, + const uint8_t *, uint32_t &); + }; + static const DisplayHandler DisplayRoutines[]; + + uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset); + StringRef ParseString(const uint8_t *Data, uint32_t &Offset); + + void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + + void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc); + + void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag, + const uint8_t *Data, uint32_t &Offset); + void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data, + uint32_t &Offset); + + void ParseAttributeList(const uint8_t *Data, uint32_t &Offset, + uint32_t Length); + void ParseIndexList(const uint8_t *Data, uint32_t &Offset, + SmallVectorImpl<uint8_t> &IndexList); + void ParseSubsection(const uint8_t *Data, uint32_t Length); +public: + ARMAttributeParser(StreamWriter &SW) : SW(SW) {} + + void Parse(ArrayRef<uint8_t> Section); +}; + +} + +#endif + diff --git a/tools/llvm-readobj/ARMEHABIPrinter.h b/tools/llvm-readobj/ARMEHABIPrinter.h new file mode 100644 index 0000000..75e2bee --- /dev/null +++ b/tools/llvm-readobj/ARMEHABIPrinter.h @@ -0,0 +1,557 @@ +//===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ARMEHABI_PRINTER_H +#define LLVM_READOBJ_ARMEHABI_PRINTER_H + +#include "Error.h" +#include "StreamWriter.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Support/ARMEHABI.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/type_traits.h" + +namespace { +template <typename type_, size_t N> +size_t countof(const type_ (&)[N]) { + return N; +} +} + +namespace llvm { +namespace ARM { +namespace EHABI { + +class OpcodeDecoder { + StreamWriter &SW; + raw_ostream &OS; + + struct RingEntry { + uint8_t Mask; + uint8_t Value; + void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI); + }; + static const RingEntry Ring[]; + + void Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI); + void Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI); + void Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, unsigned &OI); + void Decode_10011101(const uint8_t *Opcodes, unsigned &OI); + void Decode_10011111(const uint8_t *Opcodes, unsigned &OI); + void Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110000(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110001_0000iiii(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110010_uleb128(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110011_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_101101nn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_11000110_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_11000111_0000iiii(const uint8_t *Opcodes, unsigned &OI); + void Decode_11001000_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_11001001_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI); + void Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI); + + void PrintGPR(uint16_t GPRMask); + void PrintRegisters(uint32_t Mask, StringRef Prefix); + +public: + OpcodeDecoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {} + void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length); +}; + +const OpcodeDecoder::RingEntry OpcodeDecoder::Ring[] = { + { 0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx }, + { 0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx }, + { 0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii }, + { 0xff, 0x9d, &OpcodeDecoder::Decode_10011101 }, + { 0xff, 0x9f, &OpcodeDecoder::Decode_10011111 }, + { 0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn }, + { 0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn }, + { 0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn }, + { 0xff, 0xb0, &OpcodeDecoder::Decode_10110000 }, + { 0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii }, + { 0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128 }, + { 0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc }, + { 0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn }, + { 0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn }, + { 0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc }, + { 0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii }, + { 0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc }, + { 0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc }, + { 0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy }, + { 0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn }, + { 0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn }, + { 0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy }, +}; + +void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; vsp = vsp + %u\n", Opcode, + ((Opcode & 0x3f) << 2) + 4); +} +void OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; vsp = vsp - %u\n", Opcode, + ((Opcode & 0x3f) << 2) + 4); +} +void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + + uint16_t GPRMask = (Opcode1 << 4) | ((Opcode0 & 0x0f) << 12); + SW.startLine() + << format("0x%02X 0x%02X ; %s", + Opcode0, Opcode1, GPRMask ? "pop " : "refuse to unwind"); + if (GPRMask) + PrintGPR(GPRMask); + OS << '\n'; +} +void OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; reserved (ARM MOVrr)\n", Opcode); +} +void OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; reserved (WiMMX MOVrr)\n", Opcode); +} +void OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; vsp = r%u\n", Opcode, (Opcode & 0x0f)); +} +void OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4)); + OS << '\n'; +} +void OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4) | (1 << 14)); + OS << '\n'; +} +void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; finish\n", Opcode); +} +void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + + SW.startLine() + << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1, + ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop "); + if (((Opcode1 & 0xf0) == 0x00) && Opcode1) + PrintGPR((Opcode1 & 0x0f)); + OS << '\n'; +} +void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ", Opcode); + + SmallVector<uint8_t, 4> ULEB; + do { ULEB.push_back(Opcodes[OI ^ 3]); } while (Opcodes[OI++ ^ 3] & 0x80); + + for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI) + OS << format("0x%02X ", ULEB[BI]); + + uint64_t Value = 0; + for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI) + Value = Value | ((ULEB[BI] & 0x7f) << (7 * BI)); + + OS << format("; vsp = vsp + %" PRIu64 "\n", 0x204 + (Value << 2)); +} +void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; spare\n", Opcode); +} +void OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "wR"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() + << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1, + ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop "); + if ((Opcode1 & 0xf0) == 0x00 && Opcode1) + PrintRegisters(Opcode1 & 0x0f, "wCGR"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = 16 + ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; spare\n", Opcode); +} +void OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 10), "wR"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; spare\n", Opcode); +} + +void OpcodeDecoder::PrintGPR(uint16_t GPRMask) { + static const char *GPRRegisterNames[16] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "fp", "ip", "sp", "lr", "pc" + }; + + OS << '{'; + bool Comma = false; + for (unsigned RI = 0, RE = 17; RI < RE; ++RI) { + if (GPRMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << GPRRegisterNames[RI]; + Comma = true; + } + } + OS << '}'; +} + +void OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) { + OS << '{'; + bool Comma = false; + for (unsigned RI = 0, RE = 32; RI < RE; ++RI) { + if (VFPMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << Prefix << RI; + Comma = true; + } + } + OS << '}'; +} + +void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, size_t Length) { + for (unsigned OCI = Offset; OCI < Length + Offset; ) { + bool Decoded = false; + for (unsigned REI = 0, REE = countof(Ring); REI != REE && !Decoded; ++REI) { + if ((Opcodes[OCI ^ 3] & Ring[REI].Mask) == Ring[REI].Value) { + (this->*Ring[REI].Routine)(Opcodes, OCI); + Decoded = true; + break; + } + } + if (!Decoded) + SW.startLine() << format("0x%02X ; reserved\n", Opcodes[OCI++ ^ 3]); + } +} + +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_Iter Elf_Rel_iterator; + typedef typename object::ELFFile<ET>::Elf_Sym_Iter Elf_Sym_iterator; + typedef typename object::ELFFile<ET>::Elf_Shdr_Iter Elf_Shdr_iterator; + + static const size_t IndexTableEntrySize; + + static uint64_t PREL31(uint32_t Address, uint32_t Place) { + uint64_t Location = Address & 0x7fffffff; + if (Location & 0x04000000) + Location |= (uint64_t) ~0x7fffffff; + return Location + Place; + } + + ErrorOr<StringRef> FunctionAtAddress(unsigned Section, uint64_t Address) const; + const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex, + off_t IndexTableOffset) const; + + void PrintIndexTable(unsigned SectionIndex, const Elf_Shdr *IT) const; + void PrintExceptionTable(const Elf_Shdr *IT, const Elf_Shdr *EHT, + uint64_t TableEntryOffset) const; + 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) {} + + void PrintUnwindInformation() const; +}; + +template <typename ET> +const size_t PrinterContext<ET>::IndexTableEntrySize = 8; + +template <typename ET> +ErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(unsigned Section, + uint64_t Address) const { + for (Elf_Sym_iterator SI = ELF->begin_symbols(), SE = ELF->end_symbols(); + SI != SE; ++SI) + if (SI->st_shndx == Section && SI->st_value == Address && + SI->getType() == ELF::STT_FUNC) + return ELF->getSymbolName(SI); + return readobj_error::unknown_symbol; +} + +template <typename ET> +const typename object::ELFFile<ET>::Elf_Shdr * +PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, + off_t IndexTableOffset) const { + /// Iterate through the sections, searching for the relocation section + /// associated with the unwind index table section specified by + /// IndexSectionIndex. Iterate the associated section searching for the + /// relocation associated with the index table entry specified by + /// IndexTableOffset. The symbol is the section symbol for the exception + /// handling table. Use this symbol to recover the actual exception handling + /// table. + + for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections(); + SI != SE; ++SI) { + if (SI->sh_type == ELF::SHT_REL && SI->sh_info == IndexSectionIndex) { + for (Elf_Rel_iterator RI = ELF->begin_rel(&*SI), RE = ELF->end_rel(&*SI); + 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(&(*SI), &RelA); + + return ELF->getSection(Symbol.second); + } + } + } + } + return NULL; +} + +template <typename ET> +void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr *IT, + const Elf_Shdr *EHT, + uint64_t TableEntryOffset) const { + ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(EHT); + if (!Contents) + return; + + /// ARM EHABI Section 6.2 - The generic model + /// + /// An exception-handling table entry for the generic model is laid out as: + /// + /// 3 3 + /// 1 0 0 + /// +-+------------------------------+ + /// |0| personality routine offset | + /// +-+------------------------------+ + /// | personality routine data ... | + /// + /// + /// ARM EHABI Section 6.3 - The ARM-defined compact model + /// + /// An exception-handling table entry for the compact model looks like: + /// + /// 3 3 2 2 2 2 + /// 1 0 8 7 4 3 0 + /// +-+---+----+-----------------------+ + /// |1| 0 | Ix | data for pers routine | + /// +-+---+----+-----------------------+ + /// | more personality routine data | + + const support::ulittle32_t Word = + *reinterpret_cast<const support::ulittle32_t *>(Contents->data() + TableEntryOffset); + + if (Word & 0x80000000) { + SW.printString("Model", StringRef("Compact")); + + unsigned PersonalityIndex = (Word & 0x0f000000) >> 24; + SW.printNumber("PersonalityIndex", PersonalityIndex); + + switch (PersonalityIndex) { + case AEABI_UNWIND_CPP_PR0: + PrintOpcodes(Contents->data() + TableEntryOffset, 3, 1); + break; + case AEABI_UNWIND_CPP_PR1: + case AEABI_UNWIND_CPP_PR2: + unsigned AdditionalWords = (Word & 0x00ff0000) >> 16; + PrintOpcodes(Contents->data() + TableEntryOffset, 2 + 4 * AdditionalWords, + 2); + break; + } + } else { + SW.printString("Model", StringRef("Generic")); + + uint64_t Address = PREL31(Word, EHT->sh_addr); + SW.printHex("PersonalityRoutineAddress", Address); + if (ErrorOr<StringRef> Name = FunctionAtAddress(EHT->sh_link, Address)) + SW.printString("PersonalityRoutineName", *Name); + } +} + +template <typename ET> +void PrinterContext<ET>::PrintOpcodes(const uint8_t *Entry, + size_t Length, off_t Offset) const { + ListScope OCC(SW, "Opcodes"); + OpcodeDecoder(OCC.W).Decode(Entry, Offset, Length); +} + +template <typename ET> +void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex, + const Elf_Shdr *IT) const { + ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(IT); + if (!Contents) + return; + + /// ARM EHABI Section 5 - Index Table Entries + /// * The first word contains a PREL31 offset to the start of a function with + /// bit 31 clear + /// * The second word contains one of: + /// - The PREL31 offset of the start of the table entry for the function, + /// with bit 31 clear + /// - The exception-handling table entry itself with bit 31 set + /// - The special bit pattern EXIDX_CANTUNWIND, indicating that associated + /// frames cannot be unwound + + const support::ulittle32_t *Data = + reinterpret_cast<const support::ulittle32_t *>(Contents->data()); + const unsigned Entries = IT->sh_size / IndexTableEntrySize; + + ListScope E(SW, "Entries"); + for (unsigned Entry = 0; Entry < Entries; ++Entry) { + DictScope E(SW, "Entry"); + + const support::ulittle32_t Word0 = + Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 0]; + const support::ulittle32_t Word1 = + Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 1]; + + if (Word0 & 0x80000000) { + errs() << "corrupt unwind data in section " << SectionIndex << "\n"; + continue; + } + + const uint64_t Offset = PREL31(Word0, IT->sh_addr); + SW.printHex("FunctionAddress", Offset); + if (ErrorOr<StringRef> Name = FunctionAtAddress(IT->sh_link, Offset)) + SW.printString("FunctionName", *Name); + + if (Word1 == EXIDX_CANTUNWIND) { + SW.printString("Model", StringRef("CantUnwind")); + continue; + } + + if (Word1 & 0x80000000) { + SW.printString("Model", StringRef("Compact (Inline)")); + + unsigned PersonalityIndex = (Word1 & 0x0f000000) >> 24; + SW.printNumber("PersonalityIndex", PersonalityIndex); + + PrintOpcodes(Contents->data() + Entry * IndexTableEntrySize + 4, 3, 1); + } else { + const Elf_Shdr *EHT = + FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4); + + if (ErrorOr<StringRef> Name = ELF->getSectionName(EHT)) + SW.printString("ExceptionHandlingTable", *Name); + + uint64_t TableEntryOffset = PREL31(Word1, IT->sh_addr); + SW.printHex("TableEntryOffset", TableEntryOffset); + + PrintExceptionTable(IT, EHT, TableEntryOffset); + } + } +} + +template <typename ET> +void PrinterContext<ET>::PrintUnwindInformation() const { + DictScope UI(SW, "UnwindInformation"); + + int SectionIndex = 0; + for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections(); + SI != SE; ++SI, ++SectionIndex) { + if (SI->sh_type == ELF::SHT_ARM_EXIDX) { + const Elf_Shdr *IT = &(*SI); + + DictScope UIT(SW, "UnwindIndexTable"); + + SW.printNumber("SectionIndex", SectionIndex); + if (ErrorOr<StringRef> SectionName = ELF->getSectionName(IT)) + SW.printString("SectionName", *SectionName); + SW.printHex("SectionOffset", IT->sh_offset); + + PrintIndexTable(SectionIndex, IT); + } + } +} +} +} +} + +#endif + diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index 90997a8..036185d 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -1,7 +1,8 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - bitreader - object) + Object + Support + ) add_llvm_tool(llvm-readobj llvm-readobj.cpp @@ -11,4 +12,5 @@ add_llvm_tool(llvm-readobj MachODumper.cpp Error.cpp StreamWriter.cpp + ARMAttributeParser.cpp ) diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 2f309e3..cd40da7 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -13,23 +13,22 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" -#include "ObjDumper.h" - #include "Error.h" +#include "ObjDumper.h" #include "StreamWriter.h" - #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/COFF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Win64EH.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" - #include <algorithm> #include <cstring> #include <time.h> @@ -48,22 +47,23 @@ public: cacheRelocations(); } - virtual void printFileHeaders() LLVM_OVERRIDE; - virtual void printSections() LLVM_OVERRIDE; - virtual void printRelocations() LLVM_OVERRIDE; - virtual void printSymbols() LLVM_OVERRIDE; - virtual void printDynamicSymbols() LLVM_OVERRIDE; - virtual void printUnwindInfo() LLVM_OVERRIDE; + virtual void printFileHeaders() override; + virtual void printSections() override; + virtual void printRelocations() override; + virtual void printSymbols() override; + virtual void printDynamicSymbols() override; + virtual void printUnwindInfo() override; private: - void printSymbol(symbol_iterator SymI); - - void printRelocation(section_iterator SecI, relocation_iterator RelI); - + void printSymbol(const SymbolRef &Sym); + void printRelocation(const SectionRef &Section, const RelocationRef &Reloc); void printDataDirectory(uint32_t Index, const std::string &FieldName); - void printX64UnwindInfo(); + template <class PEHeader> void printPEHeader(const PEHeader *Hdr); + void printBaseOfDataField(const pe32_header *Hdr); + void printBaseOfDataField(const pe32plus_header *Hdr); + void printRuntimeFunction( const RuntimeFunction& RTF, uint64_t OffsetInSection, @@ -74,7 +74,9 @@ private: uint64_t OffsetInSection, const std::vector<RelocationRef> &Rels); - void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs); + void printUnwindCode(const Win64EH::UnwindInfo &UI, ArrayRef<UnwindCode> UCs); + + void printCodeViewLineTables(const SectionRef &Section); void cacheRelocations(); @@ -102,9 +104,8 @@ private: namespace llvm { -error_code createCOFFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result) { +error_code createCOFFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj); if (!COFFObj) return readobj_error::unsupported_obj_file_format; @@ -183,11 +184,11 @@ static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, if (error_code EC = Sym.getAddress(ResolvedAddr)) return EC; - section_iterator iter(Obj->begin_sections()); + section_iterator iter(Obj->section_begin()); if (error_code EC = Sym.getSection(iter)) return EC; - ResolvedSection = Obj->getCOFFSection(iter); + ResolvedSection = Obj->getCOFFSection(*iter); return object_error::success; } @@ -227,7 +228,7 @@ static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = { LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ), - LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMV7 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ), @@ -279,6 +280,7 @@ static const EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = { }; static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ), @@ -428,30 +430,9 @@ static const EnumEntry<unsigned> UnwindOpInfo[] = { // Some additional COFF structures not defined by llvm::object. namespace { - struct coff_aux_function_definition { - support::ulittle32_t TagIndex; - support::ulittle32_t TotalSize; - support::ulittle32_t PointerToLineNumber; - support::ulittle32_t PointerToNextFunction; - uint8_t Unused[2]; - }; - - struct coff_aux_weak_external_definition { - support::ulittle32_t TagIndex; - support::ulittle32_t Characteristics; - uint8_t Unused[10]; - }; - struct coff_aux_file_record { char FileName[18]; }; - - struct coff_aux_clr_token { - support::ulittle8_t AuxType; - support::ulittle8_t Reserved; - support::ulittle32_t SymbolTableIndex; - uint8_t Unused[12]; - }; } // namespace static uint64_t getOffsetOfLSDA(const Win64EH::UnwindInfo& UI) { @@ -538,23 +519,11 @@ error_code COFFDumper::getSection( } void COFFDumper::cacheRelocations() { - error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) - break; - - const coff_section *Section = Obj->getCOFFSection(SecI); - - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) - break; + for (const SectionRef &S : Obj->sections()) { + const coff_section *Section = Obj->getCOFFSection(S); - RelocMap[Section].push_back(*RelI); - } + for (const RelocationRef &Reloc : S.relocations()) + RelocMap[Section].push_back(Reloc); // Sort relocations by address. std::sort(RelocMap[Section].begin(), RelocMap[Section].end(), @@ -598,73 +567,239 @@ void COFFDumper::printFileHeaders() { const pe32_header *PEHeader = 0; if (error(Obj->getPE32Header(PEHeader))) return; + if (PEHeader) + printPEHeader<pe32_header>(PEHeader); + + const pe32plus_header *PEPlusHeader = 0; + if (error(Obj->getPE32PlusHeader(PEPlusHeader))) + return; + if (PEPlusHeader) + printPEHeader<pe32plus_header>(PEPlusHeader); +} + +template <class PEHeader> +void COFFDumper::printPEHeader(const PEHeader *Hdr) { + DictScope D(W, "ImageOptionalHeader"); + W.printNumber("MajorLinkerVersion", Hdr->MajorLinkerVersion); + W.printNumber("MinorLinkerVersion", Hdr->MinorLinkerVersion); + W.printNumber("SizeOfCode", Hdr->SizeOfCode); + W.printNumber("SizeOfInitializedData", Hdr->SizeOfInitializedData); + W.printNumber("SizeOfUninitializedData", Hdr->SizeOfUninitializedData); + W.printHex ("AddressOfEntryPoint", Hdr->AddressOfEntryPoint); + W.printHex ("BaseOfCode", Hdr->BaseOfCode); + printBaseOfDataField(Hdr); + W.printHex ("ImageBase", Hdr->ImageBase); + W.printNumber("SectionAlignment", Hdr->SectionAlignment); + W.printNumber("FileAlignment", Hdr->FileAlignment); + W.printNumber("MajorOperatingSystemVersion", + Hdr->MajorOperatingSystemVersion); + W.printNumber("MinorOperatingSystemVersion", + Hdr->MinorOperatingSystemVersion); + W.printNumber("MajorImageVersion", Hdr->MajorImageVersion); + W.printNumber("MinorImageVersion", Hdr->MinorImageVersion); + W.printNumber("MajorSubsystemVersion", Hdr->MajorSubsystemVersion); + W.printNumber("MinorSubsystemVersion", Hdr->MinorSubsystemVersion); + W.printNumber("SizeOfImage", Hdr->SizeOfImage); + W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders); + W.printEnum ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem)); + W.printFlags ("Subsystem", Hdr->DLLCharacteristics, + makeArrayRef(PEDLLCharacteristics)); + W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve); + W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit); + W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve); + W.printNumber("SizeOfHeapCommit", Hdr->SizeOfHeapCommit); + W.printNumber("NumberOfRvaAndSize", Hdr->NumberOfRvaAndSize); + + if (Hdr->NumberOfRvaAndSize > 0) { + DictScope D(W, "DataDirectory"); + static const char * const directory[] = { + "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable", + "CertificateTable", "BaseRelocationTable", "Debug", "Architecture", + "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT", + "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved" + }; + + for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) { + printDataDirectory(i, directory[i]); + } + } +} + +void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) { + W.printHex("BaseOfData", Hdr->BaseOfData); +} + +void COFFDumper::printBaseOfDataField(const pe32plus_header *) {} + +void COFFDumper::printCodeViewLineTables(const SectionRef &Section) { + StringRef Data; + if (error(Section.getContents(Data))) + return; + + SmallVector<StringRef, 10> FunctionNames; + StringMap<StringRef> FunctionLineTables; + StringRef FileIndexToStringOffsetTable; + StringRef StringTable; + + ListScope D(W, "CodeViewLineTables"); + { + DataExtractor DE(Data, true, 4); + uint32_t Offset = 0, + Magic = DE.getU32(&Offset); + W.printHex("Magic", Magic); + if (Magic != COFF::DEBUG_SECTION_MAGIC) { + error(object_error::parse_failed); + return; + } + + bool Finished = false; + while (DE.isValidOffset(Offset) && !Finished) { + // The section consists of a number of subsection in the following format: + // |Type|PayloadSize|Payload...| + uint32_t SubSectionType = DE.getU32(&Offset), + PayloadSize = DE.getU32(&Offset); + ListScope S(W, "Subsection"); + W.printHex("Type", SubSectionType); + W.printHex("PayloadSize", PayloadSize); + if (PayloadSize > Data.size() - Offset) { + error(object_error::parse_failed); + return; + } + + // Print the raw contents to simplify debugging if anything goes wrong + // afterwards. + StringRef Contents = Data.substr(Offset, PayloadSize); + W.printBinaryBlock("Contents", Contents); + + switch (SubSectionType) { + case COFF::DEBUG_LINE_TABLE_SUBSECTION: { + // Holds a PC to file:line table. Some data to parse this subsection is + // stored in the other subsections, so just check sanity and store the + // pointers for deferred processing. + + if (PayloadSize < 12) { + // There should be at least three words to store two function + // relocations and size of the code. + error(object_error::parse_failed); + return; + } + + StringRef FunctionName; + if (error(resolveSymbolName(RelocMap[Obj->getCOFFSection(Section)], + Offset, FunctionName))) + return; + W.printString("FunctionName", FunctionName); + if (FunctionLineTables.count(FunctionName) != 0) { + // Saw debug info for this function already? + error(object_error::parse_failed); + return; + } + + FunctionLineTables[FunctionName] = Contents; + FunctionNames.push_back(FunctionName); + break; + } + case COFF::DEBUG_STRING_TABLE_SUBSECTION: + if (PayloadSize == 0 || StringTable.data() != 0 || + Contents.back() != '\0') { + // Empty or duplicate or non-null-terminated subsection. + error(object_error::parse_failed); + return; + } + StringTable = Contents; + break; + case COFF::DEBUG_INDEX_SUBSECTION: + // Holds the translation table from file indices + // to offsets in the string table. + + if (PayloadSize == 0 || FileIndexToStringOffsetTable.data() != 0) { + // Empty or duplicate subsection. + error(object_error::parse_failed); + return; + } + FileIndexToStringOffsetTable = Contents; + break; + } + Offset += PayloadSize; + + // Align the reading pointer by 4. + Offset += (-Offset) % 4; + } + } + + // Dump the line tables now that we've read all the subsections and know all + // the required information. + for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) { + StringRef Name = FunctionNames[I]; + ListScope S(W, "FunctionLineTable"); + W.printString("FunctionName", Name); + + DataExtractor DE(FunctionLineTables[Name], true, 4); + uint32_t Offset = 8; // Skip relocations. + uint32_t FunctionSize = DE.getU32(&Offset); + W.printHex("CodeSize", FunctionSize); + while (DE.isValidOffset(Offset)) { + // For each range of lines with the same filename, we have a segment + // in the line table. The filename string is accessed using double + // indirection to the string table subsection using the index subsection. + uint32_t OffsetInIndex = DE.getU32(&Offset), + SegmentLength = DE.getU32(&Offset), + FullSegmentSize = DE.getU32(&Offset); + if (FullSegmentSize != 12 + 8 * SegmentLength) { + error(object_error::parse_failed); + return; + } + + uint32_t FilenameOffset; + { + DataExtractor SDE(FileIndexToStringOffsetTable, true, 4); + uint32_t OffsetInSDE = OffsetInIndex; + if (!SDE.isValidOffset(OffsetInSDE)) { + error(object_error::parse_failed); + return; + } + FilenameOffset = SDE.getU32(&OffsetInSDE); + } - if (PEHeader) { - DictScope D(W, "ImageOptionalHeader"); - W.printNumber("MajorLinkerVersion", PEHeader->MajorLinkerVersion); - W.printNumber("MinorLinkerVersion", PEHeader->MinorLinkerVersion); - W.printNumber("SizeOfCode", PEHeader->SizeOfCode); - W.printNumber("SizeOfInitializedData", PEHeader->SizeOfInitializedData); - W.printNumber("SizeOfUninitializedData", PEHeader->SizeOfUninitializedData); - W.printHex ("AddressOfEntryPoint", PEHeader->AddressOfEntryPoint); - W.printHex ("BaseOfCode", PEHeader->BaseOfCode); - W.printHex ("BaseOfData", PEHeader->BaseOfData); - W.printHex ("ImageBase", PEHeader->ImageBase); - W.printNumber("SectionAlignment", PEHeader->SectionAlignment); - W.printNumber("FileAlignment", PEHeader->FileAlignment); - W.printNumber("MajorOperatingSystemVersion", - PEHeader->MajorOperatingSystemVersion); - W.printNumber("MinorOperatingSystemVersion", - PEHeader->MinorOperatingSystemVersion); - W.printNumber("MajorImageVersion", PEHeader->MajorImageVersion); - W.printNumber("MinorImageVersion", PEHeader->MinorImageVersion); - W.printNumber("MajorSubsystemVersion", PEHeader->MajorSubsystemVersion); - W.printNumber("MinorSubsystemVersion", PEHeader->MinorSubsystemVersion); - W.printNumber("SizeOfImage", PEHeader->SizeOfImage); - W.printNumber("SizeOfHeaders", PEHeader->SizeOfHeaders); - W.printEnum ("Subsystem", PEHeader->Subsystem, - makeArrayRef(PEWindowsSubsystem)); - W.printFlags ("Subsystem", PEHeader->DLLCharacteristics, - makeArrayRef(PEDLLCharacteristics)); - W.printNumber("SizeOfStackReserve", PEHeader->SizeOfStackReserve); - W.printNumber("SizeOfStackCommit", PEHeader->SizeOfStackCommit); - W.printNumber("SizeOfHeapReserve", PEHeader->SizeOfHeapReserve); - W.printNumber("SizeOfHeapCommit", PEHeader->SizeOfHeapCommit); - W.printNumber("NumberOfRvaAndSize", PEHeader->NumberOfRvaAndSize); - - if (PEHeader->NumberOfRvaAndSize > 0) { - DictScope D(W, "DataDirectory"); - static const char * const directory[] = { - "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable", - "CertificateTable", "BaseRelocationTable", "Debug", "Architecture", - "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT", - "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved" - }; - - for (uint32_t i = 0; i < PEHeader->NumberOfRvaAndSize; ++i) { - printDataDirectory(i, directory[i]); + if (FilenameOffset == 0 || FilenameOffset + 1 >= StringTable.size() || + StringTable.data()[FilenameOffset - 1] != '\0') { + // Each string in an F3 subsection should be preceded by a null + // character. + error(object_error::parse_failed); + return; + } + + StringRef Filename(StringTable.data() + FilenameOffset); + ListScope S(W, "FilenameSegment"); + W.printString("Filename", Filename); + for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset); + ++J) { + // Then go the (PC, LineNumber) pairs. The line number is stored in the + // least significant 31 bits of the respective word in the table. + uint32_t PC = DE.getU32(&Offset), + LineNumber = DE.getU32(&Offset) & 0x7fffffff; + if (PC >= FunctionSize) { + error(object_error::parse_failed); + return; + } + char Buffer[32]; + format("+0x%X", PC).snprint(Buffer, 32); + W.printNumber(Buffer, LineNumber); } } } } void COFFDumper::printSections() { - error_code EC; - ListScope SectionsD(W, "Sections"); int SectionNumber = 0; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) - break; - + for (const SectionRef &Sec : Obj->sections()) { ++SectionNumber; - const coff_section *Section = Obj->getCOFFSection(SecI); + const coff_section *Section = Obj->getCOFFSection(Sec); StringRef Name; - if (error(SecI->getName(Name))) - Name = ""; + if (error(Sec.getName(Name))) + Name = ""; DictScope D(W, "Section"); W.printNumber("Number", SectionNumber); @@ -683,33 +818,28 @@ void COFFDumper::printSections() { if (opts::SectionRelocations) { ListScope D(W, "Relocations"); - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - - printRelocation(SecI, RelI); - } + for (const RelocationRef &Reloc : Sec.relocations()) + printRelocation(Sec, Reloc); } if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - + for (const SymbolRef &Symbol : Obj->symbols()) { bool Contained = false; - if (SecI->containsSymbol(*SymI, Contained) || !Contained) + if (Sec.containsSymbol(Symbol, Contained) || !Contained) continue; - printSymbol(SymI); + printSymbol(Symbol); } } + if (Name == ".debug$S" && opts::CodeViewLineTables) + printCodeViewLineTables(Sec); + if (opts::SectionData) { StringRef Data; - if (error(SecI->getContents(Data))) break; + if (error(Sec.getContents(Data))) + break; W.printBinaryBlock("SectionData", Data); } @@ -719,32 +849,22 @@ void COFFDumper::printSections() { void COFFDumper::printRelocations() { ListScope D(W, "Relocations"); - error_code EC; int SectionNumber = 0; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { + for (const SectionRef &Section : Obj->sections()) { ++SectionNumber; - if (error(EC)) - break; - StringRef Name; - if (error(SecI->getName(Name))) + if (error(Section.getName(Name))) continue; bool PrintedGroup = false; - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - + for (const RelocationRef &Reloc : Section.relocations()) { if (!PrintedGroup) { W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; W.indent(); PrintedGroup = true; } - printRelocation(SecI, RelI); + printRelocation(Section, Reloc); } if (PrintedGroup) { @@ -754,19 +874,24 @@ void COFFDumper::printRelocations() { } } -void COFFDumper::printRelocation(section_iterator SecI, - relocation_iterator RelI) { +void COFFDumper::printRelocation(const SectionRef &Section, + const RelocationRef &Reloc) { uint64_t Offset; uint64_t RelocType; SmallString<32> RelocName; StringRef SymbolName; StringRef Contents; - if (error(RelI->getOffset(Offset))) return; - if (error(RelI->getType(RelocType))) return; - if (error(RelI->getTypeName(RelocName))) return; - symbol_iterator Symbol = RelI->getSymbol(); - if (error(Symbol->getName(SymbolName))) return; - if (error(SecI->getContents(Contents))) return; + if (error(Reloc.getOffset(Offset))) + return; + if (error(Reloc.getType(RelocType))) + return; + if (error(Reloc.getTypeName(RelocName))) + return; + symbol_iterator Symbol = Reloc.getSymbol(); + if (error(Symbol->getName(SymbolName))) + return; + if (error(Section.getContents(Contents))) + return; if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); @@ -785,24 +910,16 @@ void COFFDumper::printRelocation(section_iterator SecI, void COFFDumper::printSymbols() { ListScope Group(W, "Symbols"); - error_code EC; - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - - printSymbol(SymI); - } + for (const SymbolRef &Symbol : Obj->symbols()) + printSymbol(Symbol); } -void COFFDumper::printDynamicSymbols() { - ListScope Group(W, "DynamicSymbols"); -} +void COFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); } -void COFFDumper::printSymbol(symbol_iterator SymI) { +void COFFDumper::printSymbol(const SymbolRef &Sym) { DictScope D(W, "Symbol"); - const coff_symbol *Symbol = Obj->getCOFFSymbol(SymI); + const coff_symbol *Symbol = Obj->getCOFFSymbol(Sym); const coff_section *Section; if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { W.startLine() << "Invalid section number: " << EC.message() << "\n"; @@ -829,10 +946,7 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols); for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) { - if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symbol->getBaseType() == COFF::IMAGE_SYM_TYPE_NULL && - Symbol->getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION && - Symbol->SectionNumber > 0) { + if (Symbol->isFunctionDefinition()) { const coff_aux_function_definition *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; @@ -840,16 +954,12 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { DictScope AS(W, "AuxFunctionDef"); W.printNumber("TagIndex", Aux->TagIndex); W.printNumber("TotalSize", Aux->TotalSize); - W.printHex("PointerToLineNumber", Aux->PointerToLineNumber); + W.printHex("PointerToLineNumber", Aux->PointerToLinenumber); W.printHex("PointerToNextFunction", Aux->PointerToNextFunction); W.printBinary("Unused", makeArrayRef(Aux->Unused)); - } else if ( - Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL || - (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symbol->SectionNumber == 0 && - Symbol->Value == 0)) { - const coff_aux_weak_external_definition *Aux; + } else if (Symbol->isWeakExternal()) { + const coff_aux_weak_external *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; @@ -866,9 +976,9 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { W.printNumber("Linked", LinkedName, Aux->TagIndex); W.printEnum ("Search", Aux->Characteristics, makeArrayRef(WeakExternalCharacteristics)); - W.printBinary("Unused", Aux->Unused); + W.printBinary("Unused", makeArrayRef(Aux->Unused)); - } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_FILE) { + } else if (Symbol->isFileRecord()) { const coff_aux_file_record *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; @@ -876,9 +986,7 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { DictScope AS(W, "AuxFileRecord"); W.printString("FileName", StringRef(Aux->FileName)); - } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC || - (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && - Symbol->SectionNumber != COFF::IMAGE_SYM_UNDEFINED)) { + } else if (Symbol->isSectionDefinition()) { const coff_aux_section_definition *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; @@ -905,16 +1013,25 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { W.printNumber("AssocSection", AssocName, Aux->Number); } - } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_CLR_TOKEN) { + } else if (Symbol->isCLRToken()) { const coff_aux_clr_token *Aux; if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) break; + const coff_symbol *ReferredSym; + StringRef ReferredName; + error_code EC; + if ((EC = Obj->getSymbol(Aux->SymbolTableIndex, ReferredSym)) || + (EC = Obj->getSymbolName(ReferredSym, ReferredName))) { + ReferredName = ""; + error(EC); + } + DictScope AS(W, "AuxCLRToken"); W.printNumber("AuxType", Aux->AuxType); W.printNumber("Reserved", Aux->Reserved); - W.printNumber("SymbolTableIndex", Aux->SymbolTableIndex); - W.printBinary("Unused", Aux->Unused); + W.printNumber("SymbolTableIndex", ReferredName, Aux->SymbolTableIndex); + W.printBinary("Unused", makeArrayRef(Aux->Unused)); } else { W.startLine() << "<unhandled auxiliary record>\n"; @@ -938,23 +1055,17 @@ void COFFDumper::printUnwindInfo() { } void COFFDumper::printX64UnwindInfo() { - error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) break; - + for (const SectionRef &Section : Obj->sections()) { StringRef Name; - if (error(SecI->getName(Name))) + if (error(Section.getName(Name))) continue; if (Name != ".pdata" && !Name.startswith(".pdata$")) continue; - const coff_section *PData = Obj->getCOFFSection(SecI); + const coff_section *PData = Obj->getCOFFSection(Section); ArrayRef<uint8_t> Contents; - if (error(Obj->getSectionContents(PData, Contents)) || - Contents.empty()) + if (error(Obj->getSectionContents(PData, Contents)) || Contents.empty()) continue; ArrayRef<RuntimeFunction> RFs( diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 07a9083..4cd3393 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -13,12 +13,15 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" +#include "ARMAttributeParser.h" +#include "ARMEHABIPrinter.h" #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.h" - #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" @@ -39,16 +42,18 @@ public: ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) : ObjDumper(Writer), Obj(Obj) {} - virtual void printFileHeaders() LLVM_OVERRIDE; - virtual void printSections() LLVM_OVERRIDE; - virtual void printRelocations() LLVM_OVERRIDE; - virtual void printSymbols() LLVM_OVERRIDE; - virtual void printDynamicSymbols() LLVM_OVERRIDE; - virtual void printUnwindInfo() LLVM_OVERRIDE; + void printFileHeaders() override; + void printSections() override; + void printRelocations() override; + void printSymbols() override; + void printDynamicSymbols() override; + void printUnwindInfo() override; + + void printDynamicTable() override; + void printNeededLibraries() override; + void printProgramHeaders() override; - virtual void printDynamicTable() LLVM_OVERRIDE; - virtual void printNeededLibraries() LLVM_OVERRIDE; - virtual void printProgramHeaders() LLVM_OVERRIDE; + void printAttributes() override; private: typedef ELFFile<ELFT> ELFO; @@ -65,7 +70,7 @@ private: template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { if (!Val) { - error(Val); + error(Val.getError()); return Default; } @@ -78,14 +83,13 @@ namespace llvm { template <class ELFT> static error_code createELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer, - OwningPtr<ObjDumper> &Result) { + std::unique_ptr<ObjDumper> &Result) { Result.reset(new ELFDumper<ELFT>(Obj, Writer)); return readobj_error::success; } -error_code createELFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result) { +error_code createELFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { // Little-endian 32-bit if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) return createELFDumper(ELFObj->getELFFile(), Writer, Result); @@ -621,8 +625,30 @@ void ELFDumper<ELFT>::printDynamicSymbols() { template <class ELFT> void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { StringRef SymbolName = errorOrDefault(Obj->getSymbolName(Symbol)); - const Elf_Shdr *Sec = Obj->getSection(&*Symbol); - StringRef SectionName = Sec ? errorOrDefault(Obj->getSectionName(Sec)) : ""; + + unsigned SectionIndex = Symbol->st_shndx; + StringRef SectionName; + if (SectionIndex == SHN_UNDEF) { + SectionName = "Undefined"; + } else if (SectionIndex >= SHN_LOPROC && SectionIndex <= SHN_HIPROC) { + SectionName = "Processor Specific"; + } else if (SectionIndex >= SHN_LOOS && SectionIndex <= SHN_HIOS) { + SectionName = "Operating System Specific"; + } else if (SectionIndex > SHN_HIOS && SectionIndex < SHN_ABS) { + SectionName = "Reserved"; + } else if (SectionIndex == SHN_ABS) { + SectionName = "Absolute"; + } else if (SectionIndex == SHN_COMMON) { + SectionName = "Common"; + } else { + if (SectionIndex == SHN_XINDEX) + SectionIndex = Obj->getSymbolTableIndex(&*Symbol); + assert(SectionIndex != SHN_XINDEX && + "getSymbolTableIndex should handle this"); + const Elf_Shdr *Sec = Obj->getSection(SectionIndex); + SectionName = errorOrDefault(Obj->getSectionName(Sec)); + } + std::string FullSymbolName(SymbolName); if (Symbol.isDynamic()) { bool IsDefault; @@ -631,7 +657,7 @@ void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { FullSymbolName += (IsDefault ? "@@" : "@"); FullSymbolName += *Version; } else - error(Version); + error(Version.getError()); } DictScope D(W, "Symbol"); @@ -642,7 +668,7 @@ void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { makeArrayRef(ElfSymbolBindings)); W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes)); W.printNumber("Other", Symbol->st_other); - W.printHex ("Section", SectionName, Symbol->st_shndx); + W.printHex("Section", SectionName, SectionIndex); } #define LLVM_READOBJ_TYPE_CASE(name) \ @@ -693,6 +719,8 @@ static const char *getTypeString(uint64_t Type) { LLVM_READOBJ_TYPE_CASE(MIPS_SYMTABNO); LLVM_READOBJ_TYPE_CASE(MIPS_UNREFEXTNO); LLVM_READOBJ_TYPE_CASE(MIPS_GOTSYM); + LLVM_READOBJ_TYPE_CASE(MIPS_RLD_MAP); + LLVM_READOBJ_TYPE_CASE(MIPS_PLTGOT); default: return "unknown"; } } @@ -731,6 +759,8 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_MIPS_FLAGS: case DT_MIPS_BASE_ADDRESS: case DT_MIPS_GOTSYM: + case DT_MIPS_RLD_MAP: + case DT_MIPS_PLTGOT: OS << format("0x%" PRIX64, Value); break; case DT_VERNEEDNUM: @@ -770,6 +800,18 @@ void ELFDumper<ELFT>::printUnwindInfo() { W.startLine() << "UnwindInfo not implemented.\n"; } +namespace { +template <> +void ELFDumper<ELFType<support::little, 2, false> >::printUnwindInfo() { + const unsigned Machine = Obj->getHeader()->e_machine; + if (Machine == EM_ARM) { + ARM::EHABI::PrinterContext<ELFType<support::little, 2, false> > Ctx(W, Obj); + return Ctx.PrintUnwindInformation(); + } + W.startLine() << "UnwindInfo not implemented.\n"; +} +} + template<class ELFT> void ELFDumper<ELFT>::printDynamicTable() { typedef typename ELFO::Elf_Dyn_Iter EDI; @@ -839,3 +881,42 @@ void ELFDumper<ELFT>::printProgramHeaders() { W.printNumber("Alignment", PI->p_align); } } + +template <class ELFT> +void ELFDumper<ELFT>::printAttributes() { + W.startLine() << "Attributes not implemented.\n"; +} + +namespace { +template <> +void ELFDumper<ELFType<support::little, 2, false> >::printAttributes() { + if (Obj->getHeader()->e_machine != EM_ARM) { + W.startLine() << "Attributes not implemented.\n"; + return; + } + + DictScope BA(W, "BuildAttributes"); + for (ELFO::Elf_Shdr_Iter SI = Obj->begin_sections(), SE = Obj->end_sections(); + SI != SE; ++SI) { + if (SI->sh_type != ELF::SHT_ARM_ATTRIBUTES) + continue; + + ErrorOr<ArrayRef<uint8_t> > Contents = Obj->getSectionContents(&(*SI)); + if (!Contents) + continue; + + if ((*Contents)[0] != ARMBuildAttrs::Format_Version) { + errs() << "unrecognised FormatVersion: 0x" << utohexstr((*Contents)[0]) + << '\n'; + continue; + } + + W.printHex("FormatVersion", (*Contents)[0]); + if (Contents->size() == 1) + continue; + + ARMAttributeParser(W).Parse(*Contents); + } +} +} + diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp index a6c6132..83ed6a7 100644 --- a/tools/llvm-readobj/Error.cpp +++ b/tools/llvm-readobj/Error.cpp @@ -17,11 +17,11 @@ using namespace llvm; namespace { -class _readobj_error_category : public _do_message { +class _readobj_error_category : public error_category { public: - virtual const char* name() const; - virtual std::string message(int ev) const; - virtual error_condition default_error_condition(int ev) const; + const char* name() const override; + std::string message(int ev) const override; + error_condition default_error_condition(int ev) const override; }; } // namespace diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h index cf68da8..5129b4e 100644 --- a/tools/llvm-readobj/Error.h +++ b/tools/llvm-readobj/Error.h @@ -40,8 +40,8 @@ inline error_code make_error_code(readobj_error e) { return error_code(static_cast<int>(e), readobj_category()); } -template <> struct is_error_code_enum<readobj_error> : true_type { }; -template <> struct is_error_code_enum<readobj_error::_> : true_type { }; +template <> struct is_error_code_enum<readobj_error> : std::true_type { }; +template <> struct is_error_code_enum<readobj_error::_> : std::true_type { }; } // namespace llvm diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp index b97166b..2fd5d4a 100644 --- a/tools/llvm-readobj/MachODumper.cpp +++ b/tools/llvm-readobj/MachODumper.cpp @@ -15,7 +15,6 @@ #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.h" - #include "llvm/ADT/SmallString.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" @@ -31,20 +30,19 @@ public: : ObjDumper(Writer) , Obj(Obj) { } - virtual void printFileHeaders() LLVM_OVERRIDE; - virtual void printSections() LLVM_OVERRIDE; - virtual void printRelocations() LLVM_OVERRIDE; - virtual void printSymbols() LLVM_OVERRIDE; - virtual void printDynamicSymbols() LLVM_OVERRIDE; - virtual void printUnwindInfo() LLVM_OVERRIDE; + virtual void printFileHeaders() override; + virtual void printSections() override; + virtual void printRelocations() override; + virtual void printSymbols() override; + virtual void printDynamicSymbols() override; + virtual void printUnwindInfo() override; private: - void printSymbol(symbol_iterator SymI); + void printSymbol(const SymbolRef &Symbol); - void printRelocation(section_iterator SecI, relocation_iterator RelI); + void printRelocation(const RelocationRef &Reloc); - void printRelocation(const MachOObjectFile *Obj, - section_iterator SecI, relocation_iterator RelI); + void printRelocation(const MachOObjectFile *Obj, const RelocationRef &Reloc); void printSections(const MachOObjectFile *Obj); @@ -57,8 +55,8 @@ private: namespace llvm { error_code createMachODumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result) { + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); if (!MachOObj) return readobj_error::unsupported_obj_file_format; @@ -126,19 +124,13 @@ static const EnumEntry<unsigned> MachOSymbolFlags[] = { static const EnumEntry<unsigned> MachOSymbolTypes[] = { { "Undef", 0x0 }, - { "External", 0x1 }, { "Abs", 0x2 }, { "Indirect", 0xA }, { "PreboundUndef", 0xC }, - { "Section", 0xE }, - { "PrivateExternal", 0x10 } + { "Section", 0xE } }; namespace { - enum { - N_STAB = 0xE0 - }; - struct MachOSection { ArrayRef<char> Name; ArrayRef<char> SegmentName; @@ -223,21 +215,16 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { ListScope Group(W, "Sections"); int SectionIndex = -1; - error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) break; - + for (const SectionRef &Section : Obj->sections()) { ++SectionIndex; - MachOSection Section; - getSection(Obj, SecI->getRawDataRefImpl(), Section); - DataRefImpl DR = SecI->getRawDataRefImpl(); + MachOSection MOSection; + getSection(Obj, Section.getRawDataRefImpl(), MOSection); + DataRefImpl DR = Section.getRawDataRefImpl(); StringRef Name; - if (error(SecI->getName(Name))) - Name = ""; + if (error(Section.getName(Name))) + Name = ""; ArrayRef<char> RawName = Obj->getSectionRawName(DR); StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); @@ -247,48 +234,40 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { W.printNumber("Index", SectionIndex); W.printBinary("Name", Name, RawName); W.printBinary("Segment", SegmentName, RawSegmentName); - W.printHex ("Address", Section.Address); - W.printHex ("Size", Section.Size); - W.printNumber("Offset", Section.Offset); - W.printNumber("Alignment", Section.Alignment); - W.printHex ("RelocationOffset", Section.RelocationTableOffset); - W.printNumber("RelocationCount", Section.NumRelocationTableEntries); - W.printEnum ("Type", Section.Flags & 0xFF, - makeArrayRef(MachOSectionAttributes)); - W.printFlags ("Attributes", Section.Flags >> 8, - makeArrayRef(MachOSectionAttributes)); - W.printHex ("Reserved1", Section.Reserved1); - W.printHex ("Reserved2", Section.Reserved2); + W.printHex("Address", MOSection.Address); + W.printHex("Size", MOSection.Size); + W.printNumber("Offset", MOSection.Offset); + W.printNumber("Alignment", MOSection.Alignment); + W.printHex("RelocationOffset", MOSection.RelocationTableOffset); + W.printNumber("RelocationCount", MOSection.NumRelocationTableEntries); + W.printEnum("Type", MOSection.Flags & 0xFF, + makeArrayRef(MachOSectionAttributes)); + W.printFlags("Attributes", MOSection.Flags >> 8, + makeArrayRef(MachOSectionAttributes)); + W.printHex("Reserved1", MOSection.Reserved1); + W.printHex("Reserved2", MOSection.Reserved2); if (opts::SectionRelocations) { ListScope D(W, "Relocations"); - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - - printRelocation(SecI, RelI); - } + for (const RelocationRef &Reloc : Section.relocations()) + printRelocation(Reloc); } if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - + for (const SymbolRef &Symbol : Obj->symbols()) { bool Contained = false; - if (SecI->containsSymbol(*SymI, Contained) || !Contained) + if (Section.containsSymbol(Symbol, Contained) || !Contained) continue; - printSymbol(SymI); + printSymbol(Symbol); } } if (opts::SectionData) { StringRef Data; - if (error(SecI->getContents(Data))) break; + if (error(Section.getContents(Data))) + break; W.printBinaryBlock("SectionData", Data); } @@ -299,28 +278,20 @@ void MachODumper::printRelocations() { ListScope D(W, "Relocations"); error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) break; - + for (const SectionRef &Section : Obj->sections()) { StringRef Name; - if (error(SecI->getName(Name))) + if (error(Section.getName(Name))) continue; bool PrintedGroup = false; - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - + for (const RelocationRef &Reloc : Section.relocations()) { if (!PrintedGroup) { W.startLine() << "Section " << Name << " {\n"; W.indent(); PrintedGroup = true; } - printRelocation(SecI, RelI); + printRelocation(Reloc); } if (PrintedGroup) { @@ -330,25 +301,24 @@ void MachODumper::printRelocations() { } } -void MachODumper::printRelocation(section_iterator SecI, - relocation_iterator RelI) { - return printRelocation(Obj, SecI, RelI); +void MachODumper::printRelocation(const RelocationRef &Reloc) { + return printRelocation(Obj, Reloc); } void MachODumper::printRelocation(const MachOObjectFile *Obj, - section_iterator SecI, - relocation_iterator RelI) { + const RelocationRef &Reloc) { uint64_t Offset; SmallString<32> RelocName; StringRef SymbolName; - if (error(RelI->getOffset(Offset))) return; - if (error(RelI->getTypeName(RelocName))) return; - symbol_iterator Symbol = RelI->getSymbol(); - if (Symbol != Obj->end_symbols() && - error(Symbol->getName(SymbolName))) + if (error(Reloc.getOffset(Offset))) + return; + if (error(Reloc.getTypeName(RelocName))) + return; + symbol_iterator Symbol = Reloc.getSymbol(); + if (Symbol != Obj->symbol_end() && error(Symbol->getName(SymbolName))) return; - DataRefImpl DR = RelI->getRawDataRefImpl(); + DataRefImpl DR = Reloc.getRawDataRefImpl(); MachO::any_relocation_info RE = Obj->getRelocation(DR); bool IsScattered = Obj->isRelocationScattered(RE); @@ -383,13 +353,8 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, void MachODumper::printSymbols() { ListScope Group(W, "Symbols"); - error_code EC; - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - - printSymbol(SymI); + for (const SymbolRef &Symbol : Obj->symbols()) { + printSymbol(Symbol); } } @@ -397,33 +362,37 @@ void MachODumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); } -void MachODumper::printSymbol(symbol_iterator SymI) { +void MachODumper::printSymbol(const SymbolRef &Symbol) { StringRef SymbolName; - if (SymI->getName(SymbolName)) + if (Symbol.getName(SymbolName)) SymbolName = ""; - MachOSymbol Symbol; - getSymbol(Obj, SymI->getRawDataRefImpl(), Symbol); + MachOSymbol MOSymbol; + getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol); StringRef SectionName = ""; - section_iterator SecI(Obj->end_sections()); - if (!error(SymI->getSection(SecI)) && - SecI != Obj->end_sections()) - error(SecI->getName(SectionName)); + section_iterator SecI(Obj->section_begin()); + if (!error(Symbol.getSection(SecI)) && SecI != Obj->section_end()) + error(SecI->getName(SectionName)); DictScope D(W, "Symbol"); - W.printNumber("Name", SymbolName, Symbol.StringIndex); - if (Symbol.Type & N_STAB) { - W.printHex ("Type", "SymDebugTable", Symbol.Type); + W.printNumber("Name", SymbolName, MOSymbol.StringIndex); + if (MOSymbol.Type & MachO::N_STAB) { + W.printHex("Type", "SymDebugTable", MOSymbol.Type); } else { - W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes)); + if (MOSymbol.Type & MachO::N_PEXT) + W.startLine() << "PrivateExtern\n"; + if (MOSymbol.Type & MachO::N_EXT) + W.startLine() << "Extern\n"; + W.printEnum("Type", uint8_t(MOSymbol.Type & MachO::N_TYPE), + makeArrayRef(MachOSymbolTypes)); } - W.printHex ("Section", SectionName, Symbol.SectionIndex); - W.printEnum ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF), - makeArrayRef(MachOSymbolRefTypes)); - W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF), - makeArrayRef(MachOSymbolFlags)); - W.printHex ("Value", Symbol.Value); + W.printHex("Section", SectionName, MOSymbol.SectionIndex); + W.printEnum("RefType", static_cast<uint16_t>(MOSymbol.Flags & 0xF), + makeArrayRef(MachOSymbolRefTypes)); + W.printFlags("Flags", static_cast<uint16_t>(MOSymbol.Flags & ~0xF), + makeArrayRef(MachOSymbolFlags)); + W.printHex("Value", MOSymbol.Value); } void MachODumper::printUnwindInfo() { diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp index 61f5117..f500a05 100644 --- a/tools/llvm-readobj/ObjDumper.cpp +++ b/tools/llvm-readobj/ObjDumper.cpp @@ -13,10 +13,8 @@ //===----------------------------------------------------------------------===// #include "ObjDumper.h" - #include "Error.h" #include "StreamWriter.h" - #include "llvm/ADT/StringRef.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/raw_ostream.h" diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index 6918e28..9e0fd2f 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -10,6 +10,8 @@ #ifndef LLVM_READOBJ_OBJDUMPER_H #define LLVM_READOBJ_OBJDUMPER_H +#include <memory> + namespace llvm { namespace object { @@ -18,9 +20,6 @@ namespace object { class error_code; -template<typename T> -class OwningPtr; - class StreamWriter; class ObjDumper { @@ -40,21 +39,22 @@ public: virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } + // Only implemented for ARM ELF at this time. + virtual void printAttributes() { } + protected: StreamWriter& W; }; -error_code createCOFFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result); +error_code createCOFFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); -error_code createELFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result); +error_code createELFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); error_code createMachODumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr<ObjDumper> &Result); + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); } // namespace llvm diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h index 129f6e7..c40077a 100644 --- a/tools/llvm-readobj/StreamWriter.h +++ b/tools/llvm-readobj/StreamWriter.h @@ -11,8 +11,8 @@ #define LLVM_READOBJ_STREAMWRITER_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" @@ -172,6 +172,19 @@ public: startLine() << Label << ": " << int(Value) << "\n"; } + template <typename T_> + void printList(StringRef Label, const SmallVectorImpl<T_> &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (unsigned LI = 0, LE = List.size(); LI != LE; ++LI) { + if (Comma) + OS << ", "; + OS << List[LI]; + Comma = true; + } + OS << "]\n"; + } + template<typename T> void printHex(StringRef Label, T Value) { startLine() << Label << ": " << hex(Value) << "\n"; diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index f84a72f..5be959f 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -20,11 +20,9 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" - #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.h" - #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" @@ -38,7 +36,6 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/system_error.h" - #include <string> @@ -128,6 +125,16 @@ namespace opts { // -expand-relocs cl::opt<bool> ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); + + // -codeview-linetables + cl::opt<bool> CodeViewLineTables("codeview-linetables", + cl::desc("Display CodeView line table information")); + + // -arm-attributes, -a + cl::opt<bool> ARMAttributes("arm-attributes", + cl::desc("Display the ARM attributes section")); + cl::alias ARMAttributesShort("-a", cl::desc("Alias for --arm-attributes"), + cl::aliasopt(ARMAttributes)); } // namespace opts static int ReturnValue = EXIT_SUCCESS; @@ -172,9 +179,8 @@ static void reportError(StringRef Input, StringRef Message) { } /// @brief Creates an format-specific object file dumper. -static error_code createDumper(const ObjectFile *Obj, - StreamWriter &Writer, - OwningPtr<ObjDumper> &Result) { +static error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { if (!Obj) return readobj_error::unsupported_file_format; @@ -192,7 +198,7 @@ static error_code createDumper(const ObjectFile *Obj, /// @brief Dumps the specified object file. static void dumpObject(const ObjectFile *Obj) { StreamWriter Writer(outs()); - OwningPtr<ObjDumper> Dumper; + std::unique_ptr<ObjDumper> Dumper; if (error_code EC = createDumper(Obj, Writer, Dumper)) { reportError(Obj->getFileName(), EC); return; @@ -226,15 +232,18 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printNeededLibraries(); if (opts::ProgramHeaders) Dumper->printProgramHeaders(); + if (Obj->getArch() == llvm::Triple::arm && Obj->isELF()) + if (opts::ARMAttributes) + Dumper->printAttributes(); } /// @brief Dumps each object file in \a Arc; static void dumpArchive(const Archive *Arc) { - for (Archive::child_iterator ArcI = Arc->begin_children(), - ArcE = Arc->end_children(); + for (Archive::child_iterator ArcI = Arc->child_begin(), + ArcE = Arc->child_end(); ArcI != ArcE; ++ArcI) { - OwningPtr<Binary> child; + std::unique_ptr<Binary> child; if (error_code EC = ArcI->getAsBinary(child)) { // Ignore non-object files. if (EC != object_error::invalid_file_type) @@ -259,11 +268,12 @@ static void dumpInput(StringRef File) { } // Attempt to open the binary. - OwningPtr<Binary> Binary; - if (error_code EC = createBinary(File, Binary)) { + ErrorOr<Binary *> BinaryOrErr = createBinary(File); + if (error_code EC = BinaryOrErr.getError()) { reportError(File, EC); return; } + std::unique_ptr<Binary> Binary(BinaryOrErr.get()); if (Archive *Arc = dyn_cast<Archive>(Binary.get())) dumpArchive(Arc); diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h index 3f75610..cc5c85d 100644 --- a/tools/llvm-readobj/llvm-readobj.h +++ b/tools/llvm-readobj/llvm-readobj.h @@ -38,6 +38,8 @@ namespace opts { extern llvm::cl::opt<bool> DynamicSymbols; extern llvm::cl::opt<bool> UnwindInfo; extern llvm::cl::opt<bool> ExpandRelocs; + extern llvm::cl::opt<bool> CodeViewLineTables; + extern llvm::cl::opt<bool> ARMAttributes; } // namespace opts #define LLVM_READOBJ_ENUM_ENT(ns, enum) \ diff --git a/tools/llvm-rtdyld/CMakeLists.txt b/tools/llvm-rtdyld/CMakeLists.txt index 8d161d3..3ad127f 100644 --- a/tools/llvm-rtdyld/CMakeLists.txt +++ b/tools/llvm-rtdyld/CMakeLists.txt @@ -1,4 +1,9 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC object RuntimeDyld JIT debuginfo) +set(LLVM_LINK_COMPONENTS + DebugInfo + ExecutionEngine + RuntimeDyld + Support + ) add_llvm_tool(llvm-rtdyld llvm-rtdyld.cpp diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 531595e..ac43653 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringMap.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/ExecutionEngine/ObjectBuffer.h" @@ -62,17 +61,18 @@ public: SmallVector<sys::MemoryBlock, 16> DataMemory; uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, StringRef SectionName); + unsigned SectionID, + StringRef SectionName) override; uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, - bool IsReadOnly); + bool IsReadOnly) override; - virtual void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true) { + void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true) override { return 0; } - bool finalizeMemory(std::string *ErrMsg) { return false; } + 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 @@ -133,14 +133,14 @@ static int printLineInfoForInput() { RuntimeDyld Dyld(&MemMgr); // Load the input memory buffer. - OwningPtr<MemoryBuffer> InputBuffer; - OwningPtr<ObjectImage> LoadedObject; + std::unique_ptr<MemoryBuffer> InputBuffer; + std::unique_ptr<ObjectImage> LoadedObject; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], InputBuffer)) return Error("unable to read input: '" + ec.message() + "'"); // Load the object file - LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.take()))); + LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.release()))); if (!LoadedObject) { return Error(Dyld.getErrorString()); } @@ -148,14 +148,13 @@ static int printLineInfoForInput() { // Resolve all the relocations we can. Dyld.resolveRelocations(); - OwningPtr<DIContext> Context(DIContext::getDWARFContext(LoadedObject->getObjectFile())); + std::unique_ptr<DIContext> Context( + DIContext::getDWARFContext(LoadedObject->getObjectFile())); // Use symbol info to iterate functions in the object. - error_code ec; for (object::symbol_iterator I = LoadedObject->begin_symbols(), E = LoadedObject->end_symbols(); - I != E && !ec; - I.increment(ec)) { + I != E; ++I) { object::SymbolRef::Type SymType; if (I->getType(SymType)) continue; if (SymType == object::SymbolRef::ST_Function) { @@ -193,14 +192,14 @@ static int executeInput() { InputFileList.push_back("-"); for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { // Load the input memory buffer. - OwningPtr<MemoryBuffer> InputBuffer; - OwningPtr<ObjectImage> LoadedObject; + std::unique_ptr<MemoryBuffer> InputBuffer; + std::unique_ptr<ObjectImage> LoadedObject; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], InputBuffer)) return Error("unable to read input: '" + ec.message() + "'"); // Load the object file - LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.take()))); + LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.release()))); if (!LoadedObject) { return Error(Dyld.getErrorString()); } diff --git a/tools/llvm-shlib/Makefile b/tools/llvm-shlib/Makefile index 92f3132..7bbc24c 100644 --- a/tools/llvm-shlib/Makefile +++ b/tools/llvm-shlib/Makefile @@ -10,10 +10,12 @@ LEVEL := ../.. LIBRARYNAME = LLVM-$(LLVMVersion) +LIBRARYALIASNAME = LLVM-$(LLVM_VERSION_MAJOR).$(LLVM_VERSION_MINOR)$(LLVM_VERSION_SUFFIX) NO_BUILD_ARCHIVE := 1 LINK_LIBS_IN_SHARED := 1 SHARED_LIBRARY := 1 +SHARED_ALIAS := 1 include $(LEVEL)/Makefile.config @@ -49,17 +51,6 @@ ifeq ($(HOST_OS),Darwin) endif # Include everything from the .a's into the shared library. LLVMLibsOptions := $(LLVMLibsOptions) -all_load - # extra options to override libtool defaults - LLVMLibsOptions := $(LLVMLibsOptions) \ - -Wl,-dead_strip - - # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line - DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') - ifneq ($(DARWIN_VERS),8) - LLVMLibsOptions := $(LLVMLibsOptions) \ - -Wl,-install_name \ - -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" - endif endif ifeq ($(HOST_OS), $(filter $(HOST_OS), DragonFly Linux FreeBSD GNU/kFreeBSD OpenBSD GNU Bitrig)) diff --git a/tools/llvm-size/CMakeLists.txt b/tools/llvm-size/CMakeLists.txt index 933cc75..6034573 100644 --- a/tools/llvm-size/CMakeLists.txt +++ b/tools/llvm-size/CMakeLists.txt @@ -1,4 +1,7 @@ -set(LLVM_LINK_COMPONENTS object) +set(LLVM_LINK_COMPONENTS + Object + Support + ) add_llvm_tool(llvm-size llvm-size.cpp diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp index 3de6605..d1bd45a 100644 --- a/tools/llvm-size/llvm-size.cpp +++ b/tools/llvm-size/llvm-size.cpp @@ -85,10 +85,10 @@ static size_t getNumLengthAsString(uint64_t num) { return result.size(); } -/// @brief Print the size of each section in @p o. +/// @brief Print the size of each section in @p Obj. /// /// The format used is determined by @c OutputFormat and @c Radix. -static void PrintObjectSectionSizes(ObjectFile *o) { +static void PrintObjectSectionSizes(ObjectFile *Obj) { uint64_t total = 0; std::string fmtbuf; raw_string_ostream fmt(fmtbuf); @@ -111,21 +111,18 @@ static void PrintObjectSectionSizes(ObjectFile *o) { std::size_t max_name_len = strlen("section"); std::size_t max_size_len = strlen("size"); std::size_t max_addr_len = strlen("addr"); - error_code ec; - for (section_iterator i = o->begin_sections(), - e = o->end_sections(); i != e; - i.increment(ec)) { - if (error(ec)) - return; + for (const SectionRef &Section : Obj->sections()) { uint64_t size = 0; - if (error(i->getSize(size))) + if (error(Section.getSize(size))) return; total += size; StringRef name; uint64_t addr = 0; - if (error(i->getName(name))) return; - if (error(i->getAddress(addr))) return; + if (error(Section.getName(name))) + return; + if (error(Section.getAddress(addr))) + return; max_name_len = std::max(max_name_len, name.size()); max_size_len = std::max(max_size_len, getNumLengthAsString(size)); max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr)); @@ -154,24 +151,19 @@ static void PrintObjectSectionSizes(ObjectFile *o) { << "%#" << max_addr_len << radix_fmt << "\n"; // Print each section. - for (section_iterator i = o->begin_sections(), - e = o->end_sections(); i != e; - i.increment(ec)) { - if (error(ec)) - return; - + for (const SectionRef &Section : Obj->sections()) { StringRef name; uint64_t size = 0; uint64_t addr = 0; - if (error(i->getName(name))) return; - if (error(i->getSize(size))) return; - if (error(i->getAddress(addr))) return; + if (error(Section.getName(name))) + return; + if (error(Section.getSize(size))) + return; + if (error(Section.getAddress(addr))) + return; std::string namestr = name; - outs() << format(fmt.str().c_str(), - namestr.c_str(), - size, - addr); + outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr); } // Print total. @@ -189,21 +181,19 @@ static void PrintObjectSectionSizes(ObjectFile *o) { uint64_t total_bss = 0; // Make one pass over the section table to calculate sizes. - error_code ec; - for (section_iterator i = o->begin_sections(), - e = o->end_sections(); i != e; - i.increment(ec)) { - if (error(ec)) - return; - + for (const SectionRef &Section : Obj->sections()) { uint64_t size = 0; bool isText = false; bool isData = false; bool isBSS = false; - if (error(i->getSize(size))) return; - if (error(i->isText(isText))) return; - if (error(i->isData(isData))) return; - if (error(i->isBSS(isBSS))) return; + if (error(Section.getSize(size))) + return; + if (error(Section.isText(isText))) + return; + if (error(Section.isData(isData))) + return; + if (error(Section.isBSS(isBSS))) + return; if (isText) total_text += size; else if (isData) @@ -244,17 +234,18 @@ static void PrintFileSectionSizes(StringRef file) { } // Attempt to open the binary. - OwningPtr<Binary> binary; - if (error_code ec = createBinary(file, binary)) { - errs() << ToolName << ": " << file << ": " << ec.message() << ".\n"; + ErrorOr<Binary *> BinaryOrErr = createBinary(file); + if (error_code EC = BinaryOrErr.getError()) { + errs() << ToolName << ": " << file << ": " << EC.message() << ".\n"; return; } + std::unique_ptr<Binary> binary(BinaryOrErr.get()); if (Archive *a = dyn_cast<Archive>(binary.get())) { // This is an archive. Iterate over each member and display its sizes. - for (object::Archive::child_iterator i = a->begin_children(), - e = a->end_children(); i != e; ++i) { - OwningPtr<Binary> child; + for (object::Archive::child_iterator i = a->child_begin(), + e = a->child_end(); i != e; ++i) { + std::unique_ptr<Binary> child; if (error_code ec = i->getAsBinary(child)) { errs() << ToolName << ": " << file << ": " << ec.message() << ".\n"; continue; diff --git a/tools/llvm-stress/CMakeLists.txt b/tools/llvm-stress/CMakeLists.txt index e2d07a5..106ced1 100644 --- a/tools/llvm-stress/CMakeLists.txt +++ b/tools/llvm-stress/CMakeLists.txt @@ -1,5 +1,10 @@ -set(LLVM_LINK_COMPONENTS bitreader asmparser bitwriter instrumentation scalaropts ipo) +set(LLVM_LINK_COMPONENTS + Core + IPA + Support + ) add_llvm_tool(llvm-stress llvm-stress.cpp ) +set_target_properties(llvm-stress PROPERTIES ENABLE_EXPORTS 1) diff --git a/tools/llvm-stress/Makefile b/tools/llvm-stress/Makefile index 8767cbe..29245af 100644 --- a/tools/llvm-stress/Makefile +++ b/tools/llvm-stress/Makefile @@ -12,7 +12,4 @@ TOOLNAME := llvm-stress LINK_COMPONENTS := object LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts ipo -# This tool has no plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 - include $(LEVEL)/Makefile.common diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp index fd10baf..18f1e6c 100644 --- a/tools/llvm-stress/llvm-stress.cpp +++ b/tools/llvm-stress/llvm-stress.cpp @@ -11,18 +11,18 @@ // different components in LLVM. // //===----------------------------------------------------------------------===// -#include "llvm/IR/LLVMContext.h" -#include "llvm/ADT/OwningPtr.h" + #include "llvm/Analysis/CallGraphSCCPass.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Assembly/PrintModulePass.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/PassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/ToolOutputFile.h" @@ -288,8 +288,8 @@ protected: struct LoadModifier: public Modifier { LoadModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} - virtual void Act() { - // Try to use predefined pointers. If non exist, use undef pointer value; + void Act() override { + // Try to use predefined pointers. If non-exist, use undef pointer value; Value *Ptr = getRandomPointerValue(); Value *V = new LoadInst(Ptr, "L", BB->getTerminator()); PT->push_back(V); @@ -298,8 +298,8 @@ struct LoadModifier: public Modifier { struct StoreModifier: public Modifier { StoreModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} - virtual void Act() { - // Try to use predefined pointers. If non exist, use undef pointer value; + void Act() override { + // Try to use predefined pointers. If non-exist, use undef pointer value; Value *Ptr = getRandomPointerValue(); Type *Tp = Ptr->getType(); Value *Val = getRandomValue(Tp->getContainedType(0)); @@ -317,7 +317,7 @@ struct StoreModifier: public Modifier { struct BinModifier: public Modifier { BinModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} - virtual void Act() { + void Act() override { Value *Val0 = getRandomVal(); Value *Val1 = getRandomValue(Val0->getType()); @@ -360,7 +360,7 @@ struct BinModifier: public Modifier { /// Generate constant values. struct ConstModifier: public Modifier { ConstModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} - virtual void Act() { + void Act() override { Type *Ty = pickType(); if (Ty->isVectorTy()) { @@ -407,7 +407,7 @@ struct ConstModifier: public Modifier { struct AllocaModifier: public Modifier { AllocaModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R){} - virtual void Act() { + void Act() override { Type *Tp = pickType(); PT->push_back(new AllocaInst(Tp, "A", BB->getFirstNonPHI())); } @@ -417,7 +417,7 @@ struct ExtractElementModifier: public Modifier { ExtractElementModifier(BasicBlock *BB, PieceTable *PT, Random *R): Modifier(BB, PT, R) {} - virtual void Act() { + void Act() override { Value *Val0 = getRandomVectorValue(); Value *V = ExtractElementInst::Create(Val0, ConstantInt::get(Type::getInt32Ty(BB->getContext()), @@ -429,7 +429,7 @@ struct ExtractElementModifier: public Modifier { struct ShuffModifier: public Modifier { ShuffModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} - virtual void Act() { + void Act() override { Value *Val0 = getRandomVectorValue(); Value *Val1 = getRandomValue(Val0->getType()); @@ -458,7 +458,7 @@ struct InsertElementModifier: public Modifier { InsertElementModifier(BasicBlock *BB, PieceTable *PT, Random *R): Modifier(BB, PT, R) {} - virtual void Act() { + void Act() override { Value *Val0 = getRandomVectorValue(); Value *Val1 = getRandomValue(Val0->getType()->getScalarType()); @@ -473,7 +473,7 @@ struct InsertElementModifier: public Modifier { struct CastModifier: public Modifier { CastModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} - virtual void Act() { + void Act() override { Value *V = getRandomVal(); Type *VTy = V->getType(); @@ -560,7 +560,7 @@ struct SelectModifier: public Modifier { SelectModifier(BasicBlock *BB, PieceTable *PT, Random *R): Modifier(BB, PT, R) {} - virtual void Act() { + void Act() override { // Try a bunch of different select configuration until a valid one is found. Value *Val0 = getRandomVal(); Value *Val1 = getRandomValue(Val0->getType()); @@ -583,7 +583,7 @@ struct SelectModifier: public Modifier { struct CmpModifier: public Modifier { CmpModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} - virtual void Act() { + void Act() override { Value *Val0 = getRandomVal(); Value *Val1 = getRandomValue(Val0->getType()); @@ -625,15 +625,15 @@ static void FillFunction(Function *F, Random &R) { // List of modifiers which add new random instructions. std::vector<Modifier*> Modifiers; - OwningPtr<Modifier> LM(new LoadModifier(BB, &PT, &R)); - OwningPtr<Modifier> SM(new StoreModifier(BB, &PT, &R)); - OwningPtr<Modifier> EE(new ExtractElementModifier(BB, &PT, &R)); - OwningPtr<Modifier> SHM(new ShuffModifier(BB, &PT, &R)); - OwningPtr<Modifier> IE(new InsertElementModifier(BB, &PT, &R)); - OwningPtr<Modifier> BM(new BinModifier(BB, &PT, &R)); - OwningPtr<Modifier> CM(new CastModifier(BB, &PT, &R)); - OwningPtr<Modifier> SLM(new SelectModifier(BB, &PT, &R)); - OwningPtr<Modifier> PM(new CmpModifier(BB, &PT, &R)); + std::unique_ptr<Modifier> LM(new LoadModifier(BB, &PT, &R)); + std::unique_ptr<Modifier> SM(new StoreModifier(BB, &PT, &R)); + std::unique_ptr<Modifier> EE(new ExtractElementModifier(BB, &PT, &R)); + std::unique_ptr<Modifier> SHM(new ShuffModifier(BB, &PT, &R)); + std::unique_ptr<Modifier> IE(new InsertElementModifier(BB, &PT, &R)); + std::unique_ptr<Modifier> BM(new BinModifier(BB, &PT, &R)); + std::unique_ptr<Modifier> CM(new CastModifier(BB, &PT, &R)); + std::unique_ptr<Modifier> SLM(new SelectModifier(BB, &PT, &R)); + std::unique_ptr<Modifier> PM(new CmpModifier(BB, &PT, &R)); Modifiers.push_back(LM.get()); Modifiers.push_back(SM.get()); Modifiers.push_back(EE.get()); @@ -687,7 +687,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm codegen stress-tester\n"); llvm_shutdown_obj Y; - OwningPtr<Module> M(new Module("/tmp/autogen.bc", getGlobalContext())); + std::unique_ptr<Module> M(new Module("/tmp/autogen.bc", getGlobalContext())); Function *F = GenEmptyFunction(M.get()); // Pick an initial seed value @@ -698,14 +698,14 @@ int main(int argc, char **argv) { IntroduceControlFlow(F, R); // Figure out what stream we are supposed to write to... - OwningPtr<tool_output_file> Out; + std::unique_ptr<tool_output_file> Out; // Default to standard output. if (OutputFilename.empty()) OutputFilename = "-"; std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - sys::fs::F_Binary)); + sys::fs::F_None)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; @@ -713,7 +713,7 @@ int main(int argc, char **argv) { PassManager Passes; Passes.add(createVerifierPass()); - Passes.add(createPrintModulePass(&Out->os())); + Passes.add(createPrintModulePass(Out->os())); Passes.run(*M.get()); Out->keep(); diff --git a/tools/llvm-symbolizer/CMakeLists.txt b/tools/llvm-symbolizer/CMakeLists.txt index 5967b89..9e76248 100644 --- a/tools/llvm-symbolizer/CMakeLists.txt +++ b/tools/llvm-symbolizer/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS DebugInfo Object + Support ) add_llvm_tool(llvm-symbolizer diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index 320ab3f..13f2f8f 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -14,6 +14,7 @@ #include "LLVMSymbolize.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" @@ -21,7 +22,6 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" - #include <sstream> #include <stdlib.h> @@ -53,43 +53,51 @@ static void patchFunctionNameInDILineInfo(const std::string &NewFunctionName, ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx) : Module(Obj), DebugInfoContext(DICtx) { - error_code ec; - for (symbol_iterator si = Module->begin_symbols(), se = Module->end_symbols(); - si != se; si.increment(ec)) { - if (error(ec)) - return; - SymbolRef::Type SymbolType; - if (error(si->getType(SymbolType))) - continue; - if (SymbolType != SymbolRef::ST_Function && - SymbolType != SymbolRef::ST_Data) - continue; - uint64_t SymbolAddress; - if (error(si->getAddress(SymbolAddress)) || - SymbolAddress == UnknownAddressOrSize) - continue; - uint64_t SymbolSize; - // Getting symbol size is linear for Mach-O files, so assume that symbol - // occupies the memory range up to the following symbol. - if (isa<MachOObjectFile>(Obj)) - SymbolSize = 0; - else if (error(si->getSize(SymbolSize)) || - SymbolSize == UnknownAddressOrSize) - continue; - StringRef SymbolName; - if (error(si->getName(SymbolName))) - continue; - // 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. - SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; - SymbolDesc SD = { SymbolAddress, SymbolSize }; - M.insert(std::make_pair(SD, SymbolName)); + for (const SymbolRef &Symbol : Module->symbols()) { + addSymbol(Symbol); + } + bool NoSymbolTable = (Module->symbol_begin() == Module->symbol_end()); + if (NoSymbolTable && Module->isELF()) { + // Fallback to dynamic symbol table, if regular symbol table is stripped. + std::pair<symbol_iterator, symbol_iterator> IDyn = + getELFDynamicSymbolIterators(Module); + for (symbol_iterator si = IDyn.first, se = IDyn.second; si != se; ++si) { + addSymbol(*si); + } } } +void ModuleInfo::addSymbol(const SymbolRef &Symbol) { + SymbolRef::Type SymbolType; + if (error(Symbol.getType(SymbolType))) + return; + if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data) + return; + uint64_t SymbolAddress; + if (error(Symbol.getAddress(SymbolAddress)) || + SymbolAddress == UnknownAddressOrSize) + return; + uint64_t SymbolSize; + // Getting symbol size is linear for Mach-O files, so assume that symbol + // occupies the memory range up to the following symbol. + if (isa<MachOObjectFile>(Module)) + SymbolSize = 0; + else if (error(Symbol.getSize(SymbolSize)) || + SymbolSize == UnknownAddressOrSize) + return; + StringRef SymbolName; + if (error(Symbol.getName(SymbolName))) + return; + // 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. + SymbolMapTy &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 { @@ -196,7 +204,7 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, if (Opts.UseSymbolTable) { if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) { if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle) - Name = DemangleGlobalName(Name); + Name = DemangleName(Name); } } std::stringstream ss; @@ -221,7 +229,7 @@ static std::string getDarwinDWARFResourceForPath(const std::string &Path) { } static bool checkFileCRC(StringRef Path, uint32_t CRCHash) { - OwningPtr<MemoryBuffer> MB; + std::unique_ptr<MemoryBuffer> MB; if (MemoryBuffer::getFileOrSTDIN(Path, MB)) return false; return !zlib::isAvailable() || CRCHash == zlib::crc32(MB->getBuffer()); @@ -269,15 +277,13 @@ static bool getGNUDebuglinkContents(const Binary *Bin, std::string &DebugName, const ObjectFile *Obj = dyn_cast<ObjectFile>(Bin); if (!Obj) return false; - error_code EC; - for (section_iterator I = Obj->begin_sections(), E = Obj->end_sections(); - I != E; I.increment(EC)) { + for (const SectionRef &Section : Obj->sections()) { StringRef Name; - I->getName(Name); + Section.getName(Name); Name = Name.substr(Name.find_first_not_of("._")); if (Name == "gnu_debuglink") { StringRef Data; - I->getContents(Data); + Section.getContents(Data); DataExtractor DE(Data, Obj->isLittleEndian(), 0); uint32_t Offset = 0; if (const char *DebugNameStr = DE.getCStr(&Offset)) { @@ -302,22 +308,21 @@ LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { return I->second; Binary *Bin = 0; Binary *DbgBin = 0; - OwningPtr<Binary> ParsedBinary; - OwningPtr<Binary> ParsedDbgBinary; - if (!error(createBinary(Path, ParsedBinary))) { + ErrorOr<Binary *> BinaryOrErr = createBinary(Path); + if (!error(BinaryOrErr.getError())) { + std::unique_ptr<Binary> ParsedBinary(BinaryOrErr.get()); // Check if it's a universal binary. - Bin = ParsedBinary.take(); + Bin = ParsedBinary.release(); ParsedBinariesAndObjects.push_back(Bin); if (Bin->isMachO() || Bin->isMachOUniversalBinary()) { // On Darwin we may find DWARF in separate object file in // resource directory. const std::string &ResourcePath = getDarwinDWARFResourceForPath(Path); - bool ResourceFileExists = false; - if (!sys::fs::exists(ResourcePath, ResourceFileExists) && - ResourceFileExists && - !error(createBinary(ResourcePath, ParsedDbgBinary))) { - DbgBin = ParsedDbgBinary.take(); + BinaryOrErr = createBinary(ResourcePath); + error_code EC = BinaryOrErr.getError(); + if (EC != errc::no_such_file_or_directory && !error(EC)) { + DbgBin = BinaryOrErr.get(); ParsedBinariesAndObjects.push_back(DbgBin); } } @@ -327,10 +332,12 @@ LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { uint32_t CRCHash; std::string DebugBinaryPath; if (getGNUDebuglinkContents(Bin, DebuglinkName, CRCHash) && - findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath) && - !error(createBinary(DebugBinaryPath, ParsedDbgBinary))) { - DbgBin = ParsedDbgBinary.take(); - ParsedBinariesAndObjects.push_back(DbgBin); + findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) { + BinaryOrErr = createBinary(DebugBinaryPath); + if (!error(BinaryOrErr.getError())) { + DbgBin = BinaryOrErr.get(); + ParsedBinariesAndObjects.push_back(DbgBin); + } } } } @@ -351,9 +358,9 @@ LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName std::make_pair(UB, ArchName)); if (I != ObjectFileForArch.end()) return I->second; - OwningPtr<ObjectFile> ParsedObj; + std::unique_ptr<ObjectFile> ParsedObj; if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) { - Res = ParsedObj.take(); + Res = ParsedObj.release(); ParsedBinariesAndObjects.push_back(Res); } ObjectFileForArch[std::make_pair(UB, ArchName)] = Res; @@ -424,6 +431,10 @@ extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, 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(), 0, 0, &status); if (status != 0) @@ -436,11 +447,5 @@ std::string LLVMSymbolizer::DemangleName(const std::string &Name) { #endif } -std::string LLVMSymbolizer::DemangleGlobalName(const std::string &Name) { - // We can spoil names of globals with C linkage, so use an heuristic - // approach to check if the name should be demangled. - return (Name.substr(0, 2) == "_Z") ? DemangleName(Name) : Name; -} - } // namespace symbolize } // namespace llvm diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h index eb2666a..288be80 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.h +++ b/tools/llvm-symbolizer/LLVMSymbolize.h @@ -13,7 +13,6 @@ #ifndef LLVM_SYMBOLIZE_H #define LLVM_SYMBOLIZE_H -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/Object/MachOUniversal.h" @@ -71,7 +70,6 @@ private: ObjectFile *getObjectFileFromBinary(Binary *Bin, const std::string &ArchName); std::string printDILineInfo(DILineInfo LineInfo) const; - static std::string DemangleGlobalName(const std::string &Name); // Owns all the parsed binaries and object files. SmallVector<Binary*, 4> ParsedBinariesAndObjects; @@ -103,8 +101,9 @@ private: bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, std::string &Name, uint64_t &Addr, uint64_t &Size) const; + void addSymbol(const SymbolRef &Symbol); ObjectFile *Module; - OwningPtr<DIContext> DebugInfoContext; + std::unique_ptr<DIContext> DebugInfoContext; struct SymbolDesc { uint64_t Addr; diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp index c32e949..83f5c5e 100644 --- a/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -51,6 +51,11 @@ static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""), cl::desc("Default architecture " "(for multi-arch objects)")); +static cl::opt<std::string> +ClBinaryName("obj", cl::init(""), + cl::desc("Path to object file to be symbolized (if not provided, " + "object file should be specified for each input line)")); + static bool parseCommand(bool &IsData, std::string &ModuleName, uint64_t &ModuleOffset) { const char *kDataCmd = "DATA "; @@ -62,7 +67,6 @@ static bool parseCommand(bool &IsData, std::string &ModuleName, return false; IsData = false; ModuleName = ""; - std::string ModuleOffsetStr = ""; char *pos = InputString; if (strncmp(pos, kDataCmd, strlen(kDataCmd)) == 0) { IsData = true; @@ -74,26 +78,29 @@ static bool parseCommand(bool &IsData, std::string &ModuleName, // If no cmd, assume it's CODE. IsData = false; } - // Skip delimiters and parse input filename. - pos += strspn(pos, kDelimiters); - if (*pos == '"' || *pos == '\'') { - char quote = *pos; - pos++; - char *end = strchr(pos, quote); - if (end == 0) - return false; - ModuleName = std::string(pos, end - pos); - pos = end + 1; + // Skip delimiters and parse input filename (if needed). + if (ClBinaryName == "") { + pos += strspn(pos, kDelimiters); + if (*pos == '"' || *pos == '\'') { + char quote = *pos; + pos++; + char *end = strchr(pos, quote); + if (end == 0) + return false; + ModuleName = std::string(pos, end - pos); + pos = end + 1; + } else { + int name_length = strcspn(pos, kDelimiters); + ModuleName = std::string(pos, name_length); + pos += name_length; + } } else { - int name_length = strcspn(pos, kDelimiters); - ModuleName = std::string(pos, name_length); - pos += name_length; + ModuleName = ClBinaryName; } // Skip delimiters and parse module offset. pos += strspn(pos, kDelimiters); int offset_length = strcspn(pos, kDelimiters); - ModuleOffsetStr = std::string(pos, offset_length); - if (StringRef(ModuleOffsetStr).getAsInteger(0, ModuleOffset)) + if (StringRef(pos, offset_length).getAsInteger(0, ModuleOffset)) return false; return true; } @@ -104,7 +111,7 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n"); + cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n"); LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions, ClPrintInlining, ClDemangle, ClDefaultArch); LLVMSymbolizer Symbolizer(Opts); diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt index 957a9f0..542053b 100644 --- a/tools/lto/CMakeLists.txt +++ b/tools/lto/CMakeLists.txt @@ -1,6 +1,11 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - ipo scalaropts linker bitreader bitwriter lto mcdisassembler vectorize) + Core + LTO + MC + MCDisassembler + Support + ) add_definitions( -DLLVM_VERSION_INFO=\"${PACKAGE_VERSION}\" ) @@ -9,43 +14,13 @@ set(SOURCES lto.cpp ) -if( NOT CYGWIN AND LLVM_ENABLE_PIC ) - if ( WIN32 ) - # Create .def file containing a list of exports preceeded by - # 'EXPORTS'. The file "lto.exports" already contains the list, so we - # massage it into the correct format here to create "lto.exports.def". - set(LTO_EXPORTS_DEF ${CMAKE_CURRENT_BINARY_DIR}/lto.exports.def) - set(LTO_EXPORTS_DEF_TEMP ${LTO_EXPORTS_DEF}.txt) - file(READ "lto.exports" exports_list) - file(WRITE ${LTO_EXPORTS_DEF_TEMP} "LIBRARY LTO\n") - file(APPEND ${LTO_EXPORTS_DEF_TEMP} "EXPORTS\n") - file(APPEND ${LTO_EXPORTS_DEF_TEMP} ${exports_list}) - - # Copy the file only if it has changed. - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${LTO_EXPORTS_DEF_TEMP} ${LTO_EXPORTS_DEF}) - - set(SHARED_LIB_SOURCES ${SOURCES} ${LTO_EXPORTS_DEF}) - else() - set(SHARED_LIB_SOURCES ${SOURCES}) - endif() +set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/lto.exports) - set(bsl ${BUILD_SHARED_LIBS}) - set(BUILD_SHARED_LIBS ON) - add_llvm_library(LTO ${SHARED_LIB_SOURCES}) - set_property(TARGET LTO PROPERTY OUTPUT_NAME "LTO") - set(BUILD_SHARED_LIBS ${bsl}) - set(LTO_STATIC_TARGET_NAME LTO_static) -else() - set(LTO_STATIC_TARGET_NAME LTO) +if(NOT CYGWIN AND LLVM_ENABLE_PIC) + set(ENABLE_SHARED SHARED) endif() -if( NOT BUILD_SHARED_LIBS ) - add_llvm_library(${LTO_STATIC_TARGET_NAME} ${SOURCES}) - set_property(TARGET ${LTO_STATIC_TARGET_NAME} PROPERTY OUTPUT_NAME "LTO") -endif() +add_llvm_library(LTO ${ENABLE_SHARED} STATIC ${SOURCES}) -if( NOT CYGWIN ) - install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/lto.h - DESTINATION include/llvm-c) -endif() +install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/lto.h + DESTINATION include/llvm-c) diff --git a/tools/lto/Makefile b/tools/lto/Makefile index cedbee1..a4fe9ac 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -9,8 +9,7 @@ LEVEL := ../.. LIBRARYNAME := LTO -LINK_COMPONENTS := all-targets ipo scalaropts linker bitreader bitwriter \ - lto mcdisassembler vectorize +LINK_COMPONENTS := all-targets core lto mc mcdisassembler support LINK_LIBS_IN_SHARED := 1 SHARED_LIBRARY := 1 @@ -37,17 +36,6 @@ ifeq ($(HOST_OS),Darwin) -Wl,$(LTO_LIBRARY_VERSION).$(LLVM_SUBMIT_SUBVERSION) \ -Wl,-compatibility_version -Wl,1 endif - # extra options to override libtool defaults - LLVMLibsOptions := $(LLVMLibsOptions) \ - -Wl,-dead_strip - - # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line - DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') - ifneq ($(DARWIN_VERS),8) - LLVMLibsOptions := $(LLVMLibsOptions) \ - -Wl,-install_name \ - -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" - endif # If we're doing an Apple-style build, add the LTO object path. ifeq ($(RC_XBS),YES) diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index 7bfddcd..cc8318a 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -13,11 +13,11 @@ //===----------------------------------------------------------------------===// #include "llvm-c/lto.h" +#include "llvm-c/Core.h" +#include "llvm-c/Target.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/LTO/LTOCodeGenerator.h" #include "llvm/LTO/LTOModule.h" -#include "llvm-c/Core.h" -#include "llvm-c/Target.h" // extra command-line flags needed for LTOCodeGenerator static cl::opt<bool> @@ -56,28 +56,6 @@ static void lto_initialize() { } } -static void lto_set_target_options(llvm::TargetOptions &Options) { - Options.LessPreciseFPMADOption = EnableFPMAD; - Options.NoFramePointerElim = DisableFPElim; - Options.AllowFPOpFusion = FuseFPOps; - Options.UnsafeFPMath = EnableUnsafeFPMath; - Options.NoInfsFPMath = EnableNoInfsFPMath; - Options.NoNaNsFPMath = EnableNoNaNsFPMath; - Options.HonorSignDependentRoundingFPMathOption = - EnableHonorSignDependentRoundingFPMath; - Options.UseSoftFloat = GenerateSoftFloatCalls; - if (FloatABIForCalls != llvm::FloatABI::Default) - Options.FloatABIType = FloatABIForCalls; - Options.NoZerosInBSS = DontPlaceZerosInBSS; - Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; - Options.DisableTailCalls = DisableTailCalls; - Options.StackAlignmentOverride = OverrideStackAlignment; - Options.TrapFuncName = TrapFuncName; - Options.PositionIndependentExecutable = EnablePIE; - Options.EnableSegmentedStacks = SegmentedStacks; - Options.UseInitArray = UseInitArray; -} - /// lto_get_version - Returns a printable string. extern const char* lto_get_version() { return LTOCodeGenerator::getVersionString(); @@ -120,8 +98,7 @@ lto_module_is_object_file_in_memory_for_target(const void* mem, /// (check lto_get_error_message() for details). lto_module_t lto_module_create(const char* path) { lto_initialize(); - llvm::TargetOptions Options; - lto_set_target_options(Options); + llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); return LTOModule::makeLTOModule(path, Options, sLastErrorString); } @@ -129,8 +106,7 @@ lto_module_t lto_module_create(const char* path) { /// error (check lto_get_error_message() for details). lto_module_t lto_module_create_from_fd(int fd, const char *path, size_t size) { lto_initialize(); - llvm::TargetOptions Options; - lto_set_target_options(Options); + llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); return LTOModule::makeLTOModule(fd, path, size, Options, sLastErrorString); } @@ -141,8 +117,7 @@ lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path, size_t map_size, off_t offset) { lto_initialize(); - llvm::TargetOptions Options; - lto_set_target_options(Options); + llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); return LTOModule::makeLTOModule(fd, path, map_size, offset, Options, sLastErrorString); } @@ -151,11 +126,20 @@ lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path, /// NULL on error (check lto_get_error_message() for details). lto_module_t lto_module_create_from_memory(const void* mem, size_t length) { lto_initialize(); - llvm::TargetOptions Options; - lto_set_target_options(Options); + llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); return LTOModule::makeLTOModule(mem, length, Options, sLastErrorString); } +/// Loads an object file from memory with an extra path argument. +/// Returns NULL on error (check lto_get_error_message() for details). +lto_module_t lto_module_create_from_memory_with_path(const void* mem, + size_t length, + const char *path) { + lto_initialize(); + llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + return LTOModule::makeLTOModule(mem, length, Options, sLastErrorString, path); +} + /// lto_module_dispose - Frees all memory for a module. Upon return the /// lto_module_t is no longer valid. void lto_module_dispose(lto_module_t mod) { @@ -193,13 +177,41 @@ lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod, return mod->getSymbolAttributes(index); } +/// lto_module_get_num_deplibs - Returns the number of dependent libraries in +/// the object module. +unsigned int lto_module_get_num_deplibs(lto_module_t mod) { + return mod->getDependentLibraryCount(); +} + +/// lto_module_get_deplib - Returns the ith dependent library in the module. +const char* lto_module_get_deplib(lto_module_t mod, unsigned int index) { + return mod->getDependentLibrary(index); +} + +/// lto_module_get_num_linkeropts - Returns the number of linker options in the +/// object module. +unsigned int lto_module_get_num_linkeropts(lto_module_t mod) { + return mod->getLinkerOptCount(); +} + +/// lto_module_get_linkeropt - Returns the ith linker option in the module. +const char* lto_module_get_linkeropt(lto_module_t mod, unsigned int index) { + return mod->getLinkerOpt(index); +} + +/// Set a diagnostic handler. +void lto_codegen_set_diagnostic_handler(lto_code_gen_t cg, + lto_diagnostic_handler_t diag_handler, + void *ctxt) { + cg->setDiagnosticHandler(diag_handler, ctxt); +} + /// lto_codegen_create - Instantiates a code generator. Returns NULL if there /// is an error. lto_code_gen_t lto_codegen_create(void) { lto_initialize(); - TargetOptions Options; - lto_set_target_options(Options); + TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); LTOCodeGenerator *CodeGen = new LTOCodeGenerator(); if (CodeGen) diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports index 46d0d74..b10ab1a 100644 --- a/tools/lto/lto.exports +++ b/tools/lto/lto.exports @@ -5,6 +5,11 @@ lto_module_create lto_module_create_from_fd lto_module_create_from_fd_at_offset lto_module_create_from_memory +lto_module_create_from_memory_with_path +lto_module_get_deplib +lto_module_get_linkeropt +lto_module_get_num_deplibs +lto_module_get_num_linkeropts lto_module_get_num_symbols lto_module_get_symbol_attribute lto_module_get_symbol_name @@ -15,6 +20,7 @@ lto_module_is_object_file_for_target lto_module_is_object_file_in_memory lto_module_is_object_file_in_memory_for_target lto_module_dispose +lto_codegen_set_diagnostic_handler lto_codegen_add_module lto_codegen_add_must_preserve_symbol lto_codegen_compile diff --git a/tools/macho-dump/CMakeLists.txt b/tools/macho-dump/CMakeLists.txt index d55e1d5..bc2dfbf 100644 --- a/tools/macho-dump/CMakeLists.txt +++ b/tools/macho-dump/CMakeLists.txt @@ -1,4 +1,7 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support object) +set(LLVM_LINK_COMPONENTS + Object + Support + ) add_llvm_tool(macho-dump macho-dump.cpp diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index 0dfbd5f..886487b 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -96,9 +96,9 @@ static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index, // Dump the relocation entries. outs() << " ('_relocations', [\n"; unsigned RelNum = 0; - error_code EC; for (relocation_iterator I = Obj.section_rel_begin(Index), - E = Obj.section_rel_end(Index); I != E; I.increment(EC), ++RelNum) { + 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"; @@ -201,11 +201,9 @@ static int DumpSymtabCommand(const MachOObjectFile &Obj) { // Dump the symbol table. outs() << " ('_symbols', [\n"; - error_code EC; unsigned SymNum = 0; - for (symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E; - I.increment(EC), ++SymNum) { - DataRefImpl DRI = I->getRawDataRefImpl(); + 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, @@ -217,6 +215,7 @@ static int DumpSymtabCommand(const MachOObjectFile &Obj) { STE.n_sect, STE.n_desc, STE.n_value, StringTable); } + SymNum++; } outs() << " ])\n"; @@ -320,6 +319,15 @@ DumpLinkerOptionsCommand(const MachOObjectFile &Obj, 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" + << " ('reserved, " << VMLC.reserved << ")\n"; + return 0; +} + static int DumpLoadCommand(const MachOObjectFile &Obj, MachOObjectFile::LoadCommandInfo &LCI) { switch (LCI.C.cmd) { @@ -339,6 +347,9 @@ static int DumpLoadCommand(const MachOObjectFile &Obj, return DumpDataInCodeDataCommand(Obj, LCI); case MachO::LC_LINKER_OPTIONS: return DumpLinkerOptionsCommand(Obj, LCI); + case MachO::LC_VERSION_MIN_IPHONEOS: + case MachO::LC_VERSION_MIN_MACOSX: + return DumpVersionMin(Obj, LCI); default: Warning("unknown load command: " + Twine(LCI.C.cmd)); return 0; @@ -379,9 +390,10 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm Mach-O dumping tool\n"); - OwningPtr<Binary> Binary; - if (error_code EC = createBinary(InputFile, Binary)) + ErrorOr<Binary *> BinaryOrErr = createBinary(InputFile); + if (error_code EC = BinaryOrErr.getError()) return Error("unable to read input: '" + EC.message() + "'"); + std::unique_ptr<Binary> Binary(BinaryOrErr.get()); const MachOObjectFile *InputObject = dyn_cast<MachOObjectFile>(Binary.get()); if (!InputObject) diff --git a/tools/msbuild/CMakeLists.txt b/tools/msbuild/CMakeLists.txt index 08b8aee..b7be71d 100644 --- a/tools/msbuild/CMakeLists.txt +++ b/tools/msbuild/CMakeLists.txt @@ -1,41 +1,57 @@ if (WIN32) - set(prop_file_in "Microsoft.Cpp.Win32.llvm.props.in") - set(prop_file_v100 "Microsoft.Cpp.Win32.LLVM-vs2010.props") - set(prop_file_v110 "Microsoft.Cpp.Win32.LLVM-vs2012.props") - set(prop_file_v110_xp "Microsoft.Cpp.Win32.LLVM-vs2012_xp.props") - set(prop_file_v120 "toolset-vs2013.props") - set(prop_file_v120_xp "toolset-vs2013_xp.props") - # CPack will install a registry key in this format that we wish to reference. set(REG_KEY "${CPACK_PACKAGE_INSTALL_REGISTRY_KEY}") + set(LIB_PATH_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}") + + foreach (platform "Win32" "x64") + set(prop_file_in "Microsoft.Cpp.Win32.llvm.props.in") + set(prop_file_v100 "Microsoft.Cpp.${platform}.LLVM-vs2010.props") + set(prop_file_v110 "Microsoft.Cpp.${platform}.LLVM-vs2012.props") + set(prop_file_v110_xp "Microsoft.Cpp.${platform}.LLVM-vs2012_xp.props") + set(prop_file_v120 "toolset-vs2013.props") + set(prop_file_v120_xp "toolset-vs2013_xp.props") + + if (platform STREQUAL "Win32") + set(mflag "m32") + else() + set(mflag "m64") + endif() + set(VS_VERSION "v100") + set(MSC_VERSION "1600") + configure_file(${prop_file_in} ${platform}/${prop_file_v100}) + set(VS_VERSION "v110") + set(MSC_VERSION "1700") + configure_file(${prop_file_in} ${platform}/${prop_file_v110}) + set(VS_VERSION "v110_xp") + configure_file(${prop_file_in} ${platform}/${prop_file_v110_xp}) + set(VS_VERSION "v120") + set(MSC_VERSION "1800") + configure_file(${prop_file_in} ${platform}/${prop_file_v120}) + set(VS_VERSION "v120_xp") + configure_file(${prop_file_in} ${platform}/${prop_file_v120_xp}) + set(VS_VERSION) + set(MSC_VERSION) + set(mflag) + + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v100}" DESTINATION tools/msbuild/${platform}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v110}" DESTINATION tools/msbuild/${platform}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v110_xp}" DESTINATION tools/msbuild/${platform}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v120}" DESTINATION tools/msbuild/${platform}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v120_xp}" DESTINATION tools/msbuild/${platform}) - set(VS_VERSION "v100") - set(MSC_VERSION "1600") - configure_file(${prop_file_in} ${prop_file_v100}) - set(VS_VERSION "v110") - set(MSC_VERSION "1700") - configure_file(${prop_file_in} ${prop_file_v110}) - set(VS_VERSION "v110_xp") - configure_file(${prop_file_in} ${prop_file_v110_xp}) - set(VS_VERSION "v120") - set(MSC_VERSION "1800") - configure_file(${prop_file_in} ${prop_file_v120}) - set(VS_VERSION "v120_xp") - configure_file(${prop_file_in} ${prop_file_v120_xp}) + install(FILES "Microsoft.Cpp.Win32.LLVM-vs2010.targets" DESTINATION "tools/msbuild/${platform}" RENAME "Microsoft.Cpp.${platform}.LLVM-vs2010.targets") + install(FILES "Microsoft.Cpp.Win32.LLVM-vs2012.targets" DESTINATION "tools/msbuild/${platform}" RENAME "Microsoft.Cpp.${platform}.LLVM-vs2012.targets") + install(FILES "Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets" DESTINATION "tools/msbuild/${platform}" RENAME "Microsoft.Cpp.${platform}.LLVM-vs2012_xp.targets") + install(FILES "toolset-vs2013.targets" DESTINATION "tools/msbuild/${platform}") + install(FILES "toolset-vs2013_xp.targets" DESTINATION "tools/msbuild/${platform}") + endforeach() + set(LIB_PATH_VERSION) set(REG_KEY) - set(VS_VERSION) - set(MSC_VERSION) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v100}" DESTINATION tools/msbuild) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v110}" DESTINATION tools/msbuild) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v110_xp}" DESTINATION tools/msbuild) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v120}" DESTINATION tools/msbuild) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v120_xp}" DESTINATION tools/msbuild) install(DIRECTORY . DESTINATION tools/msbuild FILES_MATCHING - PATTERN "*.targets" PATTERN "*.bat" PATTERN ".svn" EXCLUDE ) diff --git a/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in b/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in index a6ef4ea..a775c31 100644 --- a/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in +++ b/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in @@ -6,13 +6,13 @@ <LLVMInstallDir>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\LLVM\@REG_KEY@)</LLVMInstallDir>
<LLVMInstallDir Condition="'$(LLVMInstallDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\LLVM\@REG_KEY@)</LLVMInstallDir>
<ExecutablePath>$(LLVMInstallDir)\msbuild-bin;$(ExecutablePath)</ExecutablePath>
- <LibraryPath>$(LLVMInstallDir)\lib\clang\3.4\lib\windows;$(LibraryPath)</LibraryPath>
+ <LibraryPath>$(LLVMInstallDir)\lib\clang\@LIB_PATH_VERSION@\lib\windows;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<!-- Set the value of _MSC_VER to claim for compatibility -->
- <AdditionalOptions>-fmsc-version=@MSC_VERSION@ %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalOptions>-@mflag@ -fmsc-version=@MSC_VERSION@ %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
</Project>
diff --git a/tools/msbuild/install.bat b/tools/msbuild/install.bat index c4c61ac..9880fb2 100644 --- a/tools/msbuild/install.bat +++ b/tools/msbuild/install.bat @@ -6,24 +6,31 @@ set SUCCESS=0 REM Change to the directory of this batch file.
cd /d %~dp0
+set PLATFORM=None
+:START
+IF %PLATFORM% == x64 GOTO LOOPEND
+IF %PLATFORM% == Win32 SET PLATFORM=x64
+IF %PLATFORM% == None SET PLATFORM=Win32
+
REM Search for the MSBuild toolsets directory.
-SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D% GOTO FOUND_V100
-SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D% GOTO FOUND_V100
:TRY_V110
-SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D% GOTO FOUND_V110
-SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D% GOTO FOUND_V110
:TRY_V120
-SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D% GOTO FOUND_V120
-SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D% GOTO FOUND_V120
+:LOOPEND
IF %SUCCESS% == 1 goto DONE
echo Failed to find MSBuild toolsets directory.
goto FAILED
@@ -32,9 +39,9 @@ goto FAILED :FOUND_V100
IF NOT EXIST %D%\LLVM-vs2010 mkdir %D%\LLVM-vs2010
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy Microsoft.Cpp.Win32.LLVM-vs2010.props %D%\LLVM-vs2010
+copy %PLATFORM%\Microsoft.Cpp.%PLATFORM%.LLVM-vs2010.props %D%\LLVM-vs2010
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy Microsoft.Cpp.Win32.LLVM-vs2010.targets %D%\LLVM-vs2010
+copy %PLATFORM%\Microsoft.Cpp.%PLATFORM%.LLVM-vs2010.targets %D%\LLVM-vs2010
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
set SUCCESS=1
GOTO TRY_V110
@@ -42,15 +49,15 @@ GOTO TRY_V110 :FOUND_V110
IF NOT EXIST %D%\LLVM-vs2012 mkdir %D%\LLVM-vs2012
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy Microsoft.Cpp.Win32.LLVM-vs2012.props %D%\LLVM-vs2012
+copy %PLATFORM%\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012.props %D%\LLVM-vs2012
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy Microsoft.Cpp.Win32.LLVM-vs2012.targets %D%\LLVM-vs2012
+copy %PLATFORM%\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012.targets %D%\LLVM-vs2012
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
IF NOT EXIST %D%\LLVM-vs2012_xp mkdir %D%\LLVM-vs2012_xp
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy Microsoft.Cpp.Win32.LLVM-vs2012_xp.props %D%\LLVM-vs2012_xp
+copy %PLATFORM%\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012_xp.props %D%\LLVM-vs2012_xp
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets %D%\LLVM-vs2012_xp
+copy %PLATFORM%\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012_xp.targets %D%\LLVM-vs2012_xp
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
set SUCCESS=1
GOTO TRY_V120
@@ -58,16 +65,19 @@ GOTO TRY_V120 :FOUND_V120
IF NOT EXIST %D%\LLVM-vs2013 mkdir %D%\LLVM-vs2013
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy toolset-vs2013.props %D%\LLVM-vs2013\toolset.props
+copy %PLATFORM%\toolset-vs2013.props %D%\LLVM-vs2013\toolset.props
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy toolset-vs2013.targets %D%\LLVM-vs2013\toolset.targets
+copy %PLATFORM%\toolset-vs2013.targets %D%\LLVM-vs2013\toolset.targets
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
IF NOT EXIST %D%\LLVM-vs2013_xp mkdir %D%\LLVM-vs2013_xp
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy toolset-vs2013_xp.props %D%\LLVM-vs2013_xp\toolset.props
+copy %PLATFORM%\toolset-vs2013_xp.props %D%\LLVM-vs2013_xp\toolset.props
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
-copy toolset-vs2013_xp.targets %D%\LLVM-vs2013_xp\toolset.targets
+copy %PLATFORM%\toolset-vs2013_xp.targets %D%\LLVM-vs2013_xp\toolset.targets
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+set SUCCESS=1
+GOTO START
+
:DONE
echo Done!
diff --git a/tools/msbuild/uninstall.bat b/tools/msbuild/uninstall.bat index 7e94f87..b0bc943 100644 --- a/tools/msbuild/uninstall.bat +++ b/tools/msbuild/uninstall.bat @@ -5,41 +5,45 @@ echo Uninstalling MSVC integration... REM CD to the directory of this batch file.
cd /d %~dp0
-SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
-IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.props
-IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.targets
-IF EXIST %D%\LLVM-vs2010 rmdir %D%\LLVM-vs2010
+set PLATFORM=None
+:START
+IF %PLATFORM% == x64 GOTO END
+IF %PLATFORM% == Win32 SET PLATFORM=x64
+IF %PLATFORM% == None SET PLATFORM=Win32
+
-SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
-IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.props
-IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.targets
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\%PLATFORM%\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.%PLATFORM%.LLVM-vs2010.props
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.%PLATFORM%.LLVM-vs2010.targets
+IF EXIST %D%\LLVM-vs2010 rmdir %D%\LLVM-vs2010
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\%PLATFORM%\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.%PLATFORM%.LLVM-vs2010.props
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.%PLATFORM%.LLVM-vs2010.targets
IF EXIST %D%\LLVM-vs2010 rmdir %D%\LLVM-vs2010
-SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
-IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.props
-IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.targets
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\%PLATFORM%\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012.props
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012.targets
IF EXIST %D%\LLVM-vs2012 rmdir %D%\LLVM-vs2012
-IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.props
-IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012_xp.props
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012_xp.targets
IF EXIST %D%\LLVM-vs2012_xp rmdir %D%\LLVM-vs2012_xp
-
-SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
-IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.props
-IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.targets
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\%PLATFORM%\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012.props
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012.targets
IF EXIST %D%\LLVM-vs2012 rmdir %D%\LLVM-vs2012
-IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.props
-IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012_xp.props
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012_xp.targets
IF EXIST %D%\LLVM-vs2012_xp rmdir %D%\LLVM-vs2012_xp
-SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.props
IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.targets
IF EXIST %D%\LLVM-vs2013 rmdir %D%\LLVM-vs2013
IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.props
IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.targets
IF EXIST %D%\LLVM-vs2013_xp rmdir %D%\LLVM-vs2013_xp
-
-SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.props
IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.targets
IF EXIST %D%\LLVM-vs2013 rmdir %D%\LLVM-vs2013
@@ -47,4 +51,8 @@ IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.props IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.targets
IF EXIST %D%\LLVM-vs2013_xp rmdir %D%\LLVM-vs2013_xp
+
+GOTO START
+
+:END
echo Done!
diff --git a/tools/obj2yaml/CMakeLists.txt b/tools/obj2yaml/CMakeLists.txt index 6b39193..9c10c04 100644 --- a/tools/obj2yaml/CMakeLists.txt +++ b/tools/obj2yaml/CMakeLists.txt @@ -1,7 +1,8 @@ -set(LLVM_LINK_COMPONENTS object) +set(LLVM_LINK_COMPONENTS + Object + Support + ) add_llvm_utility(obj2yaml obj2yaml.cpp coff2yaml.cpp ) - -target_link_libraries(obj2yaml LLVMSupport) diff --git a/tools/obj2yaml/coff2yaml.cpp b/tools/obj2yaml/coff2yaml.cpp index 02d7ebf..ef70922 100644 --- a/tools/obj2yaml/coff2yaml.cpp +++ b/tools/obj2yaml/coff2yaml.cpp @@ -51,11 +51,8 @@ void COFFDumper::dumpHeader(const object::coff_file_header *Header) { void COFFDumper::dumpSections(unsigned NumSections) { std::vector<COFFYAML::Section> &Sections = YAMLObj.Sections; - error_code ec; - for (object::section_iterator iter = Obj.begin_sections(); - iter != Obj.end_sections(); iter.increment(ec)) { - check(ec); - const object::coff_section *Sect = Obj.getCOFFSection(iter); + for (const auto &Section : Obj.sections()) { + const object::coff_section *Sect = Obj.getCOFFSection(Section); COFFYAML::Section Sec; Sec.Name = Sect->Name; // FIXME: check the null termination! uint32_t Characteristics = Sect->Characteristics; @@ -67,11 +64,10 @@ void COFFDumper::dumpSections(unsigned NumSections) { Sec.SectionData = object::yaml::BinaryRef(sectionData); std::vector<COFFYAML::Relocation> Relocations; - for (object::relocation_iterator rIter = iter->begin_relocations(); - rIter != iter->end_relocations(); rIter.increment(ec)) { - const object::coff_relocation *reloc = Obj.getCOFFRelocation(rIter); + for (const auto &Reloc : Section.relocations()) { + const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc); COFFYAML::Relocation Rel; - object::symbol_iterator Sym = rIter->getSymbol(); + object::symbol_iterator Sym = Reloc.getSymbol(); Sym->getName(Rel.SymbolName); Rel.VirtualAddress = reloc->VirtualAddress; Rel.Type = reloc->Type; @@ -82,13 +78,65 @@ void COFFDumper::dumpSections(unsigned NumSections) { } } +static void +dumpFunctionDefinition(COFFYAML::Symbol *Sym, + const object::coff_aux_function_definition *ObjFD) { + COFF::AuxiliaryFunctionDefinition YAMLFD; + YAMLFD.TagIndex = ObjFD->TagIndex; + YAMLFD.TotalSize = ObjFD->TotalSize; + YAMLFD.PointerToLinenumber = ObjFD->PointerToLinenumber; + YAMLFD.PointerToNextFunction = ObjFD->PointerToNextFunction; + + Sym->FunctionDefinition = YAMLFD; +} + +static void +dumpbfAndEfLineInfo(COFFYAML::Symbol *Sym, + const object::coff_aux_bf_and_ef_symbol *ObjBES) { + COFF::AuxiliarybfAndefSymbol YAMLAAS; + YAMLAAS.Linenumber = ObjBES->Linenumber; + YAMLAAS.PointerToNextFunction = ObjBES->PointerToNextFunction; + + Sym->bfAndefSymbol = YAMLAAS; +} + +static void dumpWeakExternal(COFFYAML::Symbol *Sym, + const object::coff_aux_weak_external *ObjWE) { + COFF::AuxiliaryWeakExternal YAMLWE; + YAMLWE.TagIndex = ObjWE->TagIndex; + YAMLWE.Characteristics = ObjWE->Characteristics; + + Sym->WeakExternal = YAMLWE; +} + +static void +dumpSectionDefinition(COFFYAML::Symbol *Sym, + const object::coff_aux_section_definition *ObjSD) { + COFF::AuxiliarySectionDefinition YAMLASD; + YAMLASD.Length = ObjSD->Length; + YAMLASD.NumberOfRelocations = ObjSD->NumberOfRelocations; + YAMLASD.NumberOfLinenumbers = ObjSD->NumberOfLinenumbers; + YAMLASD.CheckSum = ObjSD->CheckSum; + YAMLASD.Number = ObjSD->Number; + YAMLASD.Selection = ObjSD->Selection; + + Sym->SectionDefinition = YAMLASD; +} + +static void +dumpCLRTokenDefinition(COFFYAML::Symbol *Sym, + const object::coff_aux_clr_token *ObjCLRToken) { + COFF::AuxiliaryCLRToken YAMLCLRToken; + YAMLCLRToken.AuxType = ObjCLRToken->AuxType; + YAMLCLRToken.SymbolTableIndex = ObjCLRToken->SymbolTableIndex; + + Sym->CLRToken = YAMLCLRToken; +} + void COFFDumper::dumpSymbols(unsigned NumSymbols) { - error_code ec; std::vector<COFFYAML::Symbol> &Symbols = YAMLObj.Symbols; - for (object::symbol_iterator iter = Obj.begin_symbols(); - iter != Obj.end_symbols(); iter.increment(ec)) { - check(ec); - const object::coff_symbol *Symbol = Obj.getCOFFSymbol(iter); + for (const auto &S : Obj.symbols()) { + const object::coff_symbol *Symbol = Obj.getCOFFSymbol(S); COFFYAML::Symbol Sym; Obj.getSymbolName(Symbol, Sym.Name); Sym.SimpleType = COFF::SymbolBaseType(Symbol->getBaseType()); @@ -97,7 +145,63 @@ void COFFDumper::dumpSymbols(unsigned NumSymbols) { Sym.Header.Value = Symbol->Value; Sym.Header.SectionNumber = Symbol->SectionNumber; Sym.Header.NumberOfAuxSymbols = Symbol->NumberOfAuxSymbols; - Sym.AuxiliaryData = object::yaml::BinaryRef(Obj.getSymbolAuxData(Symbol)); + + if (Symbol->NumberOfAuxSymbols > 0) { + ArrayRef<uint8_t> AuxData = Obj.getSymbolAuxData(Symbol); + if (Symbol->isFunctionDefinition()) { + // This symbol represents a function definition. + assert(Symbol->NumberOfAuxSymbols == 1 && + "Expected a single aux symbol to describe this function!"); + + const object::coff_aux_function_definition *ObjFD = + reinterpret_cast<const object::coff_aux_function_definition *>( + AuxData.data()); + dumpFunctionDefinition(&Sym, ObjFD); + } else if (Symbol->isFunctionLineInfo()) { + // This symbol describes function line number information. + assert(Symbol->NumberOfAuxSymbols == 1 && + "Exepected a single aux symbol to describe this section!"); + + const object::coff_aux_bf_and_ef_symbol *ObjBES = + reinterpret_cast<const object::coff_aux_bf_and_ef_symbol *>( + AuxData.data()); + dumpbfAndEfLineInfo(&Sym, ObjBES); + } else if (Symbol->isWeakExternal()) { + // This symbol represents a weak external definition. + assert(Symbol->NumberOfAuxSymbols == 1 && + "Exepected a single aux symbol to describe this section!"); + + const object::coff_aux_weak_external *ObjWE = + reinterpret_cast<const object::coff_aux_weak_external *>( + AuxData.data()); + dumpWeakExternal(&Sym, ObjWE); + } else if (Symbol->isFileRecord()) { + // This symbol represents a file record. + Sym.File = StringRef(reinterpret_cast<const char *>(AuxData.data()), + Symbol->NumberOfAuxSymbols * COFF::SymbolSize) + .rtrim(StringRef("\0", /*length=*/1)); + } else if (Symbol->isSectionDefinition()) { + // This symbol represents a section definition. + assert(Symbol->NumberOfAuxSymbols == 1 && + "Expected a single aux symbol to describe this section!"); + + const object::coff_aux_section_definition *ObjSD = + reinterpret_cast<const object::coff_aux_section_definition *>( + AuxData.data()); + dumpSectionDefinition(&Sym, ObjSD); + } else if (Symbol->isCLRToken()) { + // This symbol represents a CLR token definition. + assert(Symbol->NumberOfAuxSymbols == 1 && + "Expected a single aux symbol to describe this CLR Token"); + + const object::coff_aux_clr_token *ObjCLRToken = + reinterpret_cast<const object::coff_aux_clr_token *>( + AuxData.data()); + dumpCLRTokenDefinition(&Sym, ObjCLRToken); + } else { + llvm_unreachable("Unhandled auxiliary symbol!"); + } + } Symbols.push_back(Sym); } } diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp index 8d128b3..38779fe 100644 --- a/tools/obj2yaml/obj2yaml.cpp +++ b/tools/obj2yaml/obj2yaml.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "obj2yaml.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include "llvm/Support/CommandLine.h" @@ -38,14 +37,14 @@ int main(int argc, char *argv[]) { llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. // Process the input file - OwningPtr<MemoryBuffer> buf; + std::unique_ptr<MemoryBuffer> buf; // TODO: If this is an archive, then burst it and dump each entry if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, buf)) { errs() << "Error: '" << ec.message() << "' opening file '" << InputFilename << "'\n"; } else { - ec = coff2yaml(outs(), buf.take()); + ec = coff2yaml(outs(), buf.release()); if (ec) errs() << "Error: " << ec.message() << " dumping COFF file\n"; } diff --git a/tools/opt/AnalysisWrappers.cpp b/tools/opt/AnalysisWrappers.cpp index 55f544f..4bdc268 100644 --- a/tools/opt/AnalysisWrappers.cpp +++ b/tools/opt/AnalysisWrappers.cpp @@ -18,9 +18,9 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/CallGraph.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" -#include "llvm/Support/CallSite.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -32,19 +32,18 @@ namespace { struct ExternalFunctionsPassedConstants : public ModulePass { static char ID; // Pass ID, replacement for typeid ExternalFunctionsPassedConstants() : ModulePass(ID) {} - virtual bool runOnModule(Module &M) { + bool runOnModule(Module &M) override { for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { if (!I->isDeclaration()) continue; - + bool PrintedFn = false; - for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); - UI != E; ++UI) { - Instruction *User = dyn_cast<Instruction>(*UI); - if (!User) continue; - - CallSite CS(cast<Value>(User)); + for (User *U : I->users()) { + Instruction *UI = dyn_cast<Instruction>(U); + if (!UI) continue; + + CallSite CS(cast<Value>(UI)); if (!CS) continue; - + for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); AI != E; ++AI) { if (!isa<Constant>(*AI)) continue; @@ -53,7 +52,7 @@ namespace { errs() << "Function '" << I->getName() << "':\n"; PrintedFn = true; } - errs() << *User; + errs() << *UI; break; } } @@ -62,7 +61,7 @@ namespace { return false; } - virtual void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); } }; @@ -78,12 +77,12 @@ namespace { static char ID; // Pass ID, replacement for typeid CallGraphPrinter() : ModulePass(ID) {} - virtual void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); - AU.addRequiredTransitive<CallGraph>(); + AU.addRequiredTransitive<CallGraphWrapperPass>(); } - virtual bool runOnModule(Module &M) { - getAnalysis<CallGraph>().print(errs(), &M); + bool runOnModule(Module &M) override { + getAnalysis<CallGraphWrapperPass>().print(errs(), &M); return false; } }; diff --git a/tools/opt/Android.mk b/tools/opt/Android.mk index 77183aa..9ba9584 100644 --- a/tools/opt/Android.mk +++ b/tools/opt/Android.mk @@ -58,6 +58,7 @@ include $(BUILD_HOST_EXECUTABLE) # opt command line tool (target) #===---------------------------------------------------------------=== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) LOCAL_MODULE := opt @@ -70,10 +71,11 @@ LOCAL_STATIC_LIBRARIES := $(llvm_opt_STATIC_LIBRARIES) LOCAL_SHARED_LIBRARIES := \ libcutils \ libdl \ - libstlport + libcxx include $(LLVM_ROOT_PATH)/llvm.mk include $(LLVM_DEVICE_BUILD_MK) include $(LLVM_GEN_INTRINSICS_MK) include $(BUILD_EXECUTABLE) +endif diff --git a/tools/opt/BreakpointPrinter.cpp b/tools/opt/BreakpointPrinter.cpp new file mode 100644 index 0000000..44f4a11 --- /dev/null +++ b/tools/opt/BreakpointPrinter.cpp @@ -0,0 +1,82 @@ +//===- BreakpointPrinter.cpp - Breakpoint location printer ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Breakpoint location printer. +/// +//===----------------------------------------------------------------------===// +#include "BreakpointPrinter.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + +struct BreakpointPrinter : public ModulePass { + raw_ostream &Out; + static char ID; + DITypeIdentifierMap TypeIdentifierMap; + + BreakpointPrinter(raw_ostream &out) : ModulePass(ID), Out(out) {} + + void getContextName(DIDescriptor Context, std::string &N) { + if (Context.isNameSpace()) { + DINameSpace NS(Context); + if (!NS.getName().empty()) { + getContextName(NS.getContext(), N); + N = N + NS.getName().str() + "::"; + } + } else if (Context.isType()) { + DIType TY(Context); + if (!TY.getName().empty()) { + getContextName(TY.getContext().resolve(TypeIdentifierMap), N); + N = N + TY.getName().str() + "::"; + } + } + } + + bool runOnModule(Module &M) override { + TypeIdentifierMap.clear(); + NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu"); + if (CU_Nodes) + TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes); + + StringSet<> Processed; + if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp")) + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { + std::string Name; + DISubprogram SP(NMD->getOperand(i)); + assert((!SP || SP.isSubprogram()) && + "A MDNode in llvm.dbg.sp should be null or a DISubprogram."); + if (!SP) + continue; + getContextName(SP.getContext().resolve(TypeIdentifierMap), Name); + Name = Name + SP.getDisplayName().str(); + if (!Name.empty() && Processed.insert(Name)) { + Out << Name << "\n"; + } + } + return false; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } +}; + +char BreakpointPrinter::ID = 0; +} + +ModulePass *llvm::createBreakpointPrinter(raw_ostream &out) { + return new BreakpointPrinter(out); +} diff --git a/tools/opt/BreakpointPrinter.h b/tools/opt/BreakpointPrinter.h new file mode 100644 index 0000000..81c88e1 --- /dev/null +++ b/tools/opt/BreakpointPrinter.h @@ -0,0 +1,25 @@ +//===- BreakpointPrinter.h - Breakpoint location printer ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Breakpoint location printer. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_OPT_BREAKPOINTPRINTER_H +#define LLVM_TOOLS_OPT_BREAKPOINTPRINTER_H + +namespace llvm { + +class ModulePass; +class raw_ostream; + +ModulePass *createBreakpointPrinter(raw_ostream &out); +} + +#endif // LLVM_TOOLS_OPT_BREAKPOINTPRINTER_H diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt index 9195911..1d3f08d 100644 --- a/tools/opt/CMakeLists.txt +++ b/tools/opt/CMakeLists.txt @@ -1,9 +1,43 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser bitwriter irreader instrumentation scalaropts objcarcopts ipo vectorize) +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + Analysis + BitWriter + CodeGen + Core + IPA + IPO + IRReader + InstCombine + Instrumentation + MC + ObjCARCOpts + ScalarOpts + Support + Target + TransformUtils + Vectorize + ) + +# Support plugins. +set(LLVM_NO_DEAD_STRIP 1) add_llvm_tool(opt AnalysisWrappers.cpp + BreakpointPrinter.cpp GraphPrinters.cpp + NewPMDriver.cpp + Passes.cpp + PassPrinters.cpp PrintSCC.cpp opt.cpp ) set_target_properties(opt PROPERTIES ENABLE_EXPORTS 1) + +if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS) + target_link_libraries(opt Polly) + if(POLLY_LINK_LIBS) + foreach(lib ${POLLY_LINK_LIBS}) + target_link_libraries(opt ${lib}) + endforeach(lib) + endif(POLLY_LINK_LIBS) +endif(WITH_POLLY AND LINK_POLLY_INTO_TOOLS) diff --git a/tools/opt/GraphPrinters.cpp b/tools/opt/GraphPrinters.cpp index f271966..640edfe 100644 --- a/tools/opt/GraphPrinters.cpp +++ b/tools/opt/GraphPrinters.cpp @@ -14,7 +14,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Analysis/Dominators.h" +#include "llvm/IR/Dominators.h" #include "llvm/Pass.h" using namespace llvm; @@ -29,14 +29,13 @@ namespace { static char ID; // Pass identification, replacement for typeid DomInfoPrinter() : FunctionPass(ID) {} - virtual void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); - AU.addRequired<DominatorTree>(); - + AU.addRequired<DominatorTreeWrapperPass>(); } - virtual bool runOnFunction(Function &F) { - getAnalysis<DominatorTree>().dump(); + bool runOnFunction(Function &F) override { + getAnalysis<DominatorTreeWrapperPass>().dump(); return false; } }; diff --git a/tools/opt/LLVMBuild.txt b/tools/opt/LLVMBuild.txt index 77b9446..b3589f8 100644 --- a/tools/opt/LLVMBuild.txt +++ b/tools/opt/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = opt parent = Tools -required_libraries = AsmParser BitReader BitWriter IRReader IPO Instrumentation Scalar ObjCARC all-targets +required_libraries = AsmParser BitReader BitWriter CodeGen IRReader IPO Instrumentation Scalar ObjCARC all-targets diff --git a/tools/opt/Makefile b/tools/opt/Makefile index a451005..cfa9c31 100644 --- a/tools/opt/Makefile +++ b/tools/opt/Makefile @@ -9,6 +9,9 @@ LEVEL := ../.. TOOLNAME := opt -LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets +LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets codegen + +# Support plugins. +NO_DEAD_STRIP := 1 include $(LEVEL)/Makefile.common diff --git a/tools/opt/NewPMDriver.cpp b/tools/opt/NewPMDriver.cpp new file mode 100644 index 0000000..fc4a1bf --- /dev/null +++ b/tools/opt/NewPMDriver.cpp @@ -0,0 +1,81 @@ +//===- NewPMDriver.cpp - Driver for opt with new PM -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file is just a split of the code that logically belongs in opt.cpp but +/// that includes the new pass manager headers. +/// +//===----------------------------------------------------------------------===// + +#include "NewPMDriver.h" +#include "Passes.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ToolOutputFile.h" + +using namespace llvm; +using namespace opt_tool; + +bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, + tool_output_file *Out, StringRef PassPipeline, + OutputKind OK, VerifierKind VK) { + FunctionAnalysisManager FAM; + ModuleAnalysisManager MAM; + + // FIXME: Lift this registration of analysis passes into a .def file adjacent + // to the one used to associate names with passes. + MAM.registerPass(LazyCallGraphAnalysis()); + + // Cross register the analysis managers through their proxies. + MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM)); + FAM.registerPass(ModuleAnalysisManagerFunctionProxy(MAM)); + + ModulePassManager MPM; + if (VK > VK_NoVerifier) + MPM.addPass(VerifierPass()); + + if (!parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass)) { + errs() << Arg0 << ": unable to parse pass pipeline description.\n"; + return false; + } + + if (VK > VK_NoVerifier) + MPM.addPass(VerifierPass()); + + // Add any relevant output pass at the end of the pipeline. + switch (OK) { + case OK_NoOutput: + break; // No output pass needed. + case OK_OutputAssembly: + MPM.addPass(PrintModulePass(Out->os())); + break; + case OK_OutputBitcode: + MPM.addPass(BitcodeWriterPass(Out->os())); + break; + } + + // Before executing passes, print the final values of the LLVM options. + cl::PrintOptionValues(); + + // Now that we have all of the passes ready, run them. + MPM.run(&M, &MAM); + + // Declare success. + if (OK != OK_NoOutput) + Out->keep(); + return true; +} diff --git a/tools/opt/NewPMDriver.h b/tools/opt/NewPMDriver.h new file mode 100644 index 0000000..3661d3e --- /dev/null +++ b/tools/opt/NewPMDriver.h @@ -0,0 +1,55 @@ +//===- NewPMDriver.h - Function to drive opt with the new PM ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// A single function which is called to drive the opt behavior for the new +/// PassManager. +/// +/// This is only in a separate TU with a header to avoid including all of the +/// old pass manager headers and the new pass manager headers into the same +/// file. Eventually all of the routines here will get folded back into +/// opt.cpp. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OPT_NEW_PM_DRIVER_H +#define LLVM_TOOLS_OPT_NEW_PM_DRIVER_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { +class LLVMContext; +class Module; +class tool_output_file; + +namespace opt_tool { +enum OutputKind { + OK_NoOutput, + OK_OutputAssembly, + OK_OutputBitcode +}; +enum VerifierKind { + VK_NoVerifier, + VK_VerifyInAndOut, + VK_VerifyEachPass +}; +} + +/// \brief Driver function to run the new pass manager over a module. +/// +/// This function only exists factored away from opt.cpp in order to prevent +/// inclusion of the new pass manager headers and the old headers into the same +/// file. It's interface is consequentially somewhat ad-hoc, but will go away +/// when the transition finishes. +bool runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, + tool_output_file *Out, StringRef PassPipeline, + opt_tool::OutputKind OK, opt_tool::VerifierKind VK); +} + +#endif diff --git a/tools/opt/PassPrinters.cpp b/tools/opt/PassPrinters.cpp new file mode 100644 index 0000000..d699489 --- /dev/null +++ b/tools/opt/PassPrinters.cpp @@ -0,0 +1,260 @@ +//===- PassPrinters.cpp - Utilities to print analysis info for passes -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Utilities to print analysis info for various kinds of passes. +/// +//===----------------------------------------------------------------------===// +#include "PassPrinters.h" +#include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/LoopPass.h" +#include "llvm/Analysis/RegionPass.h" +#include "llvm/IR/Function.h" +#include "llvm/Pass.h" +#include <string> + +using namespace llvm; + +namespace { + +struct FunctionPassPrinter : public FunctionPass { + const PassInfo *PassToPrint; + raw_ostream &Out; + static char ID; + std::string PassName; + bool QuietPass; + + FunctionPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet) + : FunctionPass(ID), PassToPrint(PI), Out(out), QuietPass(Quiet) { + std::string PassToPrintName = PassToPrint->getPassName(); + PassName = "FunctionPass Printer: " + PassToPrintName; + } + + bool runOnFunction(Function &F) override { + if (!QuietPass) + Out << "Printing analysis '" << PassToPrint->getPassName() + << "' for function '" << F.getName() << "':\n"; + + // Get and print pass... + getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, F.getParent()); + return false; + } + + const char *getPassName() const override { return PassName.c_str(); } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequiredID(PassToPrint->getTypeInfo()); + AU.setPreservesAll(); + } +}; + +char FunctionPassPrinter::ID = 0; + +struct CallGraphSCCPassPrinter : public CallGraphSCCPass { + static char ID; + const PassInfo *PassToPrint; + raw_ostream &Out; + std::string PassName; + bool QuietPass; + + CallGraphSCCPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet) + : CallGraphSCCPass(ID), PassToPrint(PI), Out(out), QuietPass(Quiet) { + std::string PassToPrintName = PassToPrint->getPassName(); + PassName = "CallGraphSCCPass Printer: " + PassToPrintName; + } + + bool runOnSCC(CallGraphSCC &SCC) override { + if (!QuietPass) + Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; + + // Get and print pass... + for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { + Function *F = (*I)->getFunction(); + if (F) + getAnalysisID<Pass>(PassToPrint->getTypeInfo()) + .print(Out, F->getParent()); + } + return false; + } + + const char *getPassName() const override { return PassName.c_str(); } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequiredID(PassToPrint->getTypeInfo()); + AU.setPreservesAll(); + } +}; + +char CallGraphSCCPassPrinter::ID = 0; + +struct ModulePassPrinter : public ModulePass { + static char ID; + const PassInfo *PassToPrint; + raw_ostream &Out; + std::string PassName; + bool QuietPass; + + ModulePassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet) + : ModulePass(ID), PassToPrint(PI), Out(out), QuietPass(Quiet) { + std::string PassToPrintName = PassToPrint->getPassName(); + PassName = "ModulePass Printer: " + PassToPrintName; + } + + bool runOnModule(Module &M) override { + if (!QuietPass) + Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; + + // Get and print pass... + getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, &M); + return false; + } + + const char *getPassName() const override { return PassName.c_str(); } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequiredID(PassToPrint->getTypeInfo()); + AU.setPreservesAll(); + } +}; + +char ModulePassPrinter::ID = 0; + +struct LoopPassPrinter : public LoopPass { + static char ID; + const PassInfo *PassToPrint; + raw_ostream &Out; + std::string PassName; + bool QuietPass; + + LoopPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet) + : LoopPass(ID), PassToPrint(PI), Out(out), QuietPass(Quiet) { + std::string PassToPrintName = PassToPrint->getPassName(); + PassName = "LoopPass Printer: " + PassToPrintName; + } + + bool runOnLoop(Loop *L, LPPassManager &LPM) override { + if (!QuietPass) + Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; + + // Get and print pass... + getAnalysisID<Pass>(PassToPrint->getTypeInfo()) + .print(Out, L->getHeader()->getParent()->getParent()); + return false; + } + + const char *getPassName() const override { return PassName.c_str(); } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequiredID(PassToPrint->getTypeInfo()); + AU.setPreservesAll(); + } +}; + +char LoopPassPrinter::ID = 0; + +struct RegionPassPrinter : public RegionPass { + static char ID; + const PassInfo *PassToPrint; + raw_ostream &Out; + std::string PassName; + bool QuietPass; + + RegionPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet) + : RegionPass(ID), PassToPrint(PI), Out(out), QuietPass(Quiet) { + std::string PassToPrintName = PassToPrint->getPassName(); + PassName = "RegionPass Printer: " + PassToPrintName; + } + + bool runOnRegion(Region *R, RGPassManager &RGM) override { + if (!QuietPass) { + Out << "Printing analysis '" << PassToPrint->getPassName() << "' for " + << "region: '" << R->getNameStr() << "' in function '" + << R->getEntry()->getParent()->getName() << "':\n"; + } + // Get and print pass... + getAnalysisID<Pass>(PassToPrint->getTypeInfo()) + .print(Out, R->getEntry()->getParent()->getParent()); + return false; + } + + const char *getPassName() const override { return PassName.c_str(); } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequiredID(PassToPrint->getTypeInfo()); + AU.setPreservesAll(); + } +}; + +char RegionPassPrinter::ID = 0; + +struct BasicBlockPassPrinter : public BasicBlockPass { + const PassInfo *PassToPrint; + raw_ostream &Out; + static char ID; + std::string PassName; + bool QuietPass; + + BasicBlockPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet) + : BasicBlockPass(ID), PassToPrint(PI), Out(out), QuietPass(Quiet) { + std::string PassToPrintName = PassToPrint->getPassName(); + PassName = "BasicBlockPass Printer: " + PassToPrintName; + } + + bool runOnBasicBlock(BasicBlock &BB) override { + if (!QuietPass) + Out << "Printing Analysis info for BasicBlock '" << BB.getName() + << "': Pass " << PassToPrint->getPassName() << ":\n"; + + // Get and print pass... + getAnalysisID<Pass>(PassToPrint->getTypeInfo()) + .print(Out, BB.getParent()->getParent()); + return false; + } + + const char *getPassName() const override { return PassName.c_str(); } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequiredID(PassToPrint->getTypeInfo()); + AU.setPreservesAll(); + } +}; + +char BasicBlockPassPrinter::ID = 0; +} + +FunctionPass *llvm::createFunctionPassPrinter(const PassInfo *PI, + raw_ostream &OS, bool Quiet) { + return new FunctionPassPrinter(PI, OS, Quiet); +} + +CallGraphSCCPass *llvm::createCallGraphPassPrinter(const PassInfo *PI, + raw_ostream &OS, + bool Quiet) { + return new CallGraphSCCPassPrinter(PI, OS, Quiet); +} + +ModulePass *llvm::createModulePassPrinter(const PassInfo *PI, raw_ostream &OS, + bool Quiet) { + return new ModulePassPrinter(PI, OS, Quiet); +} + +LoopPass *llvm::createLoopPassPrinter(const PassInfo *PI, raw_ostream &OS, + bool Quiet) { + return new LoopPassPrinter(PI, OS, Quiet); +} + +RegionPass *llvm::createRegionPassPrinter(const PassInfo *PI, raw_ostream &OS, + bool Quiet) { + return new RegionPassPrinter(PI, OS, Quiet); +} + +BasicBlockPass *llvm::createBasicBlockPassPrinter(const PassInfo *PI, + raw_ostream &OS, bool Quiet) { + return new BasicBlockPassPrinter(PI, OS, Quiet); +} diff --git a/tools/opt/PassPrinters.h b/tools/opt/PassPrinters.h new file mode 100644 index 0000000..cf46ef9 --- /dev/null +++ b/tools/opt/PassPrinters.h @@ -0,0 +1,47 @@ +//===- PassPrinters.h - Utilities to print analysis info for passes -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Utilities to print analysis info for various kinds of passes. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_OPT_PASSPRINTERS_H +#define LLVM_TOOLS_OPT_PASSPRINTERS_H + +namespace llvm { + +class BasicBlockPass; +class CallGraphSCCPass; +class FunctionPass; +class ModulePass; +class LoopPass; +class PassInfo; +class RegionPass; +class raw_ostream; + +FunctionPass *createFunctionPassPrinter(const PassInfo *PI, raw_ostream &out, + bool Quiet); + +CallGraphSCCPass *createCallGraphPassPrinter(const PassInfo *PI, + raw_ostream &out, bool Quiet); + +ModulePass *createModulePassPrinter(const PassInfo *PI, raw_ostream &out, + bool Quiet); + +LoopPass *createLoopPassPrinter(const PassInfo *PI, raw_ostream &out, + bool Quiet); + +RegionPass *createRegionPassPrinter(const PassInfo *PI, raw_ostream &out, + bool Quiet); + +BasicBlockPass *createBasicBlockPassPrinter(const PassInfo *PI, + raw_ostream &out, bool Quiet); +} + +#endif // LLVM_TOOLS_OPT_PASSPRINTERS_H diff --git a/tools/opt/Passes.cpp b/tools/opt/Passes.cpp new file mode 100644 index 0000000..ffdf9bf --- /dev/null +++ b/tools/opt/Passes.cpp @@ -0,0 +1,209 @@ +//===- Passes.cpp - Parsing, selection, and running of passes -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file provides the infrastructure to parse and build a custom pass +/// manager based on a commandline flag. It also provides helpers to aid in +/// analyzing, debugging, and testing pass structures. +/// +//===----------------------------------------------------------------------===// + +#include "Passes.h" +#include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/Debug.h" + +using namespace llvm; + +namespace { + +/// \brief No-op module pass which does nothing. +struct NoOpModulePass { + PreservedAnalyses run(Module *M) { return PreservedAnalyses::all(); } + static StringRef name() { return "NoOpModulePass"; } +}; + +/// \brief No-op function pass which does nothing. +struct NoOpFunctionPass { + PreservedAnalyses run(Function *F) { return PreservedAnalyses::all(); } + static StringRef name() { return "NoOpFunctionPass"; } +}; + +} // End anonymous namespace. + +// FIXME: Factor all of the parsing logic into a .def file that we include +// under different macros. +static bool isModulePassName(StringRef Name) { + if (Name == "no-op-module") return true; + if (Name == "print") return true; + if (Name == "print-cg") return true; + + return false; +} + +static bool isFunctionPassName(StringRef Name) { + if (Name == "no-op-function") return true; + if (Name == "print") return true; + + return false; +} + +static bool parseModulePassName(ModulePassManager &MPM, StringRef Name) { + if (Name == "no-op-module") { + MPM.addPass(NoOpModulePass()); + return true; + } + if (Name == "print") { + MPM.addPass(PrintModulePass(dbgs())); + return true; + } + if (Name == "print-cg") { + MPM.addPass(LazyCallGraphPrinterPass(dbgs())); + return true; + } + return false; +} + +static bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name) { + if (Name == "no-op-function") { + FPM.addPass(NoOpFunctionPass()); + return true; + } + if (Name == "print") { + FPM.addPass(PrintFunctionPass(dbgs())); + return true; + } + return false; +} + +static bool parseFunctionPassPipeline(FunctionPassManager &FPM, + StringRef &PipelineText, + bool VerifyEachPass) { + for (;;) { + // Parse nested pass managers by recursing. + if (PipelineText.startswith("function(")) { + FunctionPassManager NestedFPM; + + // Parse the inner pipeline inte the nested manager. + PipelineText = PipelineText.substr(strlen("function(")); + if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) || + PipelineText.empty()) + return false; + assert(PipelineText[0] == ')'); + PipelineText = PipelineText.substr(1); + + // Add the nested pass manager with the appropriate adaptor. + FPM.addPass(std::move(NestedFPM)); + } else { + // Otherwise try to parse a pass name. + size_t End = PipelineText.find_first_of(",)"); + if (!parseFunctionPassName(FPM, PipelineText.substr(0, End))) + return false; + if (VerifyEachPass) + FPM.addPass(VerifierPass()); + + PipelineText = PipelineText.substr(End); + } + + if (PipelineText.empty() || PipelineText[0] == ')') + return true; + + assert(PipelineText[0] == ','); + PipelineText = PipelineText.substr(1); + } +} + +static bool parseModulePassPipeline(ModulePassManager &MPM, + StringRef &PipelineText, + bool VerifyEachPass) { + for (;;) { + // Parse nested pass managers by recursing. + if (PipelineText.startswith("module(")) { + ModulePassManager NestedMPM; + + // Parse the inner pipeline into the nested manager. + PipelineText = PipelineText.substr(strlen("module(")); + if (!parseModulePassPipeline(NestedMPM, PipelineText, VerifyEachPass) || + PipelineText.empty()) + return false; + assert(PipelineText[0] == ')'); + PipelineText = PipelineText.substr(1); + + // Now add the nested manager as a module pass. + MPM.addPass(std::move(NestedMPM)); + } else if (PipelineText.startswith("function(")) { + FunctionPassManager NestedFPM; + + // Parse the inner pipeline inte the nested manager. + PipelineText = PipelineText.substr(strlen("function(")); + if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) || + PipelineText.empty()) + return false; + assert(PipelineText[0] == ')'); + PipelineText = PipelineText.substr(1); + + // Add the nested pass manager with the appropriate adaptor. + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(NestedFPM))); + } else { + // Otherwise try to parse a pass name. + size_t End = PipelineText.find_first_of(",)"); + if (!parseModulePassName(MPM, PipelineText.substr(0, End))) + return false; + if (VerifyEachPass) + MPM.addPass(VerifierPass()); + + PipelineText = PipelineText.substr(End); + } + + if (PipelineText.empty() || PipelineText[0] == ')') + return true; + + assert(PipelineText[0] == ','); + PipelineText = PipelineText.substr(1); + } +} + +// Primary pass pipeline description parsing routine. +// FIXME: Should this routine accept a TargetMachine or require the caller to +// pre-populate the analysis managers with target-specific stuff? +bool llvm::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, + bool VerifyEachPass) { + // Look at the first entry to figure out which layer to start parsing at. + if (PipelineText.startswith("module(")) + return parseModulePassPipeline(MPM, PipelineText, VerifyEachPass) && + PipelineText.empty(); + if (PipelineText.startswith("function(")) { + FunctionPassManager FPM; + if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass) || + !PipelineText.empty()) + return false; + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + return true; + } + + // This isn't a direct pass manager name, look for the end of a pass name. + StringRef FirstName = + PipelineText.substr(0, PipelineText.find_first_of(",)")); + if (isModulePassName(FirstName)) + return parseModulePassPipeline(MPM, PipelineText, VerifyEachPass) && + PipelineText.empty(); + + if (isFunctionPassName(FirstName)) { + FunctionPassManager FPM; + if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass) || + !PipelineText.empty()) + return false; + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + return true; + } + + return false; +} diff --git a/tools/opt/Passes.h b/tools/opt/Passes.h new file mode 100644 index 0000000..3bd6752 --- /dev/null +++ b/tools/opt/Passes.h @@ -0,0 +1,57 @@ +//===- Passes.h - Parsing, selection, and running of passes -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// Interfaces for producing common pass manager configurations and parsing +/// textual pass specifications. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OPT_PASSES_H +#define LLVM_TOOLS_OPT_PASSES_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { +class ModulePassManager; + +/// \brief Parse a textual pass pipeline description into a \c ModulePassManager. +/// +/// The format of the textual pass pipeline description looks something like: +/// +/// module(function(instcombine,sroa),dce,cgscc(inliner,function(...)),...) +/// +/// Pass managers have ()s describing the nest structure of passes. All passes +/// are comma separated. As a special shortcut, if the very first pass is not +/// a module pass (as a module pass manager is), this will automatically form +/// the shortest stack of pass managers that allow inserting that first pass. +/// So, assuming function passes 'fpassN', CGSCC passes 'cgpassN', and loop passes +/// 'lpassN', all of these are valid: +/// +/// fpass1,fpass2,fpass3 +/// cgpass1,cgpass2,cgpass3 +/// lpass1,lpass2,lpass3 +/// +/// And they are equivalent to the following (resp.): +/// +/// module(function(fpass1,fpass2,fpass3)) +/// module(cgscc(cgpass1,cgpass2,cgpass3)) +/// module(function(loop(lpass1,lpass2,lpass3))) +/// +/// This shortcut is especially useful for debugging and testing small pass +/// combinations. Note that these shortcuts don't introduce any other magic. If +/// the sequence of passes aren't all the exact same kind of pass, it will be +/// an error. You cannot mix different levels implicitly, you must explicitly +/// form a pass manager in which to nest passes. +bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, + bool VerifyEachPass = true); + +} + +#endif diff --git a/tools/opt/PrintSCC.cpp b/tools/opt/PrintSCC.cpp index a502fa7..cbc0a55 100644 --- a/tools/opt/PrintSCC.cpp +++ b/tools/opt/PrintSCC.cpp @@ -27,9 +27,9 @@ #include "llvm/ADT/SCCIterator.h" #include "llvm/Analysis/CallGraph.h" +#include "llvm/IR/CFG.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" -#include "llvm/Support/CFG.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -37,11 +37,11 @@ namespace { struct CFGSCC : public FunctionPass { static char ID; // Pass identification, replacement for typeid CFGSCC() : FunctionPass(ID) {} - bool runOnFunction(Function& func); + bool runOnFunction(Function& func) override; - void print(raw_ostream &O, const Module* = 0) const { } + void print(raw_ostream &O, const Module* = 0) const override { } - virtual void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); } }; @@ -51,14 +51,14 @@ namespace { CallGraphSCC() : ModulePass(ID) {} // run - Print out SCCs in the call graph for the specified module. - bool runOnModule(Module &M); + bool runOnModule(Module &M) override; - void print(raw_ostream &O, const Module* = 0) const { } + void print(raw_ostream &O, const Module* = 0) const override { } // getAnalysisUsage - This pass requires the CallGraph. - virtual void getAnalysisUsage(AnalysisUsage &AU) const { + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); - AU.addRequired<CallGraph>(); + AU.addRequired<CallGraphWrapperPass>(); } }; } @@ -74,8 +74,7 @@ Z("print-callgraph-sccs", "Print SCCs of the Call Graph"); bool CFGSCC::runOnFunction(Function &F) { unsigned sccNum = 0; errs() << "SCCs for Function " << F.getName() << " in PostOrder:"; - for (scc_iterator<Function*> SCCI = scc_begin(&F), - E = scc_end(&F); SCCI != E; ++SCCI) { + for (scc_iterator<Function*> SCCI = scc_begin(&F); !SCCI.isAtEnd(); ++SCCI) { std::vector<BasicBlock*> &nextSCC = *SCCI; errs() << "\nSCC #" << ++sccNum << " : "; for (std::vector<BasicBlock*>::const_iterator I = nextSCC.begin(), @@ -92,11 +91,11 @@ bool CFGSCC::runOnFunction(Function &F) { // run - Print out SCCs in the call graph for the specified module. bool CallGraphSCC::runOnModule(Module &M) { - CallGraphNode* rootNode = getAnalysis<CallGraph>().getRoot(); + CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); unsigned sccNum = 0; errs() << "SCCs for the program in PostOrder:"; - for (scc_iterator<CallGraphNode*> SCCI = scc_begin(rootNode), - E = scc_end(rootNode); SCCI != E; ++SCCI) { + for (scc_iterator<CallGraph*> SCCI = scc_begin(&CG); !SCCI.isAtEnd(); + ++SCCI) { const std::vector<CallGraphNode*> &nextSCC = *SCCI; errs() << "\nSCC #" << ++sccNum << " : "; for (std::vector<CallGraphNode*>::const_iterator I = nextSCC.begin(), diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index dba16f7..5a19881 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -12,28 +12,30 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/LLVMContext.h" -#include "llvm/ADT/StringSet.h" +#include "BreakpointPrinter.h" +#include "NewPMDriver.h" +#include "PassPrinters.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/RegionPass.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Assembly/PrintModulePass.h" -#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/CodeGen/CommandFlags.h" -#include "llvm/DebugInfo.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" +#include "llvm/InitializePasses.h" #include "llvm/LinkAllIR.h" #include "llvm/LinkAllPasses.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/PassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" @@ -48,6 +50,7 @@ #include <algorithm> #include <memory> using namespace llvm; +using namespace opt_tool; // The OptimizationList is automatically populated with registered Passes by the // PassNameParser. @@ -55,6 +58,15 @@ using namespace llvm; static cl::list<const PassInfo*, bool, PassNameParser> PassList(cl::desc("Optimizations available:")); +// This flag specifies a textual description of the optimization pass pipeline +// to run over the module. This flag switches opt to use the new pass manager +// infrastructure, completely disabling all of the flags specific to the old +// pass management. +static cl::opt<std::string> PassPipeline( + "passes", + cl::desc("A textual description of the pass pipeline for optimizing"), + cl::Hidden); + // Other command line options... // static cl::opt<std::string> @@ -172,265 +184,7 @@ DefaultDataLayout("default-data-layout", cl::desc("data layout string to use if not specified by module"), cl::value_desc("layout-string"), cl::init("")); -// ---------- Define Printers for module and function passes ------------ -namespace { - -struct CallGraphSCCPassPrinter : public CallGraphSCCPass { - static char ID; - const PassInfo *PassToPrint; - raw_ostream &Out; - std::string PassName; - - CallGraphSCCPassPrinter(const PassInfo *PI, raw_ostream &out) : - CallGraphSCCPass(ID), PassToPrint(PI), Out(out) { - std::string PassToPrintName = PassToPrint->getPassName(); - PassName = "CallGraphSCCPass Printer: " + PassToPrintName; - } - - virtual bool runOnSCC(CallGraphSCC &SCC) { - if (!Quiet) - Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; - - // Get and print pass... - for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { - Function *F = (*I)->getFunction(); - if (F) - getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, - F->getParent()); - } - return false; - } - - virtual const char *getPassName() const { return PassName.c_str(); } - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint->getTypeInfo()); - AU.setPreservesAll(); - } -}; - -char CallGraphSCCPassPrinter::ID = 0; - -struct ModulePassPrinter : public ModulePass { - static char ID; - const PassInfo *PassToPrint; - raw_ostream &Out; - std::string PassName; - - ModulePassPrinter(const PassInfo *PI, raw_ostream &out) - : ModulePass(ID), PassToPrint(PI), Out(out) { - std::string PassToPrintName = PassToPrint->getPassName(); - PassName = "ModulePass Printer: " + PassToPrintName; - } - - virtual bool runOnModule(Module &M) { - if (!Quiet) - Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; - - // Get and print pass... - getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, &M); - return false; - } - - virtual const char *getPassName() const { return PassName.c_str(); } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint->getTypeInfo()); - AU.setPreservesAll(); - } -}; - -char ModulePassPrinter::ID = 0; -struct FunctionPassPrinter : public FunctionPass { - const PassInfo *PassToPrint; - raw_ostream &Out; - static char ID; - std::string PassName; - - FunctionPassPrinter(const PassInfo *PI, raw_ostream &out) - : FunctionPass(ID), PassToPrint(PI), Out(out) { - std::string PassToPrintName = PassToPrint->getPassName(); - PassName = "FunctionPass Printer: " + PassToPrintName; - } - - virtual bool runOnFunction(Function &F) { - if (!Quiet) - Out << "Printing analysis '" << PassToPrint->getPassName() - << "' for function '" << F.getName() << "':\n"; - - // Get and print pass... - getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, - F.getParent()); - return false; - } - - virtual const char *getPassName() const { return PassName.c_str(); } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint->getTypeInfo()); - AU.setPreservesAll(); - } -}; - -char FunctionPassPrinter::ID = 0; - -struct LoopPassPrinter : public LoopPass { - static char ID; - const PassInfo *PassToPrint; - raw_ostream &Out; - std::string PassName; - - LoopPassPrinter(const PassInfo *PI, raw_ostream &out) : - LoopPass(ID), PassToPrint(PI), Out(out) { - std::string PassToPrintName = PassToPrint->getPassName(); - PassName = "LoopPass Printer: " + PassToPrintName; - } - - - virtual bool runOnLoop(Loop *L, LPPassManager &LPM) { - if (!Quiet) - Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; - - // Get and print pass... - getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, - L->getHeader()->getParent()->getParent()); - return false; - } - - virtual const char *getPassName() const { return PassName.c_str(); } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint->getTypeInfo()); - AU.setPreservesAll(); - } -}; - -char LoopPassPrinter::ID = 0; - -struct RegionPassPrinter : public RegionPass { - static char ID; - const PassInfo *PassToPrint; - raw_ostream &Out; - std::string PassName; - - RegionPassPrinter(const PassInfo *PI, raw_ostream &out) : RegionPass(ID), - PassToPrint(PI), Out(out) { - std::string PassToPrintName = PassToPrint->getPassName(); - PassName = "RegionPass Printer: " + PassToPrintName; - } - - virtual bool runOnRegion(Region *R, RGPassManager &RGM) { - if (!Quiet) { - Out << "Printing analysis '" << PassToPrint->getPassName() << "' for " - << "region: '" << R->getNameStr() << "' in function '" - << R->getEntry()->getParent()->getName() << "':\n"; - } - // Get and print pass... - getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, - R->getEntry()->getParent()->getParent()); - return false; - } - - virtual const char *getPassName() const { return PassName.c_str(); } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint->getTypeInfo()); - AU.setPreservesAll(); - } -}; - -char RegionPassPrinter::ID = 0; - -struct BasicBlockPassPrinter : public BasicBlockPass { - const PassInfo *PassToPrint; - raw_ostream &Out; - static char ID; - std::string PassName; - - BasicBlockPassPrinter(const PassInfo *PI, raw_ostream &out) - : BasicBlockPass(ID), PassToPrint(PI), Out(out) { - std::string PassToPrintName = PassToPrint->getPassName(); - PassName = "BasicBlockPass Printer: " + PassToPrintName; - } - - virtual bool runOnBasicBlock(BasicBlock &BB) { - if (!Quiet) - Out << "Printing Analysis info for BasicBlock '" << BB.getName() - << "': Pass " << PassToPrint->getPassName() << ":\n"; - - // Get and print pass... - getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, - BB.getParent()->getParent()); - return false; - } - - virtual const char *getPassName() const { return PassName.c_str(); } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint->getTypeInfo()); - AU.setPreservesAll(); - } -}; - -char BasicBlockPassPrinter::ID = 0; - -struct BreakpointPrinter : public ModulePass { - raw_ostream &Out; - static char ID; - DITypeIdentifierMap TypeIdentifierMap; - - BreakpointPrinter(raw_ostream &out) - : ModulePass(ID), Out(out) { - } - - void getContextName(DIDescriptor Context, std::string &N) { - if (Context.isNameSpace()) { - DINameSpace NS(Context); - if (!NS.getName().empty()) { - getContextName(NS.getContext(), N); - N = N + NS.getName().str() + "::"; - } - } else if (Context.isType()) { - DIType TY(Context); - if (!TY.getName().empty()) { - getContextName(TY.getContext().resolve(TypeIdentifierMap), N); - N = N + TY.getName().str() + "::"; - } - } - } - - virtual bool runOnModule(Module &M) { - TypeIdentifierMap.clear(); - NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu"); - if (CU_Nodes) - TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes); - - StringSet<> Processed; - if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp")) - for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { - std::string Name; - DISubprogram SP(NMD->getOperand(i)); - assert((!SP || SP.isSubprogram()) && - "A MDNode in llvm.dbg.sp should be null or a DISubprogram."); - if (!SP) - continue; - getContextName(SP.getContext().resolve(TypeIdentifierMap), Name); - Name = Name + SP.getDisplayName().str(); - if (!Name.empty() && Processed.insert(Name)) { - Out << Name << "\n"; - } - } - return false; - } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - } -}; - -} // anonymous namespace - -char BreakpointPrinter::ID = 0; static inline void addPass(PassManagerBase &PM, Pass *P) { // Add the pass to the pass manager... @@ -456,14 +210,7 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM, if (DisableInline) { // No inlining pass } else if (OptLevel > 1) { - unsigned Threshold = 225; - if (SizeLevel == 1) // -Os - Threshold = 75; - else if (SizeLevel == 2) // -Oz - Threshold = 25; - if (OptLevel > 2) - Threshold = 275; - Builder.Inliner = createFunctionInliningPass(Threshold); + Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel); } else { Builder.Inliner = createAlwaysInlinerPass(); } @@ -471,8 +218,14 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM, Builder.DisableUnrollLoops = (DisableLoopUnrolling.getNumOccurrences() > 0) ? DisableLoopUnrolling : OptLevel == 0; - Builder.LoopVectorize = - DisableLoopVectorization ? false : OptLevel > 1 && SizeLevel < 2; + // This is final, unless there is a #pragma vectorize enable + if (DisableLoopVectorization) + Builder.LoopVectorize = false; + // If option wasn't forced via cmd line (-vectorize-loops, -loop-vectorize) + else if (!Builder.LoopVectorize) + Builder.LoopVectorize = OptLevel > 1 && SizeLevel < 2; + + // When #pragma vectorize is on for SLP, do the same as above Builder.SLPVectorize = DisableSLPVectorization ? false : OptLevel > 1 && SizeLevel < 2; @@ -514,29 +267,6 @@ static void AddStandardLinkPasses(PassManagerBase &PM) { //===----------------------------------------------------------------------===// // CodeGen-related helper functions. // -static TargetOptions GetTargetOptions() { - TargetOptions Options; - Options.LessPreciseFPMADOption = EnableFPMAD; - Options.NoFramePointerElim = DisableFPElim; - Options.AllowFPOpFusion = FuseFPOps; - Options.UnsafeFPMath = EnableUnsafeFPMath; - Options.NoInfsFPMath = EnableNoInfsFPMath; - Options.NoNaNsFPMath = EnableNoNaNsFPMath; - Options.HonorSignDependentRoundingFPMathOption = - EnableHonorSignDependentRoundingFPMath; - Options.UseSoftFloat = GenerateSoftFloatCalls; - if (FloatABIForCalls != FloatABI::Default) - Options.FloatABIType = FloatABIForCalls; - Options.NoZerosInBSS = DontPlaceZerosInBSS; - Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; - Options.DisableTailCalls = DisableTailCalls; - Options.StackAlignmentOverride = OverrideStackAlignment; - Options.TrapFuncName = TrapFuncName; - Options.PositionIndependentExecutable = EnablePIE; - Options.EnableSegmentedStacks = SegmentedStacks; - Options.UseInitArray = UseInitArray; - return Options; -} CodeGenOpt::Level GetCodeGenOptLevel() { if (OptLevelO1) @@ -568,11 +298,18 @@ static TargetMachine* GetTargetMachine(Triple TheTriple) { } return TheTarget->createTargetMachine(TheTriple.getTriple(), - MCPU, FeaturesStr, GetTargetOptions(), + MCPU, FeaturesStr, + InitTargetOptionsFromCodeGenFlags(), RelocModel, CMModel, GetCodeGenOptLevel()); } +#ifdef LINK_POLLY_INTO_TOOLS +namespace polly { +void initializePollyPasses(llvm::PassRegistry &Registry); +} +#endif + //===----------------------------------------------------------------------===// // main for opt // @@ -603,6 +340,13 @@ int main(int argc, char **argv) { initializeInstCombine(Registry); initializeInstrumentation(Registry); initializeTarget(Registry); + // For codegen passes, only passes that do IR to IR transformation are + // supported. For now, just add CodeGenPrepare. + initializeCodeGenPreparePass(Registry); + +#ifdef LINK_POLLY_INTO_TOOLS + polly::initializePollyPasses(Registry); +#endif cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .bc modular optimizer and analysis printer\n"); @@ -615,7 +359,7 @@ int main(int argc, char **argv) { SMDiagnostic Err; // Load the input module... - OwningPtr<Module> M; + std::unique_ptr<Module> M; M.reset(ParseIRFile(InputFilename, Err, Context)); if (M.get() == 0) { @@ -628,7 +372,7 @@ int main(int argc, char **argv) { M->setTargetTriple(Triple::normalize(TargetTriple)); // Figure out what stream we are supposed to write to... - OwningPtr<tool_output_file> Out; + std::unique_ptr<tool_output_file> Out; if (NoOutput) { if (!OutputFilename.empty()) errs() << "WARNING: The -o (output filename) option is ignored when\n" @@ -640,7 +384,7 @@ int main(int argc, char **argv) { std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - sys::fs::F_Binary)); + sys::fs::F_None)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; @@ -654,6 +398,26 @@ int main(int argc, char **argv) { if (CheckBitcodeOutputToConsole(Out->os(), !Quiet)) NoOutput = true; + if (PassPipeline.getNumOccurrences() > 0) { + OutputKind OK = OK_NoOutput; + if (!NoOutput) + OK = OutputAssembly ? OK_OutputAssembly : OK_OutputBitcode; + + VerifierKind VK = VK_VerifyInAndOut; + if (NoVerify) + VK = VK_NoVerifier; + else if (VerifyEach) + VK = VK_VerifyEachPass; + + // The user has asked to use the new pass manager and provided a pipeline + // string. Hand off the rest of the functionality to the new code for that + // layer. + return runPassPipeline(argv[0], Context, *M.get(), Out.get(), PassPipeline, + OK, VK) + ? 0 + : 1; + } + // Create a PassManager to hold and optimize the collection of passes we are // about to build. // @@ -668,31 +432,30 @@ int main(int argc, char **argv) { Passes.add(TLI); // Add an appropriate DataLayout instance for this module. - DataLayout *TD = 0; - const std::string &ModuleDataLayout = M.get()->getDataLayout(); - if (!ModuleDataLayout.empty()) - TD = new DataLayout(ModuleDataLayout); - else if (!DefaultDataLayout.empty()) - TD = new DataLayout(DefaultDataLayout); + const DataLayout *DL = M.get()->getDataLayout(); + if (!DL && !DefaultDataLayout.empty()) { + M->setDataLayout(DefaultDataLayout); + DL = M.get()->getDataLayout(); + } - if (TD) - Passes.add(TD); + if (DL) + Passes.add(new DataLayoutPass(M.get())); Triple ModuleTriple(M->getTargetTriple()); TargetMachine *Machine = 0; if (ModuleTriple.getArch()) Machine = GetTargetMachine(Triple(ModuleTriple)); - OwningPtr<TargetMachine> TM(Machine); + std::unique_ptr<TargetMachine> TM(Machine); // Add internal analysis passes from the target machine. if (TM.get()) TM->addAnalysisPasses(Passes); - OwningPtr<FunctionPassManager> FPasses; + std::unique_ptr<FunctionPassManager> FPasses; if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) { FPasses.reset(new FunctionPassManager(M.get())); - if (TD) - FPasses->add(new DataLayout(*TD)); + if (DL) + FPasses->add(new DataLayoutPass(M.get())); if (TM.get()) TM->addAnalysisPasses(*FPasses); @@ -706,13 +469,13 @@ int main(int argc, char **argv) { std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - sys::fs::F_Binary)); + sys::fs::F_None)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; } } - Passes.add(new BreakpointPrinter(Out->os())); + Passes.add(createBreakpointPrinter(Out->os())); NoOutput = true; } @@ -764,7 +527,9 @@ int main(int argc, char **argv) { const PassInfo *PassInf = PassList[i]; Pass *P = 0; - if (PassInf->getNormalCtor()) + if (PassInf->getTargetMachineCtor()) + P = PassInf->getTargetMachineCtor()(TM.get()); + else if (PassInf->getNormalCtor()) P = PassInf->getNormalCtor()(); else errs() << argv[0] << ": cannot create pass: " @@ -776,29 +541,29 @@ int main(int argc, char **argv) { if (AnalyzeOnly) { switch (Kind) { case PT_BasicBlock: - Passes.add(new BasicBlockPassPrinter(PassInf, Out->os())); + Passes.add(createBasicBlockPassPrinter(PassInf, Out->os(), Quiet)); break; case PT_Region: - Passes.add(new RegionPassPrinter(PassInf, Out->os())); + Passes.add(createRegionPassPrinter(PassInf, Out->os(), Quiet)); break; case PT_Loop: - Passes.add(new LoopPassPrinter(PassInf, Out->os())); + Passes.add(createLoopPassPrinter(PassInf, Out->os(), Quiet)); break; case PT_Function: - Passes.add(new FunctionPassPrinter(PassInf, Out->os())); + Passes.add(createFunctionPassPrinter(PassInf, Out->os(), Quiet)); break; case PT_CallGraphSCC: - Passes.add(new CallGraphSCCPassPrinter(PassInf, Out->os())); + Passes.add(createCallGraphPassPrinter(PassInf, Out->os(), Quiet)); break; default: - Passes.add(new ModulePassPrinter(PassInf, Out->os())); + Passes.add(createModulePassPrinter(PassInf, Out->os(), Quiet)); break; } } } if (PrintEachXForm) - Passes.add(createPrintModulePass(&errs())); + Passes.add(createPrintModulePass(errs())); } // If -std-compile-opts was specified at the end of the pass list, add them. @@ -841,7 +606,7 @@ int main(int argc, char **argv) { // Write bitcode or assembly to the output as the last step... if (!NoOutput && !AnalyzeOnly) { if (OutputAssembly) - Passes.add(createPrintModulePass(&Out->os())); + Passes.add(createPrintModulePass(Out->os())); else Passes.add(createBitcodeWriterPass(Out->os())); } diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt index 8d9d652..5e63dfb 100644 --- a/tools/yaml2obj/CMakeLists.txt +++ b/tools/yaml2obj/CMakeLists.txt @@ -1,9 +1,10 @@ -set(LLVM_LINK_COMPONENTS object) +set(LLVM_LINK_COMPONENTS + Object + Support + ) add_llvm_utility(yaml2obj yaml2obj.cpp yaml2coff.cpp yaml2elf.cpp ) - -target_link_libraries(yaml2obj LLVMSupport) diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp index c757eb6..a0ede24 100644 --- a/tools/yaml2obj/yaml2coff.cpp +++ b/tools/yaml2obj/yaml2coff.cpp @@ -14,6 +14,7 @@ #include "yaml2obj.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" @@ -153,13 +154,22 @@ static bool layoutCOFF(COFFParser &CP) { for (std::vector<COFFYAML::Symbol>::iterator i = CP.Obj.Symbols.begin(), e = CP.Obj.Symbols.end(); i != e; ++i) { - unsigned AuxBytes = i->AuxiliaryData.binary_size(); - if (AuxBytes % COFF::SymbolSize != 0) { - errs() << "AuxiliaryData size not a multiple of symbol size!\n"; - return false; - } - i->Header.NumberOfAuxSymbols = AuxBytes / COFF::SymbolSize; - NumberOfSymbols += 1 + i->Header.NumberOfAuxSymbols; + uint32_t NumberOfAuxSymbols = 0; + if (i->FunctionDefinition) + NumberOfAuxSymbols += 1; + if (i->bfAndefSymbol) + NumberOfAuxSymbols += 1; + if (i->WeakExternal) + NumberOfAuxSymbols += 1; + if (!i->File.empty()) + NumberOfAuxSymbols += + (i->File.size() + COFF::SymbolSize - 1) / COFF::SymbolSize; + if (i->SectionDefinition) + NumberOfAuxSymbols += 1; + if (i->CLRToken) + NumberOfAuxSymbols += 1; + i->Header.NumberOfAuxSymbols = NumberOfAuxSymbols; + NumberOfSymbols += 1 + NumberOfAuxSymbols; } // Store all the allocated start addresses in the header. @@ -194,6 +204,24 @@ binary_le_impl<value_type> binary_le(value_type V) { return binary_le_impl<value_type>(V); } +template <size_t NumBytes> +struct zeros_impl { + zeros_impl() {} +}; + +template <size_t NumBytes> +raw_ostream &operator<<(raw_ostream &OS, const zeros_impl<NumBytes> &) { + char Buffer[NumBytes]; + memset(Buffer, 0, sizeof(Buffer)); + OS.write(Buffer, sizeof(Buffer)); + return OS; +} + +template <typename T> +zeros_impl<sizeof(T)> zeros(const T &) { + return zeros_impl<sizeof(T)>(); +} + bool writeCOFF(COFFParser &CP, raw_ostream &OS) { OS << binary_le(CP.Obj.Header.Machine) << binary_le(CP.Obj.Header.NumberOfSections) @@ -253,7 +281,45 @@ bool writeCOFF(COFFParser &CP, raw_ostream &OS) { << binary_le(i->Header.Type) << binary_le(i->Header.StorageClass) << binary_le(i->Header.NumberOfAuxSymbols); - i->AuxiliaryData.writeAsBinary(OS); + + if (i->FunctionDefinition) + OS << binary_le(i->FunctionDefinition->TagIndex) + << binary_le(i->FunctionDefinition->TotalSize) + << binary_le(i->FunctionDefinition->PointerToLinenumber) + << binary_le(i->FunctionDefinition->PointerToNextFunction) + << zeros(i->FunctionDefinition->unused); + if (i->bfAndefSymbol) + OS << zeros(i->bfAndefSymbol->unused1) + << binary_le(i->bfAndefSymbol->Linenumber) + << zeros(i->bfAndefSymbol->unused2) + << binary_le(i->bfAndefSymbol->PointerToNextFunction) + << zeros(i->bfAndefSymbol->unused3); + if (i->WeakExternal) + OS << binary_le(i->WeakExternal->TagIndex) + << binary_le(i->WeakExternal->Characteristics) + << zeros(i->WeakExternal->unused); + if (!i->File.empty()) { + uint32_t NumberOfAuxRecords = + (i->File.size() + COFF::SymbolSize - 1) / COFF::SymbolSize; + uint32_t NumberOfAuxBytes = NumberOfAuxRecords * COFF::SymbolSize; + uint32_t NumZeros = NumberOfAuxBytes - i->File.size(); + OS.write(i->File.data(), i->File.size()); + for (uint32_t Padding = 0; Padding < NumZeros; ++Padding) + OS.write(0); + } + if (i->SectionDefinition) + OS << binary_le(i->SectionDefinition->Length) + << binary_le(i->SectionDefinition->NumberOfRelocations) + << binary_le(i->SectionDefinition->NumberOfLinenumbers) + << binary_le(i->SectionDefinition->CheckSum) + << binary_le(i->SectionDefinition->Number) + << binary_le(i->SectionDefinition->Selection) + << zeros(i->SectionDefinition->unused); + if (i->CLRToken) + OS << binary_le(i->CLRToken->AuxType) + << zeros(i->CLRToken->unused1) + << binary_le(i->CLRToken->SymbolTableIndex) + << zeros(i->CLRToken->unused2); } // Output string table. diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index d46e154..21506d9 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -134,94 +134,125 @@ static void zero(T &Obj) { memset(&Obj, 0, sizeof(Obj)); } -/// \brief Create a string table in `SHeader`, which we assume is already -/// zero'd. -template <class Elf_Shdr> -static void createStringTableSectionHeader(Elf_Shdr &SHeader, - StringTableBuilder &STB, - ContiguousBlobAccumulator &CBA) { - SHeader.sh_type = ELF::SHT_STRTAB; - STB.writeToStream(CBA.getOSAndAlignedOffset(SHeader.sh_offset)); - SHeader.sh_size = STB.size(); - SHeader.sh_addralign = 1; -} - namespace { /// \brief "Single point of truth" for the ELF file construction. /// TODO: This class still has a ways to go before it is truly a "single /// point of truth". template <class ELFT> class ELFState { + typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr; + typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym; + /// \brief The future ".strtab" section. StringTableBuilder DotStrtab; - /// \brief The section number of the ".strtab" section. - unsigned DotStrtabSecNo; - /// \brief The accumulated contents of all sections so far. - ContiguousBlobAccumulator &SectionContentAccum; - typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr; - /// \brief The ELF file header. - Elf_Ehdr &Header; - SectionNameToIdxMap &SN2I; + /// \brief The future ".shstrtab" section. + StringTableBuilder DotShStrtab; -public: + SectionNameToIdxMap SN2I; + const ELFYAML::Object &Doc; + + bool buildSectionIndex(); + void initELFHeader(Elf_Ehdr &Header); + bool initSectionHeaders(std::vector<Elf_Shdr> &SHeaders, + ContiguousBlobAccumulator &CBA); + void initSymtabSectionHeader(Elf_Shdr &SHeader, + ContiguousBlobAccumulator &CBA); + void initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, + StringTableBuilder &STB, + ContiguousBlobAccumulator &CBA); + void addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, + std::vector<Elf_Sym> &Syms, unsigned SymbolBinding); + + // - SHT_NULL entry (placed first, i.e. 0'th entry) + // - symbol table (.symtab) (placed third to last) + // - string table (.strtab) (placed second to last) + // - section header string table (.shstrtab) (placed last) + unsigned getDotSymTabSecNo() const { return Doc.Sections.size() + 1; } + unsigned getDotStrTabSecNo() const { return Doc.Sections.size() + 2; } + unsigned getDotShStrTabSecNo() const { return Doc.Sections.size() + 3; } + unsigned getSectionCount() const { return Doc.Sections.size() + 4; } - ELFState(Elf_Ehdr &Header_, ContiguousBlobAccumulator &Accum, - unsigned DotStrtabSecNo_, SectionNameToIdxMap &SN2I_) - : DotStrtab(), DotStrtabSecNo(DotStrtabSecNo_), - SectionContentAccum(Accum), Header(Header_), SN2I(SN2I_) {} + ELFState(const ELFYAML::Object &D) : Doc(D) {} - unsigned getDotStrTabSecNo() const { return DotStrtabSecNo; } - StringTableBuilder &getStringTable() { return DotStrtab; } - ContiguousBlobAccumulator &getSectionContentAccum() { - return SectionContentAccum; - } - SectionNameToIdxMap &getSN2I() { return SN2I; } +public: + static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc); }; } // end anonymous namespace -// FIXME: At this point it is fairly clear that we need to refactor these -// static functions into methods of a class sharing some typedefs. These -// ELF type names are insane. template <class ELFT> -static void -addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, ELFState<ELFT> &State, - std::vector<typename object::ELFFile<ELFT>::Elf_Sym> &Syms, - unsigned SymbolBinding) { - typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - for (unsigned i = 0, e = Symbols.size(); i != e; ++i) { - const ELFYAML::Symbol &Sym = Symbols[i]; - Elf_Sym Symbol; - zero(Symbol); - if (!Sym.Name.empty()) - Symbol.st_name = State.getStringTable().addString(Sym.Name); - Symbol.setBindingAndType(SymbolBinding, Sym.Type); - if (!Sym.Section.empty()) { +void ELFState<ELFT>::initELFHeader(Elf_Ehdr &Header) { + using namespace llvm::ELF; + zero(Header); + Header.e_ident[EI_MAG0] = 0x7f; + Header.e_ident[EI_MAG1] = 'E'; + Header.e_ident[EI_MAG2] = 'L'; + Header.e_ident[EI_MAG3] = 'F'; + Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; + bool IsLittleEndian = ELFT::TargetEndianness == support::little; + Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; + Header.e_ident[EI_VERSION] = EV_CURRENT; + Header.e_ident[EI_OSABI] = Doc.Header.OSABI; + Header.e_ident[EI_ABIVERSION] = 0; + Header.e_type = Doc.Header.Type; + Header.e_machine = Doc.Header.Machine; + Header.e_version = EV_CURRENT; + Header.e_entry = Doc.Header.Entry; + Header.e_flags = Doc.Header.Flags; + Header.e_ehsize = sizeof(Elf_Ehdr); + Header.e_shentsize = sizeof(Elf_Shdr); + // Immediately following the ELF header. + Header.e_shoff = sizeof(Header); + Header.e_shnum = getSectionCount(); + Header.e_shstrndx = getDotShStrTabSecNo(); +} + +template <class ELFT> +bool ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders, + ContiguousBlobAccumulator &CBA) { + // Ensure SHN_UNDEF entry is present. An all-zero section header is a + // valid SHN_UNDEF entry since SHT_NULL == 0. + Elf_Shdr SHeader; + zero(SHeader); + SHeaders.push_back(SHeader); + + for (const auto &Sec : Doc.Sections) { + zero(SHeader); + SHeader.sh_name = DotShStrtab.addString(Sec.Name); + SHeader.sh_type = Sec.Type; + SHeader.sh_flags = Sec.Flags; + SHeader.sh_addr = Sec.Address; + + Sec.Content.writeAsBinary(CBA.getOSAndAlignedOffset(SHeader.sh_offset)); + SHeader.sh_size = Sec.Content.binary_size(); + + if (!Sec.Link.empty()) { unsigned Index; - if (State.getSN2I().lookupSection(Sym.Section, Index)) { - errs() << "error: Unknown section referenced: '" << Sym.Section - << "' by YAML symbol " << Sym.Name << ".\n"; - exit(1); + if (SN2I.lookupSection(Sec.Link, Index)) { + errs() << "error: Unknown section referenced: '" << Sec.Link + << "' at YAML section '" << Sec.Name << "'.\n"; + return false;; } - Symbol.st_shndx = Index; - } // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier. - Symbol.st_value = Sym.Value; - Symbol.st_size = Sym.Size; - Syms.push_back(Symbol); + SHeader.sh_link = Index; + } + SHeader.sh_info = 0; + SHeader.sh_addralign = Sec.AddressAlign; + SHeader.sh_entsize = 0; + SHeaders.push_back(SHeader); } + return true; } template <class ELFT> -static void -handleSymtabSectionHeader(const ELFYAML::LocalGlobalWeakSymbols &Symbols, - ELFState<ELFT> &State, - typename object::ELFFile<ELFT>::Elf_Shdr &SHeader) { - - typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym; +void ELFState<ELFT>::initSymtabSectionHeader(Elf_Shdr &SHeader, + ContiguousBlobAccumulator &CBA) { + zero(SHeader); + SHeader.sh_name = DotShStrtab.addString(StringRef(".symtab")); SHeader.sh_type = ELF::SHT_SYMTAB; - SHeader.sh_link = State.getDotStrTabSecNo(); + SHeader.sh_link = getDotStrTabSecNo(); // One greater than symbol table index of the last local symbol. - SHeader.sh_info = Symbols.Local.size() + 1; + SHeader.sh_info = Doc.Symbols.Local.size() + 1; SHeader.sh_entsize = sizeof(Elf_Sym); std::vector<Elf_Sym> Syms; @@ -231,134 +262,109 @@ handleSymtabSectionHeader(const ELFYAML::LocalGlobalWeakSymbols &Symbols, zero(Sym); Syms.push_back(Sym); } - addSymbols(Symbols.Local, State, Syms, ELF::STB_LOCAL); - addSymbols(Symbols.Global, State, Syms, ELF::STB_GLOBAL); - addSymbols(Symbols.Weak, State, Syms, ELF::STB_WEAK); + addSymbols(Doc.Symbols.Local, Syms, ELF::STB_LOCAL); + addSymbols(Doc.Symbols.Global, Syms, ELF::STB_GLOBAL); + addSymbols(Doc.Symbols.Weak, Syms, ELF::STB_WEAK); - ContiguousBlobAccumulator &CBA = State.getSectionContentAccum(); writeArrayData(CBA.getOSAndAlignedOffset(SHeader.sh_offset), makeArrayRef(Syms)); SHeader.sh_size = arrayDataSize(makeArrayRef(Syms)); } template <class ELFT> -static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { - using namespace llvm::ELF; - typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr; - typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - - const ELFYAML::FileHeader &Hdr = Doc.Header; - - Elf_Ehdr Header; - zero(Header); - Header.e_ident[EI_MAG0] = 0x7f; - Header.e_ident[EI_MAG1] = 'E'; - Header.e_ident[EI_MAG2] = 'L'; - Header.e_ident[EI_MAG3] = 'F'; - Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; - bool IsLittleEndian = ELFT::TargetEndianness == support::little; - Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; - Header.e_ident[EI_VERSION] = EV_CURRENT; - Header.e_ident[EI_OSABI] = Hdr.OSABI; - Header.e_ident[EI_ABIVERSION] = 0; - Header.e_type = Hdr.Type; - Header.e_machine = Hdr.Machine; - Header.e_version = EV_CURRENT; - Header.e_entry = Hdr.Entry; - Header.e_ehsize = sizeof(Elf_Ehdr); +void ELFState<ELFT>::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, + StringTableBuilder &STB, + ContiguousBlobAccumulator &CBA) { + zero(SHeader); + SHeader.sh_name = DotShStrtab.addString(Name); + SHeader.sh_type = ELF::SHT_STRTAB; + STB.writeToStream(CBA.getOSAndAlignedOffset(SHeader.sh_offset)); + SHeader.sh_size = STB.size(); + SHeader.sh_addralign = 1; +} - // TODO: Flesh out section header support. - // TODO: Program headers. +template <class ELFT> +void ELFState<ELFT>::addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, + std::vector<Elf_Sym> &Syms, + unsigned SymbolBinding) { + for (const auto &Sym : Symbols) { + Elf_Sym Symbol; + zero(Symbol); + if (!Sym.Name.empty()) + Symbol.st_name = DotStrtab.addString(Sym.Name); + Symbol.setBindingAndType(SymbolBinding, Sym.Type); + if (!Sym.Section.empty()) { + unsigned Index; + if (SN2I.lookupSection(Sym.Section, Index)) { + errs() << "error: Unknown section referenced: '" << Sym.Section + << "' by YAML symbol " << Sym.Name << ".\n"; + exit(1); + } + Symbol.st_shndx = Index; + } // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier. + Symbol.st_value = Sym.Value; + Symbol.st_size = Sym.Size; + Syms.push_back(Symbol); + } +} - Header.e_shentsize = sizeof(Elf_Shdr); - // Immediately following the ELF header. - Header.e_shoff = sizeof(Header); - const std::vector<ELFYAML::Section> &Sections = Doc.Sections; - // "+ 4" for - // - SHT_NULL entry (placed first, i.e. 0'th entry) - // - symbol table (.symtab) (placed third to last) - // - string table (.strtab) (placed second to last) - // - section header string table. (placed last) - Header.e_shnum = Sections.size() + 4; - // Place section header string table last. - Header.e_shstrndx = Header.e_shnum - 1; - const unsigned DotStrtabSecNo = Header.e_shnum - 2; +template <class ELFT> bool ELFState<ELFT>::buildSectionIndex() { + SN2I.addName(".symtab", getDotSymTabSecNo()); + SN2I.addName(".strtab", getDotStrTabSecNo()); + SN2I.addName(".shstrtab", getDotShStrTabSecNo()); - // XXX: This offset is tightly coupled with the order that we write - // things to `OS`. - const size_t SectionContentBeginOffset = - Header.e_ehsize + Header.e_shentsize * Header.e_shnum; - ContiguousBlobAccumulator CBA(SectionContentBeginOffset); - SectionNameToIdxMap SN2I; - for (unsigned i = 0, e = Sections.size(); i != e; ++i) { - StringRef Name = Sections[i].Name; + for (unsigned i = 0, e = Doc.Sections.size(); i != e; ++i) { + StringRef Name = Doc.Sections[i].Name; if (Name.empty()) continue; // "+ 1" to take into account the SHT_NULL entry. if (SN2I.addName(Name, i + 1)) { errs() << "error: Repeated section name: '" << Name << "' at YAML section number " << i << ".\n"; - return 1; + return false; } } + return true; +} - ELFState<ELFT> State(Header, CBA, DotStrtabSecNo, SN2I); +template <class ELFT> +int ELFState<ELFT>::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { + ELFState<ELFT> State(Doc); + if (!State.buildSectionIndex()) + return 1; - StringTableBuilder SHStrTab; - std::vector<Elf_Shdr> SHeaders; - { - // Ensure SHN_UNDEF entry is present. An all-zero section header is a - // valid SHN_UNDEF entry since SHT_NULL == 0. - Elf_Shdr SHdr; - zero(SHdr); - SHeaders.push_back(SHdr); - } - for (unsigned i = 0, e = Sections.size(); i != e; ++i) { - const ELFYAML::Section &Sec = Sections[i]; - Elf_Shdr SHeader; - zero(SHeader); - SHeader.sh_name = SHStrTab.addString(Sec.Name); - SHeader.sh_type = Sec.Type; - SHeader.sh_flags = Sec.Flags; - SHeader.sh_addr = Sec.Address; + Elf_Ehdr Header; + State.initELFHeader(Header); - Sec.Content.writeAsBinary(CBA.getOSAndAlignedOffset(SHeader.sh_offset)); - SHeader.sh_size = Sec.Content.binary_size(); + // TODO: Flesh out section header support. + // TODO: Program headers. - if (!Sec.Link.empty()) { - unsigned Index; - if (SN2I.lookupSection(Sec.Link, Index)) { - errs() << "error: Unknown section referenced: '" << Sec.Link - << "' at YAML section number " << i << ".\n"; - return 1; - } - SHeader.sh_link = Index; - } - SHeader.sh_info = 0; - SHeader.sh_addralign = Sec.AddressAlign; - SHeader.sh_entsize = 0; - SHeaders.push_back(SHeader); - } + // XXX: This offset is tightly coupled with the order that we write + // things to `OS`. + const size_t SectionContentBeginOffset = + Header.e_ehsize + Header.e_shentsize * Header.e_shnum; + ContiguousBlobAccumulator CBA(SectionContentBeginOffset); + + std::vector<Elf_Shdr> SHeaders; + if(!State.initSectionHeaders(SHeaders, CBA)) + return 1; // .symtab section. Elf_Shdr SymtabSHeader; - zero(SymtabSHeader); - SymtabSHeader.sh_name = SHStrTab.addString(StringRef(".symtab")); - handleSymtabSectionHeader<ELFT>(Doc.Symbols, State, SymtabSHeader); + State.initSymtabSectionHeader(SymtabSHeader, CBA); SHeaders.push_back(SymtabSHeader); // .strtab string table header. Elf_Shdr DotStrTabSHeader; - zero(DotStrTabSHeader); - DotStrTabSHeader.sh_name = SHStrTab.addString(StringRef(".strtab")); - createStringTableSectionHeader(DotStrTabSHeader, State.getStringTable(), CBA); + State.initStrtabSectionHeader(DotStrTabSHeader, ".strtab", State.DotStrtab, + CBA); SHeaders.push_back(DotStrTabSHeader); - // Section header string table header. - Elf_Shdr SHStrTabSHeader; - zero(SHStrTabSHeader); - createStringTableSectionHeader(SHStrTabSHeader, SHStrTab, CBA); - SHeaders.push_back(SHStrTabSHeader); + // .shstrtab string table header. + Elf_Shdr ShStrTabSHeader; + State.initStrtabSectionHeader(ShStrTabSHeader, ".shstrtab", State.DotShStrtab, + CBA); + SHeaders.push_back(ShStrTabSHeader); OS.write((const char *)&Header, sizeof(Header)); writeArrayData(OS, makeArrayRef(SHeaders)); @@ -389,13 +395,13 @@ int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { typedef ELFType<support::big, 4, false> BE32; if (is64Bit(Doc)) { if (isLittleEndian(Doc)) - return writeELF<LE64>(outs(), Doc); + return ELFState<LE64>::writeELF(outs(), Doc); else - return writeELF<BE64>(outs(), Doc); + return ELFState<BE64>::writeELF(outs(), Doc); } else { if (isLittleEndian(Doc)) - return writeELF<LE32>(outs(), Doc); + return ELFState<LE32>::writeELF(outs(), Doc); else - return writeELF<BE32>(outs(), Doc); + return ELFState<BE32>::writeELF(outs(), Doc); } } diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp index 6d1107c..cc0fecc 100644 --- a/tools/yaml2obj/yaml2obj.cpp +++ b/tools/yaml2obj/yaml2obj.cpp @@ -15,7 +15,6 @@ //===----------------------------------------------------------------------===// #include "yaml2obj.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" @@ -57,7 +56,7 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - OwningPtr<MemoryBuffer> Buf; + std::unique_ptr<MemoryBuffer> Buf; if (MemoryBuffer::getFileOrSTDIN(Input, Buf)) return 1; if (Format == YOF_COFF) { |