diff options
Diffstat (limited to 'tools')
115 files changed, 6366 insertions, 2599 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5e95604..e663781 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -14,7 +14,6 @@ add_subdirectory(llvm-dis) add_subdirectory(llvm-mc) add_subdirectory(llc) -add_subdirectory(llvm-ranlib) add_subdirectory(llvm-ar) add_subdirectory(llvm-nm) add_subdirectory(llvm-size) @@ -43,6 +42,9 @@ add_subdirectory(llvm-mcmarkup) add_subdirectory(llvm-symbolizer) +add_subdirectory(obj2yaml) +add_subdirectory(yaml2obj) + if( NOT WIN32 ) add_subdirectory(lto) endif() @@ -56,8 +58,11 @@ if( LLVM_ENABLE_PIC ) endif() add_llvm_external_project(clang) -add_llvm_external_project(lld) -add_llvm_external_project(lldb) -add_llvm_external_project(polly) + +if( NOT LLVM_INCLUDE_TOOLS STREQUAL "bootstrap-only" ) + add_llvm_external_project(lld) + add_llvm_external_project(lldb) + add_llvm_external_project(polly) +endif() set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE) diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index 25aa177..9ec89f3 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-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib 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-mc llvm-nm llvm-objdump llvm-prof llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup [component_0] type = Group diff --git a/tools/Makefile b/tools/Makefile index c405868..b7375c9 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -28,14 +28,14 @@ OPTIONAL_DIRS := lldb # in parallel builds. Please retain this ordering. DIRS := llvm-config PARALLEL_DIRS := opt llvm-as llvm-dis \ - llc llvm-ranlib llvm-ar llvm-nm \ + llc llvm-ar llvm-nm \ llvm-prof 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 + llvm-symbolizer obj2yaml yaml2obj # If Intel JIT Events support is configured, build an extra tool to test it. ifeq ($(USE_INTEL_JITEVENTS), 1) diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index cede4ac..a5436ba 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -16,12 +16,12 @@ #include "BugDriver.h" #include "ToolRunner.h" #include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Linker.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/Host.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include <memory> @@ -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) { - std::auto_ptr<Module> M(ParseInputFile(Filenames[i], Context)); + OwningPtr<Module> M(ParseInputFile(Filenames[i], Context)); if (M.get() == 0) return true; outs() << "Linking in input file: '" << Filenames[i] << "'\n"; @@ -194,8 +194,8 @@ bool BugDriver::run(std::string &ErrMsg) { // Make sure the reference output file gets deleted on exit from this // function, if appropriate. - sys::Path ROF(ReferenceOutputFile); - FileRemover RemoverInstance(ROF.str(), CreatedOutput && !SaveTemps); + std::string ROF(ReferenceOutputFile); + FileRemover RemoverInstance(ROF, CreatedOutput && !SaveTemps); // Diff the output of the raw program against the reference output. If it // matches, then we assume there is a miscompilation bug and try to diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index 2b621ec..27b37f4 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -191,7 +191,7 @@ public: /// this function. /// bool createReferenceFile(Module *M, const std::string &Filename - = "bugpoint.reference.out"); + = "bugpoint.reference.out-%%%%%%%"); /// diffProgram - This method executes the specified module and diffs the /// output against the file specified by ReferenceOutputFile. If the output @@ -275,6 +275,8 @@ public: /// bitcode file. If an error occurs, true is returned. /// bool writeProgramToFile(const std::string &Filename, const Module *M) const; + bool writeProgramToFile(const std::string &Filename, int FD, + const Module *M) const; private: /// runPasses - Just like the method above, but this just returns true or diff --git a/tools/bugpoint/CMakeLists.txt b/tools/bugpoint/CMakeLists.txt index 3c5e64f..0000d97 100644 --- a/tools/bugpoint/CMakeLists.txt +++ b/tools/bugpoint/CMakeLists.txt @@ -1,5 +1,5 @@ set(LLVM_LINK_COMPONENTS asmparser instrumentation scalaropts ipo - linker bitreader bitwriter vectorize objcarcopts) + linker bitreader bitwriter irreader vectorize objcarcopts) add_llvm_tool(bugpoint BugDriver.cpp @@ -12,3 +12,4 @@ add_llvm_tool(bugpoint ToolRunner.cpp bugpoint.cpp ) +set_target_properties(bugpoint PROPERTIES ENABLE_EXPORTS 1) diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index ed211a6..c8b4f6f 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -62,25 +62,23 @@ ReducePassList::TestResult ReducePassList::doTest(std::vector<std::string> &Prefix, std::vector<std::string> &Suffix, std::string &Error) { - sys::Path PrefixOutput; + std::string PrefixOutput; Module *OrigProgram = 0; if (!Prefix.empty()) { outs() << "Checking to see if these passes crash: " << getPassesString(Prefix) << ": "; - std::string PfxOutput; - if (BD.runPasses(BD.getProgram(), Prefix, PfxOutput)) + if (BD.runPasses(BD.getProgram(), Prefix, PrefixOutput)) return KeepPrefix; - PrefixOutput.set(PfxOutput); OrigProgram = BD.Program; - BD.Program = ParseInputFile(PrefixOutput.str(), BD.getContext()); + BD.Program = ParseInputFile(PrefixOutput, BD.getContext()); if (BD.Program == 0) { errs() << BD.getToolName() << ": Error reading bitcode file '" - << PrefixOutput.str() << "'!\n"; + << PrefixOutput << "'!\n"; exit(1); } - PrefixOutput.eraseFromDisk(); + sys::fs::remove(PrefixOutput); } outs() << "Checking to see if these passes crash: " diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index da36045..3d3dac3 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -265,16 +265,18 @@ bool BugDriver::initializeExecutionEnvironment() { /// void BugDriver::compileProgram(Module *M, std::string *Error) const { // Emit the program to a bitcode file... - sys::Path BitcodeFile (OutputPrefix + "-test-program.bc"); - std::string ErrMsg; - if (BitcodeFile.makeUnique(true, &ErrMsg)) { - errs() << ToolName << ": Error making unique filename: " << ErrMsg + SmallString<128> BitcodeFile; + int BitcodeFD; + error_code EC = sys::fs::createUniqueFile( + OutputPrefix + "-test-program-%%%%%%%.bc", BitcodeFD, BitcodeFile); + if (EC) { + errs() << ToolName << ": Error making unique filename: " << EC.message() << "\n"; exit(1); } - if (writeProgramToFile(BitcodeFile.str(), M)) { - errs() << ToolName << ": Error emitting bitcode to file '" - << BitcodeFile.str() << "'!\n"; + if (writeProgramToFile(BitcodeFile.str(), BitcodeFD, M)) { + errs() << ToolName << ": Error emitting bitcode to file '" << BitcodeFile + << "'!\n"; exit(1); } @@ -302,15 +304,18 @@ std::string BugDriver::executeProgram(const Module *Program, std::string ErrMsg; if (BitcodeFile.empty()) { // Emit the program to a bitcode file... - sys::Path uniqueFilename(OutputPrefix + "-test-program.bc"); - if (uniqueFilename.makeUnique(true, &ErrMsg)) { + SmallString<128> UniqueFilename; + int UniqueFD; + error_code EC = sys::fs::createUniqueFile( + OutputPrefix + "-test-program-%%%%%%%.bc", UniqueFD, UniqueFilename); + if (EC) { errs() << ToolName << ": Error making unique filename: " - << ErrMsg << "!\n"; + << EC.message() << "!\n"; exit(1); } - BitcodeFile = uniqueFilename.str(); + BitcodeFile = UniqueFilename.str(); - if (writeProgramToFile(BitcodeFile, Program)) { + if (writeProgramToFile(BitcodeFile, UniqueFD, Program)) { errs() << ToolName << ": Error emitting bitcode to file '" << BitcodeFile << "'!\n"; exit(1); @@ -319,20 +324,21 @@ std::string BugDriver::executeProgram(const Module *Program, } // Remove the temporary bitcode file when we are done. - sys::Path BitcodePath(BitcodeFile); - FileRemover BitcodeFileRemover(BitcodePath.str(), + std::string BitcodePath(BitcodeFile); + FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode && !SaveTemps); - if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output"; + if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output-%%%%%%%"; // Check to see if this is a valid output filename... - sys::Path uniqueFile(OutputFile); - if (uniqueFile.makeUnique(true, &ErrMsg)) { + SmallString<128> UniqueFile; + error_code EC = sys::fs::createUniqueFile(OutputFile, UniqueFile); + if (EC) { errs() << ToolName << ": Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - OutputFile = uniqueFile.str(); + OutputFile = UniqueFile.str(); // Figure out which shared objects to run, if any. std::vector<std::string> SharedObjs(AdditionalSOs); @@ -380,7 +386,7 @@ std::string BugDriver::executeProgramSafely(const Module *Program, std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, std::string &Error) { assert(Interpreter && "Interpreter should have been created already!"); - sys::Path OutputFile; + std::string OutputFile; // Using the known-good backend. GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile, @@ -389,7 +395,7 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, return ""; std::string SharedObjectFile; - bool Failure = gcc->MakeSharedObject(OutputFile.str(), FT, SharedObjectFile, + bool Failure = gcc->MakeSharedObject(OutputFile, FT, SharedObjectFile, AdditionalLinkerArgs, Error); if (!Error.empty()) return ""; @@ -397,7 +403,7 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, exit(1); // Remove the intermediate C file - OutputFile.eraseFromDisk(); + sys::fs::remove(OutputFile); return "./" + SharedObjectFile; } @@ -439,15 +445,15 @@ bool BugDriver::diffProgram(const Module *Program, bool RemoveBitcode, std::string *ErrMsg) const { // Execute the program, generating an output file... - sys::Path Output(executeProgram(Program, "", BitcodeFile, SharedObject, 0, - ErrMsg)); + std::string Output( + executeProgram(Program, "", BitcodeFile, SharedObject, 0, ErrMsg)); if (!ErrMsg->empty()) return false; std::string Error; bool FilesDifferent = false; - if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile), - sys::Path(Output.str()), + if (int Diff = DiffFilesWithTolerance(ReferenceOutputFile, + Output, AbsTolerance, RelTolerance, &Error)) { if (Diff == 2) { errs() << "While diffing output: " << Error << '\n'; @@ -457,12 +463,12 @@ bool BugDriver::diffProgram(const Module *Program, } else { // Remove the generated output if there are no differences. - Output.eraseFromDisk(); + sys::fs::remove(Output); } // Remove the bitcode file if we are supposed to. if (RemoveBitcode) - sys::Path(BitcodeFile).eraseFromDisk(); + sys::fs::remove(BitcodeFile); return FilesDifferent; } diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index bb27767..2098928 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -363,25 +363,19 @@ llvm::SplitFunctionsOutOfModule(Module *M, Module *BugDriver::ExtractMappedBlocksFromModule(const std::vector<BasicBlock*> &BBs, Module *M) { - sys::Path uniqueFilename(OutputPrefix + "-extractblocks"); - std::string ErrMsg; - if (uniqueFilename.createTemporaryFileOnDisk(true, &ErrMsg)) { + SmallString<128> Filename; + int FD; + error_code EC = sys::fs::createUniqueFile( + OutputPrefix + "-extractblocks%%%%%%%", FD, Filename); + if (EC) { outs() << "*** Basic Block extraction failed!\n"; - errs() << "Error creating temporary file: " << ErrMsg << "\n"; + errs() << "Error creating temporary file: " << EC.message() << "\n"; EmitProgressBitcode(M, "basicblockextractfail", true); return 0; } - sys::RemoveFileOnSignal(uniqueFilename); + sys::RemoveFileOnSignal(Filename); - std::string ErrorInfo; - tool_output_file BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo); - if (!ErrorInfo.empty()) { - outs() << "*** Basic Block extraction failed!\n"; - errs() << "Error writing list of blocks to not extract: " << ErrorInfo - << "\n"; - EmitProgressBitcode(M, "basicblockextractfail", true); - return 0; - } + tool_output_file BlocksToNotExtractFile(Filename.c_str(), FD); for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end(); I != E; ++I) { BasicBlock *BB = *I; @@ -393,22 +387,22 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const } BlocksToNotExtractFile.os().close(); if (BlocksToNotExtractFile.os().has_error()) { - errs() << "Error writing list of blocks to not extract: " << ErrorInfo - << "\n"; + errs() << "Error writing list of blocks to not extract\n"; EmitProgressBitcode(M, "basicblockextractfail", true); BlocksToNotExtractFile.os().clear_error(); return 0; } BlocksToNotExtractFile.keep(); - std::string uniqueFN = "--extract-blocks-file=" + uniqueFilename.str(); + std::string uniqueFN = "--extract-blocks-file="; + uniqueFN += Filename.str(); const char *ExtraArg = uniqueFN.c_str(); std::vector<std::string> PI; PI.push_back("extract-blocks"); Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg); - uniqueFilename.eraseFromDisk(); // Free disk space + sys::fs::remove(Filename.c_str()); if (Ret == 0) { outs() << "*** Basic Block extraction failed, please report a bug!\n"; diff --git a/tools/bugpoint/FindBugs.cpp b/tools/bugpoint/FindBugs.cpp index a291f9f..e2941f6 100644 --- a/tools/bugpoint/FindBugs.cpp +++ b/tools/bugpoint/FindBugs.cpp @@ -17,6 +17,7 @@ #include "BugDriver.h" #include "ToolRunner.h" #include "llvm/Pass.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <ctime> @@ -103,7 +104,7 @@ bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses, } outs() << "\n*** diff'd output matches!\n"; - sys::Path(Filename).eraseFromDisk(); + sys::fs::remove(Filename); outs() << "\n\n"; num++; diff --git a/tools/bugpoint/LLVMBuild.txt b/tools/bugpoint/LLVMBuild.txt index e03c594..0164355 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 IPO Instrumentation Linker Scalar ObjCARC +required_libraries = AsmParser BitReader BitWriter IRReader IPO Instrumentation Linker Scalar ObjCARC diff --git a/tools/bugpoint/Makefile b/tools/bugpoint/Makefile index 65ffc13..2049321 100644 --- a/tools/bugpoint/Makefile +++ b/tools/bugpoint/Makefile @@ -10,6 +10,6 @@ LEVEL := ../.. TOOLNAME := bugpoint LINK_COMPONENTS := asmparser instrumentation scalaropts ipo linker bitreader \ - bitwriter vectorize objcarcopts + bitwriter irreader vectorize objcarcopts include $(LEVEL)/Makefile.common diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index c676a05..771ec34 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -120,7 +120,7 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, return InternalError; if (Diff) { outs() << " nope.\n"; - sys::Path(BitcodeResult).eraseFromDisk(); + sys::fs::remove(BitcodeResult); return KeepPrefix; } outs() << " yup.\n"; // No miscompilation! @@ -130,12 +130,12 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, // OwningPtr<Module> PrefixOutput(ParseInputFile(BitcodeResult, BD.getContext())); - if (PrefixOutput == 0) { + if (!PrefixOutput) { errs() << BD.getToolName() << ": Error reading bitcode file '" << BitcodeResult << "'!\n"; exit(1); } - sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk + sys::fs::remove(BitcodeResult); // Don't check if there are no passes in the suffix. if (Suffix.empty()) @@ -337,8 +337,13 @@ static bool ExtractLoops(BugDriver &BD, false, Error, Failure); if (!New) return false; + // Delete the original and set the new program. - delete BD.swapProgramIn(New); + Module *Old = BD.swapProgramIn(New); + for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) + MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); + delete Old; + if (Failure) { BD.switchToInterpreter(AI); @@ -366,21 +371,51 @@ static bool ExtractLoops(BugDriver &BD, outs() << " Testing after loop extraction:\n"; // Clone modules, the tester function will free them. - Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted); - Module *TNOBackup = CloneModule(ToNotOptimize); + Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted, VMap); + Module *TNOBackup = CloneModule(ToNotOptimize, VMap); + + for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) + MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); + Failure = TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize, Error); if (!Error.empty()) return false; + + ToOptimizeLoopExtracted = TOLEBackup; + ToNotOptimize = TNOBackup; + if (!Failure) { outs() << "*** Loop extraction masked the problem. Undoing.\n"; // If the program is not still broken, then loop extraction did something // that masked the error. Stop loop extraction now. - delete TOLEBackup; - delete TNOBackup; + + std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions; + for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) { + Function *F = MiscompiledFunctions[i]; + MisCompFunctions.push_back(std::make_pair(F->getName(), + F->getFunctionType())); + } + + std::string ErrorMsg; + if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted, + Linker::DestroySource, &ErrorMsg)){ + errs() << BD.getToolName() << ": Error linking modules together:" + << ErrorMsg << '\n'; + exit(1); + } + + MiscompiledFunctions.clear(); + for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { + Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); + + assert(NewF && "Function not found??"); + MiscompiledFunctions.push_back(NewF); + } + + delete ToOptimizeLoopExtracted; + BD.setNewProgram(ToNotOptimize); return MadeChange; } - ToOptimizeLoopExtracted = TOLEBackup; - ToNotOptimize = TNOBackup; outs() << "*** Loop extraction successful!\n"; @@ -926,14 +961,16 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, std::string &Error) { CleanupAndPrepareModules(BD, Test, Safe); - sys::Path TestModuleBC("bugpoint.test.bc"); - std::string ErrMsg; - if (TestModuleBC.makeUnique(true, &ErrMsg)) { + SmallString<128> TestModuleBC; + int TestModuleFD; + error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc", + TestModuleFD, TestModuleBC); + if (EC) { errs() << BD.getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - if (BD.writeProgramToFile(TestModuleBC.str(), Test)) { + if (BD.writeProgramToFile(TestModuleBC.str(), TestModuleFD, Test)) { errs() << "Error writing bitcode to `" << TestModuleBC.str() << "'\nExiting."; exit(1); @@ -943,14 +980,17 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, FileRemover TestModuleBCRemover(TestModuleBC.str(), !SaveTemps); // Make the shared library - sys::Path SafeModuleBC("bugpoint.safe.bc"); - if (SafeModuleBC.makeUnique(true, &ErrMsg)) { + SmallString<128> SafeModuleBC; + int SafeModuleFD; + EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD, + SafeModuleBC); + if (EC) { errs() << BD.getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - if (BD.writeProgramToFile(SafeModuleBC.str(), Safe)) { + if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe)) { errs() << "Error writing bitcode to `" << SafeModuleBC.str() << "'\nExiting."; exit(1); @@ -1015,15 +1055,17 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { // Condition the modules CleanupAndPrepareModules(*this, ToCodeGen, ToNotCodeGen); - sys::Path TestModuleBC("bugpoint.test.bc"); - std::string ErrMsg; - if (TestModuleBC.makeUnique(true, &ErrMsg)) { + SmallString<128> TestModuleBC; + int TestModuleFD; + error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc", + TestModuleFD, TestModuleBC); + if (EC) { errs() << getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - if (writeProgramToFile(TestModuleBC.str(), ToCodeGen)) { + if (writeProgramToFile(TestModuleBC.str(), TestModuleFD, ToCodeGen)) { errs() << "Error writing bitcode to `" << TestModuleBC.str() << "'\nExiting."; exit(1); @@ -1031,14 +1073,17 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { delete ToCodeGen; // Make the shared library - sys::Path SafeModuleBC("bugpoint.safe.bc"); - if (SafeModuleBC.makeUnique(true, &ErrMsg)) { + SmallString<128> SafeModuleBC; + int SafeModuleFD; + EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD, + SafeModuleBC); + if (EC) { errs() << getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - if (writeProgramToFile(SafeModuleBC.str(), ToNotCodeGen)) { + if (writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, ToNotCodeGen)) { errs() << "Error writing bitcode to `" << SafeModuleBC.str() << "'\nExiting."; exit(1); diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index 87dc9f3..20c609c 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/PluginLoader.h" #include <fstream> + using namespace llvm; namespace llvm { @@ -43,25 +44,36 @@ namespace { // ChildOutput - This option captures the name of the child output file that // is set up by the parent bugpoint process cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden); + cl::opt<std::string> OptCmd("opt-command", cl::init(""), + cl::desc("Path to opt. (default: search path " + "for 'opt'.)")); } /// writeProgramToFile - This writes the current "Program" to the named bitcode /// file. If an error occurs, true is returned. /// +static bool writeProgramToFileAux(tool_output_file &Out, const Module *M) { + WriteBitcodeToFile(M, Out.os()); + Out.os().close(); + if (!Out.os().has_error()) { + Out.keep(); + return false; + } + return true; +} + +bool BugDriver::writeProgramToFile(const std::string &Filename, int FD, + const Module *M) const { + tool_output_file Out(Filename.c_str(), FD); + return writeProgramToFileAux(Out, M); +} + bool BugDriver::writeProgramToFile(const std::string &Filename, const Module *M) const { std::string ErrInfo; - tool_output_file Out(Filename.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); - if (ErrInfo.empty()) { - WriteBitcodeToFile(M, Out.os()); - Out.os().close(); - if (!Out.os().has_error()) { - Out.keep(); - return false; - } - } - Out.os().clear_error(); + tool_output_file Out(Filename.c_str(), ErrInfo, sys::fs::F_Binary); + if (ErrInfo.empty()) + return writeProgramToFileAux(Out, M); return true; } @@ -114,41 +126,38 @@ bool BugDriver::runPasses(Module *Program, const char * const *ExtraArgs) const { // setup the output file name outs().flush(); - sys::Path uniqueFilename(OutputPrefix + "-output.bc"); - std::string ErrMsg; - if (uniqueFilename.makeUnique(true, &ErrMsg)) { + SmallString<128> UniqueFilename; + error_code EC = sys::fs::createUniqueFile( + OutputPrefix + "-output-%%%%%%%.bc", UniqueFilename); + if (EC) { errs() << getToolName() << ": Error making unique filename: " - << ErrMsg << "\n"; - return(1); + << EC.message() << "\n"; + return 1; } - OutputFilename = uniqueFilename.str(); + OutputFilename = UniqueFilename.str(); // set up the input file name - sys::Path inputFilename(OutputPrefix + "-input.bc"); - if (inputFilename.makeUnique(true, &ErrMsg)) { + SmallString<128> InputFilename; + int InputFD; + EC = sys::fs::createUniqueFile(OutputPrefix + "-input-%%%%%%%.bc", InputFD, + InputFilename); + if (EC) { errs() << getToolName() << ": Error making unique filename: " - << ErrMsg << "\n"; - return(1); + << EC.message() << "\n"; + return 1; } - std::string ErrInfo; - tool_output_file InFile(inputFilename.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); - + tool_output_file InFile(InputFilename.c_str(), InputFD); - if (!ErrInfo.empty()) { - errs() << "Error opening bitcode file: " << inputFilename.str() << "\n"; - return 1; - } WriteBitcodeToFile(Program, InFile.os()); InFile.os().close(); if (InFile.os().has_error()) { - errs() << "Error writing bitcode file: " << inputFilename.str() << "\n"; + errs() << "Error writing bitcode file: " << InputFilename << "\n"; InFile.os().clear_error(); return 1; } - sys::Path tool = sys::Program::FindProgramByName("opt"); + std::string tool = OptCmd.empty()? sys::FindProgramByName("opt") : OptCmd; if (tool.empty()) { errs() << "Cannot find `opt' in PATH!\n"; return 1; @@ -159,14 +168,13 @@ bool BugDriver::runPasses(Module *Program, // setup the child process' arguments SmallVector<const char*, 8> Args; - std::string Opt = tool.str(); if (UseValgrind) { Args.push_back("valgrind"); Args.push_back("--error-exitcode=1"); Args.push_back("-q"); Args.push_back(tool.c_str()); } else - Args.push_back(Opt.c_str()); + Args.push_back(tool.c_str()); Args.push_back("-o"); Args.push_back(OutputFilename.c_str()); @@ -183,7 +191,7 @@ bool BugDriver::runPasses(Module *Program, for (std::vector<std::string>::const_iterator I = pass_args.begin(), E = pass_args.end(); I != E; ++I ) Args.push_back(I->c_str()); - Args.push_back(inputFilename.c_str()); + Args.push_back(InputFilename.c_str()); for (unsigned i = 0; i < NumExtraArgs; ++i) Args.push_back(*ExtraArgs); Args.push_back(0); @@ -194,27 +202,28 @@ bool BugDriver::runPasses(Module *Program, errs() << "\n"; ); - sys::Path prog; + std::string Prog; if (UseValgrind) - prog = sys::Program::FindProgramByName("valgrind"); + Prog = sys::FindProgramByName("valgrind"); else - prog = tool; + Prog = tool; // Redirect stdout and stderr to nowhere if SilencePasses is given - sys::Path Nowhere; - const sys::Path *Redirects[3] = {0, &Nowhere, &Nowhere}; + StringRef Nowhere; + const StringRef *Redirects[3] = {0, &Nowhere, &Nowhere}; - int result = sys::Program::ExecuteAndWait(prog, Args.data(), 0, - (SilencePasses ? Redirects : 0), - Timeout, MemoryLimit, &ErrMsg); + std::string ErrMsg; + int result = sys::ExecuteAndWait(Prog, Args.data(), 0, + (SilencePasses ? Redirects : 0), Timeout, + MemoryLimit, &ErrMsg); // If we are supposed to delete the bitcode file or if the passes crashed, // remove it now. This may fail if the file was never created, but that's ok. if (DeleteOutput || result != 0) - sys::Path(OutputFilename).eraseFromDisk(); + sys::fs::remove(OutputFilename); // Remove the temporary input file as well - inputFilename.eraseFromDisk(); + sys::fs::remove(InputFilename.c_str()); if (!Quiet) { if (result == 0) @@ -262,6 +271,6 @@ Module *BugDriver::runPassesOn(Module *M, << BitcodeResult << "'!\n"; exit(1); } - sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk + sys::fs::remove(BitcodeResult); return Ret; } diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 735061d..107d0db 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -16,6 +16,7 @@ #include "llvm/Config/config.h" // for HAVE_LINK_R #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" @@ -53,18 +54,15 @@ namespace { /// RunProgramWithTimeout - This function provides an alternate interface /// to the sys::Program::ExecuteAndWait interface. /// @see sys::Program::ExecuteAndWait -static int RunProgramWithTimeout(const sys::Path &ProgramPath, +static int RunProgramWithTimeout(StringRef ProgramPath, const char **Args, - const sys::Path &StdInFile, - const sys::Path &StdOutFile, - const sys::Path &StdErrFile, + StringRef StdInFile, + StringRef StdOutFile, + StringRef StdErrFile, unsigned NumSeconds = 0, unsigned MemoryLimit = 0, std::string *ErrMsg = 0) { - const sys::Path* redirects[3]; - redirects[0] = &StdInFile; - redirects[1] = &StdOutFile; - redirects[2] = &StdErrFile; + const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile }; #if 0 // For debug purposes { @@ -75,9 +73,8 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath, } #endif - return - sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, - NumSeconds, MemoryLimit, ErrMsg); + return sys::ExecuteAndWait(ProgramPath, Args, 0, Redirects, + NumSeconds, MemoryLimit, ErrMsg); } /// RunProgramRemotelyWithTimeout - This function runs the given program @@ -86,17 +83,14 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath, /// fails. Remote client is required to return 255 if it failed or program exit /// code otherwise. /// @see sys::Program::ExecuteAndWait -static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, +static int RunProgramRemotelyWithTimeout(StringRef RemoteClientPath, const char **Args, - const sys::Path &StdInFile, - const sys::Path &StdOutFile, - const sys::Path &StdErrFile, + StringRef StdInFile, + StringRef StdOutFile, + StringRef StdErrFile, unsigned NumSeconds = 0, unsigned MemoryLimit = 0) { - const sys::Path* redirects[3]; - redirects[0] = &StdInFile; - redirects[1] = &StdOutFile; - redirects[2] = &StdErrFile; + const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile }; #if 0 // For debug purposes { @@ -108,8 +102,8 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, #endif // Run the program remotely with the remote client - int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args, - 0, redirects, NumSeconds, MemoryLimit); + int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, 0, + Redirects, NumSeconds, MemoryLimit); // Has the remote client fail? if (255 == ReturnCode) { @@ -120,7 +114,8 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, OS << "\n"; // The error message is in the output file, let's print it out from there. - std::ifstream ErrorFile(StdOutFile.c_str()); + std::string StdOutFileName = StdOutFile.str(); + std::ifstream ErrorFile(StdOutFileName.c_str()); if (ErrorFile) { std::copy(std::istreambuf_iterator<char>(ErrorFile), std::istreambuf_iterator<char>(), @@ -134,7 +129,7 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, return ReturnCode; } -static std::string ProcessFailure(sys::Path ProgPath, const char** Args, +static std::string ProcessFailure(StringRef ProgPath, const char** Args, unsigned Timeout = 0, unsigned MemoryLimit = 0) { std::ostringstream OS; @@ -144,14 +139,16 @@ static std::string ProcessFailure(sys::Path ProgPath, const char** Args, OS << "\n"; // Rerun the compiler, capturing any error messages to print them. - sys::Path ErrorFilename("bugpoint.program_error_messages"); - std::string ErrMsg; - if (ErrorFilename.makeUnique(true, &ErrMsg)) { - errs() << "Error making unique filename: " << ErrMsg << "\n"; + SmallString<128> ErrorFilename; + int ErrorFD; + error_code EC = sys::fs::createTemporaryFile( + "bugpoint.program_error_messages", "", ErrorFD, ErrorFilename); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } - RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename, - ErrorFilename, Timeout, MemoryLimit); + RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(), + ErrorFilename.str(), Timeout, MemoryLimit); // FIXME: check return code ? // Print out the error messages generated by GCC if possible... @@ -163,7 +160,7 @@ static std::string ProcessFailure(sys::Path ProgPath, const char** Args, ErrorFile.close(); } - ErrorFilename.eraseFromDisk(); + sys::fs::remove(ErrorFilename.c_str()); return OS.str(); } @@ -229,19 +226,50 @@ int LLI::ExecuteProgram(const std::string &Bitcode, errs() << " " << LLIArgs[i]; errs() << "\n"; ); - return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0], - sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), + return RunProgramWithTimeout(LLIPath, &LLIArgs[0], + InputFile, OutputFile, OutputFile, Timeout, MemoryLimit, Error); } void AbstractInterpreter::anchor() { } +#if defined(LLVM_ON_UNIX) +const char EXESuffix[] = ""; +#elif defined (LLVM_ON_WIN32) +const char EXESuffix[] = "exe"; +#endif + +/// Prepend the path to the program being executed +/// to \p ExeName, given the value of argv[0] and the address of main() +/// itself. This allows us to find another LLVM tool if it is built in the same +/// directory. An empty string is returned on error; note that this function +/// just mainpulates the path and doesn't check for executability. +/// @brief Find a named executable. +static std::string PrependMainExecutablePath(const std::string &ExeName, + const char *Argv0, + void *MainAddr) { + // Check the directory that the calling program is in. We can do + // this if ProgramPath contains at least one / character, indicating that it + // is a relative path to the executable itself. + std::string Main = sys::fs::getMainExecutable(Argv0, MainAddr); + StringRef Result = sys::path::parent_path(Main); + + if (!Result.empty()) { + SmallString<128> Storage = Result; + sys::path::append(Storage, ExeName); + sys::path::replace_extension(Storage, EXESuffix); + return Storage.str(); + } + + return Result.str(); +} + // LLI create method - Try to find the LLI executable AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0, std::string &Message, const std::vector<std::string> *ToolArgs) { std::string LLIPath = - PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createLLI).str(); + PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t) & createLLI); if (!LLIPath.empty()) { Message = "Found lli: " + LLIPath + "\n"; return new LLI(LLIPath, ToolArgs); @@ -305,10 +333,10 @@ void CustomCompiler::compileProgram(const std::string &Bitcode, for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i) ProgramArgs.push_back(CompilerArgs[i].c_str()); - if (RunProgramWithTimeout( sys::Path(CompilerCommand), &ProgramArgs[0], - sys::Path(), sys::Path(), sys::Path(), + if (RunProgramWithTimeout(CompilerCommand, &ProgramArgs[0], + "", "", "", Timeout, MemoryLimit, Error)) - *Error = ProcessFailure(sys::Path(CompilerCommand), &ProgramArgs[0], + *Error = ProcessFailure(CompilerCommand, &ProgramArgs[0], Timeout, MemoryLimit); } @@ -363,9 +391,9 @@ int CustomExecutor::ExecuteProgram(const std::string &Bitcode, ProgramArgs.push_back(Args[i].c_str()); return RunProgramWithTimeout( - sys::Path(ExecutionCommand), - &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), - sys::Path(OutputFile), Timeout, MemoryLimit, Error); + ExecutionCommand, + &ProgramArgs[0], InputFile, OutputFile, + OutputFile, Timeout, MemoryLimit, Error); } // Tokenize the CommandLine to the command and the args to allow @@ -398,7 +426,7 @@ static void lexCommand(std::string &Message, const std::string &CommandLine, pos = CommandLine.find_first_of(delimiters, lastPos); } - CmdPath = sys::Program::FindProgramByName(Command).str(); + CmdPath = sys::FindProgramByName(Command); if (CmdPath.empty()) { Message = std::string("Cannot find '") + Command + @@ -444,16 +472,18 @@ AbstractInterpreter *AbstractInterpreter::createCustomExecutor( // LLC Implementation of AbstractIntepreter interface // GCC::FileType LLC::OutputCode(const std::string &Bitcode, - sys::Path &OutputAsmFile, std::string &Error, + std::string &OutputAsmFile, std::string &Error, unsigned Timeout, unsigned MemoryLimit) { const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); - sys::Path uniqueFile(Bitcode + Suffix); - std::string ErrMsg; - if (uniqueFile.makeUnique(true, &ErrMsg)) { - errs() << "Error making unique filename: " << ErrMsg << "\n"; + + SmallString<128> UniqueFile; + error_code EC = + sys::fs::createUniqueFile(Bitcode + "-%%%%%%%" + Suffix, UniqueFile); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } - OutputAsmFile = uniqueFile; + OutputAsmFile = UniqueFile.str(); std::vector<const char *> LLCArgs; LLCArgs.push_back(LLCPath.c_str()); @@ -477,19 +507,19 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, errs() << " " << LLCArgs[i]; errs() << "\n"; ); - if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0], - sys::Path(), sys::Path(), sys::Path(), + if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], + "", "", "", Timeout, MemoryLimit)) - Error = ProcessFailure(sys::Path(LLCPath), &LLCArgs[0], + Error = ProcessFailure(LLCPath, &LLCArgs[0], Timeout, MemoryLimit); return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; } void LLC::compileProgram(const std::string &Bitcode, std::string *Error, unsigned Timeout, unsigned MemoryLimit) { - sys::Path OutputAsmFile; + std::string OutputAsmFile; OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit); - OutputAsmFile.eraseFromDisk(); + sys::fs::remove(OutputAsmFile); } int LLC::ExecuteProgram(const std::string &Bitcode, @@ -502,16 +532,16 @@ int LLC::ExecuteProgram(const std::string &Bitcode, unsigned Timeout, unsigned MemoryLimit) { - sys::Path OutputAsmFile; + std::string OutputAsmFile; GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit); - FileRemover OutFileRemover(OutputAsmFile.str(), !SaveTemps); + FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); std::vector<std::string> GCCArgs(ArgsForGCC); GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); // Assuming LLC worked, compile the result with GCC and run it. - return gcc->ExecuteProgram(OutputAsmFile.str(), Args, FileKind, + return gcc->ExecuteProgram(OutputAsmFile, Args, FileKind, InputFile, OutputFile, Error, GCCArgs, Timeout, MemoryLimit); } @@ -525,7 +555,7 @@ LLC *AbstractInterpreter::createLLC(const char *Argv0, const std::vector<std::string> *GCCArgs, bool UseIntegratedAssembler) { std::string LLCPath = - PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t)&createLLC).str(); + PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t) & createLLC); if (LLCPath.empty()) { Message = "Cannot find `llc' in executable directory!\n"; return 0; @@ -603,8 +633,8 @@ int JIT::ExecuteProgram(const std::string &Bitcode, errs() << "\n"; ); DEBUG(errs() << "\nSending output to " << OutputFile << "\n"); - return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0], - sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), + return RunProgramWithTimeout(LLIPath, &JITArgs[0], + InputFile, OutputFile, OutputFile, Timeout, MemoryLimit, Error); } @@ -613,7 +643,7 @@ int JIT::ExecuteProgram(const std::string &Bitcode, AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0, std::string &Message, const std::vector<std::string> *Args) { std::string LLIPath = - PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createJIT).str(); + PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t) & createJIT); if (!LLIPath.empty()) { Message = "Found lli: " + LLIPath + "\n"; return new JIT(LLIPath, Args); @@ -682,10 +712,12 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, GCCArgs.push_back("-x"); GCCArgs.push_back("none"); GCCArgs.push_back("-o"); - sys::Path OutputBinary (ProgramFile+".gcc.exe"); - std::string ErrMsg; - if (OutputBinary.makeUnique(true, &ErrMsg)) { - errs() << "Error making unique filename: " << ErrMsg << "\n"; + + SmallString<128> OutputBinary; + error_code EC = + sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.gcc.exe", OutputBinary); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file... @@ -712,8 +744,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, errs() << " " << GCCArgs[i]; errs() << "\n"; ); - if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), - sys::Path())) { + if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "", "", "")) { *Error = ProcessFailure(GCCPath, &GCCArgs[0]); return -1; } @@ -724,7 +755,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, // ProgramArgs is used. std::string Exec; - if (RemoteClientPath.isEmpty()) + if (RemoteClientPath.empty()) ProgramArgs.push_back(OutputBinary.c_str()); else { ProgramArgs.push_back(RemoteClientPath.c_str()); @@ -766,11 +797,11 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps); - if (RemoteClientPath.isEmpty()) { + if (RemoteClientPath.empty()) { DEBUG(errs() << "<run locally>"); - int ExitCode = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], - sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), - Timeout, MemoryLimit, Error); + int ExitCode = RunProgramWithTimeout(OutputBinary.str(), &ProgramArgs[0], + InputFile, OutputFile, OutputFile, + Timeout, MemoryLimit, Error); // Treat a signal (usually SIGSEGV) or timeout as part of the program output // so that crash-causing miscompilation is handled seamlessly. if (ExitCode < -1) { @@ -782,9 +813,9 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, return ExitCode; } else { outs() << "<run remotely>"; outs().flush(); - return RunProgramRemotelyWithTimeout(sys::Path(RemoteClientPath), - &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), - sys::Path(OutputFile), Timeout, MemoryLimit); + return RunProgramRemotelyWithTimeout(RemoteClientPath, + &ProgramArgs[0], InputFile, OutputFile, + OutputFile, Timeout, MemoryLimit); } } @@ -792,13 +823,14 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, std::string &OutputFile, const std::vector<std::string> &ArgsForGCC, std::string &Error) { - sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT); - std::string ErrMsg; - if (uniqueFilename.makeUnique(true, &ErrMsg)) { - errs() << "Error making unique filename: " << ErrMsg << "\n"; + SmallString<128> UniqueFilename; + error_code EC = sys::fs::createUniqueFile( + InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } - OutputFile = uniqueFilename.str(); + OutputFile = UniqueFilename.str(); std::vector<const char*> GCCArgs; @@ -862,8 +894,7 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, errs() << " " << GCCArgs[i]; errs() << "\n"; ); - if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), - sys::Path())) { + if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "", "", "")) { Error = ProcessFailure(GCCPath, &GCCArgs[0]); return 1; } @@ -875,16 +906,16 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, GCC *GCC::create(std::string &Message, const std::string &GCCBinary, const std::vector<std::string> *Args) { - sys::Path GCCPath = sys::Program::FindProgramByName(GCCBinary); - if (GCCPath.isEmpty()) { + std::string GCCPath = sys::FindProgramByName(GCCBinary); + if (GCCPath.empty()) { Message = "Cannot find `"+ GCCBinary +"' in PATH!\n"; return 0; } - sys::Path RemoteClientPath; + std::string RemoteClientPath; if (!RemoteClient.empty()) - RemoteClientPath = sys::Program::FindProgramByName(RemoteClient); + RemoteClientPath = sys::FindProgramByName(RemoteClient); - Message = "Found gcc: " + GCCPath.str() + "\n"; + Message = "Found gcc: " + GCCPath + "\n"; return new GCC(GCCPath, RemoteClientPath, Args); } diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h index bb83ce4..bc2be46 100644 --- a/tools/bugpoint/ToolRunner.h +++ b/tools/bugpoint/ToolRunner.h @@ -30,17 +30,16 @@ namespace llvm { extern cl::opt<bool> SaveTemps; extern Triple TargetTriple; -class CBE; class LLC; //===---------------------------------------------------------------------===// // GCC abstraction // class GCC { - sys::Path GCCPath; // The path to the gcc executable. - sys::Path RemoteClientPath; // The path to the rsh / ssh executable. + std::string GCCPath; // The path to the gcc executable. + std::string RemoteClientPath; // The path to the rsh / ssh executable. std::vector<std::string> gccArgs; // GCC-specific arguments. - GCC(const sys::Path &gccPath, const sys::Path &RemotePath, + GCC(StringRef gccPath, StringRef RemotePath, const std::vector<std::string> *GCCArgs) : GCCPath(gccPath), RemoteClientPath(RemotePath) { if (GCCArgs) gccArgs = *GCCArgs; @@ -88,10 +87,6 @@ public: class AbstractInterpreter { virtual void anchor(); public: - static CBE *createCBE(const char *Argv0, std::string &Message, - const std::string &GCCBinary, - const std::vector<std::string> *Args = 0, - const std::vector<std::string> *GCCArgs = 0); static LLC *createLLC(const char *Argv0, std::string &Message, const std::string &GCCBinary, const std::vector<std::string> *Args = 0, @@ -126,7 +121,7 @@ public: /// fails, it sets Error, otherwise, this function returns the type of code /// emitted. virtual GCC::FileType OutputCode(const std::string &Bitcode, - sys::Path &OutFile, std::string &Error, + std::string &OutFile, std::string &Error, unsigned Timeout = 0, unsigned MemoryLimit = 0) { Error = "OutputCode not supported by this AbstractInterpreter!"; @@ -152,51 +147,6 @@ public: }; //===---------------------------------------------------------------------===// -// CBE Implementation of AbstractIntepreter interface -// -class CBE : public AbstractInterpreter { - sys::Path LLCPath; // The path to the `llc' executable. - std::vector<std::string> ToolArgs; // Extra args to pass to LLC. - GCC *gcc; -public: - CBE(const sys::Path &llcPath, GCC *Gcc, - const std::vector<std::string> *Args) - : LLCPath(llcPath), gcc(Gcc) { - ToolArgs.clear (); - if (Args) ToolArgs = *Args; - } - ~CBE() { delete gcc; } - - /// 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); - - 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); - - /// 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, - sys::Path &OutFile, std::string &Error, - unsigned Timeout = 0, - unsigned MemoryLimit = 0); -}; - - -//===---------------------------------------------------------------------===// // LLC Implementation of AbstractIntepreter interface // class LLC : public AbstractInterpreter { @@ -238,7 +188,7 @@ public: /// fails, it sets Error, otherwise, this function returns the type of code /// emitted. virtual GCC::FileType OutputCode(const std::string &Bitcode, - sys::Path &OutFile, std::string &Error, + std::string &OutFile, std::string &Error, unsigned Timeout = 0, unsigned MemoryLimit = 0); }; diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 40f5fd6..7771709 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -17,6 +17,7 @@ #include "llvm-c/lto.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/Errno.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -64,7 +65,7 @@ namespace { lto_codegen_model output_type = LTO_CODEGEN_PIC_MODEL_STATIC; std::string output_name = ""; std::list<claimed_file> Modules; - std::vector<sys::Path> Cleanup; + std::vector<std::string> Cleanup; lto_code_gen_t code_gen = NULL; } @@ -251,9 +252,8 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, if (file->offset) { offset = file->offset; } - if (error_code ec = - MemoryBuffer::getOpenFile(file->fd, file->name, buffer, file->filesize, - -1, offset, false)) { + if (error_code ec = MemoryBuffer::getOpenFileSlice( + file->fd, file->name, buffer, file->filesize, offset)) { (*message)(LDPL_ERROR, ec.message().c_str()); return LDPS_ERR; } @@ -447,18 +447,18 @@ static ld_plugin_status all_symbols_read_hook(void) { } if (options::obj_path.empty()) - Cleanup.push_back(sys::Path(objPath)); + Cleanup.push_back(objPath); return LDPS_OK; } static ld_plugin_status cleanup_hook(void) { - std::string ErrMsg; - - for (int i = 0, e = Cleanup.size(); i != e; ++i) - if (Cleanup[i].eraseFromDisk(false, &ErrMsg)) + for (int i = 0, e = Cleanup.size(); i != e; ++i) { + error_code EC = sys::fs::remove(Cleanup[i]); + if (EC) (*message)(LDPL_ERROR, "Failed to delete '%s': %s", Cleanup[i].c_str(), - ErrMsg.c_str()); + EC.message().c_str()); + } return LDPS_OK; } diff --git a/tools/llc/Android.mk b/tools/llc/Android.mk index c141f8a..bc19e9b 100644 --- a/tools/llc/Android.mk +++ b/tools/llc/Android.mk @@ -36,6 +36,7 @@ llvm_llc_arm_STATIC_LIBRARIES := \ llvm_llc_STATIC_LIBRARIES := \ libLLVMAsmPrinter \ + libLLVMIRReader \ libLLVMAsmParser \ libLLVMBitReader \ libLLVMBitWriter \ @@ -43,6 +44,7 @@ llvm_llc_STATIC_LIBRARIES := \ libLLVMInstCombine \ libLLVMInstrumentation \ libLLVMCodeGen \ + libLLVMObject \ libLLVMipo \ libLLVMipa \ libLLVMLinker \ diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt index 683f298..e5a5550 100644 --- a/tools/llc/CMakeLists.txt +++ b/tools/llc/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser irreader) add_llvm_tool(llc llc.cpp diff --git a/tools/llc/LLVMBuild.txt b/tools/llc/LLVMBuild.txt index 8c8794f..45cdc64 100644 --- a/tools/llc/LLVMBuild.txt +++ b/tools/llc/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llc parent = Tools -required_libraries = AsmParser BitReader all-targets +required_libraries = AsmParser BitReader IRReader all-targets diff --git a/tools/llc/Makefile b/tools/llc/Makefile index b32d557..c24f378 100644 --- a/tools/llc/Makefile +++ b/tools/llc/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llc -LINK_COMPONENTS := all-targets bitreader asmparser +LINK_COMPONENTS := all-targets bitreader asmparser irreader include $(LEVEL)/Makefile.common diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index aa65223..6aac8ff 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// + #include "llvm/IR/LLVMContext.h" #include "llvm/ADT/Triple.h" #include "llvm/Assembly/PrintModulePass.h" @@ -21,6 +22,7 @@ #include "llvm/CodeGen/LinkAllCodegenComponents.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Pass.h" #include "llvm/PassManager.h" @@ -28,11 +30,11 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" @@ -143,8 +145,9 @@ static tool_output_file *GetOutputStream(const char *TargetName, // Open the file. std::string error; - unsigned OpenFlags = 0; - if (Binary) OpenFlags |= raw_fd_ostream::F_Binary; + sys::fs::OpenFlags OpenFlags = sys::fs::F_None; + if (Binary) + OpenFlags |= sys::fs::F_Binary; tool_output_file *FDOut = new tool_output_file(OutputFilename.c_str(), error, OpenFlags); if (!error.empty()) { @@ -199,7 +202,7 @@ int main(int argc, char **argv) { static int compileModule(char **argv, LLVMContext &Context) { // Load the module to be compiled... SMDiagnostic Err; - std::auto_ptr<Module> M; + OwningPtr<Module> M; Module *mod = 0; Triple TheTriple; @@ -259,7 +262,6 @@ static int compileModule(char **argv, LLVMContext &Context) { TargetOptions Options; Options.LessPreciseFPMADOption = EnableFPMAD; Options.NoFramePointerElim = DisableFPElim; - Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf; Options.AllowFPOpFusion = FuseFPOps; Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; @@ -273,14 +275,12 @@ static int compileModule(char **argv, LLVMContext &Context) { Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.DisableTailCalls = DisableTailCalls; Options.StackAlignmentOverride = OverrideStackAlignment; - Options.RealignStack = EnableRealignStack; Options.TrapFuncName = TrapFuncName; Options.PositionIndependentExecutable = EnablePIE; Options.EnableSegmentedStacks = SegmentedStacks; Options.UseInitArray = UseInitArray; - Options.SSPBufferSize = SSPBufferSize; - std::auto_ptr<TargetMachine> + OwningPtr<TargetMachine> target(TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, FeaturesStr, Options, RelocModel, CMModel, OLvl)); diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt index 356233f..98f411d 100644 --- a/tools/lli/CMakeLists.txt +++ b/tools/lli/CMakeLists.txt @@ -1,5 +1,5 @@ -set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser selectiondag native) +set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native instrumentation) if( LLVM_USE_OPROFILE ) set(LLVM_LINK_COMPONENTS diff --git a/tools/lli/LLVMBuild.txt b/tools/lli/LLVMBuild.txt index 36ceb39..c96a9e8 100644 --- a/tools/lli/LLVMBuild.txt +++ b/tools/lli/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = lli parent = Tools -required_libraries = AsmParser BitReader Interpreter JIT MCJIT NativeCodeGen SelectionDAG Native +required_libraries = AsmParser BitReader IRReader Instrumentation Interpreter JIT MCJIT NativeCodeGen SelectionDAG Native diff --git a/tools/lli/Makefile b/tools/lli/Makefile index 85ac6b4..7a40427 100644 --- a/tools/lli/Makefile +++ b/tools/lli/Makefile @@ -12,7 +12,7 @@ TOOLNAME := lli include $(LEVEL)/Makefile.config -LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser selectiondag native +LINK_COMPONENTS := mcjit jit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native # If Intel JIT Events support is confiured, link against the LLVM Intel JIT # Events interface library diff --git a/tools/lli/RecordingMemoryManager.cpp b/tools/lli/RecordingMemoryManager.cpp index e4d992d..1fa8176 100644 --- a/tools/lli/RecordingMemoryManager.cpp +++ b/tools/lli/RecordingMemoryManager.cpp @@ -98,17 +98,6 @@ uint8_t *RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignme void RecordingMemoryManager::deallocateFunctionBody(void *Body) { llvm_unreachable("Unexpected!"); } -uint8_t* RecordingMemoryManager::startExceptionTable(const Function* F, uintptr_t &ActualSize) { - llvm_unreachable("Unexpected!"); - return 0; -} -void RecordingMemoryManager::endExceptionTable(const Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister) { - llvm_unreachable("Unexpected!"); -} -void RecordingMemoryManager::deallocateExceptionTable(void *ET) { - llvm_unreachable("Unexpected!"); -} static int jit_noop() { return 0; diff --git a/tools/lli/RecordingMemoryManager.h b/tools/lli/RecordingMemoryManager.h index 991f535..b2919c3 100644 --- a/tools/lli/RecordingMemoryManager.h +++ b/tools/lli/RecordingMemoryManager.h @@ -58,7 +58,7 @@ public: void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true); - bool applyPermissions(std::string *ErrMsg) { return false; } + bool finalizeMemory(std::string *ErrMsg) { return false; } // The following obsolete JITMemoryManager calls are stubbed out for // this model. @@ -75,11 +75,6 @@ public: uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); void deallocateFunctionBody(void *Body); - uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize); - void endExceptionTable(const Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister); - void deallocateExceptionTable(void *ET); - }; } // end namespace llvm diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 332660f..8d74b23 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -29,11 +29,11 @@ #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Format.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Memory.h" @@ -42,8 +42,10 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Instrumentation.h" #include <cerrno> #ifdef __CYGWIN__ @@ -70,6 +72,10 @@ namespace { "use-mcjit", cl::desc("Enable use of the MC-based JIT (if available)"), cl::init(false)); + cl::opt<bool> DebugIR( + "debug-ir", cl::desc("Generate debug information to allow debugging IR."), + cl::init(false)); + // The MCJIT supports building for a target address space separate from // the JIT compilation process. Use a forked process and a copying // memory manager with IPC to execute using this functionality. @@ -158,11 +164,6 @@ namespace { clEnumValEnd)); cl::opt<bool> - EnableJITExceptionHandling("jit-enable-eh", - cl::desc("Emit exception handling information"), - cl::init(false)); - - cl::opt<bool> GenerateSoftFloatCalls("soft-float", cl::desc("Generate software floating point library calls"), cl::init(false)); @@ -258,7 +259,7 @@ void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) { EE->mapSectionAddress(const_cast<void*>(Offsets[i].first), Addr); DEBUG(dbgs() << " Mapping local: " << Offsets[i].first - << " to remote: " << format("%p", Addr) << "\n"); + << " to remote: 0x" << format("%llx", Addr) << "\n"); } @@ -273,12 +274,12 @@ void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) { T->loadCode(Addr, Offsets[i].first, Sizes[i]); DEBUG(dbgs() << " loading code: " << Offsets[i].first - << " to remote: " << format("%p", Addr) << "\n"); + << " to remote: 0x" << format("%llx", Addr) << "\n"); } else { T->loadData(Addr, Offsets[i].first, Sizes[i]); DEBUG(dbgs() << " loading data: " << Offsets[i].first - << " to remote: " << format("%p", Addr) << "\n"); + << " to remote: 0x" << format("%llx", Addr) << "\n"); } } @@ -325,6 +326,17 @@ int main(int argc, char **argv, char * const *envp) { } } + if (DebugIR) { + if (!UseMCJIT) { + errs() << "warning: -debug-ir used without -use-mcjit. Only partial debug" + << " information will be emitted by the non-MC JIT engine. To see full" + << " source debug information, enable the flag '-use-mcjit'.\n"; + + } + ModulePass *DebugIRPass = createDebugIRPass(); + DebugIRPass->runOnModule(*Mod); + } + EngineBuilder builder(Mod); builder.setMArch(MArch); builder.setMCPU(MCPU); @@ -341,14 +353,14 @@ int main(int argc, char **argv, char * const *envp) { Mod->setTargetTriple(Triple::normalize(TargetTriple)); // Enable MCJIT if desired. - JITMemoryManager *JMM = 0; + RTDyldMemoryManager *RTDyldMM = 0; if (UseMCJIT && !ForceInterpreter) { builder.setUseMCJIT(true); if (RemoteMCJIT) - JMM = new RecordingMemoryManager(); + RTDyldMM = new RecordingMemoryManager(); else - JMM = new SectionMemoryManager(); - builder.setJITMemoryManager(JMM); + RTDyldMM = new SectionMemoryManager(); + builder.setMCJITMemoryManager(RTDyldMM); } else { if (RemoteMCJIT) { errs() << "error: Remote process execution requires -use-mcjit\n"; @@ -380,7 +392,6 @@ int main(int argc, char **argv, char * const *envp) { // Remote target execution doesn't handle EH or debug registration. if (!RemoteMCJIT) { - Options.JITExceptionHandling = EnableJITExceptionHandling; Options.JITEmitDebugInfo = EmitJitDebugInfo; Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk; } @@ -466,7 +477,7 @@ int main(int argc, char **argv, char * const *envp) { int Result; if (RemoteMCJIT) { - RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(JMM); + RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(RTDyldMM); // Everything is prepared now, so lay out our program for the target // address space, assign the section addresses to resolve any relocations, // and send it to the target. @@ -488,8 +499,8 @@ int main(int argc, char **argv, char * const *envp) { // FIXME: argv and envp handling. uint64_t Entry = (uint64_t)EE->getPointerToFunction(EntryFn); - DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at " - << format("%p", Entry) << "\n"); + DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x" + << format("%llx", Entry) << "\n"); if (Target.executeCode(Entry, Result)) errs() << "ERROR: " << Target.getErrorMsg() << "\n"; @@ -500,8 +511,8 @@ int main(int argc, char **argv, char * const *envp) { // invalidated will be known. (void)EE->getPointerToFunction(EntryFn); // Clear instruction cache before code will be executed. - if (JMM) - static_cast<SectionMemoryManager*>(JMM)->invalidateInstructionCache(); + if (RTDyldMM) + static_cast<SectionMemoryManager*>(RTDyldMM)->invalidateInstructionCache(); // Run main. Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp); diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index 70eb760..503999c 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS archive) +set(LLVM_LINK_COMPONENTS support object bitreader) add_llvm_tool(llvm-ar llvm-ar.cpp diff --git a/tools/llvm-ar/LLVMBuild.txt b/tools/llvm-ar/LLVMBuild.txt index 1f61a32..236b465 100644 --- a/tools/llvm-ar/LLVMBuild.txt +++ b/tools/llvm-ar/LLVMBuild.txt @@ -19,4 +19,3 @@ type = Tool name = llvm-ar parent = Tools -required_libraries = Archive diff --git a/tools/llvm-ar/Makefile b/tools/llvm-ar/Makefile index fafb14b..15fb090 100644 --- a/tools/llvm-ar/Makefile +++ b/tools/llvm-ar/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-ar -LINK_COMPONENTS := archive +LINK_COMPONENTS := bitreader support object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 86eb8e2..6026fa7 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -13,21 +13,56 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" -#include "llvm/Bitcode/Archive.h" #include "llvm/IR/Module.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstdlib> -#include <fstream> #include <memory> + +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif + using namespace llvm; +// The name this program was invoked as. +static StringRef ToolName; + +static const char *TemporaryOutput; +static int TmpArchiveFD = -1; + +// fail - Show the error message and exit. +LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { + outs() << ToolName << ": " << Error << ".\n"; + if (TmpArchiveFD != -1) + close(TmpArchiveFD); + if (TemporaryOutput) + sys::fs::remove(TemporaryOutput); + exit(1); +} + +static void failIfError(error_code EC, Twine Context = "") { + if (!EC) + return; + + std::string ContextStr = Context.str(); + if (ContextStr == "") + fail(EC.message()); + fail(Context + ": " + EC.message()); +} + // Option for compatibility with AIX, not used but must allow it to be present. static cl::opt<bool> X32Option ("X32_64", cl::Hidden, @@ -57,123 +92,72 @@ static cl::extrahelp MoreHelp( "\nMODIFIERS (operation specific):\n" " [a] - put file(s) after [relpos]\n" " [b] - put file(s) before [relpos] (same as [i])\n" - " [f] - truncate inserted file names\n" " [i] - put file(s) before [relpos] (same as [b])\n" - " [k] - always print bitcode files (default is to skip them)\n" " [N] - use instance [count] of name\n" " [o] - preserve original dates\n" - " [P] - use full path names when matching\n" - " [R] - recurse through directories when inserting\n" " [s] - create an archive index (cf. ranlib)\n" " [S] - do not build a symbol table\n" " [u] - update only files newer than archive contents\n" "\nMODIFIERS (generic):\n" " [c] - do not warn if the library had to be created\n" " [v] - be verbose about actions taken\n" - " [V] - be *really* verbose about actions taken\n" ); // This enumeration delineates the kinds of operations on an archive // that are permitted. enum ArchiveOperation { - NoOperation, ///< An operation hasn't been specified Print, ///< Print the contents of the archive Delete, ///< Delete the specified members Move, ///< Move members to end or as given by {a,b,i} modifiers QuickAppend, ///< Quickly append to end of archive ReplaceOrInsert, ///< Replace or Insert members DisplayTable, ///< Display the table of contents - Extract ///< Extract files back to file system + Extract, ///< Extract files back to file system + CreateSymTab ///< Create a symbol table in an existing archive }; // Modifiers to follow operation to vary behavior -bool AddAfter = false; ///< 'a' modifier -bool AddBefore = false; ///< 'b' modifier -bool Create = false; ///< 'c' modifier -bool TruncateNames = false; ///< 'f' modifier -bool InsertBefore = false; ///< 'i' modifier -bool DontSkipBitcode = false; ///< 'k' modifier -bool UseCount = false; ///< 'N' modifier -bool OriginalDates = false; ///< 'o' modifier -bool FullPath = false; ///< 'P' modifier -bool RecurseDirectories = false; ///< 'R' modifier -bool SymTable = true; ///< 's' & 'S' modifiers -bool OnlyUpdate = false; ///< 'u' modifier -bool Verbose = false; ///< 'v' modifier -bool ReallyVerbose = false; ///< 'V' modifier +static bool AddAfter = false; ///< 'a' modifier +static bool AddBefore = false; ///< 'b' modifier +static bool Create = false; ///< 'c' modifier +static bool OriginalDates = false; ///< 'o' modifier +static bool OnlyUpdate = false; ///< 'u' modifier +static bool Verbose = false; ///< 'v' modifier +static bool Symtab = true; ///< 's' modifier // Relative Positional Argument (for insert/move). This variable holds // the name of the archive member to which the 'a', 'b' or 'i' modifier // refers. Only one of 'a', 'b' or 'i' can be specified so we only need // one variable. -std::string RelPos; - -// Select which of multiple entries in the archive with the same name should be -// used (specified with -N) for the delete and extract operations. -int Count = 1; +static std::string RelPos; // This variable holds the name of the archive file as given on the // command line. -std::string ArchiveName; +static std::string ArchiveName; // This variable holds the list of member files to proecess, as given // on the command line. -std::vector<std::string> Members; - -// This variable holds the (possibly expanded) list of path objects that -// correspond to files we will -std::set<sys::Path> Paths; - -// The Archive object to which all the editing operations will be sent. -Archive* TheArchive = 0; - -// The name this program was invoked as. -static const char *program_name; +static std::vector<std::string> Members; // show_help - Show the error message, the help message and exit. LLVM_ATTRIBUTE_NORETURN static void show_help(const std::string &msg) { - errs() << program_name << ": " << msg << "\n\n"; + errs() << ToolName << ": " << msg << "\n\n"; cl::PrintHelpMessage(); - if (TheArchive) - delete TheArchive; - std::exit(1); -} - -// fail - Show the error message and exit. -LLVM_ATTRIBUTE_NORETURN static void -fail(const std::string &msg) { - errs() << program_name << ": " << msg << "\n\n"; - if (TheArchive) - delete TheArchive; std::exit(1); } // getRelPos - Extract the member filename from the command line for // the [relpos] argument associated with a, b, and i modifiers -void getRelPos() { +static void getRelPos() { if(RestOfArgs.size() == 0) show_help("Expected [relpos] for a, b, or i modifier"); RelPos = RestOfArgs[0]; RestOfArgs.erase(RestOfArgs.begin()); } -// getCount - Extract the [count] argument associated with the N modifier -// from the command line and check its value. -void getCount() { - if(RestOfArgs.size() == 0) - show_help("Expected [count] value with N modifier"); - - Count = atoi(RestOfArgs[0].c_str()); - RestOfArgs.erase(RestOfArgs.begin()); - - // Non-positive counts are not allowed - if (Count < 1) - show_help("Invalid [count] value (not a positive integer)"); -} - // getArchive - Get the archive file name from the command line -void getArchive() { +static void getArchive() { if(RestOfArgs.size() == 0) show_help("An archive name must be specified"); ArchiveName = RestOfArgs[0]; @@ -182,7 +166,7 @@ void getArchive() { // getMembers - Copy over remaining items in RestOfArgs to our Members vector // This is just for clarity. -void getMembers() { +static void getMembers() { if(RestOfArgs.size() > 0) Members = std::vector<std::string>(RestOfArgs); } @@ -190,7 +174,7 @@ void getMembers() { // parseCommandLine - Parse the command line options as presented and return the // operation specified. Process all modifiers and check to make sure that // constraints on modifier/operation pairs have not been violated. -ArchiveOperation parseCommandLine() { +static ArchiveOperation parseCommandLine() { // Keep track of number of operations. We can only specify one // per execution. @@ -201,7 +185,9 @@ ArchiveOperation parseCommandLine() { unsigned NumPositional = 0; // Keep track of which operation was requested - ArchiveOperation Operation = NoOperation; + ArchiveOperation Operation; + + bool MaybeJustCreateSymTab = false; for(unsigned i=0; i<Options.size(); ++i) { switch(Options[i]) { @@ -213,17 +199,17 @@ ArchiveOperation parseCommandLine() { case 't': ++NumOperations; Operation = DisplayTable; break; case 'x': ++NumOperations; Operation = Extract; break; case 'c': Create = true; break; - case 'f': TruncateNames = true; break; - case 'k': DontSkipBitcode = true; break; case 'l': /* accepted but unused */ break; case 'o': OriginalDates = true; break; - case 'P': FullPath = true; break; - case 'R': RecurseDirectories = true; break; - case 's': SymTable = true; break; - case 'S': SymTable = false; break; + case 's': + Symtab = true; + MaybeJustCreateSymTab = true; + break; + case 'S': + Symtab = false; + break; case 'u': OnlyUpdate = true; break; case 'v': Verbose = true; break; - case 'V': Verbose = ReallyVerbose = true; break; case 'a': getRelPos(); AddAfter = true; @@ -236,13 +222,9 @@ ArchiveOperation parseCommandLine() { break; case 'i': getRelPos(); - InsertBefore = true; + AddBefore = true; NumPositional++; break; - case 'N': - getCount(); - UseCount = true; - break; default: cl::PrintHelpMessage(); } @@ -255,6 +237,13 @@ ArchiveOperation parseCommandLine() { // Everything on the command line at this point is a member. getMembers(); + if (NumOperations == 0 && MaybeJustCreateSymTab) { + NumOperations = 1; + Operation = CreateSymTab; + if (!Members.empty()) + show_help("The s operation takes only an archive as argument"); + } + // Perform various checks on the operation/modifier specification // to make sure we are dealing with a legal request. if (NumOperations == 0) @@ -263,140 +252,33 @@ ArchiveOperation parseCommandLine() { show_help("Only one operation may be specified"); if (NumPositional > 1) show_help("You may only specify one of a, b, and i modifiers"); - if (AddAfter || AddBefore || InsertBefore) { + if (AddAfter || AddBefore) { if (Operation != Move && Operation != ReplaceOrInsert) show_help("The 'a', 'b' and 'i' modifiers can only be specified with " "the 'm' or 'r' operations"); } - if (RecurseDirectories && Operation != ReplaceOrInsert) - show_help("The 'R' modifiers is only applicabe to the 'r' operation"); if (OriginalDates && Operation != Extract) show_help("The 'o' modifier is only applicable to the 'x' operation"); - if (TruncateNames && Operation!=QuickAppend && Operation!=ReplaceOrInsert) - show_help("The 'f' modifier is only applicable to the 'q' and 'r' " - "operations"); if (OnlyUpdate && Operation != ReplaceOrInsert) show_help("The 'u' modifier is only applicable to the 'r' operation"); - if (Count > 1 && Members.size() > 1) - show_help("Only one member name may be specified with the 'N' modifier"); // Return the parsed operation to the caller return Operation; } -// recurseDirectories - Implements the "R" modifier. This function scans through -// the Paths vector (built by buildPaths, below) and replaces any directories it -// finds with all the files in that directory (recursively). It uses the -// sys::Path::getDirectoryContent method to perform the actual directory scans. -bool -recurseDirectories(const sys::Path& path, - std::set<sys::Path>& result, std::string* ErrMsg) { - result.clear(); - if (RecurseDirectories) { - std::set<sys::Path> content; - if (path.getDirectoryContents(content, ErrMsg)) - return true; - - for (std::set<sys::Path>::iterator I = content.begin(), E = content.end(); - I != E; ++I) { - // Make sure it exists and is a directory - sys::PathWithStatus PwS(*I); - const sys::FileStatus *Status = PwS.getFileStatus(false, ErrMsg); - if (!Status) - return true; - if (Status->isDir) { - std::set<sys::Path> moreResults; - if (recurseDirectories(*I, moreResults, ErrMsg)) - return true; - result.insert(moreResults.begin(), moreResults.end()); - } else { - result.insert(*I); - } - } - } - return false; -} +// Implements the 'p' operation. This function traverses the archive +// looking for members that match the path list. +static void doPrint(StringRef Name, object::Archive::child_iterator I) { + if (Verbose) + outs() << "Printing " << Name << "\n"; -// buildPaths - Convert the strings in the Members vector to sys::Path objects -// and make sure they are valid and exist exist. This check is only needed for -// the operations that add/replace files to the archive ('q' and 'r') -bool buildPaths(bool checkExistence, std::string* ErrMsg) { - for (unsigned i = 0; i < Members.size(); i++) { - sys::Path aPath; - if (!aPath.set(Members[i])) - fail(std::string("File member name invalid: ") + Members[i]); - if (checkExistence) { - bool Exists; - if (sys::fs::exists(aPath.str(), Exists) || !Exists) - fail(std::string("File does not exist: ") + Members[i]); - std::string Err; - sys::PathWithStatus PwS(aPath); - const sys::FileStatus *si = PwS.getFileStatus(false, &Err); - if (!si) - fail(Err); - if (si->isDir) { - std::set<sys::Path> dirpaths; - if (recurseDirectories(aPath, dirpaths, ErrMsg)) - return true; - Paths.insert(dirpaths.begin(),dirpaths.end()); - } else { - Paths.insert(aPath); - } - } else { - Paths.insert(aPath); - } - } - return false; -} - -// printSymbolTable - print out the archive's symbol table. -void printSymbolTable() { - outs() << "\nArchive Symbol Table:\n"; - const Archive::SymTabType& symtab = TheArchive->getSymbolTable(); - for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end(); - I != E; ++I ) { - unsigned offset = TheArchive->getFirstFileOffset() + I->second; - outs() << " " << format("%9u", offset) << "\t" << I->first <<"\n"; - } -} - -// doPrint - Implements the 'p' operation. This function traverses the archive -// looking for members that match the path list. It is careful to uncompress -// things that should be and to skip bitcode files unless the 'k' modifier was -// given. -bool doPrint(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; - unsigned countDown = Count; - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E; ++I ) { - if (Paths.empty() || - (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) { - if (countDown == 1) { - const char* data = reinterpret_cast<const char*>(I->getData()); - - // Skip things that don't make sense to print - if (I->isLLVMSymbolTable() || I->isSVR4SymbolTable() || - I->isBSD4SymbolTable() || (!DontSkipBitcode && I->isBitcode())) - continue; - - if (Verbose) - outs() << "Printing " << I->getPath().str() << "\n"; - - unsigned len = I->getSize(); - outs().write(data, len); - } else { - countDown--; - } - } - } - return false; + StringRef Data = I->getBuffer(); + outs().write(Data.data(), Data.size()); } // putMode - utility function for printing out the file mode when the 't' // operation is in verbose mode. -void -printMode(unsigned mode) { +static void printMode(unsigned mode) { if (mode & 004) outs() << "r"; else @@ -411,303 +293,576 @@ printMode(unsigned mode) { outs() << "-"; } -// doDisplayTable - Implement the 't' operation. This function prints out just +// Implement the 't' operation. This function prints out just // the file names of each of the members. However, if verbose mode is requested // ('v' modifier) then the file type, permission mode, user, group, size, and // modification time are also printed. -bool -doDisplayTable(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E; ++I ) { - if (Paths.empty() || - (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) { - if (Verbose) { - // FIXME: Output should be this format: - // Zrw-r--r-- 500/ 500 525 Nov 8 17:42 2004 Makefile - if (I->isBitcode()) - outs() << "b"; - else - outs() << " "; - unsigned mode = I->getMode(); - printMode((mode >> 6) & 007); - printMode((mode >> 3) & 007); - printMode(mode & 007); - outs() << " " << format("%4u", I->getUser()); - outs() << "/" << format("%4u", I->getGroup()); - outs() << " " << format("%8u", I->getSize()); - outs() << " " << format("%20s", I->getModTime().str().substr(4).c_str()); - outs() << " " << I->getPath().str() << "\n"; - } else { - outs() << I->getPath().str() << "\n"; - } - } +static void doDisplayTable(StringRef Name, object::Archive::child_iterator I) { + if (Verbose) { + sys::fs::perms Mode = I->getAccessMode(); + printMode((Mode >> 6) & 007); + printMode((Mode >> 3) & 007); + printMode(Mode & 007); + outs() << ' ' << I->getUID(); + outs() << '/' << I->getGID(); + outs() << ' ' << format("%6llu", I->getSize()); + outs() << ' ' << I->getLastModified().str(); + outs() << ' '; } - if (ReallyVerbose) - printSymbolTable(); - return false; + outs() << Name << "\n"; } -// doExtract - Implement the 'x' operation. This function extracts files back to -// the file system. -bool -doExtract(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E; ++I ) { - if (Paths.empty() || - (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) { - - // Make sure the intervening directories are created - if (I->hasPath()) { - sys::Path dirs(I->getPath()); - dirs.eraseComponent(); - if (dirs.createDirectoryOnDisk(/*create_parents=*/true, ErrMsg)) - return true; - } +// Implement the 'x' operation. This function extracts files back to the file +// system. +static void doExtract(StringRef Name, object::Archive::child_iterator I) { + // Retain the original mode. + sys::fs::perms Mode = I->getAccessMode(); + SmallString<128> Storage = Name; - // Open up a file stream for writing - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - std::ofstream file(I->getPath().c_str(), io_mode); + int FD; + failIfError( + sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_Binary, Mode), + Storage.c_str()); - // Get the data and its length - const char* data = reinterpret_cast<const char*>(I->getData()); - unsigned len = I->getSize(); + { + raw_fd_ostream file(FD, false); - // Write the data. - file.write(data,len); - file.close(); + // Get the data and its length + StringRef Data = I->getBuffer(); - // If we're supposed to retain the original modification times, etc. do so - // now. - if (OriginalDates) - I->getPath().setStatusInfoOnDisk(I->getFileStatus()); - } + // Write the data. + file.write(Data.data(), Data.size()); } - return false; + + // If we're supposed to retain the original modification times, etc. do so + // now. + if (OriginalDates) + failIfError( + sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified())); + + if (close(FD)) + fail("Could not close the file"); } -// doDelete - Implement the delete operation. This function deletes zero or more -// members from the archive. Note that if the count is specified, there should -// be no more than one path in the Paths list or else this algorithm breaks. -// That check is enforced in parseCommandLine (above). -bool -doDelete(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; - if (Paths.empty()) +static bool shouldCreateArchive(ArchiveOperation Op) { + switch (Op) { + case Print: + case Delete: + case Move: + case DisplayTable: + case Extract: + case CreateSymTab: return false; - unsigned countDown = Count; - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E; ) { - if (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end()) { - if (countDown == 1) { - Archive::iterator J = I; - ++I; - TheArchive->erase(J); - } else - countDown--; - } else { - ++I; + + case QuickAppend: + case ReplaceOrInsert: + return true; + } + + llvm_unreachable("Missing entry in covered switch."); +} + +static void performReadOperation(ArchiveOperation Operation, + object::Archive *OldArchive) { + for (object::Archive::child_iterator I = OldArchive->begin_children(), + E = OldArchive->end_children(); + I != E; ++I) { + StringRef Name; + failIfError(I->getName(Name)); + + if (!Members.empty() && + std::find(Members.begin(), Members.end(), Name) == Members.end()) + continue; + + switch (Operation) { + default: + llvm_unreachable("Not a read operation"); + case Print: + doPrint(Name, I); + break; + case DisplayTable: + doDisplayTable(Name, I); + break; + case Extract: + doExtract(Name, I); + break; } } +} - // We're done editting, reconstruct the archive. - if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg)) - return true; - if (ReallyVerbose) - printSymbolTable(); - return false; +namespace { +class NewArchiveIterator { + bool IsNewMember; + StringRef Name; + object::Archive::child_iterator OldI; + std::string NewFilename; + +public: + NewArchiveIterator(object::Archive::child_iterator I, StringRef Name); + NewArchiveIterator(std::string *I, StringRef Name); + NewArchiveIterator(); + bool isNewMember() const; + object::Archive::child_iterator getOld() const; + const char *getNew() const; + StringRef getName() const; +}; } -// doMore - Implement the move operation. This function re-arranges just the -// order of the archive members so that when the archive is written the move -// of the members is accomplished. Note the use of the RelPos variable to -// determine where the items should be moved to. -bool -doMove(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; +NewArchiveIterator::NewArchiveIterator() {} + +NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, + StringRef Name) + : IsNewMember(false), Name(Name), OldI(I) {} + +NewArchiveIterator::NewArchiveIterator(std::string *NewFilename, StringRef Name) + : IsNewMember(true), Name(Name), NewFilename(*NewFilename) {} + +StringRef NewArchiveIterator::getName() const { return Name; } + +bool NewArchiveIterator::isNewMember() const { return IsNewMember; } + +object::Archive::child_iterator NewArchiveIterator::getOld() const { + assert(!IsNewMember); + return OldI; +} + +const char *NewArchiveIterator::getNew() const { + assert(IsNewMember); + return NewFilename.c_str(); +} - // By default and convention the place to move members to is the end of the - // archive. - Archive::iterator moveto_spot = TheArchive->end(); - - // However, if the relative positioning modifiers were used, we need to scan - // the archive to find the member in question. If we don't find it, its no - // crime, we just move to the end. - if (AddBefore || InsertBefore || AddAfter) { - for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end(); - I != E; ++I ) { - if (RelPos == I->getPath().str()) { - if (AddAfter) { - moveto_spot = I; - moveto_spot++; - } else { - moveto_spot = I; - } +template <typename T> +void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name, + int Pos = -1) { + NewArchiveIterator NI(I, Name); + if (Pos == -1) + Members.push_back(NI); + else + 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, + IA_Delete, + IA_MoveOldMember, + IA_MoveNewMember +}; + +static InsertAction +computeInsertAction(ArchiveOperation Operation, + object::Archive::child_iterator I, StringRef Name, + std::vector<std::string>::iterator &Pos) { + if (Operation == QuickAppend || Members.empty()) + return IA_AddOldMember; + + std::vector<std::string>::iterator MI = + std::find_if(Members.begin(), Members.end(), HasName(Name)); + + if (MI == Members.end()) + return IA_AddOldMember; + + Pos = MI; + + if (Operation == Delete) + return IA_Delete; + + if (Operation == Move) + return IA_MoveOldMember; + + if (Operation == ReplaceOrInsert) { + StringRef PosName = sys::path::filename(RelPos); + if (!OnlyUpdate) { + if (PosName.empty()) + return IA_AddNewMeber; + return IA_MoveNewMember; + } + + // We could try to optimize this to a fstat, but it is not a common + // operation. + sys::fs::file_status Status; + failIfError(sys::fs::status(*MI, Status)); + if (Status.getLastModificationTime() < I->getLastModified()) { + if (PosName.empty()) + return IA_AddOldMember; + return IA_MoveOldMember; + } + + if (PosName.empty()) + return IA_AddNewMeber; + return IA_MoveNewMember; + } + llvm_unreachable("No such operation"); +} + +// We have to walk this twice and computing it is not trivial, so creating an +// explicit std::vector is actually fairly efficient. +static std::vector<NewArchiveIterator> +computeNewArchiveMembers(ArchiveOperation Operation, + object::Archive *OldArchive) { + std::vector<NewArchiveIterator> Ret; + std::vector<NewArchiveIterator> Moved; + int InsertPos = -1; + StringRef PosName = sys::path::filename(RelPos); + if (OldArchive) { + for (object::Archive::child_iterator I = OldArchive->begin_children(), + E = OldArchive->end_children(); + I != E; ++I) { + int Pos = Ret.size(); + StringRef Name; + failIfError(I->getName(Name)); + if (Name == PosName) { + assert(AddAfter || AddBefore); + if (AddBefore) + InsertPos = Pos; + else + InsertPos = Pos + 1; + } + + std::vector<std::string>::iterator MemberI = Members.end(); + InsertAction Action = computeInsertAction(Operation, I, Name, MemberI); + switch (Action) { + case IA_AddOldMember: + addMember(Ret, I, Name); + break; + case IA_AddNewMeber: + addMember(Ret, &*MemberI, Name); + break; + case IA_Delete: + break; + case IA_MoveOldMember: + addMember(Moved, I, Name); + break; + case IA_MoveNewMember: + addMember(Moved, &*MemberI, Name); break; } + if (MemberI != Members.end()) + Members.erase(MemberI); } } - // Keep a list of the paths remaining to be moved - std::set<sys::Path> remaining(Paths); - - // Scan the archive again, this time looking for the members to move to the - // moveto_spot. - for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end(); - I != E && !remaining.empty(); ++I ) { - std::set<sys::Path>::iterator found = - std::find(remaining.begin(),remaining.end(),I->getPath()); - if (found != remaining.end()) { - if (I != moveto_spot) - TheArchive->splice(moveto_spot,*TheArchive,I); - remaining.erase(found); - } + if (Operation == Delete) + return Ret; + + if (!RelPos.empty() && InsertPos == -1) + fail("Insertion point not found"); + + if (RelPos.empty()) + InsertPos = Ret.size(); + + assert(unsigned(InsertPos) <= Ret.size()); + Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end()); + + Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator()); + int Pos = InsertPos; + for (std::vector<std::string>::iterator I = Members.begin(), + E = Members.end(); + I != E; ++I, ++Pos) { + StringRef Name = sys::path::filename(*I); + addMember(Ret, &*I, Name, Pos); } - // We're done editting, reconstruct the archive. - if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg)) - return true; - if (ReallyVerbose) - printSymbolTable(); - return false; + return Ret; } -// doQuickAppend - Implements the 'q' operation. This function just -// indiscriminantly adds the members to the archive and rebuilds it. -bool -doQuickAppend(std::string* ErrMsg) { - // Get the list of paths to append. - if (buildPaths(true, ErrMsg)) - return true; - if (Paths.empty()) - return false; +template <typename T> +static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { + 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 << ' '; +} - // Append them quickly. - for (std::set<sys::Path>::iterator PI = Paths.begin(), PE = Paths.end(); - PI != PE; ++PI) { - if (TheArchive->addFileBefore(*PI,TheArchive->end(),ErrMsg)) - return true; +static void print32BE(raw_fd_ostream &Out, unsigned Val) { + for (int I = 3; I >= 0; --I) { + char V = (Val >> (8 * I)) & 0xff; + Out << V; } +} - // We're done editting, reconstruct the archive. - if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg)) - return true; - if (ReallyVerbose) - printSymbolTable(); - return false; +static void printRestOfMemberHeader(raw_fd_ostream &Out, + const sys::TimeValue &ModTime, unsigned UID, + unsigned GID, unsigned Perms, + unsigned Size) { + printWithSpacePadding(Out, ModTime.toEpochTime(), 12); + printWithSpacePadding(Out, UID, 6); + printWithSpacePadding(Out, GID, 6); + printWithSpacePadding(Out, format("%o", Perms), 8); + printWithSpacePadding(Out, Size, 10); + Out << "`\n"; } -// doReplaceOrInsert - Implements the 'r' operation. This function will replace -// any existing files or insert new ones into the archive. -bool -doReplaceOrInsert(std::string* ErrMsg) { +static void printMemberHeader(raw_fd_ostream &Out, StringRef Name, + const sys::TimeValue &ModTime, unsigned UID, + unsigned GID, unsigned Perms, unsigned Size) { + printWithSpacePadding(Out, Twine(Name) + "/", 16); + printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); +} - // Build the list of files to be added/replaced. - if (buildPaths(true, ErrMsg)) - return true; - if (Paths.empty()) - return false; +static void printMemberHeader(raw_fd_ostream &Out, unsigned NameOffset, + const sys::TimeValue &ModTime, unsigned UID, + unsigned GID, unsigned Perms, unsigned Size) { + Out << '/'; + printWithSpacePadding(Out, NameOffset, 15); + printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); +} - // Keep track of the paths that remain to be inserted. - std::set<sys::Path> remaining(Paths); - - // Default the insertion spot to the end of the archive - Archive::iterator insert_spot = TheArchive->end(); - - // Iterate over the archive contents - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E && !remaining.empty(); ++I ) { - - // Determine if this archive member matches one of the paths we're trying - // to replace. - - std::set<sys::Path>::iterator found = remaining.end(); - for (std::set<sys::Path>::iterator RI = remaining.begin(), - RE = remaining.end(); RI != RE; ++RI ) { - std::string compare(RI->str()); - if (TruncateNames && compare.length() > 15) { - const char* nm = compare.c_str(); - unsigned len = compare.length(); - size_t slashpos = compare.rfind('/'); - if (slashpos != std::string::npos) { - nm += slashpos + 1; - len -= slashpos +1; - } - if (len > 15) - len = 15; - compare.assign(nm,len); - } - if (compare == I->getPath().str()) { - found = RI; - break; - } +static void writeStringTable(raw_fd_ostream &Out, + ArrayRef<NewArchiveIterator> Members, + std::vector<unsigned> &StringMapIndexes) { + unsigned StartOffset = 0; + for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), + E = Members.end(); + I != E; ++I) { + StringRef Name = I->getName(); + if (Name.size() < 16) + continue; + if (StartOffset == 0) { + printWithSpacePadding(Out, "//", 58); + Out << "`\n"; + StartOffset = Out.tell(); } + StringMapIndexes.push_back(Out.tell() - StartOffset); + Out << Name << "/\n"; + } + if (StartOffset == 0) + return; + if (Out.tell() % 2) + Out << '\n'; + int Pos = Out.tell(); + Out.seek(StartOffset - 12); + printWithSpacePadding(Out, Pos - StartOffset, 10); + Out.seek(Pos); +} - if (found != remaining.end()) { - std::string Err; - sys::PathWithStatus PwS(*found); - const sys::FileStatus *si = PwS.getFileStatus(false, &Err); - if (!si) - return true; - if (!si->isDir) { - if (OnlyUpdate) { - // Replace the item only if it is newer. - if (si->modTime > I->getModTime()) - if (I->replaceWith(*found, ErrMsg)) - return true; - } else { - // Replace the item regardless of time stamp - if (I->replaceWith(*found, ErrMsg)) - return true; - } +static void writeSymbolTable( + raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, + std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { + unsigned StartOffset = 0; + unsigned MemberNum = 0; + std::vector<StringRef> SymNames; + std::vector<object::ObjectFile *> DeleteIt; + 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 { - // We purposefully ignore directories. + Obj = dyn_cast<object::ObjectFile>(Binary.get()); + if (Obj) + Binary.take(); } - - // Remove it from our "to do" list - remaining.erase(found); + } + if (!Obj) + continue; + DeleteIt.push_back(Obj); + if (!StartOffset) { + printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); + StartOffset = Out.tell(); + print32BE(Out, 0); } - // Determine if this is the place where we should insert - if ((AddBefore || InsertBefore) && RelPos == I->getPath().str()) - insert_spot = I; - else if (AddAfter && RelPos == I->getPath().str()) { - insert_spot = I; - insert_spot++; + 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)); + 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); + 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'; + } + + for (std::vector<object::ObjectFile *>::iterator I = DeleteIt.begin(), + E = DeleteIt.end(); + I != E; ++I) { + object::ObjectFile *O = *I; + delete O; + } + + if (StartOffset == 0) + return; + + if (Out.tell() % 2) + Out << '\0'; + + unsigned Pos = Out.tell(); + Out.seek(StartOffset - 12); + printWithSpacePadding(Out, Pos - StartOffset, 10); + Out.seek(StartOffset); + print32BE(Out, SymNames.size()); + Out.seek(Pos); +} + +static void performWriteOperation(ArchiveOperation Operation, + object::Archive *OldArchive) { + SmallString<128> TmpArchive; + failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", + TmpArchiveFD, TmpArchive)); + + TemporaryOutput = TmpArchive.c_str(); + tool_output_file Output(TemporaryOutput, TmpArchiveFD); + raw_fd_ostream &Out = Output.os(); + Out << "!<arch>\n"; + + std::vector<NewArchiveIterator> NewMembers = + computeNewArchiveMembers(Operation, OldArchive); + + std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs; + + if (Symtab) { + writeSymbolTable(Out, NewMembers, MemberOffsetRefs); + } + + std::vector<unsigned> StringMapIndexes; + writeStringTable(Out, NewMembers, StringMapIndexes); + + std::vector<std::pair<unsigned, unsigned> >::iterator MemberRefsI = + MemberOffsetRefs.begin(); - // If we didn't replace all the members, some will remain and need to be - // inserted at the previously computed insert-spot. - if (!remaining.empty()) { - for (std::set<sys::Path>::iterator PI = remaining.begin(), - PE = remaining.end(); PI != PE; ++PI) { - if (TheArchive->addFileBefore(*PI,insert_spot, ErrMsg)) - return true; + unsigned MemberNum = 0; + unsigned LongNameMemberNum = 0; + for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(), + E = NewMembers.end(); + I != E; ++I, ++MemberNum) { + + unsigned Pos = Out.tell(); + while (MemberRefsI != MemberOffsetRefs.end() && + MemberRefsI->second == MemberNum) { + Out.seek(MemberRefsI->first); + print32BE(Out, Pos); + ++MemberRefsI; + } + Out.seek(Pos); + + 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); + + OwningPtr<MemoryBuffer> File; + failIfError(MemoryBuffer::getOpenFile(FD, FileName, File, + Status.getSize(), false), + FileName); + + StringRef Name = sys::path::filename(FileName); + if (Name.size() < 16) + printMemberHeader(Out, Name, Status.getLastModificationTime(), + Status.getUser(), Status.getGroup(), + Status.permissions(), Status.getSize()); + else + printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], + 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(); + + if (Name.size() < 16) + printMemberHeader(Out, Name, OldMember->getLastModified(), + OldMember->getUID(), OldMember->getGID(), + OldMember->getAccessMode(), OldMember->getSize()); + else + printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], + OldMember->getLastModified(), OldMember->getUID(), + OldMember->getGID(), OldMember->getAccessMode(), + OldMember->getSize()); + Out << OldMember->getBuffer(); } + + if (Out.tell() % 2) + Out << '\n'; } + Output.keep(); + Out.close(); + sys::fs::rename(TemporaryOutput, ArchiveName); + TemporaryOutput = NULL; +} - // We're done editting, reconstruct the archive. - if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg)) - return true; - if (ReallyVerbose) - printSymbolTable(); - return false; +static void createSymbolTable(object::Archive *OldArchive) { + // When an archive is created or modified, if the s option is given, the + // resulting archive will have a current symbol table. If the S option + // is given, it will have no symbol table. + // In summary, we only need to update the symbol table if we have none. + // This is actually very common because of broken build systems that think + // they have to run ranlib. + if (OldArchive->hasSymbolTable()) + return; + + performWriteOperation(CreateSymTab, OldArchive); +} + +static void performOperation(ArchiveOperation Operation, + object::Archive *OldArchive) { + switch (Operation) { + case Print: + case DisplayTable: + case Extract: + performReadOperation(Operation, OldArchive); + return; + + case Delete: + case Move: + case QuickAppend: + case ReplaceOrInsert: + performWriteOperation(Operation, OldArchive); + return; + case CreateSymTab: + createSymbolTable(OldArchive); + return; + } + llvm_unreachable("Unknown operation."); } // main - main program for llvm-ar .. see comments in the code int main(int argc, char **argv) { - program_name = argv[0]; + ToolName = argv[0]; // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. // Have the command line options parsed and handle things @@ -717,63 +872,42 @@ int main(int argc, char **argv) { " This program archives bitcode files into single libraries\n" ); - int exitCode = 0; - // Do our own parsing of the command line because the CommandLine utility // can't handle the grouped positional parameters without a dash. ArchiveOperation Operation = parseCommandLine(); - // Check the path name of the archive - sys::Path ArchivePath; - if (!ArchivePath.set(ArchiveName)) { - errs() << argv[0] << ": Archive name invalid: " << ArchiveName << "\n"; + // Create or open the archive object. + OwningPtr<MemoryBuffer> Buf; + error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); + if (EC && EC != llvm::errc::no_such_file_or_directory) { + errs() << argv[0] << ": error opening '" << ArchiveName + << "': " << EC.message() << "!\n"; return 1; } - // Create or open the archive object. - bool Exists; - if (llvm::sys::fs::exists(ArchivePath.str(), Exists) || !Exists) { - // Produce a warning if we should and we're creating the archive - if (!Create) - errs() << argv[0] << ": creating " << ArchivePath.str() << "\n"; - TheArchive = Archive::CreateEmpty(ArchivePath, Context); - TheArchive->writeToDisk(); - } else { - std::string Error; - TheArchive = Archive::OpenAndLoad(ArchivePath, Context, &Error); - if (TheArchive == 0) { - errs() << argv[0] << ": error loading '" << ArchivePath.str() << "': " - << Error << "!\n"; + if (!EC) { + object::Archive Archive(Buf.take(), EC); + + if (EC) { + errs() << argv[0] << ": error loading '" << ArchiveName + << "': " << EC.message() << "!\n"; return 1; } + performOperation(Operation, &Archive); + return 0; } - // Make sure we're not fooling ourselves. - assert(TheArchive && "Unable to instantiate the archive"); + assert(EC == llvm::errc::no_such_file_or_directory); - // Perform the operation - std::string ErrMsg; - bool haveError = false; - switch (Operation) { - case Print: haveError = doPrint(&ErrMsg); break; - case Delete: haveError = doDelete(&ErrMsg); break; - case Move: haveError = doMove(&ErrMsg); break; - case QuickAppend: haveError = doQuickAppend(&ErrMsg); break; - case ReplaceOrInsert: haveError = doReplaceOrInsert(&ErrMsg); break; - case DisplayTable: haveError = doDisplayTable(&ErrMsg); break; - case Extract: haveError = doExtract(&ErrMsg); break; - case NoOperation: - errs() << argv[0] << ": No operation was selected.\n"; - break; - } - if (haveError) { - errs() << argv[0] << ": " << ErrMsg << "\n"; - return 1; + if (!shouldCreateArchive(Operation)) { + failIfError(EC, Twine("error loading '") + ArchiveName + "'"); + } else { + if (!Create) { + // Produce a warning if we should and we're creating the archive + errs() << argv[0] << ": creating " << ArchiveName << "\n"; + } } - delete TheArchive; - TheArchive = 0; - - // Return result code back to operating system. - return exitCode; + performOperation(Operation, NULL); + return 0; } diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp index 273c427..b2e44ef 100644 --- a/tools/llvm-as/llvm-as.cpp +++ b/tools/llvm-as/llvm-as.cpp @@ -69,9 +69,8 @@ static void WriteOutputFile(const Module *M) { } std::string ErrorInfo; - OwningPtr<tool_output_file> Out - (new tool_output_file(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + OwningPtr<tool_output_file> Out(new tool_output_file( + OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; exit(1); @@ -94,7 +93,7 @@ int main(int argc, char **argv) { // Parse the file now... SMDiagnostic Err; - std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context)); + OwningPtr<Module> M(ParseAssemblyFile(InputFilename, Err, Context)); if (M.get() == 0) { Err.print(argv[0], errs()); return 1; diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 99479a4..186eea9 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -481,7 +481,7 @@ static int AnalyzeBitcode() { OwningPtr<MemoryBuffer> MemBuf; if (error_code ec = - MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), MemBuf)) + MemoryBuffer::getFileOrSTDIN(InputFilename, MemBuf)) return Error("Error reading '" + InputFilename + "': " + ec.message()); if (MemBuf->getBufferSize() & 3) diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp index 7edf5ec..3924e2e 100644 --- a/tools/llvm-config/llvm-config.cpp +++ b/tools/llvm-config/llvm-config.cpp @@ -161,11 +161,11 @@ Typical components:\n\ } /// \brief Compute the path to the main executable. -llvm::sys::Path GetExecutablePath(const char *Argv0) { +std::string GetExecutablePath(const char *Argv0) { // This just needs to be some symbol in the binary; C++ doesn't // allow taking the address of ::main however. void *P = (void*) (intptr_t) GetExecutablePath; - return llvm::sys::Path::GetMainExecutable(Argv0, P); + return llvm::sys::fs::getMainExecutable(Argv0, P); } int main(int argc, char **argv) { @@ -179,7 +179,7 @@ int main(int argc, char **argv) { // tree. bool IsInDevelopmentTree; enum { MakefileStyle, CMakeStyle, CMakeBuildModeStyle } DevelopmentTreeLayout; - llvm::SmallString<256> CurrentPath(GetExecutablePath(argv[0]).str()); + llvm::SmallString<256> CurrentPath(GetExecutablePath(argv[0])); std::string CurrentExecPrefix; std::string ActiveObjRoot; diff --git a/tools/llvm-diff/CMakeLists.txt b/tools/llvm-diff/CMakeLists.txt index c59d69e..0df8b9e 100644 --- a/tools/llvm-diff/CMakeLists.txt +++ b/tools/llvm-diff/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS support asmparser bitreader) +set(LLVM_LINK_COMPONENTS support asmparser bitreader irreader) add_llvm_tool(llvm-diff llvm-diff.cpp diff --git a/tools/llvm-diff/LLVMBuild.txt b/tools/llvm-diff/LLVMBuild.txt index fa06a03..5adfdc2 100644 --- a/tools/llvm-diff/LLVMBuild.txt +++ b/tools/llvm-diff/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-diff parent = Tools -required_libraries = AsmParser BitReader +required_libraries = AsmParser BitReader IRReader diff --git a/tools/llvm-diff/Makefile b/tools/llvm-diff/Makefile index f7fa715..bd97a6a 100644 --- a/tools/llvm-diff/Makefile +++ b/tools/llvm-diff/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-diff -LINK_COMPONENTS := asmparser bitreader +LINK_COMPONENTS := asmparser bitreader irreader # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp index 0b9e92b..6eca1e2 100644 --- a/tools/llvm-diff/llvm-diff.cpp +++ b/tools/llvm-diff/llvm-diff.cpp @@ -19,8 +19,8 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index 2baa91d..87eb347 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -123,7 +123,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n"); std::string ErrorMessage; - std::auto_ptr<Module> M; + OwningPtr<Module> M; // Use the bitcode streaming interface DataStreamer *streamer = getDataFileStreamer(InputFilename, &ErrorMessage); @@ -168,9 +168,8 @@ int main(int argc, char **argv) { } std::string ErrorInfo; - OwningPtr<tool_output_file> - Out(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + OwningPtr<tool_output_file> Out(new tool_output_file( + OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index 8094856..eef6f79 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -63,6 +63,7 @@ DumpType("debug-dump", cl::init(DIDT_All), clEnumValN(DIDT_Info, "info", ".debug_info"), clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"), clEnumValN(DIDT_Line, "line", ".debug_line"), + clEnumValN(DIDT_Loc, "loc", ".debug_loc"), clEnumValN(DIDT_Frames, "frames", ".debug_frame"), clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"), clEnumValN(DIDT_Pubnames, "pubnames", ".debug_pubnames"), diff --git a/tools/llvm-extract/CMakeLists.txt b/tools/llvm-extract/CMakeLists.txt index a4e3266..3163c4b 100644 --- a/tools/llvm-extract/CMakeLists.txt +++ b/tools/llvm-extract/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter) +set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter irreader) add_llvm_tool(llvm-extract llvm-extract.cpp diff --git a/tools/llvm-extract/LLVMBuild.txt b/tools/llvm-extract/LLVMBuild.txt index 1b1a4c3..70e3507 100644 --- a/tools/llvm-extract/LLVMBuild.txt +++ b/tools/llvm-extract/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-extract parent = Tools -required_libraries = AsmParser BitReader BitWriter IPO +required_libraries = AsmParser BitReader BitWriter IRReader IPO diff --git a/tools/llvm-extract/Makefile b/tools/llvm-extract/Makefile index a1e93f5..d371c54 100644 --- a/tools/llvm-extract/Makefile +++ b/tools/llvm-extract/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-extract -LINK_COMPONENTS := ipo bitreader bitwriter asmparser +LINK_COMPONENTS := ipo bitreader bitwriter asmparser irreader # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index 85a9211..9ba68b4 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -19,13 +19,14 @@ #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Regex.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Transforms/IPO.h" @@ -99,7 +100,7 @@ int main(int argc, char **argv) { // Use lazy loading, since we only care about selected global values. SMDiagnostic Err; - std::auto_ptr<Module> M; + OwningPtr<Module> M; M.reset(getLazyIRFileModule(InputFilename, Err, Context)); if (M.get() == 0) { @@ -264,8 +265,7 @@ int main(int argc, char **argv) { Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls std::string ErrorInfo; - tool_output_file Out(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary); + tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; diff --git a/tools/llvm-jitlistener/CMakeLists.txt b/tools/llvm-jitlistener/CMakeLists.txt index d429af9..c9704fb 100644 --- a/tools/llvm-jitlistener/CMakeLists.txt +++ b/tools/llvm-jitlistener/CMakeLists.txt @@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS debuginfo
inteljitevents
interpreter
+ irreader
jit
mcjit
nativecodegen
diff --git a/tools/llvm-jitlistener/LLVMBuild.txt b/tools/llvm-jitlistener/LLVMBuild.txt index c436dd9..1ce78ac 100644 --- a/tools/llvm-jitlistener/LLVMBuild.txt +++ b/tools/llvm-jitlistener/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-jitlistener parent = Tools -required_libraries = AsmParser BitReader Interpreter JIT MCJIT NativeCodeGen Object SelectionDAG Native +required_libraries = AsmParser BitReader IRReader Interpreter JIT MCJIT NativeCodeGen Object SelectionDAG Native diff --git a/tools/llvm-jitlistener/Makefile b/tools/llvm-jitlistener/Makefile index 3018235..b132227 100644 --- a/tools/llvm-jitlistener/Makefile +++ b/tools/llvm-jitlistener/Makefile @@ -12,7 +12,7 @@ TOOLNAME := llvm-jitlistener include $(LEVEL)/Makefile.config
-LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser selectiondag Object
+LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag Object
# If Intel JIT Events support is configured, link against the LLVM Intel JIT
# Events interface library. If not, this tool will do nothing useful, but it
diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp index d6f5032..dbaf075 100644 --- a/tools/llvm-jitlistener/llvm-jitlistener.cpp +++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp @@ -22,9 +22,9 @@ #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Host.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" diff --git a/tools/llvm-link/Android.mk b/tools/llvm-link/Android.mk index 4398246..db8f2af 100644 --- a/tools/llvm-link/Android.mk +++ b/tools/llvm-link/Android.mk @@ -5,6 +5,7 @@ llvm_link_SRC_FILES := \ llvm_link_STATIC_LIBRARIES := \ libLLVMLinker \ + libLLVMIRReader \ libLLVMBitReader \ libLLVMBitWriter \ libLLVMAsmParser \ diff --git a/tools/llvm-link/CMakeLists.txt b/tools/llvm-link/CMakeLists.txt index 11933f7..4df5356 100644 --- a/tools/llvm-link/CMakeLists.txt +++ b/tools/llvm-link/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser) +set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser irreader) add_llvm_tool(llvm-link llvm-link.cpp diff --git a/tools/llvm-link/LLVMBuild.txt b/tools/llvm-link/LLVMBuild.txt index 6399ded..2e386f3 100644 --- a/tools/llvm-link/LLVMBuild.txt +++ b/tools/llvm-link/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-link parent = Tools -required_libraries = AsmParser BitReader BitWriter Linker +required_libraries = AsmParser BitReader BitWriter IRReader Linker diff --git a/tools/llvm-link/Makefile b/tools/llvm-link/Makefile index 2553db0..ed30d2d 100644 --- a/tools/llvm-link/Makefile +++ b/tools/llvm-link/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-link -LINK_COMPONENTS := linker bitreader bitwriter asmparser +LINK_COMPONENTS := linker bitreader bitwriter asmparser irreader # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index f6c9f11..652c414 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -17,12 +17,13 @@ #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/ToolOutputFile.h" #include <memory> @@ -52,25 +53,17 @@ DumpAsm("d", cl::desc("Print assembly as linked"), cl::Hidden); // 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... // -static inline std::auto_ptr<Module> LoadFile(const char *argv0, - const std::string &FN, - LLVMContext& Context) { - sys::Path Filename; - if (!Filename.set(FN)) { - errs() << "Invalid file name: '" << FN << "'\n"; - return std::auto_ptr<Module>(); - } - +static inline Module *LoadFile(const char *argv0, const std::string &FN, + LLVMContext& Context) { SMDiagnostic Err; - if (Verbose) errs() << "Loading '" << Filename.c_str() << "'\n"; + if (Verbose) errs() << "Loading '" << FN << "'\n"; Module* Result = 0; - - const std::string &FNStr = Filename.str(); - Result = ParseIRFile(FNStr, Err, Context); - if (Result) return std::auto_ptr<Module>(Result); // Load successful! + + Result = ParseIRFile(FN, Err, Context); + if (Result) return Result; // Load successful! Err.print(argv0, errs()); - return std::auto_ptr<Module>(); + return NULL; } int main(int argc, char **argv) { @@ -85,17 +78,17 @@ int main(int argc, char **argv) { unsigned BaseArg = 0; std::string ErrorMessage; - std::auto_ptr<Module> Composite(LoadFile(argv[0], - InputFilenames[BaseArg], Context)); + OwningPtr<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()); for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) { - std::auto_ptr<Module> M(LoadFile(argv[0], - InputFilenames[i], Context)); + OwningPtr<Module> M(LoadFile(argv[0], InputFilenames[i], Context)); if (M.get() == 0) { errs() << argv[0] << ": error loading file '" <<InputFilenames[i]<< "'\n"; return 1; @@ -103,22 +96,17 @@ int main(int argc, char **argv) { if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n"; - if (Linker::LinkModules(Composite.get(), M.get(), Linker::DestroySource, - &ErrorMessage)) { + if (L.linkInModule(M.get(), &ErrorMessage)) { errs() << argv[0] << ": link error in '" << InputFilenames[i] << "': " << ErrorMessage << "\n"; return 1; } } - // TODO: Iterate over the -l list and link in any modules containing - // global symbols that have not been resolved so far. - if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite; std::string ErrorInfo; - tool_output_file Out(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary); + tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp index 06c7721..81a0045 100644 --- a/tools/llvm-mc/Disassembler.cpp +++ b/tools/llvm-mc/Disassembler.cpp @@ -51,7 +51,7 @@ public: static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes, SourceMgr &SM, raw_ostream &Out, - MCStreamer &Streamer) { + MCStreamer &Streamer, bool InAtomicBlock) { // Wrap the vector in a MemoryObject. VectorMemoryObject memoryObject(Bytes); @@ -70,8 +70,13 @@ static bool PrintInsts(const MCDisassembler &DisAsm, SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second), SourceMgr::DK_Warning, "invalid instruction encoding"); + // Don't try to resynchronise the stream in a block + if (InAtomicBlock) + return true; + if (Size == 0) Size = 1; // skip illegible bytes + break; case MCDisassembler::SoftFail: @@ -89,14 +94,11 @@ static bool PrintInsts(const MCDisassembler &DisAsm, return false; } -static bool ByteArrayFromString(ByteArrayTy &ByteArray, - StringRef &Str, - SourceMgr &SM) { - while (!Str.empty()) { - // Strip horizontal whitespace. - if (size_t Pos = Str.find_first_not_of(" \t\r")) { +static bool SkipToToken(StringRef &Str) { + while (!Str.empty() && Str.find_first_not_of(" \t\r\n#,") != 0) { + // Strip horizontal whitespace and commas. + if (size_t Pos = Str.find_first_not_of(" \t\r,")) { Str = Str.substr(Pos); - continue; } // If this is the end of a line or start of a comment, remove the rest of @@ -113,9 +115,22 @@ static bool ByteArrayFromString(ByteArrayTy &ByteArray, } continue; } + } + + return !Str.empty(); +} + + +static bool ByteArrayFromString(ByteArrayTy &ByteArray, + StringRef &Str, + SourceMgr &SM) { + while (SkipToToken(Str)) { + // Handled by higher level + if (Str[0] == '[' || Str[0] == ']') + return false; // Get the current token. - size_t Next = Str.find_first_of(" \t\n\r#"); + size_t Next = Str.find_first_of(" \t\n\r,#[]"); StringRef Value = Str.substr(0, Next); // Convert to a byte and add to the byte vector. @@ -157,11 +172,44 @@ int Disassembler::disassemble(const Target &T, // Convert the input to a vector for disassembly. ByteArrayTy ByteArray; StringRef Str = Buffer.getBuffer(); + bool InAtomicBlock = false; + + while (SkipToToken(Str)) { + ByteArray.clear(); + + if (Str[0] == '[') { + if (InAtomicBlock) { + SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error, + "nested atomic blocks make no sense"); + ErrorOccurred = true; + } + InAtomicBlock = true; + Str = Str.drop_front(); + continue; + } else if (Str[0] == ']') { + if (!InAtomicBlock) { + SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error, + "attempt to close atomic block without opening"); + ErrorOccurred = true; + } + InAtomicBlock = false; + Str = Str.drop_front(); + continue; + } - ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM); + // It's a real token, get the bytes and emit them + ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM); - if (!ByteArray.empty()) - ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer); + if (!ByteArray.empty()) + ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer, + InAtomicBlock); + } + + if (InAtomicBlock) { + SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error, + "unclosed atomic block"); + ErrorOccurred = true; + } return ErrorOccurred; } diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index 243899b..f10a614 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -16,7 +16,6 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCInstrInfo.h" @@ -27,7 +26,6 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetAsmParser.h" -#include "llvm/MC/SubtargetFeature.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/FormattedStream.h" @@ -40,7 +38,6 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/system_error.h" using namespace llvm; static cl::opt<std::string> @@ -213,8 +210,8 @@ static tool_output_file *GetOutputStream() { OutputFilename = "-"; std::string Err; - tool_output_file *Out = new tool_output_file(OutputFilename.c_str(), Err, - raw_fd_ostream::F_Binary); + tool_output_file *Out = + new tool_output_file(OutputFilename.c_str(), Err, sys::fs::F_Binary); if (!Err.empty()) { errs() << Err << '\n'; delete Out; @@ -382,16 +379,16 @@ int main(int argc, char **argv) { // it later. SrcMgr.setIncludeDirs(IncludeDirs); - llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName)); - assert(MAI && "Unable to create target asm info!"); - llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); + llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); + assert(MAI && "Unable to create target asm info!"); + // 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()); - MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); + MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx); if (SaveTempLabels) diff --git a/tools/llvm-nm/CMakeLists.txt b/tools/llvm-nm/CMakeLists.txt index b6cd80b..b1672ff 100644 --- a/tools/llvm-nm/CMakeLists.txt +++ b/tools/llvm-nm/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS archive bitreader object) +set(LLVM_LINK_COMPONENTS bitreader object) add_llvm_tool(llvm-nm llvm-nm.cpp diff --git a/tools/llvm-nm/LLVMBuild.txt b/tools/llvm-nm/LLVMBuild.txt index 38ecbfd..3e64577 100644 --- a/tools/llvm-nm/LLVMBuild.txt +++ b/tools/llvm-nm/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-nm parent = Tools -required_libraries = Archive BitReader Object +required_libraries = BitReader Object diff --git a/tools/llvm-nm/Makefile b/tools/llvm-nm/Makefile index d9cee98..b95e920 100644 --- a/tools/llvm-nm/Makefile +++ b/tools/llvm-nm/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-nm -LINK_COMPONENTS := archive bitreader object +LINK_COMPONENTS := bitreader object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index a24aae6..01dd1c3 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -17,10 +17,10 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" -#include "llvm/Bitcode/Archive.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -121,6 +121,8 @@ namespace { bool MultipleFiles = false; + bool HadError = false; + std::string ToolName; } @@ -132,6 +134,7 @@ static void error(Twine message, Twine path = Twine()) { static bool error(error_code ec, Twine path = Twine()) { if (ec) { error(ec.message(), path); + HadError = true; return true; } return false; @@ -362,21 +365,24 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { if (ArchiveMap) { - outs() << "Archive map" << "\n"; - for (object::Archive::symbol_iterator i = a->begin_symbols(), - e = a->end_symbols(); i != e; ++i) { - object::Archive::child_iterator c; - StringRef symname; - StringRef filename; - if (error(i->getMember(c))) + 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))) + if (error(I->getName(symname))) return; - if (error(c->getName(filename))) + if (error(c->getName(filename))) return; - outs() << symname << " in " << filename << "\n"; + outs() << symname << " in " << filename << "\n"; + } + outs() << "\n"; } - outs() << "\n"; } for (object::Archive::child_iterator i = a->begin_children(), @@ -403,6 +409,23 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { } } } + } 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(); + I != E; ++I) { + OwningPtr<ObjectFile> Obj; + if (!I->getAsObjectFile(Obj)) { + outs() << Obj->getFileName() << ":\n"; + DumpSymbolNamesFromObject(Obj.get()); + } + } } else if (magic.is_object()) { OwningPtr<Binary> obj; if (error(object::createBinary(Buffer.take(), obj), Filename)) @@ -412,6 +435,7 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { } else { errs() << ToolName << ": " << Filename << ": " << "unrecognizable file type\n"; + HadError = true; return; } } @@ -425,7 +449,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n"); // llvm-nm only reads binary files. - if (error(sys::Program::ChangeStdinToBinary())) + if (error(sys::ChangeStdinToBinary())) return 1; ToolName = argv[0]; @@ -446,5 +470,9 @@ int main(int argc, char **argv) { std::for_each(InputFilenames.begin(), InputFilenames.end(), DumpSymbolNamesFromFile); + + if (HadError) + return 1; + return 0; } diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index 0c49d0b..e983ec9 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -12,5 +12,4 @@ add_llvm_tool(llvm-objdump COFFDump.cpp ELFDump.cpp MachODump.cpp - MCFunction.cpp ) diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp index 2ada683..bca6fc9 100644 --- a/tools/llvm-objdump/COFFDump.cpp +++ b/tools/llvm-objdump/COFFDump.cpp @@ -178,7 +178,7 @@ static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, uint64_t Ofs; if (error_code ec = I->getOffset(Ofs)) return ec; if (Ofs == Offset) { - if (error_code ec = I->getSymbol(Sym)) return ec; + Sym = *I->getSymbol(); break; } } @@ -229,7 +229,7 @@ static void printCOFFSymbolAddress(llvm::raw_ostream &Out, void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { const coff_file_header *Header; - if (error(Obj->getHeader(Header))) return; + if (error(Obj->getCOFFHeader(Header))) return; if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { errs() << "Unsupported image machine type " diff --git a/tools/llvm-objdump/ELFDump.cpp b/tools/llvm-objdump/ELFDump.cpp index bd15231..ef1f0e9 100644 --- a/tools/llvm-objdump/ELFDump.cpp +++ b/tools/llvm-objdump/ELFDump.cpp @@ -63,7 +63,7 @@ void printProgramHeaders( << format(Fmt, (uint64_t)pi->p_vaddr) << "paddr " << format(Fmt, (uint64_t)pi->p_paddr) - << format("align 2**%u\n", CountTrailingZeros_64(pi->p_align)) + << format("align 2**%u\n", countTrailingZeros<uint64_t>(pi->p_align)) << " filesz " << format(Fmt, (uint64_t)pi->p_filesz) << "memsz " @@ -79,22 +79,18 @@ void printProgramHeaders( void llvm::printELFFileHeader(const object::ObjectFile *Obj) { // Little-endian 32-bit - if (const ELFObjectFile<ELFType<support::little, 4, false> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::little, 4, false> > >(Obj)) + if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) printProgramHeaders(ELFObj); // Big-endian 32-bit - if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(Obj)) + if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) printProgramHeaders(ELFObj); // Little-endian 64-bit - if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(Obj)) + if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) printProgramHeaders(ELFObj); // Big-endian 64-bit - if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(Obj)) + if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) printProgramHeaders(ELFObj); } diff --git a/tools/llvm-objdump/MCFunction.cpp b/tools/llvm-objdump/MCFunction.cpp deleted file mode 100644 index 5c67f1b..0000000 --- a/tools/llvm-objdump/MCFunction.cpp +++ /dev/null @@ -1,138 +0,0 @@ -//===-- MCFunction.cpp ----------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the algorithm to break down a region of machine code -// into basic blocks and try to reconstruct a CFG from it. -// -//===----------------------------------------------------------------------===// - -#include "MCFunction.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/MC/MCDisassembler.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstPrinter.h" -#include "llvm/MC/MCInstrAnalysis.h" -#include "llvm/MC/MCInstrDesc.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/Support/MemoryObject.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" -#include <set> -using namespace llvm; - -MCFunction -MCFunction::createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, - const MemoryObject &Region, uint64_t Start, - uint64_t End, const MCInstrAnalysis *Ana, - raw_ostream &DebugOut, - SmallVectorImpl<uint64_t> &Calls) { - std::vector<MCDecodedInst> Instructions; - std::set<uint64_t> Splits; - Splits.insert(Start); - uint64_t Size; - - MCFunction f(Name); - - { - DenseSet<uint64_t> VisitedInsts; - SmallVector<uint64_t, 16> WorkList; - WorkList.push_back(Start); - // Disassemble code and gather basic block split points. - while (!WorkList.empty()) { - uint64_t Index = WorkList.pop_back_val(); - if (VisitedInsts.find(Index) != VisitedInsts.end()) - continue; // Already visited this location. - - for (;Index < End; Index += Size) { - VisitedInsts.insert(Index); - - MCInst Inst; - if (DisAsm->getInstruction(Inst, Size, Region, Index, DebugOut, nulls())){ - Instructions.push_back(MCDecodedInst(Index, Size, Inst)); - if (Ana->isBranch(Inst)) { - uint64_t targ = Ana->evaluateBranch(Inst, Index, Size); - if (targ != -1ULL && targ == Index+Size) - continue; // Skip nop jumps. - - // If we could determine the branch target, make a note to start a - // new basic block there and add the target to the worklist. - if (targ != -1ULL) { - Splits.insert(targ); - WorkList.push_back(targ); - WorkList.push_back(Index+Size); - } - Splits.insert(Index+Size); - break; - } else if (Ana->isReturn(Inst)) { - // Return instruction. This basic block ends here. - Splits.insert(Index+Size); - break; - } else if (Ana->isCall(Inst)) { - uint64_t targ = Ana->evaluateBranch(Inst, Index, Size); - // Add the call to the call list if the destination is known. - if (targ != -1ULL && targ != Index+Size) - Calls.push_back(targ); - } - } else { - errs().write_hex(Index) << ": warning: invalid instruction encoding\n"; - if (Size == 0) - Size = 1; // skip illegible bytes - } - } - } - } - - // Make sure the instruction list is sorted. - std::sort(Instructions.begin(), Instructions.end()); - - // Create basic blocks. - unsigned ii = 0, ie = Instructions.size(); - for (std::set<uint64_t>::iterator spi = Splits.begin(), - spe = llvm::prior(Splits.end()); spi != spe; ++spi) { - MCBasicBlock BB; - uint64_t BlockEnd = *llvm::next(spi); - // Add instructions to the BB. - for (; ii != ie; ++ii) { - if (Instructions[ii].Address < *spi || - Instructions[ii].Address >= BlockEnd) - break; - BB.addInst(Instructions[ii]); - } - f.addBlock(*spi, BB); - } - - std::sort(f.Blocks.begin(), f.Blocks.end()); - - // Calculate successors of each block. - for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) { - MCBasicBlock &BB = const_cast<MCBasicBlock&>(i->second); - if (BB.getInsts().empty()) continue; - const MCDecodedInst &Inst = BB.getInsts().back(); - - if (Ana->isBranch(Inst.Inst)) { - uint64_t targ = Ana->evaluateBranch(Inst.Inst, Inst.Address, Inst.Size); - if (targ == -1ULL) { - // Indirect branch. Bail and add all blocks of the function as a - // successor. - for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) - BB.addSucc(i->first); - } else if (targ != Inst.Address+Inst.Size) - BB.addSucc(targ); - // Conditional branches can also fall through to the next block. - if (Ana->isConditionalBranch(Inst.Inst) && llvm::next(i) != e) - BB.addSucc(llvm::next(i)->first); - } else { - // No branch. Fall through to the next block. - if (!Ana->isReturn(Inst.Inst) && llvm::next(i) != e) - BB.addSucc(llvm::next(i)->first); - } - } - - return f; -} diff --git a/tools/llvm-objdump/MCFunction.h b/tools/llvm-objdump/MCFunction.h deleted file mode 100644 index 6d3a548..0000000 --- a/tools/llvm-objdump/MCFunction.h +++ /dev/null @@ -1,100 +0,0 @@ -//===-- MCFunction.h ------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the data structures to hold a CFG reconstructed from -// machine code. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_OBJECTDUMP_MCFUNCTION_H -#define LLVM_OBJECTDUMP_MCFUNCTION_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/MC/MCInst.h" -#include <map> - -namespace llvm { - -class MCDisassembler; -class MCInstrAnalysis; -class MemoryObject; -class raw_ostream; - -/// MCDecodedInst - Small container to hold an MCInst and associated info like -/// address and size. -struct MCDecodedInst { - uint64_t Address; - uint64_t Size; - MCInst Inst; - - MCDecodedInst() {} - MCDecodedInst(uint64_t Address, uint64_t Size, MCInst Inst) - : Address(Address), Size(Size), Inst(Inst) {} - - bool operator<(const MCDecodedInst &RHS) const { - return Address < RHS.Address; - } -}; - -/// MCBasicBlock - Consists of multiple MCDecodedInsts and a list of successing -/// MCBasicBlocks. -class MCBasicBlock { - std::vector<MCDecodedInst> Insts; - typedef DenseSet<uint64_t> SetTy; - SetTy Succs; -public: - ArrayRef<MCDecodedInst> getInsts() const { return Insts; } - - typedef SetTy::const_iterator succ_iterator; - succ_iterator succ_begin() const { return Succs.begin(); } - succ_iterator succ_end() const { return Succs.end(); } - - bool contains(uint64_t Addr) const { return Succs.count(Addr); } - - void addInst(const MCDecodedInst &Inst) { Insts.push_back(Inst); } - void addSucc(uint64_t Addr) { Succs.insert(Addr); } - - bool operator<(const MCBasicBlock &RHS) const { - return Insts.size() < RHS.Insts.size(); - } -}; - -/// MCFunction - Represents a named function in machine code, containing -/// multiple MCBasicBlocks. -class MCFunction { - const StringRef Name; - // Keep BBs sorted by address. - typedef std::vector<std::pair<uint64_t, MCBasicBlock> > MapTy; - MapTy Blocks; -public: - MCFunction(StringRef Name) : Name(Name) {} - - // Create an MCFunction from a region of binary machine code. - static MCFunction - createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, - const MemoryObject &Region, uint64_t Start, uint64_t End, - const MCInstrAnalysis *Ana, raw_ostream &DebugOut, - SmallVectorImpl<uint64_t> &Calls); - - typedef MapTy::const_iterator iterator; - iterator begin() const { return Blocks.begin(); } - iterator end() const { return Blocks.end(); } - - StringRef getName() const { return Name; } - - MCBasicBlock &addBlock(uint64_t Address, const MCBasicBlock &BB) { - Blocks.push_back(std::make_pair(Address, BB)); - return Blocks.back().second; - } -}; - -} - -#endif diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index c324ff1..e0ec9cc 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -12,9 +12,9 @@ //===----------------------------------------------------------------------===// #include "llvm-objdump.h" -#include "MCFunction.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/MC/MCAsmInfo.h" @@ -27,6 +27,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Object/MachO.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" @@ -43,36 +44,16 @@ using namespace llvm; using namespace object; static cl::opt<bool> - CFG("cfg", cl::desc("Create a CFG for every symbol in the object file and" - " write it to a graphviz file (MachO-only)")); - -static cl::opt<bool> UseDbg("g", cl::desc("Print line information from debug info if available")); static cl::opt<std::string> DSYMFile("dsym", cl::desc("Use .dSYM file for debug info")); -static const Target *GetTarget(const MachOObject *MachOObj) { +static const Target *GetTarget(const MachOObjectFile *MachOObj) { // Figure out the target triple. if (TripleName.empty()) { llvm::Triple TT("unknown-unknown-unknown"); - switch (MachOObj->getHeader().CPUType) { - case llvm::MachO::CPUTypeI386: - TT.setArch(Triple::ArchType(Triple::x86)); - break; - case llvm::MachO::CPUTypeX86_64: - TT.setArch(Triple::ArchType(Triple::x86_64)); - break; - case llvm::MachO::CPUTypeARM: - TT.setArch(Triple::ArchType(Triple::arm)); - break; - case llvm::MachO::CPUTypePowerPC: - TT.setArch(Triple::ArchType(Triple::ppc)); - break; - case llvm::MachO::CPUTypePowerPC64: - TT.setArch(Triple::ArchType(Triple::ppc64)); - break; - } + TT.setArch(Triple::ArchType(MachOObj->getArch())); TripleName = TT.str(); } @@ -106,105 +87,73 @@ struct SymbolSorter { } }; -// Print additional information about an address, if available. -static void DumpAddress(uint64_t Address, ArrayRef<SectionRef> Sections, - MachOObject *MachOObj, raw_ostream &OS) { - for (unsigned i = 0; i != Sections.size(); ++i) { - uint64_t SectAddr = 0, SectSize = 0; - Sections[i].getAddress(SectAddr); - Sections[i].getSize(SectSize); - uint64_t addr = SectAddr; - if (SectAddr <= Address && - SectAddr + SectSize > Address) { - StringRef bytes, name; - Sections[i].getContents(bytes); - Sections[i].getName(name); - // Print constant strings. - if (!name.compare("__cstring")) - OS << '"' << bytes.substr(addr, bytes.find('\0', addr)) << '"'; - // Print constant CFStrings. - if (!name.compare("__cfstring")) - OS << "@\"" << bytes.substr(addr, bytes.find('\0', addr)) << '"'; - } - } -} +// Types for the storted data in code table that is built before disassembly +// and the predicate function to sort them. +typedef std::pair<uint64_t, DiceRef> DiceTableEntry; +typedef std::vector<DiceTableEntry> DiceTable; +typedef DiceTable::iterator dice_table_iterator; -typedef std::map<uint64_t, MCFunction*> FunctionMapTy; -typedef SmallVector<MCFunction, 16> FunctionListTy; -static void createMCFunctionAndSaveCalls(StringRef Name, - const MCDisassembler *DisAsm, - MemoryObject &Object, uint64_t Start, - uint64_t End, - MCInstrAnalysis *InstrAnalysis, - uint64_t Address, - raw_ostream &DebugOut, - FunctionMapTy &FunctionMap, - FunctionListTy &Functions) { - SmallVector<uint64_t, 16> Calls; - MCFunction f = - MCFunction::createFunctionFromMC(Name, DisAsm, Object, Start, End, - InstrAnalysis, DebugOut, Calls); - Functions.push_back(f); - FunctionMap[Address] = &Functions.back(); - - // Add the gathered callees to the map. - for (unsigned i = 0, e = Calls.size(); i != e; ++i) - FunctionMap.insert(std::make_pair(Calls[i], (MCFunction*)0)); +static bool +compareDiceTableEntries(const DiceTableEntry i, + const DiceTableEntry j) { + return i.first == j.first; } -// Write a graphviz file for the CFG inside an MCFunction. -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); - if (!Error.empty()) { - errs() << "llvm-objdump: warning: " << Error << '\n'; - return; - } - - Out << "digraph " << f.getName() << " {\n"; - Out << "graph [ rankdir = \"LR\" ];\n"; - for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) { - bool hasPreds = false; - // Only print blocks that have predecessors. - // FIXME: Slow. - for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe; - ++pi) - if (pi->second.contains(i->first)) { - hasPreds = true; - break; - } - - if (!hasPreds && i != f.begin()) - continue; - - Out << '"' << i->first << "\" [ label=\"<a>"; - // Print instructions. - for (unsigned ii = 0, ie = i->second.getInsts().size(); ii != ie; - ++ii) { - // Escape special chars and print the instruction in mnemonic form. - std::string Str; - raw_string_ostream OS(Str); - IP->printInst(&i->second.getInsts()[ii].Inst, OS, ""); - Out << DOT::EscapeString(OS.str()) << '|'; +static void DumpDataInCode(const char *bytes, uint64_t Size, + unsigned short Kind) { + uint64_t Value; + + switch (Kind) { + case macho::Data: + switch (Size) { + case 4: + Value = bytes[3] << 24 | + bytes[2] << 16 | + bytes[1] << 8 | + bytes[0]; + outs() << "\t.long " << Value; + break; + case 2: + Value = bytes[1] << 8 | + bytes[0]; + outs() << "\t.short " << Value; + break; + case 1: + Value = bytes[0]; + outs() << "\t.byte " << Value; + break; } - Out << "<o>\" shape=\"record\" ];\n"; - - // Add edges. - for (MCBasicBlock::succ_iterator si = i->second.succ_begin(), - se = i->second.succ_end(); si != se; ++si) - Out << i->first << ":o -> " << *si <<":a\n"; + outs() << "\t@ KIND_DATA\n"; + break; + case macho::JumpTable8: + Value = bytes[0]; + outs() << "\t.byte " << Value << "\t@ KIND_JUMP_TABLE8"; + break; + case macho::JumpTable16: + Value = bytes[1] << 8 | + bytes[0]; + outs() << "\t.short " << Value << "\t@ KIND_JUMP_TABLE16"; + break; + case macho::JumpTable32: + Value = bytes[3] << 24 | + bytes[2] << 16 | + bytes[1] << 8 | + bytes[0]; + outs() << "\t.long " << Value << "\t@ KIND_JUMP_TABLE32"; + break; + default: + outs() << "\t@ data in code kind = " << Kind << "\n"; + break; } - Out << "}\n"; } -static void getSectionsAndSymbols(const macho::Header &Header, - MachOObjectFile *MachOObj, - InMemoryStruct<macho::SymtabLoadCommand> *SymtabLC, - std::vector<SectionRef> &Sections, - std::vector<SymbolRef> &Symbols, - SmallVectorImpl<uint64_t> &FoundFns) { +static void +getSectionsAndSymbols(const macho::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)) @@ -218,20 +167,38 @@ static void getSectionsAndSymbols(const macho::Header &Header, Sections.push_back(*SI); } - for (unsigned i = 0; i != Header.NumLoadCommands; ++i) { - const MachOObject::LoadCommandInfo &LCI = - MachOObj->getObject()->getLoadCommandInfo(i); - if (LCI.Command.Type == macho::LCT_FunctionStarts) { + MachOObjectFile::LoadCommandInfo Command = + MachOObj->getFirstLoadCommandInfo(); + bool BaseSegmentAddressSet = false; + for (unsigned i = 0; ; ++i) { + if (Command.C.Type == macho::LCT_FunctionStarts) { // We found a function starts segment, parse the addresses for later // consumption. - InMemoryStruct<macho::LinkeditDataLoadCommand> LLC; - MachOObj->getObject()->ReadLinkeditDataLoadCommand(LCI, LLC); + macho::LinkeditDataLoadCommand LLC = + MachOObj->getLinkeditDataLoadCommand(Command); - MachOObj->getObject()->ReadULEB128s(LLC->DataOffset, FoundFns); + MachOObj->ReadULEB128s(LLC.DataOffset, FoundFns); } + else if (Command.C.Type == macho::LCT_Segment) { + macho::SegmentLoadCommand SLC = + MachOObj->getSegmentLoadCommand(Command); + StringRef SegName = SLC.Name; + if(!BaseSegmentAddressSet && SegName != "__PAGEZERO") { + BaseSegmentAddressSet = true; + BaseSegmentAddress = SLC.VMAddress; + } + } + + if (i == Header.NumLoadCommands - 1) + break; + else + Command = MachOObj->getNextLoadCommandInfo(Command); } } +static void DisassembleInputMachO2(StringRef Filename, + MachOObjectFile *MachOOF); + void llvm::DisassembleInputMachO(StringRef Filename) { OwningPtr<MemoryBuffer> Buff; @@ -242,9 +209,13 @@ void llvm::DisassembleInputMachO(StringRef Filename) { OwningPtr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile*>( ObjectFile::createMachOObjectFile(Buff.take()))); - MachOObject *MachOObj = MachOOF->getObject(); - const Target *TheTarget = GetTarget(MachOObj); + DisassembleInputMachO2(Filename, MachOOF.get()); +} + +static void DisassembleInputMachO2(StringRef Filename, + MachOObjectFile *MachOOF) { + const Target *TheTarget = GetTarget(MachOOF); if (!TheTarget) { // GetTarget prints out stuff. return; @@ -254,11 +225,12 @@ void llvm::DisassembleInputMachO(StringRef Filename) { InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo.get())); // Set up disassembler. - OwningPtr<const MCAsmInfo> AsmInfo(TheTarget->createMCAsmInfo(TripleName)); + OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); + OwningPtr<const MCAsmInfo> AsmInfo( + TheTarget->createMCAsmInfo(*MRI, TripleName)); OwningPtr<const MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, "", "")); OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); - OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *InstrInfo, @@ -272,37 +244,43 @@ void llvm::DisassembleInputMachO(StringRef Filename) { outs() << '\n' << Filename << ":\n\n"; - const macho::Header &Header = MachOObj->getHeader(); - - const MachOObject::LoadCommandInfo *SymtabLCI = 0; - // First, find the symbol table segment. - for (unsigned i = 0; i != Header.NumLoadCommands; ++i) { - const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i); - if (LCI.Command.Type == macho::LCT_Symtab) { - SymtabLCI = &LCI; - break; - } - } - - // Read and register the symbol table data. - InMemoryStruct<macho::SymtabLoadCommand> SymtabLC; - if (SymtabLCI) { - MachOObj->ReadSymtabLoadCommand(*SymtabLCI, SymtabLC); - MachOObj->RegisterStringTable(*SymtabLC); - } + macho::Header Header = MachOOF->getHeader(); + // FIXME: FoundFns isn't used anymore. Using symbols/LC_FUNCTION_STARTS to + // determine function locations will eventually go in MCObjectDisassembler. + // FIXME: Using the -cfg command line option, this code used to be able to + // annotate relocations with the referenced symbol's name, and if this was + // inside a __[cf]string section, the data it points to. This is now replaced + // by the upcoming MCSymbolizer, which needs the appropriate setup done above. std::vector<SectionRef> Sections; std::vector<SymbolRef> Symbols; SmallVector<uint64_t, 8> FoundFns; + uint64_t BaseSegmentAddress; - getSectionsAndSymbols(Header, MachOOF.get(), &SymtabLC, Sections, Symbols, - FoundFns); + getSectionsAndSymbols(Header, MachOOF, Sections, Symbols, FoundFns, + BaseSegmentAddress); // Make a copy of the unsorted symbol list. FIXME: duplication std::vector<SymbolRef> UnsortedSymbols(Symbols); // Sort the symbols by address, just in case they didn't come in that way. std::sort(Symbols.begin(), Symbols.end(), SymbolSorter()); + // Build a data in code table that is sorted on by the address of each entry. + uint64_t BaseAddress = 0; + if (Header.FileType == macho::HFT_Object) + Sections[0].getAddress(BaseAddress); + else + BaseAddress = BaseSegmentAddress; + DiceTable Dices; + error_code ec; + for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices(); + DI != DE; DI.increment(ec)){ + uint32_t Offset; + DI->getOffset(Offset); + Dices.push_back(std::make_pair(BaseAddress + Offset, *DI)); + } + array_pod_sort(Dices.begin(), Dices.end()); + #ifndef NDEBUG raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); #else @@ -310,14 +288,14 @@ void llvm::DisassembleInputMachO(StringRef Filename) { #endif OwningPtr<DIContext> diContext; - ObjectFile *DbgObj = MachOOF.get(); + 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; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile.c_str(), Buf)) { + if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile, Buf)) { errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n'; return; } @@ -328,31 +306,23 @@ void llvm::DisassembleInputMachO(StringRef Filename) { diContext.reset(DIContext::getDWARFContext(DbgObj)); } - FunctionMapTy FunctionMap; - FunctionListTy Functions; - for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { + + bool SectIsText = false; + Sections[SectIdx].isText(SectIsText); + if (SectIsText == false) + continue; + StringRef SectName; if (Sections[SectIdx].getName(SectName) || SectName != "__text") continue; // Skip non-text sections - StringRef SegmentName; DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl(); - if (MachOOF->getSectionFinalSegmentName(DR, SegmentName) || - SegmentName != "__TEXT") - continue; - // Insert the functions from the function starts segment into our map. - uint64_t VMAddr; - Sections[SectIdx].getAddress(VMAddr); - for (unsigned i = 0, e = FoundFns.size(); i != e; ++i) { - StringRef SectBegin; - Sections[SectIdx].getContents(SectBegin); - uint64_t Offset = (uint64_t)SectBegin.data(); - FunctionMap.insert(std::make_pair(VMAddr + FoundFns[i]-Offset, - (MCFunction*)0)); - } + StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR); + if (SegmentName != "__TEXT") + continue; StringRef Bytes; Sections[SectIdx].getContents(Bytes); @@ -365,14 +335,13 @@ void llvm::DisassembleInputMachO(StringRef Filename) { for (relocation_iterator RI = Sections[SectIdx].begin_relocations(), RE = Sections[SectIdx].end_relocations(); RI != RE; RI.increment(ec)) { uint64_t RelocOffset, SectionAddress; - RI->getAddress(RelocOffset); + RI->getOffset(RelocOffset); Sections[SectIdx].getAddress(SectionAddress); RelocOffset -= SectionAddress; - SymbolRef RelocSym; - RI->getSymbol(RelocSym); + symbol_iterator RelocSym = RI->getSymbol(); - Relocs.push_back(std::make_pair(RelocOffset, RelocSym)); + Relocs.push_back(std::make_pair(RelocOffset, *RelocSym)); } array_pod_sort(Relocs.begin(), Relocs.end()); @@ -424,52 +393,56 @@ void llvm::DisassembleInputMachO(StringRef Filename) { symbolTableWorked = true; - if (!CFG) { - // Normal disassembly, print addresses, bytes and mnemonic form. - StringRef SymName; - Symbols[SymIdx].getName(SymName); - - outs() << SymName << ":\n"; - DILineInfo lastLine; - for (uint64_t Index = Start; Index < End; Index += Size) { - MCInst Inst; - - if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, - DebugOut, nulls())) { - uint64_t SectAddress = 0; - Sections[SectIdx].getAddress(SectAddress); - outs() << format("%8" PRIx64 ":\t", SectAddress + Index); - - DumpBytes(StringRef(Bytes.data() + Index, Size)); - IP->printInst(&Inst, outs(), ""); - - // Print debug info. - if (diContext) { - DILineInfo dli = - diContext->getLineInfoForAddress(SectAddress + Index); - // Print valid line info if it changed. - if (dli != lastLine && dli.getLine() != 0) - outs() << "\t## " << dli.getFileName() << ':' - << dli.getLine() << ':' << dli.getColumn(); - lastLine = dli; - } - outs() << "\n"; - } else { - errs() << "llvm-objdump: warning: invalid instruction encoding\n"; - if (Size == 0) - Size = 1; // skip illegible bytes + outs() << SymName << ":\n"; + DILineInfo lastLine; + for (uint64_t Index = Start; Index < End; Index += Size) { + MCInst Inst; + + uint64_t SectAddress = 0; + Sections[SectIdx].getAddress(SectAddress); + outs() << format("%8" PRIx64 ":\t", SectAddress + Index); + + // Check the data in code table here to see if this is data not an + // instruction to be disassembled. + DiceTable Dice; + Dice.push_back(std::make_pair(SectAddress + Index, DiceRef())); + dice_table_iterator DTI = std::search(Dices.begin(), Dices.end(), + Dice.begin(), Dice.end(), + compareDiceTableEntries); + if (DTI != Dices.end()){ + uint16_t Length; + DTI->second.getLength(Length); + DumpBytes(StringRef(Bytes.data() + Index, Length)); + uint16_t Kind; + DTI->second.getKind(Kind); + DumpDataInCode(Bytes.data() + Index, Length, Kind); + continue; + } + + if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, + DebugOut, nulls())) { + DumpBytes(StringRef(Bytes.data() + Index, Size)); + IP->printInst(&Inst, outs(), ""); + + // Print debug info. + if (diContext) { + DILineInfo dli = + diContext->getLineInfoForAddress(SectAddress + Index); + // Print valid line info if it changed. + if (dli != lastLine && dli.getLine() != 0) + outs() << "\t## " << dli.getFileName() << ':' + << dli.getLine() << ':' << dli.getColumn(); + lastLine = dli; } + outs() << "\n"; + } else { + errs() << "llvm-objdump: warning: invalid instruction encoding\n"; + if (Size == 0) + Size = 1; // skip illegible bytes } - } else { - // Create CFG and use it for disassembly. - StringRef SymName; - Symbols[SymIdx].getName(SymName); - createMCFunctionAndSaveCalls( - SymName, DisAsm.get(), memoryObject, Start, End, - InstrAnalysis.get(), Start, DebugOut, FunctionMap, Functions); } } - if (!CFG && !symbolTableWorked) { + if (!symbolTableWorked) { // Reading the symbol table didn't work, disassemble the whole section. uint64_t SectAddress; Sections[SectIdx].getAddress(SectAddress); @@ -492,142 +465,5 @@ void llvm::DisassembleInputMachO(StringRef Filename) { } } } - - if (CFG) { - if (!symbolTableWorked) { - // Reading the symbol table didn't work, create a big __TEXT symbol. - uint64_t SectSize = 0, SectAddress = 0; - Sections[SectIdx].getSize(SectSize); - Sections[SectIdx].getAddress(SectAddress); - createMCFunctionAndSaveCalls("__TEXT", DisAsm.get(), memoryObject, - 0, SectSize, - InstrAnalysis.get(), - SectAddress, DebugOut, - FunctionMap, Functions); - } - for (std::map<uint64_t, MCFunction*>::iterator mi = FunctionMap.begin(), - me = FunctionMap.end(); mi != me; ++mi) - if (mi->second == 0) { - // Create functions for the remaining callees we have gathered, - // but we didn't find a name for them. - uint64_t SectSize = 0; - Sections[SectIdx].getSize(SectSize); - - SmallVector<uint64_t, 16> Calls; - MCFunction f = - MCFunction::createFunctionFromMC("unknown", DisAsm.get(), - memoryObject, mi->first, - SectSize, - InstrAnalysis.get(), DebugOut, - Calls); - Functions.push_back(f); - mi->second = &Functions.back(); - for (unsigned i = 0, e = Calls.size(); i != e; ++i) { - std::pair<uint64_t, MCFunction*> p(Calls[i], (MCFunction*)0); - if (FunctionMap.insert(p).second) - mi = FunctionMap.begin(); - } - } - - DenseSet<uint64_t> PrintedBlocks; - for (unsigned ffi = 0, ffe = Functions.size(); ffi != ffe; ++ffi) { - MCFunction &f = Functions[ffi]; - for (MCFunction::iterator fi = f.begin(), fe = f.end(); fi != fe; ++fi){ - if (!PrintedBlocks.insert(fi->first).second) - continue; // We already printed this block. - - // We assume a block has predecessors when it's the first block after - // a symbol. - bool hasPreds = FunctionMap.find(fi->first) != FunctionMap.end(); - - // See if this block has predecessors. - // FIXME: Slow. - for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe; - ++pi) - if (pi->second.contains(fi->first)) { - hasPreds = true; - break; - } - - uint64_t SectSize = 0, SectAddress; - Sections[SectIdx].getSize(SectSize); - Sections[SectIdx].getAddress(SectAddress); - - // No predecessors, this is a data block. Print as .byte directives. - if (!hasPreds) { - uint64_t End = llvm::next(fi) == fe ? SectSize : - llvm::next(fi)->first; - outs() << "# " << End-fi->first << " bytes of data:\n"; - for (unsigned pos = fi->first; pos != End; ++pos) { - outs() << format("%8x:\t", SectAddress + pos); - DumpBytes(StringRef(Bytes.data() + pos, 1)); - outs() << format("\t.byte 0x%02x\n", (uint8_t)Bytes[pos]); - } - continue; - } - - if (fi->second.contains(fi->first)) // Print a header for simple loops - outs() << "# Loop begin:\n"; - - DILineInfo lastLine; - // Walk over the instructions and print them. - for (unsigned ii = 0, ie = fi->second.getInsts().size(); ii != ie; - ++ii) { - const MCDecodedInst &Inst = fi->second.getInsts()[ii]; - - // If there's a symbol at this address, print its name. - if (FunctionMap.find(SectAddress + Inst.Address) != - FunctionMap.end()) - outs() << FunctionMap[SectAddress + Inst.Address]-> getName() - << ":\n"; - - outs() << format("%8" PRIx64 ":\t", SectAddress + Inst.Address); - DumpBytes(StringRef(Bytes.data() + Inst.Address, Inst.Size)); - - if (fi->second.contains(fi->first)) // Indent simple loops. - outs() << '\t'; - - IP->printInst(&Inst.Inst, outs(), ""); - - // Look for relocations inside this instructions, if there is one - // print its target and additional information if available. - for (unsigned j = 0; j != Relocs.size(); ++j) - if (Relocs[j].first >= SectAddress + Inst.Address && - Relocs[j].first < SectAddress + Inst.Address + Inst.Size) { - StringRef SymName; - uint64_t Addr; - Relocs[j].second.getAddress(Addr); - Relocs[j].second.getName(SymName); - - outs() << "\t# " << SymName << ' '; - DumpAddress(Addr, Sections, MachOObj, outs()); - } - - // If this instructions contains an address, see if we can evaluate - // it and print additional information. - uint64_t targ = InstrAnalysis->evaluateBranch(Inst.Inst, - Inst.Address, - Inst.Size); - if (targ != -1ULL) - DumpAddress(targ, Sections, MachOObj, outs()); - - // Print debug info. - if (diContext) { - DILineInfo dli = - diContext->getLineInfoForAddress(SectAddress + Inst.Address); - // Print valid line info if it changed. - if (dli != lastLine && dli.getLine() != 0) - outs() << "\t## " << dli.getFileName() << ':' - << dli.getLine() << ':' << dli.getColumn(); - lastLine = dli; - } - - outs() << '\n'; - } - } - - emitDOTFile((f.getName().str() + ".dot").c_str(), f, IP.get()); - } - } } } diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 322bd21..122ac83 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -17,17 +17,25 @@ //===----------------------------------------------------------------------===// #include "llvm-objdump.h" -#include "MCFunction.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAtom.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCFunction.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCModule.h" +#include "llvm/MC/MCObjectDisassembler.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectSymbolizer.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCRelocationInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" @@ -123,6 +131,14 @@ static cl::alias PrivateHeadersShort("p", cl::desc("Alias for --private-headers"), cl::aliasopt(PrivateHeaders)); +static cl::opt<bool> +Symbolize("symbolize", cl::desc("When disassembling instructions, " + "try to symbolize operands.")); + +static cl::opt<bool> +CFG("cfg", cl::desc("Create a CFG for every function found in the object" + " and write it to a graphviz file")); + static StringRef ToolName; bool llvm::error(error_code ec) { @@ -137,8 +153,13 @@ static const Target *getTarget(const ObjectFile *Obj = NULL) { // Figure out the target triple. llvm::Triple TheTriple("unknown-unknown-unknown"); if (TripleName.empty()) { - if (Obj) + if (Obj) { TheTriple.setArch(Triple::ArchType(Obj->getArch())); + // 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); + } } else TheTriple.setTriple(Triple::normalize(TripleName)); @@ -156,7 +177,51 @@ static const Target *getTarget(const ObjectFile *Obj = NULL) { return TheTarget; } -void llvm::StringRefMemoryObject::anchor() { } +// Write a graphviz file for the CFG inside an MCFunction. +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); + if (!Error.empty()) { + errs() << "llvm-objdump: warning: " << Error << '\n'; + return; + } + + Out << "digraph \"" << f.getName() << "\" {\n"; + Out << "graph [ rankdir = \"LR\" ];\n"; + for (MCFunction::const_iterator i = f.begin(), e = f.end(); i != e; ++i) { + // Only print blocks that have predecessors. + bool hasPreds = (*i)->pred_begin() != (*i)->pred_end(); + + if (!hasPreds && i != f.begin()) + continue; + + Out << '"' << (*i)->getInsts()->getBeginAddr() << "\" [ label=\"<a>"; + // Print instructions. + for (unsigned ii = 0, ie = (*i)->getInsts()->size(); ii != ie; + ++ii) { + if (ii != 0) // Not the first line, start a new row. + Out << '|'; + if (ii + 1 == ie) // Last line, add an end id. + Out << "<o>"; + + // Escape special chars and print the instruction in mnemonic form. + std::string Str; + raw_string_ostream OS(Str); + IP->printInst(&(*i)->getInsts()->at(ii).Inst, OS, ""); + Out << DOT::EscapeString(OS.str()); + } + Out << "\" shape=\"record\" ];\n"; + + // Add edges. + for (MCBasicBlock::succ_const_iterator si = (*i)->succ_begin(), + se = (*i)->succ_end(); si != se; ++si) + Out << (*i)->getInsts()->getBeginAddr() << ":o -> " + << (*si)->getInsts()->getBeginAddr() << ":a\n"; + } + Out << "}\n"; +} void llvm::DumpBytes(StringRef bytes) { static const char hex_rep[] = "0123456789abcdef"; @@ -186,8 +251,8 @@ void llvm::DumpBytes(StringRef bytes) { bool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) { uint64_t a_addr, b_addr; - if (error(a.getAddress(a_addr))) return false; - if (error(b.getAddress(b_addr))) return false; + if (error(a.getOffset(a_addr))) return false; + if (error(b.getOffset(b_addr))) return false; return a_addr < b_addr; } @@ -207,6 +272,96 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { FeaturesStr = Features.getString(); } + OwningPtr<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)); + if (!AsmInfo) { + errs() << "error: no assembly info for target " << TripleName << "\n"; + return; + } + + OwningPtr<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()); + if (!MII) { + errs() << "error: no instruction info for target " << TripleName << "\n"; + return; + } + + OwningPtr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); + if (!DisAsm) { + errs() << "error: no disassembler for target " << TripleName << "\n"; + return; + } + + OwningPtr<const MCObjectFileInfo> MOFI; + OwningPtr<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())); + if (RelInfo) { + OwningPtr<MCSymbolizer> Symzer( + MCObjectSymbolizer::createObjectSymbolizer(*Ctx.get(), RelInfo, Obj)); + if (Symzer) + DisAsm->setSymbolizer(Symzer); + } + } + + OwningPtr<const MCInstrAnalysis> + MIA(TheTarget->createMCInstrAnalysis(MII.get())); + + int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); + OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( + AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI)); + if (!IP) { + errs() << "error: no instruction printer for target " << TripleName + << '\n'; + return; + } + + if (CFG) { + OwningPtr<MCObjectDisassembler> OD( + new MCObjectDisassembler(*Obj, *DisAsm, *MIA)); + OwningPtr<MCModule> Mod(OD->buildModule(/* withCFG */ true)); + for (MCModule::const_atom_iterator AI = Mod->atom_begin(), + AE = Mod->atom_end(); + AI != AE; ++AI) { + outs() << "Atom " << (*AI)->getName() << ": \n"; + if (const MCTextAtom *TA = dyn_cast<MCTextAtom>(*AI)) { + for (MCTextAtom::const_iterator II = TA->begin(), IE = TA->end(); + II != IE; + ++II) { + IP->printInst(&II->Inst, outs(), ""); + outs() << "\n"; + } + } + } + for (MCModule::const_func_iterator FI = Mod->func_begin(), + FE = Mod->func_end(); + FI != FE; ++FI) { + static int filenum = 0; + emitDOTFile((Twine((*FI)->getName()) + "_" + + utostr(filenum) + ".dot").str().c_str(), + **FI, IP.get()); + ++filenum; + } + } + + error_code ec; for (section_iterator i = Obj->begin_sections(), e = Obj->end_sections(); @@ -228,6 +383,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (!error(i->containsSymbol(*si, contains)) && contains) { uint64_t Address; if (error(si->getAddress(Address))) break; + if (Address == UnknownAddressOrSize) continue; Address -= SectionAddr; StringRef Name; @@ -254,10 +410,10 @@ 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)) { + if (const MachOObjectFile *MachO = + dyn_cast<const MachOObjectFile>(Obj)) { DataRefImpl DR = i->getRawDataRefImpl(); - if (error(MachO->getSectionFinalSegmentName(DR, SegmentName))) - break; + SegmentName = MachO->getSectionFinalSegmentName(DR); } StringRef name; if (error(i->getName(name))) break; @@ -271,53 +427,13 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (Symbols.empty()) Symbols.push_back(std::make_pair(0, name)); - // Set up disassembler. - OwningPtr<const MCAsmInfo> AsmInfo(TheTarget->createMCAsmInfo(TripleName)); - if (!AsmInfo) { - errs() << "error: no assembly info for target " << TripleName << "\n"; - return; - } - - OwningPtr<const MCSubtargetInfo> STI( - TheTarget->createMCSubtargetInfo(TripleName, "", FeaturesStr)); - - if (!STI) { - errs() << "error: no subtarget info for target " << TripleName << "\n"; - return; - } - - OwningPtr<const MCDisassembler> DisAsm( - TheTarget->createMCDisassembler(*STI)); - if (!DisAsm) { - errs() << "error: no disassembler for target " << TripleName << "\n"; - return; - } - - OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); - if (!MRI) { - errs() << "error: no register info for target " << TripleName << "\n"; - return; - } - - OwningPtr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo()); - if (!MII) { - errs() << "error: no instruction info for target " << TripleName << "\n"; - return; - } - - int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); - OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( - AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI)); - if (!IP) { - errs() << "error: no instruction printer for target " << TripleName - << '\n'; - return; - } + SmallString<40> Comments; + raw_svector_ostream CommentStream(Comments); StringRef Bytes; if (error(i->getContents(Bytes))) break; - StringRefMemoryObject memoryObject(Bytes); + StringRefMemoryObject memoryObject(Bytes, SectionAddr); uint64_t Size; uint64_t Index; uint64_t SectSize; @@ -351,14 +467,17 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { for (Index = Start; Index < End; Index += Size) { MCInst Inst; - if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, - DebugOut, nulls())) { + if (DisAsm->getInstruction(Inst, Size, memoryObject, + SectionAddr + Index, + DebugOut, CommentStream)) { outs() << format("%8" PRIx64 ":", SectionAddr + Index); if (!NoShowRawInsn) { outs() << "\t"; DumpBytes(StringRef(Bytes.data() + Index, Size)); } IP->printInst(&Inst, outs(), ""); + outs() << CommentStream.str(); + Comments.clear(); outs() << "\n"; } else { errs() << ToolName << ": warning: invalid instruction encoding\n"; @@ -377,7 +496,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (error(rel_cur->getHidden(hidden))) goto skip_print_rel; if (hidden) goto skip_print_rel; - if (error(rel_cur->getAddress(addr))) goto skip_print_rel; + if (error(rel_cur->getOffset(addr))) goto skip_print_rel; // Stop when rel_cur's address is past the current instruction. if (addr >= Index + Size) break; if (error(rel_cur->getTypeName(name))) goto skip_print_rel; @@ -416,7 +535,7 @@ static void PrintRelocations(const ObjectFile *o) { if (error(ri->getHidden(hidden))) continue; if (hidden) continue; if (error(ri->getTypeName(relocname))) continue; - if (error(ri->getAddress(address))) continue; + if (error(ri->getOffset(address))) continue; if (error(ri->getValueString(valuestr))) continue; outs() << address << " " << relocname << " " << valuestr << "\n"; } @@ -459,11 +578,19 @@ static void PrintSectionContents(const ObjectFile *o) { 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; outs() << "Contents of section " << Name << ":\n"; + if (BSS) { + outs() << format("<skipping contents of bss section at [%04" PRIx64 + ", %04" PRIx64 ")>\n", BaseAddr, + BaseAddr + Contents.size()); + continue; + } // Dump out the content as hex and printable ascii characters. for (std::size_t addr = 0, end = Contents.size(); addr < end; addr += 16) { @@ -591,11 +718,10 @@ static void PrintSymbolTable(const ObjectFile *o) { else if (Section == o->end_sections()) outs() << "*UND*"; else { - if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(o)) { - StringRef SegmentName; + if (const MachOObjectFile *MachO = + dyn_cast<const MachOObjectFile>(o)) { DataRefImpl DR = Section->getRawDataRefImpl(); - if (error(MachO->getSectionFinalSegmentName(DR, SegmentName))) - SegmentName = ""; + StringRef SegmentName = MachO->getSectionFinalSegmentName(DR); outs() << SegmentName << ","; } StringRef SectionName; diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index ca7bced..87f19ba 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -13,7 +13,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DataTypes.h" -#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/StringRefMemoryObject.h" namespace llvm { @@ -35,23 +35,6 @@ void DisassembleInputMachO(StringRef Filename); void printCOFFUnwindInfo(const object::COFFObjectFile* o); void printELFFileHeader(const object::ObjectFile *o); -class StringRefMemoryObject : public MemoryObject { - virtual void anchor(); - StringRef Bytes; -public: - StringRefMemoryObject(StringRef bytes) : Bytes(bytes) {} - - uint64_t getBase() const { return 0; } - uint64_t getExtent() const { return Bytes.size(); } - - int readByte(uint64_t Addr, uint8_t *Byte) const { - if (Addr >= getExtent()) - return -1; - *Byte = Bytes[Addr]; - return 0; - } -}; - } #endif diff --git a/tools/llvm-ranlib/CMakeLists.txt b/tools/llvm-ranlib/CMakeLists.txt deleted file mode 100644 index 2d7defe..0000000 --- a/tools/llvm-ranlib/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(LLVM_LINK_COMPONENTS archive) - -add_llvm_tool(llvm-ranlib - llvm-ranlib.cpp - ) diff --git a/tools/llvm-ranlib/LLVMBuild.txt b/tools/llvm-ranlib/LLVMBuild.txt deleted file mode 100644 index 23015c5..0000000 --- a/tools/llvm-ranlib/LLVMBuild.txt +++ /dev/null @@ -1,22 +0,0 @@ -;===- ./tools/llvm-ranlib/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-ranlib -parent = Tools -required_libraries = Archive diff --git a/tools/llvm-ranlib/llvm-ranlib.cpp b/tools/llvm-ranlib/llvm-ranlib.cpp deleted file mode 100644 index fe9d3e2..0000000 --- a/tools/llvm-ranlib/llvm-ranlib.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//===-- llvm-ranlib.cpp - LLVM archive index generator --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Adds or updates an index (symbol table) for an LLVM archive file. -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/LLVMContext.h" -#include "llvm/Bitcode/Archive.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/raw_ostream.h" -#include <memory> -using namespace llvm; - -// llvm-ar operation code and modifier flags -static cl::opt<std::string> -ArchiveName(cl::Positional, cl::Optional, cl::desc("<archive-file>")); - -static cl::opt<bool> -Verbose("verbose",cl::Optional,cl::init(false), - cl::desc("Print the symbol table")); - -// printSymbolTable - print out the archive's symbol table. -void printSymbolTable(Archive* TheArchive) { - outs() << "\nArchive Symbol Table:\n"; - const Archive::SymTabType& symtab = TheArchive->getSymbolTable(); - for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end(); - I != E; ++I ) { - unsigned offset = TheArchive->getFirstFileOffset() + I->second; - outs() << " " << format("%9u", offset) << "\t" << I->first <<"\n"; - } -} - -int main(int argc, char **argv) { - // Print a stack trace if we signal out. - llvm::sys::PrintStackTraceOnErrorSignal(); - llvm::PrettyStackTraceProgram X(argc, argv); - - LLVMContext &Context = getGlobalContext(); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - - // Have the command line options parsed and handle things - // like --help and --version. - cl::ParseCommandLineOptions(argc, argv, - "LLVM Archive Index Generator (llvm-ranlib)\n\n" - " This program adds or updates an index of bitcode symbols\n" - " to an LLVM archive file." - ); - - int exitCode = 0; - - // Check the path name of the archive - sys::Path ArchivePath; - if (!ArchivePath.set(ArchiveName)) { - errs() << argv[0] << ": " << "Archive name invalid: " << ArchiveName << - "\n"; - return 1; - } - - // Make sure it exists, we don't create empty archives - bool Exists; - if (llvm::sys::fs::exists(ArchivePath.str(), Exists) || !Exists) { - errs() << argv[0] << ": " << "Archive file does not exist" << - ArchivePath.str() << "\n"; - return 1; - } - - std::string err_msg; - std::auto_ptr<Archive> - AutoArchive(Archive::OpenAndLoad(ArchivePath, Context, &err_msg)); - Archive* TheArchive = AutoArchive.get(); - if (!TheArchive) { - errs() << argv[0] << ": " << err_msg << "\n"; - return 1; - } - - if (TheArchive->writeToDisk(true, false, &err_msg )) { - errs() << argv[0] << ": " << err_msg << "\n"; - return 1; - } - - if (Verbose) - printSymbolTable(TheArchive); - - return exitCode; -} diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index 676c23d..90997a8 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -1,6 +1,14 @@ -set(LLVM_LINK_COMPONENTS archive bitreader object) +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + bitreader + object) add_llvm_tool(llvm-readobj - ELF.cpp llvm-readobj.cpp + ObjDumper.cpp + COFFDumper.cpp + ELFDumper.cpp + MachODumper.cpp + Error.cpp + StreamWriter.cpp ) diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp new file mode 100644 index 0000000..2f309e3 --- /dev/null +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -0,0 +1,1114 @@ +//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the COFF-specific dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "ObjDumper.h" + +#include "Error.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/Casting.h" +#include "llvm/Support/Compiler.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> + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::Win64EH; + +namespace { + +class COFFDumper : public ObjDumper { +public: + COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer) + : ObjDumper(Writer) + , Obj(Obj) { + 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; + +private: + void printSymbol(symbol_iterator SymI); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + void printDataDirectory(uint32_t Index, const std::string &FieldName); + + void printX64UnwindInfo(); + + void printRuntimeFunction( + const RuntimeFunction& RTF, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels); + + void printUnwindInfo( + const Win64EH::UnwindInfo& UI, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels); + + void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs); + + void cacheRelocations(); + + error_code getSectionContents( + const std::vector<RelocationRef> &Rels, + uint64_t Offset, + ArrayRef<uint8_t> &Contents, + uint64_t &Addr); + + error_code getSection( + const std::vector<RelocationRef> &Rels, + uint64_t Offset, + const coff_section **Section, + uint64_t *AddrPtr); + + typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy; + + const llvm::object::COFFObjectFile *Obj; + RelocMapTy RelocMap; + std::vector<RelocationRef> EmptyRelocs; +}; + +} // namespace + + +namespace llvm { + +error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result) { + const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj); + if (!COFFObj) + return readobj_error::unsupported_obj_file_format; + + Result.reset(new COFFDumper(COFFObj, Writer)); + return readobj_error::success; +} + +} // namespace llvm + + +// Returns the name of the unwind code. +static StringRef getUnwindCodeTypeName(uint8_t Code) { + switch(Code) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: return "PUSH_NONVOL"; + case UOP_AllocLarge: return "ALLOC_LARGE"; + case UOP_AllocSmall: return "ALLOC_SMALL"; + case UOP_SetFPReg: return "SET_FPREG"; + case UOP_SaveNonVol: return "SAVE_NONVOL"; + case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR"; + case UOP_SaveXMM128: return "SAVE_XMM128"; + case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; + case UOP_PushMachFrame: return "PUSH_MACHFRAME"; + } +} + +// Returns the name of a referenced register. +static StringRef getUnwindRegisterName(uint8_t Reg) { + switch(Reg) { + default: llvm_unreachable("Invalid register"); + case 0: return "RAX"; + case 1: return "RCX"; + case 2: return "RDX"; + case 3: return "RBX"; + case 4: return "RSP"; + case 5: return "RBP"; + case 6: return "RSI"; + case 7: return "RDI"; + case 8: return "R8"; + case 9: return "R9"; + case 10: return "R10"; + case 11: return "R11"; + case 12: return "R12"; + case 13: return "R13"; + case 14: return "R14"; + case 15: return "R15"; + } +} + +// Calculates the number of array slots required for the unwind code. +static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { + switch (UnwindCode.getUnwindOp()) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: + case UOP_AllocSmall: + case UOP_SetFPReg: + case UOP_PushMachFrame: + return 1; + case UOP_SaveNonVol: + case UOP_SaveXMM128: + return 2; + case UOP_SaveNonVolBig: + case UOP_SaveXMM128Big: + return 3; + case UOP_AllocLarge: + return (UnwindCode.getOpInfo() == 0) ? 2 : 3; + } +} + +// Given a symbol sym this functions returns the address and section of it. +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); + return object_error::success; +} + +// Given a vector of relocations for a section and an offset into this section +// the function returns the symbol used for the relocation at the offset. +static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, + uint64_t Offset, SymbolRef &Sym) { + for (std::vector<RelocationRef>::const_iterator RelI = Rels.begin(), + RelE = Rels.end(); + RelI != RelE; ++RelI) { + uint64_t Ofs; + if (error_code EC = RelI->getOffset(Ofs)) + return EC; + + if (Ofs == Offset) { + Sym = *RelI->getSymbol(); + return readobj_error::success; + } + } + + return readobj_error::unknown_symbol; +} + +// Given a vector of relocations for a section and an offset into this section +// the function returns the name of the symbol used for the relocation at the +// offset. +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; + return object_error::success; +} + +static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN ), + 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_EBC ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2) +}; + +static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI ) +}; + +static const EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_UNKNOWN ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_NATIVE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_GUI ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CUI ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_POSIX_CUI ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_APPLICATION ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_ROM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_XBOX ), +}; + +static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = { + 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 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE), +}; + +static const EnumEntry<COFF::SectionCharacteristics> +ImageSectionCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE ) +}; + +static const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = { + { "Null" , COFF::IMAGE_SYM_TYPE_NULL }, + { "Void" , COFF::IMAGE_SYM_TYPE_VOID }, + { "Char" , COFF::IMAGE_SYM_TYPE_CHAR }, + { "Short" , COFF::IMAGE_SYM_TYPE_SHORT }, + { "Int" , COFF::IMAGE_SYM_TYPE_INT }, + { "Long" , COFF::IMAGE_SYM_TYPE_LONG }, + { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT }, + { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE }, + { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT }, + { "Union" , COFF::IMAGE_SYM_TYPE_UNION }, + { "Enum" , COFF::IMAGE_SYM_TYPE_ENUM }, + { "MOE" , COFF::IMAGE_SYM_TYPE_MOE }, + { "Byte" , COFF::IMAGE_SYM_TYPE_BYTE }, + { "Word" , COFF::IMAGE_SYM_TYPE_WORD }, + { "UInt" , COFF::IMAGE_SYM_TYPE_UINT }, + { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD } +}; + +static const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = { + { "Null" , COFF::IMAGE_SYM_DTYPE_NULL }, + { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER }, + { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION }, + { "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY } +}; + +static const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = { + { "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION }, + { "Null" , COFF::IMAGE_SYM_CLASS_NULL }, + { "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC }, + { "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL }, + { "Static" , COFF::IMAGE_SYM_CLASS_STATIC }, + { "Register" , COFF::IMAGE_SYM_CLASS_REGISTER }, + { "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF }, + { "Label" , COFF::IMAGE_SYM_CLASS_LABEL }, + { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL }, + { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT }, + { "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT }, + { "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG }, + { "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION }, + { "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG }, + { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION }, + { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC }, + { "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG }, + { "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM }, + { "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM }, + { "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD }, + { "Block" , COFF::IMAGE_SYM_CLASS_BLOCK }, + { "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION }, + { "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT }, + { "File" , COFF::IMAGE_SYM_CLASS_FILE }, + { "Section" , COFF::IMAGE_SYM_CLASS_SECTION }, + { "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL }, + { "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN } +}; + +static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = { + { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES }, + { "Any" , COFF::IMAGE_COMDAT_SELECT_ANY }, + { "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE }, + { "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH }, + { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE }, + { "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST }, + { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST } +}; + +static const EnumEntry<COFF::WeakExternalCharacteristics> +WeakExternalCharacteristics[] = { + { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY }, + { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY }, + { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } +}; + +static const EnumEntry<unsigned> UnwindFlags[] = { + { "ExceptionHandler", Win64EH::UNW_ExceptionHandler }, + { "TerminateHandler", Win64EH::UNW_TerminateHandler }, + { "ChainInfo" , Win64EH::UNW_ChainInfo } +}; + +static const EnumEntry<unsigned> UnwindOpInfo[] = { + { "RAX", 0 }, + { "RCX", 1 }, + { "RDX", 2 }, + { "RBX", 3 }, + { "RSP", 4 }, + { "RBP", 5 }, + { "RSI", 6 }, + { "RDI", 7 }, + { "R8", 8 }, + { "R9", 9 }, + { "R10", 10 }, + { "R11", 11 }, + { "R12", 12 }, + { "R13", 13 }, + { "R14", 14 }, + { "R15", 15 } +}; + +// 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) { + return static_cast<const char*>(UI.getLanguageSpecificData()) + - reinterpret_cast<const char*>(&UI); +} + +static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UCs) { + if (UCs.size() < 3) + return 0; + + return UCs[1].FrameOffset + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16); +} + +template<typename T> +static error_code getSymbolAuxData(const COFFObjectFile *Obj, + const coff_symbol *Symbol, const T* &Aux) { + ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); + Aux = reinterpret_cast<const T*>(AuxData.data()); + return readobj_error::success; +} + +static std::string formatSymbol(const std::vector<RelocationRef> &Rels, + uint64_t Offset, uint32_t Disp) { + std::string Buffer; + raw_string_ostream Str(Buffer); + + StringRef Sym; + if (resolveSymbolName(Rels, Offset, Sym)) { + Str << format(" (0x%" PRIX64 ")", Offset); + return Str.str(); + } + + Str << Sym; + if (Disp > 0) { + Str << format(" +0x%X (0x%" PRIX64 ")", Disp, Offset); + } else { + Str << format(" (0x%" PRIX64 ")", Offset); + } + + return Str.str(); +} + +// Given a vector of relocations for a section and an offset into this section +// the function resolves the symbol used for the relocation at the offset and +// returns the section content and the address inside the content pointed to +// by the symbol. +error_code COFFDumper::getSectionContents( + const std::vector<RelocationRef> &Rels, uint64_t Offset, + ArrayRef<uint8_t> &Contents, uint64_t &Addr) { + + SymbolRef Sym; + const coff_section *Section; + + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + 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; +} + +error_code COFFDumper::getSection( + const std::vector<RelocationRef> &Rels, uint64_t Offset, + const coff_section **SectionPtr, uint64_t *AddrPtr) { + + SymbolRef Sym; + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; + + const coff_section *Section; + uint64_t Addr; + if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + return EC; + + if (SectionPtr) + *SectionPtr = Section; + if (AddrPtr) + *AddrPtr = Addr; + + return object_error::success; +} + +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; + + RelocMap[Section].push_back(*RelI); + } + + // Sort relocations by address. + std::sort(RelocMap[Section].begin(), RelocMap[Section].end(), + relocAddressLess); + } +} + +void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName) { + const data_directory *Data; + if (Obj->getDataDirectory(Index, Data)) + return; + W.printHex(FieldName + "RVA", Data->RelativeVirtualAddress); + W.printHex(FieldName + "Size", Data->Size); +} + +void COFFDumper::printFileHeaders() { + // Print COFF header + const coff_file_header *COFFHeader = 0; + if (error(Obj->getCOFFHeader(COFFHeader))) + return; + + time_t TDS = COFFHeader->TimeDateStamp; + char FormattedTime[20] = { }; + strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS)); + + { + DictScope D(W, "ImageFileHeader"); + W.printEnum ("Machine", COFFHeader->Machine, + makeArrayRef(ImageFileMachineType)); + W.printNumber("SectionCount", COFFHeader->NumberOfSections); + W.printHex ("TimeDateStamp", FormattedTime, COFFHeader->TimeDateStamp); + W.printHex ("PointerToSymbolTable", COFFHeader->PointerToSymbolTable); + W.printNumber("SymbolCount", COFFHeader->NumberOfSymbols); + W.printNumber("OptionalHeaderSize", COFFHeader->SizeOfOptionalHeader); + W.printFlags ("Characteristics", COFFHeader->Characteristics, + makeArrayRef(ImageFileCharacteristics)); + } + + // Print PE header. This header does not exist if this is an object file and + // not an executable. + const pe32_header *PEHeader = 0; + if (error(Obj->getPE32Header(PEHeader))) + return; + + 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]); + } + } + } +} + +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; + + ++SectionNumber; + const coff_section *Section = Obj->getCOFFSection(SecI); + + StringRef Name; + if (error(SecI->getName(Name))) + Name = ""; + + DictScope D(W, "Section"); + W.printNumber("Number", SectionNumber); + W.printBinary("Name", Name, Section->Name); + W.printHex ("VirtualSize", Section->VirtualSize); + W.printHex ("VirtualAddress", Section->VirtualAddress); + W.printNumber("RawDataSize", Section->SizeOfRawData); + W.printHex ("PointerToRawData", Section->PointerToRawData); + W.printHex ("PointerToRelocations", Section->PointerToRelocations); + W.printHex ("PointerToLineNumbers", Section->PointerToLinenumbers); + W.printNumber("RelocationCount", Section->NumberOfRelocations); + W.printNumber("LineNumberCount", Section->NumberOfLinenumbers); + W.printFlags ("Characteristics", Section->Characteristics, + makeArrayRef(ImageSectionCharacteristics), + COFF::SectionCharacteristics(0x00F00000)); + + 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); + } + } + + 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; + + bool Contained = false; + if (SecI->containsSymbol(*SymI, Contained) || !Contained) + continue; + + printSymbol(SymI); + } + } + + if (opts::SectionData) { + StringRef Data; + if (error(SecI->getContents(Data))) break; + + W.printBinaryBlock("SectionData", Data); + } + } +} + +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)) { + ++SectionNumber; + if (error(EC)) + break; + + StringRef Name; + if (error(SecI->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; + + if (!PrintedGroup) { + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(SecI, RelI); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +void COFFDumper::printRelocation(section_iterator SecI, + relocation_iterator RelI) { + 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 (opts::ExpandRelocs) { + DictScope Group(W, "Relocation"); + W.printHex("Offset", Offset); + W.printNumber("Type", RelocName, RelocType); + W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); + } else { + raw_ostream& OS = W.startLine(); + OS << W.hex(Offset) + << " " << RelocName + << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << "\n"; + } +} + +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); + } +} + +void COFFDumper::printDynamicSymbols() { + ListScope Group(W, "DynamicSymbols"); +} + +void COFFDumper::printSymbol(symbol_iterator SymI) { + DictScope D(W, "Symbol"); + + const coff_symbol *Symbol = Obj->getCOFFSymbol(SymI); + const coff_section *Section; + if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { + W.startLine() << "Invalid section number: " << EC.message() << "\n"; + W.flush(); + return; + } + + StringRef SymbolName; + if (Obj->getSymbolName(Symbol, SymbolName)) + SymbolName = ""; + + StringRef SectionName = ""; + if (Section) + Obj->getSectionName(Section, SectionName); + + W.printString("Name", SymbolName); + W.printNumber("Value", Symbol->Value); + W.printNumber("Section", SectionName, Symbol->SectionNumber); + W.printEnum ("BaseType", Symbol->getBaseType(), makeArrayRef(ImageSymType)); + W.printEnum ("ComplexType", Symbol->getComplexType(), + makeArrayRef(ImageSymDType)); + W.printEnum ("StorageClass", Symbol->StorageClass, + makeArrayRef(ImageSymClass)); + 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) { + const coff_aux_function_definition *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + DictScope AS(W, "AuxFunctionDef"); + W.printNumber("TagIndex", Aux->TagIndex); + W.printNumber("TotalSize", Aux->TotalSize); + 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; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + const coff_symbol *Linked; + StringRef LinkedName; + error_code EC; + if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) || + (EC = Obj->getSymbolName(Linked, LinkedName))) { + LinkedName = ""; + error(EC); + } + + DictScope AS(W, "AuxWeakExternal"); + W.printNumber("Linked", LinkedName, Aux->TagIndex); + W.printEnum ("Search", Aux->Characteristics, + makeArrayRef(WeakExternalCharacteristics)); + W.printBinary("Unused", Aux->Unused); + + } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_FILE) { + const coff_aux_file_record *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + 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)) { + const coff_aux_section_definition *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + DictScope AS(W, "AuxSectionDef"); + W.printNumber("Length", Aux->Length); + W.printNumber("RelocationCount", Aux->NumberOfRelocations); + W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers); + W.printHex("Checksum", Aux->CheckSum); + W.printNumber("Number", Aux->Number); + W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect)); + W.printBinary("Unused", makeArrayRef(Aux->Unused)); + + if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT + && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + const coff_section *Assoc; + StringRef AssocName; + error_code EC; + if ((EC = Obj->getSection(Aux->Number, Assoc)) || + (EC = Obj->getSectionName(Assoc, AssocName))) { + AssocName = ""; + error(EC); + } + + W.printNumber("AssocSection", AssocName, Aux->Number); + } + } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_CLR_TOKEN) { + const coff_aux_clr_token *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + DictScope AS(W, "AuxCLRToken"); + W.printNumber("AuxType", Aux->AuxType); + W.printNumber("Reserved", Aux->Reserved); + W.printNumber("SymbolTableIndex", Aux->SymbolTableIndex); + W.printBinary("Unused", Aux->Unused); + + } else { + W.startLine() << "<unhandled auxiliary record>\n"; + } + } +} + +void COFFDumper::printUnwindInfo() { + const coff_file_header *Header; + if (error(Obj->getCOFFHeader(Header))) + return; + + ListScope D(W, "UnwindInformation"); + if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { + W.startLine() << "Unsupported image machine type " + "(currently only AMD64 is supported).\n"; + return; + } + + printX64UnwindInfo(); +} + +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; + + StringRef Name; + if (error(SecI->getName(Name))) + continue; + if (Name != ".pdata" && !Name.startswith(".pdata$")) + continue; + + const coff_section *PData = Obj->getCOFFSection(SecI); + + ArrayRef<uint8_t> Contents; + if (error(Obj->getSectionContents(PData, Contents)) || + Contents.empty()) + continue; + + 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 OffsetInSection = std::distance(RFs.begin(), I) + * sizeof(RuntimeFunction); + + printRuntimeFunction(*I, OffsetInSection, RelocMap[PData]); + } + } +} + +void COFFDumper::printRuntimeFunction( + const RuntimeFunction& RTF, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels) { + + DictScope D(W, "RuntimeFunction"); + W.printString("StartAddress", + formatSymbol(Rels, OffsetInSection + 0, RTF.StartAddress)); + W.printString("EndAddress", + formatSymbol(Rels, OffsetInSection + 4, RTF.EndAddress)); + W.printString("UnwindInfoAddress", + formatSymbol(Rels, OffsetInSection + 8, RTF.UnwindInfoOffset)); + + const coff_section* XData = 0; + uint64_t UnwindInfoOffset = 0; + if (error(getSection(Rels, OffsetInSection + 8, &XData, &UnwindInfoOffset))) + return; + + ArrayRef<uint8_t> XContents; + if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty()) + return; + + UnwindInfoOffset += RTF.UnwindInfoOffset; + if (UnwindInfoOffset > XContents.size()) + return; + + const Win64EH::UnwindInfo *UI = + reinterpret_cast<const Win64EH::UnwindInfo *>( + XContents.data() + UnwindInfoOffset); + + printUnwindInfo(*UI, UnwindInfoOffset, RelocMap[XData]); +} + +void COFFDumper::printUnwindInfo( + const Win64EH::UnwindInfo& UI, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels) { + DictScope D(W, "UnwindInfo"); + W.printNumber("Version", UI.getVersion()); + W.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags)); + W.printNumber("PrologSize", UI.PrologSize); + if (UI.getFrameRegister() != 0) { + W.printEnum("FrameRegister", UI.getFrameRegister(), + makeArrayRef(UnwindOpInfo)); + W.printHex("FrameOffset", UI.getFrameOffset()); + } else { + W.printString("FrameRegister", StringRef("-")); + W.printString("FrameOffset", StringRef("-")); + } + + W.printNumber("UnwindCodeCount", UI.NumCodes); + { + ListScope CodesD(W, "UnwindCodes"); + ArrayRef<UnwindCode> UCs(&UI.UnwindCodes[0], UI.NumCodes); + for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ++I) { + unsigned UsedSlots = getNumUsedSlots(*I); + if (UsedSlots > UCs.size()) { + errs() << "Corrupt unwind data"; + return; + } + printUnwindCode(UI, ArrayRef<UnwindCode>(I, E)); + I += UsedSlots - 1; + } + } + + uint64_t LSDAOffset = OffsetInSection + getOffsetOfLSDA(UI); + if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { + W.printString("Handler", formatSymbol(Rels, LSDAOffset, + UI.getLanguageSpecificHandlerOffset())); + } else if (UI.getFlags() & UNW_ChainInfo) { + const RuntimeFunction *Chained = UI.getChainedFunctionEntry(); + if (Chained) { + DictScope D(W, "Chained"); + W.printString("StartAddress", formatSymbol(Rels, LSDAOffset + 0, + Chained->StartAddress)); + W.printString("EndAddress", formatSymbol(Rels, LSDAOffset + 4, + Chained->EndAddress)); + W.printString("UnwindInfoAddress", formatSymbol(Rels, LSDAOffset + 8, + Chained->UnwindInfoOffset)); + } + } +} + +// Prints one unwind code. Because an unwind code can occupy up to 3 slots in +// the unwind codes array, this function requires that the correct number of +// slots is provided. +void COFFDumper::printUnwindCode(const Win64EH::UnwindInfo& UI, + ArrayRef<UnwindCode> UCs) { + assert(UCs.size() >= getNumUsedSlots(UCs[0])); + + W.startLine() << format("0x%02X: ", unsigned(UCs[0].u.CodeOffset)) + << getUnwindCodeTypeName(UCs[0].getUnwindOp()); + + uint32_t AllocSize = 0; + + switch (UCs[0].getUnwindOp()) { + case UOP_PushNonVol: + outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()); + break; + + case UOP_AllocLarge: + if (UCs[0].getOpInfo() == 0) { + AllocSize = UCs[1].FrameOffset * 8; + } else { + AllocSize = getLargeSlotValue(UCs); + } + outs() << " size=" << AllocSize; + break; + case UOP_AllocSmall: + outs() << " size=" << ((UCs[0].getOpInfo() + 1) * 8); + break; + case UOP_SetFPReg: + if (UI.getFrameRegister() == 0) { + outs() << " reg=<invalid>"; + } else { + outs() << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) + << format(", offset=0x%X", UI.getFrameOffset() * 16); + } + break; + case UOP_SaveNonVol: + outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) + << format(", offset=0x%X", UCs[1].FrameOffset * 8); + break; + case UOP_SaveNonVolBig: + outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) + << format(", offset=0x%X", getLargeSlotValue(UCs)); + break; + case UOP_SaveXMM128: + outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) + << format(", offset=0x%X", UCs[1].FrameOffset * 16); + break; + case UOP_SaveXMM128Big: + outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) + << format(", offset=0x%X", getLargeSlotValue(UCs)); + break; + case UOP_PushMachFrame: + outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes"); + break; + } + + outs() << "\n"; +} diff --git a/tools/llvm-readobj/ELF.cpp b/tools/llvm-readobj/ELF.cpp deleted file mode 100644 index 07f15b3..0000000 --- a/tools/llvm-readobj/ELF.cpp +++ /dev/null @@ -1,196 +0,0 @@ -//===- llvm-readobj/ELF.cpp - ELF Specific Dumper -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm-readobj.h" - -#include "llvm/Object/ELF.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Format.h" - -namespace llvm { -using namespace object; -using namespace ELF; - -const char *getTypeString(uint64_t Type) { - switch (Type) { - case DT_BIND_NOW: - return "(BIND_NOW)"; - case DT_DEBUG: - return "(DEBUG)"; - case DT_FINI: - return "(FINI)"; - case DT_FINI_ARRAY: - return "(FINI_ARRAY)"; - case DT_FINI_ARRAYSZ: - return "(FINI_ARRAYSZ)"; - case DT_FLAGS: - return "(FLAGS)"; - case DT_HASH: - return "(HASH)"; - case DT_INIT: - return "(INIT)"; - case DT_INIT_ARRAY: - return "(INIT_ARRAY)"; - case DT_INIT_ARRAYSZ: - return "(INIT_ARRAYSZ)"; - case DT_PREINIT_ARRAY: - return "(PREINIT_ARRAY)"; - case DT_PREINIT_ARRAYSZ: - return "(PREINIT_ARRAYSZ)"; - case DT_JMPREL: - return "(JMPREL)"; - case DT_NEEDED: - return "(NEEDED)"; - case DT_NULL: - return "(NULL)"; - case DT_PLTGOT: - return "(PLTGOT)"; - case DT_PLTREL: - return "(PLTREL)"; - case DT_PLTRELSZ: - return "(PLTRELSZ)"; - case DT_REL: - return "(REL)"; - case DT_RELA: - return "(RELA)"; - case DT_RELENT: - return "(RELENT)"; - case DT_RELSZ: - return "(RELSZ)"; - case DT_RELAENT: - return "(RELAENT)"; - case DT_RELASZ: - return "(RELASZ)"; - case DT_RPATH: - return "(RPATH)"; - case DT_RUNPATH: - return "(RUNPATH)"; - case DT_SONAME: - return "(SONAME)"; - case DT_STRSZ: - return "(STRSZ)"; - case DT_STRTAB: - return "(STRTAB)"; - case DT_SYMBOLIC: - return "(SYMBOLIC)"; - case DT_SYMENT: - return "(SYMENT)"; - case DT_SYMTAB: - return "(SYMTAB)"; - case DT_TEXTREL: - return "(TEXTREL)"; - default: - return "unknown"; - } -} - -template <class ELFT> -void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, uint64_t Value, - bool Is64, raw_ostream &OS) { - switch (Type) { - case DT_PLTREL: - if (Value == DT_REL) { - OS << "REL"; - break; - } else if (Value == DT_RELA) { - OS << "RELA"; - break; - } - // Fallthrough. - case DT_PLTGOT: - case DT_HASH: - case DT_STRTAB: - case DT_SYMTAB: - case DT_RELA: - case DT_INIT: - case DT_FINI: - case DT_REL: - case DT_JMPREL: - case DT_INIT_ARRAY: - case DT_FINI_ARRAY: - case DT_PREINIT_ARRAY: - case DT_DEBUG: - case DT_NULL: - OS << format("0x%" PRIx64, Value); - break; - case DT_PLTRELSZ: - case DT_RELASZ: - case DT_RELAENT: - case DT_STRSZ: - case DT_SYMENT: - case DT_RELSZ: - case DT_RELENT: - case DT_INIT_ARRAYSZ: - case DT_FINI_ARRAYSZ: - case DT_PREINIT_ARRAYSZ: - OS << Value << " (bytes)"; - break; - case DT_NEEDED: - OS << "Shared library: [" - << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]"; - break; - case DT_SONAME: - OS << "Library soname: [" - << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]"; - break; - } -} - -template <class ELFT> -ErrorOr<void> dumpDynamicTable(const ELFObjectFile<ELFT> *O, raw_ostream &OS) { - typedef ELFObjectFile<ELFT> ELFO; - typedef typename ELFO::Elf_Dyn_iterator EDI; - EDI Start = O->begin_dynamic_table(), - End = O->end_dynamic_table(true); - - if (Start == End) - return error_code::success(); - - ptrdiff_t Total = std::distance(Start, End); - OS << "Dynamic section contains " << Total << " entries\n"; - - bool Is64 = O->getBytesInAddress() == 8; - - OS << " Tag" << (Is64 ? " " : " ") << "Type" - << " " << "Name/Value\n"; - for (; Start != End; ++Start) { - OS << " " - << format(Is64 ? "0x%016" PRIx64 : "0x%08" PRIx64, Start->getTag()) - << " " << format("%-21s", getTypeString(Start->getTag())); - printValue(O, Start->getTag(), Start->getVal(), Is64, OS); - OS << "\n"; - } - - OS << " Total: " << Total << "\n\n"; - return error_code::success(); -} - -ErrorOr<void> dumpELFDynamicTable(ObjectFile *O, raw_ostream &OS) { - // Little-endian 32-bit - if (const ELFObjectFile<ELFType<support::little, 4, false> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::little, 4, false> > >(O)) - return dumpDynamicTable(ELFObj, OS); - - // Big-endian 32-bit - if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(O)) - return dumpDynamicTable(ELFObj, OS); - - // Little-endian 64-bit - if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(O)) - return dumpDynamicTable(ELFObj, OS); - - // Big-endian 64-bit - if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(O)) - return dumpDynamicTable(ELFObj, OS); - return error_code(object_error::invalid_file_type); -} -} // end namespace llvm diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp new file mode 100644 index 0000000..3628c3b --- /dev/null +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -0,0 +1,848 @@ +//===-- ELFDumper.cpp - ELF-specific dumper ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the ELF-specific dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; +using namespace ELF; + + +#define LLVM_READOBJ_ENUM_CASE(ns, enum) \ + case ns::enum: return #enum; + +namespace { + +template<typename ELFT> +class ELFDumper : public ObjDumper { +public: + ELFDumper(const ELFObjectFile<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; + + virtual void printDynamicTable() LLVM_OVERRIDE; + virtual void printNeededLibraries() LLVM_OVERRIDE; + virtual void printProgramHeaders() LLVM_OVERRIDE; + +private: + typedef ELFObjectFile<ELFT> ELFO; + typedef typename ELFO::Elf_Shdr Elf_Shdr; + typedef typename ELFO::Elf_Sym Elf_Sym; + + void printSymbol(symbol_iterator SymI, bool IsDynamic = false); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + const ELFO *Obj; +}; + +} // namespace + + +namespace llvm { + +template <class ELFT> +static error_code createELFDumper(const ELFObjectFile<ELFT> *Obj, + StreamWriter &Writer, + OwningPtr<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) { + // Little-endian 32-bit + if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) + return createELFDumper(ELFObj, Writer, Result); + + // Big-endian 32-bit + if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) + return createELFDumper(ELFObj, Writer, Result); + + // Little-endian 64-bit + if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) + return createELFDumper(ELFObj, Writer, Result); + + // Big-endian 64-bit + if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) + return createELFDumper(ELFObj, Writer, Result); + + return readobj_error::unsupported_obj_file_format; +} + +} // namespace llvm + + +static const EnumEntry<unsigned> ElfClass[] = { + { "None", ELF::ELFCLASSNONE }, + { "32-bit", ELF::ELFCLASS32 }, + { "64-bit", ELF::ELFCLASS64 }, +}; + +static const EnumEntry<unsigned> ElfDataEncoding[] = { + { "None", ELF::ELFDATANONE }, + { "LittleEndian", ELF::ELFDATA2LSB }, + { "BigEndian", ELF::ELFDATA2MSB }, +}; + +static const EnumEntry<unsigned> ElfObjectFileType[] = { + { "None", ELF::ET_NONE }, + { "Relocatable", ELF::ET_REL }, + { "Executable", ELF::ET_EXEC }, + { "SharedObject", ELF::ET_DYN }, + { "Core", ELF::ET_CORE }, +}; + +static const EnumEntry<unsigned> ElfOSABI[] = { + { "SystemV", ELF::ELFOSABI_NONE }, + { "HPUX", ELF::ELFOSABI_HPUX }, + { "NetBSD", ELF::ELFOSABI_NETBSD }, + { "GNU/Linux", ELF::ELFOSABI_LINUX }, + { "GNU/Hurd", ELF::ELFOSABI_HURD }, + { "Solaris", ELF::ELFOSABI_SOLARIS }, + { "AIX", ELF::ELFOSABI_AIX }, + { "IRIX", ELF::ELFOSABI_IRIX }, + { "FreeBSD", ELF::ELFOSABI_FREEBSD }, + { "TRU64", ELF::ELFOSABI_TRU64 }, + { "Modesto", ELF::ELFOSABI_MODESTO }, + { "OpenBSD", ELF::ELFOSABI_OPENBSD }, + { "OpenVMS", ELF::ELFOSABI_OPENVMS }, + { "NSK", ELF::ELFOSABI_NSK }, + { "AROS", ELF::ELFOSABI_AROS }, + { "FenixOS", ELF::ELFOSABI_FENIXOS }, + { "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI }, + { "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX }, + { "ARM", ELF::ELFOSABI_ARM }, + { "Standalone" , ELF::ELFOSABI_STANDALONE } +}; + +static const EnumEntry<unsigned> ElfMachineType[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EM_NONE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_386 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_88K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_486 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_860 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_S370 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_RS3_LE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PARISC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VPP500 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC32PLUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_960 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_S390 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPU ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_V800 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FR20 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RH32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RCE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARM ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ALPHA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SH ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARCV9 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TRICORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300H ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8S ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_500 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_IA_64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_COLDFIRE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC12 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MMA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PCP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NCPU ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NDR1 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_STARCORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ME16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST100 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TINYJ ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_X86_64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PDSP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP10 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP11 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FX66 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST9PLUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST7 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC11 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC08 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC05 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SVX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST19 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VAX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CRIS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_JAVELIN ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FIREPATH ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ZSP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MMIX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_HUANY ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PRISM ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FR30 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_D10V ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_D30V ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_V850 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M32R ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10300 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10200 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PJ ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_OPENRISC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_XTENSA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TMM_GPP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NS32K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TPC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SNP1K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST200 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_IP2K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MAX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CR ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_F2MC16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MSP430 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_BLACKFIN ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C33 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SEP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARCA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_UNICORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_EXCESS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_DXP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ALTERA_NIOS2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CRX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_XGATE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_C166 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M16C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_DSPIC30F ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M32C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TSK3000 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RS08 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SHARC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SCORE7 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_DSP24 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE3 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_LATTICEMICO32), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C17 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C6000 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C2000 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C5500 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MMDSP_PLUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CYPRESS_M8C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_R32C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TRIMEDIA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_HEXAGON ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_8051 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_STXP7X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NDS32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MAXQ30 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_XIMO16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MANIK ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CRAYNV2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_METAG ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MCST_ELBRUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CR16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ETPU ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SLE9X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_L10M ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_K10M ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_AARCH64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_STM8 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TILE64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEPRO ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CUDA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEGX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CLOUDSHIELD ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_1ST ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_2ND ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_OPEN8 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RL78 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE5 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_78KOR ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_56800EX ) +}; + +static const EnumEntry<unsigned> ElfSymbolBindings[] = { + { "Local", ELF::STB_LOCAL }, + { "Global", ELF::STB_GLOBAL }, + { "Weak", ELF::STB_WEAK } +}; + +static const EnumEntry<unsigned> ElfSymbolTypes[] = { + { "None", ELF::STT_NOTYPE }, + { "Object", ELF::STT_OBJECT }, + { "Function", ELF::STT_FUNC }, + { "Section", ELF::STT_SECTION }, + { "File", ELF::STT_FILE }, + { "Common", ELF::STT_COMMON }, + { "TLS", ELF::STT_TLS }, + { "GNU_IFunc", ELF::STT_GNU_IFUNC } +}; + +static const char *getElfSectionType(unsigned Arch, unsigned Type) { + switch (Arch) { + case Triple::arm: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION); + } + case Triple::hexagon: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); + } + case Triple::x86_64: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); + } + case Triple::mips: + case Triple::mipsel: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); + } + } + + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_NULL ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_PROGBITS ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_STRTAB ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_RELA ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_HASH ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNAMIC ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOTE ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOBITS ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_REL ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_SHLIB ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNSYM ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_INIT_ARRAY ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_FINI_ARRAY ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_PREINIT_ARRAY ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GROUP ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_HASH ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verdef ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verneed ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_versym ); + default: return ""; + } +} + +static const EnumEntry<unsigned> ElfSectionFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, SHF_WRITE ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_ALLOC ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_INFO_LINK ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_LINK_ORDER ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_OS_NONCONFORMING), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_GROUP ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ), + LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION), + LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ) +}; + +static const EnumEntry<unsigned> ElfSegmentTypes[] = { + LLVM_READOBJ_ENUM_ENT(ELF, PT_NULL ), + LLVM_READOBJ_ENUM_ENT(ELF, PT_LOAD ), + LLVM_READOBJ_ENUM_ENT(ELF, PT_DYNAMIC), + LLVM_READOBJ_ENUM_ENT(ELF, PT_INTERP ), + LLVM_READOBJ_ENUM_ENT(ELF, PT_NOTE ), + LLVM_READOBJ_ENUM_ENT(ELF, PT_SHLIB ), + LLVM_READOBJ_ENUM_ENT(ELF, PT_PHDR ), + LLVM_READOBJ_ENUM_ENT(ELF, PT_TLS ), + + LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_EH_FRAME), + LLVM_READOBJ_ENUM_ENT(ELF, PT_SUNW_EH_FRAME), + LLVM_READOBJ_ENUM_ENT(ELF, PT_SUNW_UNWIND), + + LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_STACK), + LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_RELRO), + + LLVM_READOBJ_ENUM_ENT(ELF, PT_ARM_EXIDX), + LLVM_READOBJ_ENUM_ENT(ELF, PT_ARM_UNWIND) +}; + +static const EnumEntry<unsigned> ElfSegmentFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, PF_X), + LLVM_READOBJ_ENUM_ENT(ELF, PF_W), + LLVM_READOBJ_ENUM_ENT(ELF, PF_R) +}; + + +template<class ELFT> +void ELFDumper<ELFT>::printFileHeaders() { + error_code EC; + + const typename ELFO::Elf_Ehdr *Header = Obj->getElfHeader(); + + { + DictScope D(W, "ElfHeader"); + { + DictScope D(W, "Ident"); + W.printBinary("Magic", makeArrayRef(Header->e_ident).slice(ELF::EI_MAG0, + 4)); + W.printEnum ("Class", Header->e_ident[ELF::EI_CLASS], + makeArrayRef(ElfClass)); + W.printEnum ("DataEncoding", Header->e_ident[ELF::EI_DATA], + makeArrayRef(ElfDataEncoding)); + W.printNumber("FileVersion", Header->e_ident[ELF::EI_VERSION]); + W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI], + makeArrayRef(ElfOSABI)); + W.printNumber("ABIVersion", Header->e_ident[ELF::EI_ABIVERSION]); + W.printBinary("Unused", makeArrayRef(Header->e_ident).slice(ELF::EI_PAD)); + } + + W.printEnum ("Type", Header->e_type, makeArrayRef(ElfObjectFileType)); + W.printEnum ("Machine", Header->e_machine, makeArrayRef(ElfMachineType)); + W.printNumber("Version", Header->e_version); + W.printHex ("Entry", Header->e_entry); + W.printHex ("ProgramHeaderOffset", Header->e_phoff); + W.printHex ("SectionHeaderOffset", Header->e_shoff); + W.printFlags ("Flags", Header->e_flags); + W.printNumber("HeaderSize", Header->e_ehsize); + W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize); + W.printNumber("ProgramHeaderCount", Header->e_phnum); + W.printNumber("SectionHeaderEntrySize", Header->e_shentsize); + W.printNumber("SectionHeaderCount", Header->e_shnum); + W.printNumber("StringTableSectionIndex", Header->e_shstrndx); + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printSections() { + ListScope SectionsD(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; + + ++SectionIndex; + + const Elf_Shdr *Section = Obj->getElfSection(SecI); + StringRef Name; + if (error(SecI->getName(Name))) + Name = ""; + + DictScope SectionD(W, "Section"); + W.printNumber("Index", SectionIndex); + W.printNumber("Name", Name, Section->sh_name); + W.printHex ("Type", getElfSectionType(Obj->getArch(), Section->sh_type), + Section->sh_type); + W.printFlags ("Flags", Section->sh_flags, makeArrayRef(ElfSectionFlags)); + W.printHex ("Address", Section->sh_addr); + W.printHex ("Offset", Section->sh_offset); + W.printNumber("Size", Section->sh_size); + W.printNumber("Link", Section->sh_link); + W.printNumber("Info", Section->sh_info); + W.printNumber("AddressAlignment", Section->sh_addralign); + W.printNumber("EntrySize", Section->sh_entsize); + + 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); + } + } + + 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; + + bool Contained = false; + if (SecI->containsSymbol(*SymI, Contained) || !Contained) + continue; + + printSymbol(SymI); + } + } + + if (opts::SectionData) { + StringRef Data; + if (error(SecI->getContents(Data))) break; + + W.printBinaryBlock("SectionData", Data); + } + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printRelocations() { + ListScope D(W, "Relocations"); + + error_code EC; + int SectionNumber = -1; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + ++SectionNumber; + StringRef Name; + if (error(SecI->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; + + if (!PrintedGroup) { + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(SecI, RelI); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printRelocation(section_iterator Sec, + relocation_iterator RelI) { + uint64_t Offset; + uint64_t RelocType; + SmallString<32> RelocName; + int64_t Addend; + StringRef SymbolName; + if (Obj->getElfHeader()->e_type == ELF::ET_REL){ + if (error(RelI->getOffset(Offset))) return; + } else { + if (error(RelI->getAddress(Offset))) return; + } + if (error(RelI->getType(RelocType))) return; + if (error(RelI->getTypeName(RelocName))) return; + if (error(getELFRelocationAddend(*RelI, Addend))) return; + symbol_iterator Symbol = RelI->getSymbol(); + if (Symbol != Obj->end_symbols() && error(Symbol->getName(SymbolName))) + return; + + if (opts::ExpandRelocs) { + DictScope Group(W, "Relocation"); + W.printHex("Offset", Offset); + W.printNumber("Type", RelocName, RelocType); + W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); + W.printHex("Addend", Addend); + } else { + raw_ostream& OS = W.startLine(); + OS << W.hex(Offset) + << " " << RelocName + << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << " " << W.hex(Addend) + << "\n"; + } +} + +template<class ELFT> +void ELFDumper<ELFT>::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); + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printDynamicSymbols() { + ListScope Group(W, "DynamicSymbols"); + + error_code EC; + for (symbol_iterator SymI = Obj->begin_dynamic_symbols(), + SymE = Obj->end_dynamic_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + printSymbol(SymI, true); + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printSymbol(symbol_iterator SymI, bool IsDynamic) { + error_code EC; + + const Elf_Sym *Symbol = Obj->getElfSymbol(SymI); + const Elf_Shdr *Section = Obj->getSection(Symbol); + + StringRef SymbolName; + if (SymI->getName(SymbolName)) + SymbolName = ""; + + StringRef SectionName = ""; + if (Section) + Obj->getSectionName(Section, SectionName); + + std::string FullSymbolName(SymbolName); + if (IsDynamic) { + StringRef Version; + bool IsDefault; + if (error(Obj->getSymbolVersion(*SymI, Version, IsDefault))) + return; + if (!Version.empty()) { + FullSymbolName += (IsDefault ? "@@" : "@"); + FullSymbolName += Version; + } + } + + DictScope D(W, "Symbol"); + W.printNumber("Name", FullSymbolName, Symbol->st_name); + W.printHex ("Value", Symbol->st_value); + W.printNumber("Size", Symbol->st_size); + W.printEnum ("Binding", Symbol->getBinding(), + makeArrayRef(ElfSymbolBindings)); + W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes)); + W.printNumber("Other", Symbol->st_other); + W.printHex ("Section", SectionName, Symbol->st_shndx); +} + +#define LLVM_READOBJ_TYPE_CASE(name) \ + case DT_##name: return #name + +static const char *getTypeString(uint64_t Type) { + switch (Type) { + LLVM_READOBJ_TYPE_CASE(BIND_NOW); + LLVM_READOBJ_TYPE_CASE(DEBUG); + LLVM_READOBJ_TYPE_CASE(FINI); + LLVM_READOBJ_TYPE_CASE(FINI_ARRAY); + LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ); + LLVM_READOBJ_TYPE_CASE(FLAGS); + LLVM_READOBJ_TYPE_CASE(HASH); + LLVM_READOBJ_TYPE_CASE(INIT); + LLVM_READOBJ_TYPE_CASE(INIT_ARRAY); + LLVM_READOBJ_TYPE_CASE(INIT_ARRAYSZ); + LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAY); + LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAYSZ); + LLVM_READOBJ_TYPE_CASE(JMPREL); + LLVM_READOBJ_TYPE_CASE(NEEDED); + LLVM_READOBJ_TYPE_CASE(NULL); + LLVM_READOBJ_TYPE_CASE(PLTGOT); + LLVM_READOBJ_TYPE_CASE(PLTREL); + LLVM_READOBJ_TYPE_CASE(PLTRELSZ); + LLVM_READOBJ_TYPE_CASE(REL); + LLVM_READOBJ_TYPE_CASE(RELA); + LLVM_READOBJ_TYPE_CASE(RELENT); + LLVM_READOBJ_TYPE_CASE(RELSZ); + LLVM_READOBJ_TYPE_CASE(RELAENT); + LLVM_READOBJ_TYPE_CASE(RELASZ); + LLVM_READOBJ_TYPE_CASE(RPATH); + LLVM_READOBJ_TYPE_CASE(RUNPATH); + LLVM_READOBJ_TYPE_CASE(SONAME); + LLVM_READOBJ_TYPE_CASE(STRSZ); + LLVM_READOBJ_TYPE_CASE(STRTAB); + LLVM_READOBJ_TYPE_CASE(SYMBOLIC); + LLVM_READOBJ_TYPE_CASE(SYMENT); + LLVM_READOBJ_TYPE_CASE(SYMTAB); + LLVM_READOBJ_TYPE_CASE(TEXTREL); + default: return "unknown"; + } +} + +#undef LLVM_READOBJ_TYPE_CASE + +template<class ELFT> +static void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, + uint64_t Value, bool Is64, raw_ostream &OS) { + switch (Type) { + case DT_PLTREL: + if (Value == DT_REL) { + OS << "REL"; + break; + } else if (Value == DT_RELA) { + OS << "RELA"; + break; + } + // Fallthrough. + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + case DT_DEBUG: + case DT_NULL: + OS << format("0x%" PRIX64, Value); + break; + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_RELSZ: + case DT_RELENT: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_PREINIT_ARRAYSZ: + OS << Value << " (bytes)"; + break; + case DT_NEEDED: + OS << "SharedLibrary (" + << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + break; + case DT_SONAME: + OS << "LibrarySoname (" + << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + break; + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printUnwindInfo() { + W.startLine() << "UnwindInfo not implemented.\n"; +} + +template<class ELFT> +void ELFDumper<ELFT>::printDynamicTable() { + typedef typename ELFO::Elf_Dyn_iterator EDI; + EDI Start = Obj->begin_dynamic_table(), + End = Obj->end_dynamic_table(true); + + if (Start == End) + return; + + ptrdiff_t Total = std::distance(Start, End); + raw_ostream &OS = W.getOStream(); + W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; + + bool Is64 = Obj->getBytesInAddress() == 8; + + W.startLine() + << " Tag" << (Is64 ? " " : " ") << "Type" + << " " << "Name/Value\n"; + for (; Start != End; ++Start) { + W.startLine() + << " " + << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Start->getTag()) + << " " << format("%-21s", getTypeString(Start->getTag())); + printValue(Obj, Start->getTag(), Start->getVal(), Is64, OS); + OS << "\n"; + } + + W.startLine() << "]\n"; +} + +static bool compareLibraryName(const LibraryRef &L, const LibraryRef &R) { + StringRef LPath, RPath; + L.getPath(LPath); + R.getPath(RPath); + return LPath < RPath; +} + +template<class ELFT> +void ELFDumper<ELFT>::printNeededLibraries() { + ListScope D(W, "NeededLibraries"); + + error_code EC; + + typedef std::vector<LibraryRef> LibsTy; + LibsTy Libs; + + for (library_iterator I = Obj->begin_libraries_needed(), + E = Obj->end_libraries_needed(); + I != E; I.increment(EC)) { + if (EC) + report_fatal_error("Needed libraries iteration failed"); + + Libs.push_back(*I); + } + + std::sort(Libs.begin(), Libs.end(), &compareLibraryName); + + for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); + I != E; ++I) { + StringRef Path; + I->getPath(Path); + outs() << " " << Path << "\n"; + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printProgramHeaders() { + ListScope L(W, "ProgramHeaders"); + + for (typename ELFO::Elf_Phdr_Iter PI = Obj->begin_program_headers(), + PE = Obj->end_program_headers(); + PI != PE; ++PI) { + DictScope P(W, "ProgramHeader"); + W.printEnum ("Type", PI->p_type, makeArrayRef(ElfSegmentTypes)); + W.printHex ("Offset", PI->p_offset); + W.printHex ("VirtualAddress", PI->p_vaddr); + W.printHex ("PhysicalAddress", PI->p_paddr); + W.printNumber("FileSize", PI->p_filesz); + W.printNumber("MemSize", PI->p_memsz); + W.printFlags ("Flags", PI->p_flags, makeArrayRef(ElfSegmentFlags)); + W.printNumber("Alignment", PI->p_align); + } +} diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp new file mode 100644 index 0000000..a6c6132 --- /dev/null +++ b/tools/llvm-readobj/Error.cpp @@ -0,0 +1,62 @@ +//===- Error.cpp - system_error extensions for llvm-readobj -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines a new error_category for the llvm-readobj tool. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { +class _readobj_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; + virtual error_condition default_error_condition(int ev) const; +}; +} // namespace + +const char *_readobj_error_category::name() const { + return "llvm.readobj"; +} + +std::string _readobj_error_category::message(int ev) const { + switch (ev) { + case readobj_error::success: return "Success"; + case readobj_error::file_not_found: + return "No such file."; + case readobj_error::unsupported_file_format: + return "The file was not recognized as a valid object file."; + case readobj_error::unrecognized_file_format: + return "Unrecognized file type."; + case readobj_error::unsupported_obj_file_format: + return "Unsupported object file format."; + case readobj_error::unknown_symbol: + return "Unknown symbol."; + default: + llvm_unreachable("An enumerator of readobj_error does not have a message " + "defined."); + } +} + +error_condition _readobj_error_category::default_error_condition(int ev) const { + if (ev == readobj_error::success) + return errc::success; + return errc::invalid_argument; +} + +namespace llvm { +const error_category &readobj_category() { + static _readobj_error_category o; + return o; +} +} // namespace llvm diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h new file mode 100644 index 0000000..cf68da8 --- /dev/null +++ b/tools/llvm-readobj/Error.h @@ -0,0 +1,48 @@ +//===- Error.h - system_error extensions for llvm-readobj -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This declares a new error_category for the llvm-readobj tool. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ERROR_H +#define LLVM_READOBJ_ERROR_H + +#include "llvm/Support/system_error.h" + +namespace llvm { + +const error_category &readobj_category(); + +struct readobj_error { + enum _ { + success = 0, + file_not_found, + unsupported_file_format, + unrecognized_file_format, + unsupported_obj_file_format, + unknown_symbol + }; + _ v_; + + readobj_error(_ v) : v_(v) {} + explicit readobj_error(int v) : v_(_(v)) {} + operator int() const {return v_;} +}; + +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 { }; + +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/LLVMBuild.txt b/tools/llvm-readobj/LLVMBuild.txt index c9f934f..e75f195 100644 --- a/tools/llvm-readobj/LLVMBuild.txt +++ b/tools/llvm-readobj/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-readobj parent = Tools -required_libraries = Archive BitReader Object +required_libraries = all-targets BitReader Object diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp new file mode 100644 index 0000000..8df6fd6 --- /dev/null +++ b/tools/llvm-readobj/MachODumper.cpp @@ -0,0 +1,433 @@ +//===-- MachODump.cpp - Object file dumping utility for llvm --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MachO-specific dumper for llvm-readobj. +// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Casting.h" + +using namespace llvm; +using namespace object; + +namespace { + +class MachODumper : public ObjDumper { +public: + MachODumper(const MachOObjectFile *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; + +private: + void printSymbol(symbol_iterator SymI); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + void printRelocation(const MachOObjectFile *Obj, + section_iterator SecI, relocation_iterator RelI); + + void printSections(const MachOObjectFile *Obj); + + const MachOObjectFile *Obj; +}; + +} // namespace + + +namespace llvm { + +error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result) { + const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); + if (!MachOObj) + return readobj_error::unsupported_obj_file_format; + + Result.reset(new MachODumper(MachOObj, Writer)); + return readobj_error::success; +} + +} // namespace llvm + + +static const EnumEntry<unsigned> MachOSectionTypes[] = { + { "Regular" , 0x00 }, + { "ZeroFill" , 0x01 }, + { "CStringLiterals" , 0x02 }, + { "4ByteLiterals" , 0x03 }, + { "8ByteLiterals" , 0x04 }, + { "LiteralPointers" , 0x05 }, + { "NonLazySymbolPointers" , 0x06 }, + { "LazySymbolPointers" , 0x07 }, + { "SymbolStubs" , 0x08 }, + { "ModInitFuncs" , 0x09 }, + { "ModTermFuncs" , 0x0A }, + { "Coalesced" , 0x0B }, + { "GBZeroFill" , 0x0C }, + { "Interposing" , 0x0D }, + { "16ByteLiterals" , 0x0E }, + { "DTraceDOF" , 0x0F }, + { "LazyDylibSymbolPoints" , 0x10 }, + { "ThreadLocalRegular" , 0x11 }, + { "ThreadLocalZerofill" , 0x12 }, + { "ThreadLocalVariables" , 0x13 }, + { "ThreadLocalVariablePointers" , 0x14 }, + { "ThreadLocalInitFunctionPointers", 0x15 } +}; + +static const EnumEntry<unsigned> MachOSectionAttributes[] = { + { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ }, + { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ }, + { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ }, + { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ }, + { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ }, + { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ }, + { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ }, + { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ }, + { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ }, + { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ }, +}; + +static const EnumEntry<unsigned> MachOSymbolRefTypes[] = { + { "UndefinedNonLazy", 0 }, + { "ReferenceFlagUndefinedLazy", 1 }, + { "ReferenceFlagDefined", 2 }, + { "ReferenceFlagPrivateDefined", 3 }, + { "ReferenceFlagPrivateUndefinedNonLazy", 4 }, + { "ReferenceFlagPrivateUndefinedLazy", 5 } +}; + +static const EnumEntry<unsigned> MachOSymbolFlags[] = { + { "ReferencedDynamically", 0x10 }, + { "NoDeadStrip", 0x20 }, + { "WeakRef", 0x40 }, + { "WeakDef", 0x80 } +}; + +static const EnumEntry<unsigned> MachOSymbolTypes[] = { + { "Undef", 0x0 }, + { "External", 0x1 }, + { "Abs", 0x2 }, + { "Indirect", 0xA }, + { "PreboundUndef", 0xC }, + { "Section", 0xE }, + { "PrivateExternal", 0x10 } +}; + +namespace { + enum { + N_STAB = 0xE0 + }; + + struct MachOSection { + ArrayRef<char> Name; + ArrayRef<char> SegmentName; + uint64_t Address; + uint64_t Size; + uint32_t Offset; + uint32_t Alignment; + uint32_t RelocationTableOffset; + uint32_t NumRelocationTableEntries; + uint32_t Flags; + uint32_t Reserved1; + uint32_t Reserved2; + }; + + struct MachOSymbol { + uint32_t StringIndex; + uint8_t Type; + uint8_t SectionIndex; + uint16_t Flags; + uint64_t Value; + }; +} + +static void getSection(const MachOObjectFile *Obj, + DataRefImpl Sec, + MachOSection &Section) { + if (!Obj->is64Bit()) { + macho::Section Sect = Obj->getSection(Sec); + Section.Address = Sect.Address; + Section.Size = Sect.Size; + Section.Offset = Sect.Offset; + Section.Alignment = Sect.Align; + Section.RelocationTableOffset = Sect.RelocationTableOffset; + Section.NumRelocationTableEntries = Sect.NumRelocationTableEntries; + Section.Flags = Sect.Flags; + Section.Reserved1 = Sect.Reserved1; + Section.Reserved2 = Sect.Reserved2; + return; + } + macho::Section64 Sect = Obj->getSection64(Sec); + Section.Address = Sect.Address; + Section.Size = Sect.Size; + Section.Offset = Sect.Offset; + Section.Alignment = Sect.Align; + Section.RelocationTableOffset = Sect.RelocationTableOffset; + Section.NumRelocationTableEntries = Sect.NumRelocationTableEntries; + Section.Flags = Sect.Flags; + Section.Reserved1 = Sect.Reserved1; + Section.Reserved2 = Sect.Reserved2; +} + + +static void getSymbol(const MachOObjectFile *Obj, + DataRefImpl DRI, + MachOSymbol &Symbol) { + if (!Obj->is64Bit()) { + macho::SymbolTableEntry Entry = Obj->getSymbolTableEntry(DRI); + Symbol.StringIndex = Entry.StringIndex; + Symbol.Type = Entry.Type; + Symbol.SectionIndex = Entry.SectionIndex; + Symbol.Flags = Entry.Flags; + Symbol.Value = Entry.Value; + return; + } + macho::Symbol64TableEntry Entry = Obj->getSymbol64TableEntry(DRI); + Symbol.StringIndex = Entry.StringIndex; + Symbol.Type = Entry.Type; + Symbol.SectionIndex = Entry.SectionIndex; + Symbol.Flags = Entry.Flags; + Symbol.Value = Entry.Value; +} + +void MachODumper::printFileHeaders() { + W.startLine() << "FileHeaders not implemented.\n"; +} + +void MachODumper::printSections() { + return printSections(Obj); +} + +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; + + ++SectionIndex; + + MachOSection Section; + getSection(Obj, SecI->getRawDataRefImpl(), Section); + DataRefImpl DR = SecI->getRawDataRefImpl(); + + StringRef Name; + if (error(SecI->getName(Name))) + Name = ""; + + ArrayRef<char> RawName = Obj->getSectionRawName(DR); + StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); + ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR); + + DictScope SectionD(W, "Section"); + 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); + + 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); + } + } + + 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; + + bool Contained = false; + if (SecI->containsSymbol(*SymI, Contained) || !Contained) + continue; + + printSymbol(SymI); + } + } + + if (opts::SectionData) { + StringRef Data; + if (error(SecI->getContents(Data))) break; + + W.printBinaryBlock("SectionData", Data); + } + } +} + +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; + + StringRef Name; + if (error(SecI->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; + + if (!PrintedGroup) { + W.startLine() << "Section " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(SecI, RelI); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +void MachODumper::printRelocation(section_iterator SecI, + relocation_iterator RelI) { + return printRelocation(Obj, SecI, RelI); +} + +void MachODumper::printRelocation(const MachOObjectFile *Obj, + section_iterator SecI, + relocation_iterator RelI) { + 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))) + return; + + DataRefImpl DR = RelI->getRawDataRefImpl(); + macho::RelocationEntry RE = Obj->getRelocation(DR); + bool IsScattered = Obj->isRelocationScattered(RE); + + if (opts::ExpandRelocs) { + DictScope Group(W, "Relocation"); + W.printHex("Offset", Offset); + W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE)); + W.printNumber("Length", Obj->getAnyRelocationLength(RE)); + if (IsScattered) + W.printString("Extern", StringRef("N/A")); + else + W.printNumber("Extern", Obj->getPlainRelocationExternal(RE)); + W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE)); + W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); + W.printNumber("Scattered", IsScattered); + } else { + raw_ostream& OS = W.startLine(); + OS << W.hex(Offset) + << " " << Obj->getAnyRelocationPCRel(RE) + << " " << Obj->getAnyRelocationLength(RE); + if (IsScattered) + OS << " n/a"; + else + OS << " " << Obj->getPlainRelocationExternal(RE); + OS << " " << RelocName + << " " << IsScattered + << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << "\n"; + } +} + +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); + } +} + +void MachODumper::printDynamicSymbols() { + ListScope Group(W, "DynamicSymbols"); +} + +void MachODumper::printSymbol(symbol_iterator SymI) { + error_code EC; + + StringRef SymbolName; + if (SymI->getName(SymbolName)) + SymbolName = ""; + + MachOSymbol Symbol; + getSymbol(Obj, SymI->getRawDataRefImpl(), Symbol); + + StringRef SectionName = ""; + section_iterator SecI(Obj->end_sections()); + if (!error(SymI->getSection(SecI)) && + SecI != Obj->end_sections()) + 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); + } else { + W.printEnum("Type", Symbol.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); +} + +void MachODumper::printUnwindInfo() { + W.startLine() << "UnwindInfo not implemented.\n"; +} diff --git a/tools/llvm-readobj/Makefile b/tools/llvm-readobj/Makefile index a7a7de3..958bd0c 100644 --- a/tools/llvm-readobj/Makefile +++ b/tools/llvm-readobj/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-readobj -LINK_COMPONENTS := archive bitreader object +LINK_COMPONENTS := bitreader object all-targets # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp new file mode 100644 index 0000000..61f5117 --- /dev/null +++ b/tools/llvm-readobj/ObjDumper.cpp @@ -0,0 +1,33 @@ +//===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements ObjDumper. +/// +//===----------------------------------------------------------------------===// + +#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" + +namespace llvm { + +ObjDumper::ObjDumper(StreamWriter& Writer) + : W(Writer) { +} + +ObjDumper::~ObjDumper() { +} + +} // namespace llvm diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h new file mode 100644 index 0000000..6918e28 --- /dev/null +++ b/tools/llvm-readobj/ObjDumper.h @@ -0,0 +1,61 @@ +//===-- ObjDumper.h -------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_OBJDUMPER_H +#define LLVM_READOBJ_OBJDUMPER_H + +namespace llvm { + +namespace object { + class ObjectFile; +} + +class error_code; + +template<typename T> +class OwningPtr; + +class StreamWriter; + +class ObjDumper { +public: + ObjDumper(StreamWriter& Writer); + virtual ~ObjDumper(); + + virtual void printFileHeaders() = 0; + virtual void printSections() = 0; + virtual void printRelocations() = 0; + virtual void printSymbols() = 0; + virtual void printDynamicSymbols() = 0; + virtual void printUnwindInfo() = 0; + + // Only implemented for ELF at this time. + virtual void printDynamicTable() { } + virtual void printNeededLibraries() { } + virtual void printProgramHeaders() { } + +protected: + StreamWriter& W; +}; + +error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result); + +error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result); + +error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result); + +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/StreamWriter.cpp b/tools/llvm-readobj/StreamWriter.cpp new file mode 100644 index 0000000..8718112 --- /dev/null +++ b/tools/llvm-readobj/StreamWriter.cpp @@ -0,0 +1,79 @@ +#include "StreamWriter.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Format.h" +#include <cctype> + +using namespace llvm::support; + +namespace llvm { + +raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value) { + uint64_t N = Value.Value; + // Zero is a special case. + if (N == 0) + return OS << "0x0"; + + char NumberBuffer[20]; + char *EndPtr = NumberBuffer + sizeof(NumberBuffer); + char *CurPtr = EndPtr; + + while (N) { + uintptr_t X = N % 16; + *--CurPtr = (X < 10 ? '0' + X : 'A' + X - 10); + N /= 16; + } + + OS << "0x"; + return OS.write(CurPtr, EndPtr - CurPtr); +} + +void StreamWriter::printBinaryImpl(StringRef Label, StringRef Str, + ArrayRef<uint8_t> Data, bool Block) { + if (Data.size() > 16) + Block = true; + + if (Block) { + startLine() << Label; + if (Str.size() > 0) + OS << ": " << Str; + OS << " (\n"; + for (size_t addr = 0, end = Data.size(); addr < end; addr += 16) { + startLine() << format(" %04" PRIX64 ": ", uint64_t(addr)); + // Dump line of hex. + for (size_t i = 0; i < 16; ++i) { + if (i != 0 && i % 4 == 0) + OS << ' '; + if (addr + i < end) + OS << hexdigit((Data[addr + i] >> 4) & 0xF, false) + << hexdigit(Data[addr + i] & 0xF, false); + else + OS << " "; + } + // Print ascii. + OS << " |"; + for (std::size_t i = 0; i < 16 && addr + i < end; ++i) { + if (std::isprint(Data[addr + i] & 0xFF)) + OS << Data[addr + i]; + else + OS << "."; + } + OS << "|\n"; + } + + startLine() << ")\n"; + } else { + startLine() << Label << ":"; + if (Str.size() > 0) + OS << " " << Str; + OS << " ("; + for (size_t i = 0; i < Data.size(); ++i) { + if (i > 0) + OS << " "; + + OS << format("%02X", static_cast<int>(Data[i])); + } + OS << ")\n"; + } +} + +} // namespace llvm diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h new file mode 100644 index 0000000..129f6e7 --- /dev/null +++ b/tools/llvm-readobj/StreamWriter.h @@ -0,0 +1,282 @@ +//===-- StreamWriter.h ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_STREAMWRITER_H +#define LLVM_READOBJ_STREAMWRITER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +using namespace llvm; +using namespace llvm::support; + +namespace llvm { + +template<typename T> +struct EnumEntry { + StringRef Name; + T Value; +}; + +struct HexNumber { + // To avoid sign-extension we have to explicitly cast to the appropriate + // unsigned type. The overloads are here so that every type that is implicitly + // convertible to an integer (including enums and endian helpers) can be used + // without requiring type traits or call-site changes. + HexNumber(int8_t Value) : Value(static_cast<uint8_t >(Value)) { } + HexNumber(int16_t Value) : Value(static_cast<uint16_t>(Value)) { } + HexNumber(int32_t Value) : Value(static_cast<uint32_t>(Value)) { } + HexNumber(int64_t Value) : Value(static_cast<uint64_t>(Value)) { } + HexNumber(uint8_t Value) : Value(Value) { } + HexNumber(uint16_t Value) : Value(Value) { } + HexNumber(uint32_t Value) : Value(Value) { } + HexNumber(uint64_t Value) : Value(Value) { } + uint64_t Value; +}; + +raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value); + +class StreamWriter { +public: + StreamWriter(raw_ostream &OS) + : OS(OS) + , IndentLevel(0) { + } + + void flush() { + OS.flush(); + } + + void indent(int Levels = 1) { + IndentLevel += Levels; + } + + void unindent(int Levels = 1) { + IndentLevel = std::max(0, IndentLevel - Levels); + } + + void printIndent() { + for (int i = 0; i < IndentLevel; ++i) + OS << " "; + } + + template<typename T> + HexNumber hex(T Value) { + return HexNumber(Value); + } + + template<typename T, typename TEnum> + void printEnum(StringRef Label, T Value, + ArrayRef<EnumEntry<TEnum> > EnumValues) { + StringRef Name; + bool Found = false; + for (size_t i = 0; i < EnumValues.size(); ++i) { + if (EnumValues[i].Value == Value) { + Name = EnumValues[i].Name; + Found = true; + break; + } + } + + if (Found) { + startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n"; + } else { + startLine() << Label << ": " << hex(Value) << "\n"; + } + } + + template<typename T, typename TFlag> + void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag> > Flags, + TFlag EnumMask = TFlag(0)) { + typedef EnumEntry<TFlag> FlagEntry; + typedef SmallVector<FlagEntry, 10> FlagVector; + FlagVector SetFlags; + + for (typename ArrayRef<FlagEntry>::const_iterator I = Flags.begin(), + E = Flags.end(); I != E; ++I) { + if (I->Value == 0) + continue; + + bool IsEnum = (I->Value & EnumMask) != 0; + if ((!IsEnum && (Value & I->Value) == I->Value) || + (IsEnum && (Value & EnumMask) == I->Value)) { + SetFlags.push_back(*I); + } + } + + std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>); + + startLine() << Label << " [ (" << hex(Value) << ")\n"; + for (typename FlagVector::const_iterator I = SetFlags.begin(), + E = SetFlags.end(); + I != E; ++I) { + startLine() << " " << I->Name << " (" << hex(I->Value) << ")\n"; + } + startLine() << "]\n"; + } + + template<typename T> + void printFlags(StringRef Label, T Value) { + startLine() << Label << " [ (" << hex(Value) << ")\n"; + uint64_t Flag = 1; + uint64_t Curr = Value; + while (Curr > 0) { + if (Curr & 1) + startLine() << " " << hex(Flag) << "\n"; + Curr >>= 1; + Flag <<= 1; + } + startLine() << "]\n"; + } + + void printNumber(StringRef Label, uint64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint8_t Value) { + startLine() << Label << ": " << unsigned(Value) << "\n"; + } + + void printNumber(StringRef Label, int64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int8_t Value) { + startLine() << Label << ": " << int(Value) << "\n"; + } + + template<typename T> + void printHex(StringRef Label, T Value) { + startLine() << Label << ": " << hex(Value) << "\n"; + } + + template<typename T> + void printHex(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n"; + } + + void printString(StringRef Label, StringRef Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printString(StringRef Label, const std::string &Value) { + startLine() << Label << ": " << Value << "\n"; + } + + template<typename T> + void printNumber(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << Value << ")\n"; + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, Str, Value, false); + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, Str, V, false); + } + + void printBinary(StringRef Label, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, StringRef(), Value, false); + } + + void printBinary(StringRef Label, ArrayRef<char> Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinary(StringRef Label, StringRef Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinaryBlock(StringRef Label, StringRef Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, true); + } + + raw_ostream& startLine() { + printIndent(); + return OS; + } + + raw_ostream& getOStream() { + return OS; + } + +private: + template<typename T> + static bool flagName(const EnumEntry<T>& lhs, const EnumEntry<T>& rhs) { + return lhs.Name < rhs.Name; + } + + void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value, + bool Block); + + raw_ostream &OS; + int IndentLevel; +}; + +struct DictScope { + DictScope(StreamWriter& W, StringRef N) : W(W) { + W.startLine() << N << " {\n"; + W.indent(); + } + + ~DictScope() { + W.unindent(); + W.startLine() << "}\n"; + } + + StreamWriter& W; +}; + +struct ListScope { + ListScope(StreamWriter& W, StringRef N) : W(W) { + W.startLine() << N << " [\n"; + W.indent(); + } + + ~ListScope() { + W.unindent(); + W.startLine() << "]\n"; + } + + StreamWriter& W; +}; + +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 8f0917f..2e95b6b 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -21,261 +21,273 @@ #include "llvm-readobj.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Object/ELF.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" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/system_error.h" -using namespace llvm; -using namespace llvm::object; - -static cl::opt<std::string> -InputFilename(cl::Positional, cl::desc("<input object>"), cl::init("")); - -static void dumpSymbolHeader() { - outs() << format(" %-32s", (const char*)"Name") - << format(" %-4s", (const char*)"Type") - << format(" %-16s", (const char*)"Address") - << format(" %-16s", (const char*)"Size") - << format(" %-16s", (const char*)"FileOffset") - << format(" %-26s", (const char*)"Flags") - << "\n"; -} +#include <string> -static void dumpSectionHeader() { - outs() << format(" %-24s", (const char*)"Name") - << format(" %-16s", (const char*)"Address") - << format(" %-16s", (const char*)"Size") - << format(" %-8s", (const char*)"Align") - << format(" %-26s", (const char*)"Flags") - << "\n"; -} -static const char *getTypeStr(SymbolRef::Type Type) { - switch (Type) { - case SymbolRef::ST_Unknown: return "?"; - case SymbolRef::ST_Data: return "DATA"; - case SymbolRef::ST_Debug: return "DBG"; - case SymbolRef::ST_File: return "FILE"; - case SymbolRef::ST_Function: return "FUNC"; - case SymbolRef::ST_Other: return "-"; - } - return "INV"; -} +using namespace llvm; +using namespace llvm::object; -static std::string getSymbolFlagStr(uint32_t Flags) { - std::string result; - if (Flags & SymbolRef::SF_Undefined) - result += "undef,"; - if (Flags & SymbolRef::SF_Global) - result += "global,"; - if (Flags & SymbolRef::SF_Weak) - result += "weak,"; - if (Flags & SymbolRef::SF_Absolute) - result += "absolute,"; - if (Flags & SymbolRef::SF_ThreadLocal) - result += "threadlocal,"; - if (Flags & SymbolRef::SF_Common) - result += "common,"; - if (Flags & SymbolRef::SF_FormatSpecific) - result += "formatspecific,"; - - // Remove trailing comma - if (result.size() > 0) { - result.erase(result.size() - 1); - } - return result; +namespace opts { + cl::list<std::string> InputFilenames(cl::Positional, + cl::desc("<input object files>"), + cl::ZeroOrMore); + + // -file-headers, -h + cl::opt<bool> FileHeaders("file-headers", + cl::desc("Display file headers ")); + cl::alias FileHeadersShort("h", + cl::desc("Alias for --file-headers"), + cl::aliasopt(FileHeaders)); + + // -sections, -s + cl::opt<bool> Sections("sections", + cl::desc("Display all sections.")); + cl::alias SectionsShort("s", + cl::desc("Alias for --sections"), + cl::aliasopt(Sections)); + + // -section-relocations, -sr + cl::opt<bool> SectionRelocations("section-relocations", + cl::desc("Display relocations for each section shown.")); + cl::alias SectionRelocationsShort("sr", + cl::desc("Alias for --section-relocations"), + cl::aliasopt(SectionRelocations)); + + // -section-symbols, -st + cl::opt<bool> SectionSymbols("section-symbols", + cl::desc("Display symbols for each section shown.")); + cl::alias SectionSymbolsShort("st", + cl::desc("Alias for --section-symbols"), + cl::aliasopt(SectionSymbols)); + + // -section-data, -sd + cl::opt<bool> SectionData("section-data", + cl::desc("Display section data for each section shown.")); + cl::alias SectionDataShort("sd", + cl::desc("Alias for --section-data"), + cl::aliasopt(SectionData)); + + // -relocations, -r + cl::opt<bool> Relocations("relocations", + cl::desc("Display the relocation entries in the file")); + cl::alias RelocationsShort("r", + cl::desc("Alias for --relocations"), + cl::aliasopt(Relocations)); + + // -symbols, -t + cl::opt<bool> Symbols("symbols", + cl::desc("Display the symbol table")); + cl::alias SymbolsShort("t", + cl::desc("Alias for --symbols"), + cl::aliasopt(Symbols)); + + // -dyn-symbols, -dt + cl::opt<bool> DynamicSymbols("dyn-symbols", + cl::desc("Display the dynamic symbol table")); + cl::alias DynamicSymbolsShort("dt", + cl::desc("Alias for --dyn-symbols"), + cl::aliasopt(DynamicSymbols)); + + // -unwind, -u + cl::opt<bool> UnwindInfo("unwind", + cl::desc("Display unwind information")); + cl::alias UnwindInfoShort("u", + cl::desc("Alias for --unwind"), + cl::aliasopt(UnwindInfo)); + + // -dynamic-table + cl::opt<bool> DynamicTable("dynamic-table", + cl::desc("Display the ELF .dynamic section table")); + + // -needed-libs + cl::opt<bool> NeededLibraries("needed-libs", + cl::desc("Display the needed libraries")); + + // -program-headers + cl::opt<bool> ProgramHeaders("program-headers", + cl::desc("Display ELF program headers")); + + // -expand-relocs + cl::opt<bool> ExpandRelocs("expand-relocs", + cl::desc("Expand each shown relocation to multiple lines")); +} // namespace opts + +namespace llvm { + +bool error(error_code EC) { + if (!EC) + return false; + + outs() << "\nError reading file: " << EC.message() << ".\n"; + outs().flush(); + return true; } -static void checkError(error_code ec, const char *msg) { - if (ec) - report_fatal_error(std::string(msg) + ": " + ec.message()); +bool relocAddressLess(RelocationRef a, RelocationRef b) { + uint64_t a_addr, b_addr; + if (error(a.getOffset(a_addr))) return false; + if (error(b.getOffset(b_addr))) return false; + return a_addr < b_addr; } -static std::string getSectionFlagStr(const SectionRef &Section) { - const struct { - error_code (SectionRef::*MemF)(bool &) const; - const char *FlagStr, *ErrorStr; - } Work[] = - {{ &SectionRef::isText, "text,", "Section.isText() failed" }, - { &SectionRef::isData, "data,", "Section.isData() failed" }, - { &SectionRef::isBSS, "bss,", "Section.isBSS() failed" }, - { &SectionRef::isRequiredForExecution, "required,", - "Section.isRequiredForExecution() failed" }, - { &SectionRef::isVirtual, "virtual,", "Section.isVirtual() failed" }, - { &SectionRef::isZeroInit, "zeroinit,", "Section.isZeroInit() failed" }, - { &SectionRef::isReadOnlyData, "rodata,", - "Section.isReadOnlyData() failed" }}; - - std::string result; - for (uint32_t I = 0; I < sizeof(Work)/sizeof(*Work); ++I) { - bool B; - checkError((Section.*Work[I].MemF)(B), Work[I].ErrorStr); - if (B) - result += Work[I].FlagStr; - } +} // namespace llvm - // Remove trailing comma - if (result.size() > 0) { - result.erase(result.size() - 1); - } - return result; -} -static void -dumpSymbol(const SymbolRef &Sym, const ObjectFile *obj, bool IsDynamic) { - StringRef Name; - SymbolRef::Type Type; - uint32_t Flags; - uint64_t Address; - uint64_t Size; - uint64_t FileOffset; - checkError(Sym.getName(Name), "SymbolRef.getName() failed"); - checkError(Sym.getAddress(Address), "SymbolRef.getAddress() failed"); - checkError(Sym.getSize(Size), "SymbolRef.getSize() failed"); - checkError(Sym.getFileOffset(FileOffset), - "SymbolRef.getFileOffset() failed"); - checkError(Sym.getType(Type), "SymbolRef.getType() failed"); - checkError(Sym.getFlags(Flags), "SymbolRef.getFlags() failed"); - std::string FullName = Name; - - // If this is a dynamic symbol from an ELF object, append - // the symbol's version to the name. - if (IsDynamic && obj->isELF()) { - StringRef Version; - bool IsDefault; - GetELFSymbolVersion(obj, Sym, Version, IsDefault); - if (!Version.empty()) { - FullName += (IsDefault ? "@@" : "@"); - FullName += Version; - } - } +static void reportError(StringRef Input, error_code EC) { + if (Input == "-") + Input = "<stdin>"; - // format() can't handle StringRefs - outs() << format(" %-32s", FullName.c_str()) - << format(" %-4s", getTypeStr(Type)) - << format(" %16" PRIx64, Address) - << format(" %16" PRIx64, Size) - << format(" %16" PRIx64, FileOffset) - << " " << getSymbolFlagStr(Flags) - << "\n"; + errs() << Input << ": " << EC.message() << "\n"; + errs().flush(); } -static void dumpStaticSymbol(const SymbolRef &Sym, const ObjectFile *obj) { - return dumpSymbol(Sym, obj, false); -} +static void reportError(StringRef Input, StringRef Message) { + if (Input == "-") + Input = "<stdin>"; -static void dumpDynamicSymbol(const SymbolRef &Sym, const ObjectFile *obj) { - return dumpSymbol(Sym, obj, true); + errs() << Input << ": " << Message << "\n"; } -static void dumpSection(const SectionRef &Section, const ObjectFile *obj) { - StringRef Name; - checkError(Section.getName(Name), "SectionRef::getName() failed"); - uint64_t Addr, Size, Align; - checkError(Section.getAddress(Addr), "SectionRef::getAddress() failed"); - checkError(Section.getSize(Size), "SectionRef::getSize() failed"); - checkError(Section.getAlignment(Align), "SectionRef::getAlignment() failed"); - outs() << format(" %-24s", std::string(Name).c_str()) - << format(" %16" PRIx64, Addr) - << format(" %16" PRIx64, Size) - << format(" %8" PRIx64, Align) - << " " << getSectionFlagStr(Section) - << "\n"; +/// @brief Creates an format-specific object file dumper. +static error_code createDumper(const ObjectFile *Obj, + StreamWriter &Writer, + OwningPtr<ObjDumper> &Result) { + if (!Obj) + return readobj_error::unsupported_file_format; + + if (Obj->isCOFF()) + return createCOFFDumper(Obj, Writer, Result); + if (Obj->isELF()) + return createELFDumper(Obj, Writer, Result); + if (Obj->isMachO()) + return createMachODumper(Obj, Writer, Result); + + return readobj_error::unsupported_obj_file_format; } -static void dumpLibrary(const LibraryRef &lib, const ObjectFile *obj) { - StringRef path; - lib.getPath(path); - outs() << " " << path << "\n"; -} -template<typename Iterator, typename Func> -static void dump(const ObjectFile *obj, Func f, Iterator begin, Iterator end, - const char *errStr) { - error_code ec; - uint32_t count = 0; - Iterator it = begin, ie = end; - while (it != ie) { - f(*it, obj); - it.increment(ec); - if (ec) - report_fatal_error(errStr); - ++count; +/// @brief Dumps the specified object file. +static void dumpObject(const ObjectFile *Obj) { + StreamWriter Writer(outs()); + OwningPtr<ObjDumper> Dumper; + if (error_code EC = createDumper(Obj, Writer, Dumper)) { + reportError(Obj->getFileName(), EC); + return; } - outs() << " Total: " << count << "\n\n"; -} -static void dumpHeaders(const ObjectFile *obj) { - outs() << "File Format : " << obj->getFileFormatName() << "\n"; - outs() << "Arch : " - << Triple::getArchTypeName((llvm::Triple::ArchType)obj->getArch()) + outs() << '\n'; + outs() << "File: " << Obj->getFileName() << "\n"; + outs() << "Format: " << Obj->getFileFormatName() << "\n"; + outs() << "Arch: " + << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch()) << "\n"; - outs() << "Address Size: " << (8*obj->getBytesInAddress()) << " bits\n"; - outs() << "Load Name : " << obj->getLoadName() << "\n"; - outs() << "\n"; + outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n"; + if (Obj->isELF()) + outs() << "LoadName: " << Obj->getLoadName() << "\n"; + + if (opts::FileHeaders) + Dumper->printFileHeaders(); + if (opts::Sections) + Dumper->printSections(); + if (opts::Relocations) + Dumper->printRelocations(); + if (opts::Symbols) + Dumper->printSymbols(); + if (opts::DynamicSymbols) + Dumper->printDynamicSymbols(); + if (opts::UnwindInfo) + Dumper->printUnwindInfo(); + if (opts::DynamicTable) + Dumper->printDynamicTable(); + if (opts::NeededLibraries) + Dumper->printNeededLibraries(); + if (opts::ProgramHeaders) + Dumper->printProgramHeaders(); } -int main(int argc, char** argv) { - error_code ec; - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - cl::ParseCommandLineOptions(argc, argv, - "LLVM Object Reader\n"); +/// @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(); + ArcI != ArcE; ++ArcI) { + OwningPtr<Binary> child; + if (error_code EC = ArcI->getAsBinary(child)) { + // Ignore non-object files. + if (EC != object_error::invalid_file_type) + reportError(Arc->getFileName(), EC.message()); + continue; + } - if (InputFilename.empty()) { - errs() << "Please specify an input filename\n"; - return 1; + if (ObjectFile *Obj = dyn_cast<ObjectFile>(child.get())) + dumpObject(Obj); + else + reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); } +} - // Open the object file - OwningPtr<MemoryBuffer> File; - if (MemoryBuffer::getFile(InputFilename, File)) { - errs() << InputFilename << ": Open failed\n"; - return 1; + +/// @brief Opens \a File and dumps it. +static void dumpInput(StringRef File) { + // If file isn't stdin, check that it exists. + if (File != "-" && !sys::fs::exists(File)) { + reportError(File, readobj_error::file_not_found); + return; } - OwningPtr<ObjectFile> o(ObjectFile::createObjectFile(File.take())); - ObjectFile *obj = o.get(); - if (!obj) { - errs() << InputFilename << ": Object type not recognized\n"; + // Attempt to open the binary. + OwningPtr<Binary> Binary; + if (error_code EC = createBinary(File, Binary)) { + reportError(File, EC); + return; } - dumpHeaders(obj); + if (Archive *Arc = dyn_cast<Archive>(Binary.get())) + dumpArchive(Arc); + else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Binary.get())) + dumpObject(Obj); + else + reportError(File, readobj_error::unrecognized_file_format); +} - outs() << "Symbols:\n"; - dumpSymbolHeader(); - dump(obj, dumpStaticSymbol, obj->begin_symbols(), obj->end_symbols(), - "Symbol iteration failed"); - outs() << "Dynamic Symbols:\n"; - dumpSymbolHeader(); - dump(obj, dumpDynamicSymbol, obj->begin_dynamic_symbols(), - obj->end_dynamic_symbols(), "Symbol iteration failed"); +int main(int argc, const char *argv[]) { + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; - outs() << "Sections:\n"; - dumpSectionHeader(); - dump(obj, &dumpSection, obj->begin_sections(), obj->end_sections(), - "Section iteration failed"); + // Initialize targets. + llvm::InitializeAllTargetInfos(); - if (obj->isELF()) { - if (ErrorOr<void> e = dumpELFDynamicTable(obj, outs())) - ; - else - errs() << "InputFilename" << ": " << error_code(e).message() << "\n"; - } + // Register the target printer for --version. + cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); + + cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n"); - outs() << "Libraries needed:\n"; - dump(obj, &dumpLibrary, obj->begin_libraries_needed(), - obj->end_libraries_needed(), "Needed libraries iteration failed"); + // Default to stdin if no filename is specified. + if (opts::InputFilenames.size() == 0) + opts::InputFilenames.push_back("-"); + + std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), + dumpInput); return 0; } - diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h index cf492b2..3f75610 100644 --- a/tools/llvm-readobj/llvm-readobj.h +++ b/tools/llvm-readobj/llvm-readobj.h @@ -1,4 +1,4 @@ -//===- llvm-readobj.h - Dump contents of an Object File -------------------===// +//===-- llvm-readobj.h ----------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,13 +10,37 @@ #ifndef LLVM_TOOLS_READ_OBJ_H #define LLVM_TOOLS_READ_OBJ_H -#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/CommandLine.h" +#include <string> namespace llvm { -namespace object { class ObjectFile; } -class raw_ostream; + namespace object { + class RelocationRef; + } -ErrorOr<void> dumpELFDynamicTable(object::ObjectFile *O, raw_ostream &OS); -} // end namespace llvm + class error_code; + + // Various helper functions. + bool error(error_code ec); + bool relocAddressLess(object::RelocationRef A, + object::RelocationRef B); +} // namespace llvm + +namespace opts { + extern llvm::cl::list<std::string> InputFilenames; + extern llvm::cl::opt<bool> FileHeaders; + extern llvm::cl::opt<bool> Sections; + extern llvm::cl::opt<bool> SectionRelocations; + extern llvm::cl::opt<bool> SectionSymbols; + extern llvm::cl::opt<bool> SectionData; + extern llvm::cl::opt<bool> Relocations; + extern llvm::cl::opt<bool> Symbols; + extern llvm::cl::opt<bool> DynamicSymbols; + extern llvm::cl::opt<bool> UnwindInfo; + extern llvm::cl::opt<bool> ExpandRelocs; +} // namespace opts + +#define LLVM_READOBJ_ENUM_ENT(ns, enum) \ + { #enum, ns::enum } #endif diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 4d8d345..7f042d2 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -17,7 +17,7 @@ #include "llvm/ExecutionEngine/ObjectBuffer.h" #include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "llvm/Object/MachOObject.h" +#include "llvm/Object/MachO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Memory.h" @@ -69,7 +69,7 @@ public: return 0; } - bool applyPermissions(std::string *ErrMsg) { return false; } + bool finalizeMemory(std::string *ErrMsg) { return false; } // Invalidate instruction cache for sections with execute permissions. // Some platforms with separate data cache and instruction cache require @@ -124,8 +124,8 @@ static int printLineInfoForInput() { InputFileList.push_back("-"); for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { // Instantiate a dynamic linker. - TrivialMemoryManager *MemMgr = new TrivialMemoryManager; - RuntimeDyld Dyld(MemMgr); + TrivialMemoryManager MemMgr; + RuntimeDyld Dyld(&MemMgr); // Load the input memory buffer. OwningPtr<MemoryBuffer> InputBuffer; @@ -180,8 +180,8 @@ static int printLineInfoForInput() { static int executeInput() { // Instantiate a dynamic linker. - TrivialMemoryManager *MemMgr = new TrivialMemoryManager; - RuntimeDyld Dyld(MemMgr); + TrivialMemoryManager MemMgr; + RuntimeDyld Dyld(&MemMgr); // If we don't have any input files, read from stdin. if (!InputFileList.size()) @@ -204,7 +204,7 @@ static int executeInput() { // Resolve all the relocations we can. Dyld.resolveRelocations(); // Clear instruction cache before code will be executed. - MemMgr->invalidateInstructionCache(); + MemMgr.invalidateInstructionCache(); // FIXME: Error out if there are unresolved relocations. @@ -214,8 +214,8 @@ static int executeInput() { return Error("no definition for '" + EntryPoint + "'"); // Invalidate the instruction cache for each loaded function. - for (unsigned i = 0, e = MemMgr->FunctionMemory.size(); i != e; ++i) { - sys::MemoryBlock &Data = MemMgr->FunctionMemory[i]; + for (unsigned i = 0, e = MemMgr.FunctionMemory.size(); i != e; ++i) { + sys::MemoryBlock &Data = MemMgr.FunctionMemory[i]; // Make sure the memory is executable. std::string ErrorStr; sys::Memory::InvalidateInstructionCache(Data.base(), Data.size()); diff --git a/tools/llvm-shlib/Makefile b/tools/llvm-shlib/Makefile index 6d6c6e9..1d9053b 100644 --- a/tools/llvm-shlib/Makefile +++ b/tools/llvm-shlib/Makefile @@ -51,30 +51,29 @@ ifeq ($(HOST_OS),Darwin) LLVMLibsOptions := $(LLVMLibsOptions) -all_load # extra options to override libtool defaults LLVMLibsOptions := $(LLVMLibsOptions) \ - -Wl,-dead_strip \ - -Wl,-seg1addr -Wl,0xE0000000 + -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)" + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif -ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD OpenBSD GNU Bitrig)) +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD OpenBSD GNU Bitrig)) # Include everything from the .a's into the shared library. LLVMLibsOptions := -Wl,--whole-archive $(LLVMLibsOptions) \ -Wl,--no-whole-archive endif -ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU)) +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD GNU)) # Add soname to the library. LLVMLibsOptions += -Wl,--soname,lib$(LIBRARYNAME)$(SHLIBEXT) endif -ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux GNU)) +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux GNU GNU/kFreeBSD)) # Don't allow unresolved symbols. LLVMLibsOptions += -Wl,--no-undefined endif diff --git a/tools/llvm-stress/Makefile b/tools/llvm-stress/Makefile index 90d57c3..8767cbe 100644 --- a/tools/llvm-stress/Makefile +++ b/tools/llvm-stress/Makefile @@ -10,7 +10,7 @@ LEVEL := ../.. TOOLNAME := llvm-stress LINK_COMPONENTS := object -LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts ipo +LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts ipo # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp index fbda1b7..15f7abf 100644 --- a/tools/llvm-stress/llvm-stress.cpp +++ b/tools/llvm-stress/llvm-stress.cpp @@ -702,7 +702,7 @@ int main(int argc, char **argv) { std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + sys::fs::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index 86ea34b..0346fb2 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -12,8 +12,10 @@ //===----------------------------------------------------------------------===// #include "LLVMSymbolize.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include <sstream> @@ -62,15 +64,23 @@ ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx) SymbolAddress == UnknownAddressOrSize) continue; uint64_t SymbolSize; - if (error(si->getSize(SymbolSize)) || SymbolSize == UnknownAddressOrSize) + // 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, SymbolAddress + SymbolSize }; + SymbolDesc SD = { SymbolAddress, SymbolSize }; M.insert(std::make_pair(SD, SymbolName)); } } @@ -79,15 +89,18 @@ bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, std::string &Name, uint64_t &Addr, uint64_t &Size) const { const SymbolMapTy &M = Type == SymbolRef::ST_Function ? Functions : Objects; - SymbolDesc SD = { Address, Address + 1 }; - SymbolMapTy::const_iterator it = M.find(SD); - if (it == M.end()) + if (M.empty()) return false; - if (Address < it->first.Addr || Address >= it->first.AddrEnd) + SymbolDesc SD = { Address, Address }; + SymbolMapTy::const_iterator it = M.upper_bound(SD); + if (it == M.begin()) + return false; + --it; + if (it->first.Size != 0 && it->first.Addr + it->first.Size <= Address) return false; Name = it->second.str(); Addr = it->first.Addr; - Size = it->first.AddrEnd - it->first.Addr; + Size = it->first.Size; return true; } @@ -177,8 +190,8 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, uint64_t Size = 0; if (Opts.UseSymbolTable) { if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) { - if (Info->symbolizeData(ModuleOffset, Name, Start, Size)) - DemangleName(Name); + if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle) + Name = DemangleName(Name); } } std::stringstream ss; @@ -186,21 +199,14 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, return ss.str(); } -// Returns true if the object endianness is known. -static bool getObjectEndianness(const ObjectFile *Obj, bool &IsLittleEndian) { - // FIXME: Implement this when libLLVMObject allows to do it easily. - IsLittleEndian = true; - return true; -} - -static ObjectFile *getObjectFile(const std::string &Path) { - OwningPtr<MemoryBuffer> Buff; - if (error_code ec = MemoryBuffer::getFile(Path, Buff)) - error(ec); - return ObjectFile::createObjectFile(Buff.take()); +void LLVMSymbolizer::flush() { + DeleteContainerSeconds(Modules); + DeleteContainerPointers(ParsedBinariesAndObjects); + BinaryForPath.clear(); + ObjectFileForArch.clear(); } -static std::string getDarwinDWARFResourceForModule(const std::string &Path) { +static std::string getDarwinDWARFResourceForPath(const std::string &Path) { StringRef Basename = sys::path::filename(Path); const std::string &DSymDirectory = Path + ".dSYM"; SmallString<16> ResourceName = StringRef(DSymDirectory); @@ -209,36 +215,89 @@ static std::string getDarwinDWARFResourceForModule(const std::string &Path) { return ResourceName.str(); } +LLVMSymbolizer::BinaryPair +LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { + BinaryMapTy::iterator I = BinaryForPath.find(Path); + if (I != BinaryForPath.end()) + return I->second; + Binary *Bin = 0; + Binary *DbgBin = 0; + OwningPtr<Binary> ParsedBinary; + OwningPtr<Binary> ParsedDbgBinary; + if (!error(createBinary(Path, ParsedBinary))) { + // Check if it's a universal binary. + Bin = ParsedBinary.take(); + 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(); + ParsedBinariesAndObjects.push_back(DbgBin); + } + } + } + if (DbgBin == 0) + DbgBin = Bin; + BinaryPair Res = std::make_pair(Bin, DbgBin); + BinaryForPath[Path] = Res; + return Res; +} + +ObjectFile * +LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName) { + if (Bin == 0) + return 0; + ObjectFile *Res = 0; + if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) { + ObjectFileForArchMapTy::iterator I = ObjectFileForArch.find( + std::make_pair(UB, ArchName)); + if (I != ObjectFileForArch.end()) + return I->second; + OwningPtr<ObjectFile> ParsedObj; + if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) { + Res = ParsedObj.take(); + ParsedBinariesAndObjects.push_back(Res); + } + ObjectFileForArch[std::make_pair(UB, ArchName)] = Res; + } else if (Bin->isObject()) { + Res = cast<ObjectFile>(Bin); + } + return Res; +} + ModuleInfo * LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { ModuleMapTy::iterator I = Modules.find(ModuleName); if (I != Modules.end()) return I->second; + std::string BinaryName = ModuleName; + std::string ArchName = Opts.DefaultArch; + size_t ColonPos = ModuleName.find_last_of(':'); + // Verify that substring after colon form a valid arch name. + if (ColonPos != std::string::npos) { + std::string ArchStr = ModuleName.substr(ColonPos + 1); + if (Triple(ArchStr).getArch() != Triple::UnknownArch) { + BinaryName = ModuleName.substr(0, ColonPos); + ArchName = ArchStr; + } + } + BinaryPair Binaries = getOrCreateBinary(BinaryName); + ObjectFile *Obj = getObjectFileFromBinary(Binaries.first, ArchName); + ObjectFile *DbgObj = getObjectFileFromBinary(Binaries.second, ArchName); - ObjectFile *Obj = getObjectFile(ModuleName); if (Obj == 0) { - // Module name doesn't point to a valid object file. + // Failed to find valid object file. Modules.insert(make_pair(ModuleName, (ModuleInfo *)0)); return 0; } - - DIContext *Context = 0; - bool IsLittleEndian; - if (getObjectEndianness(Obj, IsLittleEndian)) { - // On Darwin we may find DWARF in separate object file in - // resource directory. - ObjectFile *DbgObj = Obj; - if (isa<MachOObjectFile>(Obj)) { - const std::string &ResourceName = - getDarwinDWARFResourceForModule(ModuleName); - ObjectFile *ResourceObj = getObjectFile(ResourceName); - if (ResourceObj != 0) - DbgObj = ResourceObj; - } - Context = DIContext::getDWARFContext(DbgObj); - assert(Context); - } - + DIContext *Context = DIContext::getDWARFContext(DbgObj); + assert(Context); ModuleInfo *Info = new ModuleInfo(Obj, Context); Modules.insert(make_pair(ModuleName, Info)); return Info; @@ -253,7 +312,8 @@ std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const { std::string FunctionName = LineInfo.getFunctionName(); if (FunctionName == kDILineInfoBadString) FunctionName = kBadString; - DemangleName(FunctionName); + else if (Opts.Demangle) + FunctionName = DemangleName(FunctionName); Result << FunctionName << "\n"; } std::string Filename = LineInfo.getFileName(); @@ -270,16 +330,17 @@ extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, size_t *length, int *status); #endif -void LLVMSymbolizer::DemangleName(std::string &Name) const { +std::string LLVMSymbolizer::DemangleName(const std::string &Name) { #if !defined(_MSC_VER) - if (!Opts.Demangle) - return; int status = 0; char *DemangledName = __cxa_demangle(Name.c_str(), 0, 0, &status); if (status != 0) - return; - Name = DemangledName; + return Name; + std::string Result = DemangledName; free(DemangledName); + return Result; +#else + return Name; #endif } diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h index e6220aa..03c765c 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.h +++ b/tools/llvm-symbolizer/LLVMSymbolize.h @@ -14,7 +14,9 @@ #define LLVM_SYMBOLIZE_H #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/MemoryBuffer.h" #include <map> @@ -35,14 +37,20 @@ public: bool PrintFunctions : 1; bool PrintInlining : 1; bool Demangle : 1; + std::string DefaultArch; Options(bool UseSymbolTable = true, bool PrintFunctions = true, - bool PrintInlining = true, bool Demangle = true) + bool PrintInlining = true, bool Demangle = true, + std::string DefaultArch = "") : UseSymbolTable(UseSymbolTable), PrintFunctions(PrintFunctions), - PrintInlining(PrintInlining), Demangle(Demangle) { + PrintInlining(PrintInlining), Demangle(Demangle), + DefaultArch(DefaultArch) { } }; LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {} + ~LLVMSymbolizer() { + flush(); + } // Returns the result of symbolization for module name/offset as // a string (possibly containing newlines). @@ -50,13 +58,31 @@ public: symbolizeCode(const std::string &ModuleName, uint64_t ModuleOffset); std::string symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset); + void flush(); + static std::string DemangleName(const std::string &Name); private: + typedef std::pair<Binary*, Binary*> BinaryPair; + ModuleInfo *getOrCreateModuleInfo(const std::string &ModuleName); + /// \brief Returns pair of pointers to binary and debug binary. + BinaryPair getOrCreateBinary(const std::string &Path); + /// \brief Returns a parsed object file for a given architecture in a + /// universal binary (or the binary itself if it is an object file). + ObjectFile *getObjectFileFromBinary(Binary *Bin, const std::string &ArchName); + std::string printDILineInfo(DILineInfo LineInfo) const; - void DemangleName(std::string &Name) const; + // Owns all the parsed binaries and object files. + SmallVector<Binary*, 4> ParsedBinariesAndObjects; + // Owns module info objects. typedef std::map<std::string, ModuleInfo *> ModuleMapTy; ModuleMapTy Modules; + typedef std::map<std::string, BinaryPair> BinaryMapTy; + BinaryMapTy BinaryForPath; + typedef std::map<std::pair<MachOUniversalBinary *, std::string>, ObjectFile *> + ObjectFileForArchMapTy; + ObjectFileForArchMapTy ObjectFileForArch; + Options Opts; static const char kBadString[]; }; @@ -76,14 +102,16 @@ private: bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, std::string &Name, uint64_t &Addr, uint64_t &Size) const; - OwningPtr<ObjectFile> Module; + ObjectFile *Module; OwningPtr<DIContext> DebugInfoContext; struct SymbolDesc { uint64_t Addr; - uint64_t AddrEnd; + // If size is 0, assume that symbol occupies the whole memory range up to + // the following symbol. + uint64_t Size; friend bool operator<(const SymbolDesc &s1, const SymbolDesc &s2) { - return s1.AddrEnd <= s2.Addr; + return s1.Addr < s2.Addr; } }; typedef std::map<SymbolDesc, StringRef> SymbolMapTy; diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp index d039ec6..c32e949 100644 --- a/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -47,6 +47,10 @@ ClPrintInlining("inlining", cl::init(true), static cl::opt<bool> ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names")); +static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""), + cl::desc("Default architecture " + "(for multi-arch objects)")); + static bool parseCommand(bool &IsData, std::string &ModuleName, uint64_t &ModuleOffset) { const char *kDataCmd = "DATA "; @@ -70,12 +74,25 @@ static bool parseCommand(bool &IsData, std::string &ModuleName, // If no cmd, assume it's CODE. IsData = false; } - // FIXME: Handle case when filename is given in quotes. - if (char *FilePath = strtok(pos, kDelimiters)) { - ModuleName = FilePath; - if (char *OffsetStr = strtok((char *)0, kDelimiters)) - ModuleOffsetStr = OffsetStr; + // 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; + } else { + int name_length = strcspn(pos, kDelimiters); + ModuleName = std::string(pos, name_length); + pos += name_length; } + // 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)) return false; return true; @@ -89,7 +106,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n"); LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions, - ClPrintInlining, ClDemangle); + ClPrintInlining, ClDemangle, ClDefaultArch); LLVMSymbolizer Symbolizer(Opts); bool IsData = false; diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index cf7ffe2..758227d 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -24,12 +24,14 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" #include "llvm/Linker.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" @@ -44,6 +46,7 @@ #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/ObjCARC.h" using namespace llvm; static cl::opt<bool> @@ -68,76 +71,107 @@ const char* LTOCodeGenerator::getVersionString() { LTOCodeGenerator::LTOCodeGenerator() : _context(getGlobalContext()), - _linker("LinkTimeOptimizer", "ld-temp.o", _context), _target(NULL), + _linker(new Module("ld-temp.o", _context)), _target(NULL), _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false), _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC), _nativeObjectFile(NULL) { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); + initializeLTOPasses(); } LTOCodeGenerator::~LTOCodeGenerator() { delete _target; delete _nativeObjectFile; + delete _linker.getModule(); for (std::vector<char*>::iterator I = _codegenOptions.begin(), E = _codegenOptions.end(); I != E; ++I) free(*I); } +// Initialize LTO passes. Please keep this funciton in sync with +// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO +// passes are initialized. +// +void LTOCodeGenerator::initializeLTOPasses() { + PassRegistry &R = *PassRegistry::getPassRegistry(); + + initializeInternalizePassPass(R); + initializeIPSCCPPass(R); + initializeGlobalOptPass(R); + initializeConstantMergePass(R); + initializeDAHPass(R); + initializeInstCombinerPass(R); + initializeSimpleInlinerPass(R); + initializePruneEHPass(R); + initializeGlobalDCEPass(R); + initializeArgPromotionPass(R); + initializeJumpThreadingPass(R); + initializeSROAPass(R); + initializeSROA_DTPass(R); + initializeSROA_SSAUpPass(R); + initializeFunctionAttrsPass(R); + initializeGlobalsModRefPass(R); + initializeLICMPass(R); + initializeGVNPass(R); + initializeMemCpyOptPass(R); + initializeDCEPass(R); + initializeCFGSimplifyPassPass(R); +} + bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) { - bool ret = _linker.LinkInModule(mod->getLLVVMModule(), &errMsg); + bool ret = _linker.linkInModule(mod->getLLVVMModule(), &errMsg); const std::vector<const char*> &undefs = mod->getAsmUndefinedRefs(); for (int i = 0, e = undefs.size(); i != e; ++i) _asmUndefinedRefs[undefs[i]] = 1; - return ret; + return !ret; } -bool LTOCodeGenerator::setDebugInfo(lto_debug_model debug, - std::string& errMsg) { +void LTOCodeGenerator::setDebugInfo(lto_debug_model debug) { switch (debug) { case LTO_DEBUG_MODEL_NONE: _emitDwarfDebugInfo = false; - return false; + return; case LTO_DEBUG_MODEL_DWARF: _emitDwarfDebugInfo = true; - return false; + return; } llvm_unreachable("Unknown debug format!"); } -bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model, - std::string& errMsg) { +void LTOCodeGenerator::setCodePICModel(lto_codegen_model model) { switch (model) { case LTO_CODEGEN_PIC_MODEL_STATIC: case LTO_CODEGEN_PIC_MODEL_DYNAMIC: case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: _codeModel = model; - return false; + return; } llvm_unreachable("Unknown PIC model!"); } bool LTOCodeGenerator::writeMergedModules(const char *path, std::string &errMsg) { - if (determineTarget(errMsg)) - return true; + if (!determineTarget(errMsg)) + return false; - // mark which symbols can not be internalized - applyScopeRestrictions(); + // Run the verifier on the merged modules. + PassManager passes; + passes.add(createVerifierPass()); + passes.run(*_linker.getModule()); // create output file std::string ErrInfo; - tool_output_file Out(path, ErrInfo, - raw_fd_ostream::F_Binary); + tool_output_file Out(path, ErrInfo, sys::fs::F_Binary); if (!ErrInfo.empty()) { errMsg = "could not open bitcode file for writing: "; errMsg += path; - return true; + return false; } // write bitcode to it @@ -148,52 +182,48 @@ bool LTOCodeGenerator::writeMergedModules(const char *path, errMsg = "could not write bitcode file: "; errMsg += path; Out.os().clear_error(); - return true; + return false; } Out.keep(); - return false; + return true; } bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) { // make unique temp .o file to put generated object file - sys::PathWithStatus uniqueObjPath("lto-llvm.o"); - if (uniqueObjPath.createTemporaryFileOnDisk(false, &errMsg)) { - uniqueObjPath.eraseFromDisk(); - return true; + SmallString<128> Filename; + int FD; + error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); + if (EC) { + errMsg = EC.message(); + return false; } - sys::RemoveFileOnSignal(uniqueObjPath); // generate object file - bool genResult = false; - tool_output_file objFile(uniqueObjPath.c_str(), errMsg); - if (!errMsg.empty()) { - uniqueObjPath.eraseFromDisk(); - return true; - } + tool_output_file objFile(Filename.c_str(), FD); - genResult = this->generateObjectFile(objFile.os(), errMsg); + bool genResult = generateObjectFile(objFile.os(), errMsg); objFile.os().close(); if (objFile.os().has_error()) { objFile.os().clear_error(); - uniqueObjPath.eraseFromDisk(); - return true; + sys::fs::remove(Twine(Filename)); + return false; } objFile.keep(); - if (genResult) { - uniqueObjPath.eraseFromDisk(); - return true; + if (!genResult) { + sys::fs::remove(Twine(Filename)); + return false; } - _nativeObjectPath = uniqueObjPath.str(); + _nativeObjectPath = Filename.c_str(); *name = _nativeObjectPath.c_str(); - return false; + return true; } const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { const char *name; - if (compile_to_file(&name, errMsg)) + if (!compile_to_file(&name, errMsg)) return NULL; // remove old buffer if compile() called twice @@ -203,13 +233,13 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { OwningPtr<MemoryBuffer> BuffPtr; if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) { errMsg = ec.message(); - sys::Path(_nativeObjectPath).eraseFromDisk(); + sys::fs::remove(_nativeObjectPath); return NULL; } _nativeObjectFile = BuffPtr.take(); // remove temp files - sys::Path(_nativeObjectPath).eraseFromDisk(); + sys::fs::remove(_nativeObjectPath); // return buffer, unless error if (_nativeObjectFile == NULL) @@ -218,9 +248,14 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { return _nativeObjectFile->getBufferStart(); } -bool LTOCodeGenerator::determineTarget(std::string& errMsg) { +bool LTOCodeGenerator::determineTarget(std::string &errMsg) { if (_target != NULL) - return false; + return true; + + // if options were requested, set them + if (!_codegenOptions.empty()) + cl::ParseCommandLineOptions(_codegenOptions.size(), + const_cast<char **>(&_codegenOptions[0])); std::string TripleStr = _linker.getModule()->getTargetTriple(); if (TripleStr.empty()) @@ -230,7 +265,7 @@ bool LTOCodeGenerator::determineTarget(std::string& errMsg) { // create target machine from info for merged modules const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); if (march == NULL) - return true; + return false; // The relocation model is actually a static member of TargetMachine and // needs to be set before the TargetMachine is instantiated. @@ -263,7 +298,7 @@ bool LTOCodeGenerator::determineTarget(std::string& errMsg) { _target = march->createTargetMachine(TripleStr, _mCpu, FeatureStr, Options, RelocModel, CodeModel::Default, CodeGenOpt::Aggressive); - return false; + return true; } void LTOCodeGenerator:: @@ -286,9 +321,7 @@ static void findUsedValues(GlobalVariable *LLVMUsed, SmallPtrSet<GlobalValue*, 8> &UsedValues) { if (LLVMUsed == 0) return; - ConstantArray *Inits = dyn_cast<ConstantArray>(LLVMUsed->getInitializer()); - if (Inits == 0) return; - + ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer()); for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) if (GlobalValue *GV = dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts())) @@ -304,8 +337,8 @@ void LTOCodeGenerator::applyScopeRestrictions() { passes.add(createVerifierPass()); // mark which symbols can not be internalized - MCContext Context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(),NULL); - Mangler mangler(Context, *_target->getDataLayout()); + MCContext Context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL); + Mangler mangler(Context, _target); std::vector<const char*> mustPreserveList; SmallPtrSet<GlobalValue*, 8> asmUsed; @@ -325,24 +358,26 @@ void LTOCodeGenerator::applyScopeRestrictions() { if (LLVMCompilerUsed) LLVMCompilerUsed->eraseFromParent(); - llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context); - std::vector<Constant*> asmUsed2; - for (SmallPtrSet<GlobalValue*, 16>::const_iterator i = asmUsed.begin(), - e = asmUsed.end(); i !=e; ++i) { - GlobalValue *GV = *i; - Constant *c = ConstantExpr::getBitCast(GV, i8PTy); - asmUsed2.push_back(c); + if (!asmUsed.empty()) { + llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context); + std::vector<Constant*> asmUsed2; + for (SmallPtrSet<GlobalValue*, 16>::const_iterator i = asmUsed.begin(), + e = asmUsed.end(); i !=e; ++i) { + GlobalValue *GV = *i; + Constant *c = ConstantExpr::getBitCast(GV, i8PTy); + asmUsed2.push_back(c); + } + + llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size()); + LLVMCompilerUsed = + new llvm::GlobalVariable(*mergedModule, ATy, false, + llvm::GlobalValue::AppendingLinkage, + llvm::ConstantArray::get(ATy, asmUsed2), + "llvm.compiler.used"); + + LLVMCompilerUsed->setSection("llvm.metadata"); } - llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size()); - LLVMCompilerUsed = - new llvm::GlobalVariable(*mergedModule, ATy, false, - llvm::GlobalValue::AppendingLinkage, - llvm::ConstantArray::get(ATy, asmUsed2), - "llvm.compiler.used"); - - LLVMCompilerUsed->setSection("llvm.metadata"); - passes.add(createInternalizePass(mustPreserveList)); // apply scope restrictions @@ -354,17 +389,12 @@ void LTOCodeGenerator::applyScopeRestrictions() { /// Optimize merged modules using various IPO passes bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, std::string &errMsg) { - if (this->determineTarget(errMsg)) - return true; + if (!this->determineTarget(errMsg)) + return false; Module* mergedModule = _linker.getModule(); - // if options were requested, set them - if (!_codegenOptions.empty()) - cl::ParseCommandLineOptions(_codegenOptions.size(), - const_cast<char **>(&_codegenOptions[0])); - - // mark which symbols can not be internalized + // Mark which symbols can not be internalized this->applyScopeRestrictions(); // Instantiate the pass manager to organize the passes. @@ -380,12 +410,11 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, // Enabling internalize here would use its AllButMain variant. It // keeps only main if it exists and does nothing for libraries. Instead // we create the pass ourselves with the symbol list provided by the linker. - if (!DisableOpt) { + if (!DisableOpt) PassManagerBuilder().populateLTOPassManager(passes, /*Internalize=*/false, !DisableInline, DisableGVNLoadPRE); - } // Make sure everything is still good. passes.add(createVerifierPass()); @@ -397,10 +426,14 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, formatted_raw_ostream Out(out); + // If the bitcode files contain ARC code and were compiled with optimization, + // the ObjCARCContractPass must be run, so do it unconditionally here. + codeGenPasses.add(createObjCARCContractPass()); + if (_target->addPassesToEmitFile(codeGenPasses, Out, TargetMachine::CGFT_ObjectFile)) { errMsg = "target file type not supported"; - return true; + return false; } // Run our queue of passes all at once now, efficiently. @@ -409,7 +442,7 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, // Run the code generator, and write assembly file codeGenPasses.run(*mergedModule); - return false; // success + return true; } /// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h index 601dbfa..8f37cf0 100644 --- a/tools/lto/LTOCodeGenerator.h +++ b/tools/lto/LTOCodeGenerator.h @@ -9,6 +9,27 @@ // // This file declares the LTOCodeGenerator class. // +// LTO compilation consists of three phases: Pre-IPO, IPO and Post-IPO. +// +// The Pre-IPO phase compiles source code into bitcode file. The resulting +// bitcode files, along with object files and libraries, will be fed to the +// linker to through the IPO and Post-IPO phases. By using obj-file extension, +// the resulting bitcode file disguises itself as an object file, and therefore +// obviates the need of writing a special set of the make-rules only for LTO +// compilation. +// +// The IPO phase perform inter-procedural analyses and optimizations, and +// the Post-IPO consists two sub-phases: intra-procedural scalar optimizations +// (SOPT), and intra-procedural target-dependent code generator (CG). +// +// As of this writing, we don't separate IPO and the Post-IPO SOPT. They +// are intermingled together, and are driven by a single pass manager (see +// PassManagerBuilder::populateLTOPassManager()). +// +// The "LTOCodeGenerator" is the driver for the IPO and Post-IPO stages. +// The "CodeGenerator" here is bit confusing. Don't confuse the "CodeGenerator" +// with the machine specific code generator. +// //===----------------------------------------------------------------------===// #ifndef LTO_CODE_GENERATOR_H @@ -19,6 +40,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/Linker.h" #include <string> +#include <vector> namespace llvm { class LLVMContext; @@ -39,9 +61,11 @@ struct LTOCodeGenerator { LTOCodeGenerator(); ~LTOCodeGenerator(); + // Merge given module, return true on success. bool addModule(struct LTOModule*, std::string &errMsg); - bool setDebugInfo(lto_debug_model, std::string &errMsg); - bool setCodePICModel(lto_codegen_model, std::string &errMsg); + + void setDebugInfo(lto_debug_model); + void setCodePICModel(lto_codegen_model); void setCpu(const char* mCpu) { _mCpu = mCpu; } @@ -49,12 +73,38 @@ struct LTOCodeGenerator { _mustPreserveSymbols[sym] = 1; } + // To pass options to the driver and optimization passes. These options are + // not necessarily for debugging purpose (The function name is misleading). + // This function should be called before LTOCodeGenerator::compilexxx(), + // and LTOCodeGenerator::writeMergedModules(). + // + void setCodeGenDebugOptions(const char *opts); + + // Write the merged module to the file specified by the given path. + // Return true on success. bool writeMergedModules(const char *path, std::string &errMsg); + + // Compile the merged module into a *single* object file; the path to object + // file is returned to the caller via argument "name". Return true on + // success. + // + // NOTE that it is up to the linker to remove the intermediate object file. + // Do not try to remove the object file in LTOCodeGenerator's destructor + // as we don't who (LTOCodeGenerator or the obj file) will last longer. + // bool compile_to_file(const char **name, std::string &errMsg); + + // As with compile_to_file(), this function compiles the merged module into + // single object file. Instead of returning the object-file-path to the caller + // (linker), it brings the object to a buffer, and return the buffer to the + // caller. This function should delete intermediate object file once its content + // is brought to memory. Return NULL is the compilation was not successful. + // const void *compile(size_t *length, std::string &errMsg); - void setCodeGenDebugOptions(const char *opts); private: + void initializeLTOPasses(); + bool generateObjectFile(llvm::raw_ostream &out, std::string &errMsg); void applyScopeRestrictions(); void applyRestriction(llvm::GlobalValue &GV, diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index ff67769..e89733f 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -29,6 +29,7 @@ #include "llvm/MC/SubtargetFeature.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Host.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" @@ -49,11 +50,6 @@ DisableFPElim("disable-fp-elim", cl::init(false)); static cl::opt<bool> -DisableFPElimNonLeaf("disable-non-leaf-fp-elim", - cl::desc("Disable frame pointer elimination optimization for non-leaf funcs"), - cl::init(false)); - -static cl::opt<bool> EnableUnsafeFPMath("enable-unsafe-fp-math", cl::desc("Enable optimizations that may decrease FP precision"), cl::init(false)); @@ -125,11 +121,6 @@ OverrideStackAlignment("stack-alignment", cl::desc("Override default stack alignment"), cl::init(0)); -static cl::opt<bool> -EnableRealignStack("realign-stack", - cl::desc("Realign stack if needed"), - cl::init(true)); - static cl::opt<std::string> TrapFuncName("trap-func", cl::Hidden, cl::desc("Emit a call to trap function rather than a trap instruction"), @@ -150,25 +141,23 @@ UseInitArray("use-init-array", cl::desc("Use .init_array instead of .ctors."), cl::init(false)); -static cl::opt<unsigned> -SSPBufferSize("stack-protector-buffer-size", cl::init(8), - cl::desc("Lower bound for a buffer to be considered for " - "stack protection")); - LTOModule::LTOModule(llvm::Module *m, llvm::TargetMachine *t) : _module(m), _target(t), - _context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(), NULL), - _mangler(_context, *_target->getDataLayout()) {} + _context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL), + _mangler(_context, t) {} /// isBitcodeFile - Returns 'true' if the file (or memory contents) is LLVM /// bitcode. bool LTOModule::isBitcodeFile(const void *mem, size_t length) { - return llvm::sys::IdentifyFileType((const char*)mem, length) - == llvm::sys::Bitcode_FileType; + return sys::fs::identify_magic(StringRef((const char *)mem, length)) == + sys::fs::file_magic::bitcode; } bool LTOModule::isBitcodeFile(const char *path) { - return llvm::sys::Path(path).isBitcodeFile(); + sys::fs::file_magic type; + if (sys::fs::identify_magic(path, type)) + return false; + return type == sys::fs::file_magic::bitcode; } /// isBitcodeFileForTarget - Returns 'true' if the file (or memory contents) is @@ -210,17 +199,16 @@ LTOModule *LTOModule::makeLTOModule(const char *path, std::string &errMsg) { LTOModule *LTOModule::makeLTOModule(int fd, const char *path, size_t size, std::string &errMsg) { - return makeLTOModule(fd, path, size, size, 0, errMsg); + return makeLTOModule(fd, path, size, 0, errMsg); } LTOModule *LTOModule::makeLTOModule(int fd, const char *path, - size_t file_size, size_t map_size, off_t offset, std::string &errMsg) { OwningPtr<MemoryBuffer> buffer; - if (error_code ec = MemoryBuffer::getOpenFile(fd, path, buffer, file_size, - map_size, offset, false)) { + if (error_code ec = + MemoryBuffer::getOpenFileSlice(fd, path, buffer, map_size, offset)) { errMsg = ec.message(); return NULL; } @@ -238,7 +226,6 @@ LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, void LTOModule::getTargetOptions(TargetOptions &Options) { Options.LessPreciseFPMADOption = EnableFPMAD; Options.NoFramePointerElim = DisableFPElim; - Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf; Options.AllowFPOpFusion = FuseFPOps; Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; @@ -252,12 +239,10 @@ void LTOModule::getTargetOptions(TargetOptions &Options) { Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.DisableTailCalls = DisableTailCalls; Options.StackAlignmentOverride = OverrideStackAlignment; - Options.RealignStack = EnableRealignStack; Options.TrapFuncName = TrapFuncName; Options.PositionIndependentExecutable = EnablePIE; Options.EnableSegmentedStacks = SegmentedStacks; Options.UseInitArray = UseInitArray; - Options.SSPBufferSize = SSPBufferSize; } LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, @@ -487,7 +472,7 @@ void LTOModule::addDefinedSymbol(const GlobalValue *def, bool isFunction) { // set alignment part log2() can have rounding errors uint32_t align = def->getAlignment(); - uint32_t attr = align ? CountTrailingZeros_32(def->getAlignment()) : 0; + uint32_t attr = align ? countTrailingZeros(def->getAlignment()) : 0; // set permissions part if (isFunction) { @@ -743,7 +728,7 @@ namespace { AddValueSymbols(Inst.getOperand(i).getExpr()); } virtual void EmitLabel(MCSymbol *Symbol) { - Symbol->setSection(*getCurrentSection()); + Symbol->setSection(*getCurrentSection().first); markDefined(*Symbol); } virtual void EmitDebugLabel(MCSymbol *Symbol) { @@ -771,7 +756,8 @@ namespace { virtual void EmitBundleUnlock() {} // Noop calls. - virtual void ChangeSection(const MCSection *Section) {} + virtual void ChangeSection(const MCSection *Section, + const MCExpr *Subsection) {} virtual void InitToTextSection() {} virtual void InitSections() {} virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} @@ -787,9 +773,8 @@ namespace { unsigned ByteAlignment) {} virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} - virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {} - virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) {} + virtual void EmitBytes(StringRef Data) {} + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size) {} virtual void EmitULEB128Value(const MCExpr *Value) {} virtual void EmitSLEB128Value(const MCExpr *Value) {} virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h index 83f3a7d..902e9c5 100644 --- a/tools/lto/LTOModule.h +++ b/tools/lto/LTOModule.h @@ -82,7 +82,6 @@ public: static LTOModule *makeLTOModule(int fd, const char *path, size_t size, std::string &errMsg); static LTOModule *makeLTOModule(int fd, const char *path, - size_t file_size, size_t map_size, off_t offset, std::string& errMsg); diff --git a/tools/lto/Makefile b/tools/lto/Makefile index ab2e16e..56c67df 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -39,15 +39,14 @@ ifeq ($(HOST_OS),Darwin) endif # extra options to override libtool defaults LLVMLibsOptions := $(LLVMLibsOptions) \ - -Wl,-dead_strip \ - -Wl,-seg1addr -Wl,0xE0000000 + -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)" + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif # If we're doing an Apple-style build, add the LTO object path. diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index 11ad532..db7147c 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -78,8 +78,7 @@ lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path, size_t file_size, size_t map_size, off_t offset) { - return LTOModule::makeLTOModule(fd, path, file_size, map_size, - offset, sLastErrorString); + return LTOModule::makeLTOModule(fd, path, map_size, offset, sLastErrorString); } /// lto_module_create_from_memory - Loads an object file from memory. Returns @@ -141,20 +140,22 @@ void lto_codegen_dispose(lto_code_gen_t cg) { /// which code will be generated. Returns true on error (check /// lto_get_error_message() for details). bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod) { - return cg->addModule(mod, sLastErrorString); + return !cg->addModule(mod, sLastErrorString); } /// lto_codegen_set_debug_model - Sets what if any format of debug info should /// be generated. Returns true on error (check lto_get_error_message() for /// details). bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug) { - return cg->setDebugInfo(debug, sLastErrorString); + cg->setDebugInfo(debug); + return false; } /// lto_codegen_set_pic_model - Sets what code model to generated. Returns true /// on error (check lto_get_error_message() for details). bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model) { - return cg->setCodePICModel(model, sLastErrorString); + cg->setCodePICModel(model); + return false; } /// lto_codegen_set_cpu - Sets the cpu to generate code for. @@ -186,7 +187,7 @@ void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, /// that contains the merged contents of all modules added so far. Returns true /// on error (check lto_get_error_message() for details). bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) { - return cg->writeMergedModules(path, sLastErrorString); + return !cg->writeMergedModules(path, sLastErrorString); } /// lto_codegen_compile - Generates code for all added modules into one native @@ -203,7 +204,7 @@ const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) { /// native object file. The name of the file is written to name. Returns true on /// error. bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) { - return cg->compile_to_file(name, sLastErrorString); + return !cg->compile_to_file(name, sLastErrorString); } /// lto_codegen_debug_options - Used to pass extra options to the code diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index 3bd3ecc..897a785 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -11,9 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Object/MachOObject.h" +#include "llvm/Object/MachO.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" @@ -66,7 +67,8 @@ static void DumpSegmentCommandData(StringRef Name, outs() << " ('flags', " << Flags << ")\n"; } -static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name, +static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index, + StringRef Name, StringRef SegmentName, uint64_t Address, uint64_t Size, uint32_t Offset, uint32_t Align, uint32_t RelocationTableOffset, @@ -92,26 +94,22 @@ static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name, outs() << " ),\n"; // Dump the relocation entries. - int Res = 0; outs() << " ('_relocations', [\n"; - for (unsigned i = 0; i != NumRelocationTableEntries; ++i) { - InMemoryStruct<macho::RelocationEntry> RE; - Obj.ReadRelocationEntry(RelocationTableOffset, i, RE); - if (!RE) { - Res = Error("unable to read relocation table entry '" + Twine(i) + "'"); - break; - } - - outs() << " # Relocation " << i << "\n"; - outs() << " (('word-0', " << format("0x%x", RE->Word0) << "),\n"; - outs() << " ('word-1', " << format("0x%x", RE->Word1) << ")),\n"; + unsigned RelNum = 0; + error_code EC; + for (relocation_iterator I = Obj.getSectionRelBegin(Index), + E = Obj.getSectionRelEnd(Index); I != E; I.increment(EC), ++RelNum) { + macho::RelocationEntry RE = Obj.getRelocation(I->getRawDataRefImpl()); + outs() << " # Relocation " << RelNum << "\n"; + outs() << " (('word-0', " << format("0x%x", RE.Word0) << "),\n"; + outs() << " ('word-1', " << format("0x%x", RE.Word1) << ")),\n"; } outs() << " ])\n"; // Dump the section data, if requested. if (ShowSectionData) { outs() << " ('_section_data', '"; - StringRef Data = Obj.getData(Offset, Size); + StringRef Data = Obj.getData().substr(Offset, Size); for (unsigned i = 0; i != Data.size(); ++i) { if (i && (i % 4) == 0) outs() << ' '; @@ -121,208 +119,162 @@ static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name, outs() << "')\n"; } - return Res; + return 0; } -static int DumpSegmentCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct<macho::SegmentLoadCommand> SLC; - Obj.ReadSegmentLoadCommand(LCI, SLC); - if (!SLC) - return Error("unable to read segment load command"); +static int DumpSegmentCommand(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::SegmentLoadCommand SLC = Obj.getSegmentLoadCommand(LCI); - DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress, - SLC->VMSize, SLC->FileOffset, SLC->FileSize, - SLC->MaxVMProtection, SLC->InitialVMProtection, - SLC->NumSections, SLC->Flags); + DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress, + SLC.VMSize, SLC.FileOffset, SLC.FileSize, + SLC.MaxVMProtection, SLC.InitialVMProtection, + SLC.NumSections, SLC.Flags); // Dump the sections. - int Res = 0; outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC->NumSections; ++i) { - InMemoryStruct<macho::Section> Sect; - Obj.ReadSection(LCI, i, Sect); - if (!SLC) { - Res = Error("unable to read section '" + Twine(i) + "'"); - break; - } - - if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16), - StringRef(Sect->SegmentName, 16), Sect->Address, - Sect->Size, Sect->Offset, Sect->Align, - Sect->RelocationTableOffset, - Sect->NumRelocationTableEntries, Sect->Flags, - Sect->Reserved1, Sect->Reserved2))) - break; + for (unsigned i = 0; i != SLC.NumSections; ++i) { + macho::Section Sect = Obj.getSection(LCI, i); + DumpSectionData(Obj, i, StringRef(Sect.Name, 16), + StringRef(Sect.SegmentName, 16), Sect.Address, + Sect.Size, Sect.Offset, Sect.Align, + Sect.RelocationTableOffset, + Sect.NumRelocationTableEntries, Sect.Flags, + Sect.Reserved1, Sect.Reserved2); } outs() << " ])\n"; - return Res; + return 0; } -static int DumpSegment64Command(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct<macho::Segment64LoadCommand> SLC; - Obj.ReadSegment64LoadCommand(LCI, SLC); - if (!SLC) - return Error("unable to read segment load command"); - - DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress, - SLC->VMSize, SLC->FileOffset, SLC->FileSize, - SLC->MaxVMProtection, SLC->InitialVMProtection, - SLC->NumSections, SLC->Flags); +static int DumpSegment64Command(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::Segment64LoadCommand SLC = Obj.getSegment64LoadCommand(LCI); + DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress, + SLC.VMSize, SLC.FileOffset, SLC.FileSize, + SLC.MaxVMProtection, SLC.InitialVMProtection, + SLC.NumSections, SLC.Flags); // Dump the sections. - int Res = 0; outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC->NumSections; ++i) { - InMemoryStruct<macho::Section64> Sect; - Obj.ReadSection64(LCI, i, Sect); - if (!SLC) { - Res = Error("unable to read section '" + Twine(i) + "'"); - break; - } - - if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16), - StringRef(Sect->SegmentName, 16), Sect->Address, - Sect->Size, Sect->Offset, Sect->Align, - Sect->RelocationTableOffset, - Sect->NumRelocationTableEntries, Sect->Flags, - Sect->Reserved1, Sect->Reserved2, - Sect->Reserved3))) - break; + for (unsigned i = 0; i != SLC.NumSections; ++i) { + macho::Section64 Sect = Obj.getSection64(LCI, i); + + DumpSectionData(Obj, i, StringRef(Sect.Name, 16), + StringRef(Sect.SegmentName, 16), Sect.Address, + Sect.Size, Sect.Offset, Sect.Align, + Sect.RelocationTableOffset, + Sect.NumRelocationTableEntries, Sect.Flags, + Sect.Reserved1, Sect.Reserved2, + Sect.Reserved3); } outs() << " ])\n"; - return Res; + return 0; } -static void DumpSymbolTableEntryData(MachOObject &Obj, +static void DumpSymbolTableEntryData(const MachOObjectFile &Obj, unsigned Index, uint32_t StringIndex, uint8_t Type, uint8_t SectionIndex, - uint16_t Flags, uint64_t Value) { + uint16_t Flags, uint64_t Value, + StringRef StringTable) { + const char *Name = &StringTable.data()[StringIndex]; outs() << " # Symbol " << Index << "\n"; outs() << " (('n_strx', " << StringIndex << ")\n"; outs() << " ('n_type', " << format("0x%x", Type) << ")\n"; outs() << " ('n_sect', " << uint32_t(SectionIndex) << ")\n"; outs() << " ('n_desc', " << Flags << ")\n"; outs() << " ('n_value', " << Value << ")\n"; - outs() << " ('_string', '" << Obj.getStringAtIndex(StringIndex) << "')\n"; + outs() << " ('_string', '" << Name << "')\n"; outs() << " ),\n"; } -static int DumpSymtabCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct<macho::SymtabLoadCommand> SLC; - Obj.ReadSymtabLoadCommand(LCI, SLC); - if (!SLC) - return Error("unable to read segment load command"); - - outs() << " ('symoff', " << SLC->SymbolTableOffset << ")\n"; - outs() << " ('nsyms', " << SLC->NumSymbolTableEntries << ")\n"; - outs() << " ('stroff', " << SLC->StringTableOffset << ")\n"; - outs() << " ('strsize', " << SLC->StringTableSize << ")\n"; +static int DumpSymtabCommand(const MachOObjectFile &Obj) { + macho::SymtabLoadCommand SLC = Obj.getSymtabLoadCommand(); - // Cache the string table data. - Obj.RegisterStringTable(*SLC); + outs() << " ('symoff', " << SLC.SymbolTableOffset << ")\n"; + outs() << " ('nsyms', " << SLC.NumSymbolTableEntries << ")\n"; + outs() << " ('stroff', " << SLC.StringTableOffset << ")\n"; + outs() << " ('strsize', " << SLC.StringTableSize << ")\n"; // Dump the string data. outs() << " ('_string_data', '"; - outs().write_escaped(Obj.getStringTableData(), + StringRef StringTable = Obj.getStringTableData(); + outs().write_escaped(StringTable, /*UseHexEscapes=*/true) << "')\n"; // Dump the symbol table. - int Res = 0; outs() << " ('_symbols', [\n"; - for (unsigned i = 0; i != SLC->NumSymbolTableEntries; ++i) { + 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(); if (Obj.is64Bit()) { - InMemoryStruct<macho::Symbol64TableEntry> STE; - Obj.ReadSymbol64TableEntry(SLC->SymbolTableOffset, i, STE); - if (!STE) { - Res = Error("unable to read symbol: '" + Twine(i) + "'"); - break; - } - - DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type, - STE->SectionIndex, STE->Flags, STE->Value); + macho::Symbol64TableEntry STE = Obj.getSymbol64TableEntry(DRI); + DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type, + STE.SectionIndex, STE.Flags, STE.Value, + StringTable); } else { - InMemoryStruct<macho::SymbolTableEntry> STE; - Obj.ReadSymbolTableEntry(SLC->SymbolTableOffset, i, STE); - if (!SLC) { - Res = Error("unable to read symbol: '" + Twine(i) + "'"); - break; - } - - DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type, - STE->SectionIndex, STE->Flags, STE->Value); + macho::SymbolTableEntry STE = Obj.getSymbolTableEntry(DRI); + DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type, + STE.SectionIndex, STE.Flags, STE.Value, + StringTable); } } outs() << " ])\n"; - return Res; + return 0; } -static int DumpDysymtabCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct<macho::DysymtabLoadCommand> DLC; - Obj.ReadDysymtabLoadCommand(LCI, DLC); - if (!DLC) - return Error("unable to read segment load command"); - - outs() << " ('ilocalsym', " << DLC->LocalSymbolsIndex << ")\n"; - outs() << " ('nlocalsym', " << DLC->NumLocalSymbols << ")\n"; - outs() << " ('iextdefsym', " << DLC->ExternalSymbolsIndex << ")\n"; - outs() << " ('nextdefsym', " << DLC->NumExternalSymbols << ")\n"; - outs() << " ('iundefsym', " << DLC->UndefinedSymbolsIndex << ")\n"; - outs() << " ('nundefsym', " << DLC->NumUndefinedSymbols << ")\n"; - outs() << " ('tocoff', " << DLC->TOCOffset << ")\n"; - outs() << " ('ntoc', " << DLC->NumTOCEntries << ")\n"; - outs() << " ('modtaboff', " << DLC->ModuleTableOffset << ")\n"; - outs() << " ('nmodtab', " << DLC->NumModuleTableEntries << ")\n"; - outs() << " ('extrefsymoff', " << DLC->ReferenceSymbolTableOffset << ")\n"; +static int DumpDysymtabCommand(const MachOObjectFile &Obj) { + macho::DysymtabLoadCommand DLC = Obj.getDysymtabLoadCommand(); + + outs() << " ('ilocalsym', " << DLC.LocalSymbolsIndex << ")\n"; + outs() << " ('nlocalsym', " << DLC.NumLocalSymbols << ")\n"; + outs() << " ('iextdefsym', " << DLC.ExternalSymbolsIndex << ")\n"; + outs() << " ('nextdefsym', " << DLC.NumExternalSymbols << ")\n"; + outs() << " ('iundefsym', " << DLC.UndefinedSymbolsIndex << ")\n"; + outs() << " ('nundefsym', " << DLC.NumUndefinedSymbols << ")\n"; + outs() << " ('tocoff', " << DLC.TOCOffset << ")\n"; + outs() << " ('ntoc', " << DLC.NumTOCEntries << ")\n"; + outs() << " ('modtaboff', " << DLC.ModuleTableOffset << ")\n"; + outs() << " ('nmodtab', " << DLC.NumModuleTableEntries << ")\n"; + outs() << " ('extrefsymoff', " << DLC.ReferenceSymbolTableOffset << ")\n"; outs() << " ('nextrefsyms', " - << DLC->NumReferencedSymbolTableEntries << ")\n"; - outs() << " ('indirectsymoff', " << DLC->IndirectSymbolTableOffset << ")\n"; + << DLC.NumReferencedSymbolTableEntries << ")\n"; + outs() << " ('indirectsymoff', " << DLC.IndirectSymbolTableOffset << ")\n"; outs() << " ('nindirectsyms', " - << DLC->NumIndirectSymbolTableEntries << ")\n"; - outs() << " ('extreloff', " << DLC->ExternalRelocationTableOffset << ")\n"; - outs() << " ('nextrel', " << DLC->NumExternalRelocationTableEntries << ")\n"; - outs() << " ('locreloff', " << DLC->LocalRelocationTableOffset << ")\n"; - outs() << " ('nlocrel', " << DLC->NumLocalRelocationTableEntries << ")\n"; + << DLC.NumIndirectSymbolTableEntries << ")\n"; + outs() << " ('extreloff', " << DLC.ExternalRelocationTableOffset << ")\n"; + outs() << " ('nextrel', " << DLC.NumExternalRelocationTableEntries << ")\n"; + outs() << " ('locreloff', " << DLC.LocalRelocationTableOffset << ")\n"; + outs() << " ('nlocrel', " << DLC.NumLocalRelocationTableEntries << ")\n"; // Dump the indirect symbol table. - int Res = 0; outs() << " ('_indirect_symbols', [\n"; - for (unsigned i = 0; i != DLC->NumIndirectSymbolTableEntries; ++i) { - InMemoryStruct<macho::IndirectSymbolTableEntry> ISTE; - Obj.ReadIndirectSymbolTableEntry(*DLC, i, ISTE); - if (!ISTE) { - Res = Error("unable to read segment load command"); - break; - } - + for (unsigned i = 0; i != DLC.NumIndirectSymbolTableEntries; ++i) { + macho::IndirectSymbolTableEntry ISTE = + Obj.getIndirectSymbolTableEntry(DLC, i); outs() << " # Indirect Symbol " << i << "\n"; outs() << " (('symbol_index', " - << format("0x%x", ISTE->Index) << "),),\n"; + << format("0x%x", ISTE.Index) << "),),\n"; } outs() << " ])\n"; - return Res; + return 0; } -static int DumpLinkeditDataCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct<macho::LinkeditDataLoadCommand> LLC; - Obj.ReadLinkeditDataLoadCommand(LCI, LLC); - if (!LLC) - return Error("unable to read segment load command"); - - outs() << " ('dataoff', " << LLC->DataOffset << ")\n" - << " ('datasize', " << LLC->DataSize << ")\n" +static int +DumpLinkeditDataCommand(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI); + outs() << " ('dataoff', " << LLC.DataOffset << ")\n" + << " ('datasize', " << LLC.DataSize << ")\n" << " ('_addresses', [\n"; SmallVector<uint64_t, 8> Addresses; - Obj.ReadULEB128s(LLC->DataOffset, Addresses); + Obj.ReadULEB128s(LLC.DataOffset, Addresses); for (unsigned i = 0, e = Addresses.size(); i != e; ++i) outs() << " # Address " << i << '\n' << " ('address', " << format("0x%x", Addresses[i]) << "),\n"; @@ -332,28 +284,22 @@ static int DumpLinkeditDataCommand(MachOObject &Obj, return 0; } -static int DumpDataInCodeDataCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct<macho::LinkeditDataLoadCommand> LLC; - Obj.ReadLinkeditDataLoadCommand(LCI, LLC); - if (!LLC) - return Error("unable to read data-in-code load command"); - - outs() << " ('dataoff', " << LLC->DataOffset << ")\n" - << " ('datasize', " << LLC->DataSize << ")\n" +static int +DumpDataInCodeDataCommand(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI); + outs() << " ('dataoff', " << LLC.DataOffset << ")\n" + << " ('datasize', " << LLC.DataSize << ")\n" << " ('_data_regions', [\n"; - - unsigned NumRegions = LLC->DataSize / 8; + unsigned NumRegions = LLC.DataSize / sizeof(macho::DataInCodeTableEntry); for (unsigned i = 0; i < NumRegions; ++i) { - InMemoryStruct<macho::DataInCodeTableEntry> DICE; - Obj.ReadDataInCodeTableEntry(LLC->DataOffset, i, DICE); - if (!DICE) - return Error("unable to read DataInCodeTableEntry"); + macho::DataInCodeTableEntry DICE = + Obj.getDataInCodeTableEntry(LLC.DataOffset, i); outs() << " # DICE " << i << "\n" - << " ('offset', " << DICE->Offset << ")\n" - << " ('length', " << DICE->Length << ")\n" - << " ('kind', " << DICE->Kind << ")\n"; + << " ('offset', " << DICE.Offset << ")\n" + << " ('length', " << DICE.Length << ")\n" + << " ('kind', " << DICE.Kind << ")\n"; } outs() <<" ])\n"; @@ -361,99 +307,111 @@ static int DumpDataInCodeDataCommand(MachOObject &Obj, return 0; } -static int DumpLinkerOptionsCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct<macho::LinkerOptionsLoadCommand> LOLC; - Obj.ReadLinkerOptionsLoadCommand(LCI, LOLC); - if (!LOLC) - return Error("unable to read linker options load command"); - - outs() << " ('count', " << LOLC->Count << ")\n" - << " ('_strings', [\n"; - - uint64_t DataSize = LOLC->Size - sizeof(macho::LinkerOptionsLoadCommand); - StringRef Data = Obj.getData( - LCI.Offset + sizeof(macho::LinkerOptionsLoadCommand), DataSize); - for (unsigned i = 0; i != LOLC->Count; ++i) { - std::pair<StringRef,StringRef> Split = Data.split('\0'); - outs() << "\t\""; - outs().write_escaped(Split.first); - outs() << "\",\n"; - Data = Split.second; - } - outs() <<" ])\n"; +static int +DumpLinkerOptionsCommand(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::LinkerOptionsLoadCommand LOLC = Obj.getLinkerOptionsLoadCommand(LCI); + outs() << " ('count', " << LOLC.Count << ")\n" + << " ('_strings', [\n"; + + uint64_t DataSize = LOLC.Size - sizeof(macho::LinkerOptionsLoadCommand); + const char *P = LCI.Ptr + sizeof(macho::LinkerOptionsLoadCommand); + StringRef Data(P, DataSize); + for (unsigned i = 0; i != LOLC.Count; ++i) { + std::pair<StringRef,StringRef> Split = Data.split('\0'); + outs() << "\t\""; + outs().write_escaped(Split.first); + outs() << "\",\n"; + Data = Split.second; + } + outs() <<" ])\n"; return 0; } - -static int DumpLoadCommand(MachOObject &Obj, unsigned Index) { - const MachOObject::LoadCommandInfo &LCI = Obj.getLoadCommandInfo(Index); - int Res = 0; - - outs() << " # Load Command " << Index << "\n" - << " (('command', " << LCI.Command.Type << ")\n" - << " ('size', " << LCI.Command.Size << ")\n"; - switch (LCI.Command.Type) { +static int DumpLoadCommand(const MachOObjectFile &Obj, + MachOObjectFile::LoadCommandInfo &LCI) { + switch (LCI.C.Type) { case macho::LCT_Segment: - Res = DumpSegmentCommand(Obj, LCI); - break; + return DumpSegmentCommand(Obj, LCI); case macho::LCT_Segment64: - Res = DumpSegment64Command(Obj, LCI); - break; + return DumpSegment64Command(Obj, LCI); case macho::LCT_Symtab: - Res = DumpSymtabCommand(Obj, LCI); - break; + return DumpSymtabCommand(Obj); case macho::LCT_Dysymtab: - Res = DumpDysymtabCommand(Obj, LCI); - break; + return DumpDysymtabCommand(Obj); case macho::LCT_CodeSignature: case macho::LCT_SegmentSplitInfo: case macho::LCT_FunctionStarts: - Res = DumpLinkeditDataCommand(Obj, LCI); - break; + return DumpLinkeditDataCommand(Obj, LCI); case macho::LCT_DataInCode: - Res = DumpDataInCodeDataCommand(Obj, LCI); - break; + return DumpDataInCodeDataCommand(Obj, LCI); case macho::LCT_LinkerOptions: - Res = DumpLinkerOptionsCommand(Obj, LCI); - break; + return DumpLinkerOptionsCommand(Obj, LCI); default: - Warning("unknown load command: " + Twine(LCI.Command.Type)); - break; + Warning("unknown load command: " + Twine(LCI.C.Type)); + return 0; } - outs() << " ),\n"; +} + +static int DumpLoadCommand(const MachOObjectFile &Obj, unsigned Index, + MachOObjectFile::LoadCommandInfo &LCI) { + outs() << " # Load Command " << Index << "\n" + << " (('command', " << LCI.C.Type << ")\n" + << " ('size', " << LCI.C.Size << ")\n"; + int Res = DumpLoadCommand(Obj, LCI); + outs() << " ),\n"; return Res; } +static void printHeader(const MachOObjectFile *Obj, + const macho::Header &Header) { + outs() << "('cputype', " << Header.CPUType << ")\n"; + outs() << "('cpusubtype', " << Header.CPUSubtype << ")\n"; + outs() << "('filetype', " << Header.FileType << ")\n"; + outs() << "('num_load_commands', " << Header.NumLoadCommands << ")\n"; + outs() << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n"; + outs() << "('flag', " << Header.Flags << ")\n"; + + // Print extended header if 64-bit. + if (Obj->is64Bit()) { + macho::Header64Ext Header64Ext = Obj->getHeader64Ext(); + outs() << "('reserved', " << Header64Ext.Reserved << ")\n"; + } +} + int main(int argc, char **argv) { ProgramName = argv[0]; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm Mach-O dumping tool\n"); - // Load the input file. - std::string ErrorStr; - OwningPtr<MemoryBuffer> InputBuffer; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFile, InputBuffer)) - return Error("unable to read input: '" + ec.message() + "'"); + OwningPtr<Binary> Binary; + if (error_code EC = createBinary(InputFile, Binary)) + return Error("unable to read input: '" + EC.message() + "'"); - // Construct the Mach-O wrapper object. - OwningPtr<MachOObject> InputObject( - MachOObject::LoadFromBuffer(InputBuffer.take(), &ErrorStr)); + const MachOObjectFile *InputObject = dyn_cast<MachOObjectFile>(Binary.get()); if (!InputObject) - return Error("unable to load object: '" + ErrorStr + "'"); + return Error("Not a MachO object"); // Print the header - InputObject->printHeader(outs()); + macho::Header Header = InputObject->getHeader(); + printHeader(InputObject, Header); // Print the load commands. int Res = 0; + MachOObjectFile::LoadCommandInfo Command = + InputObject->getFirstLoadCommandInfo(); outs() << "('load_commands', [\n"; - for (unsigned i = 0; i != InputObject->getHeader().NumLoadCommands; ++i) - if ((Res = DumpLoadCommand(*InputObject, i))) + for (unsigned i = 0; ; ++i) { + if (DumpLoadCommand(*InputObject, i, Command)) break; + + if (i == Header.NumLoadCommands - 1) + break; + Command = InputObject->getNextLoadCommandInfo(Command); + } outs() << "])\n"; return Res; diff --git a/tools/obj2yaml/CMakeLists.txt b/tools/obj2yaml/CMakeLists.txt new file mode 100644 index 0000000..6b39193 --- /dev/null +++ b/tools/obj2yaml/CMakeLists.txt @@ -0,0 +1,7 @@ +set(LLVM_LINK_COMPONENTS object) + +add_llvm_utility(obj2yaml + obj2yaml.cpp coff2yaml.cpp + ) + +target_link_libraries(obj2yaml LLVMSupport) diff --git a/tools/llvm-ranlib/Makefile b/tools/obj2yaml/Makefile index cca9501..95f393d 100644 --- a/tools/llvm-ranlib/Makefile +++ b/tools/obj2yaml/Makefile @@ -1,17 +1,20 @@ -##===- tools/llvm-ranlib/Makefile --------------------------*- Makefile -*-===## -# +##===- utils/obj2yaml/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-ranlib -LINK_COMPONENTS := archive +LEVEL = ../.. +TOOLNAME = obj2yaml +LINK_COMPONENTS := object # This tool has no plugins, optimize startup time. -TOOL_NO_EXPORTS := 1 +TOOL_NO_EXPORTS = 1 + +# Don't install this utility +NO_INSTALL = 1 include $(LEVEL)/Makefile.common diff --git a/tools/obj2yaml/coff2yaml.cpp b/tools/obj2yaml/coff2yaml.cpp new file mode 100644 index 0000000..1e28c4e --- /dev/null +++ b/tools/obj2yaml/coff2yaml.cpp @@ -0,0 +1,120 @@ +//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "obj2yaml.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/COFFYAML.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace llvm; + +namespace { + +class COFFDumper { + const object::COFFObjectFile &Obj; + COFFYAML::Object YAMLObj; + void dumpHeader(const object::coff_file_header *Header); + void dumpSections(unsigned numSections); + void dumpSymbols(unsigned numSymbols); + +public: + COFFDumper(const object::COFFObjectFile &Obj); + COFFYAML::Object &getYAMLObj(); +}; + +} + +static void check(error_code ec) { + if (ec) + report_fatal_error(ec.message()); +} + +COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) { + const object::coff_file_header *Header; + check(Obj.getCOFFHeader(Header)); + dumpHeader(Header); + dumpSections(Header->NumberOfSections); + dumpSymbols(Header->NumberOfSymbols); +} + +void COFFDumper::dumpHeader(const object::coff_file_header *Header) { + YAMLObj.Header.Machine = Header->Machine; + YAMLObj.Header.Characteristics = Header->Characteristics; +} + +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); + COFFYAML::Section Sec; + Sec.Name = Sect->Name; // FIXME: check the null termination! + uint32_t Characteristics = Sect->Characteristics; + Sec.Header.Characteristics = Characteristics; + Sec.Alignment = 1 << (((Characteristics >> 20) & 0xf) - 1); + + ArrayRef<uint8_t> sectionData; + Obj.getSectionContents(Sect, sectionData); + 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); + COFFYAML::Relocation Rel; + object::symbol_iterator Sym = rIter->getSymbol(); + StringRef Name; + Sym->getName(Rel.SymbolName); + Rel.VirtualAddress = reloc->VirtualAddress; + Rel.Type = reloc->Type; + Relocations.push_back(Rel); + } + Sec.Relocations = Relocations; + Sections.push_back(Sec); + } +} + +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); + COFFYAML::Symbol Sym; + Obj.getSymbolName(Symbol, Sym.Name); + Sym.SimpleType = COFF::SymbolBaseType(Symbol->getBaseType()); + Sym.ComplexType = COFF::SymbolComplexType(Symbol->getComplexType()); + Sym.Header.StorageClass = Symbol->StorageClass; + Sym.Header.Value = Symbol->Value; + Sym.Header.SectionNumber = Symbol->SectionNumber; + Sym.Header.NumberOfAuxSymbols = Symbol->NumberOfAuxSymbols; + Sym.AuxiliaryData = object::yaml::BinaryRef(Obj.getSymbolAuxData(Symbol)); + Symbols.push_back(Sym); + } +} + +COFFYAML::Object &COFFDumper::getYAMLObj() { + return YAMLObj; +} + +error_code coff2yaml(raw_ostream &Out, MemoryBuffer *Buff) { + error_code ec; + object::COFFObjectFile Obj(Buff, ec); + check(ec); + COFFDumper Dumper(Obj); + + yaml::Output Yout(Out); + Yout << Dumper.getYAMLObj(); + + return object::object_error::success; +} diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp new file mode 100644 index 0000000..8d128b3 --- /dev/null +++ b/tools/obj2yaml/obj2yaml.cpp @@ -0,0 +1,54 @@ +//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "obj2yaml.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" + +using namespace llvm; + +namespace { +enum ObjectFileType { + coff +}; +} + +cl::opt<ObjectFileType> InputFormat( + cl::desc("Choose input format"), + cl::values(clEnumVal(coff, "process COFF object files"), clEnumValEnd)); + +cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"), + cl::init("-")); + +int main(int argc, char *argv[]) { + cl::ParseCommandLineOptions(argc, argv); + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + // Process the input file + OwningPtr<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()); + if (ec) + errs() << "Error: " << ec.message() << " dumping COFF file\n"; + } + + return 0; +} diff --git a/tools/obj2yaml/obj2yaml.h b/tools/obj2yaml/obj2yaml.h new file mode 100644 index 0000000..bde82e6 --- /dev/null +++ b/tools/obj2yaml/obj2yaml.h @@ -0,0 +1,22 @@ +//===------ utils/obj2yaml.hpp - obj2yaml conversion tool -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// This file declares some helper routines, and also the format-specific +// writers. To add a new format, add the declaration here, and, in a separate +// source file, implement it. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OBJ2YAML_H +#define LLVM_TOOLS_OBJ2YAML_H + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + +llvm::error_code coff2yaml(llvm::raw_ostream &Out, llvm::MemoryBuffer *TheObj); + +#endif diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt index cf5e5a8..9195911 100644 --- a/tools/opt/CMakeLists.txt +++ b/tools/opt/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser bitwriter instrumentation scalaropts objcarcopts ipo vectorize) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser bitwriter irreader instrumentation scalaropts objcarcopts ipo vectorize) add_llvm_tool(opt AnalysisWrappers.cpp @@ -6,3 +6,4 @@ add_llvm_tool(opt PrintSCC.cpp opt.cpp ) +set_target_properties(opt PROPERTIES ENABLE_EXPORTS 1) diff --git a/tools/opt/LLVMBuild.txt b/tools/opt/LLVMBuild.txt index a866d12..77b9446 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 IPO Instrumentation Scalar ObjCARC all-targets +required_libraries = AsmParser BitReader BitWriter IRReader IPO Instrumentation Scalar ObjCARC all-targets diff --git a/tools/opt/Makefile b/tools/opt/Makefile index 79ed815..a451005 100644 --- a/tools/opt/Makefile +++ b/tools/opt/Makefile @@ -9,6 +9,6 @@ LEVEL := ../.. TOOLNAME := opt -LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts objcarcopts ipo vectorize all-targets +LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets include $(LEVEL)/Makefile.common diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 81a2de2..37637ca 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -26,17 +26,18 @@ #include "llvm/DebugInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.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/IRReader.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" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" @@ -388,8 +389,11 @@ struct BreakpointPrinter : public ModulePass { for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { std::string Name; DISubprogram SP(NMD->getOperand(i)); - if (SP.Verify()) - getContextName(SP.getContext(), Name); + assert((!SP || SP.isSubprogram()) && + "A MDNode in llvm.dbg.sp should be null or a DISubprogram."); + if (!SP) + continue; + getContextName(SP.getContext(), Name); Name = Name + SP.getDisplayName().str(); if (!Name.empty() && Processed.insert(Name)) { Out << Name << "\n"; @@ -444,7 +448,6 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM, } Builder.DisableUnitAtATime = !UnitAtATime; Builder.DisableUnrollLoops = OptLevel == 0; - Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls; Builder.populateFunctionPassManager(FPM); Builder.populateModulePassManager(MPM); @@ -464,7 +467,6 @@ static void AddStandardCompilePasses(PassManagerBase &PM) { if (!DisableInline) Builder.Inliner = createFunctionInliningPass(); Builder.OptLevel = 3; - Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls; Builder.populateModulePassManager(PM); } @@ -489,7 +491,6 @@ static TargetOptions GetTargetOptions() { TargetOptions Options; Options.LessPreciseFPMADOption = EnableFPMAD; Options.NoFramePointerElim = DisableFPElim; - Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf; Options.AllowFPOpFusion = FuseFPOps; Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; @@ -503,12 +504,10 @@ static TargetOptions GetTargetOptions() { Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.DisableTailCalls = DisableTailCalls; Options.StackAlignmentOverride = OverrideStackAlignment; - Options.RealignStack = EnableRealignStack; Options.TrapFuncName = TrapFuncName; Options.PositionIndependentExecutable = EnablePIE; Options.EnableSegmentedStacks = SegmentedStacks; Options.UseInitArray = UseInitArray; - Options.SSPBufferSize = SSPBufferSize; return Options; } @@ -566,6 +565,7 @@ int main(int argc, char **argv) { // Initialize passes PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); + initializeDebugIRPass(Registry); initializeScalarOpts(Registry); initializeObjCARCOpts(Registry); initializeVectorization(Registry); @@ -588,7 +588,7 @@ int main(int argc, char **argv) { SMDiagnostic Err; // Load the input module... - std::auto_ptr<Module> M; + OwningPtr<Module> M; M.reset(ParseIRFile(InputFilename, Err, Context)); if (M.get() == 0) { @@ -613,7 +613,7 @@ int main(int argc, char **argv) { std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + sys::fs::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; @@ -655,7 +655,7 @@ int main(int argc, char **argv) { TargetMachine *Machine = 0; if (ModuleTriple.getArch()) Machine = GetTargetMachine(Triple(ModuleTriple)); - std::auto_ptr<TargetMachine> TM(Machine); + OwningPtr<TargetMachine> TM(Machine); // Add internal analysis passes from the target machine. if (TM.get()) @@ -666,6 +666,9 @@ int main(int argc, char **argv) { FPasses.reset(new FunctionPassManager(M.get())); if (TD) FPasses->add(new DataLayout(*TD)); + if (TM.get()) + TM->addAnalysisPasses(*FPasses); + } if (PrintBreakpoints) { @@ -676,7 +679,7 @@ int main(int argc, char **argv) { std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + sys::fs::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt new file mode 100644 index 0000000..8d9d652 --- /dev/null +++ b/tools/yaml2obj/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS object) + +add_llvm_utility(yaml2obj + yaml2obj.cpp + yaml2coff.cpp + yaml2elf.cpp + ) + +target_link_libraries(yaml2obj LLVMSupport) diff --git a/tools/yaml2obj/Makefile b/tools/yaml2obj/Makefile new file mode 100644 index 0000000..8801795 --- /dev/null +++ b/tools/yaml2obj/Makefile @@ -0,0 +1,20 @@ +##===- utils/yaml2obj/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 = yaml2obj +LINK_COMPONENTS := object + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 + +# Don't install this utility +NO_INSTALL = 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp new file mode 100644 index 0000000..11aae0e --- /dev/null +++ b/tools/yaml2obj/yaml2coff.cpp @@ -0,0 +1,288 @@ +//===- yaml2coff - Convert YAML to a COFF object file ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief The COFF component of yaml2obj. +/// +//===----------------------------------------------------------------------===// + +#include "yaml2obj.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/COFFYAML.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> + +using namespace llvm; + +/// This parses a yaml stream that represents a COFF object file. +/// See docs/yaml2obj for the yaml scheema. +struct COFFParser { + COFFParser(COFFYAML::Object &Obj) : Obj(Obj) { + // A COFF string table always starts with a 4 byte size field. Offsets into + // it include this size, so allocate it now. + StringTable.append(4, 0); + } + + bool parseSections() { + for (std::vector<COFFYAML::Section>::iterator i = Obj.Sections.begin(), + e = Obj.Sections.end(); i != e; ++i) { + COFFYAML::Section &Sec = *i; + + // If the name is less than 8 bytes, store it in place, otherwise + // store it in the string table. + StringRef Name = Sec.Name; + + if (Name.size() <= COFF::NameSize) { + std::copy(Name.begin(), Name.end(), Sec.Header.Name); + } else { + // Add string to the string table and format the index for output. + unsigned Index = getStringIndex(Name); + std::string str = utostr(Index); + if (str.size() > 7) { + errs() << "String table got too large"; + return false; + } + Sec.Header.Name[0] = '/'; + std::copy(str.begin(), str.end(), Sec.Header.Name + 1); + } + + Sec.Header.Characteristics |= (Log2_32(Sec.Alignment) + 1) << 20; + } + return true; + } + + bool parseSymbols() { + for (std::vector<COFFYAML::Symbol>::iterator i = Obj.Symbols.begin(), + e = Obj.Symbols.end(); i != e; ++i) { + COFFYAML::Symbol &Sym = *i; + + // If the name is less than 8 bytes, store it in place, otherwise + // store it in the string table. + StringRef Name = Sym.Name; + if (Name.size() <= COFF::NameSize) { + std::copy(Name.begin(), Name.end(), Sym.Header.Name); + } else { + // Add string to the string table and format the index for output. + unsigned Index = getStringIndex(Name); + *reinterpret_cast<support::aligned_ulittle32_t*>( + Sym.Header.Name + 4) = Index; + } + + Sym.Header.Type = Sym.SimpleType; + Sym.Header.Type |= Sym.ComplexType << COFF::SCT_COMPLEX_TYPE_SHIFT; + } + return true; + } + + bool parse() { + if (!parseSections()) + return false; + if (!parseSymbols()) + return false; + return true; + } + + unsigned getStringIndex(StringRef Str) { + StringMap<unsigned>::iterator i = StringTableMap.find(Str); + if (i == StringTableMap.end()) { + unsigned Index = StringTable.size(); + StringTable.append(Str.begin(), Str.end()); + StringTable.push_back(0); + StringTableMap[Str] = Index; + return Index; + } + return i->second; + } + + COFFYAML::Object &Obj; + + StringMap<unsigned> StringTableMap; + std::string StringTable; +}; + +// Take a CP and assign addresses and sizes to everything. Returns false if the +// layout is not valid to do. +static bool layoutCOFF(COFFParser &CP) { + uint32_t SectionTableStart = 0; + uint32_t SectionTableSize = 0; + + // The section table starts immediately after the header, including the + // optional header. + SectionTableStart = sizeof(COFF::header) + CP.Obj.Header.SizeOfOptionalHeader; + SectionTableSize = sizeof(COFF::section) * CP.Obj.Sections.size(); + + uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize; + + // Assign each section data address consecutively. + for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(), + e = CP.Obj.Sections.end(); + i != e; ++i) { + if (i->SectionData.binary_size() > 0) { + i->Header.SizeOfRawData = i->SectionData.binary_size(); + i->Header.PointerToRawData = CurrentSectionDataOffset; + CurrentSectionDataOffset += i->Header.SizeOfRawData; + if (!i->Relocations.empty()) { + i->Header.PointerToRelocations = CurrentSectionDataOffset; + i->Header.NumberOfRelocations = i->Relocations.size(); + CurrentSectionDataOffset += i->Header.NumberOfRelocations * + COFF::RelocationSize; + } + // TODO: Handle alignment. + } else { + i->Header.SizeOfRawData = 0; + i->Header.PointerToRawData = 0; + } + } + + uint32_t SymbolTableStart = CurrentSectionDataOffset; + + // Calculate number of symbols. + uint32_t NumberOfSymbols = 0; + 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; + } + + // Store all the allocated start addresses in the header. + CP.Obj.Header.NumberOfSections = CP.Obj.Sections.size(); + CP.Obj.Header.NumberOfSymbols = NumberOfSymbols; + CP.Obj.Header.PointerToSymbolTable = SymbolTableStart; + + *reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0]) + = CP.StringTable.size(); + + return true; +} + +template <typename value_type> +struct binary_le_impl { + value_type Value; + binary_le_impl(value_type V) : Value(V) {} +}; + +template <typename value_type> +raw_ostream &operator <<( raw_ostream &OS + , const binary_le_impl<value_type> &BLE) { + char Buffer[sizeof(BLE.Value)]; + support::endian::write<value_type, support::little, support::unaligned>( + Buffer, BLE.Value); + OS.write(Buffer, sizeof(BLE.Value)); + return OS; +} + +template <typename value_type> +binary_le_impl<value_type> binary_le(value_type V) { + return binary_le_impl<value_type>(V); +} + +bool writeCOFF(COFFParser &CP, raw_ostream &OS) { + OS << binary_le(CP.Obj.Header.Machine) + << binary_le(CP.Obj.Header.NumberOfSections) + << binary_le(CP.Obj.Header.TimeDateStamp) + << binary_le(CP.Obj.Header.PointerToSymbolTable) + << binary_le(CP.Obj.Header.NumberOfSymbols) + << binary_le(CP.Obj.Header.SizeOfOptionalHeader) + << binary_le(CP.Obj.Header.Characteristics); + + // Output section table. + for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(), + e = CP.Obj.Sections.end(); + i != e; ++i) { + OS.write(i->Header.Name, COFF::NameSize); + OS << binary_le(i->Header.VirtualSize) + << binary_le(i->Header.VirtualAddress) + << binary_le(i->Header.SizeOfRawData) + << binary_le(i->Header.PointerToRawData) + << binary_le(i->Header.PointerToRelocations) + << binary_le(i->Header.PointerToLineNumbers) + << binary_le(i->Header.NumberOfRelocations) + << binary_le(i->Header.NumberOfLineNumbers) + << binary_le(i->Header.Characteristics); + } + + unsigned CurSymbol = 0; + StringMap<unsigned> SymbolTableIndexMap; + for (std::vector<COFFYAML::Symbol>::iterator I = CP.Obj.Symbols.begin(), + E = CP.Obj.Symbols.end(); + I != E; ++I) { + SymbolTableIndexMap[I->Name] = CurSymbol; + CurSymbol += 1 + I->Header.NumberOfAuxSymbols; + } + + // Output section data. + for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(), + e = CP.Obj.Sections.end(); + i != e; ++i) { + i->SectionData.writeAsBinary(OS); + for (unsigned I2 = 0, E2 = i->Relocations.size(); I2 != E2; ++I2) { + const COFFYAML::Relocation &R = i->Relocations[I2]; + uint32_t SymbolTableIndex = SymbolTableIndexMap[R.SymbolName]; + OS << binary_le(R.VirtualAddress) + << binary_le(SymbolTableIndex) + << binary_le(R.Type); + } + } + + // Output symbol table. + + for (std::vector<COFFYAML::Symbol>::const_iterator i = CP.Obj.Symbols.begin(), + e = CP.Obj.Symbols.end(); + i != e; ++i) { + OS.write(i->Header.Name, COFF::NameSize); + OS << binary_le(i->Header.Value) + << binary_le(i->Header.SectionNumber) + << binary_le(i->Header.Type) + << binary_le(i->Header.StorageClass) + << binary_le(i->Header.NumberOfAuxSymbols); + i->AuxiliaryData.writeAsBinary(OS); + } + + // Output string table. + OS.write(&CP.StringTable[0], CP.StringTable.size()); + return true; +} + +int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { + yaml::Input YIn(Buf->getBuffer()); + COFFYAML::Object Doc; + YIn >> Doc; + if (YIn.error()) { + errs() << "yaml2obj: Failed to parse YAML file!\n"; + return 1; + } + + COFFParser CP(Doc); + if (!CP.parse()) { + errs() << "yaml2obj: Failed to parse YAML file!\n"; + return 1; + } + + if (!layoutCOFF(CP)) { + errs() << "yaml2obj: Failed to layout COFF file!\n"; + return 1; + } + if (!writeCOFF(CP, Out)) { + errs() << "yaml2obj: Failed to write COFF file!\n"; + return 1; + } + return 0; +} diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp new file mode 100644 index 0000000..61252a4 --- /dev/null +++ b/tools/yaml2obj/yaml2elf.cpp @@ -0,0 +1,398 @@ +//===- yaml2elf - Convert YAML to a ELF object file -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief The ELF component of yaml2obj. +/// +//===----------------------------------------------------------------------===// + +#include "yaml2obj.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFYAML.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +// There is similar code in yaml2coff, but with some slight COFF-specific +// variations like different initial state. Might be able to deduplicate +// some day, but also want to make sure that the Mach-O use case is served. +// +// This class has a deliberately small interface, since a lot of +// implementation variation is possible. +// +// TODO: Use an ordered container with a suffix-based comparison in order +// to deduplicate suffixes. std::map<> with a custom comparator is likely +// to be the simplest implementation, but a suffix trie could be more +// suitable for the job. +namespace { +class StringTableBuilder { + /// \brief Indices of strings currently present in `Buf`. + StringMap<unsigned> StringIndices; + /// \brief The contents of the string table as we build it. + std::string Buf; +public: + StringTableBuilder() { + Buf.push_back('\0'); + } + /// \returns Index of string in string table. + unsigned addString(StringRef S) { + StringMapEntry<unsigned> &Entry = StringIndices.GetOrCreateValue(S); + unsigned &I = Entry.getValue(); + if (I != 0) + return I; + I = Buf.size(); + Buf.append(S.begin(), S.end()); + Buf.push_back('\0'); + return I; + } + size_t size() const { + return Buf.size(); + } + void writeToStream(raw_ostream &OS) { + OS.write(Buf.data(), Buf.size()); + } +}; +} // end anonymous namespace + +// This class is used to build up a contiguous binary blob while keeping +// track of an offset in the output (which notionally begins at +// `InitialOffset`). +namespace { +class ContiguousBlobAccumulator { + const uint64_t InitialOffset; + SmallVector<char, 128> Buf; + raw_svector_ostream OS; + + /// \returns The new offset. + uint64_t padToAlignment(unsigned Align) { + uint64_t CurrentOffset = InitialOffset + OS.tell(); + uint64_t AlignedOffset = RoundUpToAlignment(CurrentOffset, Align); + for (; CurrentOffset != AlignedOffset; ++CurrentOffset) + OS.write('\0'); + return AlignedOffset; // == CurrentOffset; + } + +public: + ContiguousBlobAccumulator(uint64_t InitialOffset_) + : InitialOffset(InitialOffset_), Buf(), OS(Buf) {} + template <class Integer> + raw_ostream &getOSAndAlignedOffset(Integer &Offset, unsigned Align = 16) { + Offset = padToAlignment(Align); + return OS; + } + void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); } +}; +} // end anonymous namespace + +// Used to keep track of section names, so that in the YAML file sections +// can be referenced by name instead of by index. +namespace { +class SectionNameToIdxMap { + StringMap<int> Map; +public: + /// \returns true if name is already present in the map. + bool addName(StringRef SecName, unsigned i) { + StringMapEntry<int> &Entry = Map.GetOrCreateValue(SecName, -1); + if (Entry.getValue() != -1) + return true; + Entry.setValue((int)i); + return false; + } + /// \returns true if name is not present in the map + bool lookupSection(StringRef SecName, unsigned &Idx) const { + StringMap<int>::const_iterator I = Map.find(SecName); + if (I == Map.end()) + return true; + Idx = I->getValue(); + return false; + } +}; +} // end anonymous namespace + +template <class T> +static size_t vectorDataSize(const std::vector<T> &Vec) { + return Vec.size() * sizeof(T); +} + +template <class T> +static void writeVectorData(raw_ostream &OS, const std::vector<T> &Vec) { + OS.write((const char *)Vec.data(), vectorDataSize(Vec)); +} + +template <class T> +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 { + /// \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::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr; + /// \brief The ELF file header. + Elf_Ehdr &Header; + + SectionNameToIdxMap &SN2I; + +public: + + ELFState(Elf_Ehdr &Header_, ContiguousBlobAccumulator &Accum, + unsigned DotStrtabSecNo_, SectionNameToIdxMap &SN2I_) + : DotStrtab(), DotStrtabSecNo(DotStrtabSecNo_), + SectionContentAccum(Accum), Header(Header_), SN2I(SN2I_) {} + + unsigned getDotStrTabSecNo() const { return DotStrtabSecNo; } + StringTableBuilder &getStringTable() { return DotStrtab; } + ContiguousBlobAccumulator &getSectionContentAccum() { + return SectionContentAccum; + } + SectionNameToIdxMap &getSN2I() { return SN2I; } +}; +} // 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::ELFObjectFile<ELFT>::Elf_Sym> &Syms, + unsigned SymbolBinding) { + typedef typename object::ELFObjectFile<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()) { + unsigned Index; + if (State.getSN2I().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); + } +} + +template <class ELFT> +static void handleSymtabSectionHeader( + const ELFYAML::LocalGlobalWeakSymbols &Symbols, ELFState<ELFT> &State, + typename object::ELFObjectFile<ELFT>::Elf_Shdr &SHeader) { + + typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + SHeader.sh_type = ELF::SHT_SYMTAB; + SHeader.sh_link = State.getDotStrTabSecNo(); + // One greater than symbol table index of the last local symbol. + SHeader.sh_info = Symbols.Local.size() + 1; + SHeader.sh_entsize = sizeof(Elf_Sym); + + std::vector<Elf_Sym> Syms; + { + // Ensure STN_UNDEF is present + Elf_Sym Sym; + 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); + + ContiguousBlobAccumulator &CBA = State.getSectionContentAccum(); + writeVectorData(CBA.getOSAndAlignedOffset(SHeader.sh_offset), Syms); + SHeader.sh_size = vectorDataSize(Syms); +} + +template <class ELFT> +static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { + using namespace llvm::ELF; + typedef typename object::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr; + typedef typename object::ELFObjectFile<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); + + // TODO: Flesh out section header support. + // TODO: Program headers. + + 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; + + // 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; + 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; + } + } + + ELFState<ELFT> State(Header, CBA, DotStrtabSecNo, SN2I); + + 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; + + Sec.Content.writeAsBinary(CBA.getOSAndAlignedOffset(SHeader.sh_offset)); + SHeader.sh_size = Sec.Content.binary_size(); + + 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); + } + + // .symtab section. + Elf_Shdr SymtabSHeader; + zero(SymtabSHeader); + SymtabSHeader.sh_name = SHStrTab.addString(StringRef(".symtab")); + handleSymtabSectionHeader<ELFT>(Doc.Symbols, State, SymtabSHeader); + 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); + SHeaders.push_back(DotStrTabSHeader); + + // Section header string table header. + Elf_Shdr SHStrTabSHeader; + zero(SHStrTabSHeader); + createStringTableSectionHeader(SHStrTabSHeader, SHStrTab, CBA); + SHeaders.push_back(SHStrTabSHeader); + + OS.write((const char *)&Header, sizeof(Header)); + writeVectorData(OS, SHeaders); + CBA.writeBlobToStream(OS); + return 0; +} + +static bool is64Bit(const ELFYAML::Object &Doc) { + return Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); +} + +static bool isLittleEndian(const ELFYAML::Object &Doc) { + return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); +} + +int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { + yaml::Input YIn(Buf->getBuffer()); + ELFYAML::Object Doc; + YIn >> Doc; + if (YIn.error()) { + errs() << "yaml2obj: Failed to parse YAML file!\n"; + return 1; + } + using object::ELFType; + typedef ELFType<support::little, 8, true> LE64; + typedef ELFType<support::big, 8, true> BE64; + typedef ELFType<support::little, 4, false> LE32; + typedef ELFType<support::big, 4, false> BE32; + if (is64Bit(Doc)) { + if (isLittleEndian(Doc)) + return writeELF<LE64>(outs(), Doc); + else + return writeELF<BE64>(outs(), Doc); + } else { + if (isLittleEndian(Doc)) + return writeELF<LE32>(outs(), Doc); + else + return writeELF<BE32>(outs(), Doc); + } +} diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp new file mode 100644 index 0000000..6d1107c --- /dev/null +++ b/tools/yaml2obj/yaml2obj.cpp @@ -0,0 +1,71 @@ +//===- yaml2obj - Convert YAML to a binary object file --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program takes a YAML description of an object file and outputs the +// binary equivalent. +// +// This is used for writing tests that require binary files. +// +//===----------------------------------------------------------------------===// + +#include "yaml2obj.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/CommandLine.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" +#include "llvm/Support/system_error.h" + +using namespace llvm; + +static cl::opt<std::string> + Input(cl::Positional, cl::desc("<input>"), cl::init("-")); + +// TODO: The "right" way to tell what kind of object file a given YAML file +// corresponds to is to look at YAML "tags" (e.g. `!Foo`). Then, different +// tags (`!ELF`, `!COFF`, etc.) would be used to discriminate between them. +// Interpreting the tags is needed eventually for when writing test cases, +// so that we can e.g. have `!Archive` contain a sequence of `!ELF`, and +// just Do The Right Thing. However, interpreting these tags and acting on +// them appropriately requires some work in the YAML parser and the YAMLIO +// library. +enum YAMLObjectFormat { + YOF_COFF, + YOF_ELF +}; + +cl::opt<YAMLObjectFormat> Format( + "format", + cl::desc("Interpret input as this type of object file"), + cl::values( + clEnumValN(YOF_COFF, "coff", "COFF object file format"), + clEnumValN(YOF_ELF, "elf", "ELF object file format"), + clEnumValEnd)); + + +int main(int argc, char **argv) { + cl::ParseCommandLineOptions(argc, argv); + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + OwningPtr<MemoryBuffer> Buf; + if (MemoryBuffer::getFileOrSTDIN(Input, Buf)) + return 1; + if (Format == YOF_COFF) { + return yaml2coff(outs(), Buf.get()); + } else if (Format == YOF_ELF) { + return yaml2elf(outs(), Buf.get()); + } else { + errs() << "Not yet implemented\n"; + return 1; + } +} diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h new file mode 100644 index 0000000..095435c --- /dev/null +++ b/tools/yaml2obj/yaml2obj.h @@ -0,0 +1,22 @@ +//===--- yaml2obj.h - -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief Common declarations for yaml2obj +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_YAML2OBJ_H +#define LLVM_TOOLS_YAML2OBJ_H + +namespace llvm { + class raw_ostream; + class MemoryBuffer; +} +int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf); +int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf); + +#endif |
