diff options
author | dim <dim@FreeBSD.org> | 2013-12-22 00:04:03 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-12-22 00:04:03 +0000 |
commit | 8cf58e3ee36bd550746fca361a894e2727485200 (patch) | |
tree | 2ba0398b4c42ad4f55561327538044fd2c925a8b /tools | |
parent | aa45f148926e3461a1fd8b10c990f0a51a908cc9 (diff) | |
download | FreeBSD-src-8cf58e3ee36bd550746fca361a894e2727485200.zip FreeBSD-src-8cf58e3ee36bd550746fca361a894e2727485200.tar.gz |
Vendor import of llvm release_34 branch r197841 (effectively, 3.4 RC3):
https://llvm.org/svn/llvm-project/llvm/branches/release_34@197841
Diffstat (limited to 'tools')
130 files changed, 6287 insertions, 5528 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6b7c884..12e10fd 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -2,65 +2,78 @@ # three small executables. This is done to minimize memory load in parallel # builds. Please retain this ordering. -if( NOT WIN32 OR MSYS OR CYGWIN ) - # We currently require 'sed' to build llvm-config, so don't try to build it - # on pure Win32. - add_subdirectory(llvm-config) -endif() +add_llvm_tool_subdirectory(llvm-config) -add_subdirectory(opt) -add_subdirectory(llvm-as) -add_subdirectory(llvm-dis) -add_subdirectory(llvm-mc) +add_llvm_tool_subdirectory(opt) +add_llvm_tool_subdirectory(llvm-as) +add_llvm_tool_subdirectory(llvm-dis) +add_llvm_tool_subdirectory(llvm-mc) -add_subdirectory(llc) -add_subdirectory(llvm-ranlib) -add_subdirectory(llvm-ar) -add_subdirectory(llvm-nm) -add_subdirectory(llvm-size) +add_llvm_tool_subdirectory(llc) +add_llvm_tool_subdirectory(llvm-ar) +add_llvm_tool_subdirectory(llvm-nm) +add_llvm_tool_subdirectory(llvm-size) -add_subdirectory(llvm-cov) -add_subdirectory(llvm-prof) -add_subdirectory(llvm-link) -add_subdirectory(lli) +add_llvm_tool_subdirectory(llvm-cov) +add_llvm_tool_subdirectory(llvm-link) +add_llvm_tool_subdirectory(lli) -add_subdirectory(llvm-extract) -add_subdirectory(llvm-diff) -add_subdirectory(macho-dump) -add_subdirectory(llvm-objdump) -add_subdirectory(llvm-readobj) -add_subdirectory(llvm-rtdyld) -add_subdirectory(llvm-dwarfdump) +add_llvm_tool_subdirectory(llvm-extract) +add_llvm_tool_subdirectory(llvm-diff) +add_llvm_tool_subdirectory(macho-dump) +add_llvm_tool_subdirectory(llvm-objdump) +add_llvm_tool_subdirectory(llvm-readobj) +add_llvm_tool_subdirectory(llvm-rtdyld) +add_llvm_tool_subdirectory(llvm-dwarfdump) if( LLVM_USE_INTEL_JITEVENTS ) - add_subdirectory(llvm-jitlistener) + add_llvm_tool_subdirectory(llvm-jitlistener) +else() + ignore_llvm_tool_subdirectory(llvm-jitlistener) endif( LLVM_USE_INTEL_JITEVENTS ) -add_subdirectory(bugpoint) -add_subdirectory(bugpoint-passes) -add_subdirectory(llvm-bcanalyzer) -add_subdirectory(llvm-stress) -add_subdirectory(llvm-mcmarkup) +add_llvm_tool_subdirectory(bugpoint) +add_llvm_tool_subdirectory(bugpoint-passes) +add_llvm_tool_subdirectory(llvm-bcanalyzer) +add_llvm_tool_subdirectory(llvm-stress) +add_llvm_tool_subdirectory(llvm-mcmarkup) + +add_llvm_tool_subdirectory(llvm-symbolizer) -add_subdirectory(llvm-symbolizer) +add_llvm_tool_subdirectory(llvm-c-test) -add_subdirectory(obj2yaml) -add_subdirectory(yaml2obj) +add_llvm_tool_subdirectory(obj2yaml) +add_llvm_tool_subdirectory(yaml2obj) -if( NOT WIN32 ) - add_subdirectory(lto) +if( NOT CYGWIN ) + add_llvm_tool_subdirectory(lto) + add_llvm_tool_subdirectory(llvm-lto) +else() + ignore_llvm_tool_subdirectory(lto) + ignore_llvm_tool_subdirectory(llvm-lto) endif() if( LLVM_ENABLE_PIC ) # TODO: support other systems: if( (CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ) - add_subdirectory(gold) + add_llvm_tool_subdirectory(gold) + else() + ignore_llvm_tool_subdirectory(gold) endif() +else() + ignore_llvm_tool_subdirectory(gold) 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) + + # Automatically add remaining sub-directories containing a 'CMakeLists.txt' + # file as external projects. + add_llvm_implicit_external_projects() +endif() set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE) diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index 25aa177..93b8d98 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-lto llvm-mc llvm-nm llvm-objdump llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup [component_0] type = Group diff --git a/tools/Makefile b/tools/Makefile index eaf9ed3..be87254 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -27,15 +27,11 @@ OPTIONAL_DIRS := lldb # large and three small executables. This is done to minimize memory load # in parallel builds. Please retain this ordering. DIRS := llvm-config -PARALLEL_DIRS := opt llvm-as llvm-dis \ - llc llvm-ranlib 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 obj2yaml yaml2obj +PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \ + lli llvm-extract llvm-mc bugpoint llvm-bcanalyzer llvm-diff \ + macho-dump llvm-objdump llvm-readobj llvm-rtdyld \ + llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \ + llvm-symbolizer obj2yaml yaml2obj llvm-c-test # If Intel JIT Events support is configured, build an extra tool to test it. ifeq ($(USE_INTEL_JITEVENTS), 1) @@ -54,11 +50,10 @@ endif ifndef ONLY_TOOLS ifeq ($(ENABLE_PIC),1) # gold only builds if binutils is around. It requires "lto" to build before - # it so it is added to DIRS. + # it so it is added to DIRS. llvm-lto also requires lto + DIRS += lto llvm-lto ifdef BINUTILS_INCDIR - DIRS += lto gold - else - PARALLEL_DIRS += lto + DIRS += gold endif PARALLEL_DIRS += bugpoint-passes diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index 937d86a..a5436ba 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -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/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index ed211a6..b90fc61 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: " @@ -197,10 +195,10 @@ namespace { } bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { - - //if main isn't present, claim there is no problem - if (KeepMain && find(Funcs.begin(), Funcs.end(), - BD.getProgram()->getFunction("main")) == Funcs.end()) + // If main isn't present, claim there is no problem. + if (KeepMain && std::find(Funcs.begin(), Funcs.end(), + BD.getProgram()->getFunction("main")) == + Funcs.end()) return false; // Clone the program to try hacking it apart... diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index da36045..c05c8d7 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); } @@ -299,18 +301,20 @@ std::string BugDriver::executeProgram(const Module *Program, if (AI == 0) AI = Interpreter; assert(AI && "Interpreter should have been created already!"); bool CreatedBitcode = false; - 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 +323,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 +385,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 +394,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 +402,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 +444,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 +462,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/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..254d997 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); @@ -632,7 +662,7 @@ static bool IsARMArchitecture(std::vector<const char*> Args) { I = Args.begin(), E = Args.end(); I != E; ++I) { if (StringRef(*I).equals_lower("-arch")) { ++I; - if (I != E && StringRef(*I).substr(0, strlen("arm")).equals_lower("arm")) + if (I != E && StringRef(*I).startswith_lower("arm")) return true; } } @@ -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/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index 5e8fdd1..9bc592e 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -49,8 +49,8 @@ TimeoutValue("timeout", cl::init(300), cl::value_desc("seconds"), static cl::opt<int> MemoryLimit("mlimit", cl::init(-1), cl::value_desc("MBytes"), - cl::desc("Maximum amount of memory to use. 0 disables check." - " Defaults to 100MB (800MB under valgrind).")); + cl::desc("Maximum amount of memory to use. 0 disables check." + " Defaults to 300MB (800MB under valgrind).")); static cl::opt<bool> UseValgrind("enable-valgrind", @@ -152,7 +152,7 @@ int main(int argc, char **argv) { if (sys::RunningOnValgrind() || UseValgrind) MemoryLimit = 800; else - MemoryLimit = 100; + MemoryLimit = 300; } BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit, diff --git a/tools/gold/README.txt b/tools/gold/README.txt index a906a90..286d9af 100644 --- a/tools/gold/README.txt +++ b/tools/gold/README.txt @@ -1,21 +1,13 @@ +The LLVM Gold LTO Plugin +======================== + This directory contains a plugin that is designed to work with binutils gold linker. At present time, this is not the default linker in binutils, and the default build of gold does not support plugins. -Obtaining binutils: - - cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src login - {enter "anoncvs" as the password} - cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co binutils - -This will create a src/ directory. Make a build/ directory and from -there configure binutils with "../src/configure --enable-gold --enable-plugins". -Then build binutils with "make all-gold". +See docs/GoldPlugin.html for complete build and usage instructions. -To build the LLVMgold plugin, configure LLVM with the option ---with-binutils-include=/path/to/binutils/src/include/ --enable-pic. To use the -plugin, run "ld-new --plugin /path/to/LLVMgold.so". -Without PIC libLTO and LLVMgold are not being built (because they would fail -link on x86-64 with a relocation error: PIC and non-PIC can't be combined). +NOTE: libLTO and LLVMgold aren't built without PIC because they would fail +to link on x86-64 with a relocation error: PIC and non-PIC can't be combined. As an alternative to passing --enable-pic, you can use 'make ENABLE_PIC=1' in your entire LLVM build. diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 40f5fd6..0e3bad2 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -15,8 +15,10 @@ #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H #include "plugin-api.h" #include "llvm-c/lto.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/Errno.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -64,8 +66,9 @@ 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; + StringSet<> CannotBeHidden; } namespace options { @@ -196,7 +199,7 @@ ld_plugin_status onload(ld_plugin_tv *tv) { case LDPT_ADD_SYMBOLS: add_symbols = tv->tv_u.tv_add_symbols; break; - case LDPT_GET_SYMBOLS: + case LDPT_GET_SYMBOLS_V2: get_symbols = tv->tv_u.tv_get_symbols; break; case LDPT_ADD_INPUT_FILE: @@ -251,9 +254,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; } @@ -297,6 +299,9 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, sym.version = NULL; int scope = attrs & LTO_SYMBOL_SCOPE_MASK; + bool CanBeHidden = scope == LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; + if (!CanBeHidden) + CannotBeHidden.insert(sym.name); switch (scope) { case LTO_SYMBOL_SCOPE_HIDDEN: sym.visibility = LDPV_HIDDEN; @@ -306,6 +311,7 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, break; case 0: // extern case LTO_SYMBOL_SCOPE_DEFAULT: + case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN: sym.visibility = LDPV_DEFAULT; break; default: @@ -351,14 +357,27 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, } } - if (code_gen) - lto_codegen_add_module(code_gen, M); + if (code_gen) { + if (lto_codegen_add_module(code_gen, M)) { + (*message)(LDPL_ERROR, "Error linking module: %s", + lto_get_error_message()); + return LDPS_ERR; + } + } lto_module_dispose(M); return LDPS_OK; } +static bool mustPreserve(const claimed_file &F, int i) { + if (F.syms[i].resolution == LDPR_PREVAILING_DEF) + return true; + if (F.syms[i].resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) + return CannotBeHidden.count(F.syms[i].name); + return false; +} + /// all_symbols_read_hook - gold informs us that all symbols have been read. /// At this point, we use get_symbols to see if any of our definitions have /// been overridden by a native object file. Then, perform optimization and @@ -381,7 +400,7 @@ static ld_plugin_status all_symbols_read_hook(void) { continue; (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]); for (unsigned i = 0, e = I->syms.size(); i != e; i++) { - if (I->syms[i].resolution == LDPR_PREVAILING_DEF) { + if (mustPreserve(*I, i)) { lto_codegen_add_must_preserve_symbol(code_gen, I->syms[i].name); if (options::generate_api_file) @@ -417,12 +436,19 @@ static ld_plugin_status all_symbols_read_hook(void) { bool err = lto_codegen_write_merged_modules(code_gen, path.c_str()); if (err) (*message)(LDPL_FATAL, "Failed to write the output file."); - if (options::generate_bc_file == options::BC_ONLY) + if (options::generate_bc_file == options::BC_ONLY) { + lto_codegen_dispose(code_gen); exit(0); + } } - const char *objPath; - if (lto_codegen_compile_to_file(code_gen, &objPath)) { - (*message)(LDPL_ERROR, "Could not produce a combined object file\n"); + + std::string ObjPath; + { + const char *Temp; + if (lto_codegen_compile_to_file(code_gen, &Temp)) { + (*message)(LDPL_ERROR, "Could not produce a combined object file\n"); + } + ObjPath = Temp; } lto_codegen_dispose(code_gen); @@ -434,9 +460,9 @@ static ld_plugin_status all_symbols_read_hook(void) { } } - if ((*add_input_file)(objPath) != LDPS_OK) { + if ((*add_input_file)(ObjPath.c_str()) != LDPS_OK) { (*message)(LDPL_ERROR, "Unable to add .o file to the link."); - (*message)(LDPL_ERROR, "File left behind in: %s", objPath); + (*message)(LDPL_ERROR, "File left behind in: %s", ObjPath.c_str()); return LDPS_ERR; } @@ -447,18 +473,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/llc.cpp b/tools/llc/llc.cpp index 8a462c6..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" @@ -144,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()) { @@ -260,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; @@ -274,12 +275,10 @@ 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; OwningPtr<TargetMachine> target(TheTarget->createTargetMachine(TheTriple.getTriple(), diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt index aaa6598..5f8c7c9 100644 --- a/tools/lli/CMakeLists.txt +++ b/tools/lli/CMakeLists.txt @@ -1,5 +1,7 @@ -set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native) +set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native instrumentation) + +add_subdirectory(ChildTarget) if( LLVM_USE_OPROFILE ) set(LLVM_LINK_COMPONENTS @@ -19,6 +21,7 @@ endif( LLVM_USE_INTEL_JITEVENTS ) add_llvm_tool(lli lli.cpp - RecordingMemoryManager.cpp + RemoteMemoryManager.cpp RemoteTarget.cpp + RemoteTargetExternal.cpp ) diff --git a/tools/lli/ChildTarget/CMakeLists.txt b/tools/lli/ChildTarget/CMakeLists.txt new file mode 100644 index 0000000..fd1ac24 --- /dev/null +++ b/tools/lli/ChildTarget/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_tool(lli-child-target + ChildTarget.cpp + ) diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp new file mode 100644 index 0000000..55fcae9 --- /dev/null +++ b/tools/lli/ChildTarget/ChildTarget.cpp @@ -0,0 +1,242 @@ +#include "llvm/Config/config.h" + +#include "../RemoteTargetMessage.h" +#include <assert.h> +#include <map> +#include <stdint.h> +#include <string> +#include <vector> + +using namespace llvm; + +class LLIChildTarget { +public: + ~LLIChildTarget(); // OS-specific destructor + void initialize(); + LLIMessageType waitForIncomingMessage(); + void handleMessage(LLIMessageType messageType); + +private: + // Incoming message handlers + void handleAllocateSpace(); + void handleLoadSection(bool IsCode); + void handleExecute(); + void handleTerminate(); + + // Outgoing message handlers + void sendChildActive(); + void sendAllocationResult(uint64_t Addr); + void sendLoadComplete(); + void sendExecutionComplete(uint64_t Result); + + // OS-specific functions + void initializeConnection(); + int WriteBytes(const void *Data, size_t Size); + int ReadBytes(void *Data, size_t Size); + uint64_t allocate(uint32_t Alignment, uint32_t Size); + void makeSectionExecutable(uint64_t Addr, uint32_t Size); + void InvalidateInstructionCache(const void *Addr, size_t Len); + void releaseMemory(uint64_t Addr, uint32_t Size); + + // Store a map of allocated buffers to sizes. + typedef std::map<uint64_t, uint32_t> AllocMapType; + AllocMapType m_AllocatedBufferMap; + + // Communication handles (OS-specific) + void *ConnectionData; +}; + +int main() { + LLIChildTarget ThisChild; + ThisChild.initialize(); + LLIMessageType MsgType; + do { + MsgType = ThisChild.waitForIncomingMessage(); + ThisChild.handleMessage(MsgType); + } while (MsgType != LLI_Terminate && + MsgType != LLI_Error); + return 0; +} + +// Public methods +void LLIChildTarget::initialize() { + initializeConnection(); + sendChildActive(); +} + +LLIMessageType LLIChildTarget::waitForIncomingMessage() { + int32_t MsgType = -1; + if (ReadBytes(&MsgType, 4) > 0) + return (LLIMessageType)MsgType; + return LLI_Error; +} + +void LLIChildTarget::handleMessage(LLIMessageType messageType) { + switch (messageType) { + case LLI_AllocateSpace: + handleAllocateSpace(); + break; + case LLI_LoadCodeSection: + handleLoadSection(true); + break; + case LLI_LoadDataSection: + handleLoadSection(false); + break; + case LLI_Execute: + handleExecute(); + break; + case LLI_Terminate: + handleTerminate(); + break; + default: + // FIXME: Handle error! + break; + } +} + +// Incoming message handlers +void LLIChildTarget::handleAllocateSpace() { + // Read and verify the message data size. + uint32_t DataSize; + int rc = ReadBytes(&DataSize, 4); + assert(rc == 4); + assert(DataSize == 8); + + // Read the message arguments. + uint32_t Alignment; + uint32_t AllocSize; + rc = ReadBytes(&Alignment, 4); + assert(rc == 4); + rc = ReadBytes(&AllocSize, 4); + assert(rc == 4); + + // Allocate the memory. + uint64_t Addr = allocate(Alignment, AllocSize); + + // Send AllocationResult message. + sendAllocationResult(Addr); +} + +void LLIChildTarget::handleLoadSection(bool IsCode) { + // Read the message data size. + uint32_t DataSize; + int rc = ReadBytes(&DataSize, 4); + assert(rc == 4); + + // Read the target load address. + uint64_t Addr; + rc = ReadBytes(&Addr, 8); + assert(rc == 8); + + size_t BufferSize = DataSize - 8; + + // FIXME: Verify that this is in allocated space + + // Read section data into previously allocated buffer + rc = ReadBytes((void*)Addr, DataSize - 8); + assert(rc == (int)(BufferSize)); + + // If IsCode, mark memory executable + if (IsCode) + makeSectionExecutable(Addr, BufferSize); + + // Send MarkLoadComplete message. + sendLoadComplete(); +} + +void LLIChildTarget::handleExecute() { + // Read the message data size. + uint32_t DataSize; + int rc = ReadBytes(&DataSize, 4); + assert(rc == 4); + assert(DataSize == 8); + + // Read the target address. + uint64_t Addr; + rc = ReadBytes(&Addr, 8); + assert(rc == 8); + + // Call function + int Result; + int (*fn)(void) = (int(*)(void))Addr; + Result = fn(); + + // Send ExecutionResult message. + sendExecutionComplete((int64_t)Result); +} + +void LLIChildTarget::handleTerminate() { + // Release all allocated memory + AllocMapType::iterator Begin = m_AllocatedBufferMap.begin(); + AllocMapType::iterator End = m_AllocatedBufferMap.end(); + for (AllocMapType::iterator It = Begin; It != End; ++It) { + releaseMemory(It->first, It->second); + } + m_AllocatedBufferMap.clear(); +} + +// Outgoing message handlers +void LLIChildTarget::sendChildActive() { + // Write the message type. + uint32_t MsgType = (uint32_t)LLI_ChildActive; + int rc = WriteBytes(&MsgType, 4); + assert(rc == 4); + + // Write the data size. + uint32_t DataSize = 0; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4); +} + +void LLIChildTarget::sendAllocationResult(uint64_t Addr) { + // Write the message type. + uint32_t MsgType = (uint32_t)LLI_AllocationResult; + int rc = WriteBytes(&MsgType, 4); + assert(rc == 4); + + // Write the data size. + uint32_t DataSize = 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4); + + // Write the allocated address. + rc = WriteBytes(&Addr, 8); + assert(rc == 8); +} + +void LLIChildTarget::sendLoadComplete() { + // Write the message type. + uint32_t MsgType = (uint32_t)LLI_LoadComplete; + int rc = WriteBytes(&MsgType, 4); + assert(rc == 4); + + // Write the data size. + uint32_t DataSize = 0; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4); +} + +void LLIChildTarget::sendExecutionComplete(uint64_t Result) { + // Write the message type. + uint32_t MsgType = (uint32_t)LLI_ExecutionResult; + int rc = WriteBytes(&MsgType, 4); + assert(rc == 4); + + + // Write the data size. + uint32_t DataSize = 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4); + + // Write the result. + rc = WriteBytes(&Result, 8); + assert(rc == 8); +} + +#ifdef LLVM_ON_UNIX +#include "Unix/ChildTarget.inc" +#endif + +#ifdef LLVM_ON_WIN32 +#include "Windows/ChildTarget.inc" +#endif diff --git a/tools/llvm-ranlib/LLVMBuild.txt b/tools/lli/ChildTarget/LLVMBuild.txt index 23015c5..daf6df1 100644 --- a/tools/llvm-ranlib/LLVMBuild.txt +++ b/tools/lli/ChildTarget/LLVMBuild.txt @@ -1,4 +1,4 @@ -;===- ./tools/llvm-ranlib/LLVMBuild.txt ------------------------*- Conf -*--===; +;===- ./tools/lli/ChildTarget/LLVMBuild.txt --------------------*- Conf -*--===; ; ; The LLVM Compiler Infrastructure ; @@ -17,6 +17,5 @@ [component_0] type = Tool -name = llvm-ranlib -parent = Tools -required_libraries = Archive +name = lli-child-target +parent = lli diff --git a/tools/lli/ChildTarget/Makefile b/tools/lli/ChildTarget/Makefile new file mode 100644 index 0000000..f77b144 --- /dev/null +++ b/tools/lli/ChildTarget/Makefile @@ -0,0 +1,17 @@ +##===- tools/lli/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 := lli-child-target + +include $(LEVEL)/Makefile.config + +LINK_COMPONENTS := + +include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/tools/lli/ChildTarget/Unix/ChildTarget.inc b/tools/lli/ChildTarget/Unix/ChildTarget.inc new file mode 100644 index 0000000..cc95810 --- /dev/null +++ b/tools/lli/ChildTarget/Unix/ChildTarget.inc @@ -0,0 +1,166 @@ +//===- ChildTarget.inc - Child process for external JIT execution for Unix -==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the Unix-specific parts of the ChildTarget class +// which executes JITed code in a separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#ifdef __APPLE__ +#include <mach/mach.h> +#endif + +#if defined(__mips__) +# if defined(__OpenBSD__) +# include <mips64/sysarch.h> +# else +# include <sys/cachectl.h> +# endif +#endif + +#ifdef __APPLE__ +extern "C" void sys_icache_invalidate(const void *Addr, size_t len); +#else +extern "C" void __clear_cache(void *, void*); +#endif + +namespace { + +struct ConnectionData_t { + int InputPipe; + int OutputPipe; + + ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {} +}; + +} // namespace + +LLIChildTarget::~LLIChildTarget() { + delete static_cast<ConnectionData_t *>(ConnectionData); +} + +// OS-specific methods +void LLIChildTarget::initializeConnection() { + // Store the parent ends of the pipes + ConnectionData = (void*)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO); +} + +int LLIChildTarget::WriteBytes(const void *Data, size_t Size) { + return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size); +} + +int LLIChildTarget::ReadBytes(void *Data, size_t Size) { + return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size); +} + +// The functions below duplicate functionality that is implemented in +// Support/Memory.cpp with the goal of avoiding a dependency on any +// llvm libraries. + +uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) { + if (!Alignment) + Alignment = 16; + + static const size_t PageSize = getpagesize(); + const size_t NumPages = (Size+PageSize-1)/PageSize; + Size = NumPages*PageSize; + + int fd = -1; +#ifdef NEED_DEV_ZERO_FOR_MMAP + static int zero_fd = open("/dev/zero", O_RDWR); + if (zero_fd == -1) + return 0; + fd = zero_fd; +#endif + + int MMFlags = MAP_PRIVATE | +#ifdef HAVE_MMAP_ANONYMOUS + MAP_ANONYMOUS +#else + MAP_ANON +#endif + ; // Ends statement above + + uint64_t Addr = (uint64_t)::mmap(0, Size, PROT_READ | PROT_WRITE, MMFlags, fd, 0); + if (Addr == (uint64_t)MAP_FAILED) + return 0; + + // Align the address. + Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); + + m_AllocatedBufferMap[Addr] = Size; + + // Return aligned address + return Addr; +} + +void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) { + // FIXME: We have to mark the memory as RWX because multiple code chunks may + // be on the same page. The RemoteTarget interface should be changed to + // work around that. + int Result = ::mprotect((void*)Addr, Size, PROT_READ | PROT_WRITE | PROT_EXEC); + if (Result != 0) + InvalidateInstructionCache((const void *)Addr, Size); +} + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void LLIChildTarget::InvalidateInstructionCache(const void *Addr, + size_t Len) { + +// icache invalidation for PPC and ARM. +#if defined(__APPLE__) + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) + sys_icache_invalidate(const_cast<void *>(Addr), Len); +# endif + +#else + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) + const size_t LineSize = 32; + + const intptr_t Mask = ~(LineSize - 1); + const intptr_t StartLine = ((intptr_t) Addr) & Mask; + const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("dcbf 0, %0" : : "r"(Line)); + asm volatile("sync"); + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("icbi 0, %0" : : "r"(Line)); + asm volatile("isync"); +# elif defined(__arm__) && defined(__GNUC__) + // FIXME: Can we safely always call this for __GNUC__ everywhere? + const char *Start = static_cast<const char *>(Addr); + const char *End = Start + Len; + __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); +# elif defined(__mips__) + const char *Start = static_cast<const char *>(Addr); + cacheflush(const_cast<char *>(Start), Len, BCACHE); +# endif + +#endif // end apple +} + +void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) { + ::munmap((void*)Addr, Size); +} diff --git a/tools/lli/ChildTarget/Windows/ChildTarget.inc b/tools/lli/ChildTarget/Windows/ChildTarget.inc new file mode 100644 index 0000000..45db2b0 --- /dev/null +++ b/tools/lli/ChildTarget/Windows/ChildTarget.inc @@ -0,0 +1,44 @@ +//=- ChildTarget.inc - Child process for external JIT execution for Windows -=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Non-implementation of the Windows-specific parts of the ChildTarget class +// which executes JITed code in a separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +LLIChildTarget::~LLIChildTarget() { +} + +// The RemoteTargetExternal implementation should prevent us from ever getting +// here on Windows, but nothing prevents a user from running this directly. +void LLIChildTarget::initializeConnection() { + assert(0 && "lli-child-target is not implemented for Windows"); +} + +int LLIChildTarget::WriteBytes(const void *Data, size_t Size) { + return 0; +} + +int LLIChildTarget::ReadBytes(void *Data, size_t Size) { + return 0; +} + +uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) { + return 0; +} + +void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) { +} + +void LLIChildTarget::InvalidateInstructionCache(const void *Addr, + size_t Len) { +} + +void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) { +} diff --git a/tools/lli/LLVMBuild.txt b/tools/lli/LLVMBuild.txt index 5823792..aab2a20 100644 --- a/tools/lli/LLVMBuild.txt +++ b/tools/lli/LLVMBuild.txt @@ -15,8 +15,11 @@ ; ;===------------------------------------------------------------------------===; +[common] +subdirectories = ChildTarget + [component_0] type = Tool name = lli parent = Tools -required_libraries = AsmParser BitReader IRReader 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 a653058..eca5d83 100644 --- a/tools/lli/Makefile +++ b/tools/lli/Makefile @@ -10,9 +10,11 @@ LEVEL := ../.. TOOLNAME := lli +PARALLEL_DIRS := ChildTarget + include $(LEVEL)/Makefile.config -LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser irreader 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 deleted file mode 100644 index e4d992d..0000000 --- a/tools/lli/RecordingMemoryManager.cpp +++ /dev/null @@ -1,128 +0,0 @@ -//===- RecordingMemoryManager.cpp - Recording memory manager --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This memory manager allocates local storage and keeps a record of each -// allocation. Iterators are provided for all data and code allocations. -// -//===----------------------------------------------------------------------===// - -#include "RecordingMemoryManager.h" -using namespace llvm; - -RecordingMemoryManager::~RecordingMemoryManager() { - for (SmallVectorImpl<Allocation>::iterator - I = AllocatedCodeMem.begin(), E = AllocatedCodeMem.end(); - I != E; ++I) - sys::Memory::releaseMappedMemory(I->first); - for (SmallVectorImpl<Allocation>::iterator - I = AllocatedDataMem.begin(), E = AllocatedDataMem.end(); - I != E; ++I) - sys::Memory::releaseMappedMemory(I->first); -} - -uint8_t *RecordingMemoryManager:: -allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { - // The recording memory manager is just a local copy of the remote target. - // The alignment requirement is just stored here for later use. Regular - // heap storage is sufficient here, but we're using mapped memory to work - // around a bug in MCJIT. - sys::MemoryBlock Block = allocateSection(Size); - AllocatedCodeMem.push_back(Allocation(Block, Alignment)); - return (uint8_t*)Block.base(); -} - -uint8_t *RecordingMemoryManager:: -allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly) { - // The recording memory manager is just a local copy of the remote target. - // The alignment requirement is just stored here for later use. Regular - // heap storage is sufficient here, but we're using mapped memory to work - // around a bug in MCJIT. - sys::MemoryBlock Block = allocateSection(Size); - AllocatedDataMem.push_back(Allocation(Block, Alignment)); - return (uint8_t*)Block.base(); -} - -sys::MemoryBlock RecordingMemoryManager::allocateSection(uintptr_t Size) { - error_code ec; - sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, - &Near, - sys::Memory::MF_READ | - sys::Memory::MF_WRITE, - ec); - assert(!ec && MB.base()); - - // FIXME: This is part of a work around to keep sections near one another - // when MCJIT performs relocations after code emission but before - // the generated code is moved to the remote target. - // Save this address as the basis for our next request - Near = MB; - return MB; -} - -void RecordingMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } -void RecordingMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } -void RecordingMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } -void RecordingMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } -uint8_t *RecordingMemoryManager::getGOTBase() const { - llvm_unreachable("Unexpected!"); - return 0; -} -uint8_t *RecordingMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ - llvm_unreachable("Unexpected!"); - return 0; -} -uint8_t *RecordingMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, - unsigned Alignment) { - llvm_unreachable("Unexpected!"); - return 0; -} -void RecordingMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd) { - llvm_unreachable("Unexpected!"); -} -uint8_t *RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { - llvm_unreachable("Unexpected!"); - return 0; -} -uint8_t *RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { - llvm_unreachable("Unexpected!"); - return 0; -} -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; -} - -void *RecordingMemoryManager::getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure) { - // We should not invoke parent's ctors/dtors from generated main()! - // On Mingw and Cygwin, the symbol __main is resolved to - // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors - // (and register wrong callee's dtors with atexit(3)). - // We expect ExecutionEngine::runStaticConstructorsDestructors() - // is called before ExecutionEngine::runFunctionAsMain() is called. - if (Name == "__main") return (void*)(intptr_t)&jit_noop; - - return NULL; -} diff --git a/tools/lli/RecordingMemoryManager.h b/tools/lli/RecordingMemoryManager.h deleted file mode 100644 index 991f535..0000000 --- a/tools/lli/RecordingMemoryManager.h +++ /dev/null @@ -1,87 +0,0 @@ -//===- RecordingMemoryManager.h - LLI MCJIT recording memory manager ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This memory manager allocates local storage and keeps a record of each -// allocation. Iterators are provided for all data and code allocations. -// -//===----------------------------------------------------------------------===// - -#ifndef RECORDINGMEMORYMANAGER_H -#define RECORDINGMEMORYMANAGER_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ExecutionEngine/JITMemoryManager.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Memory.h" -#include <utility> - -namespace llvm { - -class RecordingMemoryManager : public JITMemoryManager { -public: - typedef std::pair<sys::MemoryBlock, unsigned> Allocation; - -private: - SmallVector<Allocation, 16> AllocatedDataMem; - SmallVector<Allocation, 16> AllocatedCodeMem; - - // FIXME: This is part of a work around to keep sections near one another - // when MCJIT performs relocations after code emission but before - // the generated code is moved to the remote target. - sys::MemoryBlock Near; - sys::MemoryBlock allocateSection(uintptr_t Size); - -public: - RecordingMemoryManager() {} - virtual ~RecordingMemoryManager(); - - typedef SmallVectorImpl<Allocation>::const_iterator const_data_iterator; - typedef SmallVectorImpl<Allocation>::const_iterator const_code_iterator; - - const_data_iterator data_begin() const { return AllocatedDataMem.begin(); } - const_data_iterator data_end() const { return AllocatedDataMem.end(); } - const_code_iterator code_begin() const { return AllocatedCodeMem.begin(); } - const_code_iterator code_end() const { return AllocatedCodeMem.end(); } - - uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); - - uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly); - - void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true); - - bool applyPermissions(std::string *ErrMsg) { return false; } - - // The following obsolete JITMemoryManager calls are stubbed out for - // this model. - void setMemoryWritable(); - void setMemoryExecutable(); - void setPoisonMemory(bool poison); - void AllocateGOT(); - uint8_t *getGOTBase() const; - uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize); - uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, - unsigned Alignment); - void endFunctionBody(const Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd); - uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); - uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); - void deallocateFunctionBody(void *Body); - uint8_t* 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 - -#endif diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp new file mode 100644 index 0000000..04fc40e --- /dev/null +++ b/tools/lli/RemoteMemoryManager.cpp @@ -0,0 +1,206 @@ +//===---- RemoteMemoryManager.cpp - Recording memory manager --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This memory manager allocates local storage and keeps a record of each +// allocation. Iterators are provided for all data and code allocations. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "lli" +#include "RemoteMemoryManager.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" + +using namespace llvm; + +RemoteMemoryManager::~RemoteMemoryManager() { + for (SmallVector<Allocation, 2>::iterator + I = AllocatedSections.begin(), E = AllocatedSections.end(); + I != E; ++I) + sys::Memory::releaseMappedMemory(I->MB); +} + +uint8_t *RemoteMemoryManager:: +allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName) { + // The recording memory manager is just a local copy of the remote target. + // The alignment requirement is just stored here for later use. Regular + // heap storage is sufficient here, but we're using mapped memory to work + // around a bug in MCJIT. + sys::MemoryBlock Block = allocateSection(Size); + // AllocatedSections will own this memory. + AllocatedSections.push_back( Allocation(Block, Alignment, true) ); + // UnmappedSections has the same information but does not own the memory. + UnmappedSections.push_back( Allocation(Block, Alignment, true) ); + return (uint8_t*)Block.base(); +} + +uint8_t *RemoteMemoryManager:: +allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool IsReadOnly) { + // The recording memory manager is just a local copy of the remote target. + // The alignment requirement is just stored here for later use. Regular + // heap storage is sufficient here, but we're using mapped memory to work + // around a bug in MCJIT. + sys::MemoryBlock Block = allocateSection(Size); + // AllocatedSections will own this memory. + AllocatedSections.push_back( Allocation(Block, Alignment, false) ); + // UnmappedSections has the same information but does not own the memory. + UnmappedSections.push_back( Allocation(Block, Alignment, false) ); + return (uint8_t*)Block.base(); +} + +sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) { + error_code ec; + sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, + &Near, + sys::Memory::MF_READ | + sys::Memory::MF_WRITE, + ec); + assert(!ec && MB.base()); + + // FIXME: This is part of a work around to keep sections near one another + // when MCJIT performs relocations after code emission but before + // the generated code is moved to the remote target. + // Save this address as the basis for our next request + Near = MB; + return MB; +} + +void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, + const ObjectImage *Obj) { + // The client should have called setRemoteTarget() before triggering any + // code generation. + assert(Target); + if (!Target) + return; + + // FIXME: Make this function thread safe. + + // Lay out our sections in order, with all the code sections first, then + // all the data sections. + uint64_t CurOffset = 0; + unsigned MaxAlign = Target->getPageAlignment(); + SmallVector<std::pair<Allocation, uint64_t>, 16> Offsets; + unsigned NumSections = UnmappedSections.size(); + // We're going to go through the list twice to separate code and data, but + // it's a very small list, so that's OK. + for (size_t i = 0, e = NumSections; i != e; ++i) { + Allocation &Section = UnmappedSections[i]; + if (Section.IsCode) { + unsigned Size = Section.MB.size(); + unsigned Align = Section.Alignment; + DEBUG(dbgs() << "code region: size " << Size + << ", alignment " << Align << "\n"); + // Align the current offset up to whatever is needed for the next + // section. + CurOffset = (CurOffset + Align - 1) / Align * Align; + // Save off the address of the new section and allocate its space. + Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset)); + CurOffset += Size; + } + } + // Adjust to keep code and data aligned on seperate pages. + CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; + for (size_t i = 0, e = NumSections; i != e; ++i) { + Allocation &Section = UnmappedSections[i]; + if (!Section.IsCode) { + unsigned Size = Section.MB.size(); + unsigned Align = Section.Alignment; + DEBUG(dbgs() << "data region: size " << Size + << ", alignment " << Align << "\n"); + // Align the current offset up to whatever is needed for the next + // section. + CurOffset = (CurOffset + Align - 1) / Align * Align; + // Save off the address of the new section and allocate its space. + Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset)); + CurOffset += Size; + } + } + + // Allocate space in the remote target. + uint64_t RemoteAddr; + if (Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) + report_fatal_error(Target->getErrorMsg()); + + // Map the section addresses so relocations will get updated in the local + // copies of the sections. + for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { + uint64_t Addr = RemoteAddr + Offsets[i].second; + EE->mapSectionAddress(const_cast<void*>(Offsets[i].first.MB.base()), Addr); + + DEBUG(dbgs() << " Mapping local: " << Offsets[i].first.MB.base() + << " to remote: 0x" << format("%llx", Addr) << "\n"); + + MappedSections[Addr] = Offsets[i].first; + } + + UnmappedSections.clear(); +} + +bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) { + // FIXME: Make this function thread safe. + for (DenseMap<uint64_t, Allocation>::iterator + I = MappedSections.begin(), E = MappedSections.end(); + I != E; ++I) { + uint64_t RemoteAddr = I->first; + const Allocation &Section = I->second; + if (Section.IsCode) { + Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()); + + DEBUG(dbgs() << " loading code: " << Section.MB.base() + << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); + } else { + Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()); + + DEBUG(dbgs() << " loading data: " << Section.MB.base() + << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); + } + } + + MappedSections.clear(); + + return false; +} + +void RemoteMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } +void RemoteMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } +void RemoteMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } +void RemoteMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } +uint8_t *RemoteMemoryManager::getGOTBase() const { + llvm_unreachable("Unexpected!"); + return 0; +} +uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ + llvm_unreachable("Unexpected!"); + return 0; +} +uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, + unsigned Alignment) { + llvm_unreachable("Unexpected!"); + return 0; +} +void RemoteMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd) { + llvm_unreachable("Unexpected!"); +} +uint8_t *RemoteMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { + llvm_unreachable("Unexpected!"); + return 0; +} +uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { + llvm_unreachable("Unexpected!"); + return 0; +} +void RemoteMemoryManager::deallocateFunctionBody(void *Body) { + llvm_unreachable("Unexpected!"); +} diff --git a/tools/lli/RemoteMemoryManager.h b/tools/lli/RemoteMemoryManager.h new file mode 100644 index 0000000..5d0456f --- /dev/null +++ b/tools/lli/RemoteMemoryManager.h @@ -0,0 +1,114 @@ +//===- RemoteMemoryManager.h - LLI MCJIT recording memory manager ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This memory manager allocates local storage and keeps a record of each +// allocation. Iterators are provided for all data and code allocations. +// +//===----------------------------------------------------------------------===// + +#ifndef REMOTEMEMORYMANAGER_H +#define REMOTEMEMORYMANAGER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ExecutionEngine/JITMemoryManager.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Memory.h" +#include <utility> + +#include "RemoteTarget.h" + +namespace llvm { + +class RemoteMemoryManager : public JITMemoryManager { +public: + // Notice that this structure takes ownership of the memory allocated. + struct Allocation { + Allocation() {} + Allocation(sys::MemoryBlock mb, unsigned a, bool code) + : MB(mb), Alignment(a), IsCode(code) {} + + sys::MemoryBlock MB; + unsigned Alignment; + bool IsCode; + }; + +private: + // This vector contains Allocation objects for all sections which we have + // allocated. This vector effectively owns the memory associated with the + // allocations. + SmallVector<Allocation, 2> AllocatedSections; + + // This vector contains pointers to Allocation objects for any sections we + // have allocated locally but have not yet remapped for the remote target. + // When we receive notification of a completed module load, we will map + // these sections into the remote target. + SmallVector<Allocation, 2> UnmappedSections; + + // This map tracks the sections we have remapped for the remote target + // but have not yet copied to the target. + DenseMap<uint64_t, Allocation> MappedSections; + + // FIXME: This is part of a work around to keep sections near one another + // when MCJIT performs relocations after code emission but before + // the generated code is moved to the remote target. + sys::MemoryBlock Near; + sys::MemoryBlock allocateSection(uintptr_t Size); + + RemoteTarget *Target; + +public: + RemoteMemoryManager() : Target(NULL) {} + virtual ~RemoteMemoryManager(); + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName); + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool IsReadOnly); + + // For now, remote symbol resolution is not support in lli. The MCJIT + // interface does support this, but clients must provide their own + // mechanism for finding remote symbol addresses. MCJIT will resolve + // symbols from Modules it contains. + uint64_t getSymbolAddress(const std::string &Name) { return 0; } + + void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj); + + bool finalizeMemory(std::string *ErrMsg); + + // For now, remote EH frame registration isn't supported. Remote symbol + // resolution is a prerequisite to supporting remote EH frame registration. + void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {} + void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {} + + // This is a non-interface function used by lli + void setRemoteTarget(RemoteTarget *T) { Target = T; } + + // The following obsolete JITMemoryManager calls are stubbed out for + // this model. + void setMemoryWritable(); + void setMemoryExecutable(); + void setPoisonMemory(bool poison); + void AllocateGOT(); + uint8_t *getGOTBase() const; + uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize); + uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, + unsigned Alignment); + void endFunctionBody(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd); + uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); + uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); + void deallocateFunctionBody(void *Body); +}; + +} // end namespace llvm + +#endif diff --git a/tools/lli/RemoteTarget.cpp b/tools/lli/RemoteTarget.cpp index 212bdfd..5c74e6e 100644 --- a/tools/lli/RemoteTarget.cpp +++ b/tools/lli/RemoteTarget.cpp @@ -13,13 +13,44 @@ //===----------------------------------------------------------------------===// #include "RemoteTarget.h" +#include "RemoteTargetExternal.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Memory.h" #include <stdlib.h> #include <string> + using namespace llvm; +// Static methods +RemoteTarget *RemoteTarget::createRemoteTarget() { + return new RemoteTarget; +} + +RemoteTarget *RemoteTarget::createExternalRemoteTarget(std::string &ChildName) { +#ifdef LLVM_ON_UNIX + return new RemoteTargetExternal(ChildName); +#else + return 0; +#endif +} + +bool RemoteTarget::hostSupportsExternalRemoteTarget() { +#ifdef LLVM_ON_UNIX + return true; +#else + return false; +#endif +} + + +//////////////////////////////////////////////////////////////////////////////// +// Simulated remote execution +// +// This implementation will simply move generated code and data to a new memory +// location in the current executable and let it run from there. +//////////////////////////////////////////////////////////////////////////////// + bool RemoteTarget::allocateSpace(size_t Size, unsigned Alignment, uint64_t &Address) { sys::MemoryBlock *Prev = Allocations.size() ? &Allocations.back() : NULL; diff --git a/tools/lli/RemoteTarget.h b/tools/lli/RemoteTarget.h index b2a6d0e..c95fbd1 100644 --- a/tools/lli/RemoteTarget.h +++ b/tools/lli/RemoteTarget.h @@ -41,7 +41,9 @@ public: /// /// @returns False on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - bool allocateSpace(size_t Size, unsigned Alignment, uint64_t &Address); + virtual bool allocateSpace(size_t Size, + unsigned Alignment, + uint64_t &Address); /// Load data into the target address space. /// @@ -51,7 +53,9 @@ public: /// /// @returns False on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - bool loadData(uint64_t Address, const void *Data, size_t Size); + virtual bool loadData(uint64_t Address, + const void *Data, + size_t Size); /// Load code into the target address space and prepare it for execution. /// @@ -61,7 +65,9 @@ public: /// /// @returns False on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - bool loadCode(uint64_t Address, const void *Data, size_t Size); + virtual bool loadCode(uint64_t Address, + const void *Data, + size_t Size); /// Execute code in the target process. The called function is required /// to be of signature int "(*)(void)". @@ -72,24 +78,29 @@ public: /// /// @returns False on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - bool executeCode(uint64_t Address, int &RetVal); + virtual bool executeCode(uint64_t Address, + int &RetVal); /// Minimum alignment for memory permissions. Used to seperate code and /// data regions to make sure data doesn't get marked as code or vice /// versa. /// /// @returns Page alignment return value. Default of 4k. - unsigned getPageAlignment() { return 4096; } + virtual unsigned getPageAlignment() { return 4096; } /// Start the remote process. - void create(); + virtual void create(); /// Terminate the remote process. - void stop(); + virtual void stop(); RemoteTarget() : ErrorMsg(""), IsRunning(false) {} - ~RemoteTarget() { if (IsRunning) stop(); } + virtual ~RemoteTarget() { if (IsRunning) stop(); } + // Create an instance of the system-specific remote target class. + static RemoteTarget *createRemoteTarget(); + static RemoteTarget *createExternalRemoteTarget(std::string &ChildName); + static bool hostSupportsExternalRemoteTarget(); private: // Main processing function for the remote target process. Command messages // are received on file descriptor CmdFD and responses come back on OutFD. diff --git a/tools/lli/RemoteTargetExternal.cpp b/tools/lli/RemoteTargetExternal.cpp new file mode 100644 index 0000000..742a948 --- /dev/null +++ b/tools/lli/RemoteTargetExternal.cpp @@ -0,0 +1,162 @@ +//===---- RemoteTargetExternal.cpp - LLVM out-of-process JIT execution ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the RemoteTargetExternal class which executes JITed code +// in a separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" + +#include "RemoteTarget.h" +#include "RemoteTargetExternal.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Memory.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +using namespace llvm; + +bool RemoteTargetExternal::allocateSpace(size_t Size, unsigned Alignment, + uint64_t &Address) { + SendAllocateSpace(Alignment, Size); + Receive(LLI_AllocationResult, Address); + return false; +} + +bool RemoteTargetExternal::loadData(uint64_t Address, const void *Data, size_t Size) { + SendLoadSection(Address, Data, (uint32_t)Size, false); + Receive(LLI_LoadComplete); + return false; +} + +bool RemoteTargetExternal::loadCode(uint64_t Address, const void *Data, size_t Size) { + SendLoadSection(Address, Data, (uint32_t)Size, true); + Receive(LLI_LoadComplete); + return false; +} + +bool RemoteTargetExternal::executeCode(uint64_t Address, int &RetVal) { + SendExecute(Address); + + Receive(LLI_ExecutionResult, RetVal); + return false; +} + +void RemoteTargetExternal::stop() { + SendTerminate(); + Wait(); +} + +void RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) { + int rc; + uint32_t MsgType = (uint32_t)LLI_AllocateSpace; + rc = WriteBytes(&MsgType, 4); + assert(rc == 4 && "Error writing message type."); + + uint32_t DataSize = 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4 && "Error writing data size."); + + rc = WriteBytes(&Alignment, 4); + assert(rc == 4 && "Error writing alignment data."); + + rc = WriteBytes(&Size, 4); + assert(rc == 4 && "Error writing size data."); +} + +void RemoteTargetExternal::SendLoadSection(uint64_t Addr, + const void *Data, + uint32_t Size, + bool IsCode) { + int rc; + uint32_t MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection; + rc = WriteBytes(&MsgType, 4); + assert(rc == 4 && "Error writing message type."); + + uint32_t DataSize = Size + 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4 && "Error writing data size."); + + rc = WriteBytes(&Addr, 8); + assert(rc == 8 && "Error writing data."); + + rc = WriteBytes(Data, Size); + assert(rc == (int)Size && "Error writing data."); +} + +void RemoteTargetExternal::SendExecute(uint64_t Addr) { + int rc; + uint32_t MsgType = (uint32_t)LLI_Execute; + rc = WriteBytes(&MsgType, 4); + assert(rc == 4 && "Error writing message type."); + + uint32_t DataSize = 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4 && "Error writing data size."); + + rc = WriteBytes(&Addr, 8); + assert(rc == 8 && "Error writing data."); +} + +void RemoteTargetExternal::SendTerminate() { + int rc; + uint32_t MsgType = (uint32_t)LLI_Terminate; + rc = WriteBytes(&MsgType, 4); + assert(rc == 4 && "Error writing message type."); + + // No data or data size is sent with Terminate +} + + +void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType) { + int rc; + uint32_t MsgType; + rc = ReadBytes(&MsgType, 4); + assert(rc == 4 && "Error reading message type."); + assert(MsgType == (uint32_t)ExpectedMsgType && "Error: received unexpected message type."); + + uint32_t DataSize; + rc = ReadBytes(&DataSize, 4); + assert(rc == 4 && "Error reading data size."); + assert(DataSize == 0 && "Error: unexpected data size."); +} + +void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, int &Data) { + uint64_t Temp; + Receive(ExpectedMsgType, Temp); + Data = (int)(int64_t)Temp; +} + +void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, uint64_t &Data) { + int rc; + uint32_t MsgType; + rc = ReadBytes(&MsgType, 4); + assert(rc == 4 && "Error reading message type."); + assert(MsgType == (uint32_t)ExpectedMsgType && "Error: received unexpected message type."); + + uint32_t DataSize; + rc = ReadBytes(&DataSize, 4); + assert(rc == 4 && "Error reading data size."); + assert(DataSize == 8 && "Error: unexpected data size."); + + rc = ReadBytes(&Data, 8); + assert(DataSize == 8 && "Error: unexpected data."); +} + +#ifdef LLVM_ON_UNIX +#include "Unix/RemoteTargetExternal.inc" +#endif + +#ifdef LLVM_ON_WIN32 +#include "Windows/RemoteTargetExternal.inc" +#endif diff --git a/tools/lli/RemoteTargetExternal.h b/tools/lli/RemoteTargetExternal.h new file mode 100644 index 0000000..a4bfad2 --- /dev/null +++ b/tools/lli/RemoteTargetExternal.h @@ -0,0 +1,118 @@ +//===----- RemoteTargetExternal.h - LLVM out-of-process JIT execution -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Definition of the RemoteTargetExternal class which executes JITed code in a +// separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +#ifndef LLI_REMOTETARGETEXTERNAL_H +#define LLI_REMOTETARGETEXTERNAL_H + +#include "llvm/Config/config.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Memory.h" +#include <stdlib.h> +#include <string> + +#include "RemoteTarget.h" +#include "RemoteTargetMessage.h" + +namespace llvm { + +class RemoteTargetExternal : public RemoteTarget { +public: + /// Allocate space in the remote target address space. + /// + /// @param Size Amount of space, in bytes, to allocate. + /// @param Alignment Required minimum alignment for allocated space. + /// @param[out] Address Remote address of the allocated memory. + /// + /// @returns False on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + virtual bool allocateSpace(size_t Size, + unsigned Alignment, + uint64_t &Address); + + /// Load data into the target address space. + /// + /// @param Address Destination address in the target process. + /// @param Data Source address in the host process. + /// @param Size Number of bytes to copy. + /// + /// @returns False on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + virtual bool loadData(uint64_t Address, const void *Data, size_t Size); + + /// Load code into the target address space and prepare it for execution. + /// + /// @param Address Destination address in the target process. + /// @param Data Source address in the host process. + /// @param Size Number of bytes to copy. + /// + /// @returns False on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + virtual bool loadCode(uint64_t Address, const void *Data, size_t Size); + + /// Execute code in the target process. The called function is required + /// to be of signature int "(*)(void)". + /// + /// @param Address Address of the loaded function in the target + /// process. + /// @param[out] RetVal The integer return value of the called function. + /// + /// @returns False on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + virtual bool executeCode(uint64_t Address, int &RetVal); + + /// Minimum alignment for memory permissions. Used to seperate code and + /// data regions to make sure data doesn't get marked as code or vice + /// versa. + /// + /// @returns Page alignment return value. Default of 4k. + virtual unsigned getPageAlignment() { return 4096; } + + /// Start the remote process. + virtual void create(); + + /// Terminate the remote process. + virtual void stop(); + + RemoteTargetExternal(std::string &Name) : RemoteTarget(), ChildName(Name) {} + virtual ~RemoteTargetExternal(); + +private: + std::string ChildName; + + // This will get filled in as a point to an OS-specific structure. + void *ConnectionData; + + void SendAllocateSpace(uint32_t Alignment, uint32_t Size); + void SendLoadSection(uint64_t Addr, + const void *Data, + uint32_t Size, + bool IsCode); + void SendExecute(uint64_t Addr); + void SendTerminate(); + + void Receive(LLIMessageType Msg); + void Receive(LLIMessageType Msg, int &Data); + void Receive(LLIMessageType Msg, uint64_t &Data); + + int WriteBytes(const void *Data, size_t Size); + int ReadBytes(void *Data, size_t Size); + void Wait(); +}; + +} // end namespace llvm + +#endif // LLI_REMOTETARGETEXTERNAL_H diff --git a/tools/lli/RemoteTargetMessage.h b/tools/lli/RemoteTargetMessage.h new file mode 100644 index 0000000..12cfa9a --- /dev/null +++ b/tools/lli/RemoteTargetMessage.h @@ -0,0 +1,45 @@ +//===---- RemoteTargetMessage.h - LLI out-of-process message protocol -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Definition of the LLIMessageType enum which is used for communication with a +// child process for remote execution. +// +//===----------------------------------------------------------------------===// + +#ifndef LLI_REMOTETARGETMESSAGE_H +#define LLI_REMOTETARGETMESSAGE_H + +namespace llvm { + +// LLI messages from parent-to-child or vice versa follow an exceedingly simple +// protocol where the first four bytes represent the message type, the next +// four bytes represent the size of data for the command and following bytes +// represent the actual data. +// +// The protocol is not intended to be robust, secure or fault-tolerant. It is +// only here for testing purposes and is therefore intended to be the simplest +// implementation that will work. It is assumed that the parent and child +// share characteristics like endianness. + +enum LLIMessageType { + LLI_Error = -1, + LLI_ChildActive = 0, // Data = not used + LLI_AllocateSpace, // Data = struct { uint_32t Align, uint_32t Size } + LLI_AllocationResult, // Data = uint64_t AllocAddress (in Child memory space) + LLI_LoadCodeSection, // Data = uint32_t Addr, followed by section contests + LLI_LoadDataSection, // Data = uint32_t Addr, followed by section contents + LLI_LoadComplete, // Data = not used + LLI_Execute, // Data = Address of function to execute + LLI_ExecutionResult, // Data = uint64_t Result + LLI_Terminate // Data = not used +}; + +} // end namespace llvm + +#endif diff --git a/tools/lli/Unix/RemoteTargetExternal.inc b/tools/lli/Unix/RemoteTargetExternal.inc new file mode 100644 index 0000000..9c1a4cc --- /dev/null +++ b/tools/lli/Unix/RemoteTargetExternal.inc @@ -0,0 +1,96 @@ +//=- RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Unix --=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the Unix-specific parts of the RemoteTargetExternal class +// which executes JITed code in a separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> + +namespace { + +struct ConnectionData_t { + int InputPipe; + int OutputPipe; + + ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {} +}; + +} // namespace + +namespace llvm { + +void RemoteTargetExternal::create() { + int PipeFD[2][2]; + pid_t ChildPID; + + // Create two pipes. + if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0) + perror("Error creating pipe: "); + + ChildPID = fork(); + + if (ChildPID == 0) { + // In the child... + + // Close the parent ends of the pipes + close(PipeFD[0][1]); + close(PipeFD[1][0]); + + // Use our pipes as stdin and stdout + if (PipeFD[0][0] != STDIN_FILENO) { + dup2(PipeFD[0][0], STDIN_FILENO); + close(PipeFD[0][0]); + } + if (PipeFD[1][1] != STDOUT_FILENO) { + dup2(PipeFD[1][1], STDOUT_FILENO); + close(PipeFD[1][1]); + } + + // Execute the child process. + char *args[1] = { NULL }; + int rc = execv(ChildName.c_str(), args); + if (rc != 0) + perror("Error executing child process: "); + } + else { + // In the parent... + + // Close the child ends of the pipes + close(PipeFD[0][0]); + close(PipeFD[1][1]); + + // Store the parent ends of the pipes + ConnectionData = (void*)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]); + + Receive(LLI_ChildActive); + } +} + +int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) { + return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size); +} + +int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) { + return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size); +} + +void RemoteTargetExternal::Wait() { + wait(NULL); +} + +RemoteTargetExternal::~RemoteTargetExternal() { + delete static_cast<ConnectionData_t *>(ConnectionData); +} + +} // namespace llvm diff --git a/tools/lli/Windows/RemoteTargetExternal.inc b/tools/lli/Windows/RemoteTargetExternal.inc new file mode 100644 index 0000000..aef4627 --- /dev/null +++ b/tools/lli/Windows/RemoteTargetExternal.inc @@ -0,0 +1,35 @@ +//= RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Windows =// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Definition of the Windows-specific parts of the RemoteTargetExternal class +// which is meant to execute JITed code in a separate process from where it was +// built. To support this functionality on Windows, implement these functions. +// +//===----------------------------------------------------------------------===// + +namespace llvm { + +void RemoteTargetExternal::create() { +} + +int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) { + return 0; +} + +int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) { + return 0; +} + +void RemoteTargetExternal::Wait() { +} + +RemoteTargetExternal::~RemoteTargetExternal() { +} + +} // namespace llvm diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 297763f..f317566 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -15,7 +15,7 @@ #define DEBUG_TYPE "lli" #include "llvm/IR/LLVMContext.h" -#include "RecordingMemoryManager.h" +#include "RemoteMemoryManager.h" #include "RemoteTarget.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/ReaderWriter.h" @@ -27,8 +27,10 @@ #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" +#include "llvm/IR/TypeBuilder.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -41,10 +43,12 @@ #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" +#include "llvm/Support/Program.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__ @@ -71,6 +75,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. @@ -78,6 +86,18 @@ namespace { cl::desc("Execute MCJIT'ed code in a separate process."), cl::init(false)); + // Manually specify the child process for remote execution. This overrides + // the simulated remote execution that allocates address space for child + // execution. The child process will be executed and will communicate with + // lli via stdin/stdout pipes. + cl::opt<std::string> + MCJITRemoteProcess("mcjit-remote-process", + cl::desc("Specify the filename of the process to launch " + "for remote MCJIT execution. If none is specified," + "\n\tremote execution will be simulated in-process."), + cl::value_desc("filename"), + cl::init("")); + // Determine optimization level. cl::opt<char> OptLevel("O", @@ -113,6 +133,11 @@ namespace { cl::value_desc("function"), cl::init("main")); + cl::list<std::string> + ExtraModules("extra-module", + cl::desc("Extra modules to be loaded"), + cl::value_desc("input bitcode")); + cl::opt<std::string> FakeArgv0("fake-argv0", cl::desc("Override the 'argv[0]' value passed into the executing" @@ -159,11 +184,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)); @@ -209,82 +229,46 @@ static void do_shutdown() { #endif } -void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) { - // Lay out our sections in order, with all the code sections first, then - // all the data sections. - uint64_t CurOffset = 0; - unsigned MaxAlign = T->getPageAlignment(); - SmallVector<std::pair<const void*, uint64_t>, 16> Offsets; - SmallVector<unsigned, 16> Sizes; - for (RecordingMemoryManager::const_code_iterator I = JMM->code_begin(), - E = JMM->code_end(); - I != E; ++I) { - DEBUG(dbgs() << "code region: size " << I->first.size() - << ", alignment " << I->second << "\n"); - // Align the current offset up to whatever is needed for the next - // section. - unsigned Align = I->second; - CurOffset = (CurOffset + Align - 1) / Align * Align; - // Save off the address of the new section and allocate its space. - Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset)); - Sizes.push_back(I->first.size()); - CurOffset += I->first.size(); - } - // Adjust to keep code and data aligned on seperate pages. - CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; - unsigned FirstDataIndex = Offsets.size(); - for (RecordingMemoryManager::const_data_iterator I = JMM->data_begin(), - E = JMM->data_end(); - I != E; ++I) { - DEBUG(dbgs() << "data region: size " << I->first.size() - << ", alignment " << I->second << "\n"); - // Align the current offset up to whatever is needed for the next - // section. - unsigned Align = I->second; - CurOffset = (CurOffset + Align - 1) / Align * Align; - // Save off the address of the new section and allocate its space. - Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset)); - Sizes.push_back(I->first.size()); - CurOffset += I->first.size(); - } - - // Allocate space in the remote target. - uint64_t RemoteAddr; - if (T->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) - report_fatal_error(T->getErrorMsg()); - // Map the section addresses so relocations will get updated in the local - // copies of the sections. - for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { - uint64_t Addr = RemoteAddr + Offsets[i].second; - EE->mapSectionAddress(const_cast<void*>(Offsets[i].first), Addr); - - DEBUG(dbgs() << " Mapping local: " << Offsets[i].first - << " to remote: " << format("%p", Addr) << "\n"); - - } - - // Trigger application of relocations - EE->finalizeObject(); - - // Now load it all to the target. - for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { - uint64_t Addr = RemoteAddr + Offsets[i].second; - - if (i < FirstDataIndex) { - T->loadCode(Addr, Offsets[i].first, Sizes[i]); - - DEBUG(dbgs() << " loading code: " << Offsets[i].first - << " to remote: " << format("%p", Addr) << "\n"); - } else { - T->loadData(Addr, Offsets[i].first, Sizes[i]); - - DEBUG(dbgs() << " loading data: " << Offsets[i].first - << " to remote: " << format("%p", Addr) << "\n"); - } - +// On Mingw and Cygwin, an external symbol named '__main' is called from the +// generated 'main' function to allow static intialization. To avoid linking +// problems with remote targets (because lli's remote target support does not +// currently handle external linking) we add a secondary module which defines +// an empty '__main' function. +static void addCygMingExtraModule(ExecutionEngine *EE, + LLVMContext &Context, + StringRef TargetTripleStr) { + IRBuilder<> Builder(Context); + Triple TargetTriple(TargetTripleStr); + + // Create a new module. + Module *M = new Module("CygMingHelper", Context); + M->setTargetTriple(TargetTripleStr); + + // Create an empty function named "__main". + Function *Result; + if (TargetTriple.isArch64Bit()) { + Result = Function::Create( + TypeBuilder<int64_t(void), false>::get(Context), + GlobalValue::ExternalLinkage, "__main", M); + } else { + Result = Function::Create( + TypeBuilder<int32_t(void), false>::get(Context), + GlobalValue::ExternalLinkage, "__main", M); } + BasicBlock *BB = BasicBlock::Create(Context, "__main", Result); + Builder.SetInsertPoint(BB); + Value *ReturnVal; + if (TargetTriple.isArch64Bit()) + ReturnVal = ConstantInt::get(Context, APInt(64, 0)); + else + ReturnVal = ConstantInt::get(Context, APInt(32, 0)); + Builder.CreateRet(ReturnVal); + + // Add this new module to the ExecutionEngine. + EE->addModule(M); } + //===----------------------------------------------------------------------===// // main Driver function // @@ -326,6 +310,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); @@ -342,14 +337,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 RemoteMemoryManager(); 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"; @@ -381,7 +376,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; } @@ -397,6 +391,22 @@ int main(int argc, char **argv, char * const *envp) { exit(1); } + // Load any additional modules specified on the command line. + for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) { + Module *XMod = ParseIRFile(ExtraModules[i], Err, Context); + if (!XMod) { + Err.print(argv[0], errs()); + return 1; + } + EE->addModule(XMod); + } + + // If the target is Cygwin/MingW and we are generating remote code, we + // need an extra module to help out with linking. + if (RemoteMCJIT && Triple(Mod->getTargetTriple()).isOSCygMing()) { + addCygMingExtraModule(EE, Context, Mod->getTargetTriple()); + } + // The following functions have no effect if their respective profiling // support wasn't enabled in the build configuration. EE->RegisterJITEventListener( @@ -435,82 +445,43 @@ int main(int argc, char **argv, char * const *envp) { return -1; } - // If the program doesn't explicitly call exit, we will need the Exit - // function later on to make an explicit call, so get the function now. - Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), - Type::getInt32Ty(Context), - NULL); - // Reset errno to zero on entry to main. errno = 0; - // Remote target MCJIT doesn't (yet) support static constructors. No reason - // it couldn't. This is a limitation of the LLI implemantation, not the - // MCJIT itself. FIXME. - // - // Run static constructors. - if (!RemoteMCJIT) { - if (UseMCJIT && !ForceInterpreter) { - // Give MCJIT a chance to apply relocations and set page permissions. - EE->finalizeObject(); - } - EE->runStaticConstructorsDestructors(false); - } - - if (NoLazyCompilation) { - for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) { - Function *Fn = &*I; - if (Fn != EntryFn && !Fn->isDeclaration()) - EE->getPointerToFunction(Fn); - } - } - int Result; - if (RemoteMCJIT) { - RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(JMM); - // 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. - RemoteTarget Target; - Target.create(); - - // Ask for a pointer to the entry function. This triggers the actual - // compilation. - (void)EE->getPointerToFunction(EntryFn); - // Enough has been compiled to execute the entry function now, so - // layout the target memory. - layoutRemoteTargetMemory(&Target, MM); - - // Since we're executing in a (at least simulated) remote address space, - // we can't use the ExecutionEngine::runFunctionAsMain(). We have to - // grab the function address directly here and tell the remote target - // to execute the function. - // FIXME: argv and envp handling. - uint64_t Entry = (uint64_t)EE->getPointerToFunction(EntryFn); - - DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at " - << format("%p", Entry) << "\n"); + if (!RemoteMCJIT) { + // If the program doesn't explicitly call exit, we will need the Exit + // function later on to make an explicit call, so get the function now. + Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), + Type::getInt32Ty(Context), + NULL); + + // Run static constructors. + if (UseMCJIT && !ForceInterpreter) { + // Give MCJIT a chance to apply relocations and set page permissions. + EE->finalizeObject(); + } + EE->runStaticConstructorsDestructors(false); - if (Target.executeCode(Entry, Result)) - errs() << "ERROR: " << Target.getErrorMsg() << "\n"; + if (!UseMCJIT && NoLazyCompilation) { + for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) { + Function *Fn = &*I; + if (Fn != EntryFn && !Fn->isDeclaration()) + EE->getPointerToFunction(Fn); + } + } - Target.stop(); - } else { // Trigger compilation separately so code regions that need to be // invalidated will be known. (void)EE->getPointerToFunction(EntryFn); // Clear instruction cache before code will be executed. - if (JMM) - static_cast<SectionMemoryManager*>(JMM)->invalidateInstructionCache(); + if (RTDyldMM) + static_cast<SectionMemoryManager*>(RTDyldMM)->invalidateInstructionCache(); // Run main. Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp); - } - // Like static constructors, the remote target MCJIT support doesn't handle - // this yet. It could. FIXME. - if (!RemoteMCJIT) { // Run static destructors. EE->runStaticConstructorsDestructors(true); @@ -528,6 +499,67 @@ int main(int argc, char **argv, char * const *envp) { errs() << "ERROR: exit defined with wrong prototype!\n"; abort(); } + } else { + // else == "if (RemoteMCJIT)" + + // Remote target MCJIT doesn't (yet) support static constructors. No reason + // it couldn't. This is a limitation of the LLI implemantation, not the + // MCJIT itself. FIXME. + // + RemoteMemoryManager *MM = static_cast<RemoteMemoryManager*>(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. + + OwningPtr<RemoteTarget> Target; + if (!MCJITRemoteProcess.empty()) { // Remote execution on a child process + if (!RemoteTarget::hostSupportsExternalRemoteTarget()) { + errs() << "Warning: host does not support external remote targets.\n" + << " Defaulting to simulated remote execution\n"; + Target.reset(RemoteTarget::createRemoteTarget()); + } else { + std::string ChildEXE = sys::FindProgramByName(MCJITRemoteProcess); + if (ChildEXE == "") { + errs() << "Unable to find child target: '\''" << MCJITRemoteProcess << "\'\n"; + return -1; + } + Target.reset(RemoteTarget::createExternalRemoteTarget(ChildEXE)); + } + } else { + // No child process name provided, use simulated remote execution. + Target.reset(RemoteTarget::createRemoteTarget()); + } + + // Give the memory manager a pointer to our remote target interface object. + MM->setRemoteTarget(Target.get()); + + // Create the remote target. + Target->create(); + + // Since we're executing in a (at least simulated) remote address space, + // we can't use the ExecutionEngine::runFunctionAsMain(). We have to + // grab the function address directly here and tell the remote target + // to execute the function. + // + // Our memory manager will map generated code into the remote address + // space as it is loaded and copy the bits over during the finalizeMemory + // operation. + // + // FIXME: argv and envp handling. + uint64_t Entry = EE->getFunctionAddress(EntryFn->getName().str()); + + DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x" + << format("%llx", Entry) << "\n"); + + if (Target->executeCode(Entry, Result)) + errs() << "ERROR: " << Target->getErrorMsg() << "\n"; + + // Like static constructors, the remote target MCJIT support doesn't handle + // this yet. It could. FIXME. + + // Stop the remote target + Target->stop(); } + return Result; } diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index 70eb760..f15a1e2 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -1,7 +1,25 @@ -set(LLVM_LINK_COMPONENTS archive) +set(LLVM_LINK_COMPONENTS support object bitreader) add_llvm_tool(llvm-ar llvm-ar.cpp ) +# FIXME: this is duplicated from the clang CMakeLists.txt +# FIXME: bin/llvm-ranlib is not a valid build target with this setup (pr17024) + +if(UNIX) + set(LLVM_LINK_OR_COPY create_symlink) + set(llvm_ar_binary "llvm-ar${CMAKE_EXECUTABLE_SUFFIX}") +else() + set(LLVM_LINK_OR_COPY copy) + set(llvm_ar_binary "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/llvm-ar${CMAKE_EXECUTABLE_SUFFIX}") +endif() + +set(llvm_ranlib "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/llvm-ranlib${CMAKE_EXECUTABLE_SUFFIX}") +add_custom_command(TARGET llvm-ar POST_BUILD + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${llvm_ar_binary}" "${llvm_ranlib}") + +set_property(DIRECTORY APPEND + PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${llvm_ranlib}) + # TODO: Support check-local. 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..16a8283 100644 --- a/tools/llvm-ar/Makefile +++ b/tools/llvm-ar/Makefile @@ -9,7 +9,8 @@ LEVEL := ../.. TOOLNAME := llvm-ar -LINK_COMPONENTS := archive +TOOLALIAS = llvm-ranlib +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..d70db72 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -13,35 +13,63 @@ //===----------------------------------------------------------------------===// #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; -// Option for compatibility with AIX, not used but must allow it to be present. -static cl::opt<bool> -X32Option ("X32_64", cl::Hidden, - cl::desc("Ignored option for compatibility with AIX")); +// 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; -// llvm-ar operation code and modifier flags. This must come first. -static cl::opt<std::string> -Options(cl::Positional, cl::Required, cl::desc("{operation}[modifiers]...")); + std::string ContextStr = Context.str(); + if (ContextStr == "") + fail(EC.message()); + fail(Context + ": " + EC.message()); +} -// llvm-ar remaining positional arguments. +// llvm-ar/llvm-ranlib remaining positional arguments. static cl::list<std::string> RestOfArgs(cl::Positional, cl::OneOrMore, cl::desc("[relpos] [count] <archive-file> [members]...")); +std::string Options; + // MoreHelp - Provide additional help output explaining the operations and // modifiers of llvm-ar. This object instructs the CommandLine library // to print the text of the constructor when the --help option is given. @@ -57,123 +85,79 @@ 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() { +static void getOptions() { if(RestOfArgs.size() == 0) - show_help("Expected [count] value with N modifier"); - - Count = atoi(RestOfArgs[0].c_str()); + show_help("Expected options"); + Options = RestOfArgs[0]; 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,8 @@ 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() { + getOptions(); // Keep track of number of operations. We can only specify one // per execution. @@ -201,7 +186,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 +200,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 +223,9 @@ ArchiveOperation parseCommandLine() { break; case 'i': getRelPos(); - InsertBefore = true; + AddBefore = true; NumPositional++; break; - case 'N': - getCount(); - UseCount = true; - break; default: cl::PrintHelpMessage(); } @@ -255,6 +238,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 +253,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; -} - -// 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"; - } -} +// 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"; -// 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 +294,586 @@ 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)) +// 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; + + int FD; + failIfError( + sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_Binary, Mode), + Storage.c_str()); + + { + raw_fd_ostream file(FD, false); + + // Get the data and its length + StringRef Data = I->getBuffer(); + + // Write the data. + file.write(Data.data(), Data.size()); + } + + // 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"); +} + +static bool shouldCreateArchive(ArchiveOperation Op) { + switch (Op) { + case Print: + case Delete: + case Move: + case DisplayTable: + case Extract: + case CreateSymTab: + return false; + + case QuickAppend: + case ReplaceOrInsert: 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; - } + } - // 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); + llvm_unreachable("Missing entry in covered switch."); +} - // Get the data and its length - const char* data = reinterpret_cast<const char*>(I->getData()); - unsigned len = I->getSize(); +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)); - // Write the data. - file.write(data,len); - file.close(); + if (!Members.empty() && + std::find(Members.begin(), Members.end(), Name) == Members.end()) + continue; - // If we're supposed to retain the original modification times, etc. do so - // now. - if (OriginalDates) - I->getPath().setStatusInfoOnDisk(I->getFileStatus()); + 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; } } - return false; } -// 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()) - 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; +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; +}; +} + +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(); +} + +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're done editting, reconstruct the archive. - if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg)) - return true; - if (ReallyVerbose) - printSymbolTable(); - return false; -} - -// 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; +// 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; + } - // 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; - } + 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); - // 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; + 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(); + + 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); + + // Opening a directory doesn't make sense. Let it failed. + // Linux cannot open directories with open(2), although + // cygwin and *bsd can. + if (Status.type() == sys::fs::file_type::directory_file) + failIfError(error_code(errc::is_a_directory, posix_category()), + FileName); + + OwningPtr<MemoryBuffer> File; + failIfError(MemoryBuffer::getOpenFile(FD, FileName, File, + Status.getSize(), false), + FileName); + + 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."); +} + +static int ar_main(char **argv); +static int ranlib_main(); + // 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 +883,63 @@ int main(int argc, char **argv) { " This program archives bitcode files into single libraries\n" ); - int exitCode = 0; + StringRef Stem = sys::path::stem(ToolName); + if (Stem.find("ar") != StringRef::npos) + return ar_main(argv); + if (Stem.find("ranlib") != StringRef::npos) + return ranlib_main(); + fail("Not ranlib or ar!"); +} +static int performOperation(ArchiveOperation Operation); + +int ranlib_main() { + if (RestOfArgs.size() != 1) + fail(ToolName + "takes just one archive as argument"); + ArchiveName = RestOfArgs[0]; + return performOperation(CreateSymTab); +} + +int ar_main(char **argv) { // 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(); + return performOperation(Operation); +} - // Check the path name of the archive - sys::Path ArchivePath; - if (!ArchivePath.set(ArchiveName)) { - errs() << argv[0] << ": Archive name invalid: " << ArchiveName << "\n"; +static int performOperation(ArchiveOperation Operation) { + // 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() << ToolName << ": 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() << ToolName << ": 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() << ToolName << ": 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 d6f1919..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); diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 99479a4..da40da2 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -41,6 +41,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" #include <algorithm> +#include <cctype> #include <map> using namespace llvm; @@ -481,7 +482,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-c-test/CMakeLists.txt b/tools/llvm-c-test/CMakeLists.txt new file mode 100644 index 0000000..2926d9d --- /dev/null +++ b/tools/llvm-c-test/CMakeLists.txt @@ -0,0 +1,16 @@ +set(LLVM_LINK_COMPONENTS all) + +if (LLVM_COMPILER_IS_GCC_COMPATIBLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wstrict-prototypes") +endif () + +add_llvm_tool(llvm-c-test + calc.c + disassemble.c + helpers.c + include-all.c + main.c + module.c + object.c + targets.c + ) diff --git a/tools/llvm-c-test/Makefile b/tools/llvm-c-test/Makefile new file mode 100644 index 0000000..08be7c3 --- /dev/null +++ b/tools/llvm-c-test/Makefile @@ -0,0 +1,29 @@ +##===- tools/llvm-c-test -----------------------------------*- 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-c-test + +TOOL_NO_EXPORTS = 1 +NO_INSTALL = 1 + + +# If there is no shared lib, link all components... +ifneq ($(ENABLE_SHARED),1) +LINK_COMPONENTS = all +endif + +include $(LEVEL)/Makefile.common + +CFLAGS += -std=c99 -Wall -Wstrict-prototypes + +# ...but if it is built - use it +ifeq ($(ENABLE_SHARED),1) +LIBS = -lLLVM-$(LLVMVersion) +endif diff --git a/tools/llvm-c-test/calc.c b/tools/llvm-c-test/calc.c new file mode 100644 index 0000000..3119ccf --- /dev/null +++ b/tools/llvm-c-test/calc.c @@ -0,0 +1,148 @@ +/*===-- calc.c - tool for testing libLLVM and llvm-c API ------------------===*\ +|* *| +|* 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 --calc command in llvm-c-test. --calc reads lines *| +|* from stdin, parses them as a name and an expression in reverse polish *| +|* notation and prints a module with a function with the expression. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/Core.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +typedef LLVMValueRef (*binop_func_t)(LLVMBuilderRef, LLVMValueRef LHS, + LLVMValueRef RHS, const char *Name); + +static LLVMOpcode op_to_opcode(char op) { + switch (op) { + case '+': return LLVMAdd; + case '-': return LLVMSub; + case '*': return LLVMMul; + case '/': return LLVMSDiv; + case '&': return LLVMAnd; + case '|': return LLVMOr; + case '^': return LLVMXor; + } + assert(0 && "unknown operation"); + return 0; +} + +#define MAX_DEPTH 32 + +static LLVMValueRef build_from_tokens(char **tokens, int ntokens, + LLVMBuilderRef builder, + LLVMValueRef param) { + LLVMValueRef stack[MAX_DEPTH]; + int depth = 0; + int i; + + for (i = 0; i < ntokens; i++) { + char tok = tokens[i][0]; + switch (tok) { + case '+': + case '-': + case '*': + case '/': + case '&': + case '|': + case '^': + if (depth < 2) { + printf("stack underflow\n"); + return NULL; + } + + stack[depth - 2] = LLVMBuildBinOp(builder, op_to_opcode(tok), + stack[depth - 1], stack[depth - 2], ""); + depth--; + + break; + + case '@': { + LLVMValueRef off; + + if (depth < 1) { + printf("stack underflow\n"); + return NULL; + } + + off = LLVMBuildGEP(builder, param, &stack[depth - 1], 1, ""); + stack[depth - 1] = LLVMBuildLoad(builder, off, ""); + + break; + } + + default: { + char *end; + long val = strtol(tokens[i], &end, 0); + if (end[0] != '\0') { + printf("error parsing number\n"); + return NULL; + } + + if (depth >= MAX_DEPTH) { + printf("stack overflow\n"); + return NULL; + } + + stack[depth++] = LLVMConstInt(LLVMInt64Type(), val, 1); + break; + } + } + } + + if (depth < 1) { + printf("stack underflow at return\n"); + return NULL; + } + + LLVMBuildRet(builder, stack[depth - 1]); + + return stack[depth - 1]; +} + +static void handle_line(char **tokens, int ntokens) { + char *name = tokens[0]; + LLVMValueRef param; + LLVMValueRef res; + + LLVMModuleRef M = LLVMModuleCreateWithName(name); + + LLVMTypeRef I64ty = LLVMInt64Type(); + LLVMTypeRef I64Ptrty = LLVMPointerType(I64ty, 0); + LLVMTypeRef Fty = LLVMFunctionType(I64ty, &I64Ptrty, 1, 0); + + LLVMValueRef F = LLVMAddFunction(M, name, Fty); + LLVMBuilderRef builder = LLVMCreateBuilder(); + LLVMPositionBuilderAtEnd(builder, LLVMAppendBasicBlock(F, "entry")); + + LLVMGetParams(F, ¶m); + LLVMSetValueName(param, "in"); + + res = build_from_tokens(tokens + 1, ntokens - 1, builder, param); + if (res) { + char *irstr = LLVMPrintModuleToString(M); + puts(irstr); + LLVMDisposeMessage(irstr); + } + + LLVMDisposeBuilder(builder); + + LLVMDisposeModule(M); +} + +int calc(void) { + + tokenize_stdin(handle_line); + + return 0; +} diff --git a/tools/llvm-c-test/disassemble.c b/tools/llvm-c-test/disassemble.c new file mode 100644 index 0000000..eb40bf3 --- /dev/null +++ b/tools/llvm-c-test/disassemble.c @@ -0,0 +1,88 @@ +/*===-- disassemble.c - tool for testing libLLVM and llvm-c API -----------===*\ +|* *| +|* 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 --disassemble command in llvm-c-test. *| +|* --disassemble reads lines from stdin, parses them as a triple and hex *| +|* machine code, and prints disassembly of the machine code. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/Disassembler.h" +#include "llvm-c/Target.h" +#include <stdio.h> +#include <stdlib.h> + +static void pprint(int pos, unsigned char *buf, int len, const char *disasm) { + int i; + printf("%04x: ", pos); + for (i = 0; i < 8; i++) { + if (i < len) { + printf("%02x ", buf[i]); + } else { + printf(" "); + } + } + + printf(" %s\n", disasm); +} + +static void do_disassemble(const char *triple, unsigned char *buf, int siz) { + LLVMDisasmContextRef D = LLVMCreateDisasm(triple, NULL, 0, NULL, NULL); + char outline[1024]; + int pos; + + if (!D) { + printf("ERROR: Couldn't create disassebler for triple %s\n", triple); + return; + } + + pos = 0; + while (pos < siz) { + size_t l = LLVMDisasmInstruction(D, buf + pos, siz - pos, 0, outline, + sizeof(outline)); + if (!l) { + pprint(pos, buf + pos, 1, "\t???"); + pos++; + } else { + pprint(pos, buf + pos, l, outline); + pos += l; + } + } + + LLVMDisasmDispose(D); +} + +static void handle_line(char **tokens, int ntokens) { + unsigned char disbuf[128]; + size_t disbuflen = 0; + char *triple = tokens[0]; + int i; + + printf("triple: %s\n", triple); + + for (i = 1; i < ntokens; i++) { + disbuf[disbuflen++] = strtol(tokens[i], NULL, 16); + if (disbuflen >= sizeof(disbuf)) { + fprintf(stderr, "Warning: Too long line, truncating\n"); + break; + } + } + do_disassemble(triple, disbuf, disbuflen); +} + +int disassemble(void) { + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllDisassemblers(); + + tokenize_stdin(handle_line); + + return 0; +} diff --git a/tools/llvm-c-test/helpers.c b/tools/llvm-c-test/helpers.c new file mode 100644 index 0000000..1ea8a4f --- /dev/null +++ b/tools/llvm-c-test/helpers.c @@ -0,0 +1,40 @@ +/*===-- helpers.c - tool for testing libLLVM and llvm-c API ---------------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Helper functions *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include <stdio.h> +#include <string.h> + +#define MAX_TOKENS 512 +#define MAX_LINE_LEN 1024 + +void tokenize_stdin(void (*cb)(char **tokens, int ntokens)) { + char line[MAX_LINE_LEN]; + char *tokbuf[MAX_TOKENS]; + + while (fgets(line, sizeof(line), stdin)) { + int c = 0; + + if (line[0] == ';' || line[0] == '\n') + continue; + + while (c < MAX_TOKENS) { + tokbuf[c] = strtok(c ? NULL : line, " \n"); + if (!tokbuf[c]) + break; + c++; + } + if (c) + cb(tokbuf, c); + } +} diff --git a/tools/llvm-c-test/include-all.c b/tools/llvm-c-test/include-all.c new file mode 100644 index 0000000..17b9917 --- /dev/null +++ b/tools/llvm-c-test/include-all.c @@ -0,0 +1,33 @@ +/*===-- include-all.c - tool for testing libLLVM and llvm-c API -----------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file doesn't have any actual code. It just make sure that all *| +|* the llvm-c include files are good and doesn't generate any warnings *| +|* *| +\*===----------------------------------------------------------------------===*/ + +// FIXME: Autogenerate this list + +#include "llvm-c/Analysis.h" +#include "llvm-c/BitReader.h" +#include "llvm-c/BitWriter.h" +#include "llvm-c/Core.h" +#include "llvm-c/Disassembler.h" +#include "llvm-c/ExecutionEngine.h" +#include "llvm-c/Initialization.h" +#include "llvm-c/LinkTimeOptimizer.h" +#include "llvm-c/Linker.h" +#include "llvm-c/Object.h" +#include "llvm-c/Target.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Transforms/IPO.h" +#include "llvm-c/Transforms/PassManagerBuilder.h" +#include "llvm-c/Transforms/Scalar.h" +#include "llvm-c/Transforms/Vectorize.h" +#include "llvm-c/lto.h" diff --git a/tools/llvm-c-test/llvm-c-test.h b/tools/llvm-c-test/llvm-c-test.h new file mode 100644 index 0000000..0a25aa6 --- /dev/null +++ b/tools/llvm-c-test/llvm-c-test.h @@ -0,0 +1,37 @@ +/*===-- llvm-c-test.h - tool for testing libLLVM and llvm-c API -----------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Header file for llvm-c-test *| +|* *| +\*===----------------------------------------------------------------------===*/ +#ifndef LLVM_C_TEST_H +#define LLVM_C_TEST_H + +// helpers.c +void tokenize_stdin(void (*cb)(char **tokens, int ntokens)); + +// module.c +int module_dump(void); +int module_list_functions(void); +int module_list_globals(void); + +// calc.c +int calc(void); + +// disassemble.c +int disassemble(void); + +// object.c +int object_list_sections(void); +int object_list_symbols(void); + +// targets.c +int targets_list(void); + +#endif diff --git a/tools/llvm-c-test/main.c b/tools/llvm-c-test/main.c new file mode 100644 index 0000000..72f8b04 --- /dev/null +++ b/tools/llvm-c-test/main.c @@ -0,0 +1,73 @@ +/*===-- main.c - tool for testing libLLVM and llvm-c API ------------------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Main file for llvm-c-tests. "Parses" arguments and dispatches. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/BitReader.h" +#include "llvm-c/Core.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void print_usage(void) { + fprintf(stderr, "llvm-c-test command\n\n"); + fprintf(stderr, " Commands:\n"); + fprintf(stderr, " * --module-dump\n"); + fprintf(stderr, " Read bytecode from stdin - print disassembly\n\n"); + fprintf(stderr, " * --module-list-functions\n"); + fprintf(stderr, + " Read bytecode from stdin - list summary of functions\n\n"); + fprintf(stderr, " * --module-list-globals\n"); + fprintf(stderr, " Read bytecode from stdin - list summary of globals\n\n"); + fprintf(stderr, " * --targets-list\n"); + fprintf(stderr, " List available targets\n\n"); + fprintf(stderr, " * --object-list-sections\n"); + fprintf(stderr, " Read object file form stdin - list sections\n\n"); + fprintf(stderr, " * --object-list-symbols\n"); + fprintf(stderr, + " Read object file form stdin - list symbols (like nm)\n\n"); + fprintf(stderr, " * --disassemble\n"); + fprintf(stderr, " Read lines of triple, hex ascii machine code from stdin " + "- print disassembly\n\n"); + fprintf(stderr, " * --calc\n"); + fprintf( + stderr, + " Read lines of name, rpn from stdin - print generated module\n\n"); +} + +int main(int argc, char **argv) { + LLVMPassRegistryRef pr = LLVMGetGlobalPassRegistry(); + + LLVMInitializeCore(pr); + + if (argc == 2 && !strcmp(argv[1], "--module-dump")) { + return module_dump(); + } else if (argc == 2 && !strcmp(argv[1], "--module-list-functions")) { + return module_list_functions(); + } else if (argc == 2 && !strcmp(argv[1], "--module-list-globals")) { + return module_list_globals(); + } else if (argc == 2 && !strcmp(argv[1], "--targets-list")) { + return targets_list(); + } else if (argc == 2 && !strcmp(argv[1], "--object-list-sections")) { + return object_list_sections(); + } else if (argc == 2 && !strcmp(argv[1], "--object-list-symbols")) { + return object_list_symbols(); + } else if (argc == 2 && !strcmp(argv[1], "--disassemble")) { + return disassemble(); + } else if (argc == 2 && !strcmp(argv[1], "--calc")) { + return calc(); + } else { + print_usage(); + } + + return 1; +} diff --git a/tools/llvm-c-test/module.c b/tools/llvm-c-test/module.c new file mode 100644 index 0000000..2661fc8 --- /dev/null +++ b/tools/llvm-c-test/module.c @@ -0,0 +1,116 @@ +/*===-- module.c - tool for testing libLLVM and llvm-c API ----------------===*\ +|* *| +|* 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 --module-dump, --module-list-functions and *| +|* --module-list-globals commands in llvm-c-test. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/BitReader.h" +#include "llvm-c/Core.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static LLVMModuleRef load_module(void) { + LLVMMemoryBufferRef MB; + LLVMModuleRef M; + char *msg = NULL; + + if (LLVMCreateMemoryBufferWithSTDIN(&MB, &msg)) { + fprintf(stderr, "Error reading file: %s\n", msg); + exit(1); + } + + if (LLVMParseBitcode(MB, &M, &msg)) { + fprintf(stderr, "Error parsing bitcode: %s\n", msg); + LLVMDisposeMemoryBuffer(MB); + exit(1); + } + + LLVMDisposeMemoryBuffer(MB); + return M; +} + +int module_dump(void) { + LLVMModuleRef M = load_module(); + + char *irstr = LLVMPrintModuleToString(M); + puts(irstr); + LLVMDisposeMessage(irstr); + + LLVMDisposeModule(M); + + return 0; +} + +int module_list_functions(void) { + LLVMModuleRef M = load_module(); + LLVMValueRef f; + + f = LLVMGetFirstFunction(M); + while (f) { + if (LLVMIsDeclaration(f)) { + printf("FunctionDeclaration: %s\n", LLVMGetValueName(f)); + } else { + LLVMBasicBlockRef bb; + LLVMValueRef isn; + unsigned nisn = 0; + unsigned nbb = 0; + + printf("FunctionDefinition: %s [#bb=%u]\n", LLVMGetValueName(f), + LLVMCountBasicBlocks(f)); + + for (bb = LLVMGetFirstBasicBlock(f); bb; + bb = LLVMGetNextBasicBlock(bb)) { + nbb++; + for (isn = LLVMGetFirstInstruction(bb); isn; + isn = LLVMGetNextInstruction(isn)) { + nisn++; + if (LLVMIsACallInst(isn)) { + LLVMValueRef callee = + LLVMGetOperand(isn, LLVMGetNumOperands(isn) - 1); + printf(" calls: %s\n", LLVMGetValueName(callee)); + } + } + } + printf(" #isn: %u\n", nisn); + printf(" #bb: %u\n\n", nbb); + } + f = LLVMGetNextFunction(f); + } + + LLVMDisposeModule(M); + + return 0; +} + +int module_list_globals(void) { + LLVMModuleRef M = load_module(); + LLVMValueRef g; + + g = LLVMGetFirstGlobal(M); + while (g) { + LLVMTypeRef T = LLVMTypeOf(g); + char *s = LLVMPrintTypeToString(T); + + printf("Global%s: %s %s\n", + LLVMIsDeclaration(g) ? "Declaration" : "Definition", + LLVMGetValueName(g), s); + + LLVMDisposeMessage(s); + + g = LLVMGetNextGlobal(g); + } + + LLVMDisposeModule(M); + + return 0; +} diff --git a/tools/llvm-c-test/object.c b/tools/llvm-c-test/object.c new file mode 100644 index 0000000..2792928 --- /dev/null +++ b/tools/llvm-c-test/object.c @@ -0,0 +1,88 @@ +/*===-- object.c - tool for testing libLLVM and llvm-c API ----------------===*\ +|* *| +|* 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 --object-list-sections and --object-list-symbols *| +|* commands in llvm-c-test. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/Object.h" +#include <stdio.h> +#include <stdlib.h> + +int object_list_sections(void) { + LLVMMemoryBufferRef MB; + LLVMObjectFileRef O; + LLVMSectionIteratorRef sect; + char *msg = NULL; + + if (LLVMCreateMemoryBufferWithSTDIN(&MB, &msg)) { + fprintf(stderr, "Error reading file: %s\n", msg); + exit(1); + } + + O = LLVMCreateObjectFile(MB); + if (!O) { + fprintf(stderr, "Error reading object\n"); + exit(1); + } + + sect = LLVMGetSections(O); + while (!LLVMIsSectionIteratorAtEnd(O, sect)) { + printf("'%s': @0x%08" PRIx64 " +%" PRIu64 "\n", LLVMGetSectionName(sect), + LLVMGetSectionAddress(sect), LLVMGetSectionSize(sect)); + + LLVMMoveToNextSection(sect); + } + + LLVMDisposeSectionIterator(sect); + + LLVMDisposeObjectFile(O); + + return 0; +} + +int object_list_symbols(void) { + LLVMMemoryBufferRef MB; + LLVMObjectFileRef O; + LLVMSectionIteratorRef sect; + LLVMSymbolIteratorRef sym; + char *msg = NULL; + + if (LLVMCreateMemoryBufferWithSTDIN(&MB, &msg)) { + fprintf(stderr, "Error reading file: %s\n", msg); + exit(1); + } + + O = LLVMCreateObjectFile(MB); + if (!O) { + fprintf(stderr, "Error reading object\n"); + exit(1); + } + + sect = LLVMGetSections(O); + sym = LLVMGetSymbols(O); + while (!LLVMIsSymbolIteratorAtEnd(O, sym)) { + + LLVMMoveToContainingSection(sect, sym); + printf("%s @0x%08" PRIx64 "/0x%08" PRIx64 " +%" PRIu64 " (%s)\n", + LLVMGetSymbolName(sym), LLVMGetSymbolAddress(sym), + LLVMGetSymbolFileOffset(sym), LLVMGetSymbolSize(sym), + LLVMGetSectionName(sect)); + + LLVMMoveToNextSymbol(sym); + } + + LLVMDisposeSymbolIterator(sym); + + LLVMDisposeObjectFile(O); + + return 0; +} diff --git a/tools/llvm-c-test/targets.c b/tools/llvm-c-test/targets.c new file mode 100644 index 0000000..252c2e0 --- /dev/null +++ b/tools/llvm-c-test/targets.c @@ -0,0 +1,30 @@ +/*===-- targets.c - tool for testing libLLVM and llvm-c API ---------------===*\ +|* *| +|* 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 --targets command in llvm-c-test. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c/TargetMachine.h" +#include <stdio.h> + +int targets_list(void) { + LLVMTargetRef t; + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargets(); + + for (t = LLVMGetFirstTarget(); t; t = LLVMGetNextTarget(t)) { + printf("%s", LLVMGetTargetName(t)); + if (LLVMTargetHasJIT(t)) + printf(" (+jit)"); + printf("\n - %s\n", LLVMGetTargetDescription(t)); + } + + return 0; +} diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index 5ad58bf..c651833 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -1,37 +1,26 @@ set(LLVM_LINK_COMPONENTS support) -# We need to generate the BuildVariables.inc file containing values which are -# only defined when under certain build modes. Unfortunately, that precludes -# doing this inside CMake so we have to shell out to sed. For now, that means we -# can't expect to build llvm-config on Window.s set(BUILDVARIABLES_SRCPATH ${CMAKE_CURRENT_SOURCE_DIR}/BuildVariables.inc.in) set(BUILDVARIABLES_OBJPATH ${CMAKE_CURRENT_BINARY_DIR}/BuildVariables.inc) -set(SEDSCRIPT_OBJPATH ${CMAKE_CURRENT_BINARY_DIR}/BuildVariables.configure.sed) # Compute the substitution values for various items. get_system_libs(LLVM_SYSTEM_LIBS_LIST) foreach(l ${LLVM_SYSTEM_LIBS_LIST}) set(SYSTEM_LIBS ${SYSTEM_LIBS} "-l${l}") endforeach() -set(C_FLGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") -set(CXX_FLGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") -set(CPP_FLGS "${CMAKE_CPP_FLAGS} ${CMAKE_CPP_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +string(REPLACE ";" " " SYSTEM_LIBS "${SYSTEM_LIBS}") -add_custom_command(OUTPUT ${BUILDVARIABLES_OBJPATH} - COMMAND echo s!@LLVM_SRC_ROOT@!${LLVM_MAIN_SRC_DIR}! > ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_OBJ_ROOT@!${LLVM_BINARY_DIR}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_CPPFLAGS@!${CPP_FLGS}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_CFLAGS@!${C_FLGS}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_CXXFLAGS@!${CXX_FLGS}! >> ${SEDSCRIPT_OBJPATH} - # TODO: Use general flags for linking! not just for shared libs: - COMMAND echo s!@LLVM_LDFLAGS@!${CMAKE_SHARED_LINKER_FLAGS}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_BUILDMODE@!${CMAKE_BUILD_TYPE}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_SYSTEM_LIBS@!${SYSTEM_LIBS}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_TARGETS_BUILT@!${LLVM_TARGETS_TO_BUILD}! >> ${SEDSCRIPT_OBJPATH} - COMMAND sed -f ${SEDSCRIPT_OBJPATH} < ${BUILDVARIABLES_SRCPATH} > ${BUILDVARIABLES_OBJPATH} - VERBATIM - COMMENT "Building BuildVariables.inc include." - ) +# Use configure_file to create BuildVariables.inc. +set(LLVM_SRC_ROOT ${LLVM_MAIN_SRC_DIR}) +set(LLVM_OBJ_ROOT ${LLVM_BINARY_DIR}) +set(LLVM_CPPFLAGS "${CMAKE_CPP_FLAGS} ${CMAKE_CPP_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +set(LLVM_CFLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +set(LLVM_CXXFLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +set(LLVM_LDFLAGS ${CMAKE_SHARED_LINKER_FLAGS}) +set(LLVM_BUILDMODE ${CMAKE_BUILD_TYPE}) +set(LLVM_SYSTEM_LIBS ${SYSTEM_LIBS}) +string(REPLACE ";" " " LLVM_TARGETS_BUILT "${LLVM_TARGETS_TO_BUILD}") +configure_file(${BUILDVARIABLES_SRCPATH} ${BUILDVARIABLES_OBJPATH} @ONLY) # Add the llvm-config tool. add_llvm_tool(llvm-config 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-cov/CMakeLists.txt b/tools/llvm-cov/CMakeLists.txt index 7184b9e..67cea71 100644 --- a/tools/llvm-cov/CMakeLists.txt +++ b/tools/llvm-cov/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS instrumentation ) +set(LLVM_LINK_COMPONENTS core support ) add_llvm_tool(llvm-cov llvm-cov.cpp diff --git a/tools/llvm-cov/Makefile b/tools/llvm-cov/Makefile index 2d47ce4..efed6cc 100644 --- a/tools/llvm-cov/Makefile +++ b/tools/llvm-cov/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-cov -LINK_COMPONENTS := instrumentation +LINK_COMPONENTS := core support # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp index 7b21c5b..5f6999e 100644 --- a/tools/llvm-cov/llvm-cov.cpp +++ b/tools/llvm-cov/llvm-cov.cpp @@ -17,6 +17,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryObject.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" #include "llvm/Support/system_error.h" using namespace llvm; @@ -30,6 +31,9 @@ InputGCNO("gcno", cl::desc("<input gcno file>"), cl::init("")); static cl::opt<std::string> InputGCDA("gcda", cl::desc("<input gcda file>"), cl::init("")); +static cl::opt<std::string> +OutputFile("o", cl::desc("<output llvm-cov file>"), cl::init("-")); + //===----------------------------------------------------------------------===// int main(int argc, char **argv) { @@ -38,7 +42,12 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - cl::ParseCommandLineOptions(argc, argv, "llvm cov\n"); + cl::ParseCommandLineOptions(argc, argv, "llvm coverage tool\n"); + + std::string ErrorInfo; + raw_fd_ostream OS(OutputFile.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) + errs() << ErrorInfo << "\n"; GCOVFile GF; if (InputGCNO.empty()) @@ -49,7 +58,7 @@ int main(int argc, char **argv) { errs() << InputGCNO << ": " << ec.message() << "\n"; return 1; } - GCOVBuffer GCNO_GB(GCNO_Buff.take()); + GCOVBuffer GCNO_GB(GCNO_Buff.get()); if (!GF.read(GCNO_GB)) { errs() << "Invalid .gcno File!\n"; return 1; @@ -61,7 +70,7 @@ int main(int argc, char **argv) { errs() << InputGCDA << ": " << ec.message() << "\n"; return 1; } - GCOVBuffer GCDA_GB(GCDA_Buff.take()); + GCOVBuffer GCDA_GB(GCDA_Buff.get()); if (!GF.read(GCDA_GB)) { errs() << "Invalid .gcda File!\n"; return 1; @@ -74,5 +83,6 @@ int main(int argc, char **argv) { FileInfo FI; GF.collectLineCounts(FI); + FI.print(OS, InputGCNO, InputGCDA); return 0; } diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp index 4b11315..768b94b 100644 --- a/tools/llvm-diff/DifferenceEngine.cpp +++ b/tools/llvm-diff/DifferenceEngine.cpp @@ -195,8 +195,6 @@ class FunctionDifferenceEngine { BasicBlock::iterator LI = L->begin(), LE = L->end(); BasicBlock::iterator RI = R->begin(); - llvm::SmallVector<std::pair<Instruction*,Instruction*>, 20> TentativePairs; - do { assert(LI != LE && RI != R->end()); Instruction *LeftI = &*LI, *RightI = &*RI; @@ -316,15 +314,15 @@ class FunctionDifferenceEngine { bool Difference = false; - DenseMap<Constant*, BasicBlock*> LCases; + DenseMap<ConstantInt*,BasicBlock*> LCases; for (SwitchInst::CaseIt I = LI->case_begin(), E = LI->case_end(); I != E; ++I) - LCases[I.getCaseValueEx()] = I.getCaseSuccessor(); + LCases[I.getCaseValue()] = I.getCaseSuccessor(); for (SwitchInst::CaseIt I = RI->case_begin(), E = RI->case_end(); I != E; ++I) { - IntegersSubset CaseValue = I.getCaseValueEx(); + ConstantInt *CaseValue = I.getCaseValue(); BasicBlock *LCase = LCases[CaseValue]; if (LCase) { if (TryUnify) tryUnify(LCase, I.getCaseSuccessor()); @@ -336,7 +334,7 @@ class FunctionDifferenceEngine { } } if (!Difference) - for (DenseMap<Constant*, BasicBlock*>::iterator + for (DenseMap<ConstantInt*,BasicBlock*>::iterator I = LCases.begin(), E = LCases.end(); I != E; ++I) { if (Complain) Engine.logf("left switch has extra case %l") << I->first; diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp index 6eca1e2..f70219e 100644 --- a/tools/llvm-diff/llvm-diff.cpp +++ b/tools/llvm-diff/llvm-diff.cpp @@ -70,7 +70,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); LLVMContext Context; - + // Load both modules. Die if that fails. Module *LModule = ReadModule(Context, LeftFilename); Module *RModule = ReadModule(Context, RightFilename); diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index 067955e..87eb347 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -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..413a50b 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -62,10 +62,15 @@ DumpType("debug-dump", cl::init(DIDT_All), clEnumValN(DIDT_Aranges, "aranges", ".debug_aranges"), clEnumValN(DIDT_Info, "info", ".debug_info"), clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"), + clEnumValN(DIDT_Types, "types", ".debug_types"), 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"), + clEnumValN(DIDT_Pubtypes, "pubtypes", ".debug_pubtypes"), + clEnumValN(DIDT_GnuPubnames, "gnu_pubnames", ".debug_gnu_pubnames"), + clEnumValN(DIDT_GnuPubtypes, "gnu_pubtypes", ".debug_gnu_pubtypes"), clEnumValN(DIDT_Str, "str", ".debug_str"), clEnumValN(DIDT_StrDwo, "str.dwo", ".debug_str.dwo"), clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo", ".debug_str_offsets.dwo"), diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index 2f45b4e..dc1a410 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -53,7 +53,7 @@ static cl::list<std::string> ExtractFuncs("func", cl::desc("Specify function to extract"), cl::ZeroOrMore, cl::value_desc("function")); -// ExtractRegExpFuncs - The functions, matched via regular expression, to +// ExtractRegExpFuncs - The functions, matched via regular expression, to // extract from the module. static cl::list<std::string> ExtractRegExpFuncs("rfunc", cl::desc("Specify function(s) to extract using a " @@ -265,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-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index 01a61c6..99cca23 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -55,18 +55,11 @@ DumpAsm("d", cl::desc("Print assembly as linked"), cl::Hidden); // static inline 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 NULL; - } - 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); + + Result = ParseIRFile(FN, Err, Context); if (Result) return Result; // Load successful! Err.print(argv0, errs()); @@ -77,7 +70,7 @@ int main(int argc, char **argv) { // 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. cl::ParseCommandLineOptions(argc, argv, "llvm linker\n"); @@ -113,8 +106,7 @@ int main(int argc, char **argv) { if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite; std::string ErrorInfo; - tool_output_file Out(OutputFilename.c_str(), ErrorInfo, - 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-lto/CMakeLists.txt b/tools/llvm-lto/CMakeLists.txt new file mode 100644 index 0000000..348976c --- /dev/null +++ b/tools/llvm-lto/CMakeLists.txt @@ -0,0 +1,6 @@ +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} lto support) + +add_llvm_tool(llvm-lto + llvm-lto.cpp + ) + diff --git a/tools/llvm-prof/LLVMBuild.txt b/tools/llvm-lto/LLVMBuild.txt index d59127c..c1613a3 100644 --- a/tools/llvm-prof/LLVMBuild.txt +++ b/tools/llvm-lto/LLVMBuild.txt @@ -1,4 +1,4 @@ -;===- ./tools/llvm-prof/LLVMBuild.txt --------------------------*- Conf -*--===; +;===- ./tools/llvm-lto/LLVMBuild.txt ----------------------------*- Conf -*--===; ; ; The LLVM Compiler Infrastructure ; @@ -17,6 +17,6 @@ [component_0] type = Tool -name = llvm-prof +name = llvm-lto parent = Tools -required_libraries = Analysis BitReader +required_libraries = LTO Support all-targets diff --git a/tools/llvm-ranlib/Makefile b/tools/llvm-lto/Makefile index cca9501..f1801b4 100644 --- a/tools/llvm-ranlib/Makefile +++ b/tools/llvm-lto/Makefile @@ -1,17 +1,19 @@ -##===- tools/llvm-ranlib/Makefile --------------------------*- Makefile -*-===## -# +##===- tools/llvm-lto/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 +TOOLNAME := llvm-lto +LINK_COMPONENTS := lto ipo scalaropts linker bitreader bitwriter mcdisassembler support target vectorize all-targets # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 +NO_INSTALL := 1 + include $(LEVEL)/Makefile.common diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp new file mode 100644 index 0000000..0fc68ae --- /dev/null +++ b/tools/llvm-lto/llvm-lto.cpp @@ -0,0 +1,187 @@ +//===-- llvm-lto: a simple command-line program to link modules with LTO --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program takes in a list of bitcode files, links them, performs link-time +// optimization, and outputs an object file. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringSet.h" +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/LTO/LTOCodeGenerator.h" +#include "llvm/LTO/LTOModule.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TargetSelect.h" + +using namespace llvm; + +static cl::opt<bool> +DisableOpt("disable-opt", cl::init(false), + cl::desc("Do not run any optimization passes")); + +static cl::opt<bool> +DisableInline("disable-inlining", cl::init(false), + cl::desc("Do not run the inliner pass")); + +static cl::opt<bool> +DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), + cl::desc("Do not run the GVN load PRE pass")); + +static cl::list<std::string> +InputFilenames(cl::Positional, cl::OneOrMore, + cl::desc("<input bitcode files>")); + +static cl::opt<std::string> +OutputFilename("o", cl::init(""), + cl::desc("Override output filename"), + cl::value_desc("filename")); + +static cl::list<std::string> +ExportedSymbols("exported-symbol", + cl::desc("Symbol to export from the resulting object file"), + cl::ZeroOrMore); + +static cl::list<std::string> +DSOSymbols("dso-symbol", + cl::desc("Symbol to put in the symtab in the resulting dso"), + cl::ZeroOrMore); + +namespace { +struct ModuleInfo { + std::vector<bool> CanBeHidden; +}; +} + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n"); + + // Initialize the configured targets. + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + // set up the TargetOptions for the machine + TargetOptions Options; + Options.LessPreciseFPMADOption = EnableFPMAD; + Options.NoFramePointerElim = DisableFPElim; + Options.AllowFPOpFusion = FuseFPOps; + Options.UnsafeFPMath = EnableUnsafeFPMath; + Options.NoInfsFPMath = EnableNoInfsFPMath; + Options.NoNaNsFPMath = EnableNoNaNsFPMath; + Options.HonorSignDependentRoundingFPMathOption = + EnableHonorSignDependentRoundingFPMath; + Options.UseSoftFloat = GenerateSoftFloatCalls; + if (FloatABIForCalls != FloatABI::Default) + Options.FloatABIType = FloatABIForCalls; + Options.NoZerosInBSS = DontPlaceZerosInBSS; + Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; + Options.DisableTailCalls = DisableTailCalls; + Options.StackAlignmentOverride = OverrideStackAlignment; + Options.TrapFuncName = TrapFuncName; + Options.PositionIndependentExecutable = EnablePIE; + Options.EnableSegmentedStacks = SegmentedStacks; + Options.UseInitArray = UseInitArray; + + unsigned BaseArg = 0; + + LTOCodeGenerator CodeGen; + + CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC); + CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF); + CodeGen.setTargetOptions(Options); + + llvm::StringSet<llvm::MallocAllocator> DSOSymbolsSet; + for (unsigned i = 0; i < DSOSymbols.size(); ++i) + DSOSymbolsSet.insert(DSOSymbols[i]); + + std::vector<std::string> KeptDSOSyms; + + for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) { + std::string error; + OwningPtr<LTOModule> Module(LTOModule::makeLTOModule(InputFilenames[i].c_str(), + Options, error)); + if (!error.empty()) { + errs() << argv[0] << ": error loading file '" << InputFilenames[i] + << "': " << error << "\n"; + return 1; + } + + + if (!CodeGen.addModule(Module.get(), error)) { + errs() << argv[0] << ": error adding file '" << InputFilenames[i] + << "': " << error << "\n"; + return 1; + } + + unsigned NumSyms = Module->getSymbolCount(); + for (unsigned I = 0; I < NumSyms; ++I) { + StringRef Name = Module->getSymbolName(I); + if (!DSOSymbolsSet.count(Name)) + continue; + lto_symbol_attributes Attrs = Module->getSymbolAttributes(I); + unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK; + if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN) + KeptDSOSyms.push_back(Name); + } + } + + // Add all the exported symbols to the table of symbols to preserve. + for (unsigned i = 0; i < ExportedSymbols.size(); ++i) + CodeGen.addMustPreserveSymbol(ExportedSymbols[i].c_str()); + + // Add all the dso symbols to the table of symbols to expose. + for (unsigned i = 0; i < KeptDSOSyms.size(); ++i) + CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str()); + + if (!OutputFilename.empty()) { + size_t len = 0; + std::string ErrorInfo; + const void *Code = CodeGen.compile(&len, DisableOpt, DisableInline, + DisableGVNLoadPRE, ErrorInfo); + if (Code == NULL) { + errs() << argv[0] + << ": error compiling the code: " << ErrorInfo << "\n"; + return 1; + } + + raw_fd_ostream FileStream(OutputFilename.c_str(), ErrorInfo, + sys::fs::F_Binary); + if (!ErrorInfo.empty()) { + errs() << argv[0] << ": error opening the file '" << OutputFilename + << "': " << ErrorInfo << "\n"; + return 1; + } + + FileStream.write(reinterpret_cast<const char *>(Code), len); + } else { + std::string ErrorInfo; + const char *OutputName = NULL; + if (!CodeGen.compile_to_file(&OutputName, DisableOpt, DisableInline, + DisableGVNLoadPRE, ErrorInfo)) { + errs() << argv[0] + << ": error compiling the code: " << ErrorInfo + << "\n"; + return 1; + } + + outs() << "Wrote native object file '" << OutputName << "'\n"; + } + + return 0; +} 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 4b01c33..7ec2bba 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -210,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; @@ -319,10 +319,10 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, tool_output_file *Out) static int AssembleInput(const char *ProgName, const Target *TheTarget, SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str, - MCAsmInfo &MAI, MCSubtargetInfo &STI) { + MCAsmInfo &MAI, MCSubtargetInfo &STI, MCInstrInfo &MCII) { OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, Str, MAI)); - OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(STI, *Parser)); + OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(STI, *Parser, MCII)); if (!TAP) { errs() << ProgName << ": error: this target does not support assembly parsing.\n"; @@ -379,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) @@ -432,7 +432,7 @@ int main(int argc, char **argv) { MCAsmBackend *MAB = 0; if (ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); - MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); + MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); } bool UseCFI = !DisableCFI; Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true, @@ -446,7 +446,7 @@ int main(int argc, char **argv) { } else { assert(FileType == OFT_ObjectFile && "Invalid file type!"); MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); - MCAsmBackend *MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); + MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB, FOS, CE, RelaxAll, NoExecStack)); @@ -459,7 +459,7 @@ int main(int argc, char **argv) { Res = AsLexInput(SrcMgr, *MAI, Out.get()); break; case AC_Assemble: - Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI); + Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI, *MCII); break; case AC_MDisassemble: assert(IP && "Expected assembly output"); 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..8449c29 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -17,10 +17,13 @@ //===----------------------------------------------------------------------===// #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/COFF.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -121,6 +124,8 @@ namespace { bool MultipleFiles = false; + bool HadError = false; + std::string ToolName; } @@ -132,6 +137,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; @@ -300,6 +306,226 @@ static void DumpSymbolNamesFromModule(Module *M) { SortAndPrintSymbolList(); } +template <class ELFT> +error_code getSymbolNMTypeChar(ELFObjectFile<ELFT> &Obj, symbol_iterator I, + char &Result) { + typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr; + + DataRefImpl Symb = I->getRawDataRefImpl(); + const Elf_Sym *ESym = Obj.getSymbol(Symb); + const ELFFile<ELFT> &EF = *Obj.getELFFile(); + const Elf_Shdr *ESec = EF.getSection(ESym); + + char ret = '?'; + + if (ESec) { + switch (ESec->sh_type) { + case ELF::SHT_PROGBITS: + case ELF::SHT_DYNAMIC: + switch (ESec->sh_flags) { + case(ELF::SHF_ALLOC | ELF::SHF_EXECINSTR) : + ret = 't'; + break; + case(ELF::SHF_ALLOC | ELF::SHF_WRITE) : + ret = 'd'; + break; + case ELF::SHF_ALLOC: + case(ELF::SHF_ALLOC | ELF::SHF_MERGE) : + case(ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS) : + ret = 'r'; + break; + } + break; + case ELF::SHT_NOBITS: + ret = 'b'; + } + } + + switch (EF.getSymbolTableIndex(ESym)) { + case ELF::SHN_UNDEF: + if (ret == '?') + ret = 'U'; + break; + case ELF::SHN_ABS: + ret = 'a'; + break; + case ELF::SHN_COMMON: + ret = 'c'; + break; + } + + switch (ESym->getBinding()) { + case ELF::STB_GLOBAL: + ret = ::toupper(ret); + break; + case ELF::STB_WEAK: + if (EF.getSymbolTableIndex(ESym) == ELF::SHN_UNDEF) + ret = 'w'; + else if (ESym->getType() == ELF::STT_OBJECT) + ret = 'V'; + else + ret = 'W'; + } + + if (ret == '?' && ESym->getType() == ELF::STT_SECTION) { + StringRef Name; + error_code EC = I->getName(Name); + if (EC) + return EC; + Result = StringSwitch<char>(Name) + .StartsWith(".debug", 'N') + .StartsWith(".note", 'n') + .Default('?'); + return object_error::success; + } + + Result = ret; + return object_error::success; +} + +static error_code getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I, + char &Result) { + const coff_symbol *symb = Obj.getCOFFSymbol(I); + StringRef name; + if (error_code ec = I->getName(name)) + return ec; + char ret = StringSwitch<char>(name) + .StartsWith(".debug", 'N') + .StartsWith(".sxdata", 'N') + .Default('?'); + + if (ret != '?') { + Result = ret; + return object_error::success; + } + + uint32_t Characteristics = 0; + if (symb->SectionNumber > 0) { + section_iterator SecI = Obj.end_sections(); + if (error_code ec = I->getSection(SecI)) + return ec; + const coff_section *Section = Obj.getCOFFSection(SecI); + Characteristics = Section->Characteristics; + } + + switch (symb->SectionNumber) { + case COFF::IMAGE_SYM_UNDEFINED: + // Check storage classes. + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) { + Result = 'w'; + return object_error::success; // Don't do ::toupper. + } else if (symb->Value != 0) // Check for common symbols. + ret = 'c'; + else + ret = 'u'; + break; + case COFF::IMAGE_SYM_ABSOLUTE: + ret = 'a'; + break; + case COFF::IMAGE_SYM_DEBUG: + ret = 'n'; + break; + default: + // Check section type. + if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) + ret = 't'; + else if (Characteristics & COFF::IMAGE_SCN_MEM_READ && + ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. + ret = 'r'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) + ret = 'd'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) + ret = 'b'; + else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) + ret = 'i'; + + // Check for section symbol. + else if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC && + symb->Value == 0) + ret = 's'; + } + + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) + ret = ::toupper(static_cast<unsigned char>(ret)); + + Result = ret; + return object_error::success; +} + +static uint8_t getNType(MachOObjectFile &Obj, DataRefImpl Symb) { + if (Obj.is64Bit()) { + MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb); + return STE.n_type; + } + MachO::nlist STE = Obj.getSymbolTableEntry(Symb); + return STE.n_type; +} + +static error_code getSymbolNMTypeChar(MachOObjectFile &Obj, symbol_iterator I, + char &Res) { + DataRefImpl Symb = I->getRawDataRefImpl(); + uint8_t NType = getNType(Obj, Symb); + + char Char; + switch (NType & MachO::N_TYPE) { + case MachO::N_UNDF: + Char = 'u'; + break; + case MachO::N_ABS: + Char = 's'; + break; + case MachO::N_SECT: { + section_iterator Sec = Obj.end_sections(); + Obj.getSymbolSection(Symb, Sec); + DataRefImpl Ref = Sec->getRawDataRefImpl(); + StringRef SectionName; + Obj.getSectionName(Ref, SectionName); + StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref); + if (SegmentName == "__TEXT" && SectionName == "__text") + Char = 't'; + else + Char = 's'; + } break; + default: + Char = '?'; + break; + } + + if (NType & (MachO::N_EXT | MachO::N_PEXT)) + Char = toupper(static_cast<unsigned char>(Char)); + Res = Char; + return object_error::success; +} + +static char getNMTypeChar(ObjectFile *Obj, symbol_iterator I) { + char Res = '?'; + if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*COFF, I, Res)); + return Res; + } + if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*MachO, I, Res)); + return Res; + } + + if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*ELF, I, Res)); + return Res; + } + if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*ELF, I, Res)); + return Res; + } + if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*ELF, I, Res)); + return Res; + } + ELF64BEObjectFile *ELF = cast<ELF64BEObjectFile>(Obj); + error(getSymbolNMTypeChar(*ELF, I, Res)); + return Res; +} + static void DumpSymbolNamesFromObject(ObjectFile *obj) { error_code ec; symbol_iterator ibegin = obj->begin_symbols(); @@ -322,7 +548,7 @@ static void DumpSymbolNamesFromObject(ObjectFile *obj) { } if (PrintAddress) if (error(i->getAddress(s.Address))) break; - if (error(i->getNMTypeChar(s.TypeChar))) break; + s.TypeChar = getNMTypeChar(obj, i); if (error(i->getName(s.Name))) break; SymbolList.push_back(s); } @@ -362,21 +588,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 +632,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 +658,7 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { } else { errs() << ToolName << ": " << Filename << ": " << "unrecognizable file type\n"; + HadError = true; return; } } @@ -425,7 +672,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 +693,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..5f0bcbb 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; } } @@ -227,9 +227,51 @@ static void printCOFFSymbolAddress(llvm::raw_ostream &Out, Out << format(" + 0x%04x", Disp); } +// Prints import tables. The import table is a table containing the list of +// DLL name and symbol names which will be linked by the loader. +static void printImportTables(const COFFObjectFile *Obj) { + outs() << "The Import Tables:\n"; + error_code ec; + for (import_directory_iterator i = Obj->import_directory_begin(), + e = Obj->import_directory_end(); + i != e; i = i.increment(ec)) { + if (ec) + return; + + const import_directory_table_entry *Dir; + StringRef Name; + if (i->getImportTableEntry(Dir)) return; + if (i->getName(Name)) return; + + outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n", + static_cast<uint32_t>(Dir->ImportLookupTableRVA), + static_cast<uint32_t>(Dir->TimeDateStamp), + static_cast<uint32_t>(Dir->ForwarderChain), + static_cast<uint32_t>(Dir->NameRVA), + static_cast<uint32_t>(Dir->ImportAddressTableRVA)); + outs() << " DLL Name: " << Name << "\n"; + outs() << " Hint/Ord Name\n"; + const import_lookup_table_entry32 *entry; + if (i->getImportLookupEntry(entry)) + return; + for (; entry->data; ++entry) { + if (entry->isOrdinal()) { + outs() << format(" % 6d\n", entry->getOrdinal()); + continue; + } + uint16_t Hint; + StringRef Name; + if (Obj->getHintName(entry->getHintNameRVA(), Hint, Name)) + return; + outs() << format(" % 6d ", Hint) << Name << "\n"; + } + outs() << "\n"; + } +} + 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 " @@ -353,3 +395,7 @@ void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { } } } + +void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) { + printImportTables(dyn_cast<const COFFObjectFile>(Obj)); +} diff --git a/tools/llvm-objdump/ELFDump.cpp b/tools/llvm-objdump/ELFDump.cpp index bd15231..9c091a4 100644 --- a/tools/llvm-objdump/ELFDump.cpp +++ b/tools/llvm-objdump/ELFDump.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm-objdump.h" -#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -21,10 +21,8 @@ using namespace llvm; using namespace llvm::object; -template<class ELFT> -void printProgramHeaders( - const ELFObjectFile<ELFT> *o) { - typedef ELFObjectFile<ELFT> ELFO; +template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) { + typedef ELFFile<ELFT> ELFO; outs() << "Program Header:\n"; for (typename ELFO::Elf_Phdr_Iter pi = o->begin_program_headers(), pe = o->end_program_headers(); @@ -63,7 +61,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 +77,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)) - printProgramHeaders(ELFObj); + if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) + printProgramHeaders(ELFObj->getELFFile()); // Big-endian 32-bit - if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(Obj)) - printProgramHeaders(ELFObj); + if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) + printProgramHeaders(ELFObj->getELFFile()); // Little-endian 64-bit - if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(Obj)) - printProgramHeaders(ELFObj); + if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) + printProgramHeaders(ELFObj->getELFFile()); // Big-endian 64-bit - if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj = - dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(Obj)) - printProgramHeaders(ELFObj); + if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) + printProgramHeaders(ELFObj->getELFFile()); } 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 6797e2d..86923fd 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" @@ -44,10 +44,6 @@ 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> @@ -91,105 +87,73 @@ struct SymbolSorter { } }; -// Print additional information about an address, if available. -static void DumpAddress(uint64_t Address, ArrayRef<SectionRef> Sections, - const MachOObjectFile *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::DICE_KIND_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::DICE_KIND_JUMP_TABLE8: + Value = bytes[0]; + outs() << "\t.byte " << Value << "\t@ KIND_JUMP_TABLE8"; + break; + case MachO::DICE_KIND_JUMP_TABLE16: + Value = bytes[1] << 8 | + bytes[0]; + outs() << "\t.short " << Value << "\t@ KIND_JUMP_TABLE16"; + break; + case MachO::DICE_KIND_JUMP_TABLE32: + 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, +getSectionsAndSymbols(const MachO::mach_header Header, MachOObjectFile *MachOObj, std::vector<SectionRef> &Sections, std::vector<SymbolRef> &Symbols, - SmallVectorImpl<uint64_t> &FoundFns) { + 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)) @@ -205,17 +169,27 @@ getSectionsAndSymbols(const macho::Header Header, MachOObjectFile::LoadCommandInfo Command = MachOObj->getFirstLoadCommandInfo(); + bool BaseSegmentAddressSet = false; for (unsigned i = 0; ; ++i) { - if (Command.C.Type == macho::LCT_FunctionStarts) { + if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) { // We found a function starts segment, parse the addresses for later // consumption. - macho::LinkeditDataLoadCommand LLC = + MachO::linkedit_data_command LLC = MachOObj->getLinkeditDataLoadCommand(Command); - MachOObj->ReadULEB128s(LLC.DataOffset, FoundFns); + MachOObj->ReadULEB128s(LLC.dataoff, FoundFns); + } + else if (Command.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command SLC = + MachOObj->getSegmentLoadCommand(Command); + StringRef SegName = SLC.segname; + if(!BaseSegmentAddressSet && SegName != "__PAGEZERO") { + BaseSegmentAddressSet = true; + BaseSegmentAddress = SLC.vmaddr; + } } - if (i == Header.NumLoadCommands - 1) + if (i == Header.ncmds - 1) break; else Command = MachOObj->getNextLoadCommandInfo(Command); @@ -251,11 +225,12 @@ static void DisassembleInputMachO2(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, @@ -269,19 +244,41 @@ static void DisassembleInputMachO2(StringRef Filename, outs() << '\n' << Filename << ":\n\n"; - macho::Header Header = MachOOF->getHeader(); + MachO::mach_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, 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::MH_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 @@ -296,7 +293,7 @@ static void DisassembleInputMachO2(StringRef Filename, // 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; } @@ -307,31 +304,24 @@ static void DisassembleInputMachO2(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 DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl(); + StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR); if (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 Bytes; Sections[SectIdx].getContents(Bytes); StringRefMemoryObject memoryObject(Bytes); @@ -347,10 +337,9 @@ static void DisassembleInputMachO2(StringRef Filename, 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()); @@ -402,52 +391,56 @@ static void DisassembleInputMachO2(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); @@ -470,142 +463,5 @@ static void DisassembleInputMachO2(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, MachOOF, 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, MachOOF, 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 247b90f..9bc092e 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -17,17 +17,26 @@ //===----------------------------------------------------------------------===// #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/MCModuleYAML.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" @@ -53,6 +62,7 @@ #include <algorithm> #include <cctype> #include <cstring> + using namespace llvm; using namespace object; @@ -123,6 +133,20 @@ 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")); + +// FIXME: Does it make sense to have a dedicated tool for yaml cfg output? +static cl::opt<std::string> +YAMLCFG("yaml-cfg", + cl::desc("Create a CFG and write it as a YAML MCModule."), + cl::value_desc("yaml output file")); + static StringRef ToolName; bool llvm::error(error_code ec) { @@ -137,8 +161,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 +185,52 @@ static const Target *getTarget(const ObjectFile *Obj = NULL) { return TheTarget; } -void llvm::StringRefMemoryObject::anchor() { } +// Write a graphviz file for the CFG inside an MCFunction. +// FIXME: Use GraphWriter +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"; @@ -207,6 +281,107 @@ 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 || !YAMLCFG.empty()) { + 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"; + } + } + } + if (CFG) { + 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; + } + } + if (!YAMLCFG.empty()) { + std::string Error; + raw_fd_ostream YAMLOut(YAMLCFG.c_str(), Error); + if (!Error.empty()) { + errs() << ToolName << ": warning: " << Error << '\n'; + return; + } + mcmodule2yaml(YAMLOut, *Mod, *MII, *MRI); + } + } + + error_code ec; for (section_iterator i = Obj->begin_sections(), e = Obj->end_sections(); @@ -272,53 +447,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; @@ -352,14 +487,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"; @@ -632,6 +770,14 @@ static void PrintUnwindInfo(const ObjectFile *o) { } } +static void printPrivateFileHeader(const ObjectFile *o) { + if (o->isELF()) { + printELFFileHeader(o); + } else if (o->isCOFF()) { + printCOFFFileHeader(o); + } +} + static void DumpObject(const ObjectFile *o) { outs() << '\n'; outs() << o->getFileName() @@ -649,8 +795,8 @@ static void DumpObject(const ObjectFile *o) { PrintSymbolTable(o); if (UnwindInfo) PrintUnwindInfo(o); - if (PrivateHeaders && o->isELF()) - printELFFileHeader(o); + if (PrivateHeaders) + printPrivateFileHeader(o); } /// @brief Dump each object file in \a a; diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index ca7bced..b716a26 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 { @@ -34,24 +34,8 @@ void DumpBytes(StringRef bytes); void DisassembleInputMachO(StringRef Filename); void printCOFFUnwindInfo(const object::COFFObjectFile* o); void printELFFileHeader(const object::ObjectFile *o); +void printCOFFFileHeader(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; - } -}; - -} +} // end namespace llvm #endif diff --git a/tools/llvm-prof/CMakeLists.txt b/tools/llvm-prof/CMakeLists.txt deleted file mode 100644 index 442112b..0000000 --- a/tools/llvm-prof/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(LLVM_LINK_COMPONENTS bitreader analysis) - -add_llvm_tool(llvm-prof - llvm-prof.cpp - ) diff --git a/tools/llvm-prof/Makefile b/tools/llvm-prof/Makefile deleted file mode 100644 index f829786..0000000 --- a/tools/llvm-prof/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -##===- tools/llvm-prof/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-prof -LINK_COMPONENTS := bitreader analysis - -# This tool has no plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 - -include $(LEVEL)/Makefile.common diff --git a/tools/llvm-prof/llvm-prof.cpp b/tools/llvm-prof/llvm-prof.cpp deleted file mode 100644 index b2c3f06..0000000 --- a/tools/llvm-prof/llvm-prof.cpp +++ /dev/null @@ -1,293 +0,0 @@ -//===- llvm-prof.cpp - Read in and process llvmprof.out data files --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This tools is meant for use with the various LLVM profiling instrumentation -// passes. It reads in the data file produced by executing an instrumented -// program, and outputs a nice report. -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/LLVMContext.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/ProfileInfo.h" -#include "llvm/Analysis/ProfileInfoLoader.h" -#include "llvm/Assembly/AssemblyAnnotationWriter.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Module.h" -#include "llvm/PassManager.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" -#include <algorithm> -#include <iomanip> -#include <map> -#include <set> - -using namespace llvm; - -namespace { - cl::opt<std::string> - BitcodeFile(cl::Positional, cl::desc("<program bitcode file>"), - cl::Required); - - cl::opt<std::string> - ProfileDataFile(cl::Positional, cl::desc("<llvmprof.out file>"), - cl::Optional, cl::init("llvmprof.out")); - - cl::opt<bool> - PrintAnnotatedLLVM("annotated-llvm", - cl::desc("Print LLVM code with frequency annotations")); - cl::alias PrintAnnotated2("A", cl::desc("Alias for --annotated-llvm"), - cl::aliasopt(PrintAnnotatedLLVM)); - cl::opt<bool> - PrintAllCode("print-all-code", - cl::desc("Print annotated code for the entire program")); -} - -// PairSecondSort - A sorting predicate to sort by the second element of a pair. -template<class T> -struct PairSecondSortReverse - : public std::binary_function<std::pair<T, double>, - std::pair<T, double>, bool> { - bool operator()(const std::pair<T, double> &LHS, - const std::pair<T, double> &RHS) const { - return LHS.second > RHS.second; - } -}; - -static double ignoreMissing(double w) { - if (w == ProfileInfo::MissingValue) return 0; - return w; -} - -namespace { - class ProfileAnnotator : public AssemblyAnnotationWriter { - ProfileInfo &PI; - public: - ProfileAnnotator(ProfileInfo &pi) : PI(pi) {} - - virtual void emitFunctionAnnot(const Function *F, - formatted_raw_ostream &OS) { - double w = PI.getExecutionCount(F); - if (w != ProfileInfo::MissingValue) { - OS << ";;; %" << F->getName() << " called "<<(unsigned)w - <<" times.\n;;;\n"; - } - } - virtual void emitBasicBlockStartAnnot(const BasicBlock *BB, - formatted_raw_ostream &OS) { - double w = PI.getExecutionCount(BB); - if (w != ProfileInfo::MissingValue) { - if (w != 0) { - OS << "\t;;; Basic block executed " << (unsigned)w << " times.\n"; - } else { - OS << "\t;;; Never executed!\n"; - } - } - } - - virtual void emitBasicBlockEndAnnot(const BasicBlock *BB, - formatted_raw_ostream &OS) { - // Figure out how many times each successor executed. - std::vector<std::pair<ProfileInfo::Edge, double> > SuccCounts; - - const TerminatorInst *TI = BB->getTerminator(); - for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; ++s) { - BasicBlock* Succ = TI->getSuccessor(s); - double w = ignoreMissing(PI.getEdgeWeight(std::make_pair(BB, Succ))); - if (w != 0) - SuccCounts.push_back(std::make_pair(std::make_pair(BB, Succ), w)); - } - if (!SuccCounts.empty()) { - OS << "\t;;; Out-edge counts:"; - for (unsigned i = 0, e = SuccCounts.size(); i != e; ++i) - OS << " [" << (SuccCounts[i]).second << " -> " - << (SuccCounts[i]).first.second->getName() << "]"; - OS << "\n"; - } - } - }; -} - -namespace { - /// ProfileInfoPrinterPass - Helper pass to dump the profile information for - /// a module. - // - // FIXME: This should move elsewhere. - class ProfileInfoPrinterPass : public ModulePass { - ProfileInfoLoader &PIL; - public: - static char ID; // Class identification, replacement for typeinfo. - explicit ProfileInfoPrinterPass(ProfileInfoLoader &_PIL) - : ModulePass(ID), PIL(_PIL) {} - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - AU.addRequired<ProfileInfo>(); - } - - bool runOnModule(Module &M); - }; -} - -char ProfileInfoPrinterPass::ID = 0; - -bool ProfileInfoPrinterPass::runOnModule(Module &M) { - ProfileInfo &PI = getAnalysis<ProfileInfo>(); - std::map<const Function *, unsigned> FuncFreqs; - std::map<const BasicBlock*, unsigned> BlockFreqs; - std::map<ProfileInfo::Edge, unsigned> EdgeFreqs; - - // Output a report. Eventually, there will be multiple reports selectable on - // the command line, for now, just keep things simple. - - // Emit the most frequent function table... - std::vector<std::pair<Function*, double> > FunctionCounts; - std::vector<std::pair<BasicBlock*, double> > Counts; - for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) { - if (FI->isDeclaration()) continue; - double w = ignoreMissing(PI.getExecutionCount(FI)); - FunctionCounts.push_back(std::make_pair(FI, w)); - for (Function::iterator BB = FI->begin(), BBE = FI->end(); - BB != BBE; ++BB) { - double w = ignoreMissing(PI.getExecutionCount(BB)); - Counts.push_back(std::make_pair(BB, w)); - } - } - - // Sort by the frequency, backwards. - sort(FunctionCounts.begin(), FunctionCounts.end(), - PairSecondSortReverse<Function*>()); - - double TotalExecutions = 0; - for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) - TotalExecutions += FunctionCounts[i].second; - - outs() << "===" << std::string(73, '-') << "===\n" - << "LLVM profiling output for execution"; - if (PIL.getNumExecutions() != 1) outs() << "s"; - outs() << ":\n"; - - for (unsigned i = 0, e = PIL.getNumExecutions(); i != e; ++i) { - outs() << " "; - if (e != 1) outs() << i+1 << ". "; - outs() << PIL.getExecution(i) << "\n"; - } - - outs() << "\n===" << std::string(73, '-') << "===\n"; - outs() << "Function execution frequencies:\n\n"; - - // Print out the function frequencies... - outs() << " ## Frequency\n"; - for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) { - if (FunctionCounts[i].second == 0) { - outs() << "\n NOTE: " << e-i << " function" - << (e-i-1 ? "s were" : " was") << " never executed!\n"; - break; - } - - outs() << format("%3d", i+1) << ". " - << format("%5.2g", FunctionCounts[i].second) << "/" - << format("%g", TotalExecutions) << " " - << FunctionCounts[i].first->getName() << "\n"; - } - - std::set<Function*> FunctionsToPrint; - - TotalExecutions = 0; - for (unsigned i = 0, e = Counts.size(); i != e; ++i) - TotalExecutions += Counts[i].second; - - // Sort by the frequency, backwards. - sort(Counts.begin(), Counts.end(), - PairSecondSortReverse<BasicBlock*>()); - - outs() << "\n===" << std::string(73, '-') << "===\n"; - outs() << "Top 20 most frequently executed basic blocks:\n\n"; - - // Print out the function frequencies... - outs() <<" ## %% \tFrequency\n"; - unsigned BlocksToPrint = Counts.size(); - if (BlocksToPrint > 20) BlocksToPrint = 20; - for (unsigned i = 0; i != BlocksToPrint; ++i) { - if (Counts[i].second == 0) break; - Function *F = Counts[i].first->getParent(); - outs() << format("%3d", i+1) << ". " - << format("%5g", Counts[i].second/(double)TotalExecutions*100)<<"% " - << format("%5.0f", Counts[i].second) << "/" - << format("%g", TotalExecutions) << "\t" - << F->getName() << "() - " - << Counts[i].first->getName() << "\n"; - FunctionsToPrint.insert(F); - } - - if (PrintAnnotatedLLVM || PrintAllCode) { - outs() << "\n===" << std::string(73, '-') << "===\n"; - outs() << "Annotated LLVM code for the module:\n\n"; - - ProfileAnnotator PA(PI); - - if (FunctionsToPrint.empty() || PrintAllCode) - M.print(outs(), &PA); - else - // Print just a subset of the functions. - for (std::set<Function*>::iterator I = FunctionsToPrint.begin(), - E = FunctionsToPrint.end(); I != E; ++I) - (*I)->print(outs(), &PA); - } - - return false; -} - -int main(int argc, char **argv) { - // 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. - - cl::ParseCommandLineOptions(argc, argv, "llvm profile dump decoder\n"); - - // Read in the bitcode file... - std::string ErrorMessage; - OwningPtr<MemoryBuffer> Buffer; - error_code ec; - Module *M = 0; - if (!(ec = MemoryBuffer::getFileOrSTDIN(BitcodeFile, Buffer))) { - M = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); - } else - ErrorMessage = ec.message(); - if (M == 0) { - errs() << argv[0] << ": " << BitcodeFile << ": " - << ErrorMessage << "\n"; - return 1; - } - - // Read the profiling information. This is redundant since we load it again - // using the standard profile info provider pass, but for now this gives us - // access to additional information not exposed via the ProfileInfo - // interface. - ProfileInfoLoader PIL(argv[0], ProfileDataFile); - - // Run the printer pass. - PassManager PassMgr; - PassMgr.add(createProfileLoaderPass(ProfileDataFile)); - PassMgr.add(new ProfileInfoPrinterPass(PIL)); - PassMgr.run(*M); - - return 0; -} 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/llvm-ranlib.cpp b/tools/llvm-ranlib/llvm-ranlib.cpp deleted file mode 100644 index e3e3bad..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; - OwningPtr<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 3d20def..90997a8 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -1,6 +1,5 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - archive bitreader object) diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 94aafa7..2f309e3 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -60,6 +60,8 @@ private: void printRelocation(section_iterator SecI, relocation_iterator RelI); + void printDataDirectory(uint32_t Index, const std::string &FieldName); + void printX64UnwindInfo(); void printRuntimeFunction( @@ -201,8 +203,7 @@ static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, return EC; if (Ofs == Offset) { - if (error_code EC = RelI->getSymbol(Sym)) - return EC; + Sym = *RelI->getSymbol(); return readobj_error::success; } } @@ -263,6 +264,31 @@ static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = { 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 ), @@ -455,15 +481,15 @@ static std::string formatSymbol(const std::vector<RelocationRef> &Rels, StringRef Sym; if (resolveSymbolName(Rels, Offset, Sym)) { - Str << format(" (0x%X)", Offset); + Str << format(" (0x%" PRIX64 ")", Offset); return Str.str(); } Str << Sym; if (Disp > 0) { - Str << format(" +0x%X (0x%X)", Disp, Offset); + Str << format(" +0x%X (0x%" PRIX64 ")", Disp, Offset); } else { - Str << format(" (0x%X)", Offset); + Str << format(" (0x%" PRIX64 ")", Offset); } return Str.str(); @@ -536,27 +562,90 @@ void COFFDumper::cacheRelocations() { } } +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() { - const coff_file_header *Header = 0; - if (error(Obj->getHeader(Header))) + // Print COFF header + const coff_file_header *COFFHeader = 0; + if (error(Obj->getCOFFHeader(COFFHeader))) return; - time_t TDS = Header->TimeDateStamp; + 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", Header->Machine, + W.printEnum ("Machine", COFFHeader->Machine, makeArrayRef(ImageFileMachineType)); - W.printNumber("SectionCount", Header->NumberOfSections); - W.printHex ("TimeDateStamp", FormattedTime, Header->TimeDateStamp); - W.printHex ("PointerToSymbolTable", Header->PointerToSymbolTable); - W.printNumber("SymbolCount", Header->NumberOfSymbols); - W.printNumber("OptionalHeaderSize", Header->SizeOfOptionalHeader); - W.printFlags ("Characteristics", Header->Characteristics, + 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() { @@ -670,14 +759,13 @@ void COFFDumper::printRelocation(section_iterator SecI, uint64_t Offset; uint64_t RelocType; SmallString<32> RelocName; - SymbolRef Symbol; StringRef SymbolName; StringRef Contents; if (error(RelI->getOffset(Offset))) return; if (error(RelI->getType(RelocType))) return; if (error(RelI->getTypeName(RelocName))) return; - if (error(RelI->getSymbol(Symbol))) return; - if (error(Symbol.getName(SymbolName))) return; + symbol_iterator Symbol = RelI->getSymbol(); + if (error(Symbol->getName(SymbolName))) return; if (error(SecI->getContents(Contents))) return; if (opts::ExpandRelocs) { @@ -836,7 +924,7 @@ void COFFDumper::printSymbol(symbol_iterator SymI) { void COFFDumper::printUnwindInfo() { const coff_file_header *Header; - if (error(Obj->getHeader(Header))) + if (error(Obj->getCOFFHeader(Header))) return; ListScope D(W, "UnwindInformation"); diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index ea1b83f..07a9083 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -18,7 +18,7 @@ #include "StreamWriter.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" @@ -28,7 +28,6 @@ using namespace llvm; using namespace llvm::object; using namespace ELF; - #define LLVM_READOBJ_ENUM_CASE(ns, enum) \ case ns::enum: return #enum; @@ -37,9 +36,8 @@ namespace { template<typename ELFT> class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFObjectFile<ELFT> *Obj, StreamWriter& Writer) - : ObjDumper(Writer) - , Obj(Obj) { } + ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) + : ObjDumper(Writer), Obj(Obj) {} virtual void printFileHeaders() LLVM_OVERRIDE; virtual void printSections() LLVM_OVERRIDE; @@ -53,65 +51,62 @@ public: virtual void printProgramHeaders() LLVM_OVERRIDE; private: - typedef ELFObjectFile<ELFT> ELFO; + typedef ELFFile<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 printSymbol(typename ELFO::Elf_Sym_Iter Symbol); - void printRelocation(section_iterator SecI, relocation_iterator RelI); + void printRelocations(const Elf_Shdr *Sec); + void printRelocation(const Elf_Shdr *Sec, typename ELFO::Elf_Rela Rel); const ELFO *Obj; }; -} // namespace +template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { + if (!Val) { + error(Val); + return Default; + } + return *Val; +} +} // namespace namespace llvm { +template <class ELFT> +static error_code createELFDumper(const ELFFile<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) { - typedef ELFType<support::little, 4, false> Little32ELF; - typedef ELFType<support::big, 4, false> Big32ELF; - typedef ELFType<support::little, 4, true > Little64ELF; - typedef ELFType<support::big, 8, true > Big64ELF; - - typedef ELFObjectFile<Little32ELF> LittleELF32Obj; - typedef ELFObjectFile<Big32ELF > BigELF32Obj; - typedef ELFObjectFile<Little64ELF> LittleELF64Obj; - typedef ELFObjectFile<Big64ELF > BigELF64Obj; - // Little-endian 32-bit - if (const LittleELF32Obj *ELFObj = dyn_cast<LittleELF32Obj>(Obj)) { - Result.reset(new ELFDumper<Little32ELF>(ELFObj, Writer)); - return readobj_error::success; - } + if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) + return createELFDumper(ELFObj->getELFFile(), Writer, Result); // Big-endian 32-bit - if (const BigELF32Obj *ELFObj = dyn_cast<BigELF32Obj>(Obj)) { - Result.reset(new ELFDumper<Big32ELF>(ELFObj, Writer)); - return readobj_error::success; - } + if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) + return createELFDumper(ELFObj->getELFFile(), Writer, Result); // Little-endian 64-bit - if (const LittleELF64Obj *ELFObj = dyn_cast<LittleELF64Obj>(Obj)) { - Result.reset(new ELFDumper<Little64ELF>(ELFObj, Writer)); - return readobj_error::success; - } + if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) + return createELFDumper(ELFObj->getELFFile(), Writer, Result); // Big-endian 64-bit - if (const BigELF64Obj *ELFObj = dyn_cast<BigELF64Obj>(Obj)) { - Result.reset(new ELFDumper<Big64ELF>(ELFObj, Writer)); - return readobj_error::success; - } + if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) + return createELFDumper(ELFObj->getELFFile(), Writer, Result); return readobj_error::unsupported_obj_file_format; } } // namespace llvm - static const EnumEntry<unsigned> ElfClass[] = { { "None", ELF::ELFCLASSNONE }, { "32-bit", ELF::ELFCLASS32 }, @@ -300,7 +295,6 @@ static const EnumEntry<unsigned> ElfMachineType[] = { 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_MICROBLAZE ), LLVM_READOBJ_ENUM_ENT(ELF, EM_CUDA ), LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEGX ), LLVM_READOBJ_ENUM_ENT(ELF, EM_CLOUDSHIELD ), @@ -311,8 +305,7 @@ static const EnumEntry<unsigned> ElfMachineType[] = { 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 ), - LLVM_READOBJ_ENUM_ENT(ELF, EM_MBLAZE ) + LLVM_READOBJ_ENUM_ENT(ELF, EM_56800EX ) }; static const EnumEntry<unsigned> ElfSymbolBindings[] = { @@ -334,7 +327,7 @@ static const EnumEntry<unsigned> ElfSymbolTypes[] = { static const char *getElfSectionType(unsigned Arch, unsigned Type) { switch (Arch) { - case Triple::arm: + case ELF::EM_ARM: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX); LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP); @@ -342,16 +335,12 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) { 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: + case ELF::EM_HEXAGON: + switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); } + case ELF::EM_X86_64: + switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); } + case ELF::EM_MIPS: + case ELF::EM_MIPS_RS3_LE: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO); LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); @@ -388,6 +377,7 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) { 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_EXCLUDE ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ), @@ -401,26 +391,41 @@ static const EnumEntry<unsigned> ElfSectionFlags[] = { 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 char *getElfSegmentType(unsigned Arch, unsigned Type) { + // Check potentially overlapped processor-specific + // program header type. + switch (Arch) { + case ELF::EM_ARM: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); + } + case ELF::EM_MIPS: + case ELF::EM_MIPS_RS3_LE: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_REGINFO); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_RTPROC); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_OPTIONS); + } + } + + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_NULL ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_LOAD ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_DYNAMIC); + LLVM_READOBJ_ENUM_CASE(ELF, PT_INTERP ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_NOTE ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_SHLIB ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_PHDR ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_TLS ); + + LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_EH_FRAME); + LLVM_READOBJ_ENUM_CASE(ELF, PT_SUNW_UNWIND); + + LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK); + LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO); + default: return ""; + } +} static const EnumEntry<unsigned> ElfSegmentFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, PF_X), @@ -428,12 +433,9 @@ static const EnumEntry<unsigned> ElfSegmentFlags[] = { 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(); + const typename ELFO::Elf_Ehdr *Header = Obj->getHeader(); { DictScope D(W, "ElfHeader"); @@ -473,24 +475,20 @@ 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; - + for (typename ELFO::Elf_Shdr_Iter SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; ++SecI) { ++SectionIndex; - const Elf_Shdr *Section = Obj->getElfSection(SecI); - StringRef Name; - if (error(SecI->getName(Name))) - Name = ""; + const Elf_Shdr *Section = &*SecI; + StringRef Name = errorOrDefault(Obj->getSectionName(Section)); 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.printHex("Type", + getElfSectionType(Obj->getHeader()->e_machine, 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); @@ -502,35 +500,23 @@ void ELFDumper<ELFT>::printSections() { if (opts::SectionRelocations) { ListScope D(W, "Relocations"); - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - - printRelocation(SecI, RelI); - } + printRelocations(Section); } 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); + for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; ++SymI) { + if (Obj->getSection(&*SymI) == Section) + printSymbol(SymI); } } if (opts::SectionData) { - StringRef Data; - if (error(SecI->getContents(Data))) break; - - W.printBinaryBlock("SectionData", Data); + ArrayRef<uint8_t> Data = errorOrDefault(Obj->getSectionContents(Section)); + W.printBinaryBlock("SectionData", + StringRef((const char *)Data.data(), Data.size())); } } } @@ -539,72 +525,74 @@ 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; - + for (typename ELFO::Elf_Shdr_Iter SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; ++SecI) { ++SectionNumber; - StringRef Name; - if (error(SecI->getName(Name))) + + if (SecI->sh_type != ELF::SHT_REL && SecI->sh_type != ELF::SHT_RELA) continue; - bool PrintedGroup = false; - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; + StringRef Name = errorOrDefault(Obj->getSectionName(&*SecI)); - if (!PrintedGroup) { - W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; - W.indent(); - PrintedGroup = true; - } + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); - printRelocation(SecI, RelI); - } + printRelocations(&*SecI); + + W.unindent(); + W.startLine() << "}\n"; + } +} - if (PrintedGroup) { - W.unindent(); - W.startLine() << "}\n"; +template <class ELFT> +void ELFDumper<ELFT>::printRelocations(const Elf_Shdr *Sec) { + switch (Sec->sh_type) { + case ELF::SHT_REL: + for (typename ELFO::Elf_Rel_Iter RI = Obj->begin_rel(Sec), + RE = Obj->end_rel(Sec); + RI != RE; ++RI) { + typename ELFO::Elf_Rela Rela; + Rela.r_offset = RI->r_offset; + Rela.r_info = RI->r_info; + Rela.r_addend = 0; + printRelocation(Sec, Rela); + } + break; + case ELF::SHT_RELA: + for (typename ELFO::Elf_Rela_Iter RI = Obj->begin_rela(Sec), + RE = Obj->end_rela(Sec); + RI != RE; ++RI) { + printRelocation(Sec, *RI); } + break; } } -template<class ELFT> -void ELFDumper<ELFT>::printRelocation(section_iterator Sec, - relocation_iterator RelI) { - uint64_t Offset; - uint64_t RelocType; +template <class ELFT> +void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec, + typename ELFO::Elf_Rela Rel) { SmallString<32> RelocName; - int64_t Info; + Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef SymbolName; - SymbolRef Symbol; - 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(RelI->getAdditionalInfo(Info))) return; - if (error(RelI->getSymbol(Symbol))) return; - if (error(Symbol.getName(SymbolName))) return; + std::pair<const Elf_Shdr *, const Elf_Sym *> Sym = + Obj->getRelocationSymbol(Sec, &Rel); + if (Sym.first) + SymbolName = errorOrDefault(Obj->getSymbolName(Sym.first, Sym.second)); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); - W.printHex("Offset", Offset); - W.printNumber("Type", RelocName, RelocType); + W.printHex("Offset", Rel.r_offset); + W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); - W.printHex("Info", Info); + W.printHex("Addend", Rel.r_addend); } else { raw_ostream& OS = W.startLine(); - OS << W.hex(Offset) + OS << W.hex(Rel.r_offset) << " " << RelocName << " " << (SymbolName.size() > 0 ? SymbolName : "-") - << " " << W.hex(Info) + << " " << W.hex(Rel.r_addend) << "\n"; } } @@ -612,12 +600,9 @@ void ELFDumper<ELFT>::printRelocation(section_iterator Sec, 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; - + for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; ++SymI) { printSymbol(SymI); } } @@ -626,41 +611,27 @@ 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); + for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_dynamic_symbols(), + SymE = Obj->end_dynamic_symbols(); + SymI != SymE; ++SymI) { + printSymbol(SymI); } } -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); - +template <class ELFT> +void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { + StringRef SymbolName = errorOrDefault(Obj->getSymbolName(Symbol)); + const Elf_Shdr *Sec = Obj->getSection(&*Symbol); + StringRef SectionName = Sec ? errorOrDefault(Obj->getSectionName(Sec)) : ""; std::string FullSymbolName(SymbolName); - if (IsDynamic) { - StringRef Version; + if (Symbol.isDynamic()) { bool IsDefault; - if (error(Obj->getSymbolVersion(*SymI, Version, IsDefault))) - return; - if (!Version.empty()) { + ErrorOr<StringRef> Version = Obj->getSymbolVersion(0, &*Symbol, IsDefault); + if (Version) { FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += Version; - } + FullSymbolName += *Version; + } else + error(Version); } DictScope D(W, "Symbol"); @@ -712,15 +683,25 @@ static const char *getTypeString(uint64_t Type) { LLVM_READOBJ_TYPE_CASE(SYMENT); LLVM_READOBJ_TYPE_CASE(SYMTAB); LLVM_READOBJ_TYPE_CASE(TEXTREL); + LLVM_READOBJ_TYPE_CASE(VERNEED); + LLVM_READOBJ_TYPE_CASE(VERNEEDNUM); + LLVM_READOBJ_TYPE_CASE(VERSYM); + LLVM_READOBJ_TYPE_CASE(MIPS_RLD_VERSION); + LLVM_READOBJ_TYPE_CASE(MIPS_FLAGS); + LLVM_READOBJ_TYPE_CASE(MIPS_BASE_ADDRESS); + LLVM_READOBJ_TYPE_CASE(MIPS_LOCAL_GOTNO); + LLVM_READOBJ_TYPE_CASE(MIPS_SYMTABNO); + LLVM_READOBJ_TYPE_CASE(MIPS_UNREFEXTNO); + LLVM_READOBJ_TYPE_CASE(MIPS_GOTSYM); 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) { +template <class ELFT> +static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, + bool Is64, raw_ostream &OS) { switch (Type) { case DT_PLTREL: if (Value == DT_REL) { @@ -744,9 +725,21 @@ static void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: case DT_DEBUG: + case DT_VERNEED: + case DT_VERSYM: case DT_NULL: + case DT_MIPS_FLAGS: + case DT_MIPS_BASE_ADDRESS: + case DT_MIPS_GOTSYM: OS << format("0x%" PRIX64, Value); break; + case DT_VERNEEDNUM: + case DT_MIPS_RLD_VERSION: + case DT_MIPS_LOCAL_GOTNO: + case DT_MIPS_SYMTABNO: + case DT_MIPS_UNREFEXTNO: + OS << Value; + break; case DT_PLTRELSZ: case DT_RELASZ: case DT_RELAENT: @@ -760,12 +753,14 @@ static void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, OS << Value << " (bytes)"; break; case DT_NEEDED: - OS << "SharedLibrary (" - << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + OS << "SharedLibrary (" << O->getDynamicString(Value) << ")"; break; case DT_SONAME: - OS << "LibrarySoname (" - << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + OS << "LibrarySoname (" << O->getDynamicString(Value) << ")"; + break; + case DT_RPATH: + case DT_RUNPATH: + OS << O->getDynamicString(Value); break; } } @@ -777,9 +772,8 @@ void ELFDumper<ELFT>::printUnwindInfo() { 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); + typedef typename ELFO::Elf_Dyn_Iter EDI; + EDI Start = Obj->begin_dynamic_table(), End = Obj->end_dynamic_table(true); if (Start == End) return; @@ -788,7 +782,7 @@ void ELFDumper<ELFT>::printDynamicTable() { raw_ostream &OS = W.getOStream(); W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; - bool Is64 = Obj->getBytesInAddress() == 8; + bool Is64 = ELFT::Is64Bits; W.startLine() << " Tag" << (Is64 ? " " : " ") << "Type" @@ -805,38 +799,23 @@ void ELFDumper<ELFT>::printDynamicTable() { 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; + typedef std::vector<StringRef> 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); - } + for (typename ELFO::Elf_Dyn_Iter DynI = Obj->begin_dynamic_table(), + DynE = Obj->end_dynamic_table(); + DynI != DynE; ++DynI) + if (DynI->d_tag == ELF::DT_NEEDED) + Libs.push_back(Obj->getDynamicString(DynI->d_un.d_val)); - std::sort(Libs.begin(), Libs.end(), &compareLibraryName); + std::stable_sort(Libs.begin(), Libs.end()); - for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); - I != E; ++I) { - StringRef Path; - I->getPath(Path); - outs() << " " << Path << "\n"; + for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); I != E; ++I) { + outs() << " " << *I << "\n"; } } @@ -848,7 +827,9 @@ void ELFDumper<ELFT>::printProgramHeaders() { PE = Obj->end_program_headers(); PI != PE; ++PI) { DictScope P(W, "ProgramHeader"); - W.printEnum ("Type", PI->p_type, makeArrayRef(ElfSegmentTypes)); + W.printHex ("Type", + getElfSegmentType(Obj->getHeader()->e_machine, PI->p_type), + PI->p_type); W.printHex ("Offset", PI->p_offset); W.printHex ("VirtualAddress", PI->p_vaddr); W.printHex ("PhysicalAddress", PI->p_paddr); diff --git a/tools/llvm-readobj/LLVMBuild.txt b/tools/llvm-readobj/LLVMBuild.txt index 813c12b..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 = all-targets Archive BitReader Object +required_libraries = all-targets BitReader Object diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp index 31dc5ce..b97166b 100644 --- a/tools/llvm-readobj/MachODumper.cpp +++ b/tools/llvm-readobj/MachODumper.cpp @@ -166,28 +166,28 @@ 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; + MachO::section Sect = Obj->getSection(Sec); + Section.Address = Sect.addr; + Section.Size = Sect.size; + Section.Offset = Sect.offset; + Section.Alignment = Sect.align; + Section.RelocationTableOffset = Sect.reloff; + Section.NumRelocationTableEntries = Sect.nreloc; + 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; + MachO::section_64 Sect = Obj->getSection64(Sec); + Section.Address = Sect.addr; + Section.Size = Sect.size; + Section.Offset = Sect.offset; + Section.Alignment = Sect.align; + Section.RelocationTableOffset = Sect.reloff; + Section.NumRelocationTableEntries = Sect.nreloc; + Section.Flags = Sect.flags; + Section.Reserved1 = Sect.reserved1; + Section.Reserved2 = Sect.reserved2; } @@ -195,20 +195,20 @@ 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; + MachO::nlist Entry = Obj->getSymbolTableEntry(DRI); + Symbol.StringIndex = Entry.n_strx; + Symbol.Type = Entry.n_type; + Symbol.SectionIndex = Entry.n_sect; + Symbol.Flags = Entry.n_desc; + Symbol.Value = Entry.n_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; + MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI); + Symbol.StringIndex = Entry.n_strx; + Symbol.Type = Entry.n_type; + Symbol.SectionIndex = Entry.n_sect; + Symbol.Flags = Entry.n_desc; + Symbol.Value = Entry.n_value; } void MachODumper::printFileHeaders() { @@ -341,16 +341,15 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, uint64_t Offset; SmallString<32> RelocName; StringRef SymbolName; - SymbolRef Symbol; if (error(RelI->getOffset(Offset))) return; if (error(RelI->getTypeName(RelocName))) return; - if (error(RelI->getSymbol(Symbol))) return; - if (symbol_iterator(Symbol) != Obj->end_symbols() && - error(Symbol.getName(SymbolName))) + 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); + MachO::any_relocation_info RE = Obj->getRelocation(DR); bool IsScattered = Obj->isRelocationScattered(RE); if (opts::ExpandRelocs) { @@ -399,8 +398,6 @@ void MachODumper::printDynamicSymbols() { } void MachODumper::printSymbol(symbol_iterator SymI) { - error_code EC; - StringRef SymbolName; if (SymI->getName(SymbolName)) SymbolName = ""; diff --git a/tools/llvm-readobj/Makefile b/tools/llvm-readobj/Makefile index 1bb7295..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 all-targets +LINK_COMPONENTS := bitreader object all-targets # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 2e95b6b..f84a72f 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -130,12 +130,15 @@ namespace opts { cl::desc("Expand each shown relocation to multiple lines")); } // namespace opts +static int ReturnValue = EXIT_SUCCESS; + namespace llvm { bool error(error_code EC) { if (!EC) return false; + ReturnValue = EXIT_FAILURE; outs() << "\nError reading file: " << EC.message() << ".\n"; outs().flush(); return true; @@ -157,6 +160,7 @@ static void reportError(StringRef Input, error_code EC) { errs() << Input << ": " << EC.message() << "\n"; errs().flush(); + ReturnValue = EXIT_FAILURE; } static void reportError(StringRef Input, StringRef Message) { @@ -164,6 +168,7 @@ static void reportError(StringRef Input, StringRef Message) { Input = "<stdin>"; errs() << Input << ": " << Message << "\n"; + ReturnValue = EXIT_FAILURE; } /// @brief Creates an format-specific object file dumper. @@ -289,5 +294,5 @@ int main(int argc, const char *argv[]) { std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), dumpInput); - return 0; + return ReturnValue; } diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index ead541a..531595e 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -22,6 +22,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Memory.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; @@ -60,16 +62,17 @@ public: SmallVector<sys::MemoryBlock, 16> DataMemory; uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); + unsigned SectionID, StringRef SectionName); uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly); + unsigned SectionID, StringRef SectionName, + bool IsReadOnly); virtual void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true) { 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 @@ -80,7 +83,8 @@ public: uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID) { + unsigned SectionID, + StringRef SectionName) { sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); FunctionMemory.push_back(MB); return (uint8_t*)MB.base(); @@ -89,6 +93,7 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName, bool IsReadOnly) { sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); DataMemory.push_back(MB); @@ -124,8 +129,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 +185,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 +209,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 +219,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()); @@ -236,6 +241,9 @@ static int executeInput() { } int main(int argc, char **argv) { + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + ProgramName = argv[0]; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. diff --git a/tools/llvm-shlib/Makefile b/tools/llvm-shlib/Makefile index 6d6c6e9..92f3132 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), DragonFly 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), DragonFly 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/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp index fbda1b7..fd10baf 100644 --- a/tools/llvm-stress/llvm-stress.cpp +++ b/tools/llvm-stress/llvm-stress.cpp @@ -52,6 +52,7 @@ static cl::opt<bool> GenPPCFP128("generate-ppc-fp128", static cl::opt<bool> GenX86MMX("generate-x86-mmx", cl::desc("Generate X86 MMX floating-point values"), cl::init(false)); +namespace { /// A utility class to provide a pseudo-random number generator which is /// the same across all platforms. This is somewhat close to the libc /// implementation. Note: This is not a cryptographically secure pseudorandom @@ -607,7 +608,9 @@ struct CmpModifier: public Modifier { } }; -void FillFunction(Function *F, Random &R) { +} // end anonymous namespace + +static void FillFunction(Function *F, Random &R) { // Create a legal entry block. BasicBlock *BB = BasicBlock::Create(F->getContext(), "BB", F); ReturnInst::Create(F->getContext(), BB); @@ -654,7 +657,7 @@ void FillFunction(Function *F, Random &R) { SM->ActN(5); // Throw in a few stores. } -void IntroduceControlFlow(Function *F, Random &R) { +static void IntroduceControlFlow(Function *F, Random &R) { std::vector<Instruction*> BoolInst; for (BasicBlock::iterator it = F->begin()->begin(), e = F->begin()->end(); it != e; ++it) { @@ -702,7 +705,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 29d91a0..320ab3f 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -13,11 +13,17 @@ #include "LLVMSymbolize.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Config/config.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include <sstream> +#include <stdlib.h> namespace llvm { namespace symbolize { @@ -63,15 +69,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)); } } @@ -80,15 +94,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; } @@ -178,8 +195,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 = DemangleGlobalName(Name); } } std::stringstream ss; @@ -189,23 +206,12 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, void LLVMSymbolizer::flush() { DeleteContainerSeconds(Modules); + DeleteContainerPointers(ParsedBinariesAndObjects); + BinaryForPath.clear(); + ObjectFileForArch.clear(); } -// 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()); -} - -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); @@ -214,36 +220,176 @@ static std::string getDarwinDWARFResourceForModule(const std::string &Path) { return ResourceName.str(); } +static bool checkFileCRC(StringRef Path, uint32_t CRCHash) { + OwningPtr<MemoryBuffer> MB; + if (MemoryBuffer::getFileOrSTDIN(Path, MB)) + return false; + return !zlib::isAvailable() || CRCHash == zlib::crc32(MB->getBuffer()); +} + +static bool findDebugBinary(const std::string &OrigPath, + const std::string &DebuglinkName, uint32_t CRCHash, + std::string &Result) { + std::string OrigRealPath = OrigPath; +#if defined(HAVE_REALPATH) + if (char *RP = realpath(OrigPath.c_str(), NULL)) { + OrigRealPath = RP; + free(RP); + } +#endif + SmallString<16> OrigDir(OrigRealPath); + llvm::sys::path::remove_filename(OrigDir); + SmallString<16> DebugPath = OrigDir; + // Try /path/to/original_binary/debuglink_name + llvm::sys::path::append(DebugPath, DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = DebugPath.str(); + return true; + } + // Try /path/to/original_binary/.debug/debuglink_name + DebugPath = OrigRealPath; + llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = DebugPath.str(); + return true; + } + // Try /usr/lib/debug/path/to/original_binary/debuglink_name + DebugPath = "/usr/lib/debug"; + llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), + DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = DebugPath.str(); + return true; + } + return false; +} + +static bool getGNUDebuglinkContents(const Binary *Bin, std::string &DebugName, + uint32_t &CRCHash) { + const ObjectFile *Obj = dyn_cast<ObjectFile>(Bin); + if (!Obj) + return false; + error_code EC; + for (section_iterator I = Obj->begin_sections(), E = Obj->end_sections(); + I != E; I.increment(EC)) { + StringRef Name; + I->getName(Name); + Name = Name.substr(Name.find_first_not_of("._")); + if (Name == "gnu_debuglink") { + StringRef Data; + I->getContents(Data); + DataExtractor DE(Data, Obj->isLittleEndian(), 0); + uint32_t Offset = 0; + if (const char *DebugNameStr = DE.getCStr(&Offset)) { + // 4-byte align the offset. + Offset = (Offset + 3) & ~0x3; + if (DE.isValidOffsetForDataOfSize(Offset, 4)) { + DebugName = DebugNameStr; + CRCHash = DE.getU32(&Offset); + return true; + } + } + break; + } + } + return false; +} + +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); + } + } + // Try to locate the debug binary using .gnu_debuglink section. + if (DbgBin == 0) { + std::string DebuglinkName; + uint32_t CRCHash; + std::string DebugBinaryPath; + if (getGNUDebuglinkContents(Bin, DebuglinkName, CRCHash) && + findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath) && + !error(createBinary(DebugBinaryPath, ParsedDbgBinary))) { + DbgBin = ParsedDbgBinary.take(); + ParsedBinariesAndObjects.push_back(DbgBin); + } + } + } + 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; @@ -258,7 +404,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(); @@ -275,18 +422,25 @@ 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 } +std::string LLVMSymbolizer::DemangleGlobalName(const std::string &Name) { + // We can spoil names of globals with C linkage, so use an heuristic + // approach to check if the name should be demangled. + return (Name.substr(0, 2) == "_Z") ? DemangleName(Name) : Name; +} + } // namespace symbolize } // namespace llvm diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h index 0733dfb..eb2666a 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). @@ -51,13 +59,31 @@ public: 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; + static std::string DemangleGlobalName(const std::string &Name); + // 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[]; }; @@ -77,14 +103,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 0cafffa..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 "; @@ -102,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/CMakeLists.txt b/tools/lto/CMakeLists.txt index 5820b14..957a9f0 100644 --- a/tools/lto/CMakeLists.txt +++ b/tools/lto/CMakeLists.txt @@ -1,22 +1,38 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - ipo scalaropts linker bitreader bitwriter mcdisassembler vectorize) + ipo scalaropts linker bitreader bitwriter lto mcdisassembler vectorize) add_definitions( -DLLVM_VERSION_INFO=\"${PACKAGE_VERSION}\" ) set(SOURCES - LTOCodeGenerator.cpp LTODisassembler.cpp lto.cpp - LTOModule.cpp ) -set(LLVM_COMMON_DEPENDS intrinsics_gen) +if( NOT CYGWIN AND LLVM_ENABLE_PIC ) + if ( WIN32 ) + # Create .def file containing a list of exports preceeded by + # 'EXPORTS'. The file "lto.exports" already contains the list, so we + # massage it into the correct format here to create "lto.exports.def". + set(LTO_EXPORTS_DEF ${CMAKE_CURRENT_BINARY_DIR}/lto.exports.def) + set(LTO_EXPORTS_DEF_TEMP ${LTO_EXPORTS_DEF}.txt) + file(READ "lto.exports" exports_list) + file(WRITE ${LTO_EXPORTS_DEF_TEMP} "LIBRARY LTO\n") + file(APPEND ${LTO_EXPORTS_DEF_TEMP} "EXPORTS\n") + file(APPEND ${LTO_EXPORTS_DEF_TEMP} ${exports_list}) + + # Copy the file only if it has changed. + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${LTO_EXPORTS_DEF_TEMP} ${LTO_EXPORTS_DEF}) + + set(SHARED_LIB_SOURCES ${SOURCES} ${LTO_EXPORTS_DEF}) + else() + set(SHARED_LIB_SOURCES ${SOURCES}) + endif() -if( NOT WIN32 AND LLVM_ENABLE_PIC ) set(bsl ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS ON) - add_llvm_library(LTO ${SOURCES}) + add_llvm_library(LTO ${SHARED_LIB_SOURCES}) set_property(TARGET LTO PROPERTY OUTPUT_NAME "LTO") set(BUILD_SHARED_LIBS ${bsl}) set(LTO_STATIC_TARGET_NAME LTO_static) @@ -28,3 +44,8 @@ if( NOT BUILD_SHARED_LIBS ) add_llvm_library(${LTO_STATIC_TARGET_NAME} ${SOURCES}) set_property(TARGET ${LTO_STATIC_TARGET_NAME} PROPERTY OUTPUT_NAME "LTO") endif() + +if( NOT CYGWIN ) + install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/lto.h + DESTINATION include/llvm-c) +endif() diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp deleted file mode 100644 index 57e7a2d..0000000 --- a/tools/lto/LTOCodeGenerator.cpp +++ /dev/null @@ -1,432 +0,0 @@ -//===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===// -// -// 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 Link Time Optimization library. This library is -// intended to be used by linker to optimize code at link time. -// -//===----------------------------------------------------------------------===// - -#include "LTOCodeGenerator.h" -#include "LTOModule.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Config/config.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/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/FormattedStream.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/system_error.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#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> -DisableOpt("disable-opt", cl::init(false), - cl::desc("Do not run any optimization passes")); - -static cl::opt<bool> -DisableInline("disable-inlining", cl::init(false), - cl::desc("Do not run the inliner pass")); - -static cl::opt<bool> -DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), - cl::desc("Do not run the GVN load PRE pass")); - -const char* LTOCodeGenerator::getVersionString() { -#ifdef LLVM_VERSION_INFO - return PACKAGE_NAME " version " PACKAGE_VERSION ", " LLVM_VERSION_INFO; -#else - return PACKAGE_NAME " version " PACKAGE_VERSION; -#endif -} - -LTOCodeGenerator::LTOCodeGenerator() - : _context(getGlobalContext()), - _linker(new Module("ld-temp.o", _context)), _target(NULL), - _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false), - _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC), - _nativeObjectFile(NULL) { - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmPrinters(); -} - -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); -} - -bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& 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; -} - -bool LTOCodeGenerator::setDebugInfo(lto_debug_model debug, - std::string& errMsg) { - switch (debug) { - case LTO_DEBUG_MODEL_NONE: - _emitDwarfDebugInfo = false; - return false; - - case LTO_DEBUG_MODEL_DWARF: - _emitDwarfDebugInfo = true; - return false; - } - llvm_unreachable("Unknown debug format!"); -} - -bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model, - std::string& errMsg) { - 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; - } - llvm_unreachable("Unknown PIC model!"); -} - -bool LTOCodeGenerator::writeMergedModules(const char *path, - std::string &errMsg) { - if (determineTarget(errMsg)) - return true; - - // mark which symbols can not be internalized - applyScopeRestrictions(); - - // create output file - std::string ErrInfo; - tool_output_file Out(path, ErrInfo, - raw_fd_ostream::F_Binary); - if (!ErrInfo.empty()) { - errMsg = "could not open bitcode file for writing: "; - errMsg += path; - return true; - } - - // write bitcode to it - WriteBitcodeToFile(_linker.getModule(), Out.os()); - Out.os().close(); - - if (Out.os().has_error()) { - errMsg = "could not write bitcode file: "; - errMsg += path; - Out.os().clear_error(); - return true; - } - - Out.keep(); - return false; -} - -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; - } - sys::RemoveFileOnSignal(uniqueObjPath); - - // generate object file - bool genResult = false; - tool_output_file objFile(uniqueObjPath.c_str(), errMsg); - if (!errMsg.empty()) { - uniqueObjPath.eraseFromDisk(); - return true; - } - - genResult = this->generateObjectFile(objFile.os(), errMsg); - objFile.os().close(); - if (objFile.os().has_error()) { - objFile.os().clear_error(); - uniqueObjPath.eraseFromDisk(); - return true; - } - - objFile.keep(); - if (genResult) { - uniqueObjPath.eraseFromDisk(); - return true; - } - - _nativeObjectPath = uniqueObjPath.str(); - *name = _nativeObjectPath.c_str(); - return false; -} - -const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { - const char *name; - if (compile_to_file(&name, errMsg)) - return NULL; - - // remove old buffer if compile() called twice - delete _nativeObjectFile; - - // read .o file into memory buffer - OwningPtr<MemoryBuffer> BuffPtr; - if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) { - errMsg = ec.message(); - sys::Path(_nativeObjectPath).eraseFromDisk(); - return NULL; - } - _nativeObjectFile = BuffPtr.take(); - - // remove temp files - sys::Path(_nativeObjectPath).eraseFromDisk(); - - // return buffer, unless error - if (_nativeObjectFile == NULL) - return NULL; - *length = _nativeObjectFile->getBufferSize(); - return _nativeObjectFile->getBufferStart(); -} - -bool LTOCodeGenerator::determineTarget(std::string& errMsg) { - if (_target != NULL) - return false; - - std::string TripleStr = _linker.getModule()->getTargetTriple(); - if (TripleStr.empty()) - TripleStr = sys::getDefaultTargetTriple(); - llvm::Triple Triple(TripleStr); - - // create target machine from info for merged modules - const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); - if (march == NULL) - return true; - - // The relocation model is actually a static member of TargetMachine and - // needs to be set before the TargetMachine is instantiated. - Reloc::Model RelocModel = Reloc::Default; - switch (_codeModel) { - case LTO_CODEGEN_PIC_MODEL_STATIC: - RelocModel = Reloc::Static; - break; - case LTO_CODEGEN_PIC_MODEL_DYNAMIC: - RelocModel = Reloc::PIC_; - break; - case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: - RelocModel = Reloc::DynamicNoPIC; - break; - } - - // construct LTOModule, hand over ownership of module and target - SubtargetFeatures Features; - Features.getDefaultSubtargetFeatures(Triple); - std::string FeatureStr = Features.getString(); - // Set a default CPU for Darwin triples. - if (_mCpu.empty() && Triple.isOSDarwin()) { - if (Triple.getArch() == llvm::Triple::x86_64) - _mCpu = "core2"; - else if (Triple.getArch() == llvm::Triple::x86) - _mCpu = "yonah"; - } - TargetOptions Options; - LTOModule::getTargetOptions(Options); - _target = march->createTargetMachine(TripleStr, _mCpu, FeatureStr, Options, - RelocModel, CodeModel::Default, - CodeGenOpt::Aggressive); - return false; -} - -void LTOCodeGenerator:: -applyRestriction(GlobalValue &GV, - std::vector<const char*> &mustPreserveList, - SmallPtrSet<GlobalValue*, 8> &asmUsed, - Mangler &mangler) { - SmallString<64> Buffer; - mangler.getNameWithPrefix(Buffer, &GV, false); - - if (GV.isDeclaration()) - return; - if (_mustPreserveSymbols.count(Buffer)) - mustPreserveList.push_back(GV.getName().data()); - if (_asmUndefinedRefs.count(Buffer)) - asmUsed.insert(&GV); -} - -static void findUsedValues(GlobalVariable *LLVMUsed, - SmallPtrSet<GlobalValue*, 8> &UsedValues) { - if (LLVMUsed == 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())) - UsedValues.insert(GV); -} - -void LTOCodeGenerator::applyScopeRestrictions() { - if (_scopeRestrictionsDone) return; - Module *mergedModule = _linker.getModule(); - - // Start off with a verification pass. - PassManager passes; - passes.add(createVerifierPass()); - - // mark which symbols can not be internalized - MCContext Context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(),NULL); - Mangler mangler(Context, *_target->getDataLayout()); - std::vector<const char*> mustPreserveList; - SmallPtrSet<GlobalValue*, 8> asmUsed; - - for (Module::iterator f = mergedModule->begin(), - e = mergedModule->end(); f != e; ++f) - applyRestriction(*f, mustPreserveList, asmUsed, mangler); - for (Module::global_iterator v = mergedModule->global_begin(), - e = mergedModule->global_end(); v != e; ++v) - applyRestriction(*v, mustPreserveList, asmUsed, mangler); - for (Module::alias_iterator a = mergedModule->alias_begin(), - e = mergedModule->alias_end(); a != e; ++a) - applyRestriction(*a, mustPreserveList, asmUsed, mangler); - - GlobalVariable *LLVMCompilerUsed = - mergedModule->getGlobalVariable("llvm.compiler.used"); - findUsedValues(LLVMCompilerUsed, asmUsed); - if (LLVMCompilerUsed) - LLVMCompilerUsed->eraseFromParent(); - - 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"); - } - - passes.add(createInternalizePass(mustPreserveList)); - - // apply scope restrictions - passes.run(*mergedModule); - - _scopeRestrictionsDone = true; -} - -/// Optimize merged modules using various IPO passes -bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, - std::string &errMsg) { - if (this->determineTarget(errMsg)) - return true; - - 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 - this->applyScopeRestrictions(); - - // Instantiate the pass manager to organize the passes. - PassManager passes; - - // Start off with a verification pass. - passes.add(createVerifierPass()); - - // Add an appropriate DataLayout instance for this module... - passes.add(new DataLayout(*_target->getDataLayout())); - _target->addAnalysisPasses(passes); - - // 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) { - PassManagerBuilder().populateLTOPassManager(passes, - /*Internalize=*/false, - !DisableInline, - DisableGVNLoadPRE); - } - - // Make sure everything is still good. - passes.add(createVerifierPass()); - - PassManager codeGenPasses; - - codeGenPasses.add(new DataLayout(*_target->getDataLayout())); - _target->addAnalysisPasses(codeGenPasses); - - 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; - } - - // Run our queue of passes all at once now, efficiently. - passes.run(*mergedModule); - - // Run the code generator, and write assembly file - codeGenPasses.run(*mergedModule); - - return false; // success -} - -/// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging -/// LTO problems. -void LTOCodeGenerator::setCodeGenDebugOptions(const char *options) { - for (std::pair<StringRef, StringRef> o = getToken(options); - !o.first.empty(); o = getToken(o.second)) { - // ParseCommandLineOptions() expects argv[0] to be program name. Lazily add - // that. - if (_codegenOptions.empty()) - _codegenOptions.push_back(strdup("libLTO")); - _codegenOptions.push_back(strdup(o.first.str().c_str())); - } -} diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h deleted file mode 100644 index a4ade9f..0000000 --- a/tools/lto/LTOCodeGenerator.h +++ /dev/null @@ -1,83 +0,0 @@ -//===-LTOCodeGenerator.h - LLVM Link Time Optimizer -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the LTOCodeGenerator class. -// -//===----------------------------------------------------------------------===// - -#ifndef LTO_CODE_GENERATOR_H -#define LTO_CODE_GENERATOR_H - -#include "llvm-c/lto.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/Linker.h" -#include <string> -#include <vector> - -namespace llvm { - class LLVMContext; - class GlobalValue; - class Mangler; - class MemoryBuffer; - class TargetMachine; - class raw_ostream; -} - -//===----------------------------------------------------------------------===// -/// LTOCodeGenerator - C++ class which implements the opaque lto_code_gen_t -/// type. -/// -struct LTOCodeGenerator { - static const char *getVersionString(); - - LTOCodeGenerator(); - ~LTOCodeGenerator(); - - bool addModule(struct LTOModule*, std::string &errMsg); - bool setDebugInfo(lto_debug_model, std::string &errMsg); - bool setCodePICModel(lto_codegen_model, std::string &errMsg); - - void setCpu(const char* mCpu) { _mCpu = mCpu; } - - void addMustPreserveSymbol(const char* sym) { - _mustPreserveSymbols[sym] = 1; - } - - bool writeMergedModules(const char *path, std::string &errMsg); - bool compile_to_file(const char **name, std::string &errMsg); - const void *compile(size_t *length, std::string &errMsg); - void setCodeGenDebugOptions(const char *opts); - -private: - bool generateObjectFile(llvm::raw_ostream &out, std::string &errMsg); - void applyScopeRestrictions(); - void applyRestriction(llvm::GlobalValue &GV, - std::vector<const char*> &mustPreserveList, - llvm::SmallPtrSet<llvm::GlobalValue*, 8> &asmUsed, - llvm::Mangler &mangler); - bool determineTarget(std::string &errMsg); - - typedef llvm::StringMap<uint8_t> StringSet; - - llvm::LLVMContext& _context; - llvm::Linker _linker; - llvm::TargetMachine* _target; - bool _emitDwarfDebugInfo; - bool _scopeRestrictionsDone; - lto_codegen_model _codeModel; - StringSet _mustPreserveSymbols; - StringSet _asmUndefinedRefs; - llvm::MemoryBuffer* _nativeObjectFile; - std::vector<char*> _codegenOptions; - std::string _mCpu; - std::string _nativeObjectPath; -}; - -#endif // LTO_CODE_GENERATOR_H diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp deleted file mode 100644 index d805f49..0000000 --- a/tools/lto/LTOModule.cpp +++ /dev/null @@ -1,918 +0,0 @@ -//===-- LTOModule.cpp - LLVM Link Time Optimizer --------------------------===// -// -// 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 Link Time Optimization library. This library is -// intended to be used by linker to optimize code at link time. -// -//===----------------------------------------------------------------------===// - -#include "LTOModule.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCTargetAsmParser.h" -#include "llvm/MC/SubtargetFeature.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/system_error.h" -#include "llvm/Target/TargetRegisterInfo.h" -using namespace llvm; - -static cl::opt<bool> -EnableFPMAD("enable-fp-mad", - cl::desc("Enable less precise MAD instructions to be generated"), - cl::init(false)); - -static cl::opt<bool> -DisableFPElim("disable-fp-elim", - cl::desc("Disable frame pointer elimination optimization"), - 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)); - -static cl::opt<bool> -EnableNoInfsFPMath("enable-no-infs-fp-math", - cl::desc("Enable FP math optimizations that assume no +-Infs"), - cl::init(false)); - -static cl::opt<bool> -EnableNoNaNsFPMath("enable-no-nans-fp-math", - cl::desc("Enable FP math optimizations that assume no NaNs"), - cl::init(false)); - -static cl::opt<bool> -EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math", - cl::Hidden, - cl::desc("Force codegen to assume rounding mode can change dynamically"), - cl::init(false)); - -static cl::opt<bool> -GenerateSoftFloatCalls("soft-float", - cl::desc("Generate software floating point library calls"), - cl::init(false)); - -static cl::opt<llvm::FloatABI::ABIType> -FloatABIForCalls("float-abi", - cl::desc("Choose float ABI type"), - cl::init(FloatABI::Default), - cl::values( - clEnumValN(FloatABI::Default, "default", - "Target default float ABI type"), - clEnumValN(FloatABI::Soft, "soft", - "Soft float ABI (implied by -soft-float)"), - clEnumValN(FloatABI::Hard, "hard", - "Hard float ABI (uses FP registers)"), - clEnumValEnd)); - -static cl::opt<llvm::FPOpFusion::FPOpFusionMode> -FuseFPOps("fp-contract", - cl::desc("Enable aggresive formation of fused FP ops"), - cl::init(FPOpFusion::Standard), - cl::values( - clEnumValN(FPOpFusion::Fast, "fast", - "Fuse FP ops whenever profitable"), - clEnumValN(FPOpFusion::Standard, "on", - "Only fuse 'blessed' FP ops."), - clEnumValN(FPOpFusion::Strict, "off", - "Only fuse FP ops when the result won't be effected."), - clEnumValEnd)); - -static cl::opt<bool> -DontPlaceZerosInBSS("nozero-initialized-in-bss", - cl::desc("Don't place zero-initialized symbols into bss section"), - cl::init(false)); - -static cl::opt<bool> -EnableGuaranteedTailCallOpt("tailcallopt", - cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."), - cl::init(false)); - -static cl::opt<bool> -DisableTailCalls("disable-tail-calls", - cl::desc("Never emit tail calls"), - cl::init(false)); - -static cl::opt<unsigned> -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"), - cl::init("")); - -static cl::opt<bool> -EnablePIE("enable-pie", - cl::desc("Assume the creation of a position independent executable."), - cl::init(false)); - -static cl::opt<bool> -SegmentedStacks("segmented-stacks", - cl::desc("Use segmented stacks if possible."), - cl::init(false)); - -static cl::opt<bool> -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()) {} - -/// 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; -} - -bool LTOModule::isBitcodeFile(const char *path) { - return llvm::sys::Path(path).isBitcodeFile(); -} - -/// isBitcodeFileForTarget - Returns 'true' if the file (or memory contents) is -/// LLVM bitcode for the specified triple. -bool LTOModule::isBitcodeFileForTarget(const void *mem, size_t length, - const char *triplePrefix) { - MemoryBuffer *buffer = makeBuffer(mem, length); - if (!buffer) - return false; - return isTargetMatch(buffer, triplePrefix); -} - -bool LTOModule::isBitcodeFileForTarget(const char *path, - const char *triplePrefix) { - OwningPtr<MemoryBuffer> buffer; - if (MemoryBuffer::getFile(path, buffer)) - return false; - return isTargetMatch(buffer.take(), triplePrefix); -} - -/// isTargetMatch - Returns 'true' if the memory buffer is for the specified -/// target triple. -bool LTOModule::isTargetMatch(MemoryBuffer *buffer, const char *triplePrefix) { - std::string Triple = getBitcodeTargetTriple(buffer, getGlobalContext()); - delete buffer; - return strncmp(Triple.c_str(), triplePrefix, strlen(triplePrefix)) == 0; -} - -/// makeLTOModule - Create an LTOModule. N.B. These methods take ownership of -/// the buffer. -LTOModule *LTOModule::makeLTOModule(const char *path, std::string &errMsg) { - OwningPtr<MemoryBuffer> buffer; - if (error_code ec = MemoryBuffer::getFile(path, buffer)) { - errMsg = ec.message(); - return NULL; - } - return makeLTOModule(buffer.take(), errMsg); -} - -LTOModule *LTOModule::makeLTOModule(int fd, const char *path, - size_t size, std::string &errMsg) { - return makeLTOModule(fd, path, size, 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)) { - errMsg = ec.message(); - return NULL; - } - return makeLTOModule(buffer.take(), errMsg); -} - -LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, - std::string &errMsg) { - OwningPtr<MemoryBuffer> buffer(makeBuffer(mem, length)); - if (!buffer) - return NULL; - return makeLTOModule(buffer.take(), errMsg); -} - -void LTOModule::getTargetOptions(TargetOptions &Options) { - Options.LessPreciseFPMADOption = EnableFPMAD; - Options.NoFramePointerElim = DisableFPElim; - Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf; - Options.AllowFPOpFusion = FuseFPOps; - Options.UnsafeFPMath = EnableUnsafeFPMath; - Options.NoInfsFPMath = EnableNoInfsFPMath; - Options.NoNaNsFPMath = EnableNoNaNsFPMath; - Options.HonorSignDependentRoundingFPMathOption = - EnableHonorSignDependentRoundingFPMath; - Options.UseSoftFloat = GenerateSoftFloatCalls; - if (FloatABIForCalls != FloatABI::Default) - Options.FloatABIType = FloatABIForCalls; - Options.NoZerosInBSS = DontPlaceZerosInBSS; - Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; - Options.DisableTailCalls = DisableTailCalls; - Options.StackAlignmentOverride = OverrideStackAlignment; - Options.RealignStack = EnableRealignStack; - Options.TrapFuncName = TrapFuncName; - Options.PositionIndependentExecutable = EnablePIE; - Options.EnableSegmentedStacks = SegmentedStacks; - Options.UseInitArray = UseInitArray; - Options.SSPBufferSize = SSPBufferSize; -} - -LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, - std::string &errMsg) { - static bool Initialized = false; - if (!Initialized) { - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmParsers(); - Initialized = true; - } - - // parse bitcode buffer - OwningPtr<Module> m(getLazyBitcodeModule(buffer, getGlobalContext(), - &errMsg)); - if (!m) { - delete buffer; - return NULL; - } - - std::string TripleStr = m->getTargetTriple(); - if (TripleStr.empty()) - TripleStr = sys::getDefaultTargetTriple(); - llvm::Triple Triple(TripleStr); - - // find machine architecture for this module - const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); - if (!march) - return NULL; - - // construct LTOModule, hand over ownership of module and target - SubtargetFeatures Features; - Features.getDefaultSubtargetFeatures(Triple); - std::string FeatureStr = Features.getString(); - // Set a default CPU for Darwin triples. - std::string CPU; - if (Triple.isOSDarwin()) { - if (Triple.getArch() == llvm::Triple::x86_64) - CPU = "core2"; - else if (Triple.getArch() == llvm::Triple::x86) - CPU = "yonah"; - } - TargetOptions Options; - getTargetOptions(Options); - TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr, - Options); - LTOModule *Ret = new LTOModule(m.take(), target); - if (Ret->parseSymbols(errMsg)) { - delete Ret; - return NULL; - } - - return Ret; -} - -/// makeBuffer - Create a MemoryBuffer from a memory range. -MemoryBuffer *LTOModule::makeBuffer(const void *mem, size_t length) { - const char *startPtr = (const char*)mem; - return MemoryBuffer::getMemBuffer(StringRef(startPtr, length), "", false); -} - -/// objcClassNameFromExpression - Get string that the data pointer points to. -bool -LTOModule::objcClassNameFromExpression(const Constant *c, std::string &name) { - if (const ConstantExpr *ce = dyn_cast<ConstantExpr>(c)) { - Constant *op = ce->getOperand(0); - if (GlobalVariable *gvn = dyn_cast<GlobalVariable>(op)) { - Constant *cn = gvn->getInitializer(); - if (ConstantDataArray *ca = dyn_cast<ConstantDataArray>(cn)) { - if (ca->isCString()) { - name = ".objc_class_name_" + ca->getAsCString().str(); - return true; - } - } - } - } - return false; -} - -/// addObjCClass - Parse i386/ppc ObjC class data structure. -void LTOModule::addObjCClass(const GlobalVariable *clgv) { - const ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer()); - if (!c) return; - - // second slot in __OBJC,__class is pointer to superclass name - std::string superclassName; - if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { - NameAndAttributes info; - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(superclassName); - if (!entry.getValue().name) { - const char *symbolName = entry.getKey().data(); - info.name = symbolName; - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - entry.setValue(info); - } - } - - // third slot in __OBJC,__class is pointer to class name - std::string className; - if (objcClassNameFromExpression(c->getOperand(2), className)) { - StringSet::value_type &entry = _defines.GetOrCreateValue(className); - entry.setValue(1); - - NameAndAttributes info; - info.name = entry.getKey().data(); - info.attributes = LTO_SYMBOL_PERMISSIONS_DATA | - LTO_SYMBOL_DEFINITION_REGULAR | LTO_SYMBOL_SCOPE_DEFAULT; - info.isFunction = false; - info.symbol = clgv; - _symbols.push_back(info); - } -} - -/// addObjCCategory - Parse i386/ppc ObjC category data structure. -void LTOModule::addObjCCategory(const GlobalVariable *clgv) { - const ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer()); - if (!c) return; - - // second slot in __OBJC,__category is pointer to target class name - std::string targetclassName; - if (!objcClassNameFromExpression(c->getOperand(1), targetclassName)) - return; - - NameAndAttributes info; - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(targetclassName); - - if (entry.getValue().name) - return; - - const char *symbolName = entry.getKey().data(); - info.name = symbolName; - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - entry.setValue(info); -} - -/// addObjCClassRef - Parse i386/ppc ObjC class list data structure. -void LTOModule::addObjCClassRef(const GlobalVariable *clgv) { - std::string targetclassName; - if (!objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) - return; - - NameAndAttributes info; - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(targetclassName); - if (entry.getValue().name) - return; - - const char *symbolName = entry.getKey().data(); - info.name = symbolName; - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - entry.setValue(info); -} - -/// addDefinedDataSymbol - Add a data symbol as defined to the list. -void LTOModule::addDefinedDataSymbol(const GlobalValue *v) { - // Add to list of defined symbols. - addDefinedSymbol(v, false); - - if (!v->hasSection() /* || !isTargetDarwin */) - return; - - // Special case i386/ppc ObjC data structures in magic sections: - // The issue is that the old ObjC object format did some strange - // contortions to avoid real linker symbols. For instance, the - // ObjC class data structure is allocated statically in the executable - // that defines that class. That data structures contains a pointer to - // its superclass. But instead of just initializing that part of the - // struct to the address of its superclass, and letting the static and - // dynamic linkers do the rest, the runtime works by having that field - // instead point to a C-string that is the name of the superclass. - // At runtime the objc initialization updates that pointer and sets - // it to point to the actual super class. As far as the linker - // knows it is just a pointer to a string. But then someone wanted the - // linker to issue errors at build time if the superclass was not found. - // So they figured out a way in mach-o object format to use an absolute - // symbols (.objc_class_name_Foo = 0) and a floating reference - // (.reference .objc_class_name_Bar) to cause the linker into erroring when - // a class was missing. - // The following synthesizes the implicit .objc_* symbols for the linker - // from the ObjC data structures generated by the front end. - - // special case if this data blob is an ObjC class definition - if (v->getSection().compare(0, 15, "__OBJC,__class,") == 0) { - if (const GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { - addObjCClass(gv); - } - } - - // special case if this data blob is an ObjC category definition - else if (v->getSection().compare(0, 18, "__OBJC,__category,") == 0) { - if (const GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { - addObjCCategory(gv); - } - } - - // special case if this data blob is the list of referenced classes - else if (v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0) { - if (const GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { - addObjCClassRef(gv); - } - } -} - -/// addDefinedFunctionSymbol - Add a function symbol as defined to the list. -void LTOModule::addDefinedFunctionSymbol(const Function *f) { - // add to list of defined symbols - addDefinedSymbol(f, true); -} - -/// addDefinedSymbol - Add a defined symbol to the list. -void LTOModule::addDefinedSymbol(const GlobalValue *def, bool isFunction) { - // ignore all llvm.* symbols - if (def->getName().startswith("llvm.")) - return; - - // string is owned by _defines - SmallString<64> Buffer; - _mangler.getNameWithPrefix(Buffer, def, false); - - // set alignment part log2() can have rounding errors - uint32_t align = def->getAlignment(); - uint32_t attr = align ? CountTrailingZeros_32(def->getAlignment()) : 0; - - // set permissions part - if (isFunction) { - attr |= LTO_SYMBOL_PERMISSIONS_CODE; - } else { - const GlobalVariable *gv = dyn_cast<GlobalVariable>(def); - if (gv && gv->isConstant()) - attr |= LTO_SYMBOL_PERMISSIONS_RODATA; - else - attr |= LTO_SYMBOL_PERMISSIONS_DATA; - } - - // set definition part - if (def->hasWeakLinkage() || def->hasLinkOnceLinkage() || - def->hasLinkerPrivateWeakLinkage()) - attr |= LTO_SYMBOL_DEFINITION_WEAK; - else if (def->hasCommonLinkage()) - attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; - else - attr |= LTO_SYMBOL_DEFINITION_REGULAR; - - // set scope part - if (def->hasHiddenVisibility()) - attr |= LTO_SYMBOL_SCOPE_HIDDEN; - else if (def->hasProtectedVisibility()) - attr |= LTO_SYMBOL_SCOPE_PROTECTED; - else if (def->hasExternalLinkage() || def->hasWeakLinkage() || - def->hasLinkOnceLinkage() || def->hasCommonLinkage() || - def->hasLinkerPrivateWeakLinkage()) - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - else if (def->hasLinkOnceODRAutoHideLinkage()) - attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; - else - attr |= LTO_SYMBOL_SCOPE_INTERNAL; - - StringSet::value_type &entry = _defines.GetOrCreateValue(Buffer); - entry.setValue(1); - - // fill information structure - NameAndAttributes info; - StringRef Name = entry.getKey(); - info.name = Name.data(); - assert(info.name[Name.size()] == '\0'); - info.attributes = attr; - info.isFunction = isFunction; - info.symbol = def; - - // add to table of symbols - _symbols.push_back(info); -} - -/// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the -/// defined list. -void LTOModule::addAsmGlobalSymbol(const char *name, - lto_symbol_attributes scope) { - StringSet::value_type &entry = _defines.GetOrCreateValue(name); - - // only add new define if not already defined - if (entry.getValue()) - return; - - entry.setValue(1); - - NameAndAttributes &info = _undefines[entry.getKey().data()]; - - if (info.symbol == 0) { - // FIXME: This is trying to take care of module ASM like this: - // - // module asm ".zerofill __FOO, __foo, _bar_baz_qux, 0" - // - // but is gross and its mother dresses it funny. Have the ASM parser give us - // more details for this type of situation so that we're not guessing so - // much. - - // fill information structure - info.name = entry.getKey().data(); - info.attributes = - LTO_SYMBOL_PERMISSIONS_DATA | LTO_SYMBOL_DEFINITION_REGULAR | scope; - info.isFunction = false; - info.symbol = 0; - - // add to table of symbols - _symbols.push_back(info); - return; - } - - if (info.isFunction) - addDefinedFunctionSymbol(cast<Function>(info.symbol)); - else - addDefinedDataSymbol(info.symbol); - - _symbols.back().attributes &= ~LTO_SYMBOL_SCOPE_MASK; - _symbols.back().attributes |= scope; -} - -/// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to the -/// undefined list. -void LTOModule::addAsmGlobalSymbolUndef(const char *name) { - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(name); - - _asm_undefines.push_back(entry.getKey().data()); - - // we already have the symbol - if (entry.getValue().name) - return; - - uint32_t attr = LTO_SYMBOL_DEFINITION_UNDEFINED;; - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - NameAndAttributes info; - info.name = entry.getKey().data(); - info.attributes = attr; - info.isFunction = false; - info.symbol = 0; - - entry.setValue(info); -} - -/// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet to a -/// list to be resolved later. -void -LTOModule::addPotentialUndefinedSymbol(const GlobalValue *decl, bool isFunc) { - // ignore all llvm.* symbols - if (decl->getName().startswith("llvm.")) - return; - - // ignore all aliases - if (isa<GlobalAlias>(decl)) - return; - - SmallString<64> name; - _mangler.getNameWithPrefix(name, decl, false); - - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(name); - - // we already have the symbol - if (entry.getValue().name) - return; - - NameAndAttributes info; - - info.name = entry.getKey().data(); - - if (decl->hasExternalWeakLinkage()) - info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; - else - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - - info.isFunction = isFunc; - info.symbol = decl; - - entry.setValue(info); -} - -namespace { - class RecordStreamer : public MCStreamer { - public: - enum State { NeverSeen, Global, Defined, DefinedGlobal, Used }; - - private: - StringMap<State> Symbols; - - void markDefined(const MCSymbol &Symbol) { - State &S = Symbols[Symbol.getName()]; - switch (S) { - case DefinedGlobal: - case Global: - S = DefinedGlobal; - break; - case NeverSeen: - case Defined: - case Used: - S = Defined; - break; - } - } - void markGlobal(const MCSymbol &Symbol) { - State &S = Symbols[Symbol.getName()]; - switch (S) { - case DefinedGlobal: - case Defined: - S = DefinedGlobal; - break; - - case NeverSeen: - case Global: - case Used: - S = Global; - break; - } - } - void markUsed(const MCSymbol &Symbol) { - State &S = Symbols[Symbol.getName()]; - switch (S) { - case DefinedGlobal: - case Defined: - case Global: - break; - - case NeverSeen: - case Used: - S = Used; - break; - } - } - - // FIXME: mostly copied for the obj streamer. - void AddValueSymbols(const MCExpr *Value) { - switch (Value->getKind()) { - case MCExpr::Target: - // FIXME: What should we do in here? - break; - - case MCExpr::Constant: - break; - - case MCExpr::Binary: { - const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); - AddValueSymbols(BE->getLHS()); - AddValueSymbols(BE->getRHS()); - break; - } - - case MCExpr::SymbolRef: - markUsed(cast<MCSymbolRefExpr>(Value)->getSymbol()); - break; - - case MCExpr::Unary: - AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr()); - break; - } - } - - public: - typedef StringMap<State>::const_iterator const_iterator; - - const_iterator begin() { - return Symbols.begin(); - } - - const_iterator end() { - return Symbols.end(); - } - - RecordStreamer(MCContext &Context) - : MCStreamer(SK_RecordStreamer, Context) {} - - virtual void EmitInstruction(const MCInst &Inst) { - // Scan for values. - for (unsigned i = Inst.getNumOperands(); i--; ) - if (Inst.getOperand(i).isExpr()) - AddValueSymbols(Inst.getOperand(i).getExpr()); - } - virtual void EmitLabel(MCSymbol *Symbol) { - Symbol->setSection(*getCurrentSection().first); - markDefined(*Symbol); - } - virtual void EmitDebugLabel(MCSymbol *Symbol) { - EmitLabel(Symbol); - } - virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { - // FIXME: should we handle aliases? - markDefined(*Symbol); - } - virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { - if (Attribute == MCSA_Global) - markGlobal(*Symbol); - } - virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size , unsigned ByteAlignment) { - markDefined(*Symbol); - } - virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment) { - markDefined(*Symbol); - } - - virtual void EmitBundleAlignMode(unsigned AlignPow2) {} - virtual void EmitBundleLock(bool AlignToEnd) {} - virtual void EmitBundleUnlock() {} - - // Noop calls. - virtual void ChangeSection(const MCSection *Section, - const MCExpr *Subsection) {} - virtual void InitToTextSection() {} - virtual void InitSections() {} - virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} - virtual void EmitThumbFunc(MCSymbol *Func) {} - virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} - virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {} - virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {} - virtual void EmitCOFFSymbolStorageClass(int StorageClass) {} - virtual void EmitCOFFSymbolType(int Type) {} - virtual void EndCOFFSymbolDef() {} - virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, - 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 EmitULEB128Value(const MCExpr *Value) {} - virtual void EmitSLEB128Value(const MCExpr *Value) {} - virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, - unsigned ValueSize, - unsigned MaxBytesToEmit) {} - virtual void EmitCodeAlignment(unsigned ByteAlignment, - unsigned MaxBytesToEmit) {} - virtual bool EmitValueToOffset(const MCExpr *Offset, - unsigned char Value ) { return false; } - virtual void EmitFileDirective(StringRef Filename) {} - virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, - const MCSymbol *LastLabel, - const MCSymbol *Label, - unsigned PointerSize) {} - virtual void FinishImpl() {} - - static bool classof(const MCStreamer *S) { - return S->getKind() == SK_RecordStreamer; - } - }; -} // end anonymous namespace - -/// addAsmGlobalSymbols - Add global symbols from module-level ASM to the -/// defined or undefined lists. -bool LTOModule::addAsmGlobalSymbols(std::string &errMsg) { - const std::string &inlineAsm = _module->getModuleInlineAsm(); - if (inlineAsm.empty()) - return false; - - OwningPtr<RecordStreamer> Streamer(new RecordStreamer(_context)); - MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(inlineAsm); - SourceMgr SrcMgr; - SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); - OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, - _context, *Streamer, - *_target->getMCAsmInfo())); - const Target &T = _target->getTarget(); - OwningPtr<MCSubtargetInfo> - STI(T.createMCSubtargetInfo(_target->getTargetTriple(), - _target->getTargetCPU(), - _target->getTargetFeatureString())); - OwningPtr<MCTargetAsmParser> TAP(T.createMCAsmParser(*STI, *Parser.get())); - if (!TAP) { - errMsg = "target " + std::string(T.getName()) + - " does not define AsmParser."; - return true; - } - - Parser->setTargetParser(*TAP); - if (Parser->Run(false)) - return true; - - for (RecordStreamer::const_iterator i = Streamer->begin(), - e = Streamer->end(); i != e; ++i) { - StringRef Key = i->first(); - RecordStreamer::State Value = i->second; - if (Value == RecordStreamer::DefinedGlobal) - addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_DEFAULT); - else if (Value == RecordStreamer::Defined) - addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_INTERNAL); - else if (Value == RecordStreamer::Global || - Value == RecordStreamer::Used) - addAsmGlobalSymbolUndef(Key.data()); - } - - return false; -} - -/// isDeclaration - Return 'true' if the global value is a declaration. -static bool isDeclaration(const GlobalValue &V) { - if (V.hasAvailableExternallyLinkage()) - return true; - - if (V.isMaterializable()) - return false; - - return V.isDeclaration(); -} - -/// parseSymbols - Parse the symbols from the module and model-level ASM and add -/// them to either the defined or undefined lists. -bool LTOModule::parseSymbols(std::string &errMsg) { - // add functions - for (Module::iterator f = _module->begin(), e = _module->end(); f != e; ++f) { - if (isDeclaration(*f)) - addPotentialUndefinedSymbol(f, true); - else - addDefinedFunctionSymbol(f); - } - - // add data - for (Module::global_iterator v = _module->global_begin(), - e = _module->global_end(); v != e; ++v) { - if (isDeclaration(*v)) - addPotentialUndefinedSymbol(v, false); - else - addDefinedDataSymbol(v); - } - - // add asm globals - if (addAsmGlobalSymbols(errMsg)) - return true; - - // add aliases - for (Module::alias_iterator a = _module->alias_begin(), - e = _module->alias_end(); a != e; ++a) { - if (isDeclaration(*a->getAliasedGlobal())) - // Is an alias to a declaration. - addPotentialUndefinedSymbol(a, false); - else - addDefinedDataSymbol(a); - } - - // make symbols for all undefines - for (StringMap<NameAndAttributes>::iterator u =_undefines.begin(), - e = _undefines.end(); u != e; ++u) { - // If this symbol also has a definition, then don't make an undefine because - // it is a tentative definition. - if (_defines.count(u->getKey())) continue; - NameAndAttributes info = u->getValue(); - _symbols.push_back(info); - } - - return false; -} diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h deleted file mode 100644 index 83f3a7d..0000000 --- a/tools/lto/LTOModule.h +++ /dev/null @@ -1,191 +0,0 @@ -//===-LTOModule.h - LLVM Link Time Optimizer ------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the LTOModule class. -// -//===----------------------------------------------------------------------===// - -#ifndef LTO_MODULE_H -#define LTO_MODULE_H - -#include "llvm-c/lto.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/IR/Module.h" -#include "llvm/MC/MCContext.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Target/TargetMachine.h" -#include <string> -#include <vector> - -// Forward references to llvm classes. -namespace llvm { - class Function; - class GlobalValue; - class MemoryBuffer; - class TargetOptions; - class Value; -} - -//===----------------------------------------------------------------------===// -/// LTOModule - C++ class which implements the opaque lto_module_t type. -/// -struct LTOModule { -private: - typedef llvm::StringMap<uint8_t> StringSet; - - struct NameAndAttributes { - const char *name; - uint32_t attributes; - bool isFunction; - const llvm::GlobalValue *symbol; - }; - - llvm::OwningPtr<llvm::Module> _module; - llvm::OwningPtr<llvm::TargetMachine> _target; - std::vector<NameAndAttributes> _symbols; - - // _defines and _undefines only needed to disambiguate tentative definitions - StringSet _defines; - llvm::StringMap<NameAndAttributes> _undefines; - std::vector<const char*> _asm_undefines; - llvm::MCContext _context; - - // Use mangler to add GlobalPrefix to names to match linker names. - llvm::Mangler _mangler; - - LTOModule(llvm::Module *m, llvm::TargetMachine *t); -public: - /// isBitcodeFile - Returns 'true' if the file or memory contents is LLVM - /// bitcode. - static bool isBitcodeFile(const void *mem, size_t length); - static bool isBitcodeFile(const char *path); - - /// isBitcodeFileForTarget - Returns 'true' if the file or memory contents - /// is LLVM bitcode for the specified triple. - static bool isBitcodeFileForTarget(const void *mem, - size_t length, - const char *triplePrefix); - static bool isBitcodeFileForTarget(const char *path, - const char *triplePrefix); - - /// makeLTOModule - Create an LTOModule. N.B. These methods take ownership - /// of the buffer. - static LTOModule *makeLTOModule(const char* path, - std::string &errMsg); - 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); - static LTOModule *makeLTOModule(const void *mem, size_t length, - std::string &errMsg); - - /// getTargetTriple - Return the Module's target triple. - const char *getTargetTriple() { - return _module->getTargetTriple().c_str(); - } - - /// setTargetTriple - Set the Module's target triple. - void setTargetTriple(const char *triple) { - _module->setTargetTriple(triple); - } - - /// getSymbolCount - Get the number of symbols - uint32_t getSymbolCount() { - return _symbols.size(); - } - - /// getSymbolAttributes - Get the attributes for a symbol at the specified - /// index. - lto_symbol_attributes getSymbolAttributes(uint32_t index) { - if (index < _symbols.size()) - return lto_symbol_attributes(_symbols[index].attributes); - return lto_symbol_attributes(0); - } - - /// getSymbolName - Get the name of the symbol at the specified index. - const char *getSymbolName(uint32_t index) { - if (index < _symbols.size()) - return _symbols[index].name; - return NULL; - } - - /// getLLVVMModule - Return the Module. - llvm::Module *getLLVVMModule() { return _module.get(); } - - /// getAsmUndefinedRefs - - const std::vector<const char*> &getAsmUndefinedRefs() { - return _asm_undefines; - } - - /// getTargetOptions - Fill the TargetOptions object with the options - /// specified on the command line. - static void getTargetOptions(llvm::TargetOptions &Options); - -private: - /// parseSymbols - Parse the symbols from the module and model-level ASM and - /// add them to either the defined or undefined lists. - bool parseSymbols(std::string &errMsg); - - /// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet - /// to a list to be resolved later. - void addPotentialUndefinedSymbol(const llvm::GlobalValue *dcl, bool isFunc); - - /// addDefinedSymbol - Add a defined symbol to the list. - void addDefinedSymbol(const llvm::GlobalValue *def, bool isFunction); - - /// addDefinedFunctionSymbol - Add a function symbol as defined to the list. - void addDefinedFunctionSymbol(const llvm::Function *f); - - /// addDefinedDataSymbol - Add a data symbol as defined to the list. - void addDefinedDataSymbol(const llvm::GlobalValue *v); - - /// addAsmGlobalSymbols - Add global symbols from module-level ASM to the - /// defined or undefined lists. - bool addAsmGlobalSymbols(std::string &errMsg); - - /// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the - /// defined list. - void addAsmGlobalSymbol(const char *, lto_symbol_attributes scope); - - /// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to - /// the undefined list. - void addAsmGlobalSymbolUndef(const char *); - - /// addObjCClass - Parse i386/ppc ObjC class data structure. - void addObjCClass(const llvm::GlobalVariable *clgv); - - /// addObjCCategory - Parse i386/ppc ObjC category data structure. - void addObjCCategory(const llvm::GlobalVariable *clgv); - - /// addObjCClassRef - Parse i386/ppc ObjC class list data structure. - void addObjCClassRef(const llvm::GlobalVariable *clgv); - - /// objcClassNameFromExpression - Get string that the data pointer points - /// to. - bool objcClassNameFromExpression(const llvm::Constant* c, std::string &name); - - /// isTargetMatch - Returns 'true' if the memory buffer is for the specified - /// target triple. - static bool isTargetMatch(llvm::MemoryBuffer *memBuffer, - const char *triplePrefix); - - /// makeLTOModule - Create an LTOModule (private version). N.B. This - /// method takes ownership of the buffer. - static LTOModule *makeLTOModule(llvm::MemoryBuffer *buffer, - std::string &errMsg); - - /// makeBuffer - Create a MemoryBuffer from a memory range. - static llvm::MemoryBuffer *makeBuffer(const void *mem, size_t length); -}; - -#endif // LTO_MODULE_H diff --git a/tools/lto/Makefile b/tools/lto/Makefile index ab2e16e..cedbee1 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -10,7 +10,7 @@ LEVEL := ../.. LIBRARYNAME := LTO LINK_COMPONENTS := all-targets ipo scalaropts linker bitreader bitwriter \ - mcdisassembler vectorize + lto mcdisassembler vectorize LINK_LIBS_IN_SHARED := 1 SHARED_LIBRARY := 1 @@ -39,8 +39,7 @@ 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/') diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index 11ad532..7bfddcd 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -13,15 +13,71 @@ //===----------------------------------------------------------------------===// #include "llvm-c/lto.h" -#include "LTOCodeGenerator.h" -#include "LTOModule.h" +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/LTO/LTOCodeGenerator.h" +#include "llvm/LTO/LTOModule.h" #include "llvm-c/Core.h" +#include "llvm-c/Target.h" +// extra command-line flags needed for LTOCodeGenerator +static cl::opt<bool> +DisableOpt("disable-opt", cl::init(false), + cl::desc("Do not run any optimization passes")); + +static cl::opt<bool> +DisableInline("disable-inlining", cl::init(false), + cl::desc("Do not run the inliner pass")); + +static cl::opt<bool> +DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), + cl::desc("Do not run the GVN load PRE pass")); // Holds most recent error string. // *** Not thread safe *** static std::string sLastErrorString; +// Holds the initialization state of the LTO module. +// *** Not thread safe *** +static bool initialized = false; + +// Holds the command-line option parsing state of the LTO module. +static bool parsedOptions = false; + +// Initialize the configured targets if they have not been initialized. +static void lto_initialize() { + if (!initialized) { + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargets(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllAsmParsers(); + LLVMInitializeAllAsmPrinters(); + LLVMInitializeAllDisassemblers(); + initialized = true; + } +} + +static void lto_set_target_options(llvm::TargetOptions &Options) { + Options.LessPreciseFPMADOption = EnableFPMAD; + Options.NoFramePointerElim = DisableFPElim; + Options.AllowFPOpFusion = FuseFPOps; + Options.UnsafeFPMath = EnableUnsafeFPMath; + Options.NoInfsFPMath = EnableNoInfsFPMath; + Options.NoNaNsFPMath = EnableNoNaNsFPMath; + Options.HonorSignDependentRoundingFPMathOption = + EnableHonorSignDependentRoundingFPMath; + Options.UseSoftFloat = GenerateSoftFloatCalls; + if (FloatABIForCalls != llvm::FloatABI::Default) + Options.FloatABIType = FloatABIForCalls; + Options.NoZerosInBSS = DontPlaceZerosInBSS; + Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; + Options.DisableTailCalls = DisableTailCalls; + Options.StackAlignmentOverride = OverrideStackAlignment; + Options.TrapFuncName = TrapFuncName; + Options.PositionIndependentExecutable = EnablePIE; + Options.EnableSegmentedStacks = SegmentedStacks; + Options.UseInitArray = UseInitArray; +} + /// lto_get_version - Returns a printable string. extern const char* lto_get_version() { return LTOCodeGenerator::getVersionString(); @@ -63,13 +119,19 @@ lto_module_is_object_file_in_memory_for_target(const void* mem, /// lto_module_create - Loads an object file from disk. Returns NULL on error /// (check lto_get_error_message() for details). lto_module_t lto_module_create(const char* path) { - return LTOModule::makeLTOModule(path, sLastErrorString); + lto_initialize(); + llvm::TargetOptions Options; + lto_set_target_options(Options); + return LTOModule::makeLTOModule(path, Options, sLastErrorString); } /// lto_module_create_from_fd - Loads an object file from disk. Returns NULL on /// error (check lto_get_error_message() for details). lto_module_t lto_module_create_from_fd(int fd, const char *path, size_t size) { - return LTOModule::makeLTOModule(fd, path, size, sLastErrorString); + lto_initialize(); + llvm::TargetOptions Options; + lto_set_target_options(Options); + return LTOModule::makeLTOModule(fd, path, size, Options, sLastErrorString); } /// lto_module_create_from_fd_at_offset - Loads an object file from disk. @@ -78,14 +140,20 @@ 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); + lto_initialize(); + llvm::TargetOptions Options; + lto_set_target_options(Options); + return LTOModule::makeLTOModule(fd, path, map_size, offset, Options, + sLastErrorString); } /// lto_module_create_from_memory - Loads an object file from memory. Returns /// NULL on error (check lto_get_error_message() for details). lto_module_t lto_module_create_from_memory(const void* mem, size_t length) { - return LTOModule::makeLTOModule(mem, length, sLastErrorString); + lto_initialize(); + llvm::TargetOptions Options; + lto_set_target_options(Options); + return LTOModule::makeLTOModule(mem, length, Options, sLastErrorString); } /// lto_module_dispose - Frees all memory for a module. Upon return the @@ -128,7 +196,15 @@ lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod, /// lto_codegen_create - Instantiates a code generator. Returns NULL if there /// is an error. lto_code_gen_t lto_codegen_create(void) { - return new LTOCodeGenerator(); + lto_initialize(); + + TargetOptions Options; + lto_set_target_options(Options); + + LTOCodeGenerator *CodeGen = new LTOCodeGenerator(); + if (CodeGen) + CodeGen->setTargetOptions(Options); + return CodeGen; } /// lto_codegen_dispose - Frees all memory for a code generator. Upon return the @@ -141,20 +217,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 +264,11 @@ 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); + if (!parsedOptions) { + cg->parseCodeGenDebugOptions(); + parsedOptions = true; + } + return !cg->writeMergedModules(path, sLastErrorString); } /// lto_codegen_compile - Generates code for all added modules into one native @@ -196,14 +278,24 @@ bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) { /// lto_codegen_compile() is called again. On failure, returns NULL (check /// lto_get_error_message() for details). const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) { - return cg->compile(length, sLastErrorString); + if (!parsedOptions) { + cg->parseCodeGenDebugOptions(); + parsedOptions = true; + } + return cg->compile(length, DisableOpt, DisableInline, DisableGVNLoadPRE, + sLastErrorString); } /// lto_codegen_compile_to_file - Generates code for all added modules into one /// 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); + if (!parsedOptions) { + cg->parseCodeGenDebugOptions(); + parsedOptions = true; + } + return !cg->compile_to_file(name, DisableOpt, DisableInline, DisableGVNLoadPRE, + 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 88fd452..0dfbd5f 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -97,12 +97,12 @@ static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index, outs() << " ('_relocations', [\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()); + for (relocation_iterator I = Obj.section_rel_begin(Index), + E = Obj.section_rel_end(Index); I != E; I.increment(EC), ++RelNum) { + MachO::any_relocation_info 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() << " (('word-0', " << format("0x%x", RE.r_word0) << "),\n"; + outs() << " ('word-1', " << format("0x%x", RE.r_word1) << ")),\n"; } outs() << " ])\n"; @@ -124,23 +124,21 @@ static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index, static int DumpSegmentCommand(const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &LCI) { - macho::SegmentLoadCommand SLC = Obj.getSegmentLoadCommand(LCI); + MachO::segment_command 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.segname, 16), SLC.vmaddr, + SLC.vmsize, SLC.fileoff, SLC.filesize, + SLC.maxprot, SLC.initprot, SLC.nsects, SLC.flags); // Dump the sections. outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC.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); + for (unsigned i = 0; i != SLC.nsects; ++i) { + MachO::section Sect = Obj.getSection(LCI, i); + DumpSectionData(Obj, i, StringRef(Sect.sectname, 16), + StringRef(Sect.segname, 16), Sect.addr, + Sect.size, Sect.offset, Sect.align, + Sect.reloff, Sect.nreloc, Sect.flags, + Sect.reserved1, Sect.reserved2); } outs() << " ])\n"; @@ -149,24 +147,22 @@ static int DumpSegmentCommand(const MachOObjectFile &Obj, 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); + MachO::segment_command_64 SLC = Obj.getSegment64LoadCommand(LCI); + DumpSegmentCommandData(StringRef(SLC.segname, 16), SLC.vmaddr, + SLC.vmsize, SLC.fileoff, SLC.filesize, + SLC.maxprot, SLC.initprot, SLC.nsects, SLC.flags); // Dump the sections. outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC.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); + for (unsigned i = 0; i != SLC.nsects; ++i) { + MachO::section_64 Sect = Obj.getSection64(LCI, i); + + DumpSectionData(Obj, i, StringRef(Sect.sectname, 16), + StringRef(Sect.segname, 16), Sect.addr, + Sect.size, Sect.offset, Sect.align, + Sect.reloff, Sect.nreloc, Sect.flags, + Sect.reserved1, Sect.reserved2, + Sect.reserved3); } outs() << " ])\n"; @@ -190,12 +186,12 @@ static void DumpSymbolTableEntryData(const MachOObjectFile &Obj, } static int DumpSymtabCommand(const MachOObjectFile &Obj) { - macho::SymtabLoadCommand SLC = Obj.getSymtabLoadCommand(); + MachO::symtab_command SLC = Obj.getSymtabLoadCommand(); - outs() << " ('symoff', " << SLC.SymbolTableOffset << ")\n"; - outs() << " ('nsyms', " << SLC.NumSymbolTableEntries << ")\n"; - outs() << " ('stroff', " << SLC.StringTableOffset << ")\n"; - outs() << " ('strsize', " << SLC.StringTableSize << ")\n"; + outs() << " ('symoff', " << SLC.symoff << ")\n"; + outs() << " ('nsyms', " << SLC.nsyms << ")\n"; + outs() << " ('stroff', " << SLC.stroff << ")\n"; + outs() << " ('strsize', " << SLC.strsize << ")\n"; // Dump the string data. outs() << " ('_string_data', '"; @@ -211,14 +207,14 @@ static int DumpSymtabCommand(const MachOObjectFile &Obj) { I.increment(EC), ++SymNum) { DataRefImpl DRI = I->getRawDataRefImpl(); if (Obj.is64Bit()) { - macho::Symbol64TableEntry STE = Obj.getSymbol64TableEntry(DRI); - DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type, - STE.SectionIndex, STE.Flags, STE.Value, + MachO::nlist_64 STE = Obj.getSymbol64TableEntry(DRI); + DumpSymbolTableEntryData(Obj, SymNum, STE.n_strx, STE.n_type, + STE.n_sect, STE.n_desc, STE.n_value, StringTable); } else { - macho::SymbolTableEntry STE = Obj.getSymbolTableEntry(DRI); - DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type, - STE.SectionIndex, STE.Flags, STE.Value, + MachO::nlist STE = Obj.getSymbolTableEntry(DRI); + DumpSymbolTableEntryData(Obj, SymNum, STE.n_strx, STE.n_type, + STE.n_sect, STE.n_desc, STE.n_value, StringTable); } } @@ -228,37 +224,33 @@ static int DumpSymtabCommand(const MachOObjectFile &Obj) { } 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"; - 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"; + MachO::dysymtab_command DLC = Obj.getDysymtabLoadCommand(); + + outs() << " ('ilocalsym', " << DLC.ilocalsym << ")\n"; + outs() << " ('nlocalsym', " << DLC.nlocalsym << ")\n"; + outs() << " ('iextdefsym', " << DLC.iextdefsym << ")\n"; + outs() << " ('nextdefsym', " << DLC.nextdefsym << ")\n"; + outs() << " ('iundefsym', " << DLC.iundefsym << ")\n"; + outs() << " ('nundefsym', " << DLC.nundefsym << ")\n"; + outs() << " ('tocoff', " << DLC.tocoff << ")\n"; + outs() << " ('ntoc', " << DLC.ntoc << ")\n"; + outs() << " ('modtaboff', " << DLC.modtaboff << ")\n"; + outs() << " ('nmodtab', " << DLC.nmodtab << ")\n"; + outs() << " ('extrefsymoff', " << DLC.extrefsymoff << ")\n"; + outs() << " ('nextrefsyms', " << DLC.nextrefsyms << ")\n"; + outs() << " ('indirectsymoff', " << DLC.indirectsymoff << ")\n"; + outs() << " ('nindirectsyms', " << DLC.nindirectsyms << ")\n"; + outs() << " ('extreloff', " << DLC.extreloff << ")\n"; + outs() << " ('nextrel', " << DLC.nextrel << ")\n"; + outs() << " ('locreloff', " << DLC.locreloff << ")\n"; + outs() << " ('nlocrel', " << DLC.nlocrel << ")\n"; // Dump the indirect symbol table. outs() << " ('_indirect_symbols', [\n"; - for (unsigned i = 0; i != DLC.NumIndirectSymbolTableEntries; ++i) { - macho::IndirectSymbolTableEntry ISTE = - Obj.getIndirectSymbolTableEntry(DLC, i); + for (unsigned i = 0; i != DLC.nindirectsyms; ++i) { + uint32_t ISTE = Obj.getIndirectSymbolTableEntry(DLC, i); outs() << " # Indirect Symbol " << i << "\n"; - outs() << " (('symbol_index', " - << format("0x%x", ISTE.Index) << "),),\n"; + outs() << " (('symbol_index', " << format("0x%x", ISTE) << "),),\n"; } outs() << " ])\n"; @@ -268,13 +260,13 @@ static int DumpDysymtabCommand(const MachOObjectFile &Obj) { 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" + MachO::linkedit_data_command LLC = Obj.getLinkeditDataLoadCommand(LCI); + outs() << " ('dataoff', " << LLC.dataoff << ")\n" + << " ('datasize', " << LLC.datasize << ")\n" << " ('_addresses', [\n"; SmallVector<uint64_t, 8> Addresses; - Obj.ReadULEB128s(LLC.DataOffset, Addresses); + Obj.ReadULEB128s(LLC.dataoff, Addresses); for (unsigned i = 0, e = Addresses.size(); i != e; ++i) outs() << " # Address " << i << '\n' << " ('address', " << format("0x%x", Addresses[i]) << "),\n"; @@ -287,19 +279,18 @@ DumpLinkeditDataCommand(const MachOObjectFile &Obj, 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" + MachO::linkedit_data_command LLC = Obj.getLinkeditDataLoadCommand(LCI); + outs() << " ('dataoff', " << LLC.dataoff << ")\n" + << " ('datasize', " << LLC.datasize << ")\n" << " ('_data_regions', [\n"; - unsigned NumRegions = LLC.DataSize / 8; + unsigned NumRegions = LLC.datasize / sizeof(MachO::data_in_code_entry); for (unsigned i = 0; i < NumRegions; ++i) { - macho::DataInCodeTableEntry DICE = - Obj.getDataInCodeTableEntry(LLC.DataOffset, i); + MachO::data_in_code_entry DICE= Obj.getDataInCodeTableEntry(LLC.dataoff, i); outs() << " # DICE " << i << "\n" - << " ('offset', " << DICE.Offset << ")\n" - << " ('length', " << DICE.Length << ")\n" - << " ('kind', " << DICE.Kind << ")\n"; + << " ('offset', " << DICE.offset << ")\n" + << " ('length', " << DICE.length << ")\n" + << " ('kind', " << DICE.kind << ")\n"; } outs() <<" ])\n"; @@ -310,46 +301,46 @@ DumpDataInCodeDataCommand(const MachOObjectFile &Obj, 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"; + MachO::linker_options_command LOLC = Obj.getLinkerOptionsLoadCommand(LCI); + outs() << " ('count', " << LOLC.count << ")\n" + << " ('_strings', [\n"; + + uint64_t DataSize = LOLC.cmdsize - sizeof(MachO::linker_options_command); + const char *P = LCI.Ptr + sizeof(MachO::linker_options_command); + StringRef Data(P, DataSize); + for (unsigned i = 0; i != LOLC.count; ++i) { + std::pair<StringRef,StringRef> Split = Data.split('\0'); + outs() << "\t\""; + outs().write_escaped(Split.first); + outs() << "\",\n"; + Data = Split.second; + } + outs() <<" ])\n"; return 0; } static int DumpLoadCommand(const MachOObjectFile &Obj, MachOObjectFile::LoadCommandInfo &LCI) { - switch (LCI.C.Type) { - case macho::LCT_Segment: + switch (LCI.C.cmd) { + case MachO::LC_SEGMENT: return DumpSegmentCommand(Obj, LCI); - case macho::LCT_Segment64: + case MachO::LC_SEGMENT_64: return DumpSegment64Command(Obj, LCI); - case macho::LCT_Symtab: + case MachO::LC_SYMTAB: return DumpSymtabCommand(Obj); - case macho::LCT_Dysymtab: + case MachO::LC_DYSYMTAB: return DumpDysymtabCommand(Obj); - case macho::LCT_CodeSignature: - case macho::LCT_SegmentSplitInfo: - case macho::LCT_FunctionStarts: + case MachO::LC_CODE_SIGNATURE: + case MachO::LC_SEGMENT_SPLIT_INFO: + case MachO::LC_FUNCTION_STARTS: return DumpLinkeditDataCommand(Obj, LCI); - case macho::LCT_DataInCode: + case MachO::LC_DATA_IN_CODE: return DumpDataInCodeDataCommand(Obj, LCI); - case macho::LCT_LinkerOptions: + case MachO::LC_LINKER_OPTIONS: return DumpLinkerOptionsCommand(Obj, LCI); default: - Warning("unknown load command: " + Twine(LCI.C.Type)); + Warning("unknown load command: " + Twine(LCI.C.cmd)); return 0; } } @@ -358,26 +349,27 @@ static int DumpLoadCommand(const MachOObjectFile &Obj, 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"; + << " (('command', " << LCI.C.cmd << ")\n" + << " ('size', " << LCI.C.cmdsize << ")\n"; int Res = DumpLoadCommand(Obj, LCI); outs() << " ),\n"; return Res; } static void printHeader(const MachOObjectFile *Obj, - const macho::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"; + const MachO::mach_header &Header) { + outs() << "('cputype', " << Header.cputype << ")\n"; + outs() << "('cpusubtype', " << Header.cpusubtype << ")\n"; + outs() << "('filetype', " << Header.filetype << ")\n"; + outs() << "('num_load_commands', " << Header.ncmds << ")\n"; + outs() << "('load_commands_size', " << Header.sizeofcmds << ")\n"; + outs() << "('flag', " << Header.flags << ")\n"; // Print extended header if 64-bit. if (Obj->is64Bit()) { - macho::Header64Ext Header64Ext = Obj->getHeader64Ext(); - outs() << "('reserved', " << Header64Ext.Reserved << ")\n"; + const MachO::mach_header_64 *Header64 = + reinterpret_cast<const MachO::mach_header_64 *>(&Header); + outs() << "('reserved', " << Header64->reserved << ")\n"; } } @@ -396,8 +388,13 @@ int main(int argc, char **argv) { return Error("Not a MachO object"); // Print the header - macho::Header Header = InputObject->getHeader(); - printHeader(InputObject, Header); + MachO::mach_header_64 Header64; + MachO::mach_header *Header = reinterpret_cast<MachO::mach_header*>(&Header64); + if (InputObject->is64Bit()) + Header64 = InputObject->getHeader64(); + else + *Header = InputObject->getHeader(); + printHeader(InputObject, *Header); // Print the load commands. int Res = 0; @@ -408,7 +405,7 @@ int main(int argc, char **argv) { if (DumpLoadCommand(*InputObject, i, Command)) break; - if (i == Header.NumLoadCommands - 1) + if (i == Header->ncmds - 1) break; Command = InputObject->getNextLoadCommandInfo(Command); } diff --git a/tools/msbuild/CMakeLists.txt b/tools/msbuild/CMakeLists.txt new file mode 100644 index 0000000..08b8aee --- /dev/null +++ b/tools/msbuild/CMakeLists.txt @@ -0,0 +1,42 @@ +if (WIN32) + set(prop_file_in "Microsoft.Cpp.Win32.llvm.props.in") + set(prop_file_v100 "Microsoft.Cpp.Win32.LLVM-vs2010.props") + set(prop_file_v110 "Microsoft.Cpp.Win32.LLVM-vs2012.props") + set(prop_file_v110_xp "Microsoft.Cpp.Win32.LLVM-vs2012_xp.props") + set(prop_file_v120 "toolset-vs2013.props") + set(prop_file_v120_xp "toolset-vs2013_xp.props") + + # CPack will install a registry key in this format that we wish to reference. + set(REG_KEY "${CPACK_PACKAGE_INSTALL_REGISTRY_KEY}") + + set(VS_VERSION "v100") + set(MSC_VERSION "1600") + configure_file(${prop_file_in} ${prop_file_v100}) + set(VS_VERSION "v110") + set(MSC_VERSION "1700") + configure_file(${prop_file_in} ${prop_file_v110}) + set(VS_VERSION "v110_xp") + configure_file(${prop_file_in} ${prop_file_v110_xp}) + set(VS_VERSION "v120") + set(MSC_VERSION "1800") + configure_file(${prop_file_in} ${prop_file_v120}) + set(VS_VERSION "v120_xp") + configure_file(${prop_file_in} ${prop_file_v120_xp}) + + set(REG_KEY) + set(VS_VERSION) + set(MSC_VERSION) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v100}" DESTINATION tools/msbuild) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v110}" DESTINATION tools/msbuild) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v110_xp}" DESTINATION tools/msbuild) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v120}" DESTINATION tools/msbuild) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v120_xp}" DESTINATION tools/msbuild) + + install(DIRECTORY . + DESTINATION tools/msbuild + FILES_MATCHING + PATTERN "*.targets" + PATTERN "*.bat" + PATTERN ".svn" EXCLUDE + ) +endif() diff --git a/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2010.targets b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2010.targets new file mode 100644 index 0000000..df41a84 --- /dev/null +++ b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2010.targets @@ -0,0 +1,2 @@ +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
diff --git a/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012.targets b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012.targets new file mode 100644 index 0000000..f7432f2 --- /dev/null +++ b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012.targets @@ -0,0 +1,3 @@ +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" />
+</Project>
diff --git a/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets new file mode 100644 index 0000000..e8250d8 --- /dev/null +++ b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets @@ -0,0 +1,21 @@ +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <!-- Force TargetFrameworkVersion to v4.0 to support XP--> + <PropertyGroup> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <BeforeClCompileTargets>NoSupportCodeAnalysisXP;$(BeforeClCompileTargets)</BeforeClCompileTargets> + </PropertyGroup> + + <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" /> + + <Target Name="NoSupportCodeAnalysisXP" Condition="'$(ErrorNoSupportCodeAnalysisXP)' != 'false'"> + <VCMessage Condition="'$(DesignTimeBuild)' != 'true' and '@(ClCompile->AnyHaveMetadataValue('EnablePREfast', 'true'))'=='true'" Code="MSB8026" Type="Error"/> + </Target> + + <PropertyGroup> + <PrepareForBuildDependsOn>CheckWindowsSDK71A;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn> + </PropertyGroup> + + <Target Name="CheckWindowsSDK71A"> + <VCMessage Code="MSB8003" Type="Warning" Arguments="WindowsSdkDir_71A" Condition="'$(WindowsSdkDir_71A)'=='' and '$(UseEnv)' != 'true'" /> + </Target> +</Project> diff --git a/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in b/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in new file mode 100644 index 0000000..a6ef4ea --- /dev/null +++ b/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in @@ -0,0 +1,18 @@ +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(VCTargetsPath)\Platforms\$(Platform)\PlatformToolsets\@VS_VERSION@\Microsoft.Cpp.$(Platform).@VS_VERSION@.props" Condition="Exists('$(VCTargetsPath)\Platforms\$(Platform)\PlatformToolsets\@VS_VERSION@\Microsoft.Cpp.$(Platform).@VS_VERSION@.props')"/>
+ <Import Project="$(VCTargetsPath)\Platforms\$(Platform)\PlatformToolsets\@VS_VERSION@\Toolset.props" Condition="Exists('$(VCTargetsPath)\Platforms\$(Platform)\PlatformToolsets\@VS_VERSION@\Toolset.props')"/>
+
+ <PropertyGroup>
+ <LLVMInstallDir>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\LLVM\@REG_KEY@)</LLVMInstallDir>
+ <LLVMInstallDir Condition="'$(LLVMInstallDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\LLVM\@REG_KEY@)</LLVMInstallDir>
+ <ExecutablePath>$(LLVMInstallDir)\msbuild-bin;$(ExecutablePath)</ExecutablePath>
+ <LibraryPath>$(LLVMInstallDir)\lib\clang\3.4\lib\windows;$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <!-- Set the value of _MSC_VER to claim for compatibility -->
+ <AdditionalOptions>-fmsc-version=@MSC_VERSION@ %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+</Project>
diff --git a/tools/msbuild/install.bat b/tools/msbuild/install.bat new file mode 100644 index 0000000..c4c61ac --- /dev/null +++ b/tools/msbuild/install.bat @@ -0,0 +1,81 @@ +@echo off
+
+echo Installing MSVC integration...
+set SUCCESS=0
+
+REM Change to the directory of this batch file.
+cd /d %~dp0
+
+REM Search for the MSBuild toolsets directory.
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V100
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V100
+
+:TRY_V110
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V110
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V110
+
+:TRY_V120
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V120
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V120
+
+IF %SUCCESS% == 1 goto DONE
+echo Failed to find MSBuild toolsets directory.
+goto FAILED
+
+
+:FOUND_V100
+IF NOT EXIST %D%\LLVM-vs2010 mkdir %D%\LLVM-vs2010
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2010.props %D%\LLVM-vs2010
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2010.targets %D%\LLVM-vs2010
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+set SUCCESS=1
+GOTO TRY_V110
+
+:FOUND_V110
+IF NOT EXIST %D%\LLVM-vs2012 mkdir %D%\LLVM-vs2012
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2012.props %D%\LLVM-vs2012
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2012.targets %D%\LLVM-vs2012
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+IF NOT EXIST %D%\LLVM-vs2012_xp mkdir %D%\LLVM-vs2012_xp
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2012_xp.props %D%\LLVM-vs2012_xp
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets %D%\LLVM-vs2012_xp
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+set SUCCESS=1
+GOTO TRY_V120
+
+:FOUND_V120
+IF NOT EXIST %D%\LLVM-vs2013 mkdir %D%\LLVM-vs2013
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy toolset-vs2013.props %D%\LLVM-vs2013\toolset.props
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy toolset-vs2013.targets %D%\LLVM-vs2013\toolset.targets
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+IF NOT EXIST %D%\LLVM-vs2013_xp mkdir %D%\LLVM-vs2013_xp
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy toolset-vs2013_xp.props %D%\LLVM-vs2013_xp\toolset.props
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy toolset-vs2013_xp.targets %D%\LLVM-vs2013_xp\toolset.targets
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+
+:DONE
+echo Done!
+goto END
+
+:FAILED
+echo MSVC integration install failed.
+pause
+goto END
+
+:END
diff --git a/tools/msbuild/toolset-vs2013.targets b/tools/msbuild/toolset-vs2013.targets new file mode 100644 index 0000000..a6efac4 --- /dev/null +++ b/tools/msbuild/toolset-vs2013.targets @@ -0,0 +1,3 @@ +<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" />
+</Project>
diff --git a/tools/msbuild/toolset-vs2013_xp.targets b/tools/msbuild/toolset-vs2013_xp.targets new file mode 100644 index 0000000..e719681 --- /dev/null +++ b/tools/msbuild/toolset-vs2013_xp.targets @@ -0,0 +1,21 @@ +<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <!-- Force TargetFrameworkVersion to v4.0 to support XP--> + <PropertyGroup> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <BeforeClCompileTargets>NoSupportCodeAnalysisXP;$(BeforeClCompileTargets)</BeforeClCompileTargets> + </PropertyGroup> + + <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" /> + + <Target Name="NoSupportCodeAnalysisXP" Condition="'$(ErrorNoSupportCodeAnalysisXP)' != 'false'"> + <VCMessage Condition="'$(DesignTimeBuild)' != 'true' and '@(ClCompile->AnyHaveMetadataValue('EnablePREfast', 'true'))'=='true'" Code="MSB8026" Type="Error"/> + </Target> + + <PropertyGroup> + <PrepareForBuildDependsOn>CheckWindowsSDK71A;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn> + </PropertyGroup> + + <Target Name="CheckWindowsSDK71A"> + <VCMessage Code="MSB8003" Type="Warning" Arguments="WindowsSdkDir_71A" Condition="'$(WindowsSdkDir_71A)'=='' and '$(UseEnv)' != 'true'" /> + </Target> +</Project> diff --git a/tools/msbuild/uninstall.bat b/tools/msbuild/uninstall.bat new file mode 100644 index 0000000..7e94f87 --- /dev/null +++ b/tools/msbuild/uninstall.bat @@ -0,0 +1,50 @@ +@echo off
+
+echo Uninstalling MSVC integration...
+
+REM CD to the directory of this batch file.
+cd /d %~dp0
+
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.props
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.targets
+IF EXIST %D%\LLVM-vs2010 rmdir %D%\LLVM-vs2010
+
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.props
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.targets
+IF EXIST %D%\LLVM-vs2010 rmdir %D%\LLVM-vs2010
+
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.props
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.targets
+IF EXIST %D%\LLVM-vs2012 rmdir %D%\LLVM-vs2012
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.props
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets
+IF EXIST %D%\LLVM-vs2012_xp rmdir %D%\LLVM-vs2012_xp
+
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.props
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.targets
+IF EXIST %D%\LLVM-vs2012 rmdir %D%\LLVM-vs2012
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.props
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets
+IF EXIST %D%\LLVM-vs2012_xp rmdir %D%\LLVM-vs2012_xp
+
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.props
+IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.targets
+IF EXIST %D%\LLVM-vs2013 rmdir %D%\LLVM-vs2013
+IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.props
+IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.targets
+IF EXIST %D%\LLVM-vs2013_xp rmdir %D%\LLVM-vs2013_xp
+
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.props
+IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.targets
+IF EXIST %D%\LLVM-vs2013 rmdir %D%\LLVM-vs2013
+IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.props
+IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.targets
+IF EXIST %D%\LLVM-vs2013_xp rmdir %D%\LLVM-vs2013_xp
+
+echo Done!
diff --git a/tools/obj2yaml/CMakeLists.txt b/tools/obj2yaml/CMakeLists.txt index d64bf1b..6b39193 100644 --- a/tools/obj2yaml/CMakeLists.txt +++ b/tools/obj2yaml/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS archive object) +set(LLVM_LINK_COMPONENTS object) add_llvm_utility(obj2yaml obj2yaml.cpp coff2yaml.cpp diff --git a/tools/obj2yaml/coff2yaml.cpp b/tools/obj2yaml/coff2yaml.cpp index 5106a4a..02d7ebf 100644 --- a/tools/obj2yaml/coff2yaml.cpp +++ b/tools/obj2yaml/coff2yaml.cpp @@ -9,346 +9,111 @@ #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; -template <typename One, typename Two> -struct pod_pair { // I'd much rather use std::pair, but it's not a POD - One first; - Two second; -}; - -#define STRING_PAIR(x) {COFF::x, #x} -static const pod_pair<COFF::MachineTypes, const char *> -MachineTypePairs [] = { - STRING_PAIR(IMAGE_FILE_MACHINE_UNKNOWN), - STRING_PAIR(IMAGE_FILE_MACHINE_AM33), - STRING_PAIR(IMAGE_FILE_MACHINE_AMD64), - STRING_PAIR(IMAGE_FILE_MACHINE_ARM), - STRING_PAIR(IMAGE_FILE_MACHINE_ARMV7), - STRING_PAIR(IMAGE_FILE_MACHINE_EBC), - STRING_PAIR(IMAGE_FILE_MACHINE_I386), - STRING_PAIR(IMAGE_FILE_MACHINE_IA64), - STRING_PAIR(IMAGE_FILE_MACHINE_M32R), - STRING_PAIR(IMAGE_FILE_MACHINE_MIPS16), - STRING_PAIR(IMAGE_FILE_MACHINE_MIPSFPU), - STRING_PAIR(IMAGE_FILE_MACHINE_MIPSFPU16), - STRING_PAIR(IMAGE_FILE_MACHINE_POWERPC), - STRING_PAIR(IMAGE_FILE_MACHINE_POWERPCFP), - STRING_PAIR(IMAGE_FILE_MACHINE_R4000), - STRING_PAIR(IMAGE_FILE_MACHINE_SH3), - STRING_PAIR(IMAGE_FILE_MACHINE_SH3DSP), - STRING_PAIR(IMAGE_FILE_MACHINE_SH4), - STRING_PAIR(IMAGE_FILE_MACHINE_SH5), - STRING_PAIR(IMAGE_FILE_MACHINE_THUMB), - STRING_PAIR(IMAGE_FILE_MACHINE_WCEMIPSV2) -}; - -static const pod_pair<COFF::SectionCharacteristics, const char *> -SectionCharacteristicsPairs1 [] = { - STRING_PAIR(IMAGE_SCN_TYPE_NO_PAD), - STRING_PAIR(IMAGE_SCN_CNT_CODE), - STRING_PAIR(IMAGE_SCN_CNT_INITIALIZED_DATA), - STRING_PAIR(IMAGE_SCN_CNT_UNINITIALIZED_DATA), - STRING_PAIR(IMAGE_SCN_LNK_OTHER), - STRING_PAIR(IMAGE_SCN_LNK_INFO), - STRING_PAIR(IMAGE_SCN_LNK_REMOVE), - STRING_PAIR(IMAGE_SCN_LNK_COMDAT), - STRING_PAIR(IMAGE_SCN_GPREL), - STRING_PAIR(IMAGE_SCN_MEM_PURGEABLE), - STRING_PAIR(IMAGE_SCN_MEM_16BIT), - STRING_PAIR(IMAGE_SCN_MEM_LOCKED), - STRING_PAIR(IMAGE_SCN_MEM_PRELOAD) -}; +namespace { -static const pod_pair<COFF::SectionCharacteristics, const char *> -SectionCharacteristicsPairsAlignment [] = { - STRING_PAIR(IMAGE_SCN_ALIGN_1BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_2BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_4BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_8BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_16BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_32BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_64BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_128BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_256BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_512BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_1024BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_2048BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_4096BYTES), - STRING_PAIR(IMAGE_SCN_ALIGN_8192BYTES) -}; - -static const pod_pair<COFF::SectionCharacteristics, const char *> -SectionCharacteristicsPairs2 [] = { - STRING_PAIR(IMAGE_SCN_LNK_NRELOC_OVFL), - STRING_PAIR(IMAGE_SCN_MEM_DISCARDABLE), - STRING_PAIR(IMAGE_SCN_MEM_NOT_CACHED), - STRING_PAIR(IMAGE_SCN_MEM_NOT_PAGED), - STRING_PAIR(IMAGE_SCN_MEM_SHARED), - STRING_PAIR(IMAGE_SCN_MEM_EXECUTE), - STRING_PAIR(IMAGE_SCN_MEM_READ), - STRING_PAIR(IMAGE_SCN_MEM_WRITE) -}; - -static const pod_pair<COFF::SymbolBaseType, const char *> -SymbolBaseTypePairs [] = { - STRING_PAIR(IMAGE_SYM_TYPE_NULL), - STRING_PAIR(IMAGE_SYM_TYPE_VOID), - STRING_PAIR(IMAGE_SYM_TYPE_CHAR), - STRING_PAIR(IMAGE_SYM_TYPE_SHORT), - STRING_PAIR(IMAGE_SYM_TYPE_INT), - STRING_PAIR(IMAGE_SYM_TYPE_LONG), - STRING_PAIR(IMAGE_SYM_TYPE_FLOAT), - STRING_PAIR(IMAGE_SYM_TYPE_DOUBLE), - STRING_PAIR(IMAGE_SYM_TYPE_STRUCT), - STRING_PAIR(IMAGE_SYM_TYPE_UNION), - STRING_PAIR(IMAGE_SYM_TYPE_ENUM), - STRING_PAIR(IMAGE_SYM_TYPE_MOE), - STRING_PAIR(IMAGE_SYM_TYPE_BYTE), - STRING_PAIR(IMAGE_SYM_TYPE_WORD), - STRING_PAIR(IMAGE_SYM_TYPE_UINT), - STRING_PAIR(IMAGE_SYM_TYPE_DWORD) -}; +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); -static const pod_pair<COFF::SymbolComplexType, const char *> -SymbolComplexTypePairs [] = { - STRING_PAIR(IMAGE_SYM_DTYPE_NULL), - STRING_PAIR(IMAGE_SYM_DTYPE_POINTER), - STRING_PAIR(IMAGE_SYM_DTYPE_FUNCTION), - STRING_PAIR(IMAGE_SYM_DTYPE_ARRAY), +public: + COFFDumper(const object::COFFObjectFile &Obj); + COFFYAML::Object &getYAMLObj(); }; -static const pod_pair<COFF::SymbolStorageClass, const char *> -SymbolStorageClassPairs [] = { - STRING_PAIR(IMAGE_SYM_CLASS_END_OF_FUNCTION), - STRING_PAIR(IMAGE_SYM_CLASS_NULL), - STRING_PAIR(IMAGE_SYM_CLASS_AUTOMATIC), - STRING_PAIR(IMAGE_SYM_CLASS_EXTERNAL), - STRING_PAIR(IMAGE_SYM_CLASS_STATIC), - STRING_PAIR(IMAGE_SYM_CLASS_REGISTER), - STRING_PAIR(IMAGE_SYM_CLASS_EXTERNAL_DEF), - STRING_PAIR(IMAGE_SYM_CLASS_LABEL), - STRING_PAIR(IMAGE_SYM_CLASS_UNDEFINED_LABEL), - STRING_PAIR(IMAGE_SYM_CLASS_MEMBER_OF_STRUCT), - STRING_PAIR(IMAGE_SYM_CLASS_ARGUMENT), - STRING_PAIR(IMAGE_SYM_CLASS_STRUCT_TAG), - STRING_PAIR(IMAGE_SYM_CLASS_MEMBER_OF_UNION), - STRING_PAIR(IMAGE_SYM_CLASS_UNION_TAG), - STRING_PAIR(IMAGE_SYM_CLASS_TYPE_DEFINITION), - STRING_PAIR(IMAGE_SYM_CLASS_UNDEFINED_STATIC), - STRING_PAIR(IMAGE_SYM_CLASS_ENUM_TAG), - STRING_PAIR(IMAGE_SYM_CLASS_MEMBER_OF_ENUM), - STRING_PAIR(IMAGE_SYM_CLASS_REGISTER_PARAM), - STRING_PAIR(IMAGE_SYM_CLASS_BIT_FIELD), - STRING_PAIR(IMAGE_SYM_CLASS_BLOCK), - STRING_PAIR(IMAGE_SYM_CLASS_FUNCTION), - STRING_PAIR(IMAGE_SYM_CLASS_END_OF_STRUCT), - STRING_PAIR(IMAGE_SYM_CLASS_FILE), - STRING_PAIR(IMAGE_SYM_CLASS_SECTION), - STRING_PAIR(IMAGE_SYM_CLASS_WEAK_EXTERNAL), - STRING_PAIR(IMAGE_SYM_CLASS_CLR_TOKEN), -}; - -static const pod_pair<COFF::RelocationTypeX86, const char *> -RelocationTypeX86Pairs [] = { - STRING_PAIR(IMAGE_REL_I386_ABSOLUTE), - STRING_PAIR(IMAGE_REL_I386_DIR16), - STRING_PAIR(IMAGE_REL_I386_REL16), - STRING_PAIR(IMAGE_REL_I386_DIR32), - STRING_PAIR(IMAGE_REL_I386_DIR32NB), - STRING_PAIR(IMAGE_REL_I386_SEG12), - STRING_PAIR(IMAGE_REL_I386_SECTION), - STRING_PAIR(IMAGE_REL_I386_SECREL), - STRING_PAIR(IMAGE_REL_I386_TOKEN), - STRING_PAIR(IMAGE_REL_I386_SECREL7), - STRING_PAIR(IMAGE_REL_I386_REL32), - STRING_PAIR(IMAGE_REL_AMD64_ABSOLUTE), - STRING_PAIR(IMAGE_REL_AMD64_ADDR64), - STRING_PAIR(IMAGE_REL_AMD64_ADDR32), - STRING_PAIR(IMAGE_REL_AMD64_ADDR32NB), - STRING_PAIR(IMAGE_REL_AMD64_REL32), - STRING_PAIR(IMAGE_REL_AMD64_REL32_1), - STRING_PAIR(IMAGE_REL_AMD64_REL32_2), - STRING_PAIR(IMAGE_REL_AMD64_REL32_3), - STRING_PAIR(IMAGE_REL_AMD64_REL32_4), - STRING_PAIR(IMAGE_REL_AMD64_REL32_5), - STRING_PAIR(IMAGE_REL_AMD64_SECTION), - STRING_PAIR(IMAGE_REL_AMD64_SECREL), - STRING_PAIR(IMAGE_REL_AMD64_SECREL7), - STRING_PAIR(IMAGE_REL_AMD64_TOKEN), - STRING_PAIR(IMAGE_REL_AMD64_SREL32), - STRING_PAIR(IMAGE_REL_AMD64_PAIR), - STRING_PAIR(IMAGE_REL_AMD64_SSPAN32) -}; - -static const pod_pair<COFF::RelocationTypesARM, const char *> -RelocationTypesARMPairs [] = { - STRING_PAIR(IMAGE_REL_ARM_ABSOLUTE), - STRING_PAIR(IMAGE_REL_ARM_ADDR32), - STRING_PAIR(IMAGE_REL_ARM_ADDR32NB), - STRING_PAIR(IMAGE_REL_ARM_BRANCH24), - STRING_PAIR(IMAGE_REL_ARM_BRANCH11), - STRING_PAIR(IMAGE_REL_ARM_TOKEN), - STRING_PAIR(IMAGE_REL_ARM_BLX24), - STRING_PAIR(IMAGE_REL_ARM_BLX11), - STRING_PAIR(IMAGE_REL_ARM_SECTION), - STRING_PAIR(IMAGE_REL_ARM_SECREL), - STRING_PAIR(IMAGE_REL_ARM_MOV32A), - STRING_PAIR(IMAGE_REL_ARM_MOV32T), - STRING_PAIR(IMAGE_REL_ARM_BRANCH20T), - STRING_PAIR(IMAGE_REL_ARM_BRANCH24T), - STRING_PAIR(IMAGE_REL_ARM_BLX23T) -}; -#undef STRING_PAIR - -static raw_ostream &writeName(raw_ostream &Out, - const char *Name, std::size_t NameSize) { - for (std::size_t i = 0; i < NameSize; ++i) { - if (!Name[i]) break; - Out << Name[i]; - } - return Out; } -// Given an array of pod_pair<enum, const char *>, write all enums that match -template <typename T, std::size_t N> -static raw_ostream &writeBitMask(raw_ostream &Out, - const pod_pair<T, const char *> (&Arr)[N], - unsigned long Val) { - for (std::size_t i = 0; i < N; ++i) - if (Val & Arr[i].first) - Out << Arr[i].second << ", "; - return Out; +static void check(error_code ec) { + if (ec) + report_fatal_error(ec.message()); } -// Given an array of pod_pair<enum, const char *>, look up a value -template <typename T, std::size_t N> -const char *nameLookup(const pod_pair<T, const char *> (&Arr)[N], - unsigned long Val, const char *NotFound = NULL) { - T n = static_cast<T>(Val); - for (std::size_t i = 0; i < N; ++i) - if (n == Arr[i].first) - return Arr[i].second; - return NotFound; +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); } -static void yamlCOFFHeader(const object::coff_file_header *Header, - raw_ostream &Out) { - Out << "header: !Header\n"; - Out << " Machine: "; - Out << nameLookup(MachineTypePairs, Header->Machine, "# Unknown_MachineTypes") - << " # ("; - objyaml::writeHexNumber(Out, Header->Machine) << ")\n\n"; +void COFFDumper::dumpHeader(const object::coff_file_header *Header) { + YAMLObj.Header.Machine = Header->Machine; + YAMLObj.Header.Characteristics = Header->Characteristics; } - -static void yamlCOFFSections(object::COFFObjectFile &Obj, - std::size_t NumSections, raw_ostream &Out) { +void COFFDumper::dumpSections(unsigned NumSections) { + std::vector<COFFYAML::Section> &Sections = YAMLObj.Sections; error_code ec; - Out << "sections:\n"; for (object::section_iterator iter = Obj.begin_sections(); iter != Obj.end_sections(); iter.increment(ec)) { - const object::coff_section *sect = Obj.getCOFFSection(iter); - - Out << " - !Section\n"; - Out << " Name: "; - writeName(Out, sect->Name, sizeof(sect->Name)) << '\n'; - - Out << " Characteristics: ["; - writeBitMask(Out, SectionCharacteristicsPairs1, sect->Characteristics); - Out << nameLookup(SectionCharacteristicsPairsAlignment, - sect->Characteristics & 0x00F00000, "# Unrecognized_IMAGE_SCN_ALIGN") - << ", "; - writeBitMask(Out, SectionCharacteristicsPairs2, sect->Characteristics); - Out << "] # "; - objyaml::writeHexNumber(Out, sect->Characteristics) << '\n'; + 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); - Out << " SectionData: "; - objyaml::writeHexStream(Out, sectionData) << '\n'; - if (iter->begin_relocations() != iter->end_relocations()) - Out << " Relocations:\n"; + 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); - - Out << " - !Relocation\n"; - Out << " VirtualAddress: " ; - objyaml::writeHexNumber(Out, reloc->VirtualAddress) << '\n'; - Out << " SymbolTableIndex: " << reloc->SymbolTableIndex << '\n'; - Out << " Type: " - << nameLookup(RelocationTypeX86Pairs, reloc->Type) << '\n'; - // TODO: Use the correct reloc type for the machine. - Out << '\n'; - } - + COFFYAML::Relocation Rel; + object::symbol_iterator Sym = rIter->getSymbol(); + Sym->getName(Rel.SymbolName); + Rel.VirtualAddress = reloc->VirtualAddress; + Rel.Type = reloc->Type; + Relocations.push_back(Rel); + } + Sec.Relocations = Relocations; + Sections.push_back(Sec); } } -static void yamlCOFFSymbols(object::COFFObjectFile &Obj, std::size_t NumSymbols, - raw_ostream &Out) { +void COFFDumper::dumpSymbols(unsigned NumSymbols) { error_code ec; - Out << "symbols:\n"; + std::vector<COFFYAML::Symbol> &Symbols = YAMLObj.Symbols; for (object::symbol_iterator iter = Obj.begin_symbols(); iter != Obj.end_symbols(); iter.increment(ec)) { - // Gather all the info that we need - StringRef str; - const object::coff_symbol *symbol = Obj.getCOFFSymbol(iter); - Obj.getSymbolName(symbol, str); - std::size_t simpleType = symbol->getBaseType(); - std::size_t complexType = symbol->getComplexType(); - std::size_t storageClass = symbol->StorageClass; - - Out << " - !Symbol\n"; - Out << " Name: " << str << '\n'; - - Out << " Value: " << symbol->Value << '\n'; - Out << " SectionNumber: " << symbol->SectionNumber << '\n'; - - Out << " SimpleType: " - << nameLookup(SymbolBaseTypePairs, simpleType, - "# Unknown_SymbolBaseType") - << " # (" << simpleType << ")\n"; - - Out << " ComplexType: " - << nameLookup(SymbolComplexTypePairs, complexType, - "# Unknown_SymbolComplexType") - << " # (" << complexType << ")\n"; - - Out << " StorageClass: " - << nameLookup(SymbolStorageClassPairs, storageClass, - "# Unknown_StorageClass") - << " # (" << (int) storageClass << ")\n"; - - if (symbol->NumberOfAuxSymbols > 0) { - ArrayRef<uint8_t> aux = Obj.getSymbolAuxData(symbol); - Out << " NumberOfAuxSymbols: " - << (int) symbol->NumberOfAuxSymbols << '\n'; - Out << " AuxillaryData: "; - objyaml::writeHexStream(Out, aux); - } - - Out << '\n'; + 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 *TheObj) { +error_code coff2yaml(raw_ostream &Out, MemoryBuffer *Buff) { error_code ec; - object::COFFObjectFile obj(TheObj, ec); - if (ec) - return ec; - - const object::coff_file_header *hd; - ec = obj.getHeader(hd); - if (ec) - return ec; + object::COFFObjectFile Obj(Buff, ec); + check(ec); + COFFDumper Dumper(Obj); - yamlCOFFHeader(hd, Out); - yamlCOFFSections(obj, hd->NumberOfSections, Out); - yamlCOFFSymbols(obj, hd->NumberOfSymbols, Out); + yaml::Output Yout(Out); + Yout << Dumper.getYAMLObj(); - return ec; + return object::object_error::success; } diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp index 821c9ac..8d128b3 100644 --- a/tools/obj2yaml/obj2yaml.cpp +++ b/tools/obj2yaml/obj2yaml.cpp @@ -18,38 +18,6 @@ using namespace llvm; -namespace objyaml { // generic yaml-writing specific routines - -unsigned char printable(unsigned char Ch) { - return Ch >= ' ' && Ch <= '~' ? Ch : '.'; -} - -raw_ostream &writeHexStream(raw_ostream &Out, const ArrayRef<uint8_t> arr) { - const char *hex = "0123456789ABCDEF"; - Out << " !hex \""; - - typedef ArrayRef<uint8_t>::const_iterator iter_t; - const iter_t end = arr.end(); - for (iter_t iter = arr.begin(); iter != end; ++iter) - Out << hex[(*iter >> 4) & 0x0F] << hex[(*iter & 0x0F)]; - - Out << "\" # |"; - for (iter_t iter = arr.begin(); iter != end; ++iter) - Out << printable(*iter); - Out << "|\n"; - - return Out; -} - -raw_ostream &writeHexNumber(raw_ostream &Out, unsigned long long N) { - if (N >= 10) - Out << "0x"; - Out.write_hex(N); - return Out; -} - -} // end namespace yaml - namespace { enum ObjectFileType { coff diff --git a/tools/obj2yaml/obj2yaml.h b/tools/obj2yaml/obj2yaml.h index 7d52a2d..bde82e6 100644 --- a/tools/obj2yaml/obj2yaml.h +++ b/tools/obj2yaml/obj2yaml.h @@ -13,22 +13,10 @@ #ifndef LLVM_TOOLS_OBJ2YAML_H #define LLVM_TOOLS_OBJ2YAML_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -namespace objyaml { // routines for writing YAML -// Write a hex stream: -// <Prefix> !hex: "<hex digits>" #|<ASCII chars>\n - llvm::raw_ostream &writeHexStream - (llvm::raw_ostream &Out, const llvm::ArrayRef<uint8_t> arr); - -// Writes a number in hex; prefix it by 0x if it is >= 10 - llvm::raw_ostream &writeHexNumber - (llvm::raw_ostream &Out, unsigned long long N); -} - llvm::error_code coff2yaml(llvm::raw_ostream &Out, llvm::MemoryBuffer *TheObj); #endif diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index e385d7f5..dba16f7 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -136,6 +136,21 @@ UnitAtATime("funit-at-a-time", cl::init(true)); static cl::opt<bool> +DisableLoopUnrolling("disable-loop-unrolling", + cl::desc("Disable loop unrolling in all relevant passes"), + cl::init(false)); +static cl::opt<bool> +DisableLoopVectorization("disable-loop-vectorization", + cl::desc("Disable the loop vectorization pass"), + cl::init(false)); + +static cl::opt<bool> +DisableSLPVectorization("disable-slp-vectorization", + cl::desc("Disable the slp vectorization pass"), + cl::init(false)); + + +static cl::opt<bool> DisableSimplifyLibCalls("disable-simplify-libcalls", cl::desc("Disable simplify-libcalls")); @@ -362,6 +377,7 @@ char BasicBlockPassPrinter::ID = 0; struct BreakpointPrinter : public ModulePass { raw_ostream &Out; static char ID; + DITypeIdentifierMap TypeIdentifierMap; BreakpointPrinter(raw_ostream &out) : ModulePass(ID), Out(out) { @@ -377,20 +393,28 @@ struct BreakpointPrinter : public ModulePass { } else if (Context.isType()) { DIType TY(Context); if (!TY.getName().empty()) { - getContextName(TY.getContext(), N); + getContextName(TY.getContext().resolve(TypeIdentifierMap), N); N = N + TY.getName().str() + "::"; } } } virtual bool runOnModule(Module &M) { + TypeIdentifierMap.clear(); + NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu"); + if (CU_Nodes) + TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes); + StringSet<> Processed; if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp")) for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { std::string Name; DISubprogram SP(NMD->getOperand(i)); - 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().resolve(TypeIdentifierMap), Name); Name = Name + SP.getDisplayName().str(); if (!Name.empty() && Processed.insert(Name)) { Out << Name << "\n"; @@ -403,7 +427,7 @@ struct BreakpointPrinter : public ModulePass { AU.setPreservesAll(); } }; - + } // anonymous namespace char BreakpointPrinter::ID = 0; @@ -444,9 +468,14 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM, Builder.Inliner = createAlwaysInlinerPass(); } Builder.DisableUnitAtATime = !UnitAtATime; - Builder.DisableUnrollLoops = OptLevel == 0; - Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls; - + Builder.DisableUnrollLoops = (DisableLoopUnrolling.getNumOccurrences() > 0) ? + DisableLoopUnrolling : OptLevel == 0; + + Builder.LoopVectorize = + DisableLoopVectorization ? false : OptLevel > 1 && SizeLevel < 2; + Builder.SLPVectorize = + DisableSLPVectorization ? false : OptLevel > 1 && SizeLevel < 2; + Builder.populateFunctionPassManager(FPM); Builder.populateModulePassManager(MPM); } @@ -465,7 +494,6 @@ static void AddStandardCompilePasses(PassManagerBase &PM) { if (!DisableInline) Builder.Inliner = createFunctionInliningPass(); Builder.OptLevel = 3; - Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls; Builder.populateModulePassManager(PM); } @@ -490,7 +518,6 @@ static TargetOptions GetTargetOptions() { TargetOptions Options; Options.LessPreciseFPMADOption = EnableFPMAD; Options.NoFramePointerElim = DisableFPElim; - Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf; Options.AllowFPOpFusion = FuseFPOps; Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; @@ -504,12 +531,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; } @@ -567,6 +592,7 @@ int main(int argc, char **argv) { // Initialize passes PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); + initializeDebugIRPass(Registry); initializeScalarOpts(Registry); initializeObjCARCOpts(Registry); initializeVectorization(Registry); @@ -614,7 +640,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; @@ -667,6 +693,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) { @@ -677,7 +706,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 index f8b1197..8d9d652 100644 --- a/tools/yaml2obj/CMakeLists.txt +++ b/tools/yaml2obj/CMakeLists.txt @@ -1,5 +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 index cb6f477..8801795 100644 --- a/tools/yaml2obj/Makefile +++ b/tools/yaml2obj/Makefile @@ -9,7 +9,7 @@ LEVEL = ../.. TOOLNAME = yaml2obj -LINK_COMPONENTS := support +LINK_COMPONENTS := object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp new file mode 100644 index 0000000..c757eb6 --- /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, char(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..d46e154 --- /dev/null +++ b/tools/yaml2obj/yaml2elf.cpp @@ -0,0 +1,401 @@ +//===- 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/ADT/ArrayRef.h" +#include "llvm/Object/ELFObjectFile.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 arrayDataSize(ArrayRef<T> A) { + return A.size() * sizeof(T); +} + +template <class T> +static void writeArrayData(raw_ostream &OS, ArrayRef<T> A) { + OS.write((const char *)A.data(), arrayDataSize(A)); +} + +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::ELFFile<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::ELFFile<ELFT>::Elf_Sym> &Syms, + unsigned SymbolBinding) { + typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym; + for (unsigned i = 0, e = Symbols.size(); i != e; ++i) { + const ELFYAML::Symbol &Sym = Symbols[i]; + Elf_Sym Symbol; + zero(Symbol); + if (!Sym.Name.empty()) + Symbol.st_name = State.getStringTable().addString(Sym.Name); + Symbol.setBindingAndType(SymbolBinding, Sym.Type); + if (!Sym.Section.empty()) { + 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::ELFFile<ELFT>::Elf_Shdr &SHeader) { + + typedef typename object::ELFFile<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(); + writeArrayData(CBA.getOSAndAlignedOffset(SHeader.sh_offset), + makeArrayRef(Syms)); + SHeader.sh_size = arrayDataSize(makeArrayRef(Syms)); +} + +template <class ELFT> +static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { + using namespace llvm::ELF; + typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr; + typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; + + const ELFYAML::FileHeader &Hdr = Doc.Header; + + Elf_Ehdr Header; + zero(Header); + Header.e_ident[EI_MAG0] = 0x7f; + Header.e_ident[EI_MAG1] = 'E'; + Header.e_ident[EI_MAG2] = 'L'; + Header.e_ident[EI_MAG3] = 'F'; + Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; + bool IsLittleEndian = ELFT::TargetEndianness == support::little; + Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; + Header.e_ident[EI_VERSION] = EV_CURRENT; + Header.e_ident[EI_OSABI] = Hdr.OSABI; + Header.e_ident[EI_ABIVERSION] = 0; + Header.e_type = Hdr.Type; + Header.e_machine = Hdr.Machine; + Header.e_version = EV_CURRENT; + Header.e_entry = Hdr.Entry; + Header.e_ehsize = sizeof(Elf_Ehdr); + + // 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)); + writeArrayData(OS, makeArrayRef(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 index 707b6b4..6d1107c 100644 --- a/tools/yaml2obj/yaml2obj.cpp +++ b/tools/yaml2obj/yaml2obj.cpp @@ -14,636 +14,42 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/COFF.h" -#include "llvm/Support/Casting.h" +#include "yaml2obj.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Endian.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include <vector> using namespace llvm; static cl::opt<std::string> Input(cl::Positional, cl::desc("<input>"), cl::init("-")); -// The structure of the yaml files is not an exact 1:1 match to COFF. In order -// to use yaml::IO, we use these structures which are closer to the source. -namespace COFFYAML { - struct Section { - COFF::section Header; - unsigned Alignment; - StringRef SectionData; - std::vector<COFF::relocation> Relocations; - StringRef Name; - Section() { - memset(&Header, 0, sizeof(COFF::section)); - } - }; - - struct Symbol { - COFF::symbol Header; - COFF::SymbolBaseType SimpleType; - COFF::SymbolComplexType ComplexType; - StringRef AuxiliaryData; - StringRef Name; - Symbol() { - memset(&Header, 0, sizeof(COFF::symbol)); - } - }; - - struct Object { - COFF::header Header; - std::vector<Section> Sections; - std::vector<Symbol> Symbols; - Object() { - memset(&Header, 0, sizeof(COFF::header)); - } - }; -} - -/// 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; +// 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 }; -// 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.empty()) { - i->Header.SizeOfRawData = i->SectionData.size()/2; - 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.size() / 2; - 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); -} - -static bool writeHexData(StringRef Data, raw_ostream &OS) { - unsigned Size = Data.size(); - if (Size % 2) - return false; - - for (unsigned I = 0; I != Size; I += 2) { - uint8_t Byte; - if (Data.substr(I, 2).getAsInteger(16, Byte)) - return false; - OS.write(Byte); - } - - return true; -} - -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); - } - - // Output section data. - for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(), - e = CP.Obj.Sections.end(); - i != e; ++i) { - if (!i->SectionData.empty()) { - if (!writeHexData(i->SectionData, OS)) { - errs() << "SectionData must be a collection of pairs of hex bytes"; - return false; - } - } - for (unsigned I2 = 0, E2 = i->Relocations.size(); I2 != E2; ++I2) { - const COFF::relocation &R = i->Relocations[I2]; - OS << binary_le(R.VirtualAddress) - << binary_le(R.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); - if (!i->AuxiliaryData.empty()) { - if (!writeHexData(i->AuxiliaryData, OS)) { - errs() << "AuxiliaryData must be a collection of pairs of hex bytes"; - return false; - } - } - } - - // Output string table. - OS.write(&CP.StringTable[0], CP.StringTable.size()); - return true; -} - -LLVM_YAML_IS_SEQUENCE_VECTOR(COFF::relocation) -LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Section) -LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Symbol) - -namespace llvm { - -namespace COFF { - Characteristics operator|(Characteristics a, Characteristics b) { - uint32_t Ret = static_cast<uint32_t>(a) | static_cast<uint32_t>(b); - return static_cast<Characteristics>(Ret); - } - - SectionCharacteristics - operator|(SectionCharacteristics a, SectionCharacteristics b) { - uint32_t Ret = static_cast<uint32_t>(a) | static_cast<uint32_t>(b); - return static_cast<SectionCharacteristics>(Ret); - } -} +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)); -namespace yaml { - -#define BCase(X) IO.bitSetCase(Value, #X, COFF::X); - -template <> -struct ScalarBitSetTraits<COFF::SectionCharacteristics> { - static void bitset(IO &IO, COFF::SectionCharacteristics &Value) { - BCase(IMAGE_SCN_TYPE_NO_PAD); - BCase(IMAGE_SCN_CNT_CODE); - BCase(IMAGE_SCN_CNT_INITIALIZED_DATA); - BCase(IMAGE_SCN_CNT_UNINITIALIZED_DATA); - BCase(IMAGE_SCN_LNK_OTHER); - BCase(IMAGE_SCN_LNK_INFO); - BCase(IMAGE_SCN_LNK_REMOVE); - BCase(IMAGE_SCN_LNK_COMDAT); - BCase(IMAGE_SCN_GPREL); - BCase(IMAGE_SCN_MEM_PURGEABLE); - BCase(IMAGE_SCN_MEM_16BIT); - BCase(IMAGE_SCN_MEM_LOCKED); - BCase(IMAGE_SCN_MEM_PRELOAD); - BCase(IMAGE_SCN_LNK_NRELOC_OVFL); - BCase(IMAGE_SCN_MEM_DISCARDABLE); - BCase(IMAGE_SCN_MEM_NOT_CACHED); - BCase(IMAGE_SCN_MEM_NOT_PAGED); - BCase(IMAGE_SCN_MEM_SHARED); - BCase(IMAGE_SCN_MEM_EXECUTE); - BCase(IMAGE_SCN_MEM_READ); - BCase(IMAGE_SCN_MEM_WRITE); - } -}; - -template <> -struct ScalarBitSetTraits<COFF::Characteristics> { - static void bitset(IO &IO, COFF::Characteristics &Value) { - BCase(IMAGE_FILE_RELOCS_STRIPPED); - BCase(IMAGE_FILE_EXECUTABLE_IMAGE); - BCase(IMAGE_FILE_LINE_NUMS_STRIPPED); - BCase(IMAGE_FILE_LOCAL_SYMS_STRIPPED); - BCase(IMAGE_FILE_AGGRESSIVE_WS_TRIM); - BCase(IMAGE_FILE_LARGE_ADDRESS_AWARE); - BCase(IMAGE_FILE_BYTES_REVERSED_LO); - BCase(IMAGE_FILE_32BIT_MACHINE); - BCase(IMAGE_FILE_DEBUG_STRIPPED); - BCase(IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP); - BCase(IMAGE_FILE_NET_RUN_FROM_SWAP); - BCase(IMAGE_FILE_SYSTEM); - BCase(IMAGE_FILE_DLL); - BCase(IMAGE_FILE_UP_SYSTEM_ONLY); - BCase(IMAGE_FILE_BYTES_REVERSED_HI); - } -}; -#undef BCase - -#define ECase(X) IO.enumCase(Value, #X, COFF::X); - -template <> -struct ScalarEnumerationTraits<COFF::SymbolComplexType> { - static void enumeration(IO &IO, COFF::SymbolComplexType &Value) { - ECase(IMAGE_SYM_DTYPE_NULL); - ECase(IMAGE_SYM_DTYPE_POINTER); - ECase(IMAGE_SYM_DTYPE_FUNCTION); - ECase(IMAGE_SYM_DTYPE_ARRAY); - } -}; - -template <> -struct ScalarEnumerationTraits<COFF::SymbolStorageClass> { - static void enumeration(IO &IO, COFF::SymbolStorageClass &Value) { - ECase(IMAGE_SYM_CLASS_END_OF_FUNCTION); - ECase(IMAGE_SYM_CLASS_NULL); - ECase(IMAGE_SYM_CLASS_AUTOMATIC); - ECase(IMAGE_SYM_CLASS_EXTERNAL); - ECase(IMAGE_SYM_CLASS_STATIC); - ECase(IMAGE_SYM_CLASS_REGISTER); - ECase(IMAGE_SYM_CLASS_EXTERNAL_DEF); - ECase(IMAGE_SYM_CLASS_LABEL); - ECase(IMAGE_SYM_CLASS_UNDEFINED_LABEL); - ECase(IMAGE_SYM_CLASS_MEMBER_OF_STRUCT); - ECase(IMAGE_SYM_CLASS_ARGUMENT); - ECase(IMAGE_SYM_CLASS_STRUCT_TAG); - ECase(IMAGE_SYM_CLASS_MEMBER_OF_UNION); - ECase(IMAGE_SYM_CLASS_UNION_TAG); - ECase(IMAGE_SYM_CLASS_TYPE_DEFINITION); - ECase(IMAGE_SYM_CLASS_UNDEFINED_STATIC); - ECase(IMAGE_SYM_CLASS_ENUM_TAG); - ECase(IMAGE_SYM_CLASS_MEMBER_OF_ENUM); - ECase(IMAGE_SYM_CLASS_REGISTER_PARAM); - ECase(IMAGE_SYM_CLASS_BIT_FIELD); - ECase(IMAGE_SYM_CLASS_BLOCK); - ECase(IMAGE_SYM_CLASS_FUNCTION); - ECase(IMAGE_SYM_CLASS_END_OF_STRUCT); - ECase(IMAGE_SYM_CLASS_FILE); - ECase(IMAGE_SYM_CLASS_SECTION); - ECase(IMAGE_SYM_CLASS_WEAK_EXTERNAL); - ECase(IMAGE_SYM_CLASS_CLR_TOKEN); - } -}; - -template <> -struct ScalarEnumerationTraits<COFF::SymbolBaseType> { - static void enumeration(IO &IO, COFF::SymbolBaseType &Value) { - ECase(IMAGE_SYM_TYPE_NULL); - ECase(IMAGE_SYM_TYPE_VOID); - ECase(IMAGE_SYM_TYPE_CHAR); - ECase(IMAGE_SYM_TYPE_SHORT); - ECase(IMAGE_SYM_TYPE_INT); - ECase(IMAGE_SYM_TYPE_LONG); - ECase(IMAGE_SYM_TYPE_FLOAT); - ECase(IMAGE_SYM_TYPE_DOUBLE); - ECase(IMAGE_SYM_TYPE_STRUCT); - ECase(IMAGE_SYM_TYPE_UNION); - ECase(IMAGE_SYM_TYPE_ENUM); - ECase(IMAGE_SYM_TYPE_MOE); - ECase(IMAGE_SYM_TYPE_BYTE); - ECase(IMAGE_SYM_TYPE_WORD); - ECase(IMAGE_SYM_TYPE_UINT); - ECase(IMAGE_SYM_TYPE_DWORD); - } -}; - -template <> -struct ScalarEnumerationTraits<COFF::MachineTypes> { - static void enumeration(IO &IO, COFF::MachineTypes &Value) { - ECase(IMAGE_FILE_MACHINE_UNKNOWN); - ECase(IMAGE_FILE_MACHINE_AM33); - ECase(IMAGE_FILE_MACHINE_AMD64); - ECase(IMAGE_FILE_MACHINE_ARM); - ECase(IMAGE_FILE_MACHINE_ARMV7); - ECase(IMAGE_FILE_MACHINE_EBC); - ECase(IMAGE_FILE_MACHINE_I386); - ECase(IMAGE_FILE_MACHINE_IA64); - ECase(IMAGE_FILE_MACHINE_M32R); - ECase(IMAGE_FILE_MACHINE_MIPS16); - ECase(IMAGE_FILE_MACHINE_MIPSFPU); - ECase(IMAGE_FILE_MACHINE_MIPSFPU16); - ECase(IMAGE_FILE_MACHINE_POWERPC); - ECase(IMAGE_FILE_MACHINE_POWERPCFP); - ECase(IMAGE_FILE_MACHINE_R4000); - ECase(IMAGE_FILE_MACHINE_SH3); - ECase(IMAGE_FILE_MACHINE_SH3DSP); - ECase(IMAGE_FILE_MACHINE_SH4); - ECase(IMAGE_FILE_MACHINE_SH5); - ECase(IMAGE_FILE_MACHINE_THUMB); - ECase(IMAGE_FILE_MACHINE_WCEMIPSV2); - } -}; - -template <> -struct ScalarEnumerationTraits<COFF::RelocationTypeX86> { - static void enumeration(IO &IO, COFF::RelocationTypeX86 &Value) { - ECase(IMAGE_REL_I386_ABSOLUTE); - ECase(IMAGE_REL_I386_DIR16); - ECase(IMAGE_REL_I386_REL16); - ECase(IMAGE_REL_I386_DIR32); - ECase(IMAGE_REL_I386_DIR32NB); - ECase(IMAGE_REL_I386_SEG12); - ECase(IMAGE_REL_I386_SECTION); - ECase(IMAGE_REL_I386_SECREL); - ECase(IMAGE_REL_I386_TOKEN); - ECase(IMAGE_REL_I386_SECREL7); - ECase(IMAGE_REL_I386_REL32); - ECase(IMAGE_REL_AMD64_ABSOLUTE); - ECase(IMAGE_REL_AMD64_ADDR64); - ECase(IMAGE_REL_AMD64_ADDR32); - ECase(IMAGE_REL_AMD64_ADDR32NB); - ECase(IMAGE_REL_AMD64_REL32); - ECase(IMAGE_REL_AMD64_REL32_1); - ECase(IMAGE_REL_AMD64_REL32_2); - ECase(IMAGE_REL_AMD64_REL32_3); - ECase(IMAGE_REL_AMD64_REL32_4); - ECase(IMAGE_REL_AMD64_REL32_5); - ECase(IMAGE_REL_AMD64_SECTION); - ECase(IMAGE_REL_AMD64_SECREL); - ECase(IMAGE_REL_AMD64_SECREL7); - ECase(IMAGE_REL_AMD64_TOKEN); - ECase(IMAGE_REL_AMD64_SREL32); - ECase(IMAGE_REL_AMD64_PAIR); - ECase(IMAGE_REL_AMD64_SSPAN32); - } -}; - -#undef ECase - -template <> -struct MappingTraits<COFFYAML::Symbol> { - struct NStorageClass { - NStorageClass(IO&) : StorageClass(COFF::SymbolStorageClass(0)) { - } - NStorageClass(IO&, uint8_t S) : StorageClass(COFF::SymbolStorageClass(S)) { - } - uint8_t denormalize(IO &) { - return StorageClass; - } - - COFF::SymbolStorageClass StorageClass; - }; - - static void mapping(IO &IO, COFFYAML::Symbol &S) { - MappingNormalization<NStorageClass, uint8_t> NS(IO, S.Header.StorageClass); - - IO.mapRequired("SimpleType", S.SimpleType); - IO.mapOptional("NumberOfAuxSymbols", S.Header.NumberOfAuxSymbols); - IO.mapRequired("Name", S.Name); - IO.mapRequired("StorageClass", NS->StorageClass); - IO.mapOptional("AuxiliaryData", S.AuxiliaryData); - IO.mapRequired("ComplexType", S.ComplexType); - IO.mapRequired("Value", S.Header.Value); - IO.mapRequired("SectionNumber", S.Header.SectionNumber); - } -}; - -template <> -struct MappingTraits<COFF::header> { - struct NMachine { - NMachine(IO&) : Machine(COFF::MachineTypes(0)) { - } - NMachine(IO&, uint16_t M) : Machine(COFF::MachineTypes(M)) { - } - uint16_t denormalize(IO &) { - return Machine; - } - COFF::MachineTypes Machine; - }; - - struct NCharacteristics { - NCharacteristics(IO&) : Characteristics(COFF::Characteristics(0)) { - } - NCharacteristics(IO&, uint16_t C) : - Characteristics(COFF::Characteristics(C)) { - } - uint16_t denormalize(IO &) { - return Characteristics; - } - - COFF::Characteristics Characteristics; - }; - - static void mapping(IO &IO, COFF::header &H) { - MappingNormalization<NMachine, uint16_t> NM(IO, H.Machine); - MappingNormalization<NCharacteristics, uint16_t> NC(IO, H.Characteristics); - - IO.mapRequired("Machine", NM->Machine); - IO.mapOptional("Characteristics", NC->Characteristics); - } -}; - -template <> -struct MappingTraits<COFF::relocation> { - struct NType { - NType(IO &) : Type(COFF::RelocationTypeX86(0)) { - } - NType(IO &, uint16_t T) : Type(COFF::RelocationTypeX86(T)) { - } - uint16_t denormalize(IO &) { - return Type; - } - COFF::RelocationTypeX86 Type; - }; - - static void mapping(IO &IO, COFF::relocation &Rel) { - MappingNormalization<NType, uint16_t> NT(IO, Rel.Type); - - IO.mapRequired("Type", NT->Type); - IO.mapRequired("VirtualAddress", Rel.VirtualAddress); - IO.mapRequired("SymbolTableIndex", Rel.SymbolTableIndex); - } -}; - -template <> -struct MappingTraits<COFFYAML::Section> { - struct NCharacteristics { - NCharacteristics(IO &) : Characteristics(COFF::SectionCharacteristics(0)) { - } - NCharacteristics(IO &, uint32_t C) : - Characteristics(COFF::SectionCharacteristics(C)) { - } - uint32_t denormalize(IO &) { - return Characteristics; - } - COFF::SectionCharacteristics Characteristics; - }; - - static void mapping(IO &IO, COFFYAML::Section &Sec) { - MappingNormalization<NCharacteristics, uint32_t> NC(IO, - Sec.Header.Characteristics); - IO.mapOptional("Relocations", Sec.Relocations); - IO.mapRequired("SectionData", Sec.SectionData); - IO.mapRequired("Characteristics", NC->Characteristics); - IO.mapRequired("Name", Sec.Name); - IO.mapOptional("Alignment", Sec.Alignment); - } -}; - -template <> -struct MappingTraits<COFFYAML::Object> { - static void mapping(IO &IO, COFFYAML::Object &Obj) { - IO.mapRequired("sections", Obj.Sections); - IO.mapRequired("header", Obj.Header); - IO.mapRequired("symbols", Obj.Symbols); - } -}; -} // end namespace yaml -} // end namespace llvm int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); @@ -654,27 +60,12 @@ int main(int argc, char **argv) { OwningPtr<MemoryBuffer> Buf; if (MemoryBuffer::getFileOrSTDIN(Input, Buf)) return 1; - - 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, outs())) { - errs() << "yaml2obj: Failed to write COFF file!\n"; + 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 |