diff options
Diffstat (limited to 'llvm/tools')
72 files changed, 2321 insertions, 1751 deletions
diff --git a/llvm/tools/bugpoint/CrashDebugger.cpp b/llvm/tools/bugpoint/CrashDebugger.cpp index aab9debf9b59..aa88a06a6df0 100644 --- a/llvm/tools/bugpoint/CrashDebugger.cpp +++ b/llvm/tools/bugpoint/CrashDebugger.cpp @@ -16,11 +16,11 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringSet.h" #include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/Transforms/Utils/Local.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" @@ -32,6 +32,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/Local.h" #include <set> using namespace llvm; @@ -43,6 +44,10 @@ cl::opt<bool> NoGlobalRM("disable-global-remove", cl::desc("Do not remove global variables"), cl::init(false)); +cl::opt<bool> NoAttributeRM("disable-attribute-remove", + cl::desc("Do not remove function attributes"), + cl::init(false)); + cl::opt<bool> ReplaceFuncsWithNull( "replace-funcs-with-null", cl::desc("When stubbing functions, replace all uses will null"), @@ -359,6 +364,11 @@ bool ReduceCrashingFunctionAttributes::TestFuncAttrs( // Set this new list of attributes on the function. F->setAttributes(NewAttrs); + // If the attribute list includes "optnone" we need to make sure it also + // includes "noinline" otherwise we will get a verifier failure. + if (F->hasFnAttribute(Attribute::OptimizeNone)) + F->addFnAttr(Attribute::NoInline); + // Try running on the hacked up program... if (TestFn(BD, M.get())) { BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version... @@ -806,6 +816,78 @@ bool ReduceCrashingInstructions::TestInsts( } namespace { +/// ReduceCrashingMetadata reducer - This works by removing all metadata from +/// the specified instructions. +/// +class ReduceCrashingMetadata : public ListReducer<Instruction *> { + BugDriver &BD; + BugTester TestFn; + +public: + ReduceCrashingMetadata(BugDriver &bd, BugTester testFn) + : BD(bd), TestFn(testFn) {} + + Expected<TestResult> doTest(std::vector<Instruction *> &Prefix, + std::vector<Instruction *> &Kept) override { + if (!Kept.empty() && TestInsts(Kept)) + return KeepSuffix; + if (!Prefix.empty() && TestInsts(Prefix)) + return KeepPrefix; + return NoFailure; + } + + bool TestInsts(std::vector<Instruction *> &Prefix); +}; +} // namespace + +bool ReduceCrashingMetadata::TestInsts(std::vector<Instruction *> &Insts) { + // Clone the program to try hacking it apart... + ValueToValueMapTy VMap; + std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap); + + // Convert list to set for fast lookup... + SmallPtrSet<Instruction *, 32> Instructions; + for (Instruction *I : Insts) + Instructions.insert(cast<Instruction>(VMap[I])); + + outs() << "Checking for crash with metadata retained from " + << Instructions.size(); + if (Instructions.size() == 1) + outs() << " instruction: "; + else + outs() << " instructions: "; + + // Try to drop instruction metadata from all instructions, except the ones + // selected in Instructions. + for (Function &F : *M) + for (Instruction &Inst : instructions(F)) { + if (Instructions.find(&Inst) == Instructions.end()) { + Inst.dropUnknownNonDebugMetadata(); + Inst.setDebugLoc({}); + } + } + + // Verify that this is still valid. + legacy::PassManager Passes; + Passes.add(createVerifierPass(/*FatalErrors=*/false)); + Passes.run(*M); + + // Try running on the hacked up program... + if (TestFn(BD, M.get())) { + BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version... + + // Make sure to use instruction pointers that point into the now-current + // module, and that they don't include any deleted blocks. + Insts.clear(); + for (Instruction *I : Instructions) + Insts.push_back(I); + return true; + } + // It didn't crash, try something else. + return false; +} + +namespace { // Reduce the list of Named Metadata nodes. We keep this as a list of // names to avoid having to convert back and forth every time. class ReduceCrashingNamedMD : public ListReducer<std::string> { @@ -1081,6 +1163,21 @@ static Error ReduceInsts(BugDriver &BD, BugTester TestFn) { } } while (Simplification); + + // Attempt to drop metadata from instructions that does not contribute to the + // crash. + if (!BugpointIsInterrupted) { + std::vector<Instruction *> Insts; + for (Function &F : BD.getProgram()) + for (Instruction &I : instructions(F)) + Insts.push_back(&I); + + Expected<bool> Result = + ReduceCrashingMetadata(BD, TestFn).reduceList(Insts); + if (Error E = Result.takeError()) + return E; + } + BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions"); return Error::success(); } @@ -1115,36 +1212,38 @@ static Error DebugACrash(BugDriver &BD, BugTester TestFn) { BD.EmitProgressBitcode(BD.getProgram(), "reduced-function"); } - // For each remaining function, try to reduce that function's attributes. - std::vector<std::string> FunctionNames; - for (Function &F : BD.getProgram()) - FunctionNames.push_back(F.getName()); + if (!NoAttributeRM) { + // For each remaining function, try to reduce that function's attributes. + std::vector<std::string> FunctionNames; + for (Function &F : BD.getProgram()) + FunctionNames.push_back(F.getName()); - if (!FunctionNames.empty() && !BugpointIsInterrupted) { - outs() << "\n*** Attempting to reduce the number of function attributes in " - "the testcase\n"; + if (!FunctionNames.empty() && !BugpointIsInterrupted) { + outs() << "\n*** Attempting to reduce the number of function attributes" + " in the testcase\n"; - unsigned OldSize = 0; - unsigned NewSize = 0; - for (std::string &Name : FunctionNames) { - Function *Fn = BD.getProgram().getFunction(Name); - assert(Fn && "Could not find funcion?"); + unsigned OldSize = 0; + unsigned NewSize = 0; + for (std::string &Name : FunctionNames) { + Function *Fn = BD.getProgram().getFunction(Name); + assert(Fn && "Could not find funcion?"); - std::vector<Attribute> Attrs; - for (Attribute A : Fn->getAttributes().getFnAttributes()) - Attrs.push_back(A); + std::vector<Attribute> Attrs; + for (Attribute A : Fn->getAttributes().getFnAttributes()) + Attrs.push_back(A); - OldSize += Attrs.size(); - Expected<bool> Result = + OldSize += Attrs.size(); + Expected<bool> Result = ReduceCrashingFunctionAttributes(BD, Name, TestFn).reduceList(Attrs); - if (Error E = Result.takeError()) - return E; + if (Error E = Result.takeError()) + return E; - NewSize += Attrs.size(); - } + NewSize += Attrs.size(); + } - if (OldSize < NewSize) - BD.EmitProgressBitcode(BD.getProgram(), "reduced-function-attributes"); + if (OldSize < NewSize) + BD.EmitProgressBitcode(BD.getProgram(), "reduced-function-attributes"); + } } // Attempt to change conditional branches into unconditional branches to @@ -1289,7 +1388,21 @@ Error BugDriver::debugOptimizerCrash(const std::string &ID) { EmitProgressBitcode(*Program, ID); - return DebugACrash(*this, TestForOptimizerCrash); + auto Res = DebugACrash(*this, TestForOptimizerCrash); + if (Res || DontReducePassList) + return Res; + // Try to reduce the pass list again. This covers additional cases + // we failed to reduce earlier, because of more complex pass dependencies + // triggering the crash. + auto SecondRes = ReducePassList(*this).reduceList(PassesToRun); + if (Error E = SecondRes.takeError()) + return E; + outs() << "\n*** Found crashing pass" + << (PassesToRun.size() == 1 ? ": " : "es: ") + << getPassesString(PassesToRun) << '\n'; + + EmitProgressBitcode(getProgram(), "reduced-simplified"); + return Res; } static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) { diff --git a/llvm/tools/bugpoint/bugpoint.cpp b/llvm/tools/bugpoint/bugpoint.cpp index c7644e75ae4b..d29a79ee3e13 100644 --- a/llvm/tools/bugpoint/bugpoint.cpp +++ b/llvm/tools/bugpoint/bugpoint.cpp @@ -18,8 +18,10 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/LegacyPassNameParser.h" +#include "llvm/InitializePasses.h" #include "llvm/LinkAllIR.h" #include "llvm/LinkAllPasses.h" +#include "llvm/Passes/PassPlugin.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/ManagedStatic.h" @@ -133,11 +135,9 @@ static void AddOptimizationPasses(legacy::FunctionPassManager &FPM, Builder.populateModulePassManager(FPM); } -#ifdef LINK_POLLY_INTO_TOOLS -namespace polly { -void initializePollyPasses(llvm::PassRegistry &Registry); -} -#endif +#define HANDLE_EXTENSION(Ext) \ + llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); +#include "llvm/Support/Extension.def" int main(int argc, char **argv) { #ifndef DEBUG_BUGPOINT @@ -158,10 +158,6 @@ int main(int argc, char **argv) { initializeInstrumentation(Registry); initializeTarget(Registry); -#ifdef LINK_POLLY_INTO_TOOLS - polly::initializePollyPasses(Registry); -#endif - if (std::getenv("bar") == (char*) -1) { InitializeAllTargets(); InitializeAllTargetMCs(); @@ -233,6 +229,13 @@ int main(int argc, char **argv) { sys::Process::PreventCoreFiles(); #endif +// Needed to pull in symbols from statically linked extensions, including static +// registration. It is unused otherwise because bugpoint has no support for +// NewPM. +#define HANDLE_EXTENSION(Ext) \ + (void)get##Ext##PluginInfo(); +#include "llvm/Support/Extension.def" + if (Error E = D.run()) { errs() << toString(std::move(E)); return 1; diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp index 574b15b399c3..b35f8e853c30 100644 --- a/llvm/tools/llc/llc.cpp +++ b/llvm/tools/llc/llc.cpp @@ -34,6 +34,7 @@ #include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" +#include "llvm/InitializePasses.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" @@ -202,7 +203,7 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName, OutputFilename = IFN; switch (FileType) { - case TargetMachine::CGFT_AssemblyFile: + case CGFT_AssemblyFile: if (TargetName[0] == 'c') { if (TargetName[1] == 0) OutputFilename += ".cbe.c"; @@ -213,13 +214,13 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName, } else OutputFilename += ".s"; break; - case TargetMachine::CGFT_ObjectFile: + case CGFT_ObjectFile: if (OS == Triple::Win32) OutputFilename += ".obj"; else OutputFilename += ".o"; break; - case TargetMachine::CGFT_Null: + case CGFT_Null: OutputFilename += ".null"; break; } @@ -229,10 +230,10 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName, // Decide if we need "binary" output. bool Binary = false; switch (FileType) { - case TargetMachine::CGFT_AssemblyFile: + case CGFT_AssemblyFile: break; - case TargetMachine::CGFT_ObjectFile: - case TargetMachine::CGFT_Null: + case CGFT_ObjectFile: + case CGFT_Null: Binary = true; break; } @@ -394,6 +395,12 @@ static int compileModule(char **argv, LLVMContext &Context) { std::unique_ptr<Module> M; std::unique_ptr<MIRParser> MIR; Triple TheTriple; + std::string CPUStr = getCPUStr(), FeaturesStr = getFeaturesStr(); + + // Set attributes on functions as loaded from MIR from command line arguments. + auto setMIRFunctionAttributes = [&CPUStr, &FeaturesStr](Function &F) { + setFunctionAttributes(CPUStr, FeaturesStr, F); + }; bool SkipModule = MCPU == "help" || (!MAttrs.empty() && MAttrs.front() == "help"); @@ -402,7 +409,8 @@ static int compileModule(char **argv, LLVMContext &Context) { if (!SkipModule) { if (InputLanguage == "mir" || (InputLanguage == "" && StringRef(InputFilename).endswith(".mir"))) { - MIR = createMIRParserFromFile(InputFilename, Err, Context); + MIR = createMIRParserFromFile(InputFilename, Err, Context, + setMIRFunctionAttributes); if (MIR) M = MIR->parseIRModule(); } else @@ -432,8 +440,6 @@ static int compileModule(char **argv, LLVMContext &Context) { return 1; } - std::string CPUStr = getCPUStr(), FeaturesStr = getFeaturesStr(); - CodeGenOpt::Level OLvl = CodeGenOpt::Default; switch (OptLevel) { default: @@ -519,7 +525,7 @@ static int compileModule(char **argv, LLVMContext &Context) { setFunctionAttributes(CPUStr, FeaturesStr, *M); if (RelaxAll.getNumOccurrences() > 0 && - FileType != TargetMachine::CGFT_ObjectFile) + FileType != CGFT_ObjectFile) WithColor::warning(errs(), argv[0]) << ": warning: ignoring -mc-relax-all because filetype != obj"; @@ -530,7 +536,7 @@ static int compileModule(char **argv, LLVMContext &Context) { // so we can memcmp the contents in CompileTwice mode SmallVector<char, 0> Buffer; std::unique_ptr<raw_svector_ostream> BOS; - if ((FileType != TargetMachine::CGFT_AssemblyFile && + if ((FileType != CGFT_AssemblyFile && !Out->os().supportsSeeking()) || CompileTwice) { BOS = std::make_unique<raw_svector_ostream>(Buffer); diff --git a/llvm/tools/lli/RemoteJITUtils.h b/llvm/tools/lli/RemoteJITUtils.h index 8e80e73c8082..cc93294af0cf 100644 --- a/llvm/tools/lli/RemoteJITUtils.h +++ b/llvm/tools/lli/RemoteJITUtils.h @@ -13,7 +13,7 @@ #ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H #define LLVM_TOOLS_LLI_REMOTEJITUTILS_H -#include "llvm/ExecutionEngine/Orc/RawByteChannel.h" +#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h" #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include <mutex> diff --git a/llvm/tools/lli/lli.cpp b/llvm/tools/lli/lli.cpp index ccad06721414..bfe7e8f04303 100644 --- a/llvm/tools/lli/lli.cpp +++ b/llvm/tools/lli/lli.cpp @@ -792,11 +792,15 @@ int runOrcLazyJIT(const char *ProgName) { }); return TSM; }); + + orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout()); J->getMainJITDylib().addGenerator( ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - J->getDataLayout().getGlobalPrefix()))); + J->getDataLayout().getGlobalPrefix(), + [MainName = Mangle("main")](const orc::SymbolStringPtr &Name) { + return Name != MainName; + }))); - orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout()); orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides; ExitOnErr(CXXRuntimeOverrides.enable(J->getMainJITDylib(), Mangle)); @@ -850,12 +854,6 @@ int runOrcLazyJIT(const char *ProgName) { ExitOnErr(J->addObjectFile(std::move(Obj))); } - // Generate a argument string. - std::vector<std::string> Args; - Args.push_back(InputFile); - for (auto &Arg : InputArgv) - Args.push_back(Arg); - // Run any static constructors. ExitOnErr(J->runConstructors()); @@ -871,16 +869,11 @@ int runOrcLazyJIT(const char *ProgName) { // Run main. auto MainSym = ExitOnErr(J->lookup("main")); - typedef int (*MainFnPtr)(int, const char *[]); - std::vector<const char *> ArgV; - for (auto &Arg : Args) - ArgV.push_back(Arg.c_str()); - ArgV.push_back(nullptr); - - int ArgC = ArgV.size() - 1; - auto Main = - reinterpret_cast<MainFnPtr>(static_cast<uintptr_t>(MainSym.getAddress())); - auto Result = Main(ArgC, (const char **)ArgV.data()); + + typedef int (*MainFnPtr)(int, char *[]); + auto Result = orc::runAsMain( + jitTargetAddressToFunction<MainFnPtr>(MainSym.getAddress()), InputArgv, + StringRef(InputFile)); // Wait for -entry-point threads. for (auto &AltEntryThread : AltEntryThreads) diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp index c9cf217f7688..c339dfe1f33e 100644 --- a/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/llvm/tools/llvm-ar/llvm-ar.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/LLVMContext.h" @@ -56,20 +57,20 @@ static StringRef ToolName; // The basename of this program. static StringRef Stem; -const char RanlibHelp[] = R"( -OVERVIEW: LLVM Ranlib (llvm-ranlib) +const char RanlibHelp[] = R"(OVERVIEW: LLVM Ranlib (llvm-ranlib) This program generates an index to speed access to archives USAGE: llvm-ranlib <archive-file> OPTIONS: - -help - Display available options - -version - Display the version of this program + -h --help - Display available options + -v --version - Display the version of this program + -D - Use zero for timestamps and uids/gids (default) + -U - Use actual timestamps and uids/gids )"; -const char ArHelp[] = R"( -OVERVIEW: LLVM Archiver +const char ArHelp[] = R"(OVERVIEW: LLVM Archiver USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] [count] <archive> [files] llvm-ar -M [<mri-script] @@ -127,6 +128,13 @@ void printHelpMessage() { static unsigned MRILineNumber; static bool ParsingMRIScript; +// Show the error plus the usage message, and exit. +LLVM_ATTRIBUTE_NORETURN static void badUsage(Twine Error) { + WithColor::error(errs(), ToolName) << Error << "\n"; + printHelpMessage(); + exit(1); +} + // Show the error message and exit. LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { if (ParsingMRIScript) { @@ -134,9 +142,7 @@ LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { << "script line " << MRILineNumber << ": " << Error << "\n"; } else { WithColor::error(errs(), ToolName) << Error << "\n"; - printHelpMessage(); } - exit(1); } @@ -239,19 +245,19 @@ static void getRelPos() { // associated with the N modifier static void getCountParam() { if (PositionalArgs.empty()) - fail("expected [count] for 'N' modifier"); + badUsage("expected [count] for 'N' modifier"); auto CountParamArg = StringRef(PositionalArgs[0]); if (CountParamArg.getAsInteger(10, CountParam)) - fail("value for [count] must be numeric, got: " + CountParamArg); + badUsage("value for [count] must be numeric, got: " + CountParamArg); if (CountParam < 1) - fail("value for [count] must be positive, got: " + CountParamArg); + badUsage("value for [count] must be positive, got: " + CountParamArg); PositionalArgs.erase(PositionalArgs.begin()); } // Get the archive file name from the command line static void getArchive() { if (PositionalArgs.empty()) - fail("an archive name must be specified"); + badUsage("an archive name must be specified"); ArchiveName = PositionalArgs[0]; PositionalArgs.erase(PositionalArgs.begin()); } @@ -276,7 +282,7 @@ static void runMRIScript(); static ArchiveOperation parseCommandLine() { if (MRI) { if (!PositionalArgs.empty() || !Options.empty()) - fail("cannot mix -M and other options"); + badUsage("cannot mix -M and other options"); runMRIScript(); } @@ -389,7 +395,7 @@ static ArchiveOperation parseCommandLine() { printHelpMessage(); exit(0); default: - fail(std::string("unknown option ") + Options[i]); + badUsage(std::string("unknown option ") + Options[i]); } } @@ -404,31 +410,31 @@ static ArchiveOperation parseCommandLine() { NumOperations = 1; Operation = CreateSymTab; if (!Members.empty()) - fail("the 's' operation takes only an archive as argument"); + badUsage("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) - fail("you must specify at least one of the operations"); + badUsage("you must specify at least one of the operations"); if (NumOperations > 1) - fail("only one operation may be specified"); + badUsage("only one operation may be specified"); if (NumPositional > 1) - fail("you may only specify one of 'a', 'b', and 'i' modifiers"); + badUsage("you may only specify one of 'a', 'b', and 'i' modifiers"); if (AddAfter || AddBefore) if (Operation != Move && Operation != ReplaceOrInsert) - fail("the 'a', 'b' and 'i' modifiers can only be specified with " - "the 'm' or 'r' operations"); + badUsage("the 'a', 'b' and 'i' modifiers can only be specified with " + "the 'm' or 'r' operations"); if (CountParam) if (Operation != Extract && Operation != Delete) - fail("the 'N' modifier can only be specified with the 'x' or 'd' " - "operations"); + badUsage("the 'N' modifier can only be specified with the 'x' or 'd' " + "operations"); if (OriginalDates && Operation != Extract) - fail("the 'o' modifier is only applicable to the 'x' operation"); + badUsage("the 'o' modifier is only applicable to the 'x' operation"); if (OnlyUpdate && Operation != ReplaceOrInsert) - fail("the 'u' modifier is only applicable to the 'r' operation"); + badUsage("the 'u' modifier is only applicable to the 'r' operation"); if (AddLibrary && Operation != QuickAppend) - fail("the 'L' modifier is only applicable to the 'q' operation"); + badUsage("the 'L' modifier is only applicable to the 'q' operation"); // Return the parsed operation to the caller return Operation; @@ -530,8 +536,12 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) { failIfError(ModeOrErr.takeError()); sys::fs::perms Mode = ModeOrErr.get(); + llvm::StringRef outputFilePath = sys::path::filename(Name); + if (Verbose) + outs() << "x - " << outputFilePath << '\n'; + int FD; - failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD, + failIfError(sys::fs::openFileForWrite(outputFilePath, FD, sys::fs::CD_CreateAlways, sys::fs::OF_None, Mode), Name); @@ -1075,7 +1085,7 @@ static void runMRIScript() { } static bool handleGenericOption(StringRef arg) { - if (arg == "-help" || arg == "--help") { + if (arg == "-help" || arg == "--help" || arg == "-h") { printHelpMessage(); return true; } @@ -1092,7 +1102,7 @@ static int ar_main(int argc, char **argv) { cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv); for (size_t i = 1; i < Argv.size(); ++i) { StringRef Arg = Argv[i]; - const char *match; + const char *match = nullptr; auto MatchFlagWithArg = [&](const char *expected) { size_t len = strlen(expected); if (Arg == expected) { @@ -1148,15 +1158,38 @@ static int ar_main(int argc, char **argv) { static int ranlib_main(int argc, char **argv) { bool ArchiveSpecified = false; for (int i = 1; i < argc; ++i) { - if (handleGenericOption(argv[i])) { + StringRef arg(argv[i]); + if (handleGenericOption(arg)) { return 0; + } else if (arg.consume_front("-")) { + // Handle the -D/-U flag + while (!arg.empty()) { + if (arg.front() == 'D') { + Deterministic = true; + } else if (arg.front() == 'U') { + Deterministic = false; + } else if (arg.front() == 'h') { + printHelpMessage(); + return 0; + } else if (arg.front() == 'v') { + cl::PrintVersionMessage(); + return 0; + } else { + // TODO: GNU ranlib also supports a -t flag + fail("Invalid option: '-" + arg + "'"); + } + arg = arg.drop_front(1); + } } else { if (ArchiveSpecified) fail("exactly one archive should be specified"); ArchiveSpecified = true; - ArchiveName = argv[i]; + ArchiveName = arg.str(); } } + if (!ArchiveSpecified) { + badUsage("an archive name must be specified"); + } return performOperation(CreateSymTab, nullptr); } @@ -1169,16 +1202,25 @@ int main(int argc, char **argv) { llvm::InitializeAllAsmParsers(); Stem = sys::path::stem(ToolName); - if (Stem.contains_lower("dlltool")) + auto Is = [](StringRef Tool) { + // We need to recognize the following filenames. + // + // Lib.exe -> lib (see D44808, MSBuild runs Lib.exe) + // dlltool.exe -> dlltool + // arm-pokymllib32-linux-gnueabi-llvm-ar-10 -> ar + auto I = Stem.rfind_lower(Tool); + return I != StringRef::npos && + (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); + }; + + if (Is("dlltool")) return dlltoolDriverMain(makeArrayRef(argv, argc)); - - if (Stem.contains_lower("ranlib")) + if (Is("ranlib")) return ranlib_main(argc, argv); - - if (Stem.contains_lower("lib")) + if (Is("lib")) return libDriverMain(makeArrayRef(argv, argc)); - - if (Stem.contains_lower("ar")) + if (Is("ar")) return ar_main(argc, argv); + fail("not ranlib, ar, lib or dlltool"); } diff --git a/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 01cba1f6e3c9..639a6d1ec02c 100644 --- a/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -102,8 +102,9 @@ int main(int argc, char **argv) { O.Symbolic = !NonSymbolic; O.ShowBinaryBlobs = ShowBinaryBlobs; - ExitOnErr( - BA.analyze(O, CheckHash.empty() ? None : Optional<StringRef>(CheckHash))); + ExitOnErr(BA.analyze( + Dump ? Optional<BCDumpOptions>(O) : Optional<BCDumpOptions>(None), + CheckHash.empty() ? None : Optional<StringRef>(CheckHash))); if (Dump) outs() << "\n\n"; diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp index 7151cfb032f3..5f1e23f20d77 100644 --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -36,6 +36,7 @@ #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include <functional> #include <map> @@ -704,8 +705,8 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { // Read in -name-whitelist files. if (!NameFilterFiles.empty()) { std::string SpecialCaseListErr; - NameWhitelist = - SpecialCaseList::create(NameFilterFiles, SpecialCaseListErr); + NameWhitelist = SpecialCaseList::create( + NameFilterFiles, *vfs::getRealFileSystem(), SpecialCaseListErr); if (!NameWhitelist) error(SpecialCaseListErr); } diff --git a/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/llvm/tools/llvm-cov/CoverageExporterJson.cpp index 181d428ed9d8..216b5e3fd226 100644 --- a/llvm/tools/llvm-cov/CoverageExporterJson.cpp +++ b/llvm/tools/llvm-cov/CoverageExporterJson.cpp @@ -48,6 +48,7 @@ #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" #include <algorithm> +#include <limits> #include <mutex> #include <utility> @@ -61,14 +62,23 @@ using namespace llvm; namespace { +// The JSON library accepts int64_t, but profiling counts are stored as uint64_t. +// Therefore we need to explicitly convert from unsigned to signed, since a naive +// cast is implementation-defined behavior when the unsigned value cannot be +// represented as a signed value. We choose to clamp the values to preserve the +// invariant that counts are always >= 0. +int64_t clamp_uint64_to_int64(uint64_t u) { + return std::min(u, static_cast<uint64_t>(std::numeric_limits<int64_t>::max())); +} + json::Array renderSegment(const coverage::CoverageSegment &Segment) { - return json::Array({Segment.Line, Segment.Col, int64_t(Segment.Count), + return json::Array({Segment.Line, Segment.Col, clamp_uint64_to_int64(Segment.Count), Segment.HasCount, Segment.IsRegionEntry}); } json::Array renderRegion(const coverage::CountedRegion &Region) { return json::Array({Region.LineStart, Region.ColumnStart, Region.LineEnd, - Region.ColumnEnd, int64_t(Region.ExecutionCount), + Region.ColumnEnd, clamp_uint64_to_int64(Region.ExecutionCount), Region.FileID, Region.ExpandedFileID, int64_t(Region.Kind)}); } @@ -182,7 +192,7 @@ json::Array renderFunctions( for (const auto &F : Functions) FunctionArray.push_back( json::Object({{"name", F.Name}, - {"count", int64_t(F.ExecutionCount)}, + {"count", clamp_uint64_to_int64(F.ExecutionCount)}, {"regions", renderRegions(F.CountedRegions)}, {"filenames", json::Array(F.Filenames)}})); return FunctionArray; diff --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp index 9ac8bcf0ff01..6de512fc18dc 100644 --- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp +++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp @@ -7,8 +7,10 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/raw_ostream.h" #include <cstdlib> @@ -41,6 +43,13 @@ static cl::opt<bool> StripUnderscore("strip-underscore", static cl::alias StripUnderscoreShort("_", cl::desc("alias for --strip-underscore"), cl::aliasopt(StripUnderscore)); +static cl::opt<bool> + NoStripUnderscore("no-strip-underscore", + cl::desc("do not strip the leading underscore"), + cl::init(false)); +static cl::alias + NoStripUnderscoreShort("n", cl::desc("alias for --no-strip-underscore"), + cl::aliasopt(NoStripUnderscore)); static cl::opt<bool> Types("types", @@ -55,11 +64,22 @@ Decorated(cl::Positional, cl::desc("<mangled>"), cl::ZeroOrMore); static cl::extrahelp HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); -static std::string demangle(llvm::raw_ostream &OS, const std::string &Mangled) { +static bool shouldStripUnderscore() { + if (StripUnderscore) + return true; + if (NoStripUnderscore) + return false; + // If none of them are set, use the default value for platform. + // macho has symbols prefix with "_" so strip by default. + return Triple(sys::getProcessTriple()).isOSBinFormatMachO(); +} + +static std::string demangle(const std::string &Mangled) { int Status; + std::string Prefix; const char *DecoratedStr = Mangled.c_str(); - if (StripUnderscore) + if (shouldStripUnderscore()) if (DecoratedStr[0] == '_') ++DecoratedStr; size_t DecoratedLength = strlen(DecoratedStr); @@ -73,11 +93,11 @@ static std::string demangle(llvm::raw_ostream &OS, const std::string &Mangled) { if (!Undecorated && (DecoratedLength > 6 && strncmp(DecoratedStr, "__imp_", 6) == 0)) { - OS << "import thunk for "; + Prefix = "import thunk for "; Undecorated = itaniumDemangle(DecoratedStr + 6, nullptr, nullptr, &Status); } - std::string Result(Undecorated ? Undecorated : Mangled); + std::string Result(Undecorated ? Prefix + Undecorated : Mangled); free(Undecorated); return Result; } @@ -125,9 +145,9 @@ static void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) { SmallVector<std::pair<StringRef, StringRef>, 16> Words; SplitStringDelims(Mangled, Words, IsLegalItaniumChar); for (const auto &Word : Words) - Result += demangle(OS, Word.first) + Word.second.str(); + Result += ::demangle(Word.first) + Word.second.str(); } else - Result = demangle(OS, Mangled); + Result = ::demangle(Mangled); OS << Result << '\n'; OS.flush(); } diff --git a/llvm/tools/llvm-diff/DifferenceEngine.cpp b/llvm/tools/llvm-diff/DifferenceEngine.cpp index bc93ece86490..564ce7870592 100644 --- a/llvm/tools/llvm-diff/DifferenceEngine.cpp +++ b/llvm/tools/llvm-diff/DifferenceEngine.cpp @@ -732,5 +732,14 @@ void DifferenceEngine::diff(Module *L, Module *R) { bool DifferenceEngine::equivalentAsOperands(GlobalValue *L, GlobalValue *R) { if (globalValueOracle) return (*globalValueOracle)(L, R); + + if (isa<GlobalVariable>(L) && isa<GlobalVariable>(R)) { + GlobalVariable *GVL = cast<GlobalVariable>(L); + GlobalVariable *GVR = cast<GlobalVariable>(R); + if (GVL->hasLocalLinkage() && GVL->hasUniqueInitializer() && + GVR->hasLocalLinkage() && GVR->hasUniqueInitializer()) + return GVL->getInitializer() == GVR->getInitializer(); + } + return L->getName() == R->getName(); } diff --git a/llvm/tools/llvm-dis/llvm-dis.cpp b/llvm/tools/llvm-dis/llvm-dis.cpp index d66299cbf767..5d609468a380 100644 --- a/llvm/tools/llvm-dis/llvm-dis.cpp +++ b/llvm/tools/llvm-dis/llvm-dis.cpp @@ -158,53 +158,71 @@ int main(int argc, char **argv) { std::unique_ptr<MemoryBuffer> MB = ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFilename))); - std::unique_ptr<Module> M = ExitOnErr(getLazyBitcodeModule( - *MB, Context, /*ShouldLazyLoadMetadata=*/true, SetImporting)); - if (MaterializeMetadata) - ExitOnErr(M->materializeMetadata()); - else - ExitOnErr(M->materializeAll()); - - BitcodeLTOInfo LTOInfo = ExitOnErr(getBitcodeLTOInfo(*MB)); - std::unique_ptr<ModuleSummaryIndex> Index; - if (LTOInfo.HasSummary) - Index = ExitOnErr(getModuleSummaryIndex(*MB)); - - // Just use stdout. We won't actually print anything on it. - if (DontPrint) - OutputFilename = "-"; - - if (OutputFilename.empty()) { // Unspecified output, infer it. - if (InputFilename == "-") { - OutputFilename = "-"; + + BitcodeFileContents IF = ExitOnErr(llvm::getBitcodeFileContents(*MB)); + + const size_t N = IF.Mods.size(); + + if (OutputFilename == "-" && N > 1) + errs() << "only single module bitcode files can be written to stdout\n"; + + for (size_t i = 0; i < N; ++i) { + BitcodeModule MB = IF.Mods[i]; + std::unique_ptr<Module> M = ExitOnErr(MB.getLazyModule(Context, MaterializeMetadata, + SetImporting)); + if (MaterializeMetadata) + ExitOnErr(M->materializeMetadata()); + else + ExitOnErr(M->materializeAll()); + + BitcodeLTOInfo LTOInfo = ExitOnErr(MB.getLTOInfo()); + std::unique_ptr<ModuleSummaryIndex> Index; + if (LTOInfo.HasSummary) + Index = ExitOnErr(MB.getSummary()); + + std::string FinalFilename(OutputFilename); + + // Just use stdout. We won't actually print anything on it. + if (DontPrint) + FinalFilename = "-"; + + if (FinalFilename.empty()) { // Unspecified output, infer it. + if (InputFilename == "-") { + FinalFilename = "-"; + } else { + StringRef IFN = InputFilename; + FinalFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str(); + if (N > 1) + FinalFilename += std::string(".") + std::to_string(i); + FinalFilename += ".ll"; + } } else { - StringRef IFN = InputFilename; - OutputFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str(); - OutputFilename += ".ll"; + if (N > 1) + FinalFilename += std::string(".") + std::to_string(i); } - } - std::error_code EC; - std::unique_ptr<ToolOutputFile> Out( - new ToolOutputFile(OutputFilename, EC, sys::fs::OF_Text)); - if (EC) { - errs() << EC.message() << '\n'; - return 1; - } + std::error_code EC; + std::unique_ptr<ToolOutputFile> Out( + new ToolOutputFile(FinalFilename, EC, sys::fs::OF_Text)); + if (EC) { + errs() << EC.message() << '\n'; + return 1; + } - std::unique_ptr<AssemblyAnnotationWriter> Annotator; - if (ShowAnnotations) - Annotator.reset(new CommentWriter()); + std::unique_ptr<AssemblyAnnotationWriter> Annotator; + if (ShowAnnotations) + Annotator.reset(new CommentWriter()); - // All that llvm-dis does is write the assembly to a file. - if (!DontPrint) { - M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder); - if (Index) - Index->print(Out->os()); - } + // All that llvm-dis does is write the assembly to a file. + if (!DontPrint) { + M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder); + if (Index) + Index->print(Out->os()); + } - // Declare success. - Out->keep(); + // Declare success. + Out->keep(); + } return 0; } diff --git a/llvm/tools/llvm-dwarfdump/Statistics.cpp b/llvm/tools/llvm-dwarfdump/Statistics.cpp index c29ad783a9e6..5bef4d5148ca 100644 --- a/llvm/tools/llvm-dwarfdump/Statistics.cpp +++ b/llvm/tools/llvm-dwarfdump/Statistics.cpp @@ -60,28 +60,26 @@ struct PerFunctionStats { struct GlobalStats { /// Total number of PC range bytes covered by DW_AT_locations. unsigned ScopeBytesCovered = 0; - /// Total number of PC range bytes in each variable's enclosing scope, - /// starting from the first definition of the variable. - unsigned ScopeBytesFromFirstDefinition = 0; + /// Total number of PC range bytes in each variable's enclosing scope. + unsigned ScopeBytes = 0; /// Total number of PC range bytes covered by DW_AT_locations with /// the debug entry values (DW_OP_entry_value). unsigned ScopeEntryValueBytesCovered = 0; /// Total number of PC range bytes covered by DW_AT_locations of /// formal parameters. unsigned ParamScopeBytesCovered = 0; - /// Total number of PC range bytes in each variable's enclosing scope, - /// starting from the first definition of the variable (only for parameters). - unsigned ParamScopeBytesFromFirstDefinition = 0; + /// Total number of PC range bytes in each variable's enclosing scope + /// (only for parameters). + unsigned ParamScopeBytes = 0; /// Total number of PC range bytes covered by DW_AT_locations with /// the debug entry values (DW_OP_entry_value) (only for parameters). unsigned ParamScopeEntryValueBytesCovered = 0; /// Total number of PC range bytes covered by DW_AT_locations (only for local /// variables). unsigned VarScopeBytesCovered = 0; - /// Total number of PC range bytes in each variable's enclosing scope, - /// starting from the first definition of the variable (only for local - /// variables). - unsigned VarScopeBytesFromFirstDefinition = 0; + /// Total number of PC range bytes in each variable's enclosing scope + /// (only for local variables). + unsigned VarScopeBytes = 0; /// Total number of PC range bytes covered by DW_AT_locations with /// the debug entry values (DW_OP_entry_value) (only for local variables). unsigned VarScopeEntryValueBytesCovered = 0; @@ -133,19 +131,6 @@ struct LocationStats { unsigned NumVar = 0; }; -/// Extract the low pc from a Die. -static uint64_t getLowPC(DWARFDie Die) { - auto RangesOrError = Die.getAddressRanges(); - DWARFAddressRangesVector Ranges; - if (RangesOrError) - Ranges = RangesOrError.get(); - else - llvm::consumeError(RangesOrError.takeError()); - if (Ranges.size()) - return Ranges[0].LowPC; - return dwarf::toAddress(Die.find(dwarf::DW_AT_low_pc), 0); -} - /// Collect debug location statistics for one DIE. static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope, std::vector<unsigned> &VarParamLocStats, @@ -153,18 +138,16 @@ static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope, std::vector<unsigned> &VarLocStats, bool IsParam, bool IsLocalVar) { auto getCoverageBucket = [BytesCovered, BytesInScope]() -> unsigned { - unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope; - if (LocBucket == 0) { - // No debug location at all for the variable. + // No debug location at all for the variable. + if (BytesCovered == 0) return 0; - } else if (LocBucket == 100 || BytesCovered > BytesInScope) { - // Fully covered variable within its scope. + // Fully covered variable within its scope. + if (BytesCovered >= BytesInScope) return NumOfCoverageCategories - 1; - } else { - // Get covered range (e.g. 20%-29%). - LocBucket /= 10; - return LocBucket + 1; - } + // Get covered range (e.g. 20%-29%). + unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope; + LocBucket /= 10; + return LocBucket + 1; }; unsigned CoverageBucket = getCoverageBucket(); @@ -176,9 +159,9 @@ static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope, } /// Collect debug info quality metrics for one DIE. -static void collectStatsForDie(DWARFDie Die, uint64_t UnitLowPC, std::string FnPrefix, - std::string VarPrefix, uint64_t ScopeLowPC, - uint64_t BytesInScope, uint32_t InlineDepth, +static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, + std::string VarPrefix, uint64_t BytesInScope, + uint32_t InlineDepth, StringMap<PerFunctionStats> &FnStatMap, GlobalStats &GlobalStats, LocationStats &LocStats) { @@ -188,7 +171,6 @@ static void collectStatsForDie(DWARFDie Die, uint64_t UnitLowPC, std::string FnP bool IsArtificial = false; uint64_t BytesCovered = 0; uint64_t BytesEntryValuesCovered = 0; - uint64_t OffsetToFirstDefinition = 0; auto &FnStats = FnStatMap[FnPrefix]; bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter; bool IsLocalVar = Die.getTag() == dwarf::DW_TAG_variable; @@ -243,34 +225,25 @@ static void collectStatsForDie(DWARFDie Die, uint64_t UnitLowPC, std::string FnP return; } // Handle variables and function arguments. - auto FormValue = Die.find(dwarf::DW_AT_location); - HasLoc = FormValue.hasValue(); - if (HasLoc) { + Expected<std::vector<DWARFLocationExpression>> Loc = + Die.getLocations(dwarf::DW_AT_location); + if (!Loc) { + consumeError(Loc.takeError()); + } else { + HasLoc = true; // Get PC coverage. - if (auto DebugLocOffset = FormValue->getAsSectionOffset()) { - auto *DebugLoc = Die.getDwarfUnit()->getContext().getDebugLoc(); - if (auto List = DebugLoc->getLocationListAtOffset(*DebugLocOffset)) { - for (auto Entry : List->Entries) { - uint64_t BytesEntryCovered = Entry.End - Entry.Begin; - BytesCovered += BytesEntryCovered; - if (IsEntryValue(Entry.Loc)) - BytesEntryValuesCovered += BytesEntryCovered; - } - if (List->Entries.size()) { - uint64_t FirstDef = List->Entries[0].Begin; - uint64_t UnitOfs = UnitLowPC; - // Ranges sometimes start before the lexical scope. - if (UnitOfs + FirstDef >= ScopeLowPC) - OffsetToFirstDefinition = UnitOfs + FirstDef - ScopeLowPC; - // Or even after it. Count that as a failure. - if (OffsetToFirstDefinition > BytesInScope) - OffsetToFirstDefinition = 0; - } - } - assert(BytesInScope); - } else { + auto Default = find_if( + *Loc, [](const DWARFLocationExpression &L) { return !L.Range; }); + if (Default != Loc->end()) { // Assume the entire range is covered by a single location. BytesCovered = BytesInScope; + } else { + for (auto Entry : *Loc) { + uint64_t BytesEntryCovered = Entry.Range->HighPC - Entry.Range->LowPC; + BytesCovered += BytesEntryCovered; + if (IsEntryValue(Entry.Expr)) + BytesEntryValuesCovered += BytesEntryCovered; + } } } } @@ -303,25 +276,21 @@ static void collectStatsForDie(DWARFDie Die, uint64_t UnitLowPC, std::string FnP FnStats.VarsInFunction.insert(VarPrefix + VarName); if (BytesInScope) { FnStats.TotalVarWithLoc += (unsigned)HasLoc; - // Adjust for the fact the variables often start their lifetime in the - // middle of the scope. - BytesInScope -= OffsetToFirstDefinition; // Turns out we have a lot of ranges that extend past the lexical scope. GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered); - GlobalStats.ScopeBytesFromFirstDefinition += BytesInScope; + GlobalStats.ScopeBytes += BytesInScope; GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered; if (IsParam) { GlobalStats.ParamScopeBytesCovered += std::min(BytesInScope, BytesCovered); - GlobalStats.ParamScopeBytesFromFirstDefinition += BytesInScope; + GlobalStats.ParamScopeBytes += BytesInScope; GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered; } else if (IsLocalVar) { GlobalStats.VarScopeBytesCovered += std::min(BytesInScope, BytesCovered); - GlobalStats.VarScopeBytesFromFirstDefinition += BytesInScope; + GlobalStats.VarScopeBytes += BytesInScope; GlobalStats.VarScopeEntryValueBytesCovered += BytesEntryValuesCovered; } - assert(GlobalStats.ScopeBytesCovered <= - GlobalStats.ScopeBytesFromFirstDefinition); + assert(GlobalStats.ScopeBytesCovered <= GlobalStats.ScopeBytes); } else if (Die.getTag() == dwarf::DW_TAG_member) { FnStats.ConstantMembers++; } else { @@ -349,9 +318,9 @@ static void collectStatsForDie(DWARFDie Die, uint64_t UnitLowPC, std::string FnP } /// Recursively collect debug info quality metrics. -static void collectStatsRecursive(DWARFDie Die, uint64_t UnitLowPC, std::string FnPrefix, - std::string VarPrefix, uint64_t ScopeLowPC, - uint64_t BytesInScope, uint32_t InlineDepth, +static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix, + std::string VarPrefix, uint64_t BytesInScope, + uint32_t InlineDepth, StringMap<PerFunctionStats> &FnStatMap, GlobalStats &GlobalStats, LocationStats &LocStats) { @@ -386,7 +355,6 @@ static void collectStatsRecursive(DWARFDie Die, uint64_t UnitLowPC, std::string uint64_t BytesInThisScope = 0; for (auto Range : Ranges) BytesInThisScope += Range.HighPC - Range.LowPC; - ScopeLowPC = getLowPC(Die); // Count the function. if (!IsBlock) { @@ -422,8 +390,8 @@ static void collectStatsRecursive(DWARFDie Die, uint64_t UnitLowPC, std::string } } else { // Not a scope, visit the Die itself. It could be a variable. - collectStatsForDie(Die, UnitLowPC, FnPrefix, VarPrefix, ScopeLowPC, BytesInScope, - InlineDepth, FnStatMap, GlobalStats, LocStats); + collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth, + FnStatMap, GlobalStats, LocStats); } // Set InlineDepth correctly for child recursion @@ -440,9 +408,8 @@ static void collectStatsRecursive(DWARFDie Die, uint64_t UnitLowPC, std::string if (Child.getTag() == dwarf::DW_TAG_lexical_block) ChildVarPrefix += toHex(LexicalBlockIndex++) + '.'; - collectStatsRecursive(Child, UnitLowPC, FnPrefix, ChildVarPrefix, ScopeLowPC, - BytesInScope, InlineDepth, FnStatMap, GlobalStats, - LocStats); + collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, BytesInScope, + InlineDepth, FnStatMap, GlobalStats, LocStats); Child = Child.getSibling(); } } @@ -461,16 +428,16 @@ static void printLocationStats(raw_ostream &OS, << LocationStats[0]; LLVM_DEBUG(llvm::dbgs() << Key << " with 0% of its scope covered: " << LocationStats[0] << '\n'); - OS << ",\"" << Key << " with 1-9% of its scope covered\":" + OS << ",\"" << Key << " with (0%,10%) of its scope covered\":" << LocationStats[1]; - LLVM_DEBUG(llvm::dbgs() << Key << " with 1-9% of its scope covered: " + LLVM_DEBUG(llvm::dbgs() << Key << " with (0%,10%) of its scope covered: " << LocationStats[1] << '\n'); for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) { - OS << ",\"" << Key << " with " << (i - 1) * 10 << "-" << i * 10 - 1 - << "% of its scope covered\":" << LocationStats[i]; + OS << ",\"" << Key << " with [" << (i - 1) * 10 << "%," << i * 10 + << "%) of its scope covered\":" << LocationStats[i]; LLVM_DEBUG(llvm::dbgs() - << Key << " with " << (i - 1) * 10 << "-" << i * 10 - 1 - << "% of its scope covered: " << LocationStats[i]); + << Key << " with [" << (i - 1) * 10 << "%," << i * 10 + << "%) of its scope covered: " << LocationStats[i]); } OS << ",\"" << Key << " with 100% of its scope covered\":" << LocationStats[NumOfCoverageCategories - 1]; @@ -495,13 +462,13 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, StringMap<PerFunctionStats> Statistics; for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) - collectStatsRecursive(CUDie, getLowPC(CUDie), "/", "g", 0, 0, 0, - Statistics, GlobalStats, LocStats); + collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats, + LocStats); /// The version number should be increased every time the algorithm is changed /// (including bug fixes). New metrics may be added without increasing the /// version. - unsigned Version = 3; + unsigned Version = 4; unsigned VarParamTotal = 0; unsigned VarParamUnique = 0; unsigned VarParamWithLoc = 0; @@ -561,19 +528,17 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, printDatum(OS, "call site entries", GlobalStats.CallSiteEntries); printDatum(OS, "call site DIEs", GlobalStats.CallSiteDIEs); printDatum(OS, "call site parameter DIEs", GlobalStats.CallSiteParamDIEs); - printDatum(OS, "scope bytes total", - GlobalStats.ScopeBytesFromFirstDefinition); + printDatum(OS, "scope bytes total", GlobalStats.ScopeBytes); printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered); printDatum(OS, "entry value scope bytes covered", GlobalStats.ScopeEntryValueBytesCovered); printDatum(OS, "formal params scope bytes total", - GlobalStats.ParamScopeBytesFromFirstDefinition); + GlobalStats.ParamScopeBytes); printDatum(OS, "formal params scope bytes covered", GlobalStats.ParamScopeBytesCovered); printDatum(OS, "formal params entry value scope bytes covered", GlobalStats.ParamScopeEntryValueBytesCovered); - printDatum(OS, "vars scope bytes total", - GlobalStats.VarScopeBytesFromFirstDefinition); + printDatum(OS, "vars scope bytes total", GlobalStats.VarScopeBytes); printDatum(OS, "vars scope bytes covered", GlobalStats.VarScopeBytesCovered); printDatum(OS, "vars entry value scope bytes covered", GlobalStats.VarScopeEntryValueBytesCovered); @@ -608,7 +573,7 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, << "%\n"; llvm::dbgs() << "PC Ranges covered: " << (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) / - GlobalStats.ScopeBytesFromFirstDefinition) + GlobalStats.ScopeBytes) << "%\n"); return true; } diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index e20f6041f98d..374bdd482a8d 100644 --- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -271,7 +271,7 @@ static bool filterArch(ObjectFile &Obj) { return true; // Match as name. - if (MachO->getArchTriple().getArch() == Triple(Arch).getArch()) + if (MachO->getArchTriple().getArchName() == Triple(Arch).getArchName()) return true; } } diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp index 5e3b3dcb6c31..67a677dd45fb 100644 --- a/llvm/tools/llvm-lto2/llvm-lto2.cpp +++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -270,6 +270,8 @@ static int run(int argc, char **argv) { Conf.OverrideTriple = OverrideTriple; Conf.DefaultTriple = DefaultTriple; Conf.StatsFile = StatsFile; + Conf.PTO.LoopVectorization = Conf.OptLevel > 1; + Conf.PTO.SLPVectorization = Conf.OptLevel > 1; ThinBackend Backend; if (ThinLTODistributedIndexes) diff --git a/llvm/tools/llvm-mc/Disassembler.cpp b/llvm/tools/llvm-mc/Disassembler.cpp index 1ddbddfa1846..e286c0fff6e1 100644 --- a/llvm/tools/llvm-mc/Disassembler.cpp +++ b/llvm/tools/llvm-mc/Disassembler.cpp @@ -46,8 +46,7 @@ static bool PrintInsts(const MCDisassembler &DisAsm, MCInst Inst; MCDisassembler::DecodeStatus S; - S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, - /*REMOVE*/ nulls(), nulls()); + S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls()); switch (S) { case MCDisassembler::Fail: SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]), @@ -133,7 +132,8 @@ static bool ByteArrayFromString(ByteArrayTy &ByteArray, int Disassembler::disassemble(const Target &T, const std::string &Triple, MCSubtargetInfo &STI, MCStreamer &Streamer, MemoryBuffer &Buffer, SourceMgr &SM, - MCContext &Ctx, raw_ostream &Out) { + MCContext &Ctx, raw_ostream &Out, + const MCTargetOptions &MCOptions) { std::unique_ptr<const MCRegisterInfo> MRI(T.createMCRegInfo(Triple)); if (!MRI) { @@ -141,7 +141,8 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple, return -1; } - std::unique_ptr<const MCAsmInfo> MAI(T.createMCAsmInfo(*MRI, Triple)); + std::unique_ptr<const MCAsmInfo> MAI( + T.createMCAsmInfo(*MRI, Triple, MCOptions)); if (!MAI) { errs() << "error: no assembly info for target " << Triple << "\n"; return -1; diff --git a/llvm/tools/llvm-mc/Disassembler.h b/llvm/tools/llvm-mc/Disassembler.h index dcd8c279c91a..a1603e584980 100644 --- a/llvm/tools/llvm-mc/Disassembler.h +++ b/llvm/tools/llvm-mc/Disassembler.h @@ -25,13 +25,14 @@ class SourceMgr; class MCContext; class MCSubtargetInfo; class MCStreamer; +class MCTargetOptions; class Disassembler { public: static int disassemble(const Target &T, const std::string &Triple, MCSubtargetInfo &STI, MCStreamer &Streamer, MemoryBuffer &Buffer, SourceMgr &SM, MCContext &Ctx, - raw_ostream &Out); + raw_ostream &Out, const MCTargetOptions &MCOptions); }; } // namespace llvm diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp index c23740a3094d..6aa347d98be2 100644 --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -351,7 +351,8 @@ int main(int argc, char **argv) { std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); - std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); + std::unique_ptr<MCAsmInfo> MAI( + TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); assert(MAI && "Unable to create target asm info!"); MAI->setRelaxELFRelocations(RelaxELFRel); @@ -518,7 +519,7 @@ int main(int argc, char **argv) { } if (disassemble) Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, *Buffer, - SrcMgr, Ctx, Out->os()); + SrcMgr, Ctx, Out->os(), MCOptions); // Keep output if no errors. if (Res == 0) { diff --git a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp index feff0cd6d524..99deed6eae97 100644 --- a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp +++ b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp @@ -293,7 +293,7 @@ static void printInstruction(formatted_raw_ostream &FOS, FOS.PadToColumn(14); - MCIP.printInst(&MCI, InstrStream, "", STI); + MCIP.printInst(&MCI, 0, "", STI, InstrStream); InstrStream.flush(); if (UseDifferentColor) diff --git a/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp b/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp index 557b8ba17b17..a1c0cf208d35 100644 --- a/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp +++ b/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp @@ -37,7 +37,8 @@ void DispatchStatistics::printDispatchHistogram(raw_ostream &OS) const { TempStream << "\n\nDispatch Logic - " << "number of cycles where we saw N micro opcodes dispatched:\n"; TempStream << "[# dispatched], [# cycles]\n"; - for (const std::pair<unsigned, unsigned> &Entry : DispatchGroupSizePerCycle) { + for (const std::pair<const unsigned, unsigned> &Entry : + DispatchGroupSizePerCycle) { double Percentage = ((double)Entry.second / NumCycles) * 100.0; TempStream << " " << Entry.first << ", " << Entry.second << " (" << format("%.1f", floor((Percentage * 10) + 0.5) / 10) diff --git a/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp b/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp index a6f9153b4945..fbe9d9021554 100644 --- a/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp +++ b/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp @@ -95,7 +95,7 @@ void InstructionInfoView::printView(raw_ostream &OS) const { FOS.flush(); } - MCIP.printInst(&Inst, InstrStream, "", STI); + MCIP.printInst(&Inst, 0, "", STI, InstrStream); InstrStream.flush(); // Consume any tabs or spaces at the beginning of the string. diff --git a/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp b/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp index 38a2478cf4fe..bdb9dc21247b 100644 --- a/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp +++ b/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp @@ -163,7 +163,7 @@ void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const { printResourcePressure(FOS, Usage / Executions, (J + 1) * 7); } - MCIP.printInst(&MCI, InstrStream, "", STI); + MCIP.printInst(&MCI, 0, "", STI, InstrStream); InstrStream.flush(); StringRef Str(Instruction); diff --git a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp index cb4fbae78039..61c115b27be1 100644 --- a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp +++ b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp @@ -59,7 +59,7 @@ void RetireControlUnitStatistics::printView(raw_ostream &OS) const { << "number of cycles where we saw N instructions retired:\n"; TempStream << "[# retired], [# cycles]\n"; - for (const std::pair<unsigned, unsigned> &Entry : RetiredPerCycle) { + for (const std::pair<const unsigned, unsigned> &Entry : RetiredPerCycle) { TempStream << " " << Entry.first; if (Entry.first < 10) TempStream << ", "; diff --git a/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp b/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp index bd0ba350ab68..7a341d4c2079 100644 --- a/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp +++ b/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp @@ -107,7 +107,7 @@ void SchedulerStatistics::printSchedulerStats(raw_ostream &OS) const { bool HasColors = OS.has_colors(); const auto It = std::max_element(IssueWidthPerCycle.begin(), IssueWidthPerCycle.end()); - for (const std::pair<unsigned, unsigned> &Entry : IssueWidthPerCycle) { + for (const std::pair<const unsigned, unsigned> &Entry : IssueWidthPerCycle) { unsigned NumIssued = Entry.first; if (NumIssued == It->first && HasColors) OS.changeColor(raw_ostream::SAVEDCOLOR, true, false); diff --git a/llvm/tools/llvm-mca/Views/SummaryView.cpp b/llvm/tools/llvm-mca/Views/SummaryView.cpp index ef5550048f4c..f0e75f7b13ae 100644 --- a/llvm/tools/llvm-mca/Views/SummaryView.cpp +++ b/llvm/tools/llvm-mca/Views/SummaryView.cpp @@ -54,7 +54,7 @@ void SummaryView::onEvent(const HWInstructionEvent &Event) { const Instruction &Inst = *Event.IR.getInstruction(); const InstrDesc &Desc = Inst.getDesc(); NumMicroOps += Desc.NumMicroOps; - for (const std::pair<uint64_t, const ResourceUsage> &RU : Desc.Resources) { + for (const std::pair<uint64_t, ResourceUsage> &RU : Desc.Resources) { if (RU.second.size()) { unsigned ProcResID = ResIdx2ProcResID[getResourceStateIndex(RU.first)]; ProcResourceUsage[ProcResID] += RU.second.size(); diff --git a/llvm/tools/llvm-mca/Views/TimelineView.cpp b/llvm/tools/llvm-mca/Views/TimelineView.cpp index 1e7caa297ac6..cf5b48e811b8 100644 --- a/llvm/tools/llvm-mca/Views/TimelineView.cpp +++ b/llvm/tools/llvm-mca/Views/TimelineView.cpp @@ -192,7 +192,7 @@ void TimelineView::printAverageWaitTimes(raw_ostream &OS) const { for (const MCInst &Inst : Source) { printWaitTimeEntry(FOS, WaitTime[IID], IID, Executions); // Append the instruction info at the end of the line. - MCIP.printInst(&Inst, InstrStream, "", STI); + MCIP.printInst(&Inst, 0, "", STI, InstrStream); InstrStream.flush(); // Consume any tabs or spaces at the beginning of the string. @@ -307,7 +307,7 @@ void TimelineView::printTimeline(raw_ostream &OS) const { unsigned SourceIndex = IID % Source.size(); printTimelineViewEntry(FOS, Entry, Iteration, SourceIndex); // Append the instruction info at the end of the line. - MCIP.printInst(&Inst, InstrStream, "", STI); + MCIP.printInst(&Inst, 0, "", STI, InstrStream); InstrStream.flush(); // Consume any tabs or spaces at the beginning of the string. diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp index 99c45eebdd88..fff5906bb59b 100644 --- a/llvm/tools/llvm-mca/llvm-mca.cpp +++ b/llvm/tools/llvm-mca/llvm-mca.cpp @@ -353,7 +353,9 @@ int main(int argc, char **argv) { std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); - std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); + std::unique_ptr<MCAsmInfo> MAI( + TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); assert(MAI && "Unable to create target asm info!"); MCObjectFileInfo MOFI; @@ -472,7 +474,7 @@ int main(int argc, char **argv) { std::string InstructionStr; raw_string_ostream SS(InstructionStr); WithColor::error() << IE.Message << '\n'; - IP->printInst(&IE.Inst, SS, "", *STI); + IP->printInst(&IE.Inst, 0, "", *STI, SS); SS.flush(); WithColor::note() << "instruction: " << InstructionStr << '\n'; diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp index ee55722dc139..107d62b1f2b9 100644 --- a/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/llvm/tools/llvm-nm/llvm-nm.cpp @@ -1133,15 +1133,18 @@ static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I, Ret = getSymbolNMTypeChar(*MachO, I); else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj)) Ret = getSymbolNMTypeChar(*Wasm, I); - else - Ret = getSymbolNMTypeChar(cast<ELFObjectFileBase>(Obj), I); + else if (ELFObjectFileBase *ELF = dyn_cast<ELFObjectFileBase>(&Obj)) { + if (ELFSymbolRef(*I).getELFType() == ELF::STT_GNU_IFUNC) + return 'i'; + Ret = getSymbolNMTypeChar(*ELF, I); + if (ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE) + return Ret; + } else + llvm_unreachable("unknown binary format"); if (!(Symflags & object::SymbolRef::SF_Global)) return Ret; - if (Obj.isELF() && ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE) - return Ret; - return toupper(Ret); } diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp index 2a8d816e6f3c..b172fae527eb 100644 --- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -131,6 +131,12 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) { if (Error E = Obj.markSymbols()) return E; + for (Symbol &Sym : Obj.getMutableSymbols()) { + auto I = Config.SymbolsToRename.find(Sym.Name); + if (I != Config.SymbolsToRename.end()) + Sym.Name = I->getValue(); + } + // Actually do removals of symbols. Obj.removeSymbols([&](const Symbol &Sym) { // For StripAll, all relocations have been stripped and we remove all @@ -200,10 +206,9 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) { !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() || - !Config.SymbolsToRename.empty() || Config.ExtractDWO || - Config.KeepFileSymbols || Config.LocalizeHidden || Config.PreserveDates || - Config.StripDWO || Config.StripNonAlloc || Config.StripSections || - Config.Weaken || Config.DecompressDebugSections || + Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden || + Config.PreserveDates || Config.StripDWO || Config.StripNonAlloc || + Config.StripSections || Config.Weaken || Config.DecompressDebugSections || Config.DiscardMode == DiscardType::Locals || !Config.SymbolsToAdd.empty() || Config.EntryExpr) { return createStringError(llvm::errc::invalid_argument, diff --git a/llvm/tools/llvm-objcopy/COFF/Object.h b/llvm/tools/llvm-objcopy/COFF/Object.h index 21475b068629..78f8da00b8cd 100644 --- a/llvm/tools/llvm-objcopy/COFF/Object.h +++ b/llvm/tools/llvm-objcopy/COFF/Object.h @@ -25,11 +25,11 @@ namespace objcopy { namespace coff { struct Relocation { - Relocation() {} + Relocation() = default; Relocation(const object::coff_relocation& R) : Reloc(R) {} object::coff_relocation Reloc; - size_t Target; + size_t Target = 0; StringRef TargetName; // Used for diagnostics only }; @@ -124,7 +124,7 @@ struct Object { ArrayRef<Section> getSections() const { return Sections; } // This allows mutating individual Sections, but not mutating the list - // of symbols itself. + // of sections itself. iterator_range<std::vector<Section>::iterator> getMutableSections() { return make_range(Sections.begin(), Sections.end()); } diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/llvm/tools/llvm-objcopy/COFF/Reader.cpp index 2fcec0057c03..7be9cce2be3d 100644 --- a/llvm/tools/llvm-objcopy/COFF/Reader.cpp +++ b/llvm/tools/llvm-objcopy/COFF/Reader.cpp @@ -63,6 +63,7 @@ Error COFFReader::readSections(Object &Obj) const { Sections.push_back(Section()); Section &S = Sections.back(); S.Header = *Sec; + S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL; ArrayRef<uint8_t> Contents; if (Error E = COFFObj.getSectionContents(Sec, Contents)) return E; @@ -74,9 +75,6 @@ Error COFFReader::readSections(Object &Obj) const { S.Name = *NameOrErr; else return NameOrErr.takeError(); - if (Sec->hasExtendedRelocations()) - return createStringError(object_error::parse_failed, - "extended relocations not supported yet"); } Obj.addSections(Sections); return Error::success(); diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp index 6db37435fd96..e35e0474a36d 100644 --- a/llvm/tools/llvm-objcopy/COFF/Writer.cpp +++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp @@ -97,9 +97,16 @@ void COFFWriter::layoutSections() { S.Header.PointerToRawData = FileSize; FileSize += S.Header.SizeOfRawData; // For executables, this is already // aligned to FileAlignment. - S.Header.NumberOfRelocations = S.Relocs.size(); - S.Header.PointerToRelocations = - S.Header.NumberOfRelocations > 0 ? FileSize : 0; + if (S.Relocs.size() >= 0xffff) { + S.Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL; + S.Header.NumberOfRelocations = 0xffff; + S.Header.PointerToRelocations = FileSize; + FileSize += sizeof(coff_relocation); + } else { + S.Header.NumberOfRelocations = S.Relocs.size(); + S.Header.PointerToRelocations = S.Relocs.size() ? FileSize : 0; + } + FileSize += S.Relocs.size() * sizeof(coff_relocation); FileSize = alignTo(FileSize, FileAlignment); @@ -307,6 +314,15 @@ void COFFWriter::writeSections() { S.Header.SizeOfRawData - Contents.size()); Ptr += S.Header.SizeOfRawData; + + if (S.Relocs.size() >= 0xffff) { + object::coff_relocation R; + R.VirtualAddress = S.Relocs.size() + 1; + R.SymbolTableIndex = 0; + R.Type = 0; + memcpy(Ptr, &R, sizeof(R)); + Ptr += sizeof(R); + } for (const auto &R : S.Relocs) { memcpy(Ptr, &R.Reloc, sizeof(R.Reloc)); Ptr += sizeof(R.Reloc); diff --git a/llvm/tools/llvm-objcopy/CommonOpts.td b/llvm/tools/llvm-objcopy/CommonOpts.td index e8c092b44431..6481d1d1df05 100644 --- a/llvm/tools/llvm-objcopy/CommonOpts.td +++ b/llvm/tools/llvm-objcopy/CommonOpts.td @@ -40,7 +40,8 @@ def p : Flag<["-"], "p">, def strip_all : Flag<["--"], "strip-all">, HelpText<"Remove non-allocated sections outside segments. " - ".gnu.warning* sections are not removed">; + ".gnu.warning* and .ARM.attribute sections are not " + "removed">; def strip_all_gnu : Flag<["--"], "strip-all-gnu">, @@ -85,8 +86,9 @@ def keep_file_symbols : Flag<["--"], "keep-file-symbols">, def only_keep_debug : Flag<["--"], "only-keep-debug">, - HelpText<"Clear sections that would not be stripped by --strip-debug. " - "Currently only implemented for COFF.">; + HelpText< + "Produce a debug file as the output that only preserves contents of " + "sections useful for debugging purposes">; def discard_locals : Flag<["--"], "discard-locals">, HelpText<"Remove compiler-generated local symbols, (e.g. " diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp index d707bec20c49..73ed00b5cb2a 100644 --- a/llvm/tools/llvm-objcopy/CopyConfig.cpp +++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -63,6 +63,44 @@ public: ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {} }; +enum InstallNameToolID { + INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + INSTALL_NAME_TOOL_##ID, +#include "InstallNameToolOpts.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) \ + const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE; +#include "InstallNameToolOpts.inc" +#undef PREFIX + +static const opt::OptTable::Info InstallNameToolInfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + {INSTALL_NAME_TOOL_##PREFIX, \ + NAME, \ + HELPTEXT, \ + METAVAR, \ + INSTALL_NAME_TOOL_##ID, \ + opt::Option::KIND##Class, \ + PARAM, \ + FLAGS, \ + INSTALL_NAME_TOOL_##GROUP, \ + INSTALL_NAME_TOOL_##ALIAS, \ + ALIASARGS, \ + VALUES}, +#include "InstallNameToolOpts.inc" +#undef OPTION +}; + +class InstallNameToolOptTable : public opt::OptTable { +public: + InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {} +}; + enum StripID { STRIP_INVALID = 0, // This is not an option ID. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ @@ -752,6 +790,57 @@ parseObjcopyOptions(ArrayRef<const char *> ArgsArr, return std::move(DC); } +// ParseInstallNameToolOptions returns the config and sets the input arguments. +// If a help flag is set then ParseInstallNameToolOptions will print the help +// messege and exit. +Expected<DriverConfig> +parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) { + DriverConfig DC; + CopyConfig Config; + InstallNameToolOptTable T; + unsigned MissingArgumentIndex, MissingArgumentCount; + llvm::opt::InputArgList InputArgs = + T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); + + if (InputArgs.size() == 0) { + printHelp(T, errs(), "llvm-install-name-tool"); + exit(1); + } + + if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) { + printHelp(T, outs(), "llvm-install-name-tool"); + exit(0); + } + + if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) { + outs() << "llvm-install-name-tool, compatible with cctools " + "install_name_tool\n"; + cl::PrintVersionMessage(); + exit(0); + } + + for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath)) + Config.RPathToAdd.push_back(Arg->getValue()); + + SmallVector<StringRef, 2> Positional; + for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN)) + return createStringError(errc::invalid_argument, "unknown argument '%s'", + Arg->getAsString(InputArgs).c_str()); + for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT)) + Positional.push_back(Arg->getValue()); + if (Positional.empty()) + return createStringError(errc::invalid_argument, "no input file specified"); + if (Positional.size() > 1) + return createStringError( + errc::invalid_argument, + "llvm-install-name-tool expects a single input file"); + Config.InputFilename = Positional[0]; + Config.OutputFilename = Positional[0]; + + DC.CopyConfigs.push_back(std::move(Config)); + return std::move(DC); +} + // ParseStripOptions returns the config and sets the input arguments. If a // help flag is set then ParseStripOptions will print the help messege and // exit. diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h index 55a55d3a2bc2..c262934b4a41 100644 --- a/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/llvm/tools/llvm-objcopy/CopyConfig.h @@ -150,9 +150,9 @@ struct CopyConfig { // Main input/output options StringRef InputFilename; - FileFormat InputFormat; + FileFormat InputFormat = FileFormat::Unspecified; StringRef OutputFilename; - FileFormat OutputFormat; + FileFormat OutputFormat = FileFormat::Unspecified; // Only applicable when --output-format!=binary (e.g. elf64-x86-64). Optional<MachineInfo> OutputArch; @@ -175,6 +175,7 @@ struct CopyConfig { std::vector<StringRef> AddSection; std::vector<StringRef> DumpSection; std::vector<StringRef> SymbolsToAdd; + std::vector<StringRef> RPathToAdd; // Section matchers NameMatcher KeepSection; @@ -251,6 +252,12 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr, llvm::function_ref<Error(Error)> ErrorCallback); +// ParseInstallNameToolOptions returns the config and sets the input arguments. +// If a help flag is set then ParseInstallNameToolOptions will print the help +// messege and exit. +Expected<DriverConfig> +parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr); + // ParseStripOptions returns the config and sets the input arguments. If a // help flag is set then ParseStripOptions will print the help messege and // exit. ErrorCallback is used to handle recoverable errors. An Error returned @@ -258,7 +265,6 @@ parseObjcopyOptions(ArrayRef<const char *> ArgsArr, Expected<DriverConfig> parseStripOptions(ArrayRef<const char *> ArgsArr, llvm::function_ref<Error(Error)> ErrorCallback); - } // namespace objcopy } // namespace llvm diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index 8bf7e0f88010..a0cfd9a5ff86 100644 --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -136,17 +136,17 @@ static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config, // Depending on the initial ELFT and OutputFormat we need a different Writer. switch (OutputElfType) { case ELFT_ELF32LE: - return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, - !Config.StripSections); + return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections, + Config.OnlyKeepDebug); case ELFT_ELF64LE: - return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, - !Config.StripSections); + return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections, + Config.OnlyKeepDebug); case ELFT_ELF32BE: - return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, - !Config.StripSections); + return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections, + Config.OnlyKeepDebug); case ELFT_ELF64BE: - return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, - !Config.StripSections); + return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections, + Config.OnlyKeepDebug); } llvm_unreachable("Invalid output format"); } @@ -175,7 +175,7 @@ findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) { if (Phdr.p_type != PT_NOTE) continue; Error Err = Error::success(); - for (const auto &Note : In.notes(Phdr, Err)) + for (auto Note : In.notes(Phdr, Err)) if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU) return Note.getDesc(); if (Err) @@ -503,6 +503,12 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { return false; if (StringRef(Sec.Name).startswith(".gnu.warning")) return false; + // We keep the .ARM.attribute section to maintain compatibility + // with Debian derived distributions. This is a bug in their + // patchset as documented here: + // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798 + if (Sec.Type == SHT_ARM_ATTRIBUTES) + return false; if (Sec.ParentSegment != nullptr) return false; return (Sec.Flags & SHF_ALLOC) == 0; @@ -688,6 +694,11 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, } } + if (Config.OnlyKeepDebug) + for (auto &Sec : Obj.sections()) + if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) + Sec.Type = SHT_NOBITS; + for (const auto &Flag : Config.AddSection) { std::pair<StringRef, StringRef> SecPair = Flag.split("="); StringRef SecName = SecPair.first; diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp index 74145dad6e6b..ad53c75663ec 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -815,7 +815,8 @@ Error RelocationSection::removeSectionReferences( } for (const Relocation &R : Relocations) { - if (!R.RelocSymbol->DefinedIn || !ToRemove(R.RelocSymbol->DefinedIn)) + if (!R.RelocSymbol || !R.RelocSymbol->DefinedIn || + !ToRemove(R.RelocSymbol->DefinedIn)) continue; return createStringError(llvm::errc::invalid_argument, "section '%s' cannot be removed: (%s+0x%" PRIx64 @@ -868,7 +869,8 @@ static void writeRel(const RelRange &Relocations, T *Buf) { for (const auto &Reloc : Relocations) { Buf->r_offset = Reloc.Offset; setAddend(*Buf, Reloc.Addend); - Buf->setSymbolAndType(Reloc.RelocSymbol->Index, Reloc.Type, false); + Buf->setSymbolAndType(Reloc.RelocSymbol ? Reloc.RelocSymbol->Index : 0, + Reloc.Type, false); ++Buf; } } @@ -893,7 +895,7 @@ void RelocationSection::accept(MutableSectionVisitor &Visitor) { Error RelocationSection::removeSymbols( function_ref<bool(const Symbol &)> ToRemove) { for (const Relocation &Reloc : Relocations) - if (ToRemove(*Reloc.RelocSymbol)) + if (Reloc.RelocSymbol && ToRemove(*Reloc.RelocSymbol)) return createStringError( llvm::errc::invalid_argument, "not stripping symbol '%s' because it is named in a relocation", @@ -903,7 +905,8 @@ Error RelocationSection::removeSymbols( void RelocationSection::markSymbols() { for (const Relocation &Reloc : Relocations) - Reloc.RelocSymbol->Referenced = true; + if (Reloc.RelocSymbol) + Reloc.RelocSymbol->Referenced = true; } void RelocationSection::replaceSectionReferences( @@ -1006,7 +1009,7 @@ void GnuDebugLinkSection::init(StringRef File) { Size = alignTo(FileName.size() + 1, 4) + 4; // The CRC32 will only be aligned if we align the whole section. Align = 4; - Type = ELF::SHT_PROGBITS; + Type = OriginalType = ELF::SHT_PROGBITS; Name = ".gnu_debuglink"; // For sections not found in segments, OriginalOffset is only used to // establish the order that sections should go in. By using the maximum @@ -1418,7 +1421,15 @@ static void initRelocations(RelocationSection *Relocs, ToAdd.Offset = Rel.r_offset; getAddend(ToAdd.Addend, Rel); ToAdd.Type = Rel.getType(false); - ToAdd.RelocSymbol = SymbolTable->getSymbolByIndex(Rel.getSymbol(false)); + + if (uint32_t Sym = Rel.getSymbol(false)) { + if (!SymbolTable) + error("'" + Relocs->Name + + "': relocation references symbol with index " + Twine(Sym) + + ", but there is no symbol table"); + ToAdd.RelocSymbol = SymbolTable->getSymbolByIndex(Sym); + } + Relocs->addRelocation(ToAdd); } } @@ -1510,8 +1521,8 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() { } auto &Sec = makeSection(Shdr); Sec.Name = unwrapOrError(ElfFile.getSectionName(&Shdr)); - Sec.Type = Shdr.sh_type; - Sec.Flags = Shdr.sh_flags; + Sec.Type = Sec.OriginalType = Shdr.sh_type; + Sec.Flags = Sec.OriginalFlags = Shdr.sh_flags; Sec.Addr = Shdr.sh_addr; Sec.Offset = Shdr.sh_offset; Sec.OriginalOffset = Shdr.sh_offset; @@ -1528,6 +1539,21 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() { } template <class ELFT> void ELFBuilder<ELFT>::readSections(bool EnsureSymtab) { + uint32_t ShstrIndex = ElfFile.getHeader()->e_shstrndx; + if (ShstrIndex == SHN_XINDEX) + ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link; + + if (ShstrIndex == SHN_UNDEF) + Obj.HadShdrs = false; + else + Obj.SectionNames = + Obj.sections().template getSectionOfType<StringTableSection>( + ShstrIndex, + "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + + " is invalid", + "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + + " does not reference a string table"); + // If a section index table exists we'll need to initialize it before we // initialize the symbol table because the symbol table might need to // reference it. @@ -1541,13 +1567,14 @@ template <class ELFT> void ELFBuilder<ELFT>::readSections(bool EnsureSymtab) { Obj.SymbolTable->initialize(Obj.sections()); initSymbolTable(Obj.SymbolTable); } else if (EnsureSymtab) { - // Reuse the existing SHT_STRTAB section if exists. + // Reuse an existing SHT_STRTAB section if it exists. StringTableSection *StrTab = nullptr; for (auto &Sec : Obj.sections()) { if (Sec.Type == ELF::SHT_STRTAB && !(Sec.Flags & SHF_ALLOC)) { StrTab = static_cast<StringTableSection *>(&Sec); - // Prefer .strtab to .shstrtab. + // Prefer a string table that is not the section header string table, if + // such a table exists. if (Obj.SectionNames != &Sec) break; } @@ -1582,21 +1609,6 @@ template <class ELFT> void ELFBuilder<ELFT>::readSections(bool EnsureSymtab) { initGroupSection(GroupSec); } } - - uint32_t ShstrIndex = ElfFile.getHeader()->e_shstrndx; - if (ShstrIndex == SHN_XINDEX) - ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link; - - if (ShstrIndex == SHN_UNDEF) - Obj.HadShdrs = false; - else - Obj.SectionNames = - Obj.sections().template getSectionOfType<StringTableSection>( - ShstrIndex, - "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + - " is invalid", - "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + - " is not a string table"); } template <class ELFT> void ELFBuilder<ELFT>::build(bool EnsureSymtab) { @@ -1785,10 +1797,9 @@ template <class ELFT> void ELFWriter<ELFT>::writeSectionData() { template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() { for (Segment &Seg : Obj.segments()) { - uint8_t *B = Buf.getBufferStart() + Seg.Offset; - assert(Seg.FileSize == Seg.getContents().size() && - "Segment size must match contents size"); - std::memcpy(B, Seg.getContents().data(), Seg.FileSize); + size_t Size = std::min<size_t>(Seg.FileSize, Seg.getContents().size()); + std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(), + Size); } // Iterate over removed sections and overwrite their old data with zeroes. @@ -1803,8 +1814,10 @@ template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() { } template <class ELFT> -ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH) - : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs) {} +ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH, + bool OnlyKeepDebug) + : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs), + OnlyKeepDebug(OnlyKeepDebug) {} Error Object::removeSections(bool AllowBrokenLinks, std::function<bool(const SectionBase &)> ToRemove) { @@ -1945,6 +1958,78 @@ static uint64_t layoutSections(Range Sections, uint64_t Offset) { return Offset; } +// Rewrite sh_offset after some sections are changed to SHT_NOBITS and thus +// occupy no space in the file. +static uint64_t layoutSectionsForOnlyKeepDebug(Object &Obj, uint64_t Off) { + uint32_t Index = 1; + for (auto &Sec : Obj.sections()) { + Sec.Index = Index++; + + auto *FirstSec = Sec.ParentSegment && Sec.ParentSegment->Type == PT_LOAD + ? Sec.ParentSegment->firstSection() + : nullptr; + + // The first section in a PT_LOAD has to have congruent offset and address + // modulo the alignment, which usually equals the maximum page size. + if (FirstSec && FirstSec == &Sec) + Off = alignTo(Off, Sec.ParentSegment->Align, Sec.Addr); + + // sh_offset is not significant for SHT_NOBITS sections, but the congruence + // rule must be followed if it is the first section in a PT_LOAD. Do not + // advance Off. + if (Sec.Type == SHT_NOBITS) { + Sec.Offset = Off; + continue; + } + + if (!FirstSec) { + // FirstSec being nullptr generally means that Sec does not have the + // SHF_ALLOC flag. + Off = Sec.Align ? alignTo(Off, Sec.Align) : Off; + } else if (FirstSec != &Sec) { + // The offset is relative to the first section in the PT_LOAD segment. Use + // sh_offset for non-SHF_ALLOC sections. + Off = Sec.OriginalOffset - FirstSec->OriginalOffset + FirstSec->Offset; + } + Sec.Offset = Off; + Off += Sec.Size; + } + return Off; +} + +// Rewrite p_offset and p_filesz of non-empty non-PT_PHDR segments after +// sh_offset values have been updated. +static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments, + uint64_t HdrEnd) { + uint64_t MaxOffset = 0; + for (Segment *Seg : Segments) { + const SectionBase *FirstSec = Seg->firstSection(); + if (Seg->Type == PT_PHDR || !FirstSec) + continue; + + uint64_t Offset = FirstSec->Offset; + uint64_t FileSize = 0; + for (const SectionBase *Sec : Seg->Sections) { + uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size; + if (Sec->Offset + Size > Offset) + FileSize = std::max(FileSize, Sec->Offset + Size - Offset); + } + + // If the segment includes EHDR and program headers, don't make it smaller + // than the headers. + if (Seg->Offset < HdrEnd && HdrEnd <= Seg->Offset + Seg->FileSize) { + FileSize += Offset - Seg->Offset; + Offset = Seg->Offset; + FileSize = std::max(FileSize, HdrEnd - Offset); + } + + Seg->Offset = Offset; + Seg->FileSize = FileSize; + MaxOffset = std::max(MaxOffset, Offset + FileSize); + } + return MaxOffset; +} + template <class ELFT> void ELFWriter<ELFT>::initEhdrSegment() { Segment &ElfHdr = Obj.ElfHdrSegment; ElfHdr.Type = PT_PHDR; @@ -1965,12 +2050,24 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() { OrderedSegments.push_back(&Obj.ElfHdrSegment); OrderedSegments.push_back(&Obj.ProgramHdrSegment); orderSegments(OrderedSegments); - // Offset is used as the start offset of the first segment to be laid out. - // Since the ELF Header (ElfHdrSegment) must be at the start of the file, - // we start at offset 0. - uint64_t Offset = 0; - Offset = layoutSegments(OrderedSegments, Offset); - Offset = layoutSections(Obj.sections(), Offset); + + uint64_t Offset; + if (OnlyKeepDebug) { + // For --only-keep-debug, the sections that did not preserve contents were + // changed to SHT_NOBITS. We now rewrite sh_offset fields of sections, and + // then rewrite p_offset/p_filesz of program headers. + uint64_t HdrEnd = + sizeof(Elf_Ehdr) + llvm::size(Obj.segments()) * sizeof(Elf_Phdr); + Offset = layoutSectionsForOnlyKeepDebug(Obj, HdrEnd); + Offset = std::max(Offset, + layoutSegmentsForOnlyKeepDebug(OrderedSegments, HdrEnd)); + } else { + // Offset is used as the start offset of the first segment to be laid out. + // Since the ELF Header (ElfHdrSegment) must be at the start of the file, + // we start at offset 0. + Offset = layoutSegments(OrderedSegments, 0); + Offset = layoutSections(Obj.sections(), Offset); + } // If we need to write the section header table out then we need to align the // Offset so that SHOffset is valid. if (WriteSectionHeaders) @@ -2156,38 +2253,28 @@ Error BinaryWriter::finalize() { std::unique(std::begin(OrderedSegments), std::end(OrderedSegments)); OrderedSegments.erase(End, std::end(OrderedSegments)); - uint64_t Offset = 0; - - // Modify the first segment so that there is no gap at the start. This allows - // our layout algorithm to proceed as expected while not writing out the gap - // at the start. - if (!OrderedSegments.empty()) { - Segment *Seg = OrderedSegments[0]; - const SectionBase *Sec = Seg->firstSection(); - auto Diff = Sec->OriginalOffset - Seg->OriginalOffset; - Seg->OriginalOffset += Diff; - // The size needs to be shrunk as well. - Seg->FileSize -= Diff; - // The PAddr needs to be increased to remove the gap before the first - // section. - Seg->PAddr += Diff; - uint64_t LowestPAddr = Seg->PAddr; - for (Segment *Segment : OrderedSegments) { - Segment->Offset = Segment->PAddr - LowestPAddr; - Offset = std::max(Offset, Segment->Offset + Segment->FileSize); - } + // Compute the section LMA based on its sh_offset and the containing segment's + // p_offset and p_paddr. Also compute the minimum LMA of all sections as + // MinAddr. In the output, the contents between address 0 and MinAddr will be + // skipped. + uint64_t MinAddr = UINT64_MAX; + for (SectionBase &Sec : Obj.allocSections()) { + if (Sec.ParentSegment != nullptr) + Sec.Addr = + Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr; + MinAddr = std::min(MinAddr, Sec.Addr); } - layoutSections(Obj.allocSections(), Offset); - // Now that every section has been laid out we just need to compute the total // file size. This might not be the same as the offset returned by // layoutSections, because we want to truncate the last segment to the end of // its last section, to match GNU objcopy's behaviour. TotalSize = 0; - for (const SectionBase &Sec : Obj.allocSections()) + for (SectionBase &Sec : Obj.allocSections()) { + Sec.Offset = Sec.Addr - MinAddr; if (Sec.Type != SHT_NOBITS) TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size); + } if (Error E = Buf.allocate(TotalSize)) return E; diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h index eeacb014e4dc..97702a66bc47 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.h +++ b/llvm/tools/llvm-objcopy/ELF/Object.h @@ -342,16 +342,20 @@ public: virtual ~ELFWriter() {} bool WriteSectionHeaders; + // For --only-keep-debug, select an alternative section/segment layout + // algorithm. + bool OnlyKeepDebug; + Error finalize() override; Error write() override; - ELFWriter(Object &Obj, Buffer &Buf, bool WSH); + ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool OnlyKeepDebug); }; class BinaryWriter : public Writer { private: std::unique_ptr<BinarySectionWriter> SecWriter; - uint64_t TotalSize; + uint64_t TotalSize = 0; public: ~BinaryWriter() {} @@ -366,7 +370,7 @@ class IHexWriter : public Writer { }; std::set<const SectionBase *, SectionCompare> Sections; - size_t TotalSize; + size_t TotalSize = 0; Error checkSection(const SectionBase &Sec); uint64_t writeEntryPointRecord(uint8_t *Buf); @@ -383,11 +387,14 @@ class SectionBase { public: std::string Name; Segment *ParentSegment = nullptr; - uint64_t HeaderOffset; - uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max(); - uint32_t Index; + uint64_t HeaderOffset = 0; + uint32_t Index = 0; bool HasSymbol = false; + uint64_t OriginalFlags = 0; + uint64_t OriginalType = ELF::SHT_NULL; + uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max(); + uint64_t Addr = 0; uint64_t Align = 1; uint32_t EntrySize = 0; @@ -432,25 +439,24 @@ private: } }; - std::set<const SectionBase *, SectionCompare> Sections; - public: - uint32_t Type; - uint32_t Flags; - uint64_t Offset; - uint64_t VAddr; - uint64_t PAddr; - uint64_t FileSize; - uint64_t MemSize; - uint64_t Align; - - uint32_t Index; - uint64_t OriginalOffset; + uint32_t Type = 0; + uint32_t Flags = 0; + uint64_t Offset = 0; + uint64_t VAddr = 0; + uint64_t PAddr = 0; + uint64_t FileSize = 0; + uint64_t MemSize = 0; + uint64_t Align = 0; + + uint32_t Index = 0; + uint64_t OriginalOffset = 0; Segment *ParentSegment = nullptr; ArrayRef<uint8_t> Contents; + std::set<const SectionBase *, SectionCompare> Sections; explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {} - Segment() {} + Segment() = default; const SectionBase *firstSection() const { if (!Sections.empty()) @@ -490,7 +496,7 @@ public: OwnedDataSection(StringRef SecName, ArrayRef<uint8_t> Data) : Data(std::begin(Data), std::end(Data)) { Name = SecName.str(); - Type = ELF::SHT_PROGBITS; + Type = OriginalType = ELF::SHT_PROGBITS; Size = Data.size(); OriginalOffset = std::numeric_limits<uint64_t>::max(); } @@ -498,9 +504,9 @@ public: OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags, uint64_t SecOff) { Name = SecName.str(); - Type = ELF::SHT_PROGBITS; + Type = OriginalType = ELF::SHT_PROGBITS; Addr = SecAddr; - Flags = SecFlags; + Flags = OriginalFlags = SecFlags; OriginalOffset = SecOff; } @@ -530,7 +536,7 @@ public: void accept(MutableSectionVisitor &Visitor) override; static bool classof(const SectionBase *S) { - return (S->Flags & ELF::SHF_COMPRESSED) || + return (S->OriginalFlags & ELF::SHF_COMPRESSED) || (StringRef(S->Name).startswith(".zdebug")); } }; @@ -543,7 +549,7 @@ public: : SectionBase(Sec) { Size = Sec.getDecompressedSize(); Align = Sec.getDecompressedAlign(); - Flags = (Flags & ~ELF::SHF_COMPRESSED); + Flags = OriginalFlags = (Flags & ~ELF::SHF_COMPRESSED); if (StringRef(Name).startswith(".zdebug")) Name = "." + Name.substr(2); } @@ -567,7 +573,7 @@ class StringTableSection : public SectionBase { public: StringTableSection() : StrTabBuilder(StringTableBuilder::ELF) { - Type = ELF::SHT_STRTAB; + Type = OriginalType = ELF::SHT_STRTAB; } void addString(StringRef Name); @@ -577,9 +583,9 @@ public: void accept(MutableSectionVisitor &Visitor) override; static bool classof(const SectionBase *S) { - if (S->Flags & ELF::SHF_ALLOC) + if (S->OriginalFlags & ELF::SHF_ALLOC) return false; - return S->Type == ELF::SHT_STRTAB; + return S->OriginalType == ELF::SHT_STRTAB; } }; @@ -648,7 +654,7 @@ public: Name = ".symtab_shndx"; Align = 4; EntrySize = 4; - Type = ELF::SHT_SYMTAB_SHNDX; + Type = OriginalType = ELF::SHT_SYMTAB_SHNDX; } }; @@ -666,7 +672,7 @@ protected: using SymPtr = std::unique_ptr<Symbol>; public: - SymbolTableSection() { Type = ELF::SHT_SYMTAB; } + SymbolTableSection() { Type = OriginalType = ELF::SHT_SYMTAB; } void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, uint64_t Value, uint8_t Visibility, uint16_t Shndx, @@ -695,7 +701,7 @@ public: const DenseMap<SectionBase *, SectionBase *> &FromTo) override; static bool classof(const SectionBase *S) { - return S->Type == ELF::SHT_SYMTAB; + return S->OriginalType == ELF::SHT_SYMTAB; } }; @@ -724,7 +730,7 @@ public: void setSection(SectionBase *Sec) { SecToApplyRel = Sec; } static bool classof(const SectionBase *S) { - return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; + return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA; } }; @@ -762,9 +768,9 @@ public: const DenseMap<SectionBase *, SectionBase *> &FromTo) override; static bool classof(const SectionBase *S) { - if (S->Flags & ELF::SHF_ALLOC) + if (S->OriginalFlags & ELF::SHF_ALLOC) return false; - return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; + return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA; } }; @@ -799,7 +805,7 @@ public: const DenseMap<SectionBase *, SectionBase *> &FromTo) override; static bool classof(const SectionBase *S) { - return S->Type == ELF::SHT_GROUP; + return S->OriginalType == ELF::SHT_GROUP; } }; @@ -808,7 +814,7 @@ public: explicit DynamicSymbolTableSection(ArrayRef<uint8_t> Data) : Section(Data) {} static bool classof(const SectionBase *S) { - return S->Type == ELF::SHT_DYNSYM; + return S->OriginalType == ELF::SHT_DYNSYM; } }; @@ -817,7 +823,7 @@ public: explicit DynamicSection(ArrayRef<uint8_t> Data) : Section(Data) {} static bool classof(const SectionBase *S) { - return S->Type == ELF::SHT_DYNAMIC; + return S->OriginalType == ELF::SHT_DYNAMIC; } }; @@ -838,9 +844,9 @@ public: function_ref<bool(const SectionBase *)> ToRemove) override; static bool classof(const SectionBase *S) { - if (!(S->Flags & ELF::SHF_ALLOC)) + if (!(S->OriginalFlags & ELF::SHF_ALLOC)) return false; - return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; + return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA; } }; diff --git a/llvm/tools/llvm-objcopy/InstallNameToolOpts.td b/llvm/tools/llvm-objcopy/InstallNameToolOpts.td new file mode 100644 index 000000000000..35047a57994c --- /dev/null +++ b/llvm/tools/llvm-objcopy/InstallNameToolOpts.td @@ -0,0 +1,22 @@ +//===-- InstallNameToolOpts.td - llvm-install-name-tool options --------*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file describes the command line options of llvm-install-name. +// +//===----------------------------------------------------------------------===// + +include "llvm/Option/OptParser.td" + +def help : Flag<["--"], "help">; +def h : Flag<["-"], "h">, Alias<help>; + +def add_rpath : Option<["-", "--"], "add_rpath", KIND_SEPARATE>, + HelpText<"Add new rpath">; + +def version : Flag<["--"], "version">, + HelpText<"Print the version and exit.">; diff --git a/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp b/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp index f621f3aa09cf..380f2e989fe4 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp @@ -64,9 +64,11 @@ void MachOLayoutBuilder::updateDySymTab(MachO::macho_load_command &MLC) { assert(std::is_sorted(O.SymTable.Symbols.begin(), O.SymTable.Symbols.end(), [](const std::unique_ptr<SymbolEntry> &A, const std::unique_ptr<SymbolEntry> &B) { - return (A->isLocalSymbol() && !B->isLocalSymbol()) || - (!A->isUndefinedSymbol() && - B->isUndefinedSymbol()); + bool AL = A->isLocalSymbol(), BL = B->isLocalSymbol(); + if (AL != BL) + return AL; + return !AL && !A->isUndefinedSymbol() && + B->isUndefinedSymbol(); }) && "Symbols are not sorted by their types."); @@ -318,6 +320,9 @@ Error MachOLayoutBuilder::layoutTail(uint64_t Offset) { case MachO::LC_SEGMENT: case MachO::LC_SEGMENT_64: case MachO::LC_VERSION_MIN_MACOSX: + case MachO::LC_VERSION_MIN_IPHONEOS: + case MachO::LC_VERSION_MIN_TVOS: + case MachO::LC_VERSION_MIN_WATCHOS: case MachO::LC_BUILD_VERSION: case MachO::LC_ID_DYLIB: case MachO::LC_LOAD_DYLIB: diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp index 6d586e7d73f1..4578d0bb75d4 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -18,31 +18,209 @@ namespace objcopy { namespace macho { using namespace object; +using SectionPred = std::function<bool(const Section &Sec)>; + +static void removeSections(const CopyConfig &Config, Object &Obj) { + SectionPred RemovePred = [](const Section &) { return false; }; + + if (!Config.ToRemove.empty()) { + RemovePred = [&Config, RemovePred](const Section &Sec) { + return Config.ToRemove.matches(Sec.CanonicalName); + }; + } + + if (Config.StripAll || Config.StripDebug) { + // Remove all debug sections. + RemovePred = [RemovePred](const Section &Sec) { + if (Sec.Segname == "__DWARF") + return true; + + return RemovePred(Sec); + }; + } + + if (!Config.OnlySection.empty()) { + // Overwrite RemovePred because --only-section takes priority. + RemovePred = [&Config](const Section &Sec) { + return !Config.OnlySection.matches(Sec.CanonicalName); + }; + } + + return Obj.removeSections(RemovePred); +} + +static void markSymbols(const CopyConfig &Config, Object &Obj) { + // Symbols referenced from the indirect symbol table must not be removed. + for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols) + if (ISE.Symbol) + (*ISE.Symbol)->Referenced = true; +} + +static void updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { + for (SymbolEntry &Sym : Obj.SymTable) { + auto I = Config.SymbolsToRename.find(Sym.Name); + if (I != Config.SymbolsToRename.end()) + Sym.Name = I->getValue(); + } + + auto RemovePred = [Config](const std::unique_ptr<SymbolEntry> &N) { + if (N->Referenced) + return false; + return Config.StripAll; + }; + + Obj.SymTable.removeSymbols(RemovePred); +} + +static LoadCommand buildRPathLoadCommand(StringRef Path) { + LoadCommand LC; + MachO::rpath_command RPathLC; + RPathLC.cmd = MachO::LC_RPATH; + RPathLC.path = sizeof(MachO::rpath_command); + RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size(), 8); + LC.MachOLoadCommand.rpath_command_data = RPathLC; + LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0); + std::copy(Path.begin(), Path.end(), LC.Payload.begin()); + return LC; +} + +static Error dumpSectionToFile(StringRef SecName, StringRef Filename, + Object &Obj) { + for (LoadCommand &LC : Obj.LoadCommands) + for (Section &Sec : LC.Sections) { + if (Sec.CanonicalName == SecName) { + Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = + FileOutputBuffer::create(Filename, Sec.Content.size()); + if (!BufferOrErr) + return BufferOrErr.takeError(); + std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); + llvm::copy(Sec.Content, Buf->getBufferStart()); + + if (Error E = Buf->commit()) + return E; + return Error::success(); + } + } + + return createStringError(object_error::parse_failed, "section '%s' not found", + SecName.str().c_str()); +} + +static Error addSection(StringRef SecName, StringRef Filename, Object &Obj) { + ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = + MemoryBuffer::getFile(Filename); + if (!BufOrErr) + return createFileError(Filename, errorCodeToError(BufOrErr.getError())); + std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr); + + std::pair<StringRef, StringRef> Pair = SecName.split(','); + StringRef TargetSegName = Pair.first; + Section Sec(TargetSegName, Pair.second); + Sec.Content = Obj.NewSectionsContents.save(Buf->getBuffer()); + + // Add the a section into an existing segment. + for (LoadCommand &LC : Obj.LoadCommands) { + Optional<StringRef> SegName = LC.getSegmentName(); + if (SegName && SegName == TargetSegName) { + LC.Sections.push_back(Sec); + return Error::success(); + } + } + + // There's no segment named TargetSegName. Create a new load command and + // Insert a new section into it. + LoadCommand &NewSegment = Obj.addSegment(TargetSegName); + NewSegment.Sections.push_back(Sec); + return Error::success(); +} + +// isValidMachOCannonicalName returns success if Name is a MachO cannonical name +// ("<segment>,<section>") and lengths of both segment and section names are +// valid. +Error isValidMachOCannonicalName(StringRef Name) { + if (Name.count(',') != 1) + return createStringError(errc::invalid_argument, + "invalid section name '%s' (should be formatted " + "as '<segment name>,<section name>')", + Name.str().c_str()); + + std::pair<StringRef, StringRef> Pair = Name.split(','); + if (Pair.first.size() > 16) + return createStringError(errc::invalid_argument, + "too long segment name: '%s'", + Pair.first.str().c_str()); + if (Pair.second.size() > 16) + return createStringError(errc::invalid_argument, + "too long section name: '%s'", + Pair.second.str().c_str()); + return Error::success(); +} static Error handleArgs(const CopyConfig &Config, Object &Obj) { if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() || Config.BuildIdLinkInput || Config.BuildIdLinkOutput || !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() || - !Config.AllocSectionsPrefix.empty() || !Config.AddSection.empty() || - !Config.DumpSection.empty() || !Config.KeepSection.empty() || - Config.NewSymbolVisibility || !Config.OnlySection.empty() || - !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() || - !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() || - !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || - !Config.SymbolsToRename.empty() || + !Config.AllocSectionsPrefix.empty() || !Config.KeepSection.empty() || + Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() || + !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || + !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || + !Config.SectionsToRename.empty() || !Config.UnneededSymbolsToRemove.empty() || !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() || - !Config.ToRemove.empty() || Config.ExtractDWO || Config.KeepFileSymbols || - Config.LocalizeHidden || Config.PreserveDates || Config.StripDWO || + Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden || + Config.PreserveDates || Config.StripAllGNU || Config.StripDWO || Config.StripNonAlloc || Config.StripSections || Config.Weaken || - Config.DecompressDebugSections || Config.StripDebug || - Config.StripNonAlloc || Config.StripSections || Config.StripUnneeded || + Config.DecompressDebugSections || Config.StripNonAlloc || + Config.StripSections || Config.StripUnneeded || Config.DiscardMode != DiscardType::None || !Config.SymbolsToAdd.empty() || Config.EntryExpr) { return createStringError(llvm::errc::invalid_argument, "option not supported by llvm-objcopy for MachO"); } + removeSections(Config, Obj); + + // Mark symbols to determine which symbols are still needed. + if (Config.StripAll) + markSymbols(Config, Obj); + + updateAndRemoveSymbols(Config, Obj); + + if (Config.StripAll) + for (LoadCommand &LC : Obj.LoadCommands) + for (Section &Sec : LC.Sections) + Sec.Relocations.clear(); + + for (const StringRef &Flag : Config.DumpSection) { + std::pair<StringRef, StringRef> SecPair = Flag.split("="); + StringRef SecName = SecPair.first; + StringRef File = SecPair.second; + if (Error E = dumpSectionToFile(SecName, File, Obj)) + return E; + } + for (const auto &Flag : Config.AddSection) { + std::pair<StringRef, StringRef> SecPair = Flag.split("="); + StringRef SecName = SecPair.first; + StringRef File = SecPair.second; + if (Error E = isValidMachOCannonicalName(SecName)) + return E; + if (Error E = addSection(SecName, File, Obj)) + return E; + } + + for (StringRef RPath : Config.RPathToAdd) { + for (LoadCommand &LC : Obj.LoadCommands) { + if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH && + RPath == StringRef(reinterpret_cast<char *>(LC.Payload.data()), + LC.Payload.size()) + .trim(0)) { + return createStringError(errc::invalid_argument, + "rpath " + RPath + + " would create a duplicate load command"); + } + } + Obj.addLoadCommand(buildRPathLoadCommand(RPath)); + } return Error::success(); } diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp index b48a0d8952d0..46bb11727322 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -29,12 +29,9 @@ void MachOReader::readHeader(Object &O) const { template <typename SectionType> Section constructSectionCommon(SectionType Sec) { - Section S; - S.Sectname = - StringRef(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname))) - .str(); - S.Segname = - StringRef(Sec.segname, strnlen(Sec.segname, sizeof(Sec.sectname))).str(); + StringRef SegName(Sec.segname, strnlen(Sec.segname, sizeof(Sec.segname))); + StringRef SectName(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname))); + Section S(SegName, SectName); S.Addr = Sec.addr; S.Size = Sec.size; S.Offset = Sec.offset; @@ -149,10 +146,11 @@ void MachOReader::readLoadCommands(Object &O) const { sizeof(MachO::LCStruct)); \ if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \ MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \ - LC.Payload = ArrayRef<uint8_t>( \ - reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \ - sizeof(MachO::LCStruct), \ - LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \ + if (LoadCmd.C.cmdsize > sizeof(MachO::LCStruct)) \ + LC.Payload = ArrayRef<uint8_t>( \ + reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \ + sizeof(MachO::LCStruct), \ + LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \ break; switch (LoadCmd.C.cmd) { @@ -161,10 +159,11 @@ void MachOReader::readLoadCommands(Object &O) const { sizeof(MachO::load_command)); if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) MachO::swapStruct(LC.MachOLoadCommand.load_command_data); - LC.Payload = ArrayRef<uint8_t>( - reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + - sizeof(MachO::load_command), - LoadCmd.C.cmdsize - sizeof(MachO::load_command)); + if (LoadCmd.C.cmdsize > sizeof(MachO::load_command)) + LC.Payload = ArrayRef<uint8_t>( + reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + + sizeof(MachO::load_command), + LoadCmd.C.cmdsize - sizeof(MachO::load_command)); break; #include "llvm/BinaryFormat/MachO.def" } @@ -255,9 +254,16 @@ void MachOReader::readFunctionStartsData(Object &O) const { void MachOReader::readIndirectSymbolTable(Object &O) const { MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand(); - for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) - O.IndirectSymTable.Symbols.push_back( - MachOObj.getIndirectSymbolTableEntry(DySymTab, i)); + constexpr uint32_t AbsOrLocalMask = + MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS; + for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) { + uint32_t Index = MachOObj.getIndirectSymbolTableEntry(DySymTab, i); + if ((Index & AbsOrLocalMask) != 0) + O.IndirectSymTable.Symbols.emplace_back(Index, None); + else + O.IndirectSymTable.Symbols.emplace_back( + Index, O.SymTable.getSymbolByIndex(Index)); + } } std::unique_ptr<Object> MachOReader::create() const { diff --git a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp index 4ec91cc9eb7a..0d9590612eca 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp @@ -180,7 +180,8 @@ void MachOWriter::writeLoadCommands() { MachO::swapStruct(MLC.LCStruct##_data); \ memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \ Begin += sizeof(MachO::LCStruct); \ - memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \ + if (!LC.Payload.empty()) \ + memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \ Begin += LC.Payload.size(); \ break; @@ -193,7 +194,8 @@ void MachOWriter::writeLoadCommands() { MachO::swapStruct(MLC.load_command_data); memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command)); Begin += sizeof(MachO::load_command); - memcpy(Begin, LC.Payload.data(), LC.Payload.size()); + if (!LC.Payload.empty()) + memcpy(Begin, LC.Payload.data(), LC.Payload.size()); Begin += LC.Payload.size(); break; #include "llvm/BinaryFormat/MachO.def" @@ -369,11 +371,14 @@ void MachOWriter::writeIndirectSymbolTable() { O.LoadCommands[*O.DySymTabCommandIndex] .MachOLoadCommand.dysymtab_command_data; - char *Out = (char *)B.getBufferStart() + DySymTabCommand.indirectsymoff; - assert((DySymTabCommand.nindirectsyms == O.IndirectSymTable.Symbols.size()) && - "Incorrect indirect symbol table size"); - memcpy(Out, O.IndirectSymTable.Symbols.data(), - sizeof(uint32_t) * O.IndirectSymTable.Symbols.size()); + uint32_t *Out = + (uint32_t *)(B.getBufferStart() + DySymTabCommand.indirectsymoff); + for (const IndirectSymbolEntry &Sym : O.IndirectSymTable.Symbols) { + uint32_t Entry = (Sym.Symbol) ? (*Sym.Symbol)->Index : Sym.OriginalIndex; + if (IsLittleEndian != sys::IsLittleEndianHost) + sys::swapByteOrder(Entry); + *Out++ = Entry; + } } void MachOWriter::writeDataInCodeData() { diff --git a/llvm/tools/llvm-objcopy/MachO/Object.cpp b/llvm/tools/llvm-objcopy/MachO/Object.cpp index 264f39c28ed2..d3b4fdc2f633 100644 --- a/llvm/tools/llvm-objcopy/MachO/Object.cpp +++ b/llvm/tools/llvm-objcopy/MachO/Object.cpp @@ -10,6 +10,70 @@ const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const { return Symbols[Index].get(); } +SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) { + return const_cast<SymbolEntry *>( + static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index)); +} + +void SymbolTable::removeSymbols( + function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) { + Symbols.erase( + std::remove_if(std::begin(Symbols), std::end(Symbols), ToRemove), + std::end(Symbols)); +} + +void Object::removeSections(function_ref<bool(const Section &)> ToRemove) { + for (LoadCommand &LC : LoadCommands) + LC.Sections.erase(std::remove_if(std::begin(LC.Sections), + std::end(LC.Sections), ToRemove), + std::end(LC.Sections)); +} + +void Object::addLoadCommand(LoadCommand LC) { + LoadCommands.push_back(std::move(LC)); +} + +template <typename SegmentType> +static void constructSegment(SegmentType &Seg, + llvm::MachO::LoadCommandType CmdType, + StringRef SegName) { + assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name"); + memset(&Seg, 0, sizeof(SegmentType)); + Seg.cmd = CmdType; + strncpy(Seg.segname, SegName.data(), SegName.size()); +} + +LoadCommand &Object::addSegment(StringRef SegName) { + LoadCommand LC; + if (is64Bit()) + constructSegment(LC.MachOLoadCommand.segment_command_64_data, + MachO::LC_SEGMENT_64, SegName); + else + constructSegment(LC.MachOLoadCommand.segment_command_data, + MachO::LC_SEGMENT, SegName); + + LoadCommands.push_back(LC); + return LoadCommands.back(); +} + +/// Extracts a segment name from a string which is possibly non-null-terminated. +static StringRef extractSegmentName(const char *SegName) { + return StringRef(SegName, + strnlen(SegName, sizeof(MachO::segment_command::segname))); +} + +Optional<StringRef> LoadCommand::getSegmentName() const { + const MachO::macho_load_command &MLC = MachOLoadCommand; + switch (MLC.load_command_data.cmd) { + case MachO::LC_SEGMENT: + return extractSegmentName(MLC.segment_command_data.segname); + case MachO::LC_SEGMENT_64: + return extractSegmentName(MLC.segment_command_64_data.segname); + default: + return None; + } +} + } // end namespace macho } // end namespace objcopy } // end namespace llvm diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h index 1cebf8253d19..dc2606eefa4a 100644 --- a/llvm/tools/llvm-objcopy/MachO/Object.h +++ b/llvm/tools/llvm-objcopy/MachO/Object.h @@ -14,6 +14,7 @@ #include "llvm/BinaryFormat/MachO.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/ObjectYAML/DWARFYAML.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Support/YAMLTraits.h" #include <cstdint> #include <string> @@ -36,22 +37,32 @@ struct MachHeader { struct RelocationInfo; struct Section { - std::string Sectname; std::string Segname; - uint64_t Addr; - uint64_t Size; - uint32_t Offset; - uint32_t Align; - uint32_t RelOff; - uint32_t NReloc; - uint32_t Flags; - uint32_t Reserved1; - uint32_t Reserved2; - uint32_t Reserved3; - + std::string Sectname; + // CanonicalName is a string formatted as “<Segname>,<Sectname>". + std::string CanonicalName; + uint64_t Addr = 0; + uint64_t Size = 0; + uint32_t Offset = 0; + uint32_t Align = 0; + uint32_t RelOff = 0; + uint32_t NReloc = 0; + uint32_t Flags = 0; + uint32_t Reserved1 = 0; + uint32_t Reserved2 = 0; + uint32_t Reserved3 = 0; StringRef Content; std::vector<RelocationInfo> Relocations; + Section(StringRef SegName, StringRef SectName) + : Segname(SegName), Sectname(SectName), + CanonicalName((Twine(SegName) + Twine(',') + SectName).str()) {} + + Section(StringRef SegName, StringRef SectName, StringRef Content) + : Segname(SegName), Sectname(SectName), + CanonicalName((Twine(SegName) + Twine(',') + SectName).str()), + Content(Content) {} + MachO::SectionType getType() const { return static_cast<MachO::SectionType>(Flags & MachO::SECTION_TYPE); } @@ -72,19 +83,23 @@ struct LoadCommand { // The raw content of the payload of the load command (located right after the // corresponding struct). In some cases it is either empty or can be // copied-over without digging into its structure. - ArrayRef<uint8_t> Payload; + std::vector<uint8_t> Payload; // Some load commands can contain (inside the payload) an array of sections, // though the contents of the sections are stored separately. The struct // Section describes only sections' metadata and where to find the // corresponding content inside the binary. std::vector<Section> Sections; + + // Returns the segment name if the load command is a segment command. + Optional<StringRef> getSegmentName() const; }; // A symbol information. Fields which starts with "n_" are same as them in the // nlist. struct SymbolEntry { std::string Name; + bool Referenced = false; uint32_t Index; uint8_t n_type; uint8_t n_sect; @@ -107,11 +122,32 @@ struct SymbolEntry { struct SymbolTable { std::vector<std::unique_ptr<SymbolEntry>> Symbols; + using iterator = pointee_iterator< + std::vector<std::unique_ptr<SymbolEntry>>::const_iterator>; + + iterator begin() const { return iterator(Symbols.begin()); } + iterator end() const { return iterator(Symbols.end()); } + const SymbolEntry *getSymbolByIndex(uint32_t Index) const; + SymbolEntry *getSymbolByIndex(uint32_t Index); + void removeSymbols( + function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove); +}; + +struct IndirectSymbolEntry { + // The original value in an indirect symbol table. Higher bits encode extra + // information (INDIRECT_SYMBOL_LOCAL and INDIRECT_SYMBOL_ABS). + uint32_t OriginalIndex; + /// The Symbol referenced by this entry. It's None if the index is + /// INDIRECT_SYMBOL_LOCAL or INDIRECT_SYMBOL_ABS. + Optional<SymbolEntry *> Symbol; + + IndirectSymbolEntry(uint32_t OriginalIndex, Optional<SymbolEntry *> Symbol) + : OriginalIndex(OriginalIndex), Symbol(Symbol) {} }; struct IndirectSymbolTable { - std::vector<uint32_t> Symbols; + std::vector<IndirectSymbolEntry> Symbols; }; /// The location of the string table inside the binary is described by LC_SYMTAB @@ -250,6 +286,24 @@ struct Object { Optional<size_t> DataInCodeCommandIndex; /// The index LC_FUNCTION_STARTS load comamnd if present. Optional<size_t> FunctionStartsCommandIndex; + + BumpPtrAllocator Alloc; + StringSaver NewSectionsContents; + + Object() : NewSectionsContents(Alloc) {} + + void removeSections(function_ref<bool(const Section &)> ToRemove); + void addLoadCommand(LoadCommand LC); + + /// Creates a new segment load command in the object and returns a reference + /// to the newly created load command. The caller should verify that SegName + /// is not too long (SegName.size() should be less than or equal to 16). + LoadCommand &addSegment(StringRef SegName); + + bool is64Bit() const { + return Header.Magic == MachO::MH_MAGIC_64 || + Header.Magic == MachO::MH_CIGAM_64; + } }; } // end namespace macho diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp index a68210f3fdd3..e662f35f4b08 100644 --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -313,11 +313,20 @@ static Error executeObjcopy(CopyConfig &Config) { return Error::success(); } +namespace { + +enum class ToolType { Objcopy, Strip, InstallNameTool }; + +} // anonymous namespace + int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; - bool IsStrip = sys::path::stem(ToolName).contains("strip"); - + ToolType Tool = StringSwitch<ToolType>(sys::path::stem(ToolName)) + .EndsWith("strip", ToolType::Strip) + .EndsWith("install-name-tool", ToolType::InstallNameTool) + .EndsWith("install_name_tool", ToolType::InstallNameTool) + .Default(ToolType::Objcopy); // Expand response files. // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp, // into a separate function in the CommandLine library and call that function @@ -332,10 +341,11 @@ int main(int argc, char **argv) { NewArgv); auto Args = makeArrayRef(NewArgv).drop_front(); - Expected<DriverConfig> DriverConfig = - IsStrip ? parseStripOptions(Args, reportWarning) - : parseObjcopyOptions(Args, reportWarning); + (Tool == ToolType::Strip) ? parseStripOptions(Args, reportWarning) + : ((Tool == ToolType::InstallNameTool) + ? parseInstallNameToolOptions(Args) + : parseObjcopyOptions(Args, reportWarning)); if (!DriverConfig) { logAllUnhandledErrors(DriverConfig.takeError(), WithColor::error(errs(), ToolName)); diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp index 93d070eee16c..abfe08346bbd 100644 --- a/llvm/tools/llvm-objdump/ELFDump.cpp +++ b/llvm/tools/llvm-objdump/ELFDump.cpp @@ -105,9 +105,12 @@ static Error getRelocationValueString(const ELFObjectFile<ELFT> *Obj, } else { Fmt << "*ABS*"; } - - if (Addend != 0) - Fmt << (Addend < 0 ? "" : "+") << Addend; + if (Addend != 0) { + Fmt << (Addend < 0 + ? "-" + : "+") << format("0x%" PRIx64, + (Addend < 0 ? -(uint64_t)Addend : (uint64_t)Addend)); + } Fmt.flush(); Result.append(FmtBuf.begin(), FmtBuf.end()); return Error::success(); @@ -201,6 +204,9 @@ template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) { case ELF::PT_GNU_RELRO: outs() << " RELRO "; break; + case ELF::PT_GNU_PROPERTY: + outs() << " PROPERTY "; + break; case ELF::PT_GNU_STACK: outs() << " STACK "; break; diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp index e4684d0f1601..87c7a92933f1 100644 --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -29,6 +29,7 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Support/Casting.h" @@ -7208,11 +7209,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, FeaturesStr = Features.getString(); } + MCTargetOptions MCOptions; // Set up disassembler. std::unique_ptr<const MCRegisterInfo> MRI( TheTarget->createMCRegInfo(TripleName)); std::unique_ptr<const MCAsmInfo> AsmInfo( - TheTarget->createMCAsmInfo(*MRI, TripleName)); + TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); std::unique_ptr<const MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TripleName, MachOMCPU, FeaturesStr)); MCContext Ctx(AsmInfo.get(), MRI.get(), nullptr); @@ -7262,7 +7264,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, if (ThumbTarget) { ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName)); ThumbAsmInfo.reset( - ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName)); + ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName, MCOptions)); ThumbSTI.reset( ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MachOMCPU, FeaturesStr)); @@ -7324,12 +7326,6 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, } array_pod_sort(Dices.begin(), Dices.end()); -#ifndef NDEBUG - raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); -#else - raw_ostream &DebugOut = nulls(); -#endif - // Try to find debug info and set up the DIContext for it. std::unique_ptr<DIContext> diContext; std::unique_ptr<Binary> DSYMBinary; @@ -7405,7 +7401,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, reportError(MachDSYM.takeError(), DSYMPath); return; } - + // We need to keep the Binary alive with the buffer DbgObj = &*MachDSYM.get(); DSYMBinary = std::move(*MachDSYM); @@ -7620,10 +7616,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, bool gotInst; if (UseThumbTarget) gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index), - PC, DebugOut, Annotations); + PC, Annotations); else gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC, - DebugOut, Annotations); + Annotations); if (gotInst) { if (!NoShowRawInsn || Arch == Triple::arm) { dumpBytes(makeArrayRef(Bytes.data() + Index, Size), outs()); @@ -7631,9 +7627,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, formatted_raw_ostream FormattedOS(outs()); StringRef AnnotationsStr = Annotations.str(); if (UseThumbTarget) - ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr, *ThumbSTI); + ThumbIP->printInst(&Inst, PC, AnnotationsStr, *ThumbSTI, + FormattedOS); else - IP->printInst(&Inst, FormattedOS, AnnotationsStr, *STI); + IP->printInst(&Inst, PC, AnnotationsStr, *STI, FormattedOS); emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo); // Print debug info. @@ -7647,8 +7644,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, } outs() << "\n"; } else { - unsigned int Arch = MachOOF->getArch(); - if (Arch == Triple::x86_64 || Arch == Triple::x86) { + if (MachOOF->getArchTriple().isX86()) { outs() << format("\t.byte 0x%02x #bad opcode\n", *(Bytes.data() + Index) & 0xff); Size = 1; // skip exactly one illegible byte and move on. @@ -7694,7 +7690,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, SmallVector<char, 64> AnnotationsBytes; raw_svector_ostream Annotations(AnnotationsBytes); if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC, - DebugOut, Annotations)) { + Annotations)) { if (!NoLeadingAddr) { if (FullLeadingAddr) { if (MachOOF->is64Bit()) @@ -7710,11 +7706,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs()); } StringRef AnnotationsStr = Annotations.str(); - IP->printInst(&Inst, outs(), AnnotationsStr, *STI); + IP->printInst(&Inst, PC, AnnotationsStr, *STI, outs()); outs() << "\n"; } else { - unsigned int Arch = MachOOF->getArch(); - if (Arch == Triple::x86_64 || Arch == Triple::x86) { + if (MachOOF->getArchTriple().isX86()) { outs() << format("\t.byte 0x%02x #bad opcode\n", *(Bytes.data() + Index) & 0xff); InstSize = 1; // skip exactly one illegible byte and move on. @@ -7728,7 +7723,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, } } // The TripleName's need to be reset if we are called again for a different - // archtecture. + // architecture. TripleName = ""; ThumbTripleName = ""; @@ -7827,7 +7822,7 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj, auto Sym = Symbols.upper_bound(Addr); if (Sym == Symbols.begin()) { // The first symbol in the object is after this reference, the best we can - // do is section-relative notation. + // do is section-relative notation. if (Expected<StringRef> NameOrErr = RelocSection.getName()) Name = *NameOrErr; else diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index 34a44b3b7fa9..6bd37a1fb86c 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -37,6 +37,7 @@ #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include "llvm/Object/COFFImportFile.h" @@ -707,7 +708,7 @@ public: OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); if (MI) - IP.printInst(MI, OS, "", STI); + IP.printInst(MI, Address.Address, "", STI, OS); else OS << "\t<unknown>"; } @@ -743,7 +744,7 @@ public: std::string Buffer; { raw_string_ostream TempStream(Buffer); - IP.printInst(MI, TempStream, "", STI); + IP.printInst(MI, Address.Address, "", STI, TempStream); } StringRef Contents(Buffer); // Split off bundle attributes @@ -810,7 +811,7 @@ public: SmallString<40> InstStr; raw_svector_ostream IS(InstStr); - IP.printInst(MI, IS, "", STI); + IP.printInst(MI, Address.Address, "", STI, IS); OS << left_justify(IS.str(), 60); } else { @@ -864,7 +865,7 @@ public: dumpBytes(Bytes, OS); } if (MI) - IP.printInst(MI, OS, "", STI); + IP.printInst(MI, Address.Address, "", STI, OS); else OS << "\t<unknown>"; } @@ -1133,6 +1134,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj, std::map<SectionRef, SectionSymbolsTy> AllSymbols; SectionSymbolsTy AbsoluteSymbols; const StringRef FileName = Obj->getFileName(); + const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj); for (const SymbolRef &Symbol : Obj->symbols()) { uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName); @@ -1147,6 +1149,18 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj, continue; } + // Don't ask a Mach-O STAB symbol for its section unless you know that + // STAB symbol's section field refers to a valid section index. Otherwise + // the symbol may error trying to load a section that does not exist. + if (MachO) { + DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); + uint8_t NType = (MachO->is64Bit() ? + MachO->getSymbol64TableEntry(SymDRI).n_type: + MachO->getSymbolTableEntry(SymDRI).n_type); + if (NType & MachO::N_STAB) + continue; + } + section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); if (SecI != Obj->section_end()) AllSymbols[*SecI].emplace_back(Address, Name, SymbolType); @@ -1243,7 +1257,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj, } StringRef SegmentName = ""; - if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj)) { + if (MachO) { DataRefImpl DR = Section.getRawDataRefImpl(); SegmentName = MachO->getSectionFinalSegmentName(DR); } @@ -1339,16 +1353,10 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj, continue; } -#ifndef NDEBUG - raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); -#else - raw_ostream &DebugOut = nulls(); -#endif - // Some targets (like WebAssembly) have a special prelude at the start // of each symbol. DisAsm->onSymbolStart(SymbolName, Size, Bytes.slice(Start, End - Start), - SectionAddr + Start, DebugOut, CommentStream); + SectionAddr + Start, CommentStream); Start += Size; Index = Start; @@ -1412,8 +1420,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj, // provided MCInst Inst; bool Disassembled = DisAsm->getInstruction( - Inst, Size, Bytes.slice(Index), SectionAddr + Index, DebugOut, - CommentStream); + Inst, Size, Bytes.slice(Index), SectionAddr + Index, CommentStream); if (Size == 0) Size = 1; @@ -1539,8 +1546,9 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) { "no register info for target " + TripleName); // Set up disassembler. + MCTargetOptions MCOptions; std::unique_ptr<const MCAsmInfo> AsmInfo( - TheTarget->createMCAsmInfo(*MRI, TripleName)); + TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); if (!AsmInfo) reportError(Obj->getFileName(), "no assembly info for target " + TripleName); @@ -1802,6 +1810,7 @@ void printSymbolTable(const ObjectFile *O, StringRef ArchiveName, } const StringRef FileName = O->getFileName(); + const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(O); for (auto I = O->symbol_begin(), E = O->symbol_end(); I != E; ++I) { const SymbolRef &Symbol = *I; uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName, ArchiveName, @@ -1811,8 +1820,23 @@ void printSymbolTable(const ObjectFile *O, StringRef ArchiveName, SymbolRef::Type Type = unwrapOrError(Symbol.getType(), FileName, ArchiveName, ArchitectureName); uint32_t Flags = Symbol.getFlags(); - section_iterator Section = unwrapOrError(Symbol.getSection(), FileName, + + // Don't ask a Mach-O STAB symbol for its section unless you know that + // STAB symbol's section field refers to a valid section index. Otherwise + // the symbol may error trying to load a section that does not exist. + bool isSTAB = false; + if (MachO) { + DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); + uint8_t NType = (MachO->is64Bit() ? + MachO->getSymbol64TableEntry(SymDRI).n_type: + MachO->getSymbolTableEntry(SymDRI).n_type); + if (NType & MachO::N_STAB) + isSTAB = true; + } + section_iterator Section = isSTAB ? O->section_end() : + unwrapOrError(Symbol.getSection(), FileName, ArchiveName, ArchitectureName); + StringRef Name; if (Type == SymbolRef::ST_Debug && Section != O->section_end()) { if (Expected<StringRef> NameOrErr = Section->getName()) diff --git a/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp index 4d82e0fd9174..bf725ad8d606 100644 --- a/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ b/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -1407,7 +1407,7 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() { P.formatLine("Local / Global hashes:"); TypeIndex TI(TypeIndex::FirstNonSimpleIndex); - for (const auto &H : zip(LocalHashes, GlobalHashes)) { + for (auto H : zip(LocalHashes, GlobalHashes)) { AutoIndent Indent2(P); LocallyHashedType &L = std::get<0>(H); GloballyHashedType &G = std::get<1>(H); diff --git a/llvm/tools/llvm-pdbutil/InputFile.h b/llvm/tools/llvm-pdbutil/InputFile.h index f25390c971d0..a5d2897f5600 100644 --- a/llvm/tools/llvm-pdbutil/InputFile.h +++ b/llvm/tools/llvm-pdbutil/InputFile.h @@ -43,7 +43,7 @@ class InputFile { std::unique_ptr<NativeSession> PdbSession; object::OwningBinary<object::Binary> CoffObject; std::unique_ptr<MemoryBuffer> UnknownFile; - PointerUnion3<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj; + PointerUnion<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj; using TypeCollectionPtr = std::unique_ptr<codeview::LazyRandomTypeCollection>; diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp index 3e026f58871b..8f365c5ad082 100644 --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -884,7 +884,7 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, } if (XData.X()) { - const uint32_t Address = XData.ExceptionHandlerRVA(); + const uint64_t Address = COFF.getImageBase() + XData.ExceptionHandlerRVA(); const uint32_t Parameter = XData.ExceptionHandlerParameter(); const size_t HandlerOffset = HeaderWords(XData) + (XData.E() ? 0 : XData.EpilogueCount()) @@ -896,7 +896,8 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true); if (!Symbol) { ListScope EHS(SW, "ExceptionHandler"); - SW.printString("Routine", "(null)"); + SW.printHex("Routine", Address); + SW.printHex("Parameter", Parameter); return true; } @@ -925,7 +926,8 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); if (!Function) - Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + Function = getSymbol(COFF, COFF.getImageBase() + RF.BeginAddress, + /*FunctionOnly=*/true); ErrorOr<SymbolRef> XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4); if (!XDataRecord) diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 57144882c4b4..8ffb68283405 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -151,6 +151,41 @@ struct DynRegionInfo { } }; +namespace { +struct VerdAux { + unsigned Offset; + std::string Name; +}; + +struct VerDef { + unsigned Offset; + unsigned Version; + unsigned Flags; + unsigned Ndx; + unsigned Cnt; + unsigned Hash; + std::string Name; + std::vector<VerdAux> AuxV; +}; + +struct VernAux { + unsigned Hash; + unsigned Flags; + unsigned Other; + unsigned Offset; + std::string Name; +}; + +struct VerNeed { + unsigned Version; + unsigned Cnt; + unsigned Offset; + std::string File; + std::vector<VernAux> AuxV; +}; + +} // namespace + template <typename ELFT> class ELFDumper : public ObjDumper { public: ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ScopedPrinter &Writer); @@ -158,6 +193,7 @@ public: void printFileHeaders() override; void printSectionHeaders() override; void printRelocations() override; + void printDependentLibs() override; void printDynamicRelocations() override; void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override; void printHashSymbols() override; @@ -221,13 +257,11 @@ private: std::pair<const Elf_Phdr *, const Elf_Shdr *> findDynamic(const ELFFile<ELFT> *Obj); void loadDynamicTable(const ELFFile<ELFT> *Obj); - void parseDynamicTable(); + void parseDynamicTable(const ELFFile<ELFT> *Obj); - StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, - bool &IsDefault) const; - void LoadVersionMap() const; - void LoadVersionNeeds(const Elf_Shdr *ec) const; - void LoadVersionDefs(const Elf_Shdr *sec) const; + Expected<StringRef> getSymbolVersion(const Elf_Sym *symb, + bool &IsDefault) const; + Error LoadVersionMap() const; const object::ELFObjectFile<ELFT> *ObjF; DynRegionInfo DynRelRegion; @@ -250,29 +284,11 @@ private: const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r const Elf_Shdr *SymbolVersionDefSection = nullptr; // .gnu.version_d - // Records for each version index the corresponding Verdef or Vernaux entry. - // This is filled the first time LoadVersionMap() is called. - class VersionMapEntry : public PointerIntPair<const void *, 1> { - public: - // If the integer is 0, this is an Elf_Verdef*. - // If the integer is 1, this is an Elf_Vernaux*. - VersionMapEntry() : PointerIntPair<const void *, 1>(nullptr, 0) {} - VersionMapEntry(const Elf_Verdef *verdef) - : PointerIntPair<const void *, 1>(verdef, 0) {} - VersionMapEntry(const Elf_Vernaux *vernaux) - : PointerIntPair<const void *, 1>(vernaux, 1) {} - - bool isNull() const { return getPointer() == nullptr; } - bool isVerdef() const { return !isNull() && getInt() == 0; } - bool isVernaux() const { return !isNull() && getInt() == 1; } - const Elf_Verdef *getVerdef() const { - return isVerdef() ? (const Elf_Verdef *)getPointer() : nullptr; - } - const Elf_Vernaux *getVernaux() const { - return isVernaux() ? (const Elf_Vernaux *)getPointer() : nullptr; - } + struct VersionEntry { + std::string Name; + bool IsVerDef; }; - mutable SmallVector<VersionMapEntry, 16> VersionMap; + mutable SmallVector<Optional<VersionEntry>, 16> VersionMap; public: Elf_Dyn_Range dynamic_table() const { @@ -299,14 +315,14 @@ public: Elf_Relr_Range dyn_relrs() const; std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic) const; - void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym, - StringRef &SectionName, - unsigned &SectionIndex) const; + Expected<unsigned> getSymbolSectionIndex(const Elf_Sym *Symbol, + const Elf_Sym *FirstSym) const; + Expected<StringRef> getSymbolSectionName(const Elf_Sym *Symbol, + unsigned SectionIndex) const; Expected<std::string> getStaticSymbolName(uint32_t Index) const; std::string getDynamicString(uint64_t Value) const; - StringRef getSymbolVersionByIndex(StringRef StrTab, - uint32_t VersionSymbolIndex, - bool &IsDefault) const; + Expected<StringRef> getSymbolVersionByIndex(uint32_t VersionSymbolIndex, + bool &IsDefault) const; void printSymbolsHelper(bool IsDynamic) const; void printDynamicEntry(raw_ostream &OS, uint64_t Type, uint64_t Value) const; @@ -323,9 +339,307 @@ public: const DynRegionInfo &getDynamicTableRegion() const { return DynamicTable; } const Elf_Hash *getHashTable() const { return HashTable; } const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; } + + Expected<ArrayRef<Elf_Versym>> getVersionTable(const Elf_Shdr *Sec, + ArrayRef<Elf_Sym> *SymTab, + StringRef *StrTab) const; + Expected<std::vector<VerDef>> + getVersionDefinitions(const Elf_Shdr *Sec) const; + Expected<std::vector<VerNeed>> + getVersionDependencies(const Elf_Shdr *Sec) const; }; template <class ELFT> +static Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> *Obj, + const typename ELFT::Shdr *Sec, + unsigned SecNdx) { + Expected<const typename ELFT::Shdr *> StrTabSecOrErr = + Obj->getSection(Sec->sh_link); + if (!StrTabSecOrErr) + return createError("invalid section linked to " + + object::getELFSectionTypeName( + Obj->getHeader()->e_machine, Sec->sh_type) + + " section with index " + Twine(SecNdx) + ": " + + toString(StrTabSecOrErr.takeError())); + + Expected<StringRef> StrTabOrErr = Obj->getStringTable(*StrTabSecOrErr); + if (!StrTabOrErr) + return createError("invalid string table linked to " + + object::getELFSectionTypeName( + Obj->getHeader()->e_machine, Sec->sh_type) + + " section with index " + Twine(SecNdx) + ": " + + toString(StrTabOrErr.takeError())); + return *StrTabOrErr; +} + +// Returns the linked symbol table and associated string table for a given section. +template <class ELFT> +static Expected<std::pair<typename ELFT::SymRange, StringRef>> +getLinkAsSymtab(const ELFFile<ELFT> *Obj, const typename ELFT::Shdr *Sec, + unsigned SecNdx, unsigned ExpectedType) { + Expected<const typename ELFT::Shdr *> SymtabOrErr = + Obj->getSection(Sec->sh_link); + if (!SymtabOrErr) + return createError("invalid section linked to " + + object::getELFSectionTypeName( + Obj->getHeader()->e_machine, Sec->sh_type) + + " section with index " + Twine(SecNdx) + ": " + + toString(SymtabOrErr.takeError())); + + if ((*SymtabOrErr)->sh_type != ExpectedType) + return createError( + "invalid section linked to " + + object::getELFSectionTypeName(Obj->getHeader()->e_machine, + Sec->sh_type) + + " section with index " + Twine(SecNdx) + ": expected " + + object::getELFSectionTypeName(Obj->getHeader()->e_machine, + ExpectedType) + + ", but got " + + object::getELFSectionTypeName(Obj->getHeader()->e_machine, + (*SymtabOrErr)->sh_type)); + + Expected<StringRef> StrTabOrErr = + getLinkAsStrtab(Obj, *SymtabOrErr, Sec->sh_link); + if (!StrTabOrErr) + return createError( + "can't get a string table for the symbol table linked to " + + object::getELFSectionTypeName(Obj->getHeader()->e_machine, + Sec->sh_type) + + " section with index " + Twine(SecNdx) + ": " + + toString(StrTabOrErr.takeError())); + + Expected<typename ELFT::SymRange> SymsOrErr = Obj->symbols(*SymtabOrErr); + if (!SymsOrErr) + return createError( + "unable to read symbols from the symbol table with index " + + Twine(Sec->sh_link) + ": " + toString(SymsOrErr.takeError())); + + return std::make_pair(*SymsOrErr, *StrTabOrErr); +} + +template <class ELFT> +Expected<ArrayRef<typename ELFT::Versym>> +ELFDumper<ELFT>::getVersionTable(const Elf_Shdr *Sec, ArrayRef<Elf_Sym> *SymTab, + StringRef *StrTab) const { + assert((!SymTab && !StrTab) || (SymTab && StrTab)); + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); + + if (uintptr_t(Obj->base() + Sec->sh_offset) % sizeof(uint16_t) != 0) + return createError("the SHT_GNU_versym section with index " + + Twine(SecNdx) + " is misaligned"); + + Expected<ArrayRef<Elf_Versym>> VersionsOrErr = + Obj->template getSectionContentsAsArray<Elf_Versym>(Sec); + if (!VersionsOrErr) + return createError( + "cannot read content of SHT_GNU_versym section with index " + + Twine(SecNdx) + ": " + toString(VersionsOrErr.takeError())); + + Expected<std::pair<ArrayRef<Elf_Sym>, StringRef>> SymTabOrErr = + getLinkAsSymtab(Obj, Sec, SecNdx, SHT_DYNSYM); + if (!SymTabOrErr) { + ELFDumperStyle->reportUniqueWarning(SymTabOrErr.takeError()); + return *VersionsOrErr; + } + + if (SymTabOrErr->first.size() != VersionsOrErr->size()) + ELFDumperStyle->reportUniqueWarning( + createError("SHT_GNU_versym section with index " + Twine(SecNdx) + + ": the number of entries (" + Twine(VersionsOrErr->size()) + + ") does not match the number of symbols (" + + Twine(SymTabOrErr->first.size()) + + ") in the symbol table with index " + Twine(Sec->sh_link))); + + if (SymTab) + std::tie(*SymTab, *StrTab) = *SymTabOrErr; + return *VersionsOrErr; +} + +template <class ELFT> +Expected<std::vector<VerDef>> +ELFDumper<ELFT>::getVersionDefinitions(const Elf_Shdr *Sec) const { + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); + + Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx); + if (!StrTabOrErr) + return StrTabOrErr.takeError(); + + Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(Sec); + if (!ContentsOrErr) + return createError( + "cannot read content of SHT_GNU_verdef section with index " + + Twine(SecNdx) + ": " + toString(ContentsOrErr.takeError())); + + const uint8_t *Start = ContentsOrErr->data(); + const uint8_t *End = Start + ContentsOrErr->size(); + + auto ExtractNextAux = [&](const uint8_t *&VerdauxBuf, + unsigned VerDefNdx) -> Expected<VerdAux> { + if (VerdauxBuf + sizeof(Elf_Verdaux) > End) + return createError("invalid SHT_GNU_verdef section with index " + + Twine(SecNdx) + ": version definition " + + Twine(VerDefNdx) + + " refers to an auxiliary entry that goes past the end " + "of the section"); + + auto *Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); + VerdauxBuf += Verdaux->vda_next; + + VerdAux Aux; + Aux.Offset = VerdauxBuf - Start; + if (Verdaux->vda_name <= StrTabOrErr->size()) + Aux.Name = StrTabOrErr->drop_front(Verdaux->vda_name); + else + Aux.Name = "<invalid vda_name: " + to_string(Verdaux->vda_name) + ">"; + return Aux; + }; + + std::vector<VerDef> Ret; + const uint8_t *VerdefBuf = Start; + for (unsigned I = 1; I <= /*VerDefsNum=*/Sec->sh_info; ++I) { + if (VerdefBuf + sizeof(Elf_Verdef) > End) + return createError("invalid SHT_GNU_verdef section with index " + + Twine(SecNdx) + ": version definition " + Twine(I) + + " goes past the end of the section"); + + if (uintptr_t(VerdefBuf) % sizeof(uint32_t) != 0) + return createError( + "invalid SHT_GNU_verdef section with index " + Twine(SecNdx) + + ": found a misaligned version definition entry at offset 0x" + + Twine::utohexstr(VerdefBuf - Start)); + + unsigned Version = *reinterpret_cast<const Elf_Half *>(VerdefBuf); + if (Version != 1) + return createError("unable to dump SHT_GNU_verdef section with index " + + Twine(SecNdx) + ": version " + Twine(Version) + + " is not yet supported"); + + const Elf_Verdef *D = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); + VerDef &VD = *Ret.emplace(Ret.end()); + VD.Offset = VerdefBuf - Start; + VD.Version = D->vd_version; + VD.Flags = D->vd_flags; + VD.Ndx = D->vd_ndx; + VD.Cnt = D->vd_cnt; + VD.Hash = D->vd_hash; + + const uint8_t *VerdauxBuf = VerdefBuf + D->vd_aux; + for (unsigned J = 0; J < D->vd_cnt; ++J) { + if (uintptr_t(VerdauxBuf) % sizeof(uint32_t) != 0) + return createError("invalid SHT_GNU_verdef section with index " + + Twine(SecNdx) + + ": found a misaligned auxiliary entry at offset 0x" + + Twine::utohexstr(VerdauxBuf - Start)); + + Expected<VerdAux> AuxOrErr = ExtractNextAux(VerdauxBuf, I); + if (!AuxOrErr) + return AuxOrErr.takeError(); + + if (J == 0) + VD.Name = AuxOrErr->Name; + else + VD.AuxV.push_back(*AuxOrErr); + } + + VerdefBuf += D->vd_next; + } + + return Ret; +} + +template <class ELFT> +Expected<std::vector<VerNeed>> +ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const { + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); + + StringRef StrTab; + Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx); + if (!StrTabOrErr) + ELFDumperStyle->reportUniqueWarning(StrTabOrErr.takeError()); + else + StrTab = *StrTabOrErr; + + Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(Sec); + if (!ContentsOrErr) + return createError( + "cannot read content of SHT_GNU_verneed section with index " + + Twine(SecNdx) + ": " + toString(ContentsOrErr.takeError())); + + const uint8_t *Start = ContentsOrErr->data(); + const uint8_t *End = Start + ContentsOrErr->size(); + const uint8_t *VerneedBuf = Start; + + std::vector<VerNeed> Ret; + for (unsigned I = 1; I <= /*VerneedNum=*/Sec->sh_info; ++I) { + if (VerneedBuf + sizeof(Elf_Verdef) > End) + return createError("invalid SHT_GNU_verneed section with index " + + Twine(SecNdx) + ": version dependency " + Twine(I) + + " goes past the end of the section"); + + if (uintptr_t(VerneedBuf) % sizeof(uint32_t) != 0) + return createError( + "invalid SHT_GNU_verneed section with index " + Twine(SecNdx) + + ": found a misaligned version dependency entry at offset 0x" + + Twine::utohexstr(VerneedBuf - Start)); + + unsigned Version = *reinterpret_cast<const Elf_Half *>(VerneedBuf); + if (Version != 1) + return createError("unable to dump SHT_GNU_verneed section with index " + + Twine(SecNdx) + ": version " + Twine(Version) + + " is not yet supported"); + + const Elf_Verneed *Verneed = + reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + + VerNeed &VN = *Ret.emplace(Ret.end()); + VN.Version = Verneed->vn_version; + VN.Cnt = Verneed->vn_cnt; + VN.Offset = VerneedBuf - Start; + + if (Verneed->vn_file < StrTab.size()) + VN.File = StrTab.drop_front(Verneed->vn_file); + else + VN.File = "<corrupt vn_file: " + to_string(Verneed->vn_file) + ">"; + + const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; + for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { + if (uintptr_t(VernauxBuf) % sizeof(uint32_t) != 0) + return createError("invalid SHT_GNU_verneed section with index " + + Twine(SecNdx) + + ": found a misaligned auxiliary entry at offset 0x" + + Twine::utohexstr(VernauxBuf - Start)); + + if (VernauxBuf + sizeof(Elf_Vernaux) > End) + return createError( + "invalid SHT_GNU_verneed section with index " + Twine(SecNdx) + + ": version dependency " + Twine(I) + + " refers to an auxiliary entry that goes past the end " + "of the section"); + + const Elf_Vernaux *Vernaux = + reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); + + VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end()); + Aux.Hash = Vernaux->vna_hash; + Aux.Flags = Vernaux->vna_flags; + Aux.Other = Vernaux->vna_other; + Aux.Offset = VernauxBuf - Start; + if (StrTab.size() <= Vernaux->vna_name) + Aux.Name = "<corrupt>"; + else + Aux.Name = StrTab.drop_front(Vernaux->vna_name); + + VernauxBuf += Vernaux->vna_next; + } + VerneedBuf += Verneed->vn_next; + } + return Ret; +} + +template <class ELFT> void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const { StringRef StrTable, SymtabName; size_t Entries = 0; @@ -392,6 +706,7 @@ public: virtual void printSymbols(const ELFFile<ELFT> *Obj, bool PrintSymbols, bool PrintDynamicSymbols) = 0; virtual void printHashSymbols(const ELFFile<ELFT> *Obj) {} + virtual void printDependentLibs(const ELFFile<ELFT> *Obj) = 0; virtual void printDynamic(const ELFFile<ELFT> *Obj) {} virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0; virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name, @@ -432,6 +747,8 @@ public: virtual void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) = 0; const ELFDumper<ELFT> *dumper() const { return Dumper; } + void reportUniqueWarning(Error Err) const; + protected: std::function<Error(const Twine &Msg)> WarningHandler; StringRef FileName; @@ -460,6 +777,7 @@ public: void printSymbols(const ELFO *Obj, bool PrintSymbols, bool PrintDynamicSymbols) override; void printHashSymbols(const ELFO *Obj) override; + void printDependentLibs(const ELFFile<ELFT> *Obj) override; void printDynamic(const ELFFile<ELFT> *Obj) override; void printDynamicRelocations(const ELFO *Obj) override; void printSymtabMessage(const ELFO *Obj, StringRef Name, size_t Offset, @@ -553,8 +871,19 @@ private: bool checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); void printProgramHeaders(const ELFO *Obj); void printSectionMapping(const ELFO *Obj); + void printGNUVersionSectionProlog(const ELFFile<ELFT> *Obj, + const typename ELFT::Shdr *Sec, + const Twine &Label, unsigned EntriesNum); }; +template <class ELFT> +void DumpStyle<ELFT>::reportUniqueWarning(Error Err) const { + handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { + cantFail(WarningHandler(EI.message()), + "WarningHandler should always return ErrorSuccess"); + }); +} + template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> { public: TYPEDEF_ELF_TYPES(ELFT) @@ -569,6 +898,7 @@ public: void printSectionHeaders(const ELFO *Obj) override; void printSymbols(const ELFO *Obj, bool PrintSymbols, bool PrintDynamicSymbols) override; + void printDependentLibs(const ELFFile<ELFT> *Obj) override; void printDynamic(const ELFFile<ELFT> *Obj) override; void printDynamicRelocations(const ELFO *Obj) override; void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, @@ -595,6 +925,7 @@ private: void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel); void printSymbols(const ELFO *Obj); void printDynamicSymbols(const ELFO *Obj); + void printSymbolSection(const Elf_Sym *Symbol, const Elf_Sym *First); void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, StringRef StrTable, bool IsDynamic, bool /*NonVisibilityBitsUsed*/) override; @@ -640,96 +971,51 @@ std::error_code createELFDumper(const object::ObjectFile *Obj, } // end namespace llvm -// Iterate through the versions needed section, and place each Elf_Vernaux -// in the VersionMap according to its index. -template <class ELFT> -void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *Sec) const { - unsigned VerneedSize = Sec->sh_size; // Size of section in bytes - unsigned VerneedEntries = Sec->sh_info; // Number of Verneed entries - const uint8_t *VerneedStart = reinterpret_cast<const uint8_t *>( - ObjF->getELFFile()->base() + Sec->sh_offset); - const uint8_t *VerneedEnd = VerneedStart + VerneedSize; - // The first Verneed entry is at the start of the section. - const uint8_t *VerneedBuf = VerneedStart; - for (unsigned VerneedIndex = 0; VerneedIndex < VerneedEntries; - ++VerneedIndex) { - if (VerneedBuf + sizeof(Elf_Verneed) > VerneedEnd) - report_fatal_error("Section ended unexpectedly while scanning " - "version needed records."); - const Elf_Verneed *Verneed = - reinterpret_cast<const Elf_Verneed *>(VerneedBuf); - if (Verneed->vn_version != ELF::VER_NEED_CURRENT) - report_fatal_error("Unexpected verneed version"); - // Iterate through the Vernaux entries - const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; - for (unsigned VernauxIndex = 0; VernauxIndex < Verneed->vn_cnt; - ++VernauxIndex) { - if (VernauxBuf + sizeof(Elf_Vernaux) > VerneedEnd) - report_fatal_error("Section ended unexpected while scanning auxiliary " - "version needed records."); - const Elf_Vernaux *Vernaux = - reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); - size_t Index = Vernaux->vna_other & ELF::VERSYM_VERSION; - if (Index >= VersionMap.size()) - VersionMap.resize(Index + 1); - VersionMap[Index] = VersionMapEntry(Vernaux); - VernauxBuf += Vernaux->vna_next; - } - VerneedBuf += Verneed->vn_next; - } -} - -// Iterate through the version definitions, and place each Elf_Verdef -// in the VersionMap according to its index. -template <class ELFT> -void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *Sec) const { - unsigned VerdefSize = Sec->sh_size; // Size of section in bytes - unsigned VerdefEntries = Sec->sh_info; // Number of Verdef entries - const uint8_t *VerdefStart = reinterpret_cast<const uint8_t *>( - ObjF->getELFFile()->base() + Sec->sh_offset); - const uint8_t *VerdefEnd = VerdefStart + VerdefSize; - // The first Verdef entry is at the start of the section. - const uint8_t *VerdefBuf = VerdefStart; - for (unsigned VerdefIndex = 0; VerdefIndex < VerdefEntries; ++VerdefIndex) { - if (VerdefBuf + sizeof(Elf_Verdef) > VerdefEnd) - report_fatal_error("Section ended unexpectedly while scanning " - "version definitions."); - const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); - if (Verdef->vd_version != ELF::VER_DEF_CURRENT) - report_fatal_error("Unexpected verdef version"); - size_t Index = Verdef->vd_ndx & ELF::VERSYM_VERSION; - if (Index >= VersionMap.size()) - VersionMap.resize(Index + 1); - VersionMap[Index] = VersionMapEntry(Verdef); - VerdefBuf += Verdef->vd_next; - } -} - -template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() const { +template <class ELFT> Error ELFDumper<ELFT>::LoadVersionMap() const { // If there is no dynamic symtab or version table, there is nothing to do. if (!DynSymRegion.Addr || !SymbolVersionSection) - return; + return Error::success(); // Has the VersionMap already been loaded? if (!VersionMap.empty()) - return; + return Error::success(); // The first two version indexes are reserved. // Index 0 is LOCAL, index 1 is GLOBAL. - VersionMap.push_back(VersionMapEntry()); - VersionMap.push_back(VersionMapEntry()); + VersionMap.push_back(VersionEntry()); + VersionMap.push_back(VersionEntry()); + + auto InsertEntry = [this](unsigned N, StringRef Version, bool IsVerdef) { + if (N >= VersionMap.size()) + VersionMap.resize(N + 1); + VersionMap[N] = {Version, IsVerdef}; + }; - if (SymbolVersionDefSection) - LoadVersionDefs(SymbolVersionDefSection); + if (SymbolVersionDefSection) { + Expected<std::vector<VerDef>> Defs = + this->getVersionDefinitions(SymbolVersionDefSection); + if (!Defs) + return Defs.takeError(); + for (const VerDef &Def : *Defs) + InsertEntry(Def.Ndx & ELF::VERSYM_VERSION, Def.Name, true); + } + + if (SymbolVersionNeedSection) { + Expected<std::vector<VerNeed>> Deps = + this->getVersionDependencies(SymbolVersionNeedSection); + if (!Deps) + return Deps.takeError(); + for (const VerNeed &Dep : *Deps) + for (const VernAux &Aux : Dep.AuxV) + InsertEntry(Aux.Other & ELF::VERSYM_VERSION, Aux.Name, false); + } - if (SymbolVersionNeedSection) - LoadVersionNeeds(SymbolVersionNeedSection); + return Error::success(); } template <typename ELFT> -StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, - const Elf_Sym *Sym, - bool &IsDefault) const { +Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym *Sym, + bool &IsDefault) const { // This is a dynamic symbol. Look in the GNU symbol version table. if (!SymbolVersionSection) { // No version table. @@ -746,7 +1032,7 @@ StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, const Elf_Versym *Versym = unwrapOrError( ObjF->getFileName(), ObjF->getELFFile()->template getEntry<Elf_Versym>( SymbolVersionSection, EntryIndex)); - return this->getSymbolVersionByIndex(StrTab, Versym->vs_index, IsDefault); + return this->getSymbolVersionByIndex(Versym->vs_index, IsDefault); } static std::string maybeDemangle(StringRef Name) { @@ -773,9 +1059,9 @@ ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { } template <typename ELFT> -StringRef ELFDumper<ELFT>::getSymbolVersionByIndex(StringRef StrTab, - uint32_t SymbolVersionIndex, - bool &IsDefault) const { +Expected<StringRef> +ELFDumper<ELFT>::getSymbolVersionByIndex(uint32_t SymbolVersionIndex, + bool &IsDefault) const { size_t VersionIndex = SymbolVersionIndex & VERSYM_VERSION; // Special markers for unversioned symbols. @@ -785,24 +1071,18 @@ StringRef ELFDumper<ELFT>::getSymbolVersionByIndex(StringRef StrTab, } // Lookup this symbol in the version table. - LoadVersionMap(); - if (VersionIndex >= VersionMap.size() || VersionMap[VersionIndex].isNull()) - reportError(createError("Invalid version entry"), ObjF->getFileName()); - const VersionMapEntry &Entry = VersionMap[VersionIndex]; - - // Get the version name string. - size_t NameOffset; - if (Entry.isVerdef()) { - // The first Verdaux entry holds the name. - NameOffset = Entry.getVerdef()->getAux()->vda_name; + if (Error E = LoadVersionMap()) + return std::move(E); + if (VersionIndex >= VersionMap.size() || !VersionMap[VersionIndex]) + return createError("SHT_GNU_versym section refers to a version index " + + Twine(VersionIndex) + " which is missing"); + + const VersionEntry &Entry = *VersionMap[VersionIndex]; + if (Entry.IsVerDef) IsDefault = !(SymbolVersionIndex & VERSYM_HIDDEN); - } else { - NameOffset = Entry.getVernaux()->vna_name; + else IsDefault = false; - } - if (NameOffset >= StrTab.size()) - reportError(createError("Invalid string offset"), ObjF->getFileName()); - return StrTab.data() + NameOffset; + return Entry.Name.c_str(); } template <typename ELFT> @@ -813,54 +1093,77 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, unwrapOrError(ObjF->getFileName(), Symbol->getName(StrTable))); if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) { - unsigned SectionIndex; - StringRef SectionName; Elf_Sym_Range Syms = unwrapOrError( ObjF->getFileName(), ObjF->getELFFile()->symbols(DotSymtabSec)); - getSectionNameIndex(Symbol, Syms.begin(), SectionName, SectionIndex); - return SectionName; + Expected<unsigned> SectionIndex = + getSymbolSectionIndex(Symbol, Syms.begin()); + if (!SectionIndex) { + ELFDumperStyle->reportUniqueWarning(SectionIndex.takeError()); + return "<?>"; + } + Expected<StringRef> NameOrErr = getSymbolSectionName(Symbol, *SectionIndex); + if (!NameOrErr) { + ELFDumperStyle->reportUniqueWarning(NameOrErr.takeError()); + return ("<section " + Twine(*SectionIndex) + ">").str(); + } + return *NameOrErr; } if (!IsDynamic) return SymbolName; bool IsDefault; - StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault); - if (!Version.empty()) { + Expected<StringRef> VersionOrErr = getSymbolVersion(&*Symbol, IsDefault); + if (!VersionOrErr) { + ELFDumperStyle->reportUniqueWarning(VersionOrErr.takeError()); + return SymbolName + "@<corrupt>"; + } + + if (!VersionOrErr->empty()) { SymbolName += (IsDefault ? "@@" : "@"); - SymbolName += Version; + SymbolName += *VersionOrErr; } return SymbolName; } template <typename ELFT> -void ELFDumper<ELFT>::getSectionNameIndex(const Elf_Sym *Symbol, - const Elf_Sym *FirstSym, - StringRef &SectionName, - unsigned &SectionIndex) const { - SectionIndex = Symbol->st_shndx; +Expected<unsigned> +ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym *Symbol, + const Elf_Sym *FirstSym) const { + return Symbol->st_shndx == SHN_XINDEX + ? object::getExtendedSymbolTableIndex<ELFT>(Symbol, FirstSym, + ShndxTable) + : Symbol->st_shndx; +} + +// If the Symbol has a reserved st_shndx other than SHN_XINDEX, return a +// descriptive interpretation of the st_shndx value. Otherwise, return the name +// of the section with index SectionIndex. This function assumes that if the +// Symbol has st_shndx == SHN_XINDEX the SectionIndex will be the value derived +// from the SHT_SYMTAB_SHNDX section. +template <typename ELFT> +Expected<StringRef> +ELFDumper<ELFT>::getSymbolSectionName(const Elf_Sym *Symbol, + unsigned SectionIndex) const { if (Symbol->isUndefined()) - SectionName = "Undefined"; - else if (Symbol->isProcessorSpecific()) - SectionName = "Processor Specific"; - else if (Symbol->isOSSpecific()) - SectionName = "Operating System Specific"; - else if (Symbol->isAbsolute()) - SectionName = "Absolute"; - else if (Symbol->isCommon()) - SectionName = "Common"; - else if (Symbol->isReserved() && SectionIndex != SHN_XINDEX) - SectionName = "Reserved"; - else { - if (SectionIndex == SHN_XINDEX) - SectionIndex = unwrapOrError(ObjF->getFileName(), - object::getExtendedSymbolTableIndex<ELFT>( - Symbol, FirstSym, ShndxTable)); - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const typename ELFT::Shdr *Sec = - unwrapOrError(ObjF->getFileName(), Obj->getSection(SectionIndex)); - SectionName = unwrapOrError(ObjF->getFileName(), Obj->getSectionName(Sec)); - } + return "Undefined"; + if (Symbol->isProcessorSpecific()) + return "Processor Specific"; + if (Symbol->isOSSpecific()) + return "Operating System Specific"; + if (Symbol->isAbsolute()) + return "Absolute"; + if (Symbol->isCommon()) + return "Common"; + if (Symbol->isReserved() && Symbol->st_shndx != SHN_XINDEX) + return "Reserved"; + + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + Expected<const Elf_Shdr *> SecOrErr = + Obj->getSection(SectionIndex); + if (!SecOrErr) + return SecOrErr.takeError(); + return Obj->getSectionName(*SecOrErr); } template <class ELFO> @@ -1131,76 +1434,126 @@ static const char *getGroupType(uint32_t Flag) { static const EnumEntry<unsigned> ElfSectionFlags[] = { ENUM_ENT(SHF_WRITE, "W"), ENUM_ENT(SHF_ALLOC, "A"), - ENUM_ENT(SHF_EXCLUDE, "E"), ENUM_ENT(SHF_EXECINSTR, "X"), ENUM_ENT(SHF_MERGE, "M"), ENUM_ENT(SHF_STRINGS, "S"), ENUM_ENT(SHF_INFO_LINK, "I"), ENUM_ENT(SHF_LINK_ORDER, "L"), - ENUM_ENT(SHF_OS_NONCONFORMING, "o"), + ENUM_ENT(SHF_OS_NONCONFORMING, "O"), ENUM_ENT(SHF_GROUP, "G"), ENUM_ENT(SHF_TLS, "T"), - ENUM_ENT(SHF_MASKOS, "o"), - ENUM_ENT(SHF_MASKPROC, "p"), - ENUM_ENT_1(SHF_COMPRESSED), + ENUM_ENT(SHF_COMPRESSED, "C"), + ENUM_ENT(SHF_EXCLUDE, "E"), }; static const EnumEntry<unsigned> ElfXCoreSectionFlags[] = { - LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION), - LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION) + ENUM_ENT(XCORE_SHF_CP_SECTION, ""), + ENUM_ENT(XCORE_SHF_DP_SECTION, "") }; static const EnumEntry<unsigned> ElfARMSectionFlags[] = { - LLVM_READOBJ_ENUM_ENT(ELF, SHF_ARM_PURECODE) + ENUM_ENT(SHF_ARM_PURECODE, "y") }; static const EnumEntry<unsigned> ElfHexagonSectionFlags[] = { - LLVM_READOBJ_ENUM_ENT(ELF, SHF_HEX_GPREL) + ENUM_ENT(SHF_HEX_GPREL, "") }; static const EnumEntry<unsigned> ElfMipsSectionFlags[] = { - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NODUPES), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NAMES ), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_LOCAL ), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_GPREL ), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_MERGE ), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_ADDR ), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_STRING ) + ENUM_ENT(SHF_MIPS_NODUPES, ""), + ENUM_ENT(SHF_MIPS_NAMES, ""), + ENUM_ENT(SHF_MIPS_LOCAL, ""), + ENUM_ENT(SHF_MIPS_NOSTRIP, ""), + ENUM_ENT(SHF_MIPS_GPREL, ""), + ENUM_ENT(SHF_MIPS_MERGE, ""), + ENUM_ENT(SHF_MIPS_ADDR, ""), + ENUM_ENT(SHF_MIPS_STRING, "") }; static const EnumEntry<unsigned> ElfX86_64SectionFlags[] = { - LLVM_READOBJ_ENUM_ENT(ELF, SHF_X86_64_LARGE) + ENUM_ENT(SHF_X86_64_LARGE, "l") }; -static std::string getGNUFlags(uint64_t Flags) { +static std::vector<EnumEntry<unsigned>> +getSectionFlagsForTarget(unsigned EMachine) { + std::vector<EnumEntry<unsigned>> Ret(std::begin(ElfSectionFlags), + std::end(ElfSectionFlags)); + switch (EMachine) { + case EM_ARM: + Ret.insert(Ret.end(), std::begin(ElfARMSectionFlags), + std::end(ElfARMSectionFlags)); + break; + case EM_HEXAGON: + Ret.insert(Ret.end(), std::begin(ElfHexagonSectionFlags), + std::end(ElfHexagonSectionFlags)); + break; + case EM_MIPS: + Ret.insert(Ret.end(), std::begin(ElfMipsSectionFlags), + std::end(ElfMipsSectionFlags)); + break; + case EM_X86_64: + Ret.insert(Ret.end(), std::begin(ElfX86_64SectionFlags), + std::end(ElfX86_64SectionFlags)); + break; + case EM_XCORE: + Ret.insert(Ret.end(), std::begin(ElfXCoreSectionFlags), + std::end(ElfXCoreSectionFlags)); + break; + default: + break; + } + return Ret; +} + +static std::string getGNUFlags(unsigned EMachine, uint64_t Flags) { + // Here we are trying to build the flags string in the same way as GNU does. + // It is not that straightforward. Imagine we have sh_flags == 0x90000000. + // SHF_EXCLUDE ("E") has a value of 0x80000000 and SHF_MASKPROC is 0xf0000000. + // GNU readelf will not print "E" or "Ep" in this case, but will print just + // "p". It only will print "E" when no other processor flag is set. std::string Str; - for (auto Entry : ElfSectionFlags) { - uint64_t Flag = Entry.Value & Flags; - Flags &= ~Entry.Value; - switch (Flag) { - case ELF::SHF_WRITE: - case ELF::SHF_ALLOC: - case ELF::SHF_EXECINSTR: - case ELF::SHF_MERGE: - case ELF::SHF_STRINGS: - case ELF::SHF_INFO_LINK: - case ELF::SHF_LINK_ORDER: - case ELF::SHF_OS_NONCONFORMING: - case ELF::SHF_GROUP: - case ELF::SHF_TLS: - case ELF::SHF_EXCLUDE: - Str += Entry.AltName; - break; - default: - if (Flag & ELF::SHF_MASKOS) - Str += "o"; - else if (Flag & ELF::SHF_MASKPROC) - Str += "p"; - else if (Flag) - Str += "x"; + bool HasUnknownFlag = false; + bool HasOSFlag = false; + bool HasProcFlag = false; + std::vector<EnumEntry<unsigned>> FlagsList = + getSectionFlagsForTarget(EMachine); + while (Flags) { + // Take the least significant bit as a flag. + uint64_t Flag = Flags & -Flags; + Flags -= Flag; + + // Find the flag in the known flags list. + auto I = llvm::find_if(FlagsList, [=](const EnumEntry<unsigned> &E) { + // Flags with empty names are not printed in GNU style output. + return E.Value == Flag && !E.AltName.empty(); + }); + if (I != FlagsList.end()) { + Str += I->AltName; + continue; + } + + // If we did not find a matching regular flag, then we deal with an OS + // specific flag, processor specific flag or an unknown flag. + if (Flag & ELF::SHF_MASKOS) { + HasOSFlag = true; + Flags &= ~ELF::SHF_MASKOS; + } else if (Flag & ELF::SHF_MASKPROC) { + HasProcFlag = true; + // Mask off all the processor-specific bits. This removes the SHF_EXCLUDE + // bit if set so that it doesn't also get printed. + Flags &= ~ELF::SHF_MASKPROC; + } else { + HasUnknownFlag = true; } } + + // "o", "p" and "x" are printed last. + if (HasOSFlag) + Str += "o"; + if (HasProcFlag) + Str += "p"; + if (HasUnknownFlag) + Str += "x"; return Str; } @@ -1237,6 +1590,7 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK); LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO); + LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_PROPERTY); LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE); LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED); @@ -1261,6 +1615,7 @@ static std::string getElfPtType(unsigned Arch, unsigned Type) { LLVM_READOBJ_PHDR_ENUM(ELF, PT_SUNW_UNWIND) LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_STACK) LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_RELRO) + LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_PROPERTY) default: // All machine specific PT_* types switch (Arch) { @@ -1513,7 +1868,7 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { if (!DynamicPhdr || !DynamicSec) { if ((DynamicPhdr && IsPhdrTableValid) || (DynamicSec && IsSecTableValid)) { DynamicTable = DynamicPhdr ? FromPhdr : FromSec; - parseDynamicTable(); + parseDynamicTable(Obj); } else { reportWarning(createError("no valid dynamic table was found"), ObjF->getFileName()); @@ -1554,7 +1909,7 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { DynamicTable = FromSec; } - parseDynamicTable(); + parseDynamicTable(Obj); } template <typename ELFT> @@ -1620,82 +1975,13 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this)); } -static const char *getTypeString(unsigned Arch, uint64_t Type) { -#define DYNAMIC_TAG(n, v) - switch (Arch) { - - case EM_AARCH64: - switch (Type) { -#define AARCH64_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef AARCH64_DYNAMIC_TAG - } - break; - - case EM_HEXAGON: - switch (Type) { -#define HEXAGON_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef HEXAGON_DYNAMIC_TAG - } - break; - - case EM_MIPS: - switch (Type) { -#define MIPS_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef MIPS_DYNAMIC_TAG - } - break; - - case EM_PPC64: - switch (Type) { -#define PPC64_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef PPC64_DYNAMIC_TAG - } - break; - } -#undef DYNAMIC_TAG - switch (Type) { -// Now handle all dynamic tags except the architecture specific ones -#define AARCH64_DYNAMIC_TAG(name, value) -#define MIPS_DYNAMIC_TAG(name, value) -#define HEXAGON_DYNAMIC_TAG(name, value) -#define PPC64_DYNAMIC_TAG(name, value) -// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc. -#define DYNAMIC_TAG_MARKER(name, value) -#define DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef DYNAMIC_TAG -#undef AARCH64_DYNAMIC_TAG -#undef MIPS_DYNAMIC_TAG -#undef HEXAGON_DYNAMIC_TAG -#undef PPC64_DYNAMIC_TAG -#undef DYNAMIC_TAG_MARKER - default: - return "unknown"; - } -} - -template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { +template <typename ELFT> +void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) { auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * { auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr); if (!MappedAddrOrError) { Error Err = - createError("Unable to parse DT_" + - Twine(getTypeString( - ObjF->getELFFile()->getHeader()->e_machine, Tag)) + + createError("Unable to parse DT_" + Obj->getDynamicTagAsString(Tag) + ": " + llvm::toString(MappedAddrOrError.takeError())); reportWarning(std::move(Err), ObjF->getFileName()); @@ -1851,6 +2137,10 @@ template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() { SymbolVersionNeedSection); } +template <class ELFT> void ELFDumper<ELFT>::printDependentLibs() { + ELFDumperStyle->printDependentLibs(ObjF->getELFFile()); +} + template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() { ELFDumperStyle->printDynamicRelocations(ObjF->getELFFile()); } @@ -2771,8 +3061,8 @@ template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) { OS << "\n"; Str = printEnum(e->e_ident[ELF::EI_OSABI], makeArrayRef(ElfOSABI)); printFields(OS, "OS/ABI:", Str); - Str = "0x" + to_hexString(e->e_ident[ELF::EI_ABIVERSION]); - printFields(OS, "ABI Version:", Str); + printFields(OS, + "ABI Version:", std::to_string(e->e_ident[ELF::EI_ABIVERSION])); Str = printEnum(e->e_type, makeArrayRef(ElfObjectFileType)); printFields(OS, "Type:", Str); Str = printEnum(e->e_machine, makeArrayRef(ElfMachineType)); @@ -3188,6 +3478,25 @@ static std::string getSectionTypeString(unsigned Arch, unsigned Type) { return ""; } +static void printSectionDescription(formatted_raw_ostream &OS, + unsigned EMachine) { + OS << "Key to Flags:\n"; + OS << " W (write), A (alloc), X (execute), M (merge), S (strings), I " + "(info),\n"; + OS << " L (link order), O (extra OS processing required), G (group), T " + "(TLS),\n"; + OS << " C (compressed), x (unknown), o (OS specific), E (exclude),\n"; + + if (EMachine == EM_X86_64) + OS << " l (large), "; + else if (EMachine == EM_ARM) + OS << " y (purecode), "; + else + OS << " "; + + OS << "p (processor specific)\n"; +} + template <class ELFT> void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { unsigned Bias = ELFT::Is64Bits ? 0 : 8; @@ -3218,7 +3527,7 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { Fields[4].Str = to_string(format_hex_no_prefix(Sec.sh_offset, 6)); Fields[5].Str = to_string(format_hex_no_prefix(Sec.sh_size, 6)); Fields[6].Str = to_string(format_hex_no_prefix(Sec.sh_entsize, 2)); - Fields[7].Str = getGNUFlags(Sec.sh_flags); + Fields[7].Str = getGNUFlags(Obj->getHeader()->e_machine, Sec.sh_flags); Fields[8].Str = to_string(Sec.sh_link); Fields[9].Str = to_string(Sec.sh_info); Fields[10].Str = to_string(Sec.sh_addralign); @@ -3238,13 +3547,7 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { OS << "\n"; ++SectionIndex; } - OS << "Key to Flags:\n" - << " W (write), A (alloc), X (execute), M (merge), S (strings), l " - "(large)\n" - << " I (info), L (link order), G (group), T (TLS), E (exclude),\ - x (unknown)\n" - << " O (extra OS processing required) o (OS specific),\ - p (processor specific)\n"; + printSectionDescription(OS, Obj->getHeader()->e_machine); } template <class ELFT> @@ -3279,12 +3582,18 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj, return "ABS"; case ELF::SHN_COMMON: return "COM"; - case ELF::SHN_XINDEX: - return to_string(format_decimal( - unwrapOrError(this->FileName, - object::getExtendedSymbolTableIndex<ELFT>( - Symbol, FirstSym, this->dumper()->getShndxTable())), - 3)); + case ELF::SHN_XINDEX: { + Expected<uint32_t> IndexOrErr = object::getExtendedSymbolTableIndex<ELFT>( + Symbol, FirstSym, this->dumper()->getShndxTable()); + if (!IndexOrErr) { + assert(Symbol->st_shndx == SHN_XINDEX && + "getSymbolSectionIndex should only fail due to an invalid " + "SHT_SYMTAB_SHNDX table/reference"); + this->reportUniqueWarning(IndexOrErr.takeError()); + return "RSV[0xffff]"; + } + return to_string(format_decimal(*IndexOrErr, 3)); + } default: // Find if: // Processor specific @@ -3683,9 +3992,8 @@ template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) { OS << " Tag Type Name/Value\n"; for (auto Entry : Table) { uintX_t Tag = Entry.getTag(); - std::string TypeString = std::string("(") + - getTypeString(Obj->getHeader()->e_machine, Tag) + - ")"; + std::string TypeString = + std::string("(") + Obj->getDynamicTagAsString(Tag).c_str() + ")"; OS << " " << format_hex(Tag, Is64 ? 18 : 10) << format(" %-20s ", TypeString.c_str()); this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal()); @@ -3762,18 +4070,29 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { } template <class ELFT> -static void printGNUVersionSectionProlog(formatted_raw_ostream &OS, - const Twine &Name, unsigned EntriesNum, - const ELFFile<ELFT> *Obj, - const typename ELFT::Shdr *Sec, - StringRef FileName) { - StringRef SecName = unwrapOrError(FileName, Obj->getSectionName(Sec)); - OS << Name << " section '" << SecName << "' " +void GNUStyle<ELFT>::printGNUVersionSectionProlog( + const ELFFile<ELFT> *Obj, const typename ELFT::Shdr *Sec, + const Twine &Label, unsigned EntriesNum) { + StringRef SecName = unwrapOrError(this->FileName, Obj->getSectionName(Sec)); + OS << Label << " section '" << SecName << "' " << "contains " << EntriesNum << " entries:\n"; - const typename ELFT::Shdr *SymTab = - unwrapOrError(FileName, Obj->getSection(Sec->sh_link)); - StringRef SymTabName = unwrapOrError(FileName, Obj->getSectionName(SymTab)); + unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); + StringRef SymTabName = "<corrupt>"; + + Expected<const typename ELFT::Shdr *> SymTabOrErr = + Obj->getSection(Sec->sh_link); + if (SymTabOrErr) + SymTabName = + unwrapOrError(this->FileName, Obj->getSectionName(*SymTabOrErr)); + else + this->reportUniqueWarning( + createError("invalid section linked to " + + object::getELFSectionTypeName(Obj->getHeader()->e_machine, + Sec->sh_type) + + " section with index " + Twine(SecNdx) + ": " + + toString(SymTabOrErr.takeError()))); + OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16) << " Offset: " << format_hex(Sec->sh_offset, 8) << " Link: " << Sec->sh_link << " (" << SymTabName << ")\n"; @@ -3785,46 +4104,51 @@ void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, if (!Sec) return; - unsigned Entries = Sec->sh_size / sizeof(Elf_Versym); - printGNUVersionSectionProlog(OS, "Version symbols", Entries, Obj, Sec, - this->FileName); + printGNUVersionSectionProlog(Obj, Sec, "Version symbols", + Sec->sh_size / sizeof(Elf_Versym)); + Expected<ArrayRef<Elf_Versym>> VerTableOrErr = + this->dumper()->getVersionTable(Sec, /*SymTab=*/nullptr, + /*StrTab=*/nullptr); + if (!VerTableOrErr) { + this->reportUniqueWarning(VerTableOrErr.takeError()); + return; + } + + ArrayRef<Elf_Versym> VerTable = *VerTableOrErr; + std::vector<StringRef> Versions; + for (size_t I = 0, E = VerTable.size(); I < E; ++I) { + unsigned Ndx = VerTable[I].vs_index; + if (Ndx == VER_NDX_LOCAL || Ndx == VER_NDX_GLOBAL) { + Versions.emplace_back(Ndx == VER_NDX_LOCAL ? "*local*" : "*global*"); + continue; + } - const uint8_t *VersymBuf = - reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); - const ELFDumper<ELFT> *Dumper = this->dumper(); - StringRef StrTable = Dumper->getDynamicStringTable(); + bool IsDefault; + Expected<StringRef> NameOrErr = + this->dumper()->getSymbolVersionByIndex(Ndx, IsDefault); + if (!NameOrErr) { + if (!NameOrErr) { + unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); + this->reportUniqueWarning(createError( + "unable to get a version for entry " + Twine(I) + + " of SHT_GNU_versym section with index " + Twine(SecNdx) + ": " + + toString(NameOrErr.takeError()))); + } + Versions.emplace_back("<corrupt>"); + continue; + } + Versions.emplace_back(*NameOrErr); + } // readelf prints 4 entries per line. + uint64_t Entries = VerTable.size(); for (uint64_t VersymRow = 0; VersymRow < Entries; VersymRow += 4) { OS << " " << format_hex_no_prefix(VersymRow, 3) << ":"; - - for (uint64_t VersymIndex = 0; - (VersymIndex < 4) && (VersymIndex + VersymRow) < Entries; - ++VersymIndex) { - const Elf_Versym *Versym = - reinterpret_cast<const Elf_Versym *>(VersymBuf); - switch (Versym->vs_index) { - case 0: - OS << " 0 (*local*) "; - break; - case 1: - OS << " 1 (*global*) "; - break; - default: - OS << format("%4x%c", Versym->vs_index & VERSYM_VERSION, - Versym->vs_index & VERSYM_HIDDEN ? 'h' : ' '); - - bool IsDefault = true; - std::string VersionName = Dumper->getSymbolVersionByIndex( - StrTable, Versym->vs_index, IsDefault); - - if (!VersionName.empty()) - VersionName = "(" + VersionName + ")"; - else - VersionName = "(*invalid*)"; - OS << left_justify(VersionName, 13); - } - VersymBuf += sizeof(Elf_Versym); + for (uint64_t I = 0; (I < 4) && (I + VersymRow) < Entries; ++I) { + unsigned Ndx = VerTable[VersymRow + I].vs_index; + OS << format("%4x%c", Ndx & VERSYM_VERSION, + Ndx & VERSYM_HIDDEN ? 'h' : ' '); + OS << left_justify("(" + std::string(Versions[VersymRow + I]) + ")", 13); } OS << '\n'; } @@ -3858,42 +4182,25 @@ void GNUStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, if (!Sec) return; - unsigned VerDefsNum = Sec->sh_info; - printGNUVersionSectionProlog(OS, "Version definition", VerDefsNum, Obj, Sec, - this->FileName); + printGNUVersionSectionProlog(Obj, Sec, "Version definition", Sec->sh_info); - const Elf_Shdr *StrTabSec = - unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); - StringRef StringTable( - reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset), - (size_t)StrTabSec->sh_size); - - const uint8_t *VerdefBuf = - unwrapOrError(this->FileName, Obj->getSectionContents(Sec)).data(); - const uint8_t *Begin = VerdefBuf; - - while (VerDefsNum--) { - const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); - OS << format(" 0x%04x: Rev: %u Flags: %s Index: %u Cnt: %u", - VerdefBuf - Begin, (unsigned)Verdef->vd_version, - versionFlagToString(Verdef->vd_flags).c_str(), - (unsigned)Verdef->vd_ndx, (unsigned)Verdef->vd_cnt); - - const uint8_t *VerdauxBuf = VerdefBuf + Verdef->vd_aux; - const Elf_Verdaux *Verdaux = - reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); - OS << format(" Name: %s\n", - StringTable.drop_front(Verdaux->vda_name).data()); - - for (unsigned I = 1; I < Verdef->vd_cnt; ++I) { - VerdauxBuf += Verdaux->vda_next; - Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); - OS << format(" 0x%04x: Parent %u: %s\n", VerdauxBuf - Begin, I, - StringTable.drop_front(Verdaux->vda_name).data()); - } + Expected<std::vector<VerDef>> V = this->dumper()->getVersionDefinitions(Sec); + if (!V) { + this->reportUniqueWarning(V.takeError()); + return; + } - VerdefBuf += Verdef->vd_next; + for (const VerDef &Def : *V) { + OS << format(" 0x%04x: Rev: %u Flags: %s Index: %u Cnt: %u Name: %s\n", + Def.Offset, Def.Version, + versionFlagToString(Def.Flags).c_str(), Def.Ndx, Def.Cnt, + Def.Name.data()); + unsigned I = 0; + for (const VerdAux &Aux : Def.AuxV) + OS << format(" 0x%04x: Parent %u: %s\n", Aux.Offset, ++I, + Aux.Name.data()); } + OS << '\n'; } @@ -3904,42 +4211,22 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, return; unsigned VerneedNum = Sec->sh_info; - printGNUVersionSectionProlog(OS, "Version needs", VerneedNum, Obj, Sec, - this->FileName); - - ArrayRef<uint8_t> SecData = - unwrapOrError(this->FileName, Obj->getSectionContents(Sec)); - - const Elf_Shdr *StrTabSec = - unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); - StringRef StringTable = { - reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset), - (size_t)StrTabSec->sh_size}; - - const uint8_t *VerneedBuf = SecData.data(); - for (unsigned I = 0; I < VerneedNum; ++I) { - const Elf_Verneed *Verneed = - reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + printGNUVersionSectionProlog(Obj, Sec, "Version needs", VerneedNum); - OS << format(" 0x%04x: Version: %u File: %s Cnt: %u\n", - reinterpret_cast<const uint8_t *>(Verneed) - SecData.begin(), - (unsigned)Verneed->vn_version, - StringTable.drop_front(Verneed->vn_file).data(), - (unsigned)Verneed->vn_cnt); - - const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; - for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { - const Elf_Vernaux *Vernaux = - reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); + Expected<std::vector<VerNeed>> V = + this->dumper()->getVersionDependencies(Sec); + if (!V) { + this->reportUniqueWarning(V.takeError()); + return; + } - OS << format(" 0x%04x: Name: %s Flags: %s Version: %u\n", - reinterpret_cast<const uint8_t *>(Vernaux) - SecData.begin(), - StringTable.drop_front(Vernaux->vna_name).data(), - versionFlagToString(Vernaux->vna_flags).c_str(), - (unsigned)Vernaux->vna_other); - VernauxBuf += Vernaux->vna_next; - } - VerneedBuf += Verneed->vn_next; + for (const VerNeed &VN : *V) { + OS << format(" 0x%04x: Version: %u File: %s Cnt: %u\n", VN.Offset, + VN.Version, VN.File.data(), VN.Cnt); + for (const VernAux &Aux : VN.AuxV) + OS << format(" 0x%04x: Name: %s Flags: %s Version: %u\n", Aux.Offset, + Aux.Name.data(), versionFlagToString(Aux.Flags).c_str(), + Aux.Other); } OS << '\n'; } @@ -4667,7 +4954,7 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { continue; PrintHeader(S.sh_offset, S.sh_size); Error Err = Error::success(); - for (const auto &Note : Obj->notes(S, Err)) + for (auto Note : Obj->notes(S, Err)) ProcessNote(Note); if (Err) reportError(std::move(Err), this->FileName); @@ -4679,7 +4966,7 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { continue; PrintHeader(P.p_offset, P.p_filesz); Error Err = Error::success(); - for (const auto &Note : Obj->notes(P, Err)) + for (auto Note : Obj->notes(P, Err)) ProcessNote(Note); if (Err) reportError(std::move(Err), this->FileName); @@ -4692,6 +4979,11 @@ void GNUStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { OS << "printELFLinkerOptions not implemented!\n"; } +template <class ELFT> +void GNUStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) { + OS << "printDependentLibs not implemented!\n"; +} + // Used for printing section names in places where possible errors can be // ignored. static StringRef getSectionName(const SectionRef &Sec) { @@ -5345,6 +5637,8 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { int SectionIndex = -1; ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections()); const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject(); + std::vector<EnumEntry<unsigned>> FlagsList = + getSectionFlagsForTarget(Obj->getHeader()->e_machine); for (const Elf_Shdr &Sec : Sections) { StringRef Name = unwrapOrError( ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler)); @@ -5355,35 +5649,7 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { "Type", object::getELFSectionTypeName(Obj->getHeader()->e_machine, Sec.sh_type), Sec.sh_type); - std::vector<EnumEntry<unsigned>> SectionFlags(std::begin(ElfSectionFlags), - std::end(ElfSectionFlags)); - switch (Obj->getHeader()->e_machine) { - case EM_ARM: - SectionFlags.insert(SectionFlags.end(), std::begin(ElfARMSectionFlags), - std::end(ElfARMSectionFlags)); - break; - case EM_HEXAGON: - SectionFlags.insert(SectionFlags.end(), - std::begin(ElfHexagonSectionFlags), - std::end(ElfHexagonSectionFlags)); - break; - case EM_MIPS: - SectionFlags.insert(SectionFlags.end(), std::begin(ElfMipsSectionFlags), - std::end(ElfMipsSectionFlags)); - break; - case EM_X86_64: - SectionFlags.insert(SectionFlags.end(), std::begin(ElfX86_64SectionFlags), - std::end(ElfX86_64SectionFlags)); - break; - case EM_XCORE: - SectionFlags.insert(SectionFlags.end(), std::begin(ElfXCoreSectionFlags), - std::end(ElfXCoreSectionFlags)); - break; - default: - // Nothing to do. - break; - } - W.printFlags("Flags", Sec.sh_flags, makeArrayRef(SectionFlags)); + W.printFlags("Flags", Sec.sh_flags, makeArrayRef(FlagsList)); W.printHex("Address", Sec.sh_addr); W.printHex("Offset", Sec.sh_offset); W.printNumber("Size", Sec.sh_size); @@ -5427,13 +5693,34 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { } template <class ELFT> +void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol, + const Elf_Sym *First) { + Expected<unsigned> SectionIndex = + this->dumper()->getSymbolSectionIndex(Symbol, First); + if (!SectionIndex) { + assert(Symbol->st_shndx == SHN_XINDEX && + "getSymbolSectionIndex should only fail due to an invalid " + "SHT_SYMTAB_SHNDX table/reference"); + this->reportUniqueWarning(SectionIndex.takeError()); + W.printHex("Section", "Reserved", SHN_XINDEX); + return; + } + + Expected<StringRef> SectionName = + this->dumper()->getSymbolSectionName(Symbol, *SectionIndex); + if (!SectionName) { + this->reportUniqueWarning(SectionName.takeError()); + W.printHex("Section", "<?>", *SectionIndex); + } else { + W.printHex("Section", *SectionName, *SectionIndex); + } +} + +template <class ELFT> void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, StringRef StrTable, bool IsDynamic, bool /*NonVisibilityBitsUsed*/) { - unsigned SectionIndex = 0; - StringRef SectionName; - this->dumper()->getSectionNameIndex(Symbol, First, SectionName, SectionIndex); std::string FullSymbolName = this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic); unsigned char SymbolType = Symbol->getType(); @@ -5470,7 +5757,7 @@ void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, } W.printFlags("Other", Symbol->st_other, makeArrayRef(SymOtherFlags), 0x3u); } - W.printHex("Section", SectionName, SectionIndex); + printSymbolSection(Symbol, First); } template <class ELFT> @@ -5509,12 +5796,10 @@ template <class ELFT> void LLVMStyle<ELFT>::printDynamic(const ELFFile<ELFT> *Ob for (auto Entry : Table) { uintX_t Tag = Entry.getTag(); W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " " - << format("%-21s", - getTypeString(Obj->getHeader()->e_machine, Tag)); + << format("%-21s", Obj->getDynamicTagAsString(Tag).c_str()); this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal()); OS << "\n"; } - W.startLine() << "]\n"; } @@ -5619,20 +5904,23 @@ void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, if (!Sec) return; - const uint8_t *VersymBuf = - reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); - const ELFDumper<ELFT> *Dumper = this->dumper(); - StringRef StrTable = Dumper->getDynamicStringTable(); + StringRef StrTable; + ArrayRef<Elf_Sym> Syms; + Expected<ArrayRef<Elf_Versym>> VerTableOrErr = + this->dumper()->getVersionTable(Sec, &Syms, &StrTable); + if (!VerTableOrErr) { + this->reportUniqueWarning(VerTableOrErr.takeError()); + return; + } - // Same number of entries in the dynamic symbol table (DT_SYMTAB). - for (const Elf_Sym &Sym : Dumper->dynamic_symbols()) { + if (StrTable.empty() || Syms.empty() || Syms.size() != VerTableOrErr->size()) + return; + + for (size_t I = 0, E = Syms.size(); I < E; ++I) { DictScope S(W, "Symbol"); - const Elf_Versym *Versym = reinterpret_cast<const Elf_Versym *>(VersymBuf); - std::string FullSymbolName = - Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */); - W.printNumber("Version", Versym->vs_index & VERSYM_VERSION); - W.printString("Name", FullSymbolName); - VersymBuf += sizeof(Elf_Versym); + W.printNumber("Version", (*VerTableOrErr)[I].vs_index & VERSYM_VERSION); + W.printString("Name", this->dumper()->getFullSymbolName( + &Syms[I], StrTable, /*IsDynamic=*/true)); } } @@ -5643,44 +5931,22 @@ void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, if (!Sec) return; - const uint8_t *SecStartAddress = - reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); - const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size; - const uint8_t *VerdefBuf = SecStartAddress; - const Elf_Shdr *StrTab = - unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); - - unsigned VerDefsNum = Sec->sh_info; - while (VerDefsNum--) { - if (VerdefBuf + sizeof(Elf_Verdef) > SecEndAddress) - // FIXME: report_fatal_error is not a good way to report error. We should - // emit a parsing error here and below. - report_fatal_error("invalid offset in the section"); + Expected<std::vector<VerDef>> V = this->dumper()->getVersionDefinitions(Sec); + if (!V) { + this->reportUniqueWarning(V.takeError()); + return; + } - const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); + for (const VerDef &D : *V) { DictScope Def(W, "Definition"); - W.printNumber("Version", Verdef->vd_version); - W.printEnum("Flags", Verdef->vd_flags, makeArrayRef(SymVersionFlags)); - W.printNumber("Index", Verdef->vd_ndx); - W.printNumber("Hash", Verdef->vd_hash); - W.printString("Name", StringRef(reinterpret_cast<const char *>( - Obj->base() + StrTab->sh_offset + - Verdef->getAux()->vda_name))); - if (!Verdef->vd_cnt) - report_fatal_error("at least one definition string must exist"); - if (Verdef->vd_cnt > 2) - report_fatal_error("more than one predecessor is not expected"); - - if (Verdef->vd_cnt == 2) { - const uint8_t *VerdauxBuf = - VerdefBuf + Verdef->vd_aux + Verdef->getAux()->vda_next; - const Elf_Verdaux *Verdaux = - reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); - W.printString("Predecessor", - StringRef(reinterpret_cast<const char *>( - Obj->base() + StrTab->sh_offset + Verdaux->vda_name))); - } - VerdefBuf += Verdef->vd_next; + W.printNumber("Version", D.Version); + W.printFlags("Flags", D.Flags, makeArrayRef(SymVersionFlags)); + W.printNumber("Index", D.Ndx); + W.printNumber("Hash", D.Hash); + W.printString("Name", D.Name.c_str()); + W.printList( + "Predecessors", D.AuxV, + [](raw_ostream &OS, const VerdAux &Aux) { OS << Aux.Name.c_str(); }); } } @@ -5691,38 +5957,27 @@ void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, if (!Sec) return; - const uint8_t *SecData = - reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); - const Elf_Shdr *StrTab = - unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); + Expected<std::vector<VerNeed>> V = + this->dumper()->getVersionDependencies(Sec); + if (!V) { + this->reportUniqueWarning(V.takeError()); + return; + } - const uint8_t *VerneedBuf = SecData; - unsigned VerneedNum = Sec->sh_info; - for (unsigned I = 0; I < VerneedNum; ++I) { - const Elf_Verneed *Verneed = - reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + for (const VerNeed &VN : *V) { DictScope Entry(W, "Dependency"); - W.printNumber("Version", Verneed->vn_version); - W.printNumber("Count", Verneed->vn_cnt); - W.printString("FileName", - StringRef(reinterpret_cast<const char *>( - Obj->base() + StrTab->sh_offset + Verneed->vn_file))); + W.printNumber("Version", VN.Version); + W.printNumber("Count", VN.Cnt); + W.printString("FileName", VN.File.c_str()); - const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; ListScope L(W, "Entries"); - for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { - const Elf_Vernaux *Vernaux = - reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); + for (const VernAux &Aux : VN.AuxV) { DictScope Entry(W, "Entry"); - W.printNumber("Hash", Vernaux->vna_hash); - W.printEnum("Flags", Vernaux->vna_flags, makeArrayRef(SymVersionFlags)); - W.printNumber("Index", Vernaux->vna_other); - W.printString("Name", - StringRef(reinterpret_cast<const char *>( - Obj->base() + StrTab->sh_offset + Vernaux->vna_name))); - VernauxBuf += Vernaux->vna_next; + W.printNumber("Hash", Aux.Hash); + W.printFlags("Flags", Aux.Flags, makeArrayRef(SymVersionFlags)); + W.printNumber("Index", Aux.Other); + W.printString("Name", Aux.Name.c_str()); } - VerneedBuf += Verneed->vn_next; } } @@ -5911,7 +6166,7 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { DictScope D(W, "NoteSection"); PrintHeader(S.sh_offset, S.sh_size); Error Err = Error::success(); - for (const auto &Note : Obj->notes(S, Err)) + for (auto Note : Obj->notes(S, Err)) ProcessNote(Note); if (Err) reportError(std::move(Err), this->FileName); @@ -5924,7 +6179,7 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { DictScope D(W, "NoteSection"); PrintHeader(P.p_offset, P.p_filesz); Error Err = Error::success(); - for (const auto &Note : Obj->notes(P, Err)) + for (auto Note : Obj->notes(P, Err)) ProcessNote(Note); if (Err) reportError(std::move(Err), this->FileName); @@ -5936,20 +6191,76 @@ template <class ELFT> void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { ListScope L(W, "LinkerOptions"); + unsigned I = -1; for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) { + ++I; if (Shdr.sh_type != ELF::SHT_LLVM_LINKER_OPTIONS) continue; ArrayRef<uint8_t> Contents = unwrapOrError(this->FileName, Obj->getSectionContents(&Shdr)); - for (const uint8_t *P = Contents.begin(), *E = Contents.end(); P < E; ) { - StringRef Key = StringRef(reinterpret_cast<const char *>(P)); - StringRef Value = - StringRef(reinterpret_cast<const char *>(P) + Key.size() + 1); + if (Contents.empty()) + continue; + + if (Contents.back() != 0) { + reportWarning(createError("SHT_LLVM_LINKER_OPTIONS section at index " + + Twine(I) + + " is broken: the " + "content is not null-terminated"), + this->FileName); + continue; + } + + SmallVector<StringRef, 16> Strings; + toStringRef(Contents.drop_back()).split(Strings, '\0'); + if (Strings.size() % 2 != 0) { + reportWarning( + createError( + "SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) + + " is broken: an incomplete " + "key-value pair was found. The last possible key was: \"" + + Strings.back() + "\""), + this->FileName); + continue; + } - W.printString(Key, Value); + for (size_t I = 0; I < Strings.size(); I += 2) + W.printString(Strings[I], Strings[I + 1]); + } +} + +template <class ELFT> +void LLVMStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) { + ListScope L(W, "DependentLibs"); + + auto Warn = [this](unsigned SecNdx, StringRef Msg) { + this->reportUniqueWarning( + createError("SHT_LLVM_DEPENDENT_LIBRARIES section at index " + + Twine(SecNdx) + " is broken: " + Msg)); + }; + + unsigned I = -1; + for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) { + ++I; + if (Shdr.sh_type != ELF::SHT_LLVM_DEPENDENT_LIBRARIES) + continue; - P = P + Key.size() + Value.size() + 2; + Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr); + if (!ContentsOrErr) { + Warn(I, toString(ContentsOrErr.takeError())); + continue; + } + + ArrayRef<uint8_t> Contents = *ContentsOrErr; + if (!Contents.empty() && Contents.back() != 0) { + Warn(I, "the content is not null-terminated"); + continue; + } + + for (const uint8_t *I = Contents.begin(), *E = Contents.end(); I < E;) { + StringRef Lib((const char *)I); + W.printString(Lib); + I += Lib.size() + 1; } } } @@ -6016,13 +6327,7 @@ void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { const Elf_Sym *Sym = Parser.getGotSym(&E); W.printHex("Value", Sym->st_value); W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); - - unsigned SectionIndex = 0; - StringRef SectionName; - this->dumper()->getSectionNameIndex( - Sym, this->dumper()->dynamic_symbols().begin(), SectionName, - SectionIndex); - W.printHex("Section", SectionName, SectionIndex); + printSymbolSection(Sym, this->dumper()->dynamic_symbols().begin()); std::string SymName = this->dumper()->getFullSymbolName( Sym, this->dumper()->getDynamicStringTable(), true); @@ -6066,13 +6371,7 @@ void LLVMStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { const Elf_Sym *Sym = Parser.getPltSym(&E); W.printHex("Value", Sym->st_value); W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); - - unsigned SectionIndex = 0; - StringRef SectionName; - this->dumper()->getSectionNameIndex( - Sym, this->dumper()->dynamic_symbols().begin(), SectionName, - SectionIndex); - W.printHex("Section", SectionName, SectionIndex); + printSymbolSection(Sym, this->dumper()->dynamic_symbols().begin()); std::string SymName = this->dumper()->getFullSymbolName(Sym, Parser.getPltStrTable(), true); diff --git a/llvm/tools/llvm-readobj/ObjDumper.cpp b/llvm/tools/llvm-readobj/ObjDumper.cpp index 9e5ebd99ac37..6229b52693d8 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.cpp +++ b/llvm/tools/llvm-readobj/ObjDumper.cpp @@ -65,7 +65,7 @@ getSectionRefsByNameOrIndex(const object::ObjectFile *Obj, SecIndex++; } - for (const std::pair<std::string, bool> &S : SecNames) + for (const std::pair<const std::string, bool> &S : SecNames) if (!S.second) reportWarning( createError(formatv("could not find section '{0}'", S.first).str()), diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h index 2ba441342499..3fc8d3e79ac1 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -53,6 +53,7 @@ public: virtual void printUnwindInfo() = 0; // Only implemented for ELF at this time. + virtual void printDependentLibs() {} virtual void printDynamicRelocations() { } virtual void printDynamicTable() { } virtual void printNeededLibraries() { } diff --git a/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/llvm/tools/llvm-readobj/Win64EHDumper.cpp index fa268ce9d434..380baae2eeb4 100644 --- a/llvm/tools/llvm-readobj/Win64EHDumper.cpp +++ b/llvm/tools/llvm-readobj/Win64EHDumper.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Win64EHDumper.h" +#include "Error.h" #include "llvm-readobj.h" #include "llvm/Object/COFF.h" #include "llvm/Support/ErrorHandling.h" @@ -111,6 +112,20 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { } } +static std::error_code getSymbol(const COFFObjectFile &COFF, uint64_t VA, + object::SymbolRef &Sym) { + for (const auto &Symbol : COFF.symbols()) { + Expected<uint64_t> Address = Symbol.getAddress(); + if (!Address) + return errorToErrorCode(Address.takeError()); + if (*Address == VA) { + Sym = Symbol; + return readobj_error::success; + } + } + return readobj_error::unknown_symbol; +} + static std::string formatSymbol(const Dumper::Context &Ctx, const coff_section *Section, uint64_t Offset, uint32_t Displacement) { @@ -131,9 +146,22 @@ static std::string formatSymbol(const Dumper::Context &Ctx, // TODO: Actually report errors helpfully. consumeError(Name.takeError()); } + } else if (!getSymbol(Ctx.COFF, Ctx.COFF.getImageBase() + Displacement, + Symbol)) { + Expected<StringRef> Name = Symbol.getName(); + if (Name) { + OS << *Name; + OS << format(" (0x%" PRIX64 ")", Ctx.COFF.getImageBase() + Displacement); + return OS.str(); + } else { + consumeError(Name.takeError()); + } } - OS << format(" (0x%" PRIX64 ")", Offset); + if (Displacement > 0) + OS << format("(0x%" PRIX64 ")", Ctx.COFF.getImageBase() + Displacement); + else + OS << format("(0x%" PRIX64 ")", Offset); return OS.str(); } @@ -159,6 +187,18 @@ static std::error_code resolveRelocation(const Dumper::Context &Ctx, return std::error_code(); } +static const object::coff_section * +getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { + for (const auto &Section : COFF.sections()) { + uint64_t Address = Section.getAddress(); + uint64_t Size = Section.getSize(); + + if (VA >= Address && (VA - Address) <= Size) + return COFF.getCOFFSection(Section); + } + return nullptr; +} + namespace llvm { namespace Win64EH { void Dumper::printRuntimeFunctionEntry(const Context &Ctx, @@ -284,9 +324,18 @@ void Dumper::printRuntimeFunction(const Context &Ctx, DictScope RFS(SW, "RuntimeFunction"); printRuntimeFunctionEntry(Ctx, Section, SectionOffset, RF); - const coff_section *XData; + const coff_section *XData = nullptr; uint64_t Offset; resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset); + Offset = Offset + RF.UnwindInfoOffset; + + if (!XData) { + uint64_t Address = Ctx.COFF.getImageBase() + RF.UnwindInfoOffset; + XData = getSectionContaining(Ctx.COFF, Address); + if (!XData) + return; + Offset = RF.UnwindInfoOffset - XData->VirtualAddress; + } ArrayRef<uint8_t> Contents; if (Error E = Ctx.COFF.getSectionContents(XData, Contents)) @@ -295,7 +344,6 @@ void Dumper::printRuntimeFunction(const Context &Ctx, if (Contents.empty()) return; - Offset = Offset + RF.UnwindInfoOffset; if (Offset > Contents.size()) return; diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp index fe95b6d1b494..1f9403665594 100644 --- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -49,13 +49,6 @@ private: void printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr); void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); void printSymbol(const SymbolRef &); - - // Least significant 3 bits are reserved. - static constexpr unsigned SectionFlagsReservedMask = 0x7; - - // The low order 16 bits of section flags denotes the section type. - static constexpr unsigned SectionFlagsTypeMask = 0xffffu; - void printRelocations(ArrayRef<XCOFFSectionHeader32> Sections); const XCOFFObjectFile &Obj; }; @@ -496,8 +489,7 @@ void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) { DictScope SecDS(W, "Section"); W.printNumber("Index", Index++); - - uint16_t SectionType = Sec.Flags & SectionFlagsTypeMask; + uint16_t SectionType = Sec.getSectionType(); switch (SectionType) { case XCOFF::STYP_OVRFLO: printOverflowSectionHeader(Sec); @@ -513,8 +505,7 @@ void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) { printGenericSectionHeader(Sec); break; } - // For now we just dump the section type portion of the flags. - if (SectionType & SectionFlagsReservedMask) + if (Sec.isReservedSectionType()) W.printHex("Flags", "Reserved", SectionType); else W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames)); diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index 4db13897879d..fadeec1072d6 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -58,6 +58,11 @@ namespace opts { "--section-groups and --elf-hash-histogram.")); cl::alias AllShort("a", cl::desc("Alias for --all"), cl::aliasopt(All)); + // --dependent-libraries + cl::opt<bool> + DependentLibraries("dependent-libraries", + cl::desc("Display the dependent libraries section")); + // --headers -e cl::opt<bool> Headers("headers", @@ -366,7 +371,6 @@ LLVM_ATTRIBUTE_NORETURN static void error(Twine Msg) { // Flush the standard output to print the error at a // proper place. fouts().flush(); - errs() << "\n"; WithColor::error(errs(), ToolName) << Msg << "\n"; exit(1); } @@ -390,7 +394,6 @@ void reportWarning(Error Err, StringRef Input) { fouts().flush(); handleAllErrors( createFileError(Input, std::move(Err)), [&](const ErrorInfoBase &EI) { - errs() << "\n"; WithColor::warning(errs(), ToolName) << EI.message() << "\n"; }); } @@ -489,6 +492,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, if (opts::VersionInfo) Dumper->printVersionInfo(); if (Obj->isELF()) { + if (opts::DependentLibraries) + Dumper->printDependentLibs(); if (opts::ELFLinkerOptions) Dumper->printELFLinkerOptions(); if (opts::ArchSpecificInfo) diff --git a/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp index 3a36e7709483..9b84c46d3901 100644 --- a/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -23,6 +23,7 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Object/SymbolSize.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DynamicLibrary.h" @@ -749,7 +750,9 @@ static int linkAndVerify() { if (!MRI) ErrorAndExit("Unable to create target register info!"); - std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); + MCTargetOptions MCOptions; + std::unique_ptr<MCAsmInfo> MAI( + TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); if (!MAI) ErrorAndExit("Unable to create target asm info!"); diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp index 54ce87d47979..96b2b72d8ba1 100644 --- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -24,6 +24,7 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> #include <cstdio> #include <cstring> #include <string> @@ -150,6 +151,12 @@ static cl::opt<std::string> ClFallbackDebugPath("fallback-debug-path", cl::init(""), cl::desc("Fallback path for debug binaries.")); +static cl::list<std::string> + ClDebugFileDirectory("debug-file-directory", cl::ZeroOrMore, + cl::value_desc("dir"), + cl::desc("Path to directory where to look for debug " + "files.")); + static cl::opt<DIPrinter::OutputStyle> ClOutputStyle("output-style", cl::init(DIPrinter::OutputStyle::LLVM), cl::desc("Specify print style"), @@ -222,7 +229,7 @@ static void symbolizeInput(StringRef InputString, LLVMSymbolizer &Symbolizer, std::string ModuleName; uint64_t Offset = 0; if (!parseCommand(StringRef(InputString), Cmd, ModuleName, Offset)) { - outs() << InputString; + outs() << InputString << "\n"; return; } @@ -283,8 +290,10 @@ int main(int argc, char **argv) { } llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); - cl::ParseCommandLineOptions(argc, argv, IsAddr2Line ? "llvm-addr2line\n" - : "llvm-symbolizer\n"); + cl::ParseCommandLineOptions( + argc, argv, IsAddr2Line ? "llvm-addr2line\n" : "llvm-symbolizer\n", + /*Errs=*/nullptr, + IsAddr2Line ? "LLVM_ADDR2LINE_OPTS" : "LLVM_SYMBOLIZER_OPTS"); // If both --demangle and --no-demangle are specified then pick the last one. if (ClNoDemangle.getPosition() > ClDemangle.getPosition()) @@ -299,6 +308,7 @@ int main(int argc, char **argv) { Opts.DefaultArch = ClDefaultArch; Opts.FallbackDebugPath = ClFallbackDebugPath; Opts.DWPName = ClDwpName; + Opts.DebugFileDirectory = ClDebugFileDirectory; for (const auto &hint : ClDsymHint) { if (sys::path::extension(hint) == ".dSYM") { @@ -319,7 +329,13 @@ int main(int argc, char **argv) { char InputString[kMaxInputStringLength]; while (fgets(InputString, sizeof(InputString), stdin)) { - symbolizeInput(InputString, Symbolizer, Printer); + // Strip newline characters. + std::string StrippedInputString(InputString); + StrippedInputString.erase( + std::remove_if(StrippedInputString.begin(), StrippedInputString.end(), + [](char c) { return c == '\r' || c == '\n'; }), + StrippedInputString.end()); + symbolizeInput(StrippedInputString, Symbolizer, Printer); outs().flush(); } } else { diff --git a/llvm/tools/llvm-xray/xray-account.cpp b/llvm/tools/llvm-xray/xray-account.cpp index e37cd212377a..fcac33b23d4d 100644 --- a/llvm/tools/llvm-xray/xray-account.cpp +++ b/llvm/tools/llvm-xray/xray-account.cpp @@ -34,23 +34,20 @@ static cl::opt<bool> AccountKeepGoing("keep-going", cl::desc("Keep going on errors encountered"), cl::sub(Account), cl::init(false)); static cl::alias AccountKeepGoing2("k", cl::aliasopt(AccountKeepGoing), - cl::desc("Alias for -keep_going"), - cl::sub(Account)); + cl::desc("Alias for -keep_going")); static cl::opt<bool> AccountDeduceSiblingCalls( "deduce-sibling-calls", cl::desc("Deduce sibling calls when unrolling function call stacks"), cl::sub(Account), cl::init(false)); static cl::alias AccountDeduceSiblingCalls2("d", cl::aliasopt(AccountDeduceSiblingCalls), - cl::desc("Alias for -deduce_sibling_calls"), - cl::sub(Account)); + cl::desc("Alias for -deduce_sibling_calls")); static cl::opt<std::string> AccountOutput("output", cl::value_desc("output file"), cl::init("-"), cl::desc("output file; use '-' for stdout"), cl::sub(Account)); static cl::alias AccountOutput2("o", cl::aliasopt(AccountOutput), - cl::desc("Alias for -output"), - cl::sub(Account)); + cl::desc("Alias for -output")); enum class AccountOutputFormats { TEXT, CSV }; static cl::opt<AccountOutputFormats> AccountOutputFormat("format", cl::desc("output format"), @@ -60,8 +57,7 @@ static cl::opt<AccountOutputFormats> "report stats in csv")), cl::sub(Account)); static cl::alias AccountOutputFormat2("f", cl::desc("Alias of -format"), - cl::aliasopt(AccountOutputFormat), - cl::sub(Account)); + cl::aliasopt(AccountOutputFormat)); enum class SortField { FUNCID, @@ -88,8 +84,7 @@ static cl::opt<SortField> AccountSortOutput( clEnumValN(SortField::SUM, "sum", "sum of call durations"), clEnumValN(SortField::FUNC, "func", "function names"))); static cl::alias AccountSortOutput2("s", cl::aliasopt(AccountSortOutput), - cl::desc("Alias for -sort"), - cl::sub(Account)); + cl::desc("Alias for -sort")); enum class SortDirection { ASCENDING, @@ -101,14 +96,13 @@ static cl::opt<SortDirection> AccountSortOrder( clEnumValN(SortDirection::DESCENDING, "dsc", "descending")), cl::sub(Account)); static cl::alias AccountSortOrder2("r", cl::aliasopt(AccountSortOrder), - cl::desc("Alias for -sortorder"), - cl::sub(Account)); + cl::desc("Alias for -sortorder")); static cl::opt<int> AccountTop("top", cl::desc("only show the top N results"), cl::value_desc("N"), cl::sub(Account), cl::init(-1)); static cl::alias AccountTop2("p", cl::desc("Alias for -top"), - cl::aliasopt(AccountTop), cl::sub(Account)); + cl::aliasopt(AccountTop)); static cl::opt<std::string> AccountInstrMap("instr_map", @@ -117,8 +111,7 @@ static cl::opt<std::string> cl::value_desc("binary with xray_instr_map"), cl::sub(Account), cl::init("")); static cl::alias AccountInstrMap2("m", cl::aliasopt(AccountInstrMap), - cl::desc("Alias for -instr_map"), - cl::sub(Account)); + cl::desc("Alias for -instr_map")); namespace { diff --git a/llvm/tools/llvm-xray/xray-converter.cpp b/llvm/tools/llvm-xray/xray-converter.cpp index 7258245b95cc..c1a623f0f858 100644 --- a/llvm/tools/llvm-xray/xray-converter.cpp +++ b/llvm/tools/llvm-xray/xray-converter.cpp @@ -43,23 +43,20 @@ static cl::opt<ConvertFormats> ConvertOutputFormat( "May be visualized with the Catapult trace viewer.")), cl::sub(Convert)); static cl::alias ConvertOutputFormat2("f", cl::aliasopt(ConvertOutputFormat), - cl::desc("Alias for -output-format"), - cl::sub(Convert)); + cl::desc("Alias for -output-format")); static cl::opt<std::string> ConvertOutput("output", cl::value_desc("output file"), cl::init("-"), cl::desc("output file; use '-' for stdout"), cl::sub(Convert)); static cl::alias ConvertOutput2("o", cl::aliasopt(ConvertOutput), - cl::desc("Alias for -output"), - cl::sub(Convert)); + cl::desc("Alias for -output")); static cl::opt<bool> ConvertSymbolize("symbolize", cl::desc("symbolize function ids from the input log"), cl::init(false), cl::sub(Convert)); static cl::alias ConvertSymbolize2("y", cl::aliasopt(ConvertSymbolize), - cl::desc("Alias for -symbolize"), - cl::sub(Convert)); + cl::desc("Alias for -symbolize")); static cl::opt<std::string> ConvertInstrMap("instr_map", @@ -68,15 +65,13 @@ static cl::opt<std::string> cl::value_desc("binary with xray_instr_map"), cl::sub(Convert), cl::init("")); static cl::alias ConvertInstrMap2("m", cl::aliasopt(ConvertInstrMap), - cl::desc("Alias for -instr_map"), - cl::sub(Convert)); + cl::desc("Alias for -instr_map")); static cl::opt<bool> ConvertSortInput( "sort", cl::desc("determines whether to sort input log records by timestamp"), cl::sub(Convert), cl::init(true)); static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput), - cl::desc("Alias for -sort"), - cl::sub(Convert)); + cl::desc("Alias for -sort")); using llvm::yaml::Output; diff --git a/llvm/tools/llvm-xray/xray-extract.cpp b/llvm/tools/llvm-xray/xray-extract.cpp index 7800b88d9eeb..af9255af21c3 100644 --- a/llvm/tools/llvm-xray/xray-extract.cpp +++ b/llvm/tools/llvm-xray/xray-extract.cpp @@ -38,15 +38,13 @@ static cl::opt<std::string> cl::desc("output file; use '-' for stdout"), cl::sub(Extract)); static cl::alias ExtractOutput2("o", cl::aliasopt(ExtractOutput), - cl::desc("Alias for -output"), - cl::sub(Extract)); + cl::desc("Alias for -output")); static cl::opt<bool> ExtractSymbolize("symbolize", cl::value_desc("symbolize"), cl::init(false), cl::desc("symbolize functions"), cl::sub(Extract)); static cl::alias ExtractSymbolize2("s", cl::aliasopt(ExtractSymbolize), - cl::desc("alias for -symbolize"), - cl::sub(Extract)); + cl::desc("alias for -symbolize")); namespace { diff --git a/llvm/tools/llvm-xray/xray-graph-diff.cpp b/llvm/tools/llvm-xray/xray-graph-diff.cpp index 116aa6869ec1..a1bca326930e 100644 --- a/llvm/tools/llvm-xray/xray-graph-diff.cpp +++ b/llvm/tools/llvm-xray/xray-graph-diff.cpp @@ -41,22 +41,19 @@ static cl::opt<bool> cl::desc("Keep going on errors encountered"), cl::sub(GraphDiff), cl::init(false)); static cl::alias GraphDiffKeepGoingA("k", cl::aliasopt(GraphDiffKeepGoing), - cl::desc("Alias for -keep-going"), - cl::sub(GraphDiff)); + cl::desc("Alias for -keep-going")); static cl::opt<bool> GraphDiffKeepGoing1("keep-going-1", cl::desc("Keep going on errors encountered in trace 1"), cl::sub(GraphDiff), cl::init(false)); static cl::alias GraphDiffKeepGoing1A("k1", cl::aliasopt(GraphDiffKeepGoing1), - cl::desc("Alias for -keep-going-1"), - cl::sub(GraphDiff)); + cl::desc("Alias for -keep-going-1")); static cl::opt<bool> GraphDiffKeepGoing2("keep-going-2", cl::desc("Keep going on errors encountered in trace 2"), cl::sub(GraphDiff), cl::init(false)); static cl::alias GraphDiffKeepGoing2A("k2", cl::aliasopt(GraphDiffKeepGoing2), - cl::desc("Alias for -keep-going-2"), - cl::sub(GraphDiff)); + cl::desc("Alias for -keep-going-2")); static cl::opt<std::string> GraphDiffInstrMap("instr-map", @@ -65,8 +62,7 @@ static cl::opt<std::string> cl::value_desc("binary with xray_instr_map or yaml"), cl::sub(GraphDiff), cl::init("")); static cl::alias GraphDiffInstrMapA("m", cl::aliasopt(GraphDiffInstrMap), - cl::desc("Alias for -instr-map"), - cl::sub(GraphDiff)); + cl::desc("Alias for -instr-map")); static cl::opt<std::string> GraphDiffInstrMap1("instr-map-1", cl::desc("binary with the instrumentation map, or " @@ -74,8 +70,7 @@ static cl::opt<std::string> cl::value_desc("binary with xray_instr_map or yaml"), cl::sub(GraphDiff), cl::init("")); static cl::alias GraphDiffInstrMap1A("m1", cl::aliasopt(GraphDiffInstrMap1), - cl::desc("Alias for -instr-map-1"), - cl::sub(GraphDiff)); + cl::desc("Alias for -instr-map-1")); static cl::opt<std::string> GraphDiffInstrMap2("instr-map-2", cl::desc("binary with the instrumentation map, or " @@ -83,8 +78,7 @@ static cl::opt<std::string> cl::value_desc("binary with xray_instr_map or yaml"), cl::sub(GraphDiff), cl::init("")); static cl::alias GraphDiffInstrMap2A("m2", cl::aliasopt(GraphDiffInstrMap2), - cl::desc("Alias for -instr-map-2"), - cl::sub(GraphDiff)); + cl::desc("Alias for -instr-map-2")); static cl::opt<bool> GraphDiffDeduceSiblingCalls( "deduce-sibling-calls", @@ -92,22 +86,21 @@ static cl::opt<bool> GraphDiffDeduceSiblingCalls( cl::sub(GraphDiff), cl::init(false)); static cl::alias GraphDiffDeduceSiblingCallsA("d", cl::aliasopt(GraphDiffDeduceSiblingCalls), - cl::desc("Alias for -deduce-sibling-calls"), - cl::sub(GraphDiff)); + cl::desc("Alias for -deduce-sibling-calls")); static cl::opt<bool> GraphDiffDeduceSiblingCalls1( "deduce-sibling-calls-1", cl::desc("Deduce sibling calls when unrolling function call stacks"), cl::sub(GraphDiff), cl::init(false)); static cl::alias GraphDiffDeduceSiblingCalls1A( "d1", cl::aliasopt(GraphDiffDeduceSiblingCalls1), - cl::desc("Alias for -deduce-sibling-calls-1"), cl::sub(GraphDiff)); + cl::desc("Alias for -deduce-sibling-calls-1")); static cl::opt<bool> GraphDiffDeduceSiblingCalls2( "deduce-sibling-calls-2", cl::desc("Deduce sibling calls when unrolling function call stacks"), cl::sub(GraphDiff), cl::init(false)); static cl::alias GraphDiffDeduceSiblingCalls2A( "d2", cl::aliasopt(GraphDiffDeduceSiblingCalls2), - cl::desc("Alias for -deduce-sibling-calls-2"), cl::sub(GraphDiff)); + cl::desc("Alias for -deduce-sibling-calls-2")); static cl::opt<GraphRenderer::StatType> GraphDiffEdgeLabel( "edge-label", cl::desc("Output graphs with edges labeled with this field"), @@ -130,8 +123,7 @@ static cl::opt<GraphRenderer::StatType> GraphDiffEdgeLabel( clEnumValN(GraphRenderer::StatType::SUM, "sum", "sum of call durations"))); static cl::alias GraphDiffEdgeLabelA("e", cl::aliasopt(GraphDiffEdgeLabel), - cl::desc("Alias for -edge-label"), - cl::sub(GraphDiff)); + cl::desc("Alias for -edge-label")); static cl::opt<GraphRenderer::StatType> GraphDiffEdgeColor( "edge-color", cl::desc("Output graphs with edges colored by this field"), @@ -154,8 +146,7 @@ static cl::opt<GraphRenderer::StatType> GraphDiffEdgeColor( clEnumValN(GraphRenderer::StatType::SUM, "sum", "sum of call durations"))); static cl::alias GraphDiffEdgeColorA("c", cl::aliasopt(GraphDiffEdgeColor), - cl::desc("Alias for -edge-color"), - cl::sub(GraphDiff)); + cl::desc("Alias for -edge-color")); static cl::opt<GraphRenderer::StatType> GraphDiffVertexLabel( "vertex-label", @@ -179,8 +170,7 @@ static cl::opt<GraphRenderer::StatType> GraphDiffVertexLabel( clEnumValN(GraphRenderer::StatType::SUM, "sum", "sum of call durations"))); static cl::alias GraphDiffVertexLabelA("v", cl::aliasopt(GraphDiffVertexLabel), - cl::desc("Alias for -vertex-label"), - cl::sub(GraphDiff)); + cl::desc("Alias for -vertex-label")); static cl::opt<GraphRenderer::StatType> GraphDiffVertexColor( "vertex-color", @@ -204,24 +194,21 @@ static cl::opt<GraphRenderer::StatType> GraphDiffVertexColor( clEnumValN(GraphRenderer::StatType::SUM, "sum", "sum of call durations"))); static cl::alias GraphDiffVertexColorA("b", cl::aliasopt(GraphDiffVertexColor), - cl::desc("Alias for -vertex-color"), - cl::sub(GraphDiff)); + cl::desc("Alias for -vertex-color")); static cl::opt<int> GraphDiffVertexLabelTrunc( "vertex-label-trun", cl::desc("What length to truncate vertex labels to "), cl::sub(GraphDiff), cl::init(40)); static cl::alias GraphDiffVertexLabelTrunc1("t", cl::aliasopt(GraphDiffVertexLabelTrunc), - cl::desc("Alias for -vertex-label-trun"), - cl::sub(GraphDiff)); + cl::desc("Alias for -vertex-label-trun")); static cl::opt<std::string> GraphDiffOutput("output", cl::value_desc("Output file"), cl::init("-"), cl::desc("output file; use '-' for stdout"), cl::sub(GraphDiff)); static cl::alias GraphDiffOutputA("o", cl::aliasopt(GraphDiffOutput), - cl::desc("Alias for -output"), - cl::sub(GraphDiff)); + cl::desc("Alias for -output")); Expected<GraphDiffRenderer> GraphDiffRenderer::Factory::getGraphDiffRenderer() { GraphDiffRenderer R; diff --git a/llvm/tools/llvm-xray/xray-graph.cpp b/llvm/tools/llvm-xray/xray-graph.cpp index 0be511219c1a..f836f9ba54fc 100644 --- a/llvm/tools/llvm-xray/xray-graph.cpp +++ b/llvm/tools/llvm-xray/xray-graph.cpp @@ -30,14 +30,13 @@ static cl::opt<bool> GraphKeepGoing("keep-going", cl::desc("Keep going on errors encountered"), cl::sub(GraphC), cl::init(false)); static cl::alias GraphKeepGoing2("k", cl::aliasopt(GraphKeepGoing), - cl::desc("Alias for -keep-going"), - cl::sub(GraphC)); + cl::desc("Alias for -keep-going")); static cl::opt<std::string> GraphOutput("output", cl::value_desc("Output file"), cl::init("-"), cl::desc("output file; use '-' for stdout"), cl::sub(GraphC)); static cl::alias GraphOutput2("o", cl::aliasopt(GraphOutput), - cl::desc("Alias for -output"), cl::sub(GraphC)); + cl::desc("Alias for -output")); static cl::opt<std::string> GraphInstrMap("instr_map", @@ -46,8 +45,7 @@ static cl::opt<std::string> cl::value_desc("binary with xray_instr_map"), cl::sub(GraphC), cl::init("")); static cl::alias GraphInstrMap2("m", cl::aliasopt(GraphInstrMap), - cl::desc("alias for -instr_map"), - cl::sub(GraphC)); + cl::desc("alias for -instr_map")); static cl::opt<bool> GraphDeduceSiblingCalls( "deduce-sibling-calls", @@ -55,8 +53,7 @@ static cl::opt<bool> GraphDeduceSiblingCalls( cl::sub(GraphC), cl::init(false)); static cl::alias GraphDeduceSiblingCalls2("d", cl::aliasopt(GraphDeduceSiblingCalls), - cl::desc("Alias for -deduce-sibling-calls"), - cl::sub(GraphC)); + cl::desc("Alias for -deduce-sibling-calls")); static cl::opt<GraphRenderer::StatType> GraphEdgeLabel("edge-label", @@ -80,8 +77,7 @@ static cl::opt<GraphRenderer::StatType> clEnumValN(GraphRenderer::StatType::SUM, "sum", "sum of call durations"))); static cl::alias GraphEdgeLabel2("e", cl::aliasopt(GraphEdgeLabel), - cl::desc("Alias for -edge-label"), - cl::sub(GraphC)); + cl::desc("Alias for -edge-label")); static cl::opt<GraphRenderer::StatType> GraphVertexLabel( "vertex-label", @@ -105,8 +101,7 @@ static cl::opt<GraphRenderer::StatType> GraphVertexLabel( clEnumValN(GraphRenderer::StatType::SUM, "sum", "sum of call durations"))); static cl::alias GraphVertexLabel2("v", cl::aliasopt(GraphVertexLabel), - cl::desc("Alias for -edge-label"), - cl::sub(GraphC)); + cl::desc("Alias for -edge-label")); static cl::opt<GraphRenderer::StatType> GraphEdgeColorType( "color-edges", @@ -130,8 +125,7 @@ static cl::opt<GraphRenderer::StatType> GraphEdgeColorType( clEnumValN(GraphRenderer::StatType::SUM, "sum", "sum of call durations"))); static cl::alias GraphEdgeColorType2("c", cl::aliasopt(GraphEdgeColorType), - cl::desc("Alias for -color-edges"), - cl::sub(GraphC)); + cl::desc("Alias for -color-edges")); static cl::opt<GraphRenderer::StatType> GraphVertexColorType( "color-vertices", @@ -155,8 +149,7 @@ static cl::opt<GraphRenderer::StatType> GraphVertexColorType( clEnumValN(GraphRenderer::StatType::SUM, "sum", "sum of call durations"))); static cl::alias GraphVertexColorType2("b", cl::aliasopt(GraphVertexColorType), - cl::desc("Alias for -edge-label"), - cl::sub(GraphC)); + cl::desc("Alias for -edge-label")); template <class T> T diff(T L, T R) { return std::max(L, R) - std::min(L, R); } diff --git a/llvm/tools/llvm-xray/xray-stacks.cpp b/llvm/tools/llvm-xray/xray-stacks.cpp index bcfc5cb1f1be..cf292887b6b8 100644 --- a/llvm/tools/llvm-xray/xray-stacks.cpp +++ b/llvm/tools/llvm-xray/xray-stacks.cpp @@ -42,8 +42,7 @@ static cl::opt<bool> StackKeepGoing("keep-going", cl::desc("Keep going on errors encountered"), cl::sub(Stack), cl::init(false)); static cl::alias StackKeepGoing2("k", cl::aliasopt(StackKeepGoing), - cl::desc("Alias for -keep-going"), - cl::sub(Stack)); + cl::desc("Alias for -keep-going")); // TODO: Does there need to be an option to deduce tail or sibling calls? @@ -53,8 +52,7 @@ static cl::opt<std::string> StacksInstrMap( "Currently supports elf file instrumentation maps."), cl::sub(Stack), cl::init("")); static cl::alias StacksInstrMap2("m", cl::aliasopt(StacksInstrMap), - cl::desc("Alias for -instr_map"), - cl::sub(Stack)); + cl::desc("Alias for -instr_map")); static cl::opt<bool> SeparateThreadStacks("per-thread-stacks", @@ -72,8 +70,7 @@ static cl::opt<bool> "By default separates stacks per-thread."), cl::sub(Stack), cl::init(false)); static cl::alias DumpAllStacksShort("all", cl::aliasopt(DumpAllStacks), - cl::desc("Alias for -all-stacks"), - cl::sub(Stack)); + cl::desc("Alias for -all-stacks")); // TODO(kpw): Add other interesting formats. Perhaps chrome trace viewer format // possibly with aggregations or just a linear trace of timings. diff --git a/llvm/tools/opt/Debugify.cpp b/llvm/tools/opt/Debugify.cpp deleted file mode 100644 index 222cc702bc1f..000000000000 --- a/llvm/tools/opt/Debugify.cpp +++ /dev/null @@ -1,463 +0,0 @@ -//===- Debugify.cpp - Attach synthetic debug info to everything -----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file This pass attaches synthetic debug info to everything. It can be used -/// to create targeted tests for debug info preservation. -/// -//===----------------------------------------------------------------------===// - -#include "Debugify.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DIBuilder.h" -#include "llvm/IR/DebugInfo.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/Pass.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/IPO.h" - -using namespace llvm; - -namespace { - -cl::opt<bool> Quiet("debugify-quiet", - cl::desc("Suppress verbose debugify output")); - -raw_ostream &dbg() { return Quiet ? nulls() : errs(); } - -uint64_t getAllocSizeInBits(Module &M, Type *Ty) { - return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0; -} - -bool isFunctionSkipped(Function &F) { - return F.isDeclaration() || !F.hasExactDefinition(); -} - -/// Find the basic block's terminating instruction. -/// -/// Special care is needed to handle musttail and deopt calls, as these behave -/// like (but are in fact not) terminators. -Instruction *findTerminatingInstruction(BasicBlock &BB) { - if (auto *I = BB.getTerminatingMustTailCall()) - return I; - if (auto *I = BB.getTerminatingDeoptimizeCall()) - return I; - return BB.getTerminator(); -} - -bool applyDebugifyMetadata(Module &M, - iterator_range<Module::iterator> Functions, - StringRef Banner) { - // Skip modules with debug info. - if (M.getNamedMetadata("llvm.dbg.cu")) { - dbg() << Banner << "Skipping module with debug info\n"; - return false; - } - - DIBuilder DIB(M); - LLVMContext &Ctx = M.getContext(); - - // Get a DIType which corresponds to Ty. - DenseMap<uint64_t, DIType *> TypeCache; - auto getCachedDIType = [&](Type *Ty) -> DIType * { - uint64_t Size = getAllocSizeInBits(M, Ty); - DIType *&DTy = TypeCache[Size]; - if (!DTy) { - std::string Name = "ty" + utostr(Size); - DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned); - } - return DTy; - }; - - unsigned NextLine = 1; - unsigned NextVar = 1; - auto File = DIB.createFile(M.getName(), "/"); - auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "debugify", - /*isOptimized=*/true, "", 0); - - // Visit each instruction. - for (Function &F : Functions) { - if (isFunctionSkipped(F)) - continue; - - auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); - DISubprogram::DISPFlags SPFlags = - DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized; - if (F.hasPrivateLinkage() || F.hasInternalLinkage()) - SPFlags |= DISubprogram::SPFlagLocalToUnit; - auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine, - SPType, NextLine, DINode::FlagZero, SPFlags); - F.setSubprogram(SP); - for (BasicBlock &BB : F) { - // Attach debug locations. - for (Instruction &I : BB) - I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); - - // Inserting debug values into EH pads can break IR invariants. - if (BB.isEHPad()) - continue; - - // Find the terminating instruction, after which no debug values are - // attached. - Instruction *LastInst = findTerminatingInstruction(BB); - assert(LastInst && "Expected basic block with a terminator"); - - // Maintain an insertion point which can't be invalidated when updates - // are made. - BasicBlock::iterator InsertPt = BB.getFirstInsertionPt(); - assert(InsertPt != BB.end() && "Expected to find an insertion point"); - Instruction *InsertBefore = &*InsertPt; - - // Attach debug values. - for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) { - // Skip void-valued instructions. - if (I->getType()->isVoidTy()) - continue; - - // Phis and EH pads must be grouped at the beginning of the block. - // Only advance the insertion point when we finish visiting these. - if (!isa<PHINode>(I) && !I->isEHPad()) - InsertBefore = I->getNextNode(); - - std::string Name = utostr(NextVar++); - const DILocation *Loc = I->getDebugLoc().get(); - auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(), - getCachedDIType(I->getType()), - /*AlwaysPreserve=*/true); - DIB.insertDbgValueIntrinsic(I, LocalVar, DIB.createExpression(), Loc, - InsertBefore); - } - } - DIB.finalizeSubprogram(SP); - } - DIB.finalize(); - - // Track the number of distinct lines and variables. - NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify"); - auto *IntTy = Type::getInt32Ty(Ctx); - auto addDebugifyOperand = [&](unsigned N) { - NMD->addOperand(MDNode::get( - Ctx, ValueAsMetadata::getConstant(ConstantInt::get(IntTy, N)))); - }; - addDebugifyOperand(NextLine - 1); // Original number of lines. - addDebugifyOperand(NextVar - 1); // Original number of variables. - assert(NMD->getNumOperands() == 2 && - "llvm.debugify should have exactly 2 operands!"); - - // Claim that this synthetic debug info is valid. - StringRef DIVersionKey = "Debug Info Version"; - if (!M.getModuleFlag(DIVersionKey)) - M.addModuleFlag(Module::Warning, DIVersionKey, DEBUG_METADATA_VERSION); - - return true; -} - -/// Return true if a mis-sized diagnostic is issued for \p DVI. -bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { - // The size of a dbg.value's value operand should match the size of the - // variable it corresponds to. - // - // TODO: This, along with a check for non-null value operands, should be - // promoted to verifier failures. - Value *V = DVI->getValue(); - if (!V) - return false; - - // For now, don't try to interpret anything more complicated than an empty - // DIExpression. Eventually we should try to handle OP_deref and fragments. - if (DVI->getExpression()->getNumElements()) - return false; - - Type *Ty = V->getType(); - uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty); - Optional<uint64_t> DbgVarSize = DVI->getFragmentSizeInBits(); - if (!ValueOperandSize || !DbgVarSize) - return false; - - bool HasBadSize = false; - if (Ty->isIntegerTy()) { - auto Signedness = DVI->getVariable()->getSignedness(); - if (Signedness && *Signedness == DIBasicType::Signedness::Signed) - HasBadSize = ValueOperandSize < *DbgVarSize; - } else { - HasBadSize = ValueOperandSize != *DbgVarSize; - } - - if (HasBadSize) { - dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize - << ", but its variable has size " << *DbgVarSize << ": "; - DVI->print(dbg()); - dbg() << "\n"; - } - return HasBadSize; -} - -bool checkDebugifyMetadata(Module &M, - iterator_range<Module::iterator> Functions, - StringRef NameOfWrappedPass, StringRef Banner, - bool Strip, DebugifyStatsMap *StatsMap) { - // Skip modules without debugify metadata. - NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify"); - if (!NMD) { - dbg() << Banner << "Skipping module without debugify metadata\n"; - return false; - } - - auto getDebugifyOperand = [&](unsigned Idx) -> unsigned { - return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0)) - ->getZExtValue(); - }; - assert(NMD->getNumOperands() == 2 && - "llvm.debugify should have exactly 2 operands!"); - unsigned OriginalNumLines = getDebugifyOperand(0); - unsigned OriginalNumVars = getDebugifyOperand(1); - bool HasErrors = false; - - // Track debug info loss statistics if able. - DebugifyStatistics *Stats = nullptr; - if (StatsMap && !NameOfWrappedPass.empty()) - Stats = &StatsMap->operator[](NameOfWrappedPass); - - BitVector MissingLines{OriginalNumLines, true}; - BitVector MissingVars{OriginalNumVars, true}; - for (Function &F : Functions) { - if (isFunctionSkipped(F)) - continue; - - // Find missing lines. - for (Instruction &I : instructions(F)) { - if (isa<DbgValueInst>(&I)) - continue; - - auto DL = I.getDebugLoc(); - if (DL && DL.getLine() != 0) { - MissingLines.reset(DL.getLine() - 1); - continue; - } - - if (!DL) { - dbg() << "ERROR: Instruction with empty DebugLoc in function "; - dbg() << F.getName() << " --"; - I.print(dbg()); - dbg() << "\n"; - HasErrors = true; - } - } - - // Find missing variables and mis-sized debug values. - for (Instruction &I : instructions(F)) { - auto *DVI = dyn_cast<DbgValueInst>(&I); - if (!DVI) - continue; - - unsigned Var = ~0U; - (void)to_integer(DVI->getVariable()->getName(), Var, 10); - assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable"); - bool HasBadSize = diagnoseMisSizedDbgValue(M, DVI); - if (!HasBadSize) - MissingVars.reset(Var - 1); - HasErrors |= HasBadSize; - } - } - - // Print the results. - for (unsigned Idx : MissingLines.set_bits()) - dbg() << "WARNING: Missing line " << Idx + 1 << "\n"; - - for (unsigned Idx : MissingVars.set_bits()) - dbg() << "WARNING: Missing variable " << Idx + 1 << "\n"; - - // Update DI loss statistics. - if (Stats) { - Stats->NumDbgLocsExpected += OriginalNumLines; - Stats->NumDbgLocsMissing += MissingLines.count(); - Stats->NumDbgValuesExpected += OriginalNumVars; - Stats->NumDbgValuesMissing += MissingVars.count(); - } - - dbg() << Banner; - if (!NameOfWrappedPass.empty()) - dbg() << " [" << NameOfWrappedPass << "]"; - dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n'; - - // Strip the Debugify Metadata if required. - if (Strip) { - StripDebugInfo(M); - M.eraseNamedMetadata(NMD); - return true; - } - - return false; -} - -/// ModulePass for attaching synthetic debug info to everything, used with the -/// legacy module pass manager. -struct DebugifyModulePass : public ModulePass { - bool runOnModule(Module &M) override { - return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); - } - - DebugifyModulePass() : ModulePass(ID) {} - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } - - static char ID; // Pass identification. -}; - -/// FunctionPass for attaching synthetic debug info to instructions within a -/// single function, used with the legacy module pass manager. -struct DebugifyFunctionPass : public FunctionPass { - bool runOnFunction(Function &F) override { - Module &M = *F.getParent(); - auto FuncIt = F.getIterator(); - return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), - "FunctionDebugify: "); - } - - DebugifyFunctionPass() : FunctionPass(ID) {} - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } - - static char ID; // Pass identification. -}; - -/// ModulePass for checking debug info inserted by -debugify, used with the -/// legacy module pass manager. -struct CheckDebugifyModulePass : public ModulePass { - bool runOnModule(Module &M) override { - return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass, - "CheckModuleDebugify", Strip, StatsMap); - } - - CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr) - : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), - StatsMap(StatsMap) {} - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } - - static char ID; // Pass identification. - -private: - bool Strip; - StringRef NameOfWrappedPass; - DebugifyStatsMap *StatsMap; -}; - -/// FunctionPass for checking debug info inserted by -debugify-function, used -/// with the legacy module pass manager. -struct CheckDebugifyFunctionPass : public FunctionPass { - bool runOnFunction(Function &F) override { - Module &M = *F.getParent(); - auto FuncIt = F.getIterator(); - return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), - NameOfWrappedPass, "CheckFunctionDebugify", - Strip, StatsMap); - } - - CheckDebugifyFunctionPass(bool Strip = false, - StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr) - : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), - StatsMap(StatsMap) {} - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } - - static char ID; // Pass identification. - -private: - bool Strip; - StringRef NameOfWrappedPass; - DebugifyStatsMap *StatsMap; -}; - -} // end anonymous namespace - -void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map) { - std::error_code EC; - raw_fd_ostream OS{Path, EC}; - if (EC) { - errs() << "Could not open file: " << EC.message() << ", " << Path << '\n'; - return; - } - - OS << "Pass Name" << ',' << "# of missing debug values" << ',' - << "# of missing locations" << ',' << "Missing/Expected value ratio" << ',' - << "Missing/Expected location ratio" << '\n'; - for (const auto &Entry : Map) { - StringRef Pass = Entry.first; - DebugifyStatistics Stats = Entry.second; - - OS << Pass << ',' << Stats.NumDbgValuesMissing << ',' - << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ',' - << Stats.getEmptyLocationRatio() << '\n'; - } -} - -ModulePass *createDebugifyModulePass() { return new DebugifyModulePass(); } - -FunctionPass *createDebugifyFunctionPass() { - return new DebugifyFunctionPass(); -} - -PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { - applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); - return PreservedAnalyses::all(); -} - -ModulePass *createCheckDebugifyModulePass(bool Strip, - StringRef NameOfWrappedPass, - DebugifyStatsMap *StatsMap) { - return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap); -} - -FunctionPass *createCheckDebugifyFunctionPass(bool Strip, - StringRef NameOfWrappedPass, - DebugifyStatsMap *StatsMap) { - return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap); -} - -PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M, - ModuleAnalysisManager &) { - checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false, - nullptr); - return PreservedAnalyses::all(); -} - -char DebugifyModulePass::ID = 0; -static RegisterPass<DebugifyModulePass> DM("debugify", - "Attach debug info to everything"); - -char CheckDebugifyModulePass::ID = 0; -static RegisterPass<CheckDebugifyModulePass> - CDM("check-debugify", "Check debug info from -debugify"); - -char DebugifyFunctionPass::ID = 0; -static RegisterPass<DebugifyFunctionPass> DF("debugify-function", - "Attach debug info to a function"); - -char CheckDebugifyFunctionPass::ID = 0; -static RegisterPass<CheckDebugifyFunctionPass> - CDF("check-debugify-function", "Check debug info from -debugify-function"); diff --git a/llvm/tools/opt/Debugify.h b/llvm/tools/opt/Debugify.h deleted file mode 100644 index 266f577951ae..000000000000 --- a/llvm/tools/opt/Debugify.h +++ /dev/null @@ -1,74 +0,0 @@ -//===- Debugify.h - Attach synthetic debug info to everything -------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file Interface to the `debugify` synthetic debug info testing utility. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_OPT_DEBUGIFY_H -#define LLVM_TOOLS_OPT_DEBUGIFY_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/IR/PassManager.h" -#include "llvm/Support/raw_ostream.h" - -llvm::ModulePass *createDebugifyModulePass(); -llvm::FunctionPass *createDebugifyFunctionPass(); - -struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> { - llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); -}; - -/// Track how much `debugify` information has been lost. -struct DebugifyStatistics { - /// Number of missing dbg.values. - unsigned NumDbgValuesMissing = 0; - - /// Number of dbg.values expected. - unsigned NumDbgValuesExpected = 0; - - /// Number of instructions with empty debug locations. - unsigned NumDbgLocsMissing = 0; - - /// Number of instructions expected to have debug locations. - unsigned NumDbgLocsExpected = 0; - - /// Get the ratio of missing/expected dbg.values. - float getMissingValueRatio() const { - return float(NumDbgValuesMissing) / float(NumDbgLocsExpected); - } - - /// Get the ratio of missing/expected instructions with locations. - float getEmptyLocationRatio() const { - return float(NumDbgLocsMissing) / float(NumDbgLocsExpected); - } -}; - -/// Map pass names to a per-pass DebugifyStatistics instance. -using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>; - -/// Export per-pass debugify statistics to the file specified by \p Path. -void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map); - -llvm::ModulePass * -createCheckDebugifyModulePass(bool Strip = false, - llvm::StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr); - -llvm::FunctionPass * -createCheckDebugifyFunctionPass(bool Strip = false, - llvm::StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr); - -struct NewPMCheckDebugifyPass - : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> { - llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); -}; - -#endif // LLVM_TOOLS_OPT_DEBUGIFY_H diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp index efe0bec35d72..ac04a32d93fd 100644 --- a/llvm/tools/opt/NewPMDriver.cpp +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "NewPMDriver.h" -#include "Debugify.h" #include "PassPrinters.h" #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/AliasAnalysis.h" @@ -35,6 +34,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" +#include "llvm/Transforms/Utils/Debugify.h" using namespace llvm; using namespace opt_tool; @@ -202,11 +202,9 @@ static void registerEPCallbacks(PassBuilder &PB, bool VerifyEachPass, }); } -#ifdef LINK_POLLY_INTO_TOOLS -namespace polly { -void RegisterPollyPasses(PassBuilder &); -} -#endif +#define HANDLE_EXTENSION(Ext) \ + llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); +#include "llvm/Support/Extension.def" bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, ToolOutputFile *Out, ToolOutputFile *ThinLTOLinkOut, @@ -290,9 +288,9 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, return false; }); -#ifdef LINK_POLLY_INTO_TOOLS - polly::RegisterPollyPasses(PB); -#endif +#define HANDLE_EXTENSION(Ext) \ + get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB); +#include "llvm/Support/Extension.def" // Specially handle the alias analysis manager so that we can register // a custom pipeline of AA passes with it. diff --git a/llvm/tools/opt/PassPrinters.cpp b/llvm/tools/opt/PassPrinters.cpp index 70da6a43f8d9..a877d9dc90f4 100644 --- a/llvm/tools/opt/PassPrinters.cpp +++ b/llvm/tools/opt/PassPrinters.cpp @@ -198,40 +198,6 @@ struct RegionPassPrinter : public RegionPass { char RegionPassPrinter::ID = 0; -struct BasicBlockPassPrinter : public BasicBlockPass { - const PassInfo *PassToPrint; - raw_ostream &Out; - static char ID; - std::string PassName; - bool QuietPass; - - BasicBlockPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet) - : BasicBlockPass(ID), PassToPrint(PI), Out(out), QuietPass(Quiet) { - std::string PassToPrintName = PassToPrint->getPassName(); - PassName = "BasicBlockPass Printer: " + PassToPrintName; - } - - bool runOnBasicBlock(BasicBlock &BB) override { - if (!QuietPass) - Out << "Printing Analysis info for BasicBlock '" << BB.getName() - << "': Pass " << PassToPrint->getPassName() << ":\n"; - - // Get and print pass... - getAnalysisID<Pass>(PassToPrint->getTypeInfo()) - .print(Out, BB.getParent()->getParent()); - return false; - } - - StringRef getPassName() const override { return PassName; } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequiredID(PassToPrint->getTypeInfo()); - AU.setPreservesAll(); - } -}; - -char BasicBlockPassPrinter::ID = 0; - } // end anonymous namespace FunctionPass *llvm::createFunctionPassPrinter(const PassInfo *PI, @@ -260,7 +226,3 @@ RegionPass *llvm::createRegionPassPrinter(const PassInfo *PI, raw_ostream &OS, return new RegionPassPrinter(PI, OS, Quiet); } -BasicBlockPass *llvm::createBasicBlockPassPrinter(const PassInfo *PI, - raw_ostream &OS, bool Quiet) { - return new BasicBlockPassPrinter(PI, OS, Quiet); -} diff --git a/llvm/tools/opt/PassPrinters.h b/llvm/tools/opt/PassPrinters.h index d4e7a4a97f31..692befbdae75 100644 --- a/llvm/tools/opt/PassPrinters.h +++ b/llvm/tools/opt/PassPrinters.h @@ -18,7 +18,6 @@ namespace llvm { -class BasicBlockPass; class CallGraphSCCPass; class FunctionPass; class ModulePass; @@ -43,9 +42,6 @@ LoopPass *createLoopPassPrinter(const PassInfo *PI, raw_ostream &out, RegionPass *createRegionPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet); -BasicBlockPass *createBasicBlockPassPrinter(const PassInfo *PI, - raw_ostream &out, bool Quiet); - } // end namespace llvm #endif // LLVM_TOOLS_OPT_PASSPRINTERS_H diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp index 15495a511d06..75a6cdc3892b 100644 --- a/llvm/tools/opt/opt.cpp +++ b/llvm/tools/opt/opt.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "BreakpointPrinter.h" -#include "Debugify.h" #include "NewPMDriver.h" #include "PassPrinters.h" #include "llvm/ADT/Triple.h" @@ -56,6 +55,7 @@ #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/Debugify.h" #include <algorithm> #include <memory> using namespace llvm; @@ -193,6 +193,12 @@ static cl::opt<bool> DisableSimplifyLibCalls("disable-simplify-libcalls", cl::desc("Disable simplify-libcalls")); +static cl::list<std::string> +DisableBuiltins("disable-builtin", + cl::desc("Disable specific target library builtin function"), + cl::ZeroOrMore); + + static cl::opt<bool> Quiet("q", cl::desc("Obsolete option"), cl::Hidden); @@ -328,7 +334,7 @@ public: PassKind Kind = P->getPassKind(); StringRef Name = P->getPassName(); - // TODO: Implement Debugify for BasicBlockPass, LoopPass. + // TODO: Implement Debugify for LoopPass. switch (Kind) { case PT_Function: super::add(createDebugifyFunctionPass()); @@ -476,12 +482,32 @@ static TargetMachine* GetTargetMachine(Triple TheTriple, StringRef CPUStr, getCodeModel(), GetCodeGenOptLevel()); } -#ifdef LINK_POLLY_INTO_TOOLS -namespace polly { -void initializePollyPasses(llvm::PassRegistry &Registry); -} +#ifdef BUILD_EXAMPLES +void initializeExampleIRTransforms(llvm::PassRegistry &Registry); #endif + +void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map) { + std::error_code EC; + raw_fd_ostream OS{Path, EC}; + if (EC) { + errs() << "Could not open file: " << EC.message() << ", " << Path << '\n'; + return; + } + + OS << "Pass Name" << ',' << "# of missing debug values" << ',' + << "# of missing locations" << ',' << "Missing/Expected value ratio" << ',' + << "Missing/Expected location ratio" << '\n'; + for (const auto &Entry : Map) { + StringRef Pass = Entry.first; + DebugifyStatistics Stats = Entry.second; + + OS << Pass << ',' << Stats.NumDbgValuesMissing << ',' + << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ',' + << Stats.getEmptyLocationRatio() << '\n'; + } +} + //===----------------------------------------------------------------------===// // main for opt // @@ -535,9 +561,10 @@ int main(int argc, char **argv) { initializeWasmEHPreparePass(Registry); initializeWriteBitcodePassPass(Registry); initializeHardwareLoopsPass(Registry); + initializeTypePromotionPass(Registry); -#ifdef LINK_POLLY_INTO_TOOLS - polly::initializePollyPasses(Registry); +#ifdef BUILD_EXAMPLES + initializeExampleIRTransforms(Registry); #endif cl::ParseCommandLineOptions(argc, argv, @@ -697,6 +724,19 @@ int main(int argc, char **argv) { // The -disable-simplify-libcalls flag actually disables all builtin optzns. if (DisableSimplifyLibCalls) TLII.disableAllFunctions(); + else { + // Disable individual builtin functions in TargetLibraryInfo. + LibFunc F; + for (auto &FuncName : DisableBuiltins) + if (TLII.getLibFunc(FuncName, F)) + TLII.setUnavailable(F); + else { + errs() << argv[0] << ": cannot disable nonexistent builtin function " + << FuncName << '\n'; + return 1; + } + } + Passes.add(new TargetLibraryInfoWrapperPass(TLII)); // Add internal analysis passes from the target machine. @@ -790,9 +830,6 @@ int main(int argc, char **argv) { if (AnalyzeOnly) { switch (Kind) { - case PT_BasicBlock: - Passes.add(createBasicBlockPassPrinter(PassInf, Out->os(), Quiet)); - break; case PT_Region: Passes.add(createRegionPassPrinter(PassInf, Out->os(), Quiet)); break; @@ -863,8 +900,10 @@ int main(int argc, char **argv) { std::unique_ptr<raw_svector_ostream> BOS; raw_ostream *OS = nullptr; + const bool ShouldEmitOutput = !NoOutput && !AnalyzeOnly; + // Write bitcode or assembly to the output as the last step... - if (!NoOutput && !AnalyzeOnly) { + if (ShouldEmitOutput || RunTwice) { assert(Out); OS = &Out->os(); if (RunTwice) { @@ -912,13 +951,16 @@ int main(int argc, char **argv) { "Writing the result of the second run to the specified output.\n" "To generate the one-run comparison binary, just run without\n" "the compile-twice option\n"; - Out->os() << BOS->str(); - Out->keep(); + if (ShouldEmitOutput) { + Out->os() << BOS->str(); + Out->keep(); + } if (RemarksFile) RemarksFile->keep(); return 1; } - Out->os() << BOS->str(); + if (ShouldEmitOutput) + Out->os() << BOS->str(); } if (DebugifyEach && !DebugifyExport.empty()) |