diff options
author | Stephen Hines <srhines@google.com> | 2013-08-07 15:07:10 -0700 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2013-08-07 15:07:10 -0700 |
commit | fab2daa4a1127ecb217abe2b07c1769122b6fee1 (patch) | |
tree | 268ebfd1963fd98ba412e76819afdf95a7d4267b /tools | |
parent | 8197ac1c1a0a91baa70c4dea8cb488f254ef974c (diff) | |
parent | 10251753b6897adcd22cc981c0cc42f348c109de (diff) | |
download | external_llvm-fab2daa4a1127ecb217abe2b07c1769122b6fee1.zip external_llvm-fab2daa4a1127ecb217abe2b07c1769122b6fee1.tar.gz external_llvm-fab2daa4a1127ecb217abe2b07c1769122b6fee1.tar.bz2 |
Merge commit '10251753b6897adcd22cc981c0cc42f348c109de' into merge-20130807
Conflicts:
lib/Archive/ArchiveReader.cpp
lib/Support/Unix/PathV2.inc
Change-Id: I29d8c1e321a4a380b6013f00bac6a8e4b593cc4e
Diffstat (limited to 'tools')
64 files changed, 1829 insertions, 1183 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6b7c884..e663781 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -14,7 +14,6 @@ add_subdirectory(llvm-dis) add_subdirectory(llvm-mc) add_subdirectory(llc) -add_subdirectory(llvm-ranlib) add_subdirectory(llvm-ar) add_subdirectory(llvm-nm) add_subdirectory(llvm-size) @@ -59,8 +58,11 @@ if( LLVM_ENABLE_PIC ) endif() add_llvm_external_project(clang) -add_llvm_external_project(lld) -add_llvm_external_project(lldb) -add_llvm_external_project(polly) + +if( NOT LLVM_INCLUDE_TOOLS STREQUAL "bootstrap-only" ) + add_llvm_external_project(lld) + add_llvm_external_project(lldb) + add_llvm_external_project(polly) +endif() set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE) diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index 25aa177..9ec89f3 100644 --- a/tools/LLVMBuild.txt +++ b/tools/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup +subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup [component_0] type = Group diff --git a/tools/Makefile b/tools/Makefile index eaf9ed3..b7375c9 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -28,7 +28,7 @@ OPTIONAL_DIRS := lldb # in parallel builds. Please retain this ordering. DIRS := llvm-config PARALLEL_DIRS := opt llvm-as llvm-dis \ - llc llvm-ranlib llvm-ar llvm-nm \ + llc llvm-ar llvm-nm \ llvm-prof llvm-link \ lli llvm-extract llvm-mc \ bugpoint llvm-bcanalyzer \ 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..c8b4f6f 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -62,25 +62,23 @@ ReducePassList::TestResult ReducePassList::doTest(std::vector<std::string> &Prefix, std::vector<std::string> &Suffix, std::string &Error) { - sys::Path PrefixOutput; + std::string PrefixOutput; Module *OrigProgram = 0; if (!Prefix.empty()) { outs() << "Checking to see if these passes crash: " << getPassesString(Prefix) << ": "; - std::string PfxOutput; - if (BD.runPasses(BD.getProgram(), Prefix, PfxOutput)) + if (BD.runPasses(BD.getProgram(), Prefix, PrefixOutput)) return KeepPrefix; - PrefixOutput.set(PfxOutput); OrigProgram = BD.Program; - BD.Program = ParseInputFile(PrefixOutput.str(), BD.getContext()); + BD.Program = ParseInputFile(PrefixOutput, BD.getContext()); if (BD.Program == 0) { errs() << BD.getToolName() << ": Error reading bitcode file '" - << PrefixOutput.str() << "'!\n"; + << PrefixOutput << "'!\n"; exit(1); } - PrefixOutput.eraseFromDisk(); + sys::fs::remove(PrefixOutput); } outs() << "Checking to see if these passes crash: " diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index da36045..3d3dac3 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -265,16 +265,18 @@ bool BugDriver::initializeExecutionEnvironment() { /// void BugDriver::compileProgram(Module *M, std::string *Error) const { // Emit the program to a bitcode file... - sys::Path BitcodeFile (OutputPrefix + "-test-program.bc"); - std::string ErrMsg; - if (BitcodeFile.makeUnique(true, &ErrMsg)) { - errs() << ToolName << ": Error making unique filename: " << ErrMsg + SmallString<128> BitcodeFile; + int BitcodeFD; + error_code EC = sys::fs::createUniqueFile( + OutputPrefix + "-test-program-%%%%%%%.bc", BitcodeFD, BitcodeFile); + if (EC) { + errs() << ToolName << ": Error making unique filename: " << EC.message() << "\n"; exit(1); } - if (writeProgramToFile(BitcodeFile.str(), M)) { - errs() << ToolName << ": Error emitting bitcode to file '" - << BitcodeFile.str() << "'!\n"; + if (writeProgramToFile(BitcodeFile.str(), BitcodeFD, M)) { + errs() << ToolName << ": Error emitting bitcode to file '" << BitcodeFile + << "'!\n"; exit(1); } @@ -302,15 +304,18 @@ std::string BugDriver::executeProgram(const Module *Program, std::string ErrMsg; if (BitcodeFile.empty()) { // Emit the program to a bitcode file... - sys::Path uniqueFilename(OutputPrefix + "-test-program.bc"); - if (uniqueFilename.makeUnique(true, &ErrMsg)) { + SmallString<128> UniqueFilename; + int UniqueFD; + error_code EC = sys::fs::createUniqueFile( + OutputPrefix + "-test-program-%%%%%%%.bc", UniqueFD, UniqueFilename); + if (EC) { errs() << ToolName << ": Error making unique filename: " - << ErrMsg << "!\n"; + << EC.message() << "!\n"; exit(1); } - BitcodeFile = uniqueFilename.str(); + BitcodeFile = UniqueFilename.str(); - if (writeProgramToFile(BitcodeFile, Program)) { + if (writeProgramToFile(BitcodeFile, UniqueFD, Program)) { errs() << ToolName << ": Error emitting bitcode to file '" << BitcodeFile << "'!\n"; exit(1); @@ -319,20 +324,21 @@ std::string BugDriver::executeProgram(const Module *Program, } // Remove the temporary bitcode file when we are done. - sys::Path BitcodePath(BitcodeFile); - FileRemover BitcodeFileRemover(BitcodePath.str(), + std::string BitcodePath(BitcodeFile); + FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode && !SaveTemps); - if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output"; + if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output-%%%%%%%"; // Check to see if this is a valid output filename... - sys::Path uniqueFile(OutputFile); - if (uniqueFile.makeUnique(true, &ErrMsg)) { + SmallString<128> UniqueFile; + error_code EC = sys::fs::createUniqueFile(OutputFile, UniqueFile); + if (EC) { errs() << ToolName << ": Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - OutputFile = uniqueFile.str(); + OutputFile = UniqueFile.str(); // Figure out which shared objects to run, if any. std::vector<std::string> SharedObjs(AdditionalSOs); @@ -380,7 +386,7 @@ std::string BugDriver::executeProgramSafely(const Module *Program, std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, std::string &Error) { assert(Interpreter && "Interpreter should have been created already!"); - sys::Path OutputFile; + std::string OutputFile; // Using the known-good backend. GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile, @@ -389,7 +395,7 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, return ""; std::string SharedObjectFile; - bool Failure = gcc->MakeSharedObject(OutputFile.str(), FT, SharedObjectFile, + bool Failure = gcc->MakeSharedObject(OutputFile, FT, SharedObjectFile, AdditionalLinkerArgs, Error); if (!Error.empty()) return ""; @@ -397,7 +403,7 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, exit(1); // Remove the intermediate C file - OutputFile.eraseFromDisk(); + sys::fs::remove(OutputFile); return "./" + SharedObjectFile; } @@ -439,15 +445,15 @@ bool BugDriver::diffProgram(const Module *Program, bool RemoveBitcode, std::string *ErrMsg) const { // Execute the program, generating an output file... - sys::Path Output(executeProgram(Program, "", BitcodeFile, SharedObject, 0, - ErrMsg)); + std::string Output( + executeProgram(Program, "", BitcodeFile, SharedObject, 0, ErrMsg)); if (!ErrMsg->empty()) return false; std::string Error; bool FilesDifferent = false; - if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile), - sys::Path(Output.str()), + if (int Diff = DiffFilesWithTolerance(ReferenceOutputFile, + Output, AbsTolerance, RelTolerance, &Error)) { if (Diff == 2) { errs() << "While diffing output: " << Error << '\n'; @@ -457,12 +463,12 @@ bool BugDriver::diffProgram(const Module *Program, } else { // Remove the generated output if there are no differences. - Output.eraseFromDisk(); + sys::fs::remove(Output); } // Remove the bitcode file if we are supposed to. if (RemoveBitcode) - sys::Path(BitcodeFile).eraseFromDisk(); + sys::fs::remove(BitcodeFile); return FilesDifferent; } diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index bb27767..2098928 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -363,25 +363,19 @@ llvm::SplitFunctionsOutOfModule(Module *M, Module *BugDriver::ExtractMappedBlocksFromModule(const std::vector<BasicBlock*> &BBs, Module *M) { - sys::Path uniqueFilename(OutputPrefix + "-extractblocks"); - std::string ErrMsg; - if (uniqueFilename.createTemporaryFileOnDisk(true, &ErrMsg)) { + SmallString<128> Filename; + int FD; + error_code EC = sys::fs::createUniqueFile( + OutputPrefix + "-extractblocks%%%%%%%", FD, Filename); + if (EC) { outs() << "*** Basic Block extraction failed!\n"; - errs() << "Error creating temporary file: " << ErrMsg << "\n"; + errs() << "Error creating temporary file: " << EC.message() << "\n"; EmitProgressBitcode(M, "basicblockextractfail", true); return 0; } - sys::RemoveFileOnSignal(uniqueFilename); + sys::RemoveFileOnSignal(Filename); - std::string ErrorInfo; - tool_output_file BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo); - if (!ErrorInfo.empty()) { - outs() << "*** Basic Block extraction failed!\n"; - errs() << "Error writing list of blocks to not extract: " << ErrorInfo - << "\n"; - EmitProgressBitcode(M, "basicblockextractfail", true); - return 0; - } + tool_output_file BlocksToNotExtractFile(Filename.c_str(), FD); for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end(); I != E; ++I) { BasicBlock *BB = *I; @@ -393,22 +387,22 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const } BlocksToNotExtractFile.os().close(); if (BlocksToNotExtractFile.os().has_error()) { - errs() << "Error writing list of blocks to not extract: " << ErrorInfo - << "\n"; + errs() << "Error writing list of blocks to not extract\n"; EmitProgressBitcode(M, "basicblockextractfail", true); BlocksToNotExtractFile.os().clear_error(); return 0; } BlocksToNotExtractFile.keep(); - std::string uniqueFN = "--extract-blocks-file=" + uniqueFilename.str(); + std::string uniqueFN = "--extract-blocks-file="; + uniqueFN += Filename.str(); const char *ExtraArg = uniqueFN.c_str(); std::vector<std::string> PI; PI.push_back("extract-blocks"); Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg); - uniqueFilename.eraseFromDisk(); // Free disk space + sys::fs::remove(Filename.c_str()); if (Ret == 0) { outs() << "*** Basic Block extraction failed, please report a bug!\n"; diff --git a/tools/bugpoint/FindBugs.cpp b/tools/bugpoint/FindBugs.cpp index a291f9f..e2941f6 100644 --- a/tools/bugpoint/FindBugs.cpp +++ b/tools/bugpoint/FindBugs.cpp @@ -17,6 +17,7 @@ #include "BugDriver.h" #include "ToolRunner.h" #include "llvm/Pass.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <ctime> @@ -103,7 +104,7 @@ bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses, } outs() << "\n*** diff'd output matches!\n"; - sys::Path(Filename).eraseFromDisk(); + sys::fs::remove(Filename); outs() << "\n\n"; num++; diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index 11ac0de..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! @@ -135,7 +135,7 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, << BitcodeResult << "'!\n"; exit(1); } - sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk + sys::fs::remove(BitcodeResult); // Don't check if there are no passes in the suffix. if (Suffix.empty()) @@ -337,8 +337,13 @@ static bool ExtractLoops(BugDriver &BD, false, Error, Failure); if (!New) return false; + // Delete the original and set the new program. - delete BD.swapProgramIn(New); + Module *Old = BD.swapProgramIn(New); + for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) + MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); + delete Old; + if (Failure) { BD.switchToInterpreter(AI); @@ -366,21 +371,51 @@ static bool ExtractLoops(BugDriver &BD, outs() << " Testing after loop extraction:\n"; // Clone modules, the tester function will free them. - Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted); - Module *TNOBackup = CloneModule(ToNotOptimize); + Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted, VMap); + Module *TNOBackup = CloneModule(ToNotOptimize, VMap); + + for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) + MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]); + Failure = TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize, Error); if (!Error.empty()) return false; + + ToOptimizeLoopExtracted = TOLEBackup; + ToNotOptimize = TNOBackup; + if (!Failure) { outs() << "*** Loop extraction masked the problem. Undoing.\n"; // If the program is not still broken, then loop extraction did something // that masked the error. Stop loop extraction now. - delete TOLEBackup; - delete TNOBackup; + + std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions; + for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) { + Function *F = MiscompiledFunctions[i]; + MisCompFunctions.push_back(std::make_pair(F->getName(), + F->getFunctionType())); + } + + std::string ErrorMsg; + if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted, + Linker::DestroySource, &ErrorMsg)){ + errs() << BD.getToolName() << ": Error linking modules together:" + << ErrorMsg << '\n'; + exit(1); + } + + MiscompiledFunctions.clear(); + for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { + Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); + + assert(NewF && "Function not found??"); + MiscompiledFunctions.push_back(NewF); + } + + delete ToOptimizeLoopExtracted; + BD.setNewProgram(ToNotOptimize); return MadeChange; } - ToOptimizeLoopExtracted = TOLEBackup; - ToNotOptimize = TNOBackup; outs() << "*** Loop extraction successful!\n"; @@ -926,14 +961,16 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, std::string &Error) { CleanupAndPrepareModules(BD, Test, Safe); - sys::Path TestModuleBC("bugpoint.test.bc"); - std::string ErrMsg; - if (TestModuleBC.makeUnique(true, &ErrMsg)) { + SmallString<128> TestModuleBC; + int TestModuleFD; + error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc", + TestModuleFD, TestModuleBC); + if (EC) { errs() << BD.getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - if (BD.writeProgramToFile(TestModuleBC.str(), Test)) { + if (BD.writeProgramToFile(TestModuleBC.str(), TestModuleFD, Test)) { errs() << "Error writing bitcode to `" << TestModuleBC.str() << "'\nExiting."; exit(1); @@ -943,14 +980,17 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, FileRemover TestModuleBCRemover(TestModuleBC.str(), !SaveTemps); // Make the shared library - sys::Path SafeModuleBC("bugpoint.safe.bc"); - if (SafeModuleBC.makeUnique(true, &ErrMsg)) { + SmallString<128> SafeModuleBC; + int SafeModuleFD; + EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD, + SafeModuleBC); + if (EC) { errs() << BD.getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - if (BD.writeProgramToFile(SafeModuleBC.str(), Safe)) { + if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe)) { errs() << "Error writing bitcode to `" << SafeModuleBC.str() << "'\nExiting."; exit(1); @@ -1015,15 +1055,17 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { // Condition the modules CleanupAndPrepareModules(*this, ToCodeGen, ToNotCodeGen); - sys::Path TestModuleBC("bugpoint.test.bc"); - std::string ErrMsg; - if (TestModuleBC.makeUnique(true, &ErrMsg)) { + SmallString<128> TestModuleBC; + int TestModuleFD; + error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc", + TestModuleFD, TestModuleBC); + if (EC) { errs() << getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - if (writeProgramToFile(TestModuleBC.str(), ToCodeGen)) { + if (writeProgramToFile(TestModuleBC.str(), TestModuleFD, ToCodeGen)) { errs() << "Error writing bitcode to `" << TestModuleBC.str() << "'\nExiting."; exit(1); @@ -1031,14 +1073,17 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { delete ToCodeGen; // Make the shared library - sys::Path SafeModuleBC("bugpoint.safe.bc"); - if (SafeModuleBC.makeUnique(true, &ErrMsg)) { + SmallString<128> SafeModuleBC; + int SafeModuleFD; + EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD, + SafeModuleBC); + if (EC) { errs() << getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + << EC.message() << "\n"; exit(1); } - if (writeProgramToFile(SafeModuleBC.str(), ToNotCodeGen)) { + if (writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, ToNotCodeGen)) { errs() << "Error writing bitcode to `" << SafeModuleBC.str() << "'\nExiting."; exit(1); diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index 87dc9f3..20c609c 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/PluginLoader.h" #include <fstream> + using namespace llvm; namespace llvm { @@ -43,25 +44,36 @@ namespace { // ChildOutput - This option captures the name of the child output file that // is set up by the parent bugpoint process cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden); + cl::opt<std::string> OptCmd("opt-command", cl::init(""), + cl::desc("Path to opt. (default: search path " + "for 'opt'.)")); } /// writeProgramToFile - This writes the current "Program" to the named bitcode /// file. If an error occurs, true is returned. /// +static bool writeProgramToFileAux(tool_output_file &Out, const Module *M) { + WriteBitcodeToFile(M, Out.os()); + Out.os().close(); + if (!Out.os().has_error()) { + Out.keep(); + return false; + } + return true; +} + +bool BugDriver::writeProgramToFile(const std::string &Filename, int FD, + const Module *M) const { + tool_output_file Out(Filename.c_str(), FD); + return writeProgramToFileAux(Out, M); +} + bool BugDriver::writeProgramToFile(const std::string &Filename, const Module *M) const { std::string ErrInfo; - tool_output_file Out(Filename.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); - if (ErrInfo.empty()) { - WriteBitcodeToFile(M, Out.os()); - Out.os().close(); - if (!Out.os().has_error()) { - Out.keep(); - return false; - } - } - Out.os().clear_error(); + tool_output_file Out(Filename.c_str(), ErrInfo, sys::fs::F_Binary); + if (ErrInfo.empty()) + return writeProgramToFileAux(Out, M); return true; } @@ -114,41 +126,38 @@ bool BugDriver::runPasses(Module *Program, const char * const *ExtraArgs) const { // setup the output file name outs().flush(); - sys::Path uniqueFilename(OutputPrefix + "-output.bc"); - std::string ErrMsg; - if (uniqueFilename.makeUnique(true, &ErrMsg)) { + SmallString<128> UniqueFilename; + error_code EC = sys::fs::createUniqueFile( + OutputPrefix + "-output-%%%%%%%.bc", UniqueFilename); + if (EC) { errs() << getToolName() << ": Error making unique filename: " - << ErrMsg << "\n"; - return(1); + << EC.message() << "\n"; + return 1; } - OutputFilename = uniqueFilename.str(); + OutputFilename = UniqueFilename.str(); // set up the input file name - sys::Path inputFilename(OutputPrefix + "-input.bc"); - if (inputFilename.makeUnique(true, &ErrMsg)) { + SmallString<128> InputFilename; + int InputFD; + EC = sys::fs::createUniqueFile(OutputPrefix + "-input-%%%%%%%.bc", InputFD, + InputFilename); + if (EC) { errs() << getToolName() << ": Error making unique filename: " - << ErrMsg << "\n"; - return(1); + << EC.message() << "\n"; + return 1; } - std::string ErrInfo; - tool_output_file InFile(inputFilename.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); - + tool_output_file InFile(InputFilename.c_str(), InputFD); - if (!ErrInfo.empty()) { - errs() << "Error opening bitcode file: " << inputFilename.str() << "\n"; - return 1; - } WriteBitcodeToFile(Program, InFile.os()); InFile.os().close(); if (InFile.os().has_error()) { - errs() << "Error writing bitcode file: " << inputFilename.str() << "\n"; + errs() << "Error writing bitcode file: " << InputFilename << "\n"; InFile.os().clear_error(); return 1; } - sys::Path tool = sys::Program::FindProgramByName("opt"); + std::string tool = OptCmd.empty()? sys::FindProgramByName("opt") : OptCmd; if (tool.empty()) { errs() << "Cannot find `opt' in PATH!\n"; return 1; @@ -159,14 +168,13 @@ bool BugDriver::runPasses(Module *Program, // setup the child process' arguments SmallVector<const char*, 8> Args; - std::string Opt = tool.str(); if (UseValgrind) { Args.push_back("valgrind"); Args.push_back("--error-exitcode=1"); Args.push_back("-q"); Args.push_back(tool.c_str()); } else - Args.push_back(Opt.c_str()); + Args.push_back(tool.c_str()); Args.push_back("-o"); Args.push_back(OutputFilename.c_str()); @@ -183,7 +191,7 @@ bool BugDriver::runPasses(Module *Program, for (std::vector<std::string>::const_iterator I = pass_args.begin(), E = pass_args.end(); I != E; ++I ) Args.push_back(I->c_str()); - Args.push_back(inputFilename.c_str()); + Args.push_back(InputFilename.c_str()); for (unsigned i = 0; i < NumExtraArgs; ++i) Args.push_back(*ExtraArgs); Args.push_back(0); @@ -194,27 +202,28 @@ bool BugDriver::runPasses(Module *Program, errs() << "\n"; ); - sys::Path prog; + std::string Prog; if (UseValgrind) - prog = sys::Program::FindProgramByName("valgrind"); + Prog = sys::FindProgramByName("valgrind"); else - prog = tool; + Prog = tool; // Redirect stdout and stderr to nowhere if SilencePasses is given - sys::Path Nowhere; - const sys::Path *Redirects[3] = {0, &Nowhere, &Nowhere}; + StringRef Nowhere; + const StringRef *Redirects[3] = {0, &Nowhere, &Nowhere}; - int result = sys::Program::ExecuteAndWait(prog, Args.data(), 0, - (SilencePasses ? Redirects : 0), - Timeout, MemoryLimit, &ErrMsg); + std::string ErrMsg; + int result = sys::ExecuteAndWait(Prog, Args.data(), 0, + (SilencePasses ? Redirects : 0), Timeout, + MemoryLimit, &ErrMsg); // If we are supposed to delete the bitcode file or if the passes crashed, // remove it now. This may fail if the file was never created, but that's ok. if (DeleteOutput || result != 0) - sys::Path(OutputFilename).eraseFromDisk(); + sys::fs::remove(OutputFilename); // Remove the temporary input file as well - inputFilename.eraseFromDisk(); + sys::fs::remove(InputFilename.c_str()); if (!Quiet) { if (result == 0) @@ -262,6 +271,6 @@ Module *BugDriver::runPassesOn(Module *M, << BitcodeResult << "'!\n"; exit(1); } - sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk + sys::fs::remove(BitcodeResult); return Ret; } diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 735061d..107d0db 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -16,6 +16,7 @@ #include "llvm/Config/config.h" // for HAVE_LINK_R #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" @@ -53,18 +54,15 @@ namespace { /// RunProgramWithTimeout - This function provides an alternate interface /// to the sys::Program::ExecuteAndWait interface. /// @see sys::Program::ExecuteAndWait -static int RunProgramWithTimeout(const sys::Path &ProgramPath, +static int RunProgramWithTimeout(StringRef ProgramPath, const char **Args, - const sys::Path &StdInFile, - const sys::Path &StdOutFile, - const sys::Path &StdErrFile, + StringRef StdInFile, + StringRef StdOutFile, + StringRef StdErrFile, unsigned NumSeconds = 0, unsigned MemoryLimit = 0, std::string *ErrMsg = 0) { - const sys::Path* redirects[3]; - redirects[0] = &StdInFile; - redirects[1] = &StdOutFile; - redirects[2] = &StdErrFile; + const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile }; #if 0 // For debug purposes { @@ -75,9 +73,8 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath, } #endif - return - sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, - NumSeconds, MemoryLimit, ErrMsg); + return sys::ExecuteAndWait(ProgramPath, Args, 0, Redirects, + NumSeconds, MemoryLimit, ErrMsg); } /// RunProgramRemotelyWithTimeout - This function runs the given program @@ -86,17 +83,14 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath, /// fails. Remote client is required to return 255 if it failed or program exit /// code otherwise. /// @see sys::Program::ExecuteAndWait -static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, +static int RunProgramRemotelyWithTimeout(StringRef RemoteClientPath, const char **Args, - const sys::Path &StdInFile, - const sys::Path &StdOutFile, - const sys::Path &StdErrFile, + StringRef StdInFile, + StringRef StdOutFile, + StringRef StdErrFile, unsigned NumSeconds = 0, unsigned MemoryLimit = 0) { - const sys::Path* redirects[3]; - redirects[0] = &StdInFile; - redirects[1] = &StdOutFile; - redirects[2] = &StdErrFile; + const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile }; #if 0 // For debug purposes { @@ -108,8 +102,8 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, #endif // Run the program remotely with the remote client - int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args, - 0, redirects, NumSeconds, MemoryLimit); + int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, 0, + Redirects, NumSeconds, MemoryLimit); // Has the remote client fail? if (255 == ReturnCode) { @@ -120,7 +114,8 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, OS << "\n"; // The error message is in the output file, let's print it out from there. - std::ifstream ErrorFile(StdOutFile.c_str()); + std::string StdOutFileName = StdOutFile.str(); + std::ifstream ErrorFile(StdOutFileName.c_str()); if (ErrorFile) { std::copy(std::istreambuf_iterator<char>(ErrorFile), std::istreambuf_iterator<char>(), @@ -134,7 +129,7 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, return ReturnCode; } -static std::string ProcessFailure(sys::Path ProgPath, const char** Args, +static std::string ProcessFailure(StringRef ProgPath, const char** Args, unsigned Timeout = 0, unsigned MemoryLimit = 0) { std::ostringstream OS; @@ -144,14 +139,16 @@ static std::string ProcessFailure(sys::Path ProgPath, const char** Args, OS << "\n"; // Rerun the compiler, capturing any error messages to print them. - sys::Path ErrorFilename("bugpoint.program_error_messages"); - std::string ErrMsg; - if (ErrorFilename.makeUnique(true, &ErrMsg)) { - errs() << "Error making unique filename: " << ErrMsg << "\n"; + SmallString<128> ErrorFilename; + int ErrorFD; + error_code EC = sys::fs::createTemporaryFile( + "bugpoint.program_error_messages", "", ErrorFD, ErrorFilename); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } - RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename, - ErrorFilename, Timeout, MemoryLimit); + RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(), + ErrorFilename.str(), Timeout, MemoryLimit); // FIXME: check return code ? // Print out the error messages generated by GCC if possible... @@ -163,7 +160,7 @@ static std::string ProcessFailure(sys::Path ProgPath, const char** Args, ErrorFile.close(); } - ErrorFilename.eraseFromDisk(); + sys::fs::remove(ErrorFilename.c_str()); return OS.str(); } @@ -229,19 +226,50 @@ int LLI::ExecuteProgram(const std::string &Bitcode, errs() << " " << LLIArgs[i]; errs() << "\n"; ); - return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0], - sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), + return RunProgramWithTimeout(LLIPath, &LLIArgs[0], + InputFile, OutputFile, OutputFile, Timeout, MemoryLimit, Error); } void AbstractInterpreter::anchor() { } +#if defined(LLVM_ON_UNIX) +const char EXESuffix[] = ""; +#elif defined (LLVM_ON_WIN32) +const char EXESuffix[] = "exe"; +#endif + +/// Prepend the path to the program being executed +/// to \p ExeName, given the value of argv[0] and the address of main() +/// itself. This allows us to find another LLVM tool if it is built in the same +/// directory. An empty string is returned on error; note that this function +/// just mainpulates the path and doesn't check for executability. +/// @brief Find a named executable. +static std::string PrependMainExecutablePath(const std::string &ExeName, + const char *Argv0, + void *MainAddr) { + // Check the directory that the calling program is in. We can do + // this if ProgramPath contains at least one / character, indicating that it + // is a relative path to the executable itself. + std::string Main = sys::fs::getMainExecutable(Argv0, MainAddr); + StringRef Result = sys::path::parent_path(Main); + + if (!Result.empty()) { + SmallString<128> Storage = Result; + sys::path::append(Storage, ExeName); + sys::path::replace_extension(Storage, EXESuffix); + return Storage.str(); + } + + return Result.str(); +} + // LLI create method - Try to find the LLI executable AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0, std::string &Message, const std::vector<std::string> *ToolArgs) { std::string LLIPath = - PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createLLI).str(); + PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t) & createLLI); if (!LLIPath.empty()) { Message = "Found lli: " + LLIPath + "\n"; return new LLI(LLIPath, ToolArgs); @@ -305,10 +333,10 @@ void CustomCompiler::compileProgram(const std::string &Bitcode, for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i) ProgramArgs.push_back(CompilerArgs[i].c_str()); - if (RunProgramWithTimeout( sys::Path(CompilerCommand), &ProgramArgs[0], - sys::Path(), sys::Path(), sys::Path(), + if (RunProgramWithTimeout(CompilerCommand, &ProgramArgs[0], + "", "", "", Timeout, MemoryLimit, Error)) - *Error = ProcessFailure(sys::Path(CompilerCommand), &ProgramArgs[0], + *Error = ProcessFailure(CompilerCommand, &ProgramArgs[0], Timeout, MemoryLimit); } @@ -363,9 +391,9 @@ int CustomExecutor::ExecuteProgram(const std::string &Bitcode, ProgramArgs.push_back(Args[i].c_str()); return RunProgramWithTimeout( - sys::Path(ExecutionCommand), - &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), - sys::Path(OutputFile), Timeout, MemoryLimit, Error); + ExecutionCommand, + &ProgramArgs[0], InputFile, OutputFile, + OutputFile, Timeout, MemoryLimit, Error); } // Tokenize the CommandLine to the command and the args to allow @@ -398,7 +426,7 @@ static void lexCommand(std::string &Message, const std::string &CommandLine, pos = CommandLine.find_first_of(delimiters, lastPos); } - CmdPath = sys::Program::FindProgramByName(Command).str(); + CmdPath = sys::FindProgramByName(Command); if (CmdPath.empty()) { Message = std::string("Cannot find '") + Command + @@ -444,16 +472,18 @@ AbstractInterpreter *AbstractInterpreter::createCustomExecutor( // LLC Implementation of AbstractIntepreter interface // GCC::FileType LLC::OutputCode(const std::string &Bitcode, - sys::Path &OutputAsmFile, std::string &Error, + std::string &OutputAsmFile, std::string &Error, unsigned Timeout, unsigned MemoryLimit) { const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); - sys::Path uniqueFile(Bitcode + Suffix); - std::string ErrMsg; - if (uniqueFile.makeUnique(true, &ErrMsg)) { - errs() << "Error making unique filename: " << ErrMsg << "\n"; + + SmallString<128> UniqueFile; + error_code EC = + sys::fs::createUniqueFile(Bitcode + "-%%%%%%%" + Suffix, UniqueFile); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } - OutputAsmFile = uniqueFile; + OutputAsmFile = UniqueFile.str(); std::vector<const char *> LLCArgs; LLCArgs.push_back(LLCPath.c_str()); @@ -477,19 +507,19 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, errs() << " " << LLCArgs[i]; errs() << "\n"; ); - if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0], - sys::Path(), sys::Path(), sys::Path(), + if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], + "", "", "", Timeout, MemoryLimit)) - Error = ProcessFailure(sys::Path(LLCPath), &LLCArgs[0], + Error = ProcessFailure(LLCPath, &LLCArgs[0], Timeout, MemoryLimit); return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; } void LLC::compileProgram(const std::string &Bitcode, std::string *Error, unsigned Timeout, unsigned MemoryLimit) { - sys::Path OutputAsmFile; + std::string OutputAsmFile; OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit); - OutputAsmFile.eraseFromDisk(); + sys::fs::remove(OutputAsmFile); } int LLC::ExecuteProgram(const std::string &Bitcode, @@ -502,16 +532,16 @@ int LLC::ExecuteProgram(const std::string &Bitcode, unsigned Timeout, unsigned MemoryLimit) { - sys::Path OutputAsmFile; + std::string OutputAsmFile; GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit); - FileRemover OutFileRemover(OutputAsmFile.str(), !SaveTemps); + FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); std::vector<std::string> GCCArgs(ArgsForGCC); GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); // Assuming LLC worked, compile the result with GCC and run it. - return gcc->ExecuteProgram(OutputAsmFile.str(), Args, FileKind, + return gcc->ExecuteProgram(OutputAsmFile, Args, FileKind, InputFile, OutputFile, Error, GCCArgs, Timeout, MemoryLimit); } @@ -525,7 +555,7 @@ LLC *AbstractInterpreter::createLLC(const char *Argv0, const std::vector<std::string> *GCCArgs, bool UseIntegratedAssembler) { std::string LLCPath = - PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t)&createLLC).str(); + PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t) & createLLC); if (LLCPath.empty()) { Message = "Cannot find `llc' in executable directory!\n"; return 0; @@ -603,8 +633,8 @@ int JIT::ExecuteProgram(const std::string &Bitcode, errs() << "\n"; ); DEBUG(errs() << "\nSending output to " << OutputFile << "\n"); - return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0], - sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), + return RunProgramWithTimeout(LLIPath, &JITArgs[0], + InputFile, OutputFile, OutputFile, Timeout, MemoryLimit, Error); } @@ -613,7 +643,7 @@ int JIT::ExecuteProgram(const std::string &Bitcode, AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0, std::string &Message, const std::vector<std::string> *Args) { std::string LLIPath = - PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createJIT).str(); + PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t) & createJIT); if (!LLIPath.empty()) { Message = "Found lli: " + LLIPath + "\n"; return new JIT(LLIPath, Args); @@ -682,10 +712,12 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, GCCArgs.push_back("-x"); GCCArgs.push_back("none"); GCCArgs.push_back("-o"); - sys::Path OutputBinary (ProgramFile+".gcc.exe"); - std::string ErrMsg; - if (OutputBinary.makeUnique(true, &ErrMsg)) { - errs() << "Error making unique filename: " << ErrMsg << "\n"; + + SmallString<128> OutputBinary; + error_code EC = + sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.gcc.exe", OutputBinary); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file... @@ -712,8 +744,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, errs() << " " << GCCArgs[i]; errs() << "\n"; ); - if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), - sys::Path())) { + if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "", "", "")) { *Error = ProcessFailure(GCCPath, &GCCArgs[0]); return -1; } @@ -724,7 +755,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, // ProgramArgs is used. std::string Exec; - if (RemoteClientPath.isEmpty()) + if (RemoteClientPath.empty()) ProgramArgs.push_back(OutputBinary.c_str()); else { ProgramArgs.push_back(RemoteClientPath.c_str()); @@ -766,11 +797,11 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps); - if (RemoteClientPath.isEmpty()) { + if (RemoteClientPath.empty()) { DEBUG(errs() << "<run locally>"); - int ExitCode = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], - sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), - Timeout, MemoryLimit, Error); + int ExitCode = RunProgramWithTimeout(OutputBinary.str(), &ProgramArgs[0], + InputFile, OutputFile, OutputFile, + Timeout, MemoryLimit, Error); // Treat a signal (usually SIGSEGV) or timeout as part of the program output // so that crash-causing miscompilation is handled seamlessly. if (ExitCode < -1) { @@ -782,9 +813,9 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, return ExitCode; } else { outs() << "<run remotely>"; outs().flush(); - return RunProgramRemotelyWithTimeout(sys::Path(RemoteClientPath), - &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), - sys::Path(OutputFile), Timeout, MemoryLimit); + return RunProgramRemotelyWithTimeout(RemoteClientPath, + &ProgramArgs[0], InputFile, OutputFile, + OutputFile, Timeout, MemoryLimit); } } @@ -792,13 +823,14 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, std::string &OutputFile, const std::vector<std::string> &ArgsForGCC, std::string &Error) { - sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT); - std::string ErrMsg; - if (uniqueFilename.makeUnique(true, &ErrMsg)) { - errs() << "Error making unique filename: " << ErrMsg << "\n"; + SmallString<128> UniqueFilename; + error_code EC = sys::fs::createUniqueFile( + InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename); + if (EC) { + errs() << "Error making unique filename: " << EC.message() << "\n"; exit(1); } - OutputFile = uniqueFilename.str(); + OutputFile = UniqueFilename.str(); std::vector<const char*> GCCArgs; @@ -862,8 +894,7 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, errs() << " " << GCCArgs[i]; errs() << "\n"; ); - if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), - sys::Path())) { + if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "", "", "")) { Error = ProcessFailure(GCCPath, &GCCArgs[0]); return 1; } @@ -875,16 +906,16 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, GCC *GCC::create(std::string &Message, const std::string &GCCBinary, const std::vector<std::string> *Args) { - sys::Path GCCPath = sys::Program::FindProgramByName(GCCBinary); - if (GCCPath.isEmpty()) { + std::string GCCPath = sys::FindProgramByName(GCCBinary); + if (GCCPath.empty()) { Message = "Cannot find `"+ GCCBinary +"' in PATH!\n"; return 0; } - sys::Path RemoteClientPath; + std::string RemoteClientPath; if (!RemoteClient.empty()) - RemoteClientPath = sys::Program::FindProgramByName(RemoteClient); + RemoteClientPath = sys::FindProgramByName(RemoteClient); - Message = "Found gcc: " + GCCPath.str() + "\n"; + Message = "Found gcc: " + GCCPath + "\n"; return new GCC(GCCPath, RemoteClientPath, Args); } diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h index 28c09f5..bc2be46 100644 --- a/tools/bugpoint/ToolRunner.h +++ b/tools/bugpoint/ToolRunner.h @@ -21,7 +21,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" -#include "llvm/Support/PathV1.h" #include "llvm/Support/SystemUtils.h" #include <exception> #include <vector> @@ -31,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; @@ -89,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, @@ -127,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!"; @@ -153,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 { @@ -239,7 +188,7 @@ public: /// fails, it sets Error, otherwise, this function returns the type of code /// emitted. virtual GCC::FileType OutputCode(const std::string &Bitcode, - sys::Path &OutFile, std::string &Error, + std::string &OutFile, std::string &Error, unsigned Timeout = 0, unsigned MemoryLimit = 0); }; diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 40f5fd6..7771709 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -17,6 +17,7 @@ #include "llvm-c/lto.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/Errno.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -64,7 +65,7 @@ namespace { lto_codegen_model output_type = LTO_CODEGEN_PIC_MODEL_STATIC; std::string output_name = ""; std::list<claimed_file> Modules; - std::vector<sys::Path> Cleanup; + std::vector<std::string> Cleanup; lto_code_gen_t code_gen = NULL; } @@ -251,9 +252,8 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, if (file->offset) { offset = file->offset; } - if (error_code ec = - MemoryBuffer::getOpenFile(file->fd, file->name, buffer, file->filesize, - -1, offset, false)) { + if (error_code ec = MemoryBuffer::getOpenFileSlice( + file->fd, file->name, buffer, file->filesize, offset)) { (*message)(LDPL_ERROR, ec.message().c_str()); return LDPS_ERR; } @@ -447,18 +447,18 @@ static ld_plugin_status all_symbols_read_hook(void) { } if (options::obj_path.empty()) - Cleanup.push_back(sys::Path(objPath)); + Cleanup.push_back(objPath); return LDPS_OK; } static ld_plugin_status cleanup_hook(void) { - std::string ErrMsg; - - for (int i = 0, e = Cleanup.size(); i != e; ++i) - if (Cleanup[i].eraseFromDisk(false, &ErrMsg)) + for (int i = 0, e = Cleanup.size(); i != e; ++i) { + error_code EC = sys::fs::remove(Cleanup[i]); + if (EC) (*message)(LDPL_ERROR, "Failed to delete '%s': %s", Cleanup[i].c_str(), - ErrMsg.c_str()); + EC.message().c_str()); + } return LDPS_OK; } diff --git a/tools/llc/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..98f411d 100644 --- a/tools/lli/CMakeLists.txt +++ b/tools/lli/CMakeLists.txt @@ -1,5 +1,5 @@ -set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native) +set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native instrumentation) if( LLVM_USE_OPROFILE ) set(LLVM_LINK_COMPONENTS diff --git a/tools/lli/LLVMBuild.txt b/tools/lli/LLVMBuild.txt index 5823792..c96a9e8 100644 --- a/tools/lli/LLVMBuild.txt +++ b/tools/lli/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = lli parent = Tools -required_libraries = AsmParser BitReader 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..7a40427 100644 --- a/tools/lli/Makefile +++ b/tools/lli/Makefile @@ -12,7 +12,7 @@ TOOLNAME := lli include $(LEVEL)/Makefile.config -LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser 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/lli.cpp b/tools/lli/lli.cpp index 031f945..8d74b23 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -45,6 +45,7 @@ #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 +72,10 @@ namespace { "use-mcjit", cl::desc("Enable use of the MC-based JIT (if available)"), cl::init(false)); + cl::opt<bool> DebugIR( + "debug-ir", cl::desc("Generate debug information to allow debugging IR."), + cl::init(false)); + // The MCJIT supports building for a target address space separate from // the JIT compilation process. Use a forked process and a copying // memory manager with IPC to execute using this functionality. @@ -321,6 +326,17 @@ int main(int argc, char **argv, char * const *envp) { } } + if (DebugIR) { + if (!UseMCJIT) { + errs() << "warning: -debug-ir used without -use-mcjit. Only partial debug" + << " information will be emitted by the non-MC JIT engine. To see full" + << " source debug information, enable the flag '-use-mcjit'.\n"; + + } + ModulePass *DebugIRPass = createDebugIRPass(); + DebugIRPass->runOnModule(*Mod); + } + EngineBuilder builder(Mod); builder.setMArch(MArch); builder.setMCPU(MCPU); diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index 70eb760..503999c 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS archive) +set(LLVM_LINK_COMPONENTS support object bitreader) add_llvm_tool(llvm-ar llvm-ar.cpp diff --git a/tools/llvm-ar/LLVMBuild.txt b/tools/llvm-ar/LLVMBuild.txt index 1f61a32..236b465 100644 --- a/tools/llvm-ar/LLVMBuild.txt +++ b/tools/llvm-ar/LLVMBuild.txt @@ -19,4 +19,3 @@ type = Tool name = llvm-ar parent = Tools -required_libraries = Archive diff --git a/tools/llvm-ar/Makefile b/tools/llvm-ar/Makefile index fafb14b..15fb090 100644 --- a/tools/llvm-ar/Makefile +++ b/tools/llvm-ar/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-ar -LINK_COMPONENTS := archive +LINK_COMPONENTS := bitreader support object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 86eb8e2..6026fa7 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -13,21 +13,56 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" -#include "llvm/Bitcode/Archive.h" #include "llvm/IR/Module.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstdlib> -#include <fstream> #include <memory> + +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif + using namespace llvm; +// The name this program was invoked as. +static StringRef ToolName; + +static const char *TemporaryOutput; +static int TmpArchiveFD = -1; + +// fail - Show the error message and exit. +LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { + outs() << ToolName << ": " << Error << ".\n"; + if (TmpArchiveFD != -1) + close(TmpArchiveFD); + if (TemporaryOutput) + sys::fs::remove(TemporaryOutput); + exit(1); +} + +static void failIfError(error_code EC, Twine Context = "") { + if (!EC) + return; + + std::string ContextStr = Context.str(); + if (ContextStr == "") + fail(EC.message()); + fail(Context + ": " + EC.message()); +} + // Option for compatibility with AIX, not used but must allow it to be present. static cl::opt<bool> X32Option ("X32_64", cl::Hidden, @@ -57,123 +92,72 @@ static cl::extrahelp MoreHelp( "\nMODIFIERS (operation specific):\n" " [a] - put file(s) after [relpos]\n" " [b] - put file(s) before [relpos] (same as [i])\n" - " [f] - truncate inserted file names\n" " [i] - put file(s) before [relpos] (same as [b])\n" - " [k] - always print bitcode files (default is to skip them)\n" " [N] - use instance [count] of name\n" " [o] - preserve original dates\n" - " [P] - use full path names when matching\n" - " [R] - recurse through directories when inserting\n" " [s] - create an archive index (cf. ranlib)\n" " [S] - do not build a symbol table\n" " [u] - update only files newer than archive contents\n" "\nMODIFIERS (generic):\n" " [c] - do not warn if the library had to be created\n" " [v] - be verbose about actions taken\n" - " [V] - be *really* verbose about actions taken\n" ); // This enumeration delineates the kinds of operations on an archive // that are permitted. enum ArchiveOperation { - NoOperation, ///< An operation hasn't been specified Print, ///< Print the contents of the archive Delete, ///< Delete the specified members Move, ///< Move members to end or as given by {a,b,i} modifiers QuickAppend, ///< Quickly append to end of archive ReplaceOrInsert, ///< Replace or Insert members DisplayTable, ///< Display the table of contents - Extract ///< Extract files back to file system + Extract, ///< Extract files back to file system + CreateSymTab ///< Create a symbol table in an existing archive }; // Modifiers to follow operation to vary behavior -bool AddAfter = false; ///< 'a' modifier -bool AddBefore = false; ///< 'b' modifier -bool Create = false; ///< 'c' modifier -bool TruncateNames = false; ///< 'f' modifier -bool InsertBefore = false; ///< 'i' modifier -bool DontSkipBitcode = false; ///< 'k' modifier -bool UseCount = false; ///< 'N' modifier -bool OriginalDates = false; ///< 'o' modifier -bool FullPath = false; ///< 'P' modifier -bool RecurseDirectories = false; ///< 'R' modifier -bool SymTable = true; ///< 's' & 'S' modifiers -bool OnlyUpdate = false; ///< 'u' modifier -bool Verbose = false; ///< 'v' modifier -bool ReallyVerbose = false; ///< 'V' modifier +static bool AddAfter = false; ///< 'a' modifier +static bool AddBefore = false; ///< 'b' modifier +static bool Create = false; ///< 'c' modifier +static bool OriginalDates = false; ///< 'o' modifier +static bool OnlyUpdate = false; ///< 'u' modifier +static bool Verbose = false; ///< 'v' modifier +static bool Symtab = true; ///< 's' modifier // Relative Positional Argument (for insert/move). This variable holds // the name of the archive member to which the 'a', 'b' or 'i' modifier // refers. Only one of 'a', 'b' or 'i' can be specified so we only need // one variable. -std::string RelPos; - -// Select which of multiple entries in the archive with the same name should be -// used (specified with -N) for the delete and extract operations. -int Count = 1; +static std::string RelPos; // This variable holds the name of the archive file as given on the // command line. -std::string ArchiveName; +static std::string ArchiveName; // This variable holds the list of member files to proecess, as given // on the command line. -std::vector<std::string> Members; - -// This variable holds the (possibly expanded) list of path objects that -// correspond to files we will -std::set<sys::Path> Paths; - -// The Archive object to which all the editing operations will be sent. -Archive* TheArchive = 0; - -// The name this program was invoked as. -static const char *program_name; +static std::vector<std::string> Members; // show_help - Show the error message, the help message and exit. LLVM_ATTRIBUTE_NORETURN static void show_help(const std::string &msg) { - errs() << program_name << ": " << msg << "\n\n"; + errs() << ToolName << ": " << msg << "\n\n"; cl::PrintHelpMessage(); - if (TheArchive) - delete TheArchive; - std::exit(1); -} - -// fail - Show the error message and exit. -LLVM_ATTRIBUTE_NORETURN static void -fail(const std::string &msg) { - errs() << program_name << ": " << msg << "\n\n"; - if (TheArchive) - delete TheArchive; std::exit(1); } // getRelPos - Extract the member filename from the command line for // the [relpos] argument associated with a, b, and i modifiers -void getRelPos() { +static void getRelPos() { if(RestOfArgs.size() == 0) show_help("Expected [relpos] for a, b, or i modifier"); RelPos = RestOfArgs[0]; RestOfArgs.erase(RestOfArgs.begin()); } -// getCount - Extract the [count] argument associated with the N modifier -// from the command line and check its value. -void getCount() { - if(RestOfArgs.size() == 0) - show_help("Expected [count] value with N modifier"); - - Count = atoi(RestOfArgs[0].c_str()); - RestOfArgs.erase(RestOfArgs.begin()); - - // Non-positive counts are not allowed - if (Count < 1) - show_help("Invalid [count] value (not a positive integer)"); -} - // getArchive - Get the archive file name from the command line -void getArchive() { +static void getArchive() { if(RestOfArgs.size() == 0) show_help("An archive name must be specified"); ArchiveName = RestOfArgs[0]; @@ -182,7 +166,7 @@ void getArchive() { // getMembers - Copy over remaining items in RestOfArgs to our Members vector // This is just for clarity. -void getMembers() { +static void getMembers() { if(RestOfArgs.size() > 0) Members = std::vector<std::string>(RestOfArgs); } @@ -190,7 +174,7 @@ void getMembers() { // parseCommandLine - Parse the command line options as presented and return the // operation specified. Process all modifiers and check to make sure that // constraints on modifier/operation pairs have not been violated. -ArchiveOperation parseCommandLine() { +static ArchiveOperation parseCommandLine() { // Keep track of number of operations. We can only specify one // per execution. @@ -201,7 +185,9 @@ ArchiveOperation parseCommandLine() { unsigned NumPositional = 0; // Keep track of which operation was requested - ArchiveOperation Operation = NoOperation; + ArchiveOperation Operation; + + bool MaybeJustCreateSymTab = false; for(unsigned i=0; i<Options.size(); ++i) { switch(Options[i]) { @@ -213,17 +199,17 @@ ArchiveOperation parseCommandLine() { case 't': ++NumOperations; Operation = DisplayTable; break; case 'x': ++NumOperations; Operation = Extract; break; case 'c': Create = true; break; - case 'f': TruncateNames = true; break; - case 'k': DontSkipBitcode = true; break; case 'l': /* accepted but unused */ break; case 'o': OriginalDates = true; break; - case 'P': FullPath = true; break; - case 'R': RecurseDirectories = true; break; - case 's': SymTable = true; break; - case 'S': SymTable = false; break; + case 's': + Symtab = true; + MaybeJustCreateSymTab = true; + break; + case 'S': + Symtab = false; + break; case 'u': OnlyUpdate = true; break; case 'v': Verbose = true; break; - case 'V': Verbose = ReallyVerbose = true; break; case 'a': getRelPos(); AddAfter = true; @@ -236,13 +222,9 @@ ArchiveOperation parseCommandLine() { break; case 'i': getRelPos(); - InsertBefore = true; + AddBefore = true; NumPositional++; break; - case 'N': - getCount(); - UseCount = true; - break; default: cl::PrintHelpMessage(); } @@ -255,6 +237,13 @@ ArchiveOperation parseCommandLine() { // Everything on the command line at this point is a member. getMembers(); + if (NumOperations == 0 && MaybeJustCreateSymTab) { + NumOperations = 1; + Operation = CreateSymTab; + if (!Members.empty()) + show_help("The s operation takes only an archive as argument"); + } + // Perform various checks on the operation/modifier specification // to make sure we are dealing with a legal request. if (NumOperations == 0) @@ -263,140 +252,33 @@ ArchiveOperation parseCommandLine() { show_help("Only one operation may be specified"); if (NumPositional > 1) show_help("You may only specify one of a, b, and i modifiers"); - if (AddAfter || AddBefore || InsertBefore) { + if (AddAfter || AddBefore) { if (Operation != Move && Operation != ReplaceOrInsert) show_help("The 'a', 'b' and 'i' modifiers can only be specified with " "the 'm' or 'r' operations"); } - if (RecurseDirectories && Operation != ReplaceOrInsert) - show_help("The 'R' modifiers is only applicabe to the 'r' operation"); if (OriginalDates && Operation != Extract) show_help("The 'o' modifier is only applicable to the 'x' operation"); - if (TruncateNames && Operation!=QuickAppend && Operation!=ReplaceOrInsert) - show_help("The 'f' modifier is only applicable to the 'q' and 'r' " - "operations"); if (OnlyUpdate && Operation != ReplaceOrInsert) show_help("The 'u' modifier is only applicable to the 'r' operation"); - if (Count > 1 && Members.size() > 1) - show_help("Only one member name may be specified with the 'N' modifier"); // Return the parsed operation to the caller return Operation; } -// recurseDirectories - Implements the "R" modifier. This function scans through -// the Paths vector (built by buildPaths, below) and replaces any directories it -// finds with all the files in that directory (recursively). It uses the -// sys::Path::getDirectoryContent method to perform the actual directory scans. -bool -recurseDirectories(const sys::Path& path, - std::set<sys::Path>& result, std::string* ErrMsg) { - result.clear(); - if (RecurseDirectories) { - std::set<sys::Path> content; - if (path.getDirectoryContents(content, ErrMsg)) - return true; - - for (std::set<sys::Path>::iterator I = content.begin(), E = content.end(); - I != E; ++I) { - // Make sure it exists and is a directory - sys::PathWithStatus PwS(*I); - const sys::FileStatus *Status = PwS.getFileStatus(false, ErrMsg); - if (!Status) - return true; - if (Status->isDir) { - std::set<sys::Path> moreResults; - if (recurseDirectories(*I, moreResults, ErrMsg)) - return true; - result.insert(moreResults.begin(), moreResults.end()); - } else { - result.insert(*I); - } - } - } - return false; -} +// Implements the 'p' operation. This function traverses the archive +// looking for members that match the path list. +static void doPrint(StringRef Name, object::Archive::child_iterator I) { + if (Verbose) + outs() << "Printing " << Name << "\n"; -// buildPaths - Convert the strings in the Members vector to sys::Path objects -// and make sure they are valid and exist exist. This check is only needed for -// the operations that add/replace files to the archive ('q' and 'r') -bool buildPaths(bool checkExistence, std::string* ErrMsg) { - for (unsigned i = 0; i < Members.size(); i++) { - sys::Path aPath; - if (!aPath.set(Members[i])) - fail(std::string("File member name invalid: ") + Members[i]); - if (checkExistence) { - bool Exists; - if (sys::fs::exists(aPath.str(), Exists) || !Exists) - fail(std::string("File does not exist: ") + Members[i]); - std::string Err; - sys::PathWithStatus PwS(aPath); - const sys::FileStatus *si = PwS.getFileStatus(false, &Err); - if (!si) - fail(Err); - if (si->isDir) { - std::set<sys::Path> dirpaths; - if (recurseDirectories(aPath, dirpaths, ErrMsg)) - return true; - Paths.insert(dirpaths.begin(),dirpaths.end()); - } else { - Paths.insert(aPath); - } - } else { - Paths.insert(aPath); - } - } - return false; -} - -// printSymbolTable - print out the archive's symbol table. -void printSymbolTable() { - outs() << "\nArchive Symbol Table:\n"; - const Archive::SymTabType& symtab = TheArchive->getSymbolTable(); - for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end(); - I != E; ++I ) { - unsigned offset = TheArchive->getFirstFileOffset() + I->second; - outs() << " " << format("%9u", offset) << "\t" << I->first <<"\n"; - } -} - -// doPrint - Implements the 'p' operation. This function traverses the archive -// looking for members that match the path list. It is careful to uncompress -// things that should be and to skip bitcode files unless the 'k' modifier was -// given. -bool doPrint(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; - unsigned countDown = Count; - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E; ++I ) { - if (Paths.empty() || - (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) { - if (countDown == 1) { - const char* data = reinterpret_cast<const char*>(I->getData()); - - // Skip things that don't make sense to print - if (I->isLLVMSymbolTable() || I->isSVR4SymbolTable() || - I->isBSD4SymbolTable() || (!DontSkipBitcode && I->isBitcode())) - continue; - - if (Verbose) - outs() << "Printing " << I->getPath().str() << "\n"; - - unsigned len = I->getSize(); - outs().write(data, len); - } else { - countDown--; - } - } - } - return false; + StringRef Data = I->getBuffer(); + outs().write(Data.data(), Data.size()); } // putMode - utility function for printing out the file mode when the 't' // operation is in verbose mode. -void -printMode(unsigned mode) { +static void printMode(unsigned mode) { if (mode & 004) outs() << "r"; else @@ -411,303 +293,576 @@ printMode(unsigned mode) { outs() << "-"; } -// doDisplayTable - Implement the 't' operation. This function prints out just +// Implement the 't' operation. This function prints out just // the file names of each of the members. However, if verbose mode is requested // ('v' modifier) then the file type, permission mode, user, group, size, and // modification time are also printed. -bool -doDisplayTable(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E; ++I ) { - if (Paths.empty() || - (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) { - if (Verbose) { - // FIXME: Output should be this format: - // Zrw-r--r-- 500/ 500 525 Nov 8 17:42 2004 Makefile - if (I->isBitcode()) - outs() << "b"; - else - outs() << " "; - unsigned mode = I->getMode(); - printMode((mode >> 6) & 007); - printMode((mode >> 3) & 007); - printMode(mode & 007); - outs() << " " << format("%4u", I->getUser()); - outs() << "/" << format("%4u", I->getGroup()); - outs() << " " << format("%8u", I->getSize()); - outs() << " " << format("%20s", I->getModTime().str().substr(4).c_str()); - outs() << " " << I->getPath().str() << "\n"; - } else { - outs() << I->getPath().str() << "\n"; - } - } +static void doDisplayTable(StringRef Name, object::Archive::child_iterator I) { + if (Verbose) { + sys::fs::perms Mode = I->getAccessMode(); + printMode((Mode >> 6) & 007); + printMode((Mode >> 3) & 007); + printMode(Mode & 007); + outs() << ' ' << I->getUID(); + outs() << '/' << I->getGID(); + outs() << ' ' << format("%6llu", I->getSize()); + outs() << ' ' << I->getLastModified().str(); + outs() << ' '; } - if (ReallyVerbose) - printSymbolTable(); - return false; + outs() << Name << "\n"; } -// doExtract - Implement the 'x' operation. This function extracts files back to -// the file system. -bool -doExtract(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E; ++I ) { - if (Paths.empty() || - (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) { - - // Make sure the intervening directories are created - if (I->hasPath()) { - sys::Path dirs(I->getPath()); - dirs.eraseComponent(); - if (dirs.createDirectoryOnDisk(/*create_parents=*/true, ErrMsg)) - return true; - } +// Implement the 'x' operation. This function extracts files back to the file +// system. +static void doExtract(StringRef Name, object::Archive::child_iterator I) { + // Retain the original mode. + sys::fs::perms Mode = I->getAccessMode(); + SmallString<128> Storage = Name; - // Open up a file stream for writing - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - std::ofstream file(I->getPath().c_str(), io_mode); + int FD; + failIfError( + sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_Binary, Mode), + Storage.c_str()); - // Get the data and its length - const char* data = reinterpret_cast<const char*>(I->getData()); - unsigned len = I->getSize(); + { + raw_fd_ostream file(FD, false); - // Write the data. - file.write(data,len); - file.close(); + // Get the data and its length + StringRef Data = I->getBuffer(); - // If we're supposed to retain the original modification times, etc. do so - // now. - if (OriginalDates) - I->getPath().setStatusInfoOnDisk(I->getFileStatus()); - } + // Write the data. + file.write(Data.data(), Data.size()); } - return false; + + // If we're supposed to retain the original modification times, etc. do so + // now. + if (OriginalDates) + failIfError( + sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified())); + + if (close(FD)) + fail("Could not close the file"); } -// doDelete - Implement the delete operation. This function deletes zero or more -// members from the archive. Note that if the count is specified, there should -// be no more than one path in the Paths list or else this algorithm breaks. -// That check is enforced in parseCommandLine (above). -bool -doDelete(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; - if (Paths.empty()) +static bool shouldCreateArchive(ArchiveOperation Op) { + switch (Op) { + case Print: + case Delete: + case Move: + case DisplayTable: + case Extract: + case CreateSymTab: return false; - unsigned countDown = Count; - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E; ) { - if (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end()) { - if (countDown == 1) { - Archive::iterator J = I; - ++I; - TheArchive->erase(J); - } else - countDown--; - } else { - ++I; + + case QuickAppend: + case ReplaceOrInsert: + return true; + } + + llvm_unreachable("Missing entry in covered switch."); +} + +static void performReadOperation(ArchiveOperation Operation, + object::Archive *OldArchive) { + for (object::Archive::child_iterator I = OldArchive->begin_children(), + E = OldArchive->end_children(); + I != E; ++I) { + StringRef Name; + failIfError(I->getName(Name)); + + if (!Members.empty() && + std::find(Members.begin(), Members.end(), Name) == Members.end()) + continue; + + switch (Operation) { + default: + llvm_unreachable("Not a read operation"); + case Print: + doPrint(Name, I); + break; + case DisplayTable: + doDisplayTable(Name, I); + break; + case Extract: + doExtract(Name, I); + break; } } +} - // We're done editting, reconstruct the archive. - if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg)) - return true; - if (ReallyVerbose) - printSymbolTable(); - return false; +namespace { +class NewArchiveIterator { + bool IsNewMember; + StringRef Name; + object::Archive::child_iterator OldI; + std::string NewFilename; + +public: + NewArchiveIterator(object::Archive::child_iterator I, StringRef Name); + NewArchiveIterator(std::string *I, StringRef Name); + NewArchiveIterator(); + bool isNewMember() const; + object::Archive::child_iterator getOld() const; + const char *getNew() const; + StringRef getName() const; +}; } -// doMore - Implement the move operation. This function re-arranges just the -// order of the archive members so that when the archive is written the move -// of the members is accomplished. Note the use of the RelPos variable to -// determine where the items should be moved to. -bool -doMove(std::string* ErrMsg) { - if (buildPaths(false, ErrMsg)) - return true; +NewArchiveIterator::NewArchiveIterator() {} + +NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, + StringRef Name) + : IsNewMember(false), Name(Name), OldI(I) {} + +NewArchiveIterator::NewArchiveIterator(std::string *NewFilename, StringRef Name) + : IsNewMember(true), Name(Name), NewFilename(*NewFilename) {} + +StringRef NewArchiveIterator::getName() const { return Name; } + +bool NewArchiveIterator::isNewMember() const { return IsNewMember; } + +object::Archive::child_iterator NewArchiveIterator::getOld() const { + assert(!IsNewMember); + return OldI; +} + +const char *NewArchiveIterator::getNew() const { + assert(IsNewMember); + return NewFilename.c_str(); +} - // By default and convention the place to move members to is the end of the - // archive. - Archive::iterator moveto_spot = TheArchive->end(); - - // However, if the relative positioning modifiers were used, we need to scan - // the archive to find the member in question. If we don't find it, its no - // crime, we just move to the end. - if (AddBefore || InsertBefore || AddAfter) { - for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end(); - I != E; ++I ) { - if (RelPos == I->getPath().str()) { - if (AddAfter) { - moveto_spot = I; - moveto_spot++; - } else { - moveto_spot = I; - } +template <typename T> +void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name, + int Pos = -1) { + NewArchiveIterator NI(I, Name); + if (Pos == -1) + Members.push_back(NI); + else + Members[Pos] = NI; +} + +namespace { +class HasName { + StringRef Name; + +public: + HasName(StringRef Name) : Name(Name) {} + bool operator()(StringRef Path) { return Name == sys::path::filename(Path); } +}; +} + +enum InsertAction { + IA_AddOldMember, + IA_AddNewMeber, + IA_Delete, + IA_MoveOldMember, + IA_MoveNewMember +}; + +static InsertAction +computeInsertAction(ArchiveOperation Operation, + object::Archive::child_iterator I, StringRef Name, + std::vector<std::string>::iterator &Pos) { + if (Operation == QuickAppend || Members.empty()) + return IA_AddOldMember; + + std::vector<std::string>::iterator MI = + std::find_if(Members.begin(), Members.end(), HasName(Name)); + + if (MI == Members.end()) + return IA_AddOldMember; + + Pos = MI; + + if (Operation == Delete) + return IA_Delete; + + if (Operation == Move) + return IA_MoveOldMember; + + if (Operation == ReplaceOrInsert) { + StringRef PosName = sys::path::filename(RelPos); + if (!OnlyUpdate) { + if (PosName.empty()) + return IA_AddNewMeber; + return IA_MoveNewMember; + } + + // We could try to optimize this to a fstat, but it is not a common + // operation. + sys::fs::file_status Status; + failIfError(sys::fs::status(*MI, Status)); + if (Status.getLastModificationTime() < I->getLastModified()) { + if (PosName.empty()) + return IA_AddOldMember; + return IA_MoveOldMember; + } + + if (PosName.empty()) + return IA_AddNewMeber; + return IA_MoveNewMember; + } + llvm_unreachable("No such operation"); +} + +// We have to walk this twice and computing it is not trivial, so creating an +// explicit std::vector is actually fairly efficient. +static std::vector<NewArchiveIterator> +computeNewArchiveMembers(ArchiveOperation Operation, + object::Archive *OldArchive) { + std::vector<NewArchiveIterator> Ret; + std::vector<NewArchiveIterator> Moved; + int InsertPos = -1; + StringRef PosName = sys::path::filename(RelPos); + if (OldArchive) { + for (object::Archive::child_iterator I = OldArchive->begin_children(), + E = OldArchive->end_children(); + I != E; ++I) { + int Pos = Ret.size(); + StringRef Name; + failIfError(I->getName(Name)); + if (Name == PosName) { + assert(AddAfter || AddBefore); + if (AddBefore) + InsertPos = Pos; + else + InsertPos = Pos + 1; + } + + std::vector<std::string>::iterator MemberI = Members.end(); + InsertAction Action = computeInsertAction(Operation, I, Name, MemberI); + switch (Action) { + case IA_AddOldMember: + addMember(Ret, I, Name); + break; + case IA_AddNewMeber: + addMember(Ret, &*MemberI, Name); + break; + case IA_Delete: + break; + case IA_MoveOldMember: + addMember(Moved, I, Name); + break; + case IA_MoveNewMember: + addMember(Moved, &*MemberI, Name); break; } + if (MemberI != Members.end()) + Members.erase(MemberI); } } - // Keep a list of the paths remaining to be moved - std::set<sys::Path> remaining(Paths); - - // Scan the archive again, this time looking for the members to move to the - // moveto_spot. - for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end(); - I != E && !remaining.empty(); ++I ) { - std::set<sys::Path>::iterator found = - std::find(remaining.begin(),remaining.end(),I->getPath()); - if (found != remaining.end()) { - if (I != moveto_spot) - TheArchive->splice(moveto_spot,*TheArchive,I); - remaining.erase(found); - } + if (Operation == Delete) + return Ret; + + if (!RelPos.empty() && InsertPos == -1) + fail("Insertion point not found"); + + if (RelPos.empty()) + InsertPos = Ret.size(); + + assert(unsigned(InsertPos) <= Ret.size()); + Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end()); + + Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator()); + int Pos = InsertPos; + for (std::vector<std::string>::iterator I = Members.begin(), + E = Members.end(); + I != E; ++I, ++Pos) { + StringRef Name = sys::path::filename(*I); + addMember(Ret, &*I, Name, Pos); } - // We're done editting, reconstruct the archive. - if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg)) - return true; - if (ReallyVerbose) - printSymbolTable(); - return false; + return Ret; } -// doQuickAppend - Implements the 'q' operation. This function just -// indiscriminantly adds the members to the archive and rebuilds it. -bool -doQuickAppend(std::string* ErrMsg) { - // Get the list of paths to append. - if (buildPaths(true, ErrMsg)) - return true; - if (Paths.empty()) - return false; +template <typename T> +static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { + uint64_t OldPos = OS.tell(); + OS << Data; + unsigned SizeSoFar = OS.tell() - OldPos; + assert(Size >= SizeSoFar && "Data doesn't fit in Size"); + unsigned Remaining = Size - SizeSoFar; + for (unsigned I = 0; I < Remaining; ++I) + OS << ' '; +} - // Append them quickly. - for (std::set<sys::Path>::iterator PI = Paths.begin(), PE = Paths.end(); - PI != PE; ++PI) { - if (TheArchive->addFileBefore(*PI,TheArchive->end(),ErrMsg)) - return true; +static void print32BE(raw_fd_ostream &Out, unsigned Val) { + for (int I = 3; I >= 0; --I) { + char V = (Val >> (8 * I)) & 0xff; + Out << V; } +} - // We're done editting, reconstruct the archive. - if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg)) - return true; - if (ReallyVerbose) - printSymbolTable(); - return false; +static void printRestOfMemberHeader(raw_fd_ostream &Out, + const sys::TimeValue &ModTime, unsigned UID, + unsigned GID, unsigned Perms, + unsigned Size) { + printWithSpacePadding(Out, ModTime.toEpochTime(), 12); + printWithSpacePadding(Out, UID, 6); + printWithSpacePadding(Out, GID, 6); + printWithSpacePadding(Out, format("%o", Perms), 8); + printWithSpacePadding(Out, Size, 10); + Out << "`\n"; } -// doReplaceOrInsert - Implements the 'r' operation. This function will replace -// any existing files or insert new ones into the archive. -bool -doReplaceOrInsert(std::string* ErrMsg) { +static void printMemberHeader(raw_fd_ostream &Out, StringRef Name, + const sys::TimeValue &ModTime, unsigned UID, + unsigned GID, unsigned Perms, unsigned Size) { + printWithSpacePadding(Out, Twine(Name) + "/", 16); + printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); +} - // Build the list of files to be added/replaced. - if (buildPaths(true, ErrMsg)) - return true; - if (Paths.empty()) - return false; +static void printMemberHeader(raw_fd_ostream &Out, unsigned NameOffset, + const sys::TimeValue &ModTime, unsigned UID, + unsigned GID, unsigned Perms, unsigned Size) { + Out << '/'; + printWithSpacePadding(Out, NameOffset, 15); + printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); +} - // Keep track of the paths that remain to be inserted. - std::set<sys::Path> remaining(Paths); - - // Default the insertion spot to the end of the archive - Archive::iterator insert_spot = TheArchive->end(); - - // Iterate over the archive contents - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); - I != E && !remaining.empty(); ++I ) { - - // Determine if this archive member matches one of the paths we're trying - // to replace. - - std::set<sys::Path>::iterator found = remaining.end(); - for (std::set<sys::Path>::iterator RI = remaining.begin(), - RE = remaining.end(); RI != RE; ++RI ) { - std::string compare(RI->str()); - if (TruncateNames && compare.length() > 15) { - const char* nm = compare.c_str(); - unsigned len = compare.length(); - size_t slashpos = compare.rfind('/'); - if (slashpos != std::string::npos) { - nm += slashpos + 1; - len -= slashpos +1; - } - if (len > 15) - len = 15; - compare.assign(nm,len); - } - if (compare == I->getPath().str()) { - found = RI; - break; - } +static void writeStringTable(raw_fd_ostream &Out, + ArrayRef<NewArchiveIterator> Members, + std::vector<unsigned> &StringMapIndexes) { + unsigned StartOffset = 0; + for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), + E = Members.end(); + I != E; ++I) { + StringRef Name = I->getName(); + if (Name.size() < 16) + continue; + if (StartOffset == 0) { + printWithSpacePadding(Out, "//", 58); + Out << "`\n"; + StartOffset = Out.tell(); } + StringMapIndexes.push_back(Out.tell() - StartOffset); + Out << Name << "/\n"; + } + if (StartOffset == 0) + return; + if (Out.tell() % 2) + Out << '\n'; + int Pos = Out.tell(); + Out.seek(StartOffset - 12); + printWithSpacePadding(Out, Pos - StartOffset, 10); + Out.seek(Pos); +} - if (found != remaining.end()) { - std::string Err; - sys::PathWithStatus PwS(*found); - const sys::FileStatus *si = PwS.getFileStatus(false, &Err); - if (!si) - return true; - if (!si->isDir) { - if (OnlyUpdate) { - // Replace the item only if it is newer. - if (si->modTime > I->getModTime()) - if (I->replaceWith(*found, ErrMsg)) - return true; - } else { - // Replace the item regardless of time stamp - if (I->replaceWith(*found, ErrMsg)) - return true; - } +static void writeSymbolTable( + raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, + std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { + unsigned StartOffset = 0; + unsigned MemberNum = 0; + std::vector<StringRef> SymNames; + std::vector<object::ObjectFile *> DeleteIt; + for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), + E = Members.end(); + I != E; ++I, ++MemberNum) { + object::ObjectFile *Obj; + if (I->isNewMember()) { + const char *Filename = I->getNew(); + Obj = object::ObjectFile::createObjectFile(Filename); + } else { + object::Archive::child_iterator OldMember = I->getOld(); + OwningPtr<object::Binary> Binary; + error_code EC = OldMember->getAsBinary(Binary); + if (EC) { // FIXME: check only for "not an object file" errors. + Obj = NULL; } else { - // We purposefully ignore directories. + Obj = dyn_cast<object::ObjectFile>(Binary.get()); + if (Obj) + Binary.take(); } - - // Remove it from our "to do" list - remaining.erase(found); + } + if (!Obj) + continue; + DeleteIt.push_back(Obj); + if (!StartOffset) { + printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); + StartOffset = Out.tell(); + print32BE(Out, 0); } - // Determine if this is the place where we should insert - if ((AddBefore || InsertBefore) && RelPos == I->getPath().str()) - insert_spot = I; - else if (AddAfter && RelPos == I->getPath().str()) { - insert_spot = I; - insert_spot++; + error_code Err; + for (object::symbol_iterator I = Obj->begin_symbols(), + E = Obj->end_symbols(); + I != E; I.increment(Err), failIfError(Err)) { + uint32_t Symflags; + failIfError(I->getFlags(Symflags)); + if (Symflags & object::SymbolRef::SF_FormatSpecific) + continue; + if (!(Symflags & object::SymbolRef::SF_Global)) + continue; + if (Symflags & object::SymbolRef::SF_Undefined) + continue; + StringRef Name; + failIfError(I->getName(Name)); + SymNames.push_back(Name); + MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); + print32BE(Out, 0); } } + for (std::vector<StringRef>::iterator I = SymNames.begin(), + E = SymNames.end(); + I != E; ++I) { + Out << *I; + Out << '\0'; + } + + for (std::vector<object::ObjectFile *>::iterator I = DeleteIt.begin(), + E = DeleteIt.end(); + I != E; ++I) { + object::ObjectFile *O = *I; + delete O; + } + + if (StartOffset == 0) + return; + + if (Out.tell() % 2) + Out << '\0'; + + unsigned Pos = Out.tell(); + Out.seek(StartOffset - 12); + printWithSpacePadding(Out, Pos - StartOffset, 10); + Out.seek(StartOffset); + print32BE(Out, SymNames.size()); + Out.seek(Pos); +} + +static void performWriteOperation(ArchiveOperation Operation, + object::Archive *OldArchive) { + SmallString<128> TmpArchive; + failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", + TmpArchiveFD, TmpArchive)); + + TemporaryOutput = TmpArchive.c_str(); + tool_output_file Output(TemporaryOutput, TmpArchiveFD); + raw_fd_ostream &Out = Output.os(); + Out << "!<arch>\n"; + + std::vector<NewArchiveIterator> NewMembers = + computeNewArchiveMembers(Operation, OldArchive); + + std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs; + + if (Symtab) { + writeSymbolTable(Out, NewMembers, MemberOffsetRefs); + } + + std::vector<unsigned> StringMapIndexes; + writeStringTable(Out, NewMembers, StringMapIndexes); + + std::vector<std::pair<unsigned, unsigned> >::iterator MemberRefsI = + MemberOffsetRefs.begin(); - // If we didn't replace all the members, some will remain and need to be - // inserted at the previously computed insert-spot. - if (!remaining.empty()) { - for (std::set<sys::Path>::iterator PI = remaining.begin(), - PE = remaining.end(); PI != PE; ++PI) { - if (TheArchive->addFileBefore(*PI,insert_spot, ErrMsg)) - return true; + unsigned MemberNum = 0; + unsigned LongNameMemberNum = 0; + for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(), + E = NewMembers.end(); + I != E; ++I, ++MemberNum) { + + unsigned Pos = Out.tell(); + while (MemberRefsI != MemberOffsetRefs.end() && + MemberRefsI->second == MemberNum) { + Out.seek(MemberRefsI->first); + print32BE(Out, Pos); + ++MemberRefsI; + } + Out.seek(Pos); + + if (I->isNewMember()) { + const char *FileName = I->getNew(); + + int FD; + failIfError(sys::fs::openFileForRead(FileName, FD), FileName); + + sys::fs::file_status Status; + failIfError(sys::fs::status(FD, Status), FileName); + + OwningPtr<MemoryBuffer> File; + failIfError(MemoryBuffer::getOpenFile(FD, FileName, File, + Status.getSize(), false), + FileName); + + StringRef Name = sys::path::filename(FileName); + if (Name.size() < 16) + printMemberHeader(Out, Name, Status.getLastModificationTime(), + Status.getUser(), Status.getGroup(), + Status.permissions(), Status.getSize()); + else + printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], + Status.getLastModificationTime(), Status.getUser(), + Status.getGroup(), Status.permissions(), + Status.getSize()); + Out << File->getBuffer(); + } else { + object::Archive::child_iterator OldMember = I->getOld(); + StringRef Name = I->getName(); + + if (Name.size() < 16) + printMemberHeader(Out, Name, OldMember->getLastModified(), + OldMember->getUID(), OldMember->getGID(), + OldMember->getAccessMode(), OldMember->getSize()); + else + printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], + OldMember->getLastModified(), OldMember->getUID(), + OldMember->getGID(), OldMember->getAccessMode(), + OldMember->getSize()); + Out << OldMember->getBuffer(); } + + if (Out.tell() % 2) + Out << '\n'; } + Output.keep(); + Out.close(); + sys::fs::rename(TemporaryOutput, ArchiveName); + TemporaryOutput = NULL; +} - // We're done editting, reconstruct the archive. - if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg)) - return true; - if (ReallyVerbose) - printSymbolTable(); - return false; +static void createSymbolTable(object::Archive *OldArchive) { + // When an archive is created or modified, if the s option is given, the + // resulting archive will have a current symbol table. If the S option + // is given, it will have no symbol table. + // In summary, we only need to update the symbol table if we have none. + // This is actually very common because of broken build systems that think + // they have to run ranlib. + if (OldArchive->hasSymbolTable()) + return; + + performWriteOperation(CreateSymTab, OldArchive); +} + +static void performOperation(ArchiveOperation Operation, + object::Archive *OldArchive) { + switch (Operation) { + case Print: + case DisplayTable: + case Extract: + performReadOperation(Operation, OldArchive); + return; + + case Delete: + case Move: + case QuickAppend: + case ReplaceOrInsert: + performWriteOperation(Operation, OldArchive); + return; + case CreateSymTab: + createSymbolTable(OldArchive); + return; + } + llvm_unreachable("Unknown operation."); } // main - main program for llvm-ar .. see comments in the code int main(int argc, char **argv) { - program_name = argv[0]; + ToolName = argv[0]; // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. // Have the command line options parsed and handle things @@ -717,63 +872,42 @@ int main(int argc, char **argv) { " This program archives bitcode files into single libraries\n" ); - int exitCode = 0; - // Do our own parsing of the command line because the CommandLine utility // can't handle the grouped positional parameters without a dash. ArchiveOperation Operation = parseCommandLine(); - // Check the path name of the archive - sys::Path ArchivePath; - if (!ArchivePath.set(ArchiveName)) { - errs() << argv[0] << ": Archive name invalid: " << ArchiveName << "\n"; + // Create or open the archive object. + OwningPtr<MemoryBuffer> Buf; + error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); + if (EC && EC != llvm::errc::no_such_file_or_directory) { + errs() << argv[0] << ": error opening '" << ArchiveName + << "': " << EC.message() << "!\n"; return 1; } - // Create or open the archive object. - bool Exists; - if (llvm::sys::fs::exists(ArchivePath.str(), Exists) || !Exists) { - // Produce a warning if we should and we're creating the archive - if (!Create) - errs() << argv[0] << ": creating " << ArchivePath.str() << "\n"; - TheArchive = Archive::CreateEmpty(ArchivePath, Context); - TheArchive->writeToDisk(); - } else { - std::string Error; - TheArchive = Archive::OpenAndLoad(ArchivePath, Context, &Error); - if (TheArchive == 0) { - errs() << argv[0] << ": error loading '" << ArchivePath.str() << "': " - << Error << "!\n"; + if (!EC) { + object::Archive Archive(Buf.take(), EC); + + if (EC) { + errs() << argv[0] << ": error loading '" << ArchiveName + << "': " << EC.message() << "!\n"; return 1; } + performOperation(Operation, &Archive); + return 0; } - // Make sure we're not fooling ourselves. - assert(TheArchive && "Unable to instantiate the archive"); + assert(EC == llvm::errc::no_such_file_or_directory); - // Perform the operation - std::string ErrMsg; - bool haveError = false; - switch (Operation) { - case Print: haveError = doPrint(&ErrMsg); break; - case Delete: haveError = doDelete(&ErrMsg); break; - case Move: haveError = doMove(&ErrMsg); break; - case QuickAppend: haveError = doQuickAppend(&ErrMsg); break; - case ReplaceOrInsert: haveError = doReplaceOrInsert(&ErrMsg); break; - case DisplayTable: haveError = doDisplayTable(&ErrMsg); break; - case Extract: haveError = doExtract(&ErrMsg); break; - case NoOperation: - errs() << argv[0] << ": No operation was selected.\n"; - break; - } - if (haveError) { - errs() << argv[0] << ": " << ErrMsg << "\n"; - return 1; + if (!shouldCreateArchive(Operation)) { + failIfError(EC, Twine("error loading '") + ArchiveName + "'"); + } else { + if (!Create) { + // Produce a warning if we should and we're creating the archive + errs() << argv[0] << ": creating " << ArchiveName << "\n"; + } } - delete TheArchive; - TheArchive = 0; - - // Return result code back to operating system. - return exitCode; + performOperation(Operation, NULL); + return 0; } diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp index 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..186eea9 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -481,7 +481,7 @@ static int AnalyzeBitcode() { OwningPtr<MemoryBuffer> MemBuf; if (error_code ec = - MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), MemBuf)) + MemoryBuffer::getFileOrSTDIN(InputFilename, MemBuf)) return Error("Error reading '" + InputFilename + "': " + ec.message()); if (MemBuf->getBufferSize() & 3) diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp index 5151d1a..3924e2e 100644 --- a/tools/llvm-config/llvm-config.cpp +++ b/tools/llvm-config/llvm-config.cpp @@ -25,7 +25,6 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Support/PathV1.h" #include "llvm/Support/raw_ostream.h" #include <cstdlib> #include <set> @@ -162,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) { @@ -180,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-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..eef6f79 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -63,6 +63,7 @@ DumpType("debug-dump", cl::init(DIDT_All), clEnumValN(DIDT_Info, "info", ".debug_info"), clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"), clEnumValN(DIDT_Line, "line", ".debug_line"), + clEnumValN(DIDT_Loc, "loc", ".debug_loc"), clEnumValN(DIDT_Frames, "frames", ".debug_frame"), clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"), clEnumValN(DIDT_Pubnames, "pubnames", ".debug_pubnames"), diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index 2f45b4e..9ba68b4 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -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..652c414 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()); @@ -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-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 289a445..f10a614 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; @@ -388,7 +388,7 @@ int main(int argc, char **argv) { // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and // MCObjectFileInfo needs a MCContext reference in order to initialize itself. OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); - MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); + MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx); if (SaveTempLabels) diff --git a/tools/llvm-nm/CMakeLists.txt b/tools/llvm-nm/CMakeLists.txt index b6cd80b..b1672ff 100644 --- a/tools/llvm-nm/CMakeLists.txt +++ b/tools/llvm-nm/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS archive bitreader object) +set(LLVM_LINK_COMPONENTS bitreader object) add_llvm_tool(llvm-nm llvm-nm.cpp diff --git a/tools/llvm-nm/LLVMBuild.txt b/tools/llvm-nm/LLVMBuild.txt index 38ecbfd..3e64577 100644 --- a/tools/llvm-nm/LLVMBuild.txt +++ b/tools/llvm-nm/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-nm parent = Tools -required_libraries = Archive BitReader Object +required_libraries = BitReader Object diff --git a/tools/llvm-nm/Makefile b/tools/llvm-nm/Makefile index d9cee98..b95e920 100644 --- a/tools/llvm-nm/Makefile +++ b/tools/llvm-nm/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-nm -LINK_COMPONENTS := archive bitreader object +LINK_COMPONENTS := bitreader object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index a24aae6..01dd1c3 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -17,10 +17,10 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" -#include "llvm/Bitcode/Archive.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -121,6 +121,8 @@ namespace { bool MultipleFiles = false; + bool HadError = false; + std::string ToolName; } @@ -132,6 +134,7 @@ static void error(Twine message, Twine path = Twine()) { static bool error(error_code ec, Twine path = Twine()) { if (ec) { error(ec.message(), path); + HadError = true; return true; } return false; @@ -362,21 +365,24 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { if (ArchiveMap) { - outs() << "Archive map" << "\n"; - for (object::Archive::symbol_iterator i = a->begin_symbols(), - e = a->end_symbols(); i != e; ++i) { - object::Archive::child_iterator c; - StringRef symname; - StringRef filename; - if (error(i->getMember(c))) + object::Archive::symbol_iterator I = a->begin_symbols(); + object::Archive::symbol_iterator E = a->end_symbols(); + if (I !=E) { + outs() << "Archive map" << "\n"; + for (; I != E; ++I) { + object::Archive::child_iterator c; + StringRef symname; + StringRef filename; + if (error(I->getMember(c))) return; - if (error(i->getName(symname))) + if (error(I->getName(symname))) return; - if (error(c->getName(filename))) + if (error(c->getName(filename))) return; - outs() << symname << " in " << filename << "\n"; + outs() << symname << " in " << filename << "\n"; + } + outs() << "\n"; } - outs() << "\n"; } for (object::Archive::child_iterator i = a->begin_children(), @@ -403,6 +409,23 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { } } } + } else if (magic == sys::fs::file_magic::macho_universal_binary) { + OwningPtr<Binary> Bin; + if (error(object::createBinary(Buffer.take(), Bin), Filename)) + return; + + object::MachOUniversalBinary *UB = + cast<object::MachOUniversalBinary>(Bin.get()); + for (object::MachOUniversalBinary::object_iterator + I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + OwningPtr<ObjectFile> Obj; + if (!I->getAsObjectFile(Obj)) { + outs() << Obj->getFileName() << ":\n"; + DumpSymbolNamesFromObject(Obj.get()); + } + } } else if (magic.is_object()) { OwningPtr<Binary> obj; if (error(object::createBinary(Buffer.take(), obj), Filename)) @@ -412,6 +435,7 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { } else { errs() << ToolName << ": " << Filename << ": " << "unrecognizable file type\n"; + HadError = true; return; } } @@ -425,7 +449,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n"); // llvm-nm only reads binary files. - if (error(sys::Program::ChangeStdinToBinary())) + if (error(sys::ChangeStdinToBinary())) return 1; ToolName = argv[0]; @@ -446,5 +470,9 @@ int main(int argc, char **argv) { std::for_each(InputFilenames.begin(), InputFilenames.end(), DumpSymbolNamesFromFile); + + if (HadError) + return 1; + return 0; } diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp index 7b55007..bca6fc9 100644 --- a/tools/llvm-objdump/COFFDump.cpp +++ b/tools/llvm-objdump/COFFDump.cpp @@ -229,7 +229,7 @@ static void printCOFFSymbolAddress(llvm::raw_ostream &Out, void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { const coff_file_header *Header; - if (error(Obj->getHeader(Header))) return; + if (error(Obj->getCOFFHeader(Header))) return; if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { errs() << "Unsupported image machine type " diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 27e1623..e0ec9cc 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -295,7 +295,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; } diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 8049dac..122ac83 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -310,7 +310,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (Symbolize) { MOFI.reset(new MCObjectFileInfo); - Ctx.reset(new MCContext(*AsmInfo.get(), *MRI.get(), MOFI.get())); + Ctx.reset(new MCContext(AsmInfo.get(), MRI.get(), MOFI.get())); OwningPtr<MCRelocationInfo> RelInfo( TheTarget->createMCRelocationInfo(TripleName, *Ctx.get())); if (RelInfo) { diff --git a/tools/llvm-ranlib/CMakeLists.txt b/tools/llvm-ranlib/CMakeLists.txt deleted file mode 100644 index 2d7defe..0000000 --- a/tools/llvm-ranlib/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(LLVM_LINK_COMPONENTS archive) - -add_llvm_tool(llvm-ranlib - llvm-ranlib.cpp - ) diff --git a/tools/llvm-ranlib/LLVMBuild.txt b/tools/llvm-ranlib/LLVMBuild.txt deleted file mode 100644 index 23015c5..0000000 --- a/tools/llvm-ranlib/LLVMBuild.txt +++ /dev/null @@ -1,22 +0,0 @@ -;===- ./tools/llvm-ranlib/LLVMBuild.txt ------------------------*- Conf -*--===; -; -; The LLVM Compiler Infrastructure -; -; This file is distributed under the University of Illinois Open Source -; License. See LICENSE.TXT for details. -; -;===------------------------------------------------------------------------===; -; -; This is an LLVMBuild description file for the components in this subdirectory. -; -; For more information on the LLVMBuild system, please see: -; -; http://llvm.org/docs/LLVMBuild.html -; -;===------------------------------------------------------------------------===; - -[component_0] -type = Tool -name = llvm-ranlib -parent = Tools -required_libraries = Archive diff --git a/tools/llvm-ranlib/Makefile b/tools/llvm-ranlib/Makefile deleted file mode 100644 index cca9501..0000000 --- a/tools/llvm-ranlib/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -##===- tools/llvm-ranlib/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 - -# This tool has no plugins, optimize startup time. -TOOL_NO_EXPORTS := 1 - -include $(LEVEL)/Makefile.common 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 3cbb9b3..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( @@ -262,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 ), @@ -454,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(); @@ -535,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() { @@ -834,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 67bbafa..3628c3b 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -290,7 +290,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 ), @@ -301,8 +300,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[] = { 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/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-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index b68f2a0..7f042d2 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -124,8 +124,8 @@ static int printLineInfoForInput() { InputFileList.push_back("-"); for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { // Instantiate a dynamic linker. - TrivialMemoryManager *MemMgr = new TrivialMemoryManager; - RuntimeDyld Dyld(MemMgr); + TrivialMemoryManager MemMgr; + RuntimeDyld Dyld(&MemMgr); // Load the input memory buffer. OwningPtr<MemoryBuffer> InputBuffer; @@ -180,8 +180,8 @@ static int printLineInfoForInput() { static int executeInput() { // Instantiate a dynamic linker. - TrivialMemoryManager *MemMgr = new TrivialMemoryManager; - RuntimeDyld Dyld(MemMgr); + TrivialMemoryManager MemMgr; + RuntimeDyld Dyld(&MemMgr); // If we don't have any input files, read from stdin. if (!InputFileList.size()) @@ -204,7 +204,7 @@ static int executeInput() { // Resolve all the relocations we can. Dyld.resolveRelocations(); // Clear instruction cache before code will be executed. - MemMgr->invalidateInstructionCache(); + MemMgr.invalidateInstructionCache(); // FIXME: Error out if there are unresolved relocations. @@ -214,8 +214,8 @@ static int executeInput() { return Error("no definition for '" + EntryPoint + "'"); // Invalidate the instruction cache for each loaded function. - for (unsigned i = 0, e = MemMgr->FunctionMemory.size(); i != e; ++i) { - sys::MemoryBlock &Data = MemMgr->FunctionMemory[i]; + for (unsigned i = 0, e = MemMgr.FunctionMemory.size(); i != e; ++i) { + sys::MemoryBlock &Data = MemMgr.FunctionMemory[i]; // Make sure the memory is executable. std::string ErrorStr; sys::Memory::InvalidateInstructionCache(Data.base(), Data.size()); diff --git a/tools/llvm-shlib/Makefile b/tools/llvm-shlib/Makefile index 8697bbf..1d9053b 100644 --- a/tools/llvm-shlib/Makefile +++ b/tools/llvm-shlib/Makefile @@ -58,22 +58,22 @@ ifeq ($(HOST_OS),Darwin) ifneq ($(DARWIN_VERS),8) LLVMLibsOptions := $(LLVMLibsOptions) \ -Wl,-install_name \ - -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif -ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD OpenBSD GNU Bitrig)) +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD OpenBSD GNU Bitrig)) # Include everything from the .a's into the shared library. LLVMLibsOptions := -Wl,--whole-archive $(LLVMLibsOptions) \ -Wl,--no-whole-archive endif -ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU)) +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD GNU)) # Add soname to the library. LLVMLibsOptions += -Wl,--soname,lib$(LIBRARYNAME)$(SHLIBEXT) endif -ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux GNU)) +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux GNU GNU/kFreeBSD)) # Don't allow unresolved symbols. LLVMLibsOptions += -Wl,--no-undefined endif diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp index fbda1b7..15f7abf 100644 --- a/tools/llvm-stress/llvm-stress.cpp +++ b/tools/llvm-stress/llvm-stress.cpp @@ -702,7 +702,7 @@ int main(int argc, char **argv) { std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + sys::fs::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index 7fccedf..0346fb2 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -74,6 +74,9 @@ ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx) 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; @@ -187,8 +190,8 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, uint64_t Size = 0; if (Opts.UseSymbolTable) { if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) { - if (Info->symbolizeData(ModuleOffset, Name, Start, Size)) - DemangleName(Name); + if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle) + Name = DemangleName(Name); } } std::stringstream ss; @@ -198,23 +201,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(MemoryBuffer::getFile(Path, Buff))) - return 0; - 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); @@ -223,39 +215,89 @@ static std::string getDarwinDWARFResourceForModule(const std::string &Path) { return ResourceName.str(); } +LLVMSymbolizer::BinaryPair +LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { + BinaryMapTy::iterator I = BinaryForPath.find(Path); + if (I != BinaryForPath.end()) + return I->second; + Binary *Bin = 0; + Binary *DbgBin = 0; + OwningPtr<Binary> ParsedBinary; + OwningPtr<Binary> ParsedDbgBinary; + if (!error(createBinary(Path, ParsedBinary))) { + // Check if it's a universal binary. + Bin = ParsedBinary.take(); + ParsedBinariesAndObjects.push_back(Bin); + if (Bin->isMachO() || Bin->isMachOUniversalBinary()) { + // On Darwin we may find DWARF in separate object file in + // resource directory. + const std::string &ResourcePath = + getDarwinDWARFResourceForPath(Path); + bool ResourceFileExists = false; + if (!sys::fs::exists(ResourcePath, ResourceFileExists) && + ResourceFileExists && + !error(createBinary(ResourcePath, ParsedDbgBinary))) { + DbgBin = ParsedDbgBinary.take(); + ParsedBinariesAndObjects.push_back(DbgBin); + } + } + } + if (DbgBin == 0) + DbgBin = Bin; + BinaryPair Res = std::make_pair(Bin, DbgBin); + BinaryForPath[Path] = Res; + return Res; +} + +ObjectFile * +LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName) { + if (Bin == 0) + return 0; + ObjectFile *Res = 0; + if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) { + ObjectFileForArchMapTy::iterator I = ObjectFileForArch.find( + std::make_pair(UB, ArchName)); + if (I != ObjectFileForArch.end()) + return I->second; + OwningPtr<ObjectFile> ParsedObj; + if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) { + Res = ParsedObj.take(); + ParsedBinariesAndObjects.push_back(Res); + } + ObjectFileForArch[std::make_pair(UB, ArchName)] = Res; + } else if (Bin->isObject()) { + Res = cast<ObjectFile>(Bin); + } + return Res; +} + ModuleInfo * LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { ModuleMapTy::iterator I = Modules.find(ModuleName); if (I != Modules.end()) return I->second; + std::string BinaryName = ModuleName; + std::string ArchName = Opts.DefaultArch; + size_t ColonPos = ModuleName.find_last_of(':'); + // Verify that substring after colon form a valid arch name. + if (ColonPos != std::string::npos) { + std::string ArchStr = ModuleName.substr(ColonPos + 1); + if (Triple(ArchStr).getArch() != Triple::UnknownArch) { + BinaryName = ModuleName.substr(0, ColonPos); + ArchName = ArchStr; + } + } + BinaryPair Binaries = getOrCreateBinary(BinaryName); + ObjectFile *Obj = getObjectFileFromBinary(Binaries.first, ArchName); + ObjectFile *DbgObj = getObjectFileFromBinary(Binaries.second, ArchName); - ObjectFile *Obj = getObjectFile(ModuleName); if (Obj == 0) { - // Module name doesn't point to a valid object file. + // Failed to find valid object file. Modules.insert(make_pair(ModuleName, (ModuleInfo *)0)); return 0; } - - DIContext *Context = 0; - bool IsLittleEndian; - if (getObjectEndianness(Obj, IsLittleEndian)) { - // On Darwin we may find DWARF in separate object file in - // resource directory. - ObjectFile *DbgObj = Obj; - if (isa<MachOObjectFile>(Obj)) { - const std::string &ResourceName = - getDarwinDWARFResourceForModule(ModuleName); - bool ResourceFileExists = false; - if (!sys::fs::exists(ResourceName, ResourceFileExists) && - ResourceFileExists) { - if (ObjectFile *ResourceObj = getObjectFile(ResourceName)) - 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; @@ -270,7 +312,8 @@ std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const { std::string FunctionName = LineInfo.getFunctionName(); if (FunctionName == kDILineInfoBadString) FunctionName = kBadString; - DemangleName(FunctionName); + else if (Opts.Demangle) + FunctionName = DemangleName(FunctionName); Result << FunctionName << "\n"; } std::string Filename = LineInfo.getFileName(); @@ -287,16 +330,17 @@ extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, size_t *length, int *status); #endif -void LLVMSymbolizer::DemangleName(std::string &Name) const { +std::string LLVMSymbolizer::DemangleName(const std::string &Name) { #if !defined(_MSC_VER) - if (!Opts.Demangle) - return; int status = 0; char *DemangledName = __cxa_demangle(Name.c_str(), 0, 0, &status); if (status != 0) - return; - Name = DemangledName; + return Name; + std::string Result = DemangledName; free(DemangledName); + return Result; +#else + return Name; #endif } diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h index 188331b..03c765c 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.h +++ b/tools/llvm-symbolizer/LLVMSymbolize.h @@ -14,7 +14,9 @@ #define LLVM_SYMBOLIZE_H #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/MemoryBuffer.h" #include <map> @@ -35,14 +37,20 @@ public: bool PrintFunctions : 1; bool PrintInlining : 1; bool Demangle : 1; + std::string DefaultArch; Options(bool UseSymbolTable = true, bool PrintFunctions = true, - bool PrintInlining = true, bool Demangle = true) + bool PrintInlining = true, bool Demangle = true, + std::string DefaultArch = "") : UseSymbolTable(UseSymbolTable), PrintFunctions(PrintFunctions), - PrintInlining(PrintInlining), Demangle(Demangle) { + PrintInlining(PrintInlining), Demangle(Demangle), + DefaultArch(DefaultArch) { } }; LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {} + ~LLVMSymbolizer() { + flush(); + } // Returns the result of symbolization for module name/offset as // a string (possibly containing newlines). @@ -51,13 +59,30 @@ 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; + // 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,7 +102,7 @@ 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 { 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/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index 465ccb4..758227d 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -24,12 +24,14 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" #include "llvm/Linker.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" @@ -76,6 +78,7 @@ LTOCodeGenerator::LTOCodeGenerator() InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); + initializeLTOPasses(); } LTOCodeGenerator::~LTOCodeGenerator() { @@ -88,6 +91,36 @@ LTOCodeGenerator::~LTOCodeGenerator() { free(*I); } +// Initialize LTO passes. Please keep this funciton in sync with +// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO +// passes are initialized. +// +void LTOCodeGenerator::initializeLTOPasses() { + PassRegistry &R = *PassRegistry::getPassRegistry(); + + initializeInternalizePassPass(R); + initializeIPSCCPPass(R); + initializeGlobalOptPass(R); + initializeConstantMergePass(R); + initializeDAHPass(R); + initializeInstCombinerPass(R); + initializeSimpleInlinerPass(R); + initializePruneEHPass(R); + initializeGlobalDCEPass(R); + initializeArgPromotionPass(R); + initializeJumpThreadingPass(R); + initializeSROAPass(R); + initializeSROA_DTPass(R); + initializeSROA_SSAUpPass(R); + initializeFunctionAttrsPass(R); + initializeGlobalsModRefPass(R); + initializeLICMPass(R); + initializeGVNPass(R); + initializeMemCpyOptPass(R); + initializeDCEPass(R); + initializeCFGSimplifyPassPass(R); +} + bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) { bool ret = _linker.linkInModule(mod->getLLVVMModule(), &errMsg); @@ -95,51 +128,50 @@ bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) { for (int i = 0, e = undefs.size(); i != e; ++i) _asmUndefinedRefs[undefs[i]] = 1; - return ret; + return !ret; } -bool LTOCodeGenerator::setDebugInfo(lto_debug_model debug, - std::string& errMsg) { +void LTOCodeGenerator::setDebugInfo(lto_debug_model debug) { switch (debug) { case LTO_DEBUG_MODEL_NONE: _emitDwarfDebugInfo = false; - return false; + return; case LTO_DEBUG_MODEL_DWARF: _emitDwarfDebugInfo = true; - return false; + return; } llvm_unreachable("Unknown debug format!"); } -bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model, - std::string& errMsg) { +void LTOCodeGenerator::setCodePICModel(lto_codegen_model model) { switch (model) { case LTO_CODEGEN_PIC_MODEL_STATIC: case LTO_CODEGEN_PIC_MODEL_DYNAMIC: case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: _codeModel = model; - return false; + return; } llvm_unreachable("Unknown PIC model!"); } bool LTOCodeGenerator::writeMergedModules(const char *path, std::string &errMsg) { - if (determineTarget(errMsg)) - return true; + if (!determineTarget(errMsg)) + return false; - // mark which symbols can not be internalized - applyScopeRestrictions(); + // Run the verifier on the merged modules. + PassManager passes; + passes.add(createVerifierPass()); + passes.run(*_linker.getModule()); // create output file std::string ErrInfo; - tool_output_file Out(path, ErrInfo, - raw_fd_ostream::F_Binary); + tool_output_file Out(path, ErrInfo, sys::fs::F_Binary); if (!ErrInfo.empty()) { errMsg = "could not open bitcode file for writing: "; errMsg += path; - return true; + return false; } // write bitcode to it @@ -150,52 +182,48 @@ bool LTOCodeGenerator::writeMergedModules(const char *path, errMsg = "could not write bitcode file: "; errMsg += path; Out.os().clear_error(); - return true; + return false; } Out.keep(); - return false; + return true; } bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) { // make unique temp .o file to put generated object file - sys::PathWithStatus uniqueObjPath("lto-llvm.o"); - if (uniqueObjPath.createTemporaryFileOnDisk(false, &errMsg)) { - uniqueObjPath.eraseFromDisk(); - return true; + SmallString<128> Filename; + int FD; + error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); + if (EC) { + errMsg = EC.message(); + return false; } - sys::RemoveFileOnSignal(uniqueObjPath); // generate object file - bool genResult = false; - tool_output_file objFile(uniqueObjPath.c_str(), errMsg); - if (!errMsg.empty()) { - uniqueObjPath.eraseFromDisk(); - return true; - } + tool_output_file objFile(Filename.c_str(), FD); - genResult = this->generateObjectFile(objFile.os(), errMsg); + bool genResult = generateObjectFile(objFile.os(), errMsg); objFile.os().close(); if (objFile.os().has_error()) { objFile.os().clear_error(); - uniqueObjPath.eraseFromDisk(); - return true; + sys::fs::remove(Twine(Filename)); + return false; } objFile.keep(); - if (genResult) { - uniqueObjPath.eraseFromDisk(); - return true; + if (!genResult) { + sys::fs::remove(Twine(Filename)); + return false; } - _nativeObjectPath = uniqueObjPath.str(); + _nativeObjectPath = Filename.c_str(); *name = _nativeObjectPath.c_str(); - return false; + return true; } const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { const char *name; - if (compile_to_file(&name, errMsg)) + if (!compile_to_file(&name, errMsg)) return NULL; // remove old buffer if compile() called twice @@ -205,13 +233,13 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { OwningPtr<MemoryBuffer> BuffPtr; if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) { errMsg = ec.message(); - sys::Path(_nativeObjectPath).eraseFromDisk(); + sys::fs::remove(_nativeObjectPath); return NULL; } _nativeObjectFile = BuffPtr.take(); // remove temp files - sys::Path(_nativeObjectPath).eraseFromDisk(); + sys::fs::remove(_nativeObjectPath); // return buffer, unless error if (_nativeObjectFile == NULL) @@ -222,7 +250,7 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { bool LTOCodeGenerator::determineTarget(std::string &errMsg) { if (_target != NULL) - return false; + return true; // if options were requested, set them if (!_codegenOptions.empty()) @@ -237,7 +265,7 @@ bool LTOCodeGenerator::determineTarget(std::string &errMsg) { // create target machine from info for merged modules const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); if (march == NULL) - return true; + return false; // The relocation model is actually a static member of TargetMachine and // needs to be set before the TargetMachine is instantiated. @@ -270,7 +298,7 @@ bool LTOCodeGenerator::determineTarget(std::string &errMsg) { _target = march->createTargetMachine(TripleStr, _mCpu, FeatureStr, Options, RelocModel, CodeModel::Default, CodeGenOpt::Aggressive); - return false; + return true; } void LTOCodeGenerator:: @@ -309,7 +337,7 @@ void LTOCodeGenerator::applyScopeRestrictions() { passes.add(createVerifierPass()); // mark which symbols can not be internalized - MCContext Context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(),NULL); + MCContext Context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL); Mangler mangler(Context, _target); std::vector<const char*> mustPreserveList; SmallPtrSet<GlobalValue*, 8> asmUsed; @@ -361,8 +389,8 @@ void LTOCodeGenerator::applyScopeRestrictions() { /// Optimize merged modules using various IPO passes bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, std::string &errMsg) { - if (this->determineTarget(errMsg)) - return true; + if (!this->determineTarget(errMsg)) + return false; Module* mergedModule = _linker.getModule(); @@ -405,7 +433,7 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, if (_target->addPassesToEmitFile(codeGenPasses, Out, TargetMachine::CGFT_ObjectFile)) { errMsg = "target file type not supported"; - return true; + return false; } // Run our queue of passes all at once now, efficiently. @@ -414,7 +442,7 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, // Run the code generator, and write assembly file codeGenPasses.run(*mergedModule); - return false; // success + return true; } /// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h index a4ade9f..8f37cf0 100644 --- a/tools/lto/LTOCodeGenerator.h +++ b/tools/lto/LTOCodeGenerator.h @@ -9,6 +9,27 @@ // // This file declares the LTOCodeGenerator class. // +// LTO compilation consists of three phases: Pre-IPO, IPO and Post-IPO. +// +// The Pre-IPO phase compiles source code into bitcode file. The resulting +// bitcode files, along with object files and libraries, will be fed to the +// linker to through the IPO and Post-IPO phases. By using obj-file extension, +// the resulting bitcode file disguises itself as an object file, and therefore +// obviates the need of writing a special set of the make-rules only for LTO +// compilation. +// +// The IPO phase perform inter-procedural analyses and optimizations, and +// the Post-IPO consists two sub-phases: intra-procedural scalar optimizations +// (SOPT), and intra-procedural target-dependent code generator (CG). +// +// As of this writing, we don't separate IPO and the Post-IPO SOPT. They +// are intermingled together, and are driven by a single pass manager (see +// PassManagerBuilder::populateLTOPassManager()). +// +// The "LTOCodeGenerator" is the driver for the IPO and Post-IPO stages. +// The "CodeGenerator" here is bit confusing. Don't confuse the "CodeGenerator" +// with the machine specific code generator. +// //===----------------------------------------------------------------------===// #ifndef LTO_CODE_GENERATOR_H @@ -40,9 +61,11 @@ struct LTOCodeGenerator { LTOCodeGenerator(); ~LTOCodeGenerator(); + // Merge given module, return true on success. bool addModule(struct LTOModule*, std::string &errMsg); - bool setDebugInfo(lto_debug_model, std::string &errMsg); - bool setCodePICModel(lto_codegen_model, std::string &errMsg); + + void setDebugInfo(lto_debug_model); + void setCodePICModel(lto_codegen_model); void setCpu(const char* mCpu) { _mCpu = mCpu; } @@ -50,12 +73,38 @@ struct LTOCodeGenerator { _mustPreserveSymbols[sym] = 1; } + // To pass options to the driver and optimization passes. These options are + // not necessarily for debugging purpose (The function name is misleading). + // This function should be called before LTOCodeGenerator::compilexxx(), + // and LTOCodeGenerator::writeMergedModules(). + // + void setCodeGenDebugOptions(const char *opts); + + // Write the merged module to the file specified by the given path. + // Return true on success. bool writeMergedModules(const char *path, std::string &errMsg); + + // Compile the merged module into a *single* object file; the path to object + // file is returned to the caller via argument "name". Return true on + // success. + // + // NOTE that it is up to the linker to remove the intermediate object file. + // Do not try to remove the object file in LTOCodeGenerator's destructor + // as we don't who (LTOCodeGenerator or the obj file) will last longer. + // bool compile_to_file(const char **name, std::string &errMsg); + + // As with compile_to_file(), this function compiles the merged module into + // single object file. Instead of returning the object-file-path to the caller + // (linker), it brings the object to a buffer, and return the buffer to the + // caller. This function should delete intermediate object file once its content + // is brought to memory. Return NULL is the compilation was not successful. + // const void *compile(size_t *length, std::string &errMsg); - void setCodeGenDebugOptions(const char *opts); private: + void initializeLTOPasses(); + bool generateObjectFile(llvm::raw_ostream &out, std::string &errMsg); void applyScopeRestrictions(); void applyRestriction(llvm::GlobalValue &GV, diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index 263e8b3..e89733f 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -50,11 +50,6 @@ DisableFPElim("disable-fp-elim", cl::init(false)); static cl::opt<bool> -DisableFPElimNonLeaf("disable-non-leaf-fp-elim", - cl::desc("Disable frame pointer elimination optimization for non-leaf funcs"), - cl::init(false)); - -static cl::opt<bool> EnableUnsafeFPMath("enable-unsafe-fp-math", cl::desc("Enable optimizations that may decrease FP precision"), cl::init(false)); @@ -126,11 +121,6 @@ OverrideStackAlignment("stack-alignment", cl::desc("Override default stack alignment"), cl::init(0)); -static cl::opt<bool> -EnableRealignStack("realign-stack", - cl::desc("Realign stack if needed"), - cl::init(true)); - static cl::opt<std::string> TrapFuncName("trap-func", cl::Hidden, cl::desc("Emit a call to trap function rather than a trap instruction"), @@ -151,14 +141,9 @@ 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), + _context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL), _mangler(_context, t) {} /// isBitcodeFile - Returns 'true' if the file (or memory contents) is LLVM @@ -214,17 +199,16 @@ LTOModule *LTOModule::makeLTOModule(const char *path, std::string &errMsg) { LTOModule *LTOModule::makeLTOModule(int fd, const char *path, size_t size, std::string &errMsg) { - return makeLTOModule(fd, path, size, size, 0, errMsg); + return makeLTOModule(fd, path, size, 0, errMsg); } LTOModule *LTOModule::makeLTOModule(int fd, const char *path, - size_t file_size, size_t map_size, off_t offset, std::string &errMsg) { OwningPtr<MemoryBuffer> buffer; - if (error_code ec = MemoryBuffer::getOpenFile(fd, path, buffer, file_size, - map_size, offset, false)) { + if (error_code ec = + MemoryBuffer::getOpenFileSlice(fd, path, buffer, map_size, offset)) { errMsg = ec.message(); return NULL; } @@ -242,7 +226,6 @@ LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, void LTOModule::getTargetOptions(TargetOptions &Options) { Options.LessPreciseFPMADOption = EnableFPMAD; Options.NoFramePointerElim = DisableFPElim; - Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf; Options.AllowFPOpFusion = FuseFPOps; Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; @@ -256,12 +239,10 @@ void LTOModule::getTargetOptions(TargetOptions &Options) { Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.DisableTailCalls = DisableTailCalls; Options.StackAlignmentOverride = OverrideStackAlignment; - Options.RealignStack = EnableRealignStack; Options.TrapFuncName = TrapFuncName; Options.PositionIndependentExecutable = EnablePIE; Options.EnableSegmentedStacks = SegmentedStacks; Options.UseInitArray = UseInitArray; - Options.SSPBufferSize = SSPBufferSize; } LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, @@ -792,9 +773,8 @@ namespace { unsigned ByteAlignment) {} virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} - virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {} - virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) {} + virtual void EmitBytes(StringRef Data) {} + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size) {} virtual void EmitULEB128Value(const MCExpr *Value) {} virtual void EmitSLEB128Value(const MCExpr *Value) {} virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h index 83f3a7d..902e9c5 100644 --- a/tools/lto/LTOModule.h +++ b/tools/lto/LTOModule.h @@ -82,7 +82,6 @@ public: static LTOModule *makeLTOModule(int fd, const char *path, size_t size, std::string &errMsg); static LTOModule *makeLTOModule(int fd, const char *path, - size_t file_size, size_t map_size, off_t offset, std::string& errMsg); diff --git a/tools/lto/Makefile b/tools/lto/Makefile index 30719f4..56c67df 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -46,7 +46,7 @@ ifeq ($(HOST_OS),Darwin) ifneq ($(DARWIN_VERS),8) LLVMLibsOptions := $(LLVMLibsOptions) \ -Wl,-install_name \ - -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif # If we're doing an Apple-style build, add the LTO object path. diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index 11ad532..db7147c 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -78,8 +78,7 @@ lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path, size_t file_size, size_t map_size, off_t offset) { - return LTOModule::makeLTOModule(fd, path, file_size, map_size, - offset, sLastErrorString); + return LTOModule::makeLTOModule(fd, path, map_size, offset, sLastErrorString); } /// lto_module_create_from_memory - Loads an object file from memory. Returns @@ -141,20 +140,22 @@ void lto_codegen_dispose(lto_code_gen_t cg) { /// which code will be generated. Returns true on error (check /// lto_get_error_message() for details). bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod) { - return cg->addModule(mod, sLastErrorString); + return !cg->addModule(mod, sLastErrorString); } /// lto_codegen_set_debug_model - Sets what if any format of debug info should /// be generated. Returns true on error (check lto_get_error_message() for /// details). bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug) { - return cg->setDebugInfo(debug, sLastErrorString); + cg->setDebugInfo(debug); + return false; } /// lto_codegen_set_pic_model - Sets what code model to generated. Returns true /// on error (check lto_get_error_message() for details). bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model) { - return cg->setCodePICModel(model, sLastErrorString); + cg->setCodePICModel(model); + return false; } /// lto_codegen_set_cpu - Sets the cpu to generate code for. @@ -186,7 +187,7 @@ void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, /// that contains the merged contents of all modules added so far. Returns true /// on error (check lto_get_error_message() for details). bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) { - return cg->writeMergedModules(path, sLastErrorString); + return !cg->writeMergedModules(path, sLastErrorString); } /// lto_codegen_compile - Generates code for all added modules into one native @@ -203,7 +204,7 @@ const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) { /// native object file. The name of the file is written to name. Returns true on /// error. bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) { - return cg->compile_to_file(name, sLastErrorString); + return !cg->compile_to_file(name, sLastErrorString); } /// lto_codegen_debug_options - Used to pass extra options to the code diff --git a/tools/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 0ec35bf..1e28c4e 100644 --- a/tools/obj2yaml/coff2yaml.cpp +++ b/tools/obj2yaml/coff2yaml.cpp @@ -38,7 +38,7 @@ static void check(error_code ec) { COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) { const object::coff_file_header *Header; - check(Obj.getHeader(Header)); + check(Obj.getCOFFHeader(Header)); dumpHeader(Header); dumpSections(Header->NumberOfSections); dumpSymbols(Header->NumberOfSymbols); diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 57b03b4..37637ca 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -389,8 +389,11 @@ struct BreakpointPrinter : public ModulePass { for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { std::string Name; DISubprogram SP(NMD->getOperand(i)); - if (SP.Verify()) - getContextName(SP.getContext(), Name); + assert((!SP || SP.isSubprogram()) && + "A MDNode in llvm.dbg.sp should be null or a DISubprogram."); + if (!SP) + continue; + getContextName(SP.getContext(), Name); Name = Name + SP.getDisplayName().str(); if (!Name.empty() && Processed.insert(Name)) { Out << Name << "\n"; @@ -445,7 +448,6 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM, } Builder.DisableUnitAtATime = !UnitAtATime; Builder.DisableUnrollLoops = OptLevel == 0; - Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls; Builder.populateFunctionPassManager(FPM); Builder.populateModulePassManager(MPM); @@ -465,7 +467,6 @@ static void AddStandardCompilePasses(PassManagerBase &PM) { if (!DisableInline) Builder.Inliner = createFunctionInliningPass(); Builder.OptLevel = 3; - Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls; Builder.populateModulePassManager(PM); } @@ -490,7 +491,6 @@ static TargetOptions GetTargetOptions() { TargetOptions Options; Options.LessPreciseFPMADOption = EnableFPMAD; Options.NoFramePointerElim = DisableFPElim; - Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf; Options.AllowFPOpFusion = FuseFPOps; Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; @@ -504,12 +504,10 @@ static TargetOptions GetTargetOptions() { Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.DisableTailCalls = DisableTailCalls; Options.StackAlignmentOverride = OverrideStackAlignment; - Options.RealignStack = EnableRealignStack; Options.TrapFuncName = TrapFuncName; Options.PositionIndependentExecutable = EnablePIE; Options.EnableSegmentedStacks = SegmentedStacks; Options.UseInitArray = UseInitArray; - Options.SSPBufferSize = SSPBufferSize; return Options; } @@ -615,7 +613,7 @@ int main(int argc, char **argv) { std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + sys::fs::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; @@ -668,6 +666,9 @@ int main(int argc, char **argv) { FPasses.reset(new FunctionPassManager(M.get())); if (TD) FPasses->add(new DataLayout(*TD)); + if (TM.get()) + TM->addAnalysisPasses(*FPasses); + } if (PrintBreakpoints) { @@ -678,7 +679,7 @@ int main(int argc, char **argv) { std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + sys::fs::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index 45ccb62..61252a4 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -22,13 +22,232 @@ using namespace llvm; +// There is similar code in yaml2coff, but with some slight COFF-specific +// variations like different initial state. Might be able to deduplicate +// some day, but also want to make sure that the Mach-O use case is served. +// +// This class has a deliberately small interface, since a lot of +// implementation variation is possible. +// +// TODO: Use an ordered container with a suffix-based comparison in order +// to deduplicate suffixes. std::map<> with a custom comparator is likely +// to be the simplest implementation, but a suffix trie could be more +// suitable for the job. +namespace { +class StringTableBuilder { + /// \brief Indices of strings currently present in `Buf`. + StringMap<unsigned> StringIndices; + /// \brief The contents of the string table as we build it. + std::string Buf; +public: + StringTableBuilder() { + Buf.push_back('\0'); + } + /// \returns Index of string in string table. + unsigned addString(StringRef S) { + StringMapEntry<unsigned> &Entry = StringIndices.GetOrCreateValue(S); + unsigned &I = Entry.getValue(); + if (I != 0) + return I; + I = Buf.size(); + Buf.append(S.begin(), S.end()); + Buf.push_back('\0'); + return I; + } + size_t size() const { + return Buf.size(); + } + void writeToStream(raw_ostream &OS) { + OS.write(Buf.data(), Buf.size()); + } +}; +} // end anonymous namespace + +// This class is used to build up a contiguous binary blob while keeping +// track of an offset in the output (which notionally begins at +// `InitialOffset`). +namespace { +class ContiguousBlobAccumulator { + const uint64_t InitialOffset; + SmallVector<char, 128> Buf; + raw_svector_ostream OS; + + /// \returns The new offset. + uint64_t padToAlignment(unsigned Align) { + uint64_t CurrentOffset = InitialOffset + OS.tell(); + uint64_t AlignedOffset = RoundUpToAlignment(CurrentOffset, Align); + for (; CurrentOffset != AlignedOffset; ++CurrentOffset) + OS.write('\0'); + return AlignedOffset; // == CurrentOffset; + } + +public: + ContiguousBlobAccumulator(uint64_t InitialOffset_) + : InitialOffset(InitialOffset_), Buf(), OS(Buf) {} + template <class Integer> + raw_ostream &getOSAndAlignedOffset(Integer &Offset, unsigned Align = 16) { + Offset = padToAlignment(Align); + return OS; + } + void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); } +}; +} // end anonymous namespace + +// Used to keep track of section names, so that in the YAML file sections +// can be referenced by name instead of by index. +namespace { +class SectionNameToIdxMap { + StringMap<int> Map; +public: + /// \returns true if name is already present in the map. + bool addName(StringRef SecName, unsigned i) { + StringMapEntry<int> &Entry = Map.GetOrCreateValue(SecName, -1); + if (Entry.getValue() != -1) + return true; + Entry.setValue((int)i); + return false; + } + /// \returns true if name is not present in the map + bool lookupSection(StringRef SecName, unsigned &Idx) const { + StringMap<int>::const_iterator I = Map.find(SecName); + if (I == Map.end()) + return true; + Idx = I->getValue(); + return false; + } +}; +} // end anonymous namespace + +template <class T> +static size_t vectorDataSize(const std::vector<T> &Vec) { + return Vec.size() * sizeof(T); +} + +template <class T> +static void writeVectorData(raw_ostream &OS, const std::vector<T> &Vec) { + OS.write((const char *)Vec.data(), vectorDataSize(Vec)); +} + +template <class T> +static void zero(T &Obj) { + memset(&Obj, 0, sizeof(Obj)); +} + +/// \brief Create a string table in `SHeader`, which we assume is already +/// zero'd. +template <class Elf_Shdr> +static void createStringTableSectionHeader(Elf_Shdr &SHeader, + StringTableBuilder &STB, + ContiguousBlobAccumulator &CBA) { + SHeader.sh_type = ELF::SHT_STRTAB; + STB.writeToStream(CBA.getOSAndAlignedOffset(SHeader.sh_offset)); + SHeader.sh_size = STB.size(); + SHeader.sh_addralign = 1; +} + +namespace { +/// \brief "Single point of truth" for the ELF file construction. +/// TODO: This class still has a ways to go before it is truly a "single +/// point of truth". template <class ELFT> -static void writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { - const ELFYAML::FileHeader &Hdr = Doc.Header; +class ELFState { + /// \brief The future ".strtab" section. + StringTableBuilder DotStrtab; + /// \brief The section number of the ".strtab" section. + unsigned DotStrtabSecNo; + /// \brief The accumulated contents of all sections so far. + ContiguousBlobAccumulator &SectionContentAccum; + typedef typename object::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr; + /// \brief The ELF file header. + Elf_Ehdr &Header; + + SectionNameToIdxMap &SN2I; + +public: + + ELFState(Elf_Ehdr &Header_, ContiguousBlobAccumulator &Accum, + unsigned DotStrtabSecNo_, SectionNameToIdxMap &SN2I_) + : DotStrtab(), DotStrtabSecNo(DotStrtabSecNo_), + SectionContentAccum(Accum), Header(Header_), SN2I(SN2I_) {} + + unsigned getDotStrTabSecNo() const { return DotStrtabSecNo; } + StringTableBuilder &getStringTable() { return DotStrtab; } + ContiguousBlobAccumulator &getSectionContentAccum() { + return SectionContentAccum; + } + SectionNameToIdxMap &getSN2I() { return SN2I; } +}; +} // end anonymous namespace + +// FIXME: At this point it is fairly clear that we need to refactor these +// static functions into methods of a class sharing some typedefs. These +// ELF type names are insane. +template <class ELFT> +static void +addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, ELFState<ELFT> &State, + std::vector<typename object::ELFObjectFile<ELFT>::Elf_Sym> &Syms, + unsigned SymbolBinding) { + typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + for (unsigned i = 0, e = Symbols.size(); i != e; ++i) { + const ELFYAML::Symbol &Sym = Symbols[i]; + Elf_Sym Symbol; + zero(Symbol); + if (!Sym.Name.empty()) + Symbol.st_name = State.getStringTable().addString(Sym.Name); + Symbol.setBindingAndType(SymbolBinding, Sym.Type); + if (!Sym.Section.empty()) { + unsigned Index; + if (State.getSN2I().lookupSection(Sym.Section, Index)) { + errs() << "error: Unknown section referenced: '" << Sym.Section + << "' by YAML symbol " << Sym.Name << ".\n"; + exit(1); + } + Symbol.st_shndx = Index; + } // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier. + Symbol.st_value = Sym.Value; + Symbol.st_size = Sym.Size; + Syms.push_back(Symbol); + } +} + +template <class ELFT> +static void handleSymtabSectionHeader( + const ELFYAML::LocalGlobalWeakSymbols &Symbols, ELFState<ELFT> &State, + typename object::ELFObjectFile<ELFT>::Elf_Shdr &SHeader) { + + typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + SHeader.sh_type = ELF::SHT_SYMTAB; + SHeader.sh_link = State.getDotStrTabSecNo(); + // One greater than symbol table index of the last local symbol. + SHeader.sh_info = Symbols.Local.size() + 1; + SHeader.sh_entsize = sizeof(Elf_Sym); + + std::vector<Elf_Sym> Syms; + { + // Ensure STN_UNDEF is present + Elf_Sym Sym; + zero(Sym); + Syms.push_back(Sym); + } + addSymbols(Symbols.Local, State, Syms, ELF::STB_LOCAL); + addSymbols(Symbols.Global, State, Syms, ELF::STB_GLOBAL); + addSymbols(Symbols.Weak, State, Syms, ELF::STB_WEAK); + + ContiguousBlobAccumulator &CBA = State.getSectionContentAccum(); + writeVectorData(CBA.getOSAndAlignedOffset(SHeader.sh_offset), Syms); + SHeader.sh_size = vectorDataSize(Syms); +} + +template <class ELFT> +static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { using namespace llvm::ELF; - using namespace llvm::object; - typename ELFObjectFile<ELFT>::Elf_Ehdr Header; - memset(&Header, 0, sizeof(Header)); + typedef typename object::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr; + typedef typename object::ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr; + + const ELFYAML::FileHeader &Hdr = Doc.Header; + + Elf_Ehdr Header; + zero(Header); Header.e_ident[EI_MAG0] = 0x7f; Header.e_ident[EI_MAG1] = 'E'; Header.e_ident[EI_MAG2] = 'L'; @@ -36,22 +255,120 @@ static void writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { 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; - - // TODO: Implement ELF_ELFOSABI enum. - Header.e_ident[EI_OSABI] = ELFOSABI_NONE; - // TODO: Implement ELF_ABIVERSION enum. + 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(Header); + Header.e_ehsize = sizeof(Elf_Ehdr); + + // TODO: Flesh out section header support. + // TODO: Program headers. - // TODO: Section headers and program headers. + Header.e_shentsize = sizeof(Elf_Shdr); + // Immediately following the ELF header. + Header.e_shoff = sizeof(Header); + const std::vector<ELFYAML::Section> &Sections = Doc.Sections; + // "+ 4" for + // - SHT_NULL entry (placed first, i.e. 0'th entry) + // - symbol table (.symtab) (placed third to last) + // - string table (.strtab) (placed second to last) + // - section header string table. (placed last) + Header.e_shnum = Sections.size() + 4; + // Place section header string table last. + Header.e_shstrndx = Header.e_shnum - 1; + const unsigned DotStrtabSecNo = Header.e_shnum - 2; + + // XXX: This offset is tightly coupled with the order that we write + // things to `OS`. + const size_t SectionContentBeginOffset = + Header.e_ehsize + Header.e_shentsize * Header.e_shnum; + ContiguousBlobAccumulator CBA(SectionContentBeginOffset); + SectionNameToIdxMap SN2I; + for (unsigned i = 0, e = Sections.size(); i != e; ++i) { + StringRef Name = Sections[i].Name; + if (Name.empty()) + continue; + // "+ 1" to take into account the SHT_NULL entry. + if (SN2I.addName(Name, i + 1)) { + errs() << "error: Repeated section name: '" << Name + << "' at YAML section number " << i << ".\n"; + return 1; + } + } + + ELFState<ELFT> State(Header, CBA, DotStrtabSecNo, SN2I); + + StringTableBuilder SHStrTab; + std::vector<Elf_Shdr> SHeaders; + { + // Ensure SHN_UNDEF entry is present. An all-zero section header is a + // valid SHN_UNDEF entry since SHT_NULL == 0. + Elf_Shdr SHdr; + zero(SHdr); + SHeaders.push_back(SHdr); + } + for (unsigned i = 0, e = Sections.size(); i != e; ++i) { + const ELFYAML::Section &Sec = Sections[i]; + Elf_Shdr SHeader; + zero(SHeader); + SHeader.sh_name = SHStrTab.addString(Sec.Name); + SHeader.sh_type = Sec.Type; + SHeader.sh_flags = Sec.Flags; + SHeader.sh_addr = Sec.Address; + + Sec.Content.writeAsBinary(CBA.getOSAndAlignedOffset(SHeader.sh_offset)); + SHeader.sh_size = Sec.Content.binary_size(); + + if (!Sec.Link.empty()) { + unsigned Index; + if (SN2I.lookupSection(Sec.Link, Index)) { + errs() << "error: Unknown section referenced: '" << Sec.Link + << "' at YAML section number " << i << ".\n"; + return 1; + } + SHeader.sh_link = Index; + } + SHeader.sh_info = 0; + SHeader.sh_addralign = Sec.AddressAlign; + SHeader.sh_entsize = 0; + SHeaders.push_back(SHeader); + } + + // .symtab section. + Elf_Shdr SymtabSHeader; + zero(SymtabSHeader); + SymtabSHeader.sh_name = SHStrTab.addString(StringRef(".symtab")); + handleSymtabSectionHeader<ELFT>(Doc.Symbols, State, SymtabSHeader); + SHeaders.push_back(SymtabSHeader); + + // .strtab string table header. + Elf_Shdr DotStrTabSHeader; + zero(DotStrTabSHeader); + DotStrTabSHeader.sh_name = SHStrTab.addString(StringRef(".strtab")); + createStringTableSectionHeader(DotStrTabSHeader, State.getStringTable(), CBA); + SHeaders.push_back(DotStrTabSHeader); + + // Section header string table header. + Elf_Shdr SHStrTabSHeader; + zero(SHStrTabSHeader); + createStringTableSectionHeader(SHStrTabSHeader, SHStrTab, CBA); + SHeaders.push_back(SHStrTabSHeader); OS.write((const char *)&Header, sizeof(Header)); + writeVectorData(OS, SHeaders); + CBA.writeBlobToStream(OS); + return 0; +} + +static bool is64Bit(const ELFYAML::Object &Doc) { + return Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); +} + +static bool isLittleEndian(const ELFYAML::Object &Doc) { + return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); } int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { @@ -62,17 +379,20 @@ int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { errs() << "yaml2obj: Failed to parse YAML file!\n"; return 1; } - if (Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64)) { - if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB)) - writeELF<object::ELFType<support::little, 8, true> >(outs(), Doc); + 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 - writeELF<object::ELFType<support::big, 8, true> >(outs(), Doc); + return writeELF<BE64>(outs(), Doc); } else { - if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB)) - writeELF<object::ELFType<support::little, 4, false> >(outs(), Doc); + if (isLittleEndian(Doc)) + return writeELF<LE32>(outs(), Doc); else - writeELF<object::ELFType<support::big, 4, false> >(outs(), Doc); + return writeELF<BE32>(outs(), Doc); } - - return 0; } |