diff options
Diffstat (limited to 'contrib/llvm-project/llvm/tools')
84 files changed, 2911 insertions, 1574 deletions
diff --git a/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.cpp b/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.cpp index 942028cad80b..32c747fdd516 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.cpp @@ -21,9 +21,9 @@ #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" -#include "llvm/Support/Host.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" #include <memory> using namespace llvm; diff --git a/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.h b/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.h index b7c9edc5b812..9fb0880b9cd0 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.h +++ b/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.h @@ -101,15 +101,6 @@ public: /// input. Error debugMiscompilation(); - /// debugPassMiscompilation - This method is called when the specified pass - /// miscompiles Program as input. It tries to reduce the testcase to - /// something that smaller that still miscompiles the program. - /// ReferenceOutput contains the filename of the file containing the output we - /// are to match. - /// - bool debugPassMiscompilation(const PassInfo *ThePass, - const std::string &ReferenceOutput); - /// compileSharedObject - This method creates a SharedObject from a given /// BitcodeFile for debugging a code generator. /// diff --git a/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp b/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp index c90e1afd8ca4..0ca8fa28c4af 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp @@ -70,6 +70,18 @@ cl::opt<bool> VerboseErrors("verbose-errors", cl::init(false)); } +static bool isValidModule(std::unique_ptr<Module> &M, + bool ExitOnFailure = true) { + if (!llvm::verifyModule(*M.get(), &llvm::errs())) + return true; + + if (ExitOnFailure) { + llvm::errs() << "verify failed!\n"; + exit(1); + } + return false; +} + namespace llvm { class ReducePassList : public ListReducer<std::string> { BugDriver &BD; @@ -368,6 +380,10 @@ bool ReduceCrashingFunctionAttributes::TestFuncAttrs( if (F->hasFnAttribute(Attribute::OptimizeNone)) F->addFnAttr(Attribute::NoInline); + // If modifying the attribute list leads to invalid IR, revert the change + if (!isValidModule(M, /*ExitOnFailure=*/false)) + return false; + // Try running on the hacked up program... if (TestFn(BD, M.get())) { BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version... @@ -510,14 +526,7 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock *> &BBs) { ToProcess.clear(); } // Verify we didn't break anything - std::vector<std::string> Passes; - Passes.push_back("verify"); - std::unique_ptr<Module> New = BD.runPassesOn(M.get(), Passes); - if (!New) { - errs() << "verify failed!\n"; - exit(1); - } - M = std::move(New); + isValidModule(M); // Try running on the hacked up program... if (TestFn(BD, M.get())) { @@ -618,14 +627,7 @@ bool ReduceCrashingConditionals::TestBlocks( ToProcess.clear(); } // Verify we didn't break anything - std::vector<std::string> Passes; - Passes.push_back("verify"); - std::unique_ptr<Module> New = BD.runPassesOn(M.get(), Passes); - if (!New) { - errs() << "verify failed!\n"; - exit(1); - } - M = std::move(New); + isValidModule(M); // Try running on the hacked up program... if (TestFn(BD, M.get())) { @@ -711,14 +713,7 @@ bool ReduceSimplifyCFG::TestBlocks(std::vector<const BasicBlock *> &BBs) { simplifyCFG(&*BBIt++, TTI); } // Verify we didn't break anything - std::vector<std::string> Passes; - Passes.push_back("verify"); - std::unique_ptr<Module> New = BD.runPassesOn(M.get(), Passes); - if (!New) { - errs() << "verify failed!\n"; - exit(1); - } - M = std::move(New); + isValidModule(M); // Try running on the hacked up program... if (TestFn(BD, M.get())) { @@ -797,9 +792,7 @@ bool ReduceCrashingInstructions::TestInsts( } // Verify that this is still valid. - legacy::PassManager Passes; - Passes.add(createVerifierPass(/*FatalErrors=*/false)); - Passes.run(*M); + isValidModule(M, /*ExitOnFailure=*/false); // Try running on the hacked up program... if (TestFn(BD, M.get())) { @@ -869,9 +862,7 @@ bool ReduceCrashingMetadata::TestInsts(std::vector<Instruction *> &Insts) { } // Verify that this is still valid. - legacy::PassManager Passes; - Passes.add(createVerifierPass(/*FatalErrors=*/false)); - Passes.run(*M); + isValidModule(M, /*ExitOnFailure=*/false); // Try running on the hacked up program... if (TestFn(BD, M.get())) { @@ -944,9 +935,7 @@ bool ReduceCrashingNamedMD::TestNamedMDs(std::vector<std::string> &NamedMDs) { NamedMD->eraseFromParent(); // Verify that this is still valid. - legacy::PassManager Passes; - Passes.add(createVerifierPass(/*FatalErrors=*/false)); - Passes.run(*M); + isValidModule(M, /*ExitOnFailure=*/false); // Try running on the hacked up program... if (TestFn(BD, M.get())) { @@ -1009,9 +998,7 @@ bool ReduceCrashingNamedMDOps::TestNamedMDOps( } // Verify that this is still valid. - legacy::PassManager Passes; - Passes.add(createVerifierPass(/*FatalErrors=*/false)); - Passes.run(*M); + isValidModule(M, /*ExitOnFailure=*/false); // Try running on the hacked up program... if (TestFn(BD, M.get())) { diff --git a/contrib/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp b/contrib/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp index 5047aa35d7e7..dd9a82c32035 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp @@ -133,7 +133,6 @@ BugDriver::performFinalCleanups(std::unique_ptr<Module> M, I->setLinkage(GlobalValue::ExternalLinkage); std::vector<std::string> CleanupPasses; - CleanupPasses.push_back("globaldce"); if (MayModifySemantics) CleanupPasses.push_back("deadarghaX0r"); diff --git a/contrib/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp b/contrib/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp index 1197528d0dd3..f7239f5dc61b 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp @@ -207,7 +207,7 @@ bool BugDriver::runPasses(Module &Program, Args.push_back(OptArgs[i]); // Pin to legacy PM since bugpoint has lots of infra and hacks revolving // around the legacy PM. - Args.push_back("-enable-new-pm=0"); + Args.push_back("-bugpoint-enable-legacy-pm"); Args.push_back("-disable-symbolication"); Args.push_back("-o"); Args.push_back(OutputFilename); diff --git a/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp b/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp index 352588f01ac8..c6733aecd31d 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp @@ -612,7 +612,7 @@ static bool IsARMArchitecture(std::vector<StringRef> Args) { ++I; if (I == Args.size()) break; - if (Args[I].startswith_insensitive("arm")) + if (Args[I].starts_with_insensitive("arm")) return true; } diff --git a/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.h b/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.h index f6b5f26c7a66..c9da9afba0e4 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.h +++ b/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.h @@ -16,11 +16,11 @@ #ifndef LLVM_TOOLS_BUGPOINT_TOOLRUNNER_H #define LLVM_TOOLS_BUGPOINT_TOOLRUNNER_H -#include "llvm/ADT/Triple.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/Path.h" #include "llvm/Support/SystemUtils.h" +#include "llvm/TargetParser/Triple.h" #include <exception> #include <vector> diff --git a/contrib/llvm-project/llvm/tools/bugpoint/bugpoint.cpp b/contrib/llvm-project/llvm/tools/bugpoint/bugpoint.cpp index 0305f6463858..e49efdfe7c8e 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/bugpoint.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/bugpoint.cpp @@ -30,7 +30,6 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/Support/Valgrind.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" // Enable this macro to debug bugpoint itself. //#define DEBUG_BUGPOINT 1 @@ -66,24 +65,6 @@ static cl::opt<bool> static cl::list<const PassInfo *, bool, PassNameParser> PassList(cl::desc("Passes available:")); -static cl::opt<bool> - OptLevelO1("O1", cl::desc("Optimization level 1. Identical to 'opt -O1'")); - -static cl::opt<bool> - OptLevelO2("O2", cl::desc("Optimization level 2. Identical to 'opt -O2'")); - -static cl::opt<bool> OptLevelOs( - "Os", - cl::desc( - "Like -O2 with extra optimizations for size. Similar to clang -Os")); - -static cl::opt<bool> -OptLevelOz("Oz", - cl::desc("Like -Os but reduces code size further. Similar to clang -Oz")); - -static cl::opt<bool> - OptLevelO3("O3", cl::desc("Optimization level 3. Identical to 'opt -O3'")); - static cl::opt<std::string> OverrideTriple("mtriple", cl::desc("Override target triple for module")); @@ -110,26 +91,6 @@ public: }; } -// This routine adds optimization passes based on selected optimization level, -// OptLevel. -// -// OptLevel - Optimization Level -static void AddOptimizationPasses(legacy::FunctionPassManager &FPM, - unsigned OptLevel, - unsigned SizeLevel) { - PassManagerBuilder Builder; - Builder.OptLevel = OptLevel; - Builder.SizeLevel = SizeLevel; - - if (OptLevel > 1) - Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false); - else - Builder.Inliner = createAlwaysInlinerLegacyPass(); - - Builder.populateFunctionPassManager(FPM); - Builder.populateModulePassManager(FPM); -} - #define HANDLE_EXTENSION(Ext) \ llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); #include "llvm/Support/Extension.def" @@ -195,17 +156,6 @@ int main(int argc, char **argv) { AddToDriver PM(D); - if (OptLevelO1) - AddOptimizationPasses(PM, 1, 0); - else if (OptLevelO2) - AddOptimizationPasses(PM, 2, 0); - else if (OptLevelO3) - AddOptimizationPasses(PM, 3, 0); - else if (OptLevelOs) - AddOptimizationPasses(PM, 2, 1); - else if (OptLevelOz) - AddOptimizationPasses(PM, 2, 2); - for (const PassInfo *PI : PassList) D.addPass(std::string(PI->getPassArgument())); diff --git a/contrib/llvm-project/llvm/tools/llc/llc.cpp b/contrib/llvm-project/llvm/tools/llc/llc.cpp index f2dae67040ff..8934130f9913 100644 --- a/contrib/llvm-project/llvm/tools/llc/llc.cpp +++ b/contrib/llvm-project/llvm/tools/llc/llc.cpp @@ -14,7 +14,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" -#include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/LinkAllAsmWriterComponents.h" @@ -36,7 +35,6 @@ #include "llvm/IRReader/IRReader.h" #include "llvm/InitializePasses.h" #include "llvm/MC/MCTargetOptionsCommandFlags.h" -#include "llvm/MC/SubtargetFeature.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Pass.h" #include "llvm/Remarks/HotnessThresholdParser.h" @@ -44,7 +42,6 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormattedStream.h" -#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/SourceMgr.h" @@ -54,6 +51,9 @@ #include "llvm/Support/WithColor.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/SubtargetFeature.h" +#include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/Cloning.h" #include <memory> #include <optional> @@ -107,10 +107,6 @@ static cl::opt<std::string> "regardless of binutils support")); static cl::opt<bool> -NoIntegratedAssembler("no-integrated-as", cl::Hidden, - cl::desc("Disable integrated assembler")); - -static cl::opt<bool> PreserveComments("preserve-as-comments", cl::Hidden, cl::desc("Preserve Comments in outputted assembly"), cl::init(true)); @@ -366,7 +362,7 @@ int main(int argc, char **argv) { initializeScalarizeMaskedMemIntrinLegacyPassPass(*Registry); initializeExpandReductionsPass(*Registry); initializeExpandVectorPredicationPass(*Registry); - initializeHardwareLoopsPass(*Registry); + initializeHardwareLoopsLegacyPass(*Registry); initializeTransformUtils(*Registry); initializeReplaceWithVeclibLegacyPass(*Registry); initializeTLSVariableHoistLegacyPassPass(*Registry); @@ -496,9 +492,27 @@ static int compileModule(char **argv, LLVMContext &Context) { TargetOptions Options; auto InitializeOptions = [&](const Triple &TheTriple) { Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple); + + if (Options.XCOFFReadOnlyPointers) { + if (!TheTriple.isOSAIX()) + reportError("-mxcoff-roptr option is only supported on AIX", + InputFilename); + + // Since the storage mapping class is specified per csect, + // without using data sections, it is less effective to use read-only + // pointers. Using read-only pointers may cause other RO variables in the + // same csect to become RW when the linker acts upon `-bforceimprw`; + // therefore, we require that separate data sections are used in the + // presence of ReadOnlyPointers. We respect the setting of data-sections + // since we have not found reasons to do otherwise that overcome the user + // surprise of not respecting the setting. + if (!Options.DataSections) + reportError("-mxcoff-roptr option must be used with -data-sections", + InputFilename); + } + Options.BinutilsVersion = TargetMachine::parseBinutilsVersion(BinutilsVersion); - Options.DisableIntegratedAS = NoIntegratedAssembler; Options.MCOptions.ShowMCEncoding = ShowMCEncoding; Options.MCOptions.AsmVerbose = AsmVerbose; Options.MCOptions.PreserveAsmComments = PreserveComments; @@ -680,13 +694,17 @@ static int compileModule(char **argv, LLVMContext &Context) { if (!MIR) { WithColor::warning(errs(), argv[0]) << "run-pass is for .mir file only.\n"; + delete MMIWP; return 1; } - TargetPassConfig &TPC = *LLVMTM.createPassConfig(PM); + TargetPassConfig *PTPC = LLVMTM.createPassConfig(PM); + TargetPassConfig &TPC = *PTPC; if (TPC.hasLimitedCodeGenPipeline()) { WithColor::warning(errs(), argv[0]) << "run-pass cannot be used with " << TPC.getLimitedCodeGenPipelineReason(" and ") << ".\n"; + delete PTPC; + delete MMIWP; return 1; } diff --git a/contrib/llvm-project/llvm/tools/lli/ExecutionUtils.h b/contrib/llvm-project/llvm/tools/lli/ExecutionUtils.h index fcd1db05cca3..6bf9cd58e031 100644 --- a/contrib/llvm-project/llvm/tools/lli/ExecutionUtils.h +++ b/contrib/llvm-project/llvm/tools/lli/ExecutionUtils.h @@ -48,8 +48,8 @@ private: std::unique_ptr<ToolOutputFile> TestOut; template <typename T> void expose(orc::SymbolStringPtr Name, T *Handler) { - BuiltinFunctions[Name] = JITEvaluatedSymbol( - pointerToJITTargetAddress(Handler), JITSymbolFlags::Exported); + BuiltinFunctions[Name] = {orc::ExecutorAddr::fromPtr(Handler), + JITSymbolFlags::Exported}; } static std::unique_ptr<ToolOutputFile> createToolOutput(); diff --git a/contrib/llvm-project/llvm/tools/lli/lli.cpp b/contrib/llvm-project/llvm/tools/lli/lli.cpp index c9b77e23ba07..3b5250d56707 100644 --- a/contrib/llvm-project/llvm/tools/lli/lli.cpp +++ b/contrib/llvm-project/llvm/tools/lli/lli.cpp @@ -15,7 +15,6 @@ #include "ExecutionUtils.h" #include "ForwardingMemoryManager.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Triple.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" @@ -26,17 +25,13 @@ #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/ObjectCache.h" -#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" #include "llvm/ExecutionEngine/Orc/DebugUtils.h" -#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h" -#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h" #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h" #include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h" #include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" -#include "llvm/ExecutionEngine/Orc/MachOPlatform.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h" #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" @@ -68,6 +63,7 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Instrumentation.h" #include <cerrno> #include <optional> @@ -236,20 +232,22 @@ namespace { cl::desc("Do not resolve lli process symbols in JIT'd code"), cl::init(false)); - enum class LLJITPlatform { Inactive, DetectHost, ORC, GenericIR }; - - cl::opt<LLJITPlatform> - Platform("lljit-platform", cl::desc("Platform to use with LLJIT"), - cl::init(LLJITPlatform::DetectHost), - cl::values(clEnumValN(LLJITPlatform::DetectHost, "DetectHost", - "Select based on JIT target triple"), - clEnumValN(LLJITPlatform::ORC, "ORC", - "Use ORCPlatform with the ORC runtime"), - clEnumValN(LLJITPlatform::GenericIR, "GenericIR", - "Use LLJITGenericIRPlatform"), - clEnumValN(LLJITPlatform::Inactive, "Inactive", - "Disable platform support explicitly")), - cl::Hidden); + enum class LLJITPlatform { Inactive, Auto, ExecutorNative, GenericIR }; + + cl::opt<LLJITPlatform> Platform( + "lljit-platform", cl::desc("Platform to use with LLJIT"), + cl::init(LLJITPlatform::Auto), + cl::values(clEnumValN(LLJITPlatform::Auto, "Auto", + "Like 'ExecutorNative' if ORC runtime " + "provided, otherwise like 'GenericIR'"), + clEnumValN(LLJITPlatform::ExecutorNative, "ExecutorNative", + "Use the native platform for the executor." + "Requires -orc-runtime"), + clEnumValN(LLJITPlatform::GenericIR, "GenericIR", + "Use LLJITGenericIRPlatform"), + clEnumValN(LLJITPlatform::Inactive, "Inactive", + "Disable platform support explicitly")), + cl::Hidden); enum class DumpKind { NoDump, @@ -663,10 +661,6 @@ int main(int argc, char **argv, char * const *envp) { #endif } - std::unique_ptr<orc::ExecutorProcessControl> EPC = - RemoteMCJIT ? ExitOnErr(launchRemote()) - : ExitOnErr(orc::SelfExecutorProcessControl::Create()); - if (!RemoteMCJIT) { // If the program doesn't explicitly call exit, we will need the Exit // function later on to make an explicit call, so get the function now. @@ -712,6 +706,7 @@ int main(int argc, char **argv, char * const *envp) { abort(); } else { // else == "if (RemoteMCJIT)" + std::unique_ptr<orc::ExecutorProcessControl> EPC = ExitOnErr(launchRemote()); // Remote target MCJIT doesn't (yet) support static constructors. No reason // it couldn't. This is a limitation of the LLI implementation, not the @@ -829,6 +824,20 @@ loadModule(StringRef Path, orc::ThreadSafeContext TSCtx) { return orc::ThreadSafeModule(std::move(M), std::move(TSCtx)); } +int mingw_noop_main(void) { + // Cygwin and MinGW insert calls from the main function to the runtime + // function __main. The __main function is responsible for setting up main's + // environment (e.g. running static constructors), however this is not needed + // when running under lli: the executor process will have run non-JIT ctors, + // and ORC will take care of running JIT'd ctors. To avoid a missing symbol + // error we just implement __main as a no-op. + // + // FIXME: Move this to ORC-RT (and the ORC-RT substitution library once it + // exists). That will allow it to work out-of-process, and for all + // ORC tools (the problem isn't lli specific). + return 0; +} + int runOrcJIT(const char *ProgName) { // Start setting up the JIT environment. @@ -867,6 +876,9 @@ int runOrcJIT(const char *ProgName) { .setRelocationModel(codegen::getExplicitRelocModel()) .setCodeModel(codegen::getExplicitCodeModel()); + // Link process symbols unless NoProcessSymbols is set. + Builder.setLinkProcessSymbolsByDefault(!NoProcessSymbols); + // FIXME: Setting a dummy call-through manager in non-lazy mode prevents the // JIT builder to instantiate a default (which would fail with an error for // unsupported architectures). @@ -874,7 +886,8 @@ int runOrcJIT(const char *ProgName) { auto ES = std::make_unique<orc::ExecutionSession>( ExitOnErr(orc::SelfExecutorProcessControl::Create())); Builder.setLazyCallthroughManager( - std::make_unique<orc::LazyCallThroughManager>(*ES, 0, nullptr)); + std::make_unique<orc::LazyCallThroughManager>(*ES, orc::ExecutorAddr(), + nullptr)); Builder.setExecutionSession(std::move(ES)); } @@ -907,17 +920,15 @@ int runOrcJIT(const char *ProgName) { // Set up LLJIT platform. LLJITPlatform P = Platform; - if (P == LLJITPlatform::DetectHost) { - if (JITLinker == JITLinkerKind::JITLink && !OrcRuntime.empty() && - (TT->isOSBinFormatMachO() || TT->isOSBinFormatELF())) - P = LLJITPlatform::ORC; - else - P = LLJITPlatform::GenericIR; - } + if (P == LLJITPlatform::Auto) + P = OrcRuntime.empty() ? LLJITPlatform::GenericIR + : LLJITPlatform::ExecutorNative; + switch (P) { - case LLJITPlatform::ORC: - Builder.setPlatformSetUp(orc::setUpOrcPlatform); + case LLJITPlatform::ExecutorNative: { + Builder.setPlatformSetUp(orc::ExecutorNativePlatform(OrcRuntime)); break; + } case LLJITPlatform::GenericIR: // Nothing to do: LLJITBuilder will use this by default. break; @@ -936,22 +947,35 @@ int runOrcJIT(const char *ProgName) { Builder.setObjectLinkingLayerCreator([&EPC, &P](orc::ExecutionSession &ES, const Triple &TT) { auto L = std::make_unique<orc::ObjectLinkingLayer>(ES, EPC->getMemMgr()); - if (P != LLJITPlatform::ORC) { + if (P != LLJITPlatform::ExecutorNative) L->addPlugin(std::make_unique<orc::EHFrameRegistrationPlugin>( ES, ExitOnErr(orc::EPCEHFrameRegistrar::Create(ES)))); - L->addPlugin(std::make_unique<orc::DebugObjectManagerPlugin>( - ES, ExitOnErr(orc::createJITLoaderGDBRegistrar(ES)))); - } return L; }); } + // Enable debugging of JIT'd code (only works on JITLink for ELF and MachO). + Builder.setEnableDebuggerSupport(true); + auto J = ExitOnErr(Builder.create()); auto *ObjLayer = &J->getObjLinkingLayer(); - if (auto *RTDyldObjLayer = dyn_cast<orc::RTDyldObjectLinkingLayer>(ObjLayer)) + if (auto *RTDyldObjLayer = dyn_cast<orc::RTDyldObjectLinkingLayer>(ObjLayer)) { RTDyldObjLayer->registerJITEventListener( *JITEventListener::createGDBRegistrationListener()); +#if LLVM_USE_OPROFILE + RTDyldObjLayer->registerJITEventListener( + *JITEventListener::createOProfileJITEventListener()); +#endif +#if LLVM_USE_INTEL_JITEVENTS + RTDyldObjLayer->registerJITEventListener( + *JITEventListener::createIntelJITEventListener()); +#endif +#if LLVM_USE_PERF + RTDyldObjLayer->registerJITEventListener( + *JITEventListener::createPerfJITEventListener()); +#endif + } if (PerModuleLazy) J->setPartitionFunction(orc::CompileOnDemandLayer::compileWholeModule); @@ -971,48 +995,22 @@ int runOrcJIT(const char *ProgName) { return TSM; }); - orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout()); - - // Unless they've been explicitly disabled, make process symbols available to - // JIT'd code. - if (!NoProcessSymbols) - J->getMainJITDylib().addGenerator( - ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - J->getDataLayout().getGlobalPrefix(), - [MainName = Mangle("main")](const orc::SymbolStringPtr &Name) { - return Name != MainName; - }))); - - if (GenerateBuiltinFunctions.size() > 0) + if (GenerateBuiltinFunctions.size() > 0) { + // Add LLI builtins. + orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout()); J->getMainJITDylib().addGenerator( std::make_unique<LLIBuiltinFunctionGenerator>(GenerateBuiltinFunctions, Mangle)); - - if (P == LLJITPlatform::ORC) { - if (auto *OLL = llvm::dyn_cast<llvm::orc::ObjectLinkingLayer>(ObjLayer)) { - auto &ES = J->getExecutionSession(); - if (TT->isOSBinFormatMachO()) { - if (auto P = llvm::orc::MachOPlatform::Create( - ES, *OLL, J->getMainJITDylib(), OrcRuntime.c_str())) - ES.setPlatform(std::move(*P)); - else - ExitOnErr(P.takeError()); - } else if (TT->isOSBinFormatELF()) { - if (auto P = llvm::orc::ELFNixPlatform::Create( - ES, *OLL, J->getMainJITDylib(), OrcRuntime.c_str())) - ES.setPlatform(std::move(*P)); - else - ExitOnErr(P.takeError()); - } else { - errs() << "No ORC platform support\n"; - exit(1); - } - } else { - errs() << "ORC platform requires JITLink\n"; - exit(1); - } } + // If this is a Mingw or Cygwin executor then we need to alias __main to + // orc_rt_int_void_return_0. + if (J->getTargetTriple().isOSCygMing()) + ExitOnErr(J->getProcessSymbolsJITDylib()->define( + orc::absoluteSymbols({{J->mangleAndIntern("__main"), + {orc::ExecutorAddr::fromPtr(mingw_noop_main), + JITSymbolFlags::Exported}}}))); + // Regular modules are greedy: They materialize as a whole and trigger // materialization for all required symbols recursively. Lazy modules go // through partitioning and they replace outgoing calls with reexport stubs @@ -1060,8 +1058,7 @@ int runOrcJIT(const char *ProgName) { assert(EAIdx != 0 && "ExtraArchive should have index > 0"); auto JDItr = std::prev(IdxToDylib.lower_bound(EAIdx)); auto &JD = *JDItr->second; - JD.addGenerator(ExitOnErr(orc::StaticLibraryDefinitionGenerator::Load( - J->getObjLinkingLayer(), EAItr->c_str(), *TT))); + ExitOnErr(J->linkStaticLibraryInto(JD, EAItr->c_str())); } } @@ -1181,3 +1178,41 @@ Expected<std::unique_ptr<orc::ExecutorProcessControl>> launchRemote() { llvm::orc::SimpleRemoteEPC::Setup(), PipeFD[1][0], PipeFD[0][1]); #endif } + +// For MinGW environments, manually export the __chkstk function from the lli +// executable. +// +// Normally, this function is provided by compiler-rt builtins or libgcc. +// It is named "_alloca" on i386, "___chkstk_ms" on x86_64, and "__chkstk" on +// arm/aarch64. In MSVC configurations, it's named "__chkstk" in all +// configurations. +// +// When Orc tries to resolve symbols at runtime, this succeeds in MSVC +// configurations, somewhat by accident/luck; kernelbase.dll does export a +// symbol named "__chkstk" which gets found by Orc, even if regular applications +// never link against that function from that DLL (it's linked in statically +// from a compiler support library). +// +// The MinGW specific symbol names aren't available in that DLL though. +// Therefore, manually export the relevant symbol from lli, to let it be +// found at runtime during tests. +// +// For real JIT uses, the real compiler support libraries should be linked +// in, somehow; this is a workaround to let tests pass. +// +// TODO: Move this into libORC at some point, see +// https://github.com/llvm/llvm-project/issues/56603. +#ifdef __MINGW32__ +// This is a MinGW version of #pragma comment(linker, "...") that doesn't +// require compiling with -fms-extensions. +#if defined(__i386__) +static __attribute__((section(".drectve"), used)) const char export_chkstk[] = + "-export:_alloca"; +#elif defined(__x86_64__) +static __attribute__((section(".drectve"), used)) const char export_chkstk[] = + "-export:___chkstk_ms"; +#else +static __attribute__((section(".drectve"), used)) const char export_chkstk[] = + "-export:__chkstk"; +#endif +#endif diff --git a/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp b/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp index 12f3196a9844..d21650d146a9 100644 --- a/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp @@ -13,20 +13,11 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" -#include "llvm/Object/COFFImportFile.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Object/IRObjectFile.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" -#include "llvm/Object/TapiFile.h" -#include "llvm/Object/Wasm.h" -#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" @@ -34,8 +25,8 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -45,6 +36,8 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" @@ -646,31 +639,12 @@ static bool shouldCreateArchive(ArchiveOperation Op) { llvm_unreachable("Missing entry in covered switch."); } -static bool is64BitSymbolicFile(SymbolicFile &Obj) { - if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj)) - return Triple(IRObj->getTargetTriple()).isArch64Bit(); - if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj)) - return false; - if (XCOFFObjectFile *XCOFFObj = dyn_cast<XCOFFObjectFile>(&Obj)) - return XCOFFObj->is64Bit(); - if (isa<WasmObjectFile>(Obj)) - return false; - if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj)) - return Tapi->is64Bit(); - if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj)) - return MachO->is64Bit(); - if (ELFObjectFileBase *ElfO = dyn_cast<ELFObjectFileBase>(&Obj)) - return ElfO->getBytesInAddress() == 8; - - fail("unsupported file format"); -} - static bool isValidInBitMode(Binary &Bin) { if (BitMode == BitModeTy::Bit32_64 || BitMode == BitModeTy::Any) return true; if (SymbolicFile *SymFile = dyn_cast<SymbolicFile>(&Bin)) { - bool Is64Bit = is64BitSymbolicFile(*SymFile); + bool Is64Bit = SymFile->is64Bit(); if ((Is64Bit && (BitMode == BitModeTy::Bit32)) || (!Is64Bit && (BitMode == BitModeTy::Bit64))) return false; @@ -1452,7 +1426,7 @@ static int ranlib_main(int argc, char **argv) { return 0; } -int llvm_ar_main(int argc, char **argv) { +int llvm_ar_main(int argc, char **argv, const llvm::ToolContext &) { InitLLVM X(argc, argv); ToolName = argv[0]; diff --git a/contrib/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp b/contrib/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp index 7b71d5ad4554..02448dcd31a1 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -22,7 +22,6 @@ #include "SourceCoverageView.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/Debuginfod/BuildIDFetcher.h" #include "llvm/Debuginfod/Debuginfod.h" #include "llvm/Debuginfod/HTTPClient.h" @@ -42,6 +41,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Triple.h" #include <functional> #include <map> @@ -185,6 +185,8 @@ private: std::unique_ptr<SpecialCaseList> NameAllowlist; std::unique_ptr<object::BuildIDFetcher> BIDFetcher; + + bool CheckBinaryIDs; }; } @@ -439,9 +441,10 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() { if (modifiedTimeGT(ObjectFilename, PGOFilename)) warning("profile data may be out of date - object is newer", ObjectFilename); - auto CoverageOrErr = - CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches, - ViewOpts.CompilationDirectory, BIDFetcher.get()); + auto FS = vfs::getRealFileSystem(); + auto CoverageOrErr = CoverageMapping::load( + ObjectFilenames, PGOFilename, *FS, CoverageArches, + ViewOpts.CompilationDirectory, BIDFetcher.get(), CheckBinaryIDs); if (Error E = CoverageOrErr.takeError()) { error("Failed to load coverage: " + toString(std::move(E))); return nullptr; @@ -760,6 +763,10 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { "compilation-dir", cl::init(""), cl::desc("Directory used as a base for relative coverage mapping paths")); + cl::opt<bool> CheckBinaryIDs( + "check-binary-ids", cl::desc("Fail if an object couldn't be found for a " + "binary ID in the profile")); + auto commandLineParser = [&, this](int argc, const char **argv) -> int { cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); ViewOpts.Debug = DebugDump; @@ -769,6 +776,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { } else { BIDFetcher = std::make_unique<object::BuildIDFetcher>(DebugFileDirectory); } + this->CheckBinaryIDs = CheckBinaryIDs; if (!CovFilename.empty()) ObjectFilenames.emplace_back(CovFilename); diff --git a/contrib/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp b/contrib/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp index be042aa9e027..cb0b184e103c 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cov/CoverageReport.cpp @@ -13,6 +13,7 @@ #include "CoverageReport.h" #include "RenderingSupport.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/Format.h" #include "llvm/Support/Path.h" #include "llvm/Support/ThreadPool.h" diff --git a/contrib/llvm-project/llvm/tools/llvm-cov/llvm-cov.cpp b/contrib/llvm-project/llvm/tools/llvm-cov/llvm-cov.cpp index 45de2afb0855..5ada55789b24 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cov/llvm-cov.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cov/llvm-cov.cpp @@ -59,7 +59,7 @@ int main(int argc, const char **argv) { InitLLVM X(argc, argv); // If argv[0] is or ends with 'gcov', always be gcov compatible - if (sys::path::stem(argv[0]).endswith_insensitive("gcov")) + if (sys::path::stem(argv[0]).ends_with_insensitive("gcov")) return gcovMain(argc, argv); // Check if we are invoking a specific tool command. diff --git a/contrib/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/contrib/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp index 06f0a25c0dff..2bbd57f14d99 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp @@ -7,16 +7,18 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Triple.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/StringViewExtras.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" #include <cstdlib> #include <iostream> @@ -70,10 +72,11 @@ static void error(const Twine &Message) { } static std::string demangle(const std::string &Mangled) { - const char *DecoratedStr = Mangled.c_str(); + using llvm::itanium_demangle::starts_with; + std::string_view DecoratedStr = Mangled; if (StripUnderscore) if (DecoratedStr[0] == '_') - ++DecoratedStr; + DecoratedStr.remove_prefix(1); std::string Result; if (nonMicrosoftDemangle(DecoratedStr, Result)) @@ -83,11 +86,11 @@ static std::string demangle(const std::string &Mangled) { char *Undecorated = nullptr; if (Types) - Undecorated = itaniumDemangle(DecoratedStr, nullptr, nullptr, nullptr); + Undecorated = itaniumDemangle(DecoratedStr); - if (!Undecorated && strncmp(DecoratedStr, "__imp_", 6) == 0) { + if (!Undecorated && starts_with(DecoratedStr, "__imp_")) { Prefix = "import thunk for "; - Undecorated = itaniumDemangle(DecoratedStr + 6, nullptr, nullptr, nullptr); + Undecorated = itaniumDemangle(DecoratedStr.substr(6)); } Result = Undecorated ? Prefix + Undecorated : Mangled; @@ -145,7 +148,7 @@ static void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) { OS.flush(); } -int llvm_cxxfilt_main(int argc, char **argv) { +int llvm_cxxfilt_main(int argc, char **argv, const llvm::ToolContext &) { InitLLVM X(argc, argv); BumpPtrAllocator A; StringSaver Saver(A); diff --git a/contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp b/contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp index 1e18e379f23c..6a5646965df2 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp @@ -14,12 +14,12 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ProfileData/SymbolRemappingReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/SymbolRemappingReader.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" diff --git a/contrib/llvm-project/llvm/tools/llvm-debuginfo-analyzer/README.txt b/contrib/llvm-project/llvm/tools/llvm-debuginfo-analyzer/README.txt new file mode 100644 index 000000000000..e6c20db7cd71 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-debuginfo-analyzer/README.txt @@ -0,0 +1,224 @@ +//===- llvm/tools/llvm-debuginfo-analyzer/README.txt ----------------------===// +// +// 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 contains notes collected during the development, review and test. +// It describes limitations, know issues and future work. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Remove the use of macros in 'LVReader.h' that describe the bumpallocators. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D137933#inline-1389904 + +Use a standard (or LLVM) map with typeinfo (would need a specialization +to expose equality and hasher) for the allocators and the creation +functions could be a function template. + +//===----------------------------------------------------------------------===// +// Use a lit test instead of a unit test for the logical readers. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125783#inline-1324376 + +As the DebugInfoLogicalView library is sufficiently exposed via the +llvm-debuginfo-analyzer tool, follow the LLVM general approach and +use LIT tests to validate the logical readers. + +Convert the unitests: + llvm-project/llvm/unittests/DebugInfo/LogicalView/CodeViewReaderTest.cpp + llvm-project/llvm/unittests/DebugInfo/LogicalView/ELFReaderTest.cpp + +into LIT tests: + llvm-project/llvm/test/DebugInfo/LogicalView/CodeViewReader.test + llvm-project/llvm/test/DebugInfo/LogicalView/ELFReader.test + +//===----------------------------------------------------------------------===// +// Eliminate calls to 'getInputFileDirectory()' in the unit tests. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125783#inline-1324359 + +Rewrite the unittests 'LFReaderTest' and 'CodeViewReaderTest'to eliminate +the call: + + getInputFileDirectory() + +as use of that call is discouraged. + +See: Use a lit test instead of a unit test for the logical readers. + +//===----------------------------------------------------------------------===// +// Fix mismatch between %d/%x format strings and uint64_t type. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D137400 +https://github.com/llvm/llvm-project/issues/58758 + +Incorrect printing of uint64_t on 32-bit platforms. +Add the PRIx64 specifier to the printing code (format()). + +//===----------------------------------------------------------------------===// +// Remove 'LVScope::Children' container. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D137933#inline-1373902 + +Use a chaining iterator over the other containers rather than keep a +separate container 'Children' that mirrors their contents. + +//===----------------------------------------------------------------------===// +// Use TableGen for command line options. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125777#inline-1291801 + +The current trend is to use TableGen for command-line options in tools. +Change command line options to use tablegen as many other LLVM tools. + +//===----------------------------------------------------------------------===// +// LVDoubleMap to return optional<ValueType> instead of null pointer. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125783#inline-1294164 + +The more idiomatic LLVM way to handle this would be to have 'find ' +return Optional<ValueType>. + +//===----------------------------------------------------------------------===// +// Pass references instead of pointers (Comparison functions). +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125782#inline-1293920 + +In the comparison functions, pass references instead of pointers (when +pointers cannot be null). + +//===----------------------------------------------------------------------===// +// Use StringMap where possible. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125783#inline-1294211 + +LLVM has a StringMap class that is advertised as more efficient than +std::map<std::string, ValueType>. Mainly it does fewer allocations +because the key is not a std::string. + +Replace the use of std::map<std::string, ValueType> with String Map. +One specific case is the LVSymbolNames definitions. + +//===----------------------------------------------------------------------===// +// Calculate unique offset for CodeView elements. +//===----------------------------------------------------------------------===// +In order to have the same logical functionality as the ELF Reader, such +as: + +- find scopes contribution to debug info +- sort by its physical location + +The logical elements must have an unique offset (similar like the DWARF +DIE offset). + +//===----------------------------------------------------------------------===// +// Move 'initializeFileAndStringTables' to the COFF Library. +//===----------------------------------------------------------------------===// +There is some code in the CodeView reader that was extracted/adapted +from 'tools/llvm-readobj/COFFDumper.cpp' that can be moved to the COFF +library. + +We had a similar case with code shared with llvm-pdbutil that was moved +to the PDB library: https://reviews.llvm.org/D122226 + +//===----------------------------------------------------------------------===// +// Move 'getSymbolKindName'/'formatRegisterId' to the CodeView Library. +//===----------------------------------------------------------------------===// +There is some code in the CodeView reader that was extracted/adapted +from 'lib/DebugInfo/CodeView/SymbolDumper.cpp' that can be used. + +//===----------------------------------------------------------------------===// +// Use of std::unordered_set instead of std::set. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125784#inline-1221421 + +Replace the std::set usage for DeducedScopes, UnresolvedScopes and +IdentifiedNamespaces with std::unordered_set and get the benefit +of the O(1) while inserting/searching, as the order is not important. + +//===----------------------------------------------------------------------===// +// Optimize 'LVNamespaceDeduction::find' funtion. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125784#inline-1296195 + +Optimize the 'find' method to use the proposed code: + + LVStringRefs::iterator Iter = std::find_if(Components.begin(), Components.end(), + [](StringRef Name) { + return IdentifiedNamespaces.find(Name) == IdentifiedNamespaces.end(); + }); + LVStringRefs::size_type FirstNonNamespace = std::distance(Components.begin(), Iter); + +//===----------------------------------------------------------------------===// +// Move all the printing support to a common module. +//===----------------------------------------------------------------------===// +Factor out printing functionality from the logical elements into a +common module. + +//===----------------------------------------------------------------------===// +// Refactor 'LVBinaryReader::processLines'. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125783#inline-1246155 +https://reviews.llvm.org/D137156 + +During the traversal of the debug information sections, we created the +logical lines representing the disassembled instructions from the text +section and the logical lines representing the line records from the +debug line section. Using the ranges associated with the logical scopes, +we will allocate those logical lines to their logical scopes. + +Consider the case when any of those lines become orphans, causing +incorrect scope parent for disassembly or line records. + +//===----------------------------------------------------------------------===// +// Add support for '-ffunction-sections'. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125783#inline-1295012 + +Only linked executables are handled. It does not support relocatable +files compiled with -ffunction-sections. + +//===----------------------------------------------------------------------===// +// Add support for DWARF v5 .debug_names section. +// Add support for CodeView public symbols stream. +//===----------------------------------------------------------------------===// +https://reviews.llvm.org/D125783#inline-1294142 + +The ELF and CodeView readers use the public names information to create +the instructions (LVLineAssembler). Instead of relying on DWARF section +names (.debug_pubnames, .debug_names) and CodeView public symbol stream +(S_PUB32), the readers collects the needed information while processing +the debug information. + +If the object file supports the above section names and stream, use them +to create the public names. + +//===----------------------------------------------------------------------===// +// Add support for some extra DWARF locations. +//===----------------------------------------------------------------------===// +The following DWARF debug location operands are not supported: + +- DW_OP_const_type +- DW_OP_entry_value +- DW_OP_implicit_value + +//===----------------------------------------------------------------------===// +// Add support for additional binary formats. +//===----------------------------------------------------------------------===// +- WebAssembly (Wasm). + https://github.com/llvm/llvm-project/issues/57040#issuecomment-1211336680 + +- Extended COFF (XCOFF) + +//===----------------------------------------------------------------------===// +// Add support for JSON or YAML. +//===----------------------------------------------------------------------===// +The logical view uses its own and non-standard free form text when +displaying information on logical elements. + +//===----------------------------------------------------------------------===// diff --git a/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index 27330a571bbe..156e10c84ddd 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -11,9 +11,10 @@ //===----------------------------------------------------------------------===// #include "llvm-dwarfdump.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Triple.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" @@ -26,6 +27,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -34,6 +36,7 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" #include <cstdlib> using namespace llvm; @@ -171,6 +174,10 @@ static list<std::string> value_desc("name"), cat(DwarfDumpCategory)); static alias FindAlias("f", desc("Alias for --find."), aliasopt(Find), cl::NotHidden); +static opt<bool> FindAllApple( + "find-all-apple", + desc("Print every debug information entry in the accelerator tables."), + cat(DwarfDumpCategory)); static opt<bool> IgnoreCase("ignore-case", desc("Ignore case distinctions when using --name."), value_desc("i"), cat(DwarfDumpCategory)); @@ -453,6 +460,37 @@ static void filterByAccelName( Die.dump(OS, 0, DumpOpts); } +/// Print all DIEs in apple accelerator tables +static void findAllApple( + DWARFContext &DICtx, raw_ostream &OS, + std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) { + MapVector<StringRef, llvm::SmallSet<DWARFDie, 2>> NameToDies; + + auto PushDIEs = [&](const AppleAcceleratorTable &Accel) { + for (const auto &Entry : Accel.entries()) { + if (std::optional<uint64_t> Off = Entry.BaseEntry.getDIESectionOffset()) { + std::optional<StringRef> MaybeName = Entry.readName(); + DWARFDie Die = DICtx.getDIEForOffset(*Off); + if (Die && MaybeName) + NameToDies[*MaybeName].insert(Die); + } + } + }; + + PushDIEs(DICtx.getAppleNames()); + PushDIEs(DICtx.getAppleNamespaces()); + PushDIEs(DICtx.getAppleTypes()); + + DIDumpOptions DumpOpts = getDumpOpts(DICtx); + DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg; + for (const auto &[Name, Dies] : NameToDies) { + OS << llvm::formatv("\nApple accelerator entries with name = \"{0}\":\n", + Name); + for (DWARFDie Die : Dies) + Die.dump(OS, 0, DumpOpts); + } +} + /// Handle the --lookup option and dump the DIEs and line info for the given /// address. /// TODO: specified Address for --lookup option could relate for several @@ -625,6 +663,12 @@ static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, return true; } + // Handle the --find-all-apple option and lower it to --debug-info=<offset>. + if (FindAllApple) { + findAllApple(DICtx, OS, GetRegName); + return true; + } + // Dump the complete DWARF structure. auto DumpOpts = getDumpOpts(DICtx); DumpOpts.GetNameForDWARFReg = GetRegName; @@ -782,7 +826,7 @@ int main(int argc, char **argv) { // Unless dumping a specific DIE, default to --show-children. if (!ShowChildren && !Verify && !OffsetRequested && Name.empty() && - Find.empty()) + Find.empty() && !FindAllApple) ShowChildren = true; // Defaults to a.out if no filenames specified. diff --git a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp index ef222f8cc1a4..47a23e8448cc 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/DWARFLinker/DWARFLinker.h" #include "llvm/DWARFLinker/DWARFStreamer.h" +#include "llvm/DWARFLinkerParallel/DWARFLinker.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/Object/ObjectFile.h" @@ -37,11 +38,12 @@ namespace dwarfutil { // exec: [LowPC, HighPC] is not inside address ranges of .text sections // // universal: maxpc and bfd -class ObjFileAddressMap : public AddressesMap { +template <typename AddressMapBase> +class ObjFileAddressMap : public AddressMapBase { public: ObjFileAddressMap(DWARFContext &Context, const Options &Options, object::ObjectFile &ObjFile) - : Opts(Options), Context(Context) { + : Opts(Options) { // Remember addresses of existing text sections. for (const object::SectionRef &Sect : ObjFile.sections()) { if (!Sect.isText()) @@ -57,21 +59,29 @@ public: for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) { Expected<llvm::DWARFAddressRangesVector> ARanges = CU->getUnitDIE().getAddressRanges(); - if (ARanges) { - for (auto &Range : *ARanges) { - if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(), - Options.Tombstone, CU->getAddressByteSize())) - DWARFAddressRanges.insert({Range.LowPC, Range.HighPC}, 0); + if (!ARanges) { + llvm::consumeError(ARanges.takeError()); + continue; + } + + for (auto &Range : *ARanges) { + if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(), + Options.Tombstone, CU->getAddressByteSize())) { + HasValidAddressRanges = true; + break; } } + + if (HasValidAddressRanges) + break; } } // should be renamed into has valid address ranges - bool hasValidRelocs() override { return !DWARFAddressRanges.empty(); } + bool hasValidRelocs() override { return HasValidAddressRanges; } - bool isLiveSubprogram(const DWARFDie &DIE, - CompileUnit::DIEInfo &Info) override { + std::optional<int64_t> + getSubprogramRelocAdjustment(const DWARFDie &DIE) override { assert((DIE.getTag() == dwarf::DW_TAG_subprogram || DIE.getTag() == dwarf::DW_TAG_label) && "Wrong type of input die"); @@ -80,53 +90,44 @@ public: dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) { if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(), Opts.Tombstone, - DIE.getDwarfUnit()->getAddressByteSize())) { - Info.AddrAdjust = 0; - Info.InDebugMap = true; - return true; - } + DIE.getDwarfUnit()->getAddressByteSize())) + // Relocation value for the linked binary is 0. + return 0; } - return false; + return std::nullopt; } - bool isLiveVariable(const DWARFDie &DIE, - CompileUnit::DIEInfo &Info) override { - assert((DIE.getTag() == dwarf::DW_TAG_variable || - DIE.getTag() == dwarf::DW_TAG_constant) && - "Wrong type of input die"); - - if (Expected<DWARFLocationExpressionsVector> Loc = - DIE.getLocations(dwarf::DW_AT_location)) { - DWARFUnit *U = DIE.getDwarfUnit(); - for (const auto &Entry : *Loc) { - DataExtractor Data(toStringRef(Entry.Expr), - U->getContext().isLittleEndian(), 0); - DWARFExpression Expression(Data, U->getAddressByteSize(), - U->getFormParams().Format); - bool HasLiveAddresses = - any_of(Expression, [&](const DWARFExpression::Operation &Op) { - // TODO: add handling of dwarf::DW_OP_addrx - return !Op.isError() && - (Op.getCode() == dwarf::DW_OP_addr && - !isDeadAddress(Op.getRawOperand(0), U->getVersion(), - Opts.Tombstone, - DIE.getDwarfUnit()->getAddressByteSize())); - }); - - if (HasLiveAddresses) { - Info.AddrAdjust = 0; - Info.InDebugMap = true; - return true; - } + std::optional<int64_t> getExprOpAddressRelocAdjustment( + DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset, + uint64_t EndOffset) override { + switch (Op.getCode()) { + default: { + assert(false && "Specified operation does not have address operand"); + } break; + case dwarf::DW_OP_const4u: + case dwarf::DW_OP_const8u: + case dwarf::DW_OP_const4s: + case dwarf::DW_OP_const8s: + case dwarf::DW_OP_addr: { + if (!isDeadAddress(Op.getRawOperand(0), U.getVersion(), Opts.Tombstone, + U.getAddressByteSize())) + // Relocation value for the linked binary is 0. + return 0; + } break; + case dwarf::DW_OP_constx: + case dwarf::DW_OP_addrx: { + if (std::optional<object::SectionedAddress> Address = + U.getAddrOffsetSectionItem(Op.getRawOperand(0))) { + if (!isDeadAddress(Address->Address, U.getVersion(), Opts.Tombstone, + U.getAddressByteSize())) + // Relocation value for the linked binary is 0. + return 0; } - } else { - // FIXME: missing DW_AT_location is OK here, but other errors should be - // reported to the user. - consumeError(Loc.takeError()); + } break; } - return false; + return std::nullopt; } bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override { @@ -134,33 +135,7 @@ public: return false; } - RangesTy &getValidAddressRanges() override { return DWARFAddressRanges; }; - - void clear() override { DWARFAddressRanges.clear(); } - - llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t StartOffset, - uint64_t EndOffset) override { - // No relocations in linked binary. Return just address value. - - const char *AddrPtr = - Context.getDWARFObj().getAddrSection().Data.data() + StartOffset; - support::endianness Endianess = - Context.getDWARFObj().isLittleEndian() ? support::little : support::big; - - assert(EndOffset > StartOffset); - switch (EndOffset - StartOffset) { - case 1: - return *AddrPtr; - case 2: - return support::endian::read16(AddrPtr, Endianess); - case 4: - return support::endian::read32(AddrPtr, Endianess); - case 8: - return support::endian::read64(AddrPtr, Endianess); - } - - llvm_unreachable("relocateIndexedAddr unhandled case!"); - } + void clear() override {} protected: // returns true if specified address range is inside address ranges @@ -228,10 +203,9 @@ protected: } private: - RangesTy DWARFAddressRanges; AddressRanges TextAddressRanges; const Options &Opts; - DWARFContext &Context; + bool HasValidAddressRanges = false; }; static bool knownByDWARFUtil(StringRef SecName) { @@ -258,12 +232,13 @@ static bool knownByDWARFUtil(StringRef SecName) { .Default(false); } -static std::optional<DwarfLinkerAccelTableKind> +template <typename AccelTableKind> +static std::optional<AccelTableKind> getAcceleratorTableKind(StringRef SecName) { - return llvm::StringSwitch<std::optional<DwarfLinkerAccelTableKind>>(SecName) - .Case(".debug_pubnames", DwarfLinkerAccelTableKind::Pub) - .Case(".debug_pubtypes", DwarfLinkerAccelTableKind::Pub) - .Case(".debug_names", DwarfLinkerAccelTableKind::DebugNames) + return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName) + .Case(".debug_pubnames", AccelTableKind::Pub) + .Case(".debug_pubtypes", AccelTableKind::Pub) + .Case(".debug_names", AccelTableKind::DebugNames) .Default(std::nullopt); } @@ -309,9 +284,9 @@ static std::string getMessageForDeletedAcceleratorTables( return Message; } -Error linkDebugInfo(object::ObjectFile &File, const Options &Options, - raw_pwrite_stream &OutStream) { - +template <typename Linker, typename OutDwarfFile, typename AddressMapBase> +Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options, + raw_pwrite_stream &OutStream) { auto ReportWarn = [&](const Twine &Message, StringRef Context, const DWARFDie *Die) { warning(Message, Context); @@ -331,39 +306,33 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options, WithColor::error(errs(), Context) << Message << '\n'; }; - // Create output streamer. - DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr, - ReportWarn, ReportWarn); + // Create DWARF linker. + std::unique_ptr<Linker> DebugInfoLinker = + Linker::createLinker(ReportErr, ReportWarn); + Triple TargetTriple = File.makeTriple(); - if (!OutStreamer.init(TargetTriple, formatv("cannot create a stream for {0}", - TargetTriple.getTriple()) - .str())) - return createStringError(std::errc::invalid_argument, ""); + if (Error Err = DebugInfoLinker->createEmitter( + TargetTriple, Linker::OutputFileType::Object, OutStream)) + return Err; - std::unique_ptr<DWARFContext> Context = DWARFContext::create(File); + DebugInfoLinker->setEstimatedObjfilesAmount(1); + DebugInfoLinker->setNumThreads(Options.NumThreads); + DebugInfoLinker->setNoODR(!Options.DoODRDeduplication); + DebugInfoLinker->setVerbosity(Options.Verbose); + DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection); - // Create DWARF linker. - DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD); - - DebugInfoLinker.setEstimatedObjfilesAmount(1); - DebugInfoLinker.setErrorHandler(ReportErr); - DebugInfoLinker.setWarningHandler(ReportWarn); - DebugInfoLinker.setNumThreads(Options.NumThreads); - DebugInfoLinker.setNoODR(!Options.DoODRDeduplication); - DebugInfoLinker.setVerbosity(Options.Verbose); - DebugInfoLinker.setUpdate(!Options.DoGarbageCollection); - - std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1); - std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1); + std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking(1); std::vector<std::string> EmptyWarnings; // Add object files to the DWARFLinker. - AddresssMapForLinking[0] = - std::make_unique<ObjFileAddressMap>(*Context, Options, File); + std::unique_ptr<DWARFContext> Context = DWARFContext::create(File); + std::unique_ptr<ObjFileAddressMap<AddressMapBase>> AddressesMap( + std::make_unique<ObjFileAddressMap<AddressMapBase>>(*Context, Options, + File)); - ObjectsForLinking[0] = std::make_unique<DWARFFile>( - File.getFileName(), &*Context, AddresssMapForLinking[0].get(), - EmptyWarnings); + ObjectsForLinking[0] = + std::make_unique<OutDwarfFile>(File.getFileName(), std::move(Context), + std::move(AddressesMap), EmptyWarnings); uint16_t MaxDWARFVersion = 0; std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded = @@ -372,17 +341,17 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options, }; for (size_t I = 0; I < ObjectsForLinking.size(); I++) - DebugInfoLinker.addObjectFile(*ObjectsForLinking[I], nullptr, - OnCUDieLoaded); + DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr, + OnCUDieLoaded); // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway. if (MaxDWARFVersion == 0) MaxDWARFVersion = 3; - if (Error Err = DebugInfoLinker.setTargetDWARFVersion(MaxDWARFVersion)) + if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion)) return Err; - SmallVector<DwarfLinkerAccelTableKind> AccelTables; + SmallVector<typename Linker::AccelTableKind> AccelTables; switch (Options.AccelTableKind) { case DwarfUtilAccelKind::None: @@ -390,60 +359,74 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options, break; case DwarfUtilAccelKind::DWARF: // use .debug_names for all DWARF versions. - AccelTables.push_back(DwarfLinkerAccelTableKind::DebugNames); + AccelTables.push_back(Linker::AccelTableKind::DebugNames); break; } // Add accelerator tables to DWARFLinker. - for (DwarfLinkerAccelTableKind Table : AccelTables) - DebugInfoLinker.addAccelTableKind(Table); - - SmallVector<StringRef> AccelTableNamesToReplace; - SmallVector<StringRef> AccelTableNamesToDelete; - - // Unknown debug sections or non-requested accelerator sections would be - // removed. Display warning for such sections. - for (SectionName Sec : Context->getDWARFObj().getSectionNames()) { - if (isDebugSection(Sec.Name)) { - std::optional<DwarfLinkerAccelTableKind> SrcAccelTableKind = - getAcceleratorTableKind(Sec.Name); - - if (SrcAccelTableKind) { - assert(knownByDWARFUtil(Sec.Name)); - - if (Options.AccelTableKind == DwarfUtilAccelKind::None) - AccelTableNamesToDelete.push_back(Sec.Name); - else if (std::find(AccelTables.begin(), AccelTables.end(), - *SrcAccelTableKind) == AccelTables.end()) - AccelTableNamesToReplace.push_back(Sec.Name); - } else if (!knownByDWARFUtil(Sec.Name)) { - assert(!SrcAccelTableKind); - warning( - formatv("'{0}' is not currently supported: section will be skipped", - Sec.Name), - Options.InputFileName); + for (typename Linker::AccelTableKind Table : AccelTables) + DebugInfoLinker->addAccelTableKind(Table); + + for (std::unique_ptr<OutDwarfFile> &CurFile : ObjectsForLinking) { + SmallVector<StringRef> AccelTableNamesToReplace; + SmallVector<StringRef> AccelTableNamesToDelete; + + // Unknown debug sections or non-requested accelerator sections would be + // removed. Display warning for such sections. + for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) { + if (isDebugSection(Sec.Name)) { + std::optional<typename Linker::AccelTableKind> SrcAccelTableKind = + getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name); + + if (SrcAccelTableKind) { + assert(knownByDWARFUtil(Sec.Name)); + + if (Options.AccelTableKind == DwarfUtilAccelKind::None) + AccelTableNamesToDelete.push_back(Sec.Name); + else if (!llvm::is_contained(AccelTables, *SrcAccelTableKind)) + AccelTableNamesToReplace.push_back(Sec.Name); + } else if (!knownByDWARFUtil(Sec.Name)) { + assert(!SrcAccelTableKind); + warning( + formatv( + "'{0}' is not currently supported: section will be skipped", + Sec.Name), + Options.InputFileName); + } } } - } - // Display message for the replaced accelerator tables. - if (!AccelTableNamesToReplace.empty()) - warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace, - Options.AccelTableKind), - Options.InputFileName); + // Display message for the replaced accelerator tables. + if (!AccelTableNamesToReplace.empty()) + warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace, + Options.AccelTableKind), + Options.InputFileName); - // Display message for the removed accelerator tables. - if (!AccelTableNamesToDelete.empty()) - warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete), - Options.InputFileName); + // Display message for the removed accelerator tables. + if (!AccelTableNamesToDelete.empty()) + warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete), + Options.InputFileName); + } // Link debug info. - if (Error Err = DebugInfoLinker.link()) + if (Error Err = DebugInfoLinker->link()) return Err; - OutStreamer.finish(); + DebugInfoLinker->getEmitter()->finish(); return Error::success(); } +Error linkDebugInfo(object::ObjectFile &File, const Options &Options, + raw_pwrite_stream &OutStream) { + if (Options.UseLLVMDWARFLinker) + return linkDebugInfoImpl<dwarflinker_parallel::DWARFLinker, + dwarflinker_parallel::DWARFFile, + dwarflinker_parallel::AddressesMap>(File, Options, + OutStream); + else + return linkDebugInfoImpl<DWARFLinker, DWARFFile, AddressesMap>( + File, Options, OutStream); +} + } // end of namespace dwarfutil } // end of namespace llvm diff --git a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Error.h b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Error.h index 9ef288d4f657..b92c50ca5a45 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Error.h +++ b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Error.h @@ -12,12 +12,12 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Triple.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" namespace llvm { namespace dwarfutil { diff --git a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Options.h b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Options.h index 38fa2b9eda63..e97833bdd79e 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Options.h +++ b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Options.h @@ -40,6 +40,7 @@ struct Options { bool Verbose = false; int NumThreads = 0; bool Verify = false; + bool UseLLVMDWARFLinker = false; DwarfUtilAccelKind AccelTableKind = DwarfUtilAccelKind::None; std::string getSeparateDebugFileName() const { diff --git a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Options.td b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Options.td index d4541188c0c2..26b9ac678b6a 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Options.td +++ b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/Options.td @@ -20,6 +20,11 @@ def h : Flag<["-"], "h">, Alias<help>, HelpText<"Alias for --help">; +def linker: Separate<["--", "-"], "linker">, + MetaVarName<"<DWARF linker type>">, + HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">; +def: Joined<["--", "-"], "linker=">, Alias<linker>; + defm odr_deduplication : BB<"odr-deduplication", "Do ODR deduplication for debug types(default)", "Don`t do ODR deduplication for debug types">; diff --git a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp index 74b6104bc668..1c7627179795 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp @@ -123,6 +123,18 @@ static Error validateAndSetOptions(opt::InputArgList &Args, Options &Options) { formatv("unknown tombstone value: '{0}'", S).str().c_str()); } + if (opt::Arg *LinkerKind = Args.getLastArg(OPT_linker)) { + StringRef S = LinkerKind->getValue(); + if (S == "apple") + Options.UseLLVMDWARFLinker = false; + else if (S == "llvm") + Options.UseLLVMDWARFLinker = true; + else + return createStringError( + std::errc::invalid_argument, + formatv("unknown linker kind value: '{0}'", S).str().c_str()); + } + if (opt::Arg *BuildAccelerator = Args.getLastArg(OPT_build_accelerator)) { StringRef S = BuildAccelerator->getValue(); diff --git a/contrib/llvm-project/llvm/tools/llvm-dwp/Opts.td b/contrib/llvm-project/llvm/tools/llvm-dwp/Opts.td new file mode 100644 index 000000000000..c01fa4a12cba --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-dwp/Opts.td @@ -0,0 +1,13 @@ +include "llvm/Option/OptParser.td" + +class F<string name, string help> : Flag<["-", "--"], name>, HelpText<help>; +class S<string name, string help> : Separate<["-", "--"], name>, HelpText<help>; + +def help : F<"help", "Display this help">; +def : F<"h", "Alias for --help">, Alias<help>; +def version : F<"version", "Display the version of this program">; + +def execFileNames : S<"e", "Specify the executable/library files to get the list of *.dwo from.">, MetaVarName<"<filename>">; +def outputFileName : S<"o", "Specify the output file.">, MetaVarName<"<filename>">; +def continueOnCuIndexOverflow: F<"continue-on-cu-index-overflow", "This turns an error when offset for .debug_*.dwo sections " + "overfolws into a warning.">, MetaVarName<"<filename>">; diff --git a/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp b/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp index 0a2c1c1ccc02..350a37345e2c 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp @@ -23,6 +23,8 @@ #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptionsCommandFlags.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" @@ -36,20 +38,46 @@ using namespace llvm::object; static mc::RegisterMCTargetOptionsFlags MCTargetOptionsFlags; -cl::OptionCategory DwpCategory("Specific Options"); -static cl::list<std::string> - InputFiles(cl::Positional, cl::desc("<input files>"), cl::cat(DwpCategory)); +// Command-line option boilerplate. +namespace { +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Opts.inc" +#undef OPTION +}; -static cl::list<std::string> ExecFilenames( - "e", - cl::desc( - "Specify the executable/library files to get the list of *.dwo from"), - cl::value_desc("filename"), cl::cat(DwpCategory)); +#define PREFIX(NAME, VALUE) \ + static constexpr StringLiteral NAME##_init[] = VALUE; \ + static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ + std::size(NAME##_init) - 1); +#include "Opts.inc" +#undef PREFIX -static cl::opt<std::string> OutputFilename(cl::Required, "o", - cl::desc("Specify the output file."), - cl::value_desc("filename"), - cl::cat(DwpCategory)); +static constexpr opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + { \ + PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Opts.inc" +#undef OPTION +}; + +class DwpOptTable : public opt::GenericOptTable { +public: + DwpOptTable() : GenericOptTable(InfoTable) {} +}; +} // end anonymous namespace + +// Options +static std::vector<std::string> ExecFilenames; +static std::string OutputFilename; +static bool ContinueOnCuIndexOverflow; static Expected<SmallVector<std::string, 16>> getDWOFilenames(StringRef ExecFilename) { @@ -100,15 +128,41 @@ static Expected<Triple> readTargetTriple(StringRef FileName) { int main(int argc, char **argv) { InitLLVM X(argc, argv); - cl::HideUnrelatedOptions({&DwpCategory, &getColorCategory()}); - cl::ParseCommandLineOptions(argc, argv, "merge split dwarf (.dwo) files\n"); + DwpOptTable Tbl; + llvm::BumpPtrAllocator A; + llvm::StringSaver Saver{A}; + opt::InputArgList Args = + Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { + llvm::errs() << Msg << '\n'; + std::exit(1); + }); + + if (Args.hasArg(OPT_help)) { + Tbl.printHelp(llvm::outs(), "llvm-dwp [options] <input files>", + "merge split dwarf (.dwo) files"); + std::exit(0); + } + + if (Args.hasArg(OPT_version)) { + llvm::cl::PrintVersionMessage(); + std::exit(0); + } + + OutputFilename = Args.getLastArgValue(OPT_outputFileName, ""); + ContinueOnCuIndexOverflow = Args.hasArg(OPT_continueOnCuIndexOverflow); + + for (const llvm::opt::Arg *A : Args.filtered(OPT_execFileNames)) + ExecFilenames.emplace_back(A->getValue()); + + std::vector<std::string> DWOFilenames; + for (const llvm::opt::Arg *A : Args.filtered(OPT_INPUT)) + DWOFilenames.emplace_back(A->getValue()); llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllTargets(); llvm::InitializeAllAsmPrinters(); - std::vector<std::string> DWOFilenames = InputFiles; for (const auto &ExecFilename : ExecFilenames) { auto DWOs = getDWOFilenames(ExecFilename); if (!DWOs) { @@ -207,7 +261,7 @@ int main(int argc, char **argv) { if (!MS) return error("no object streamer for target " + TripleName, Context); - if (auto Err = write(*MS, DWOFilenames)) { + if (auto Err = write(*MS, DWOFilenames, ContinueOnCuIndexOverflow)) { logAllUnhandledErrors(std::move(Err), WithColor::error()); return 1; } diff --git a/contrib/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp b/contrib/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp index 79e9d93061a2..51921d44d748 100644 --- a/contrib/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp @@ -516,11 +516,10 @@ static void getThinLTOOldAndNewPrefix(std::string &OldPrefix, /// Given the original \p Path to an output file, replace any path /// prefix matching \p OldPrefix with \p NewPrefix. Also, create the /// resulting directory if it does not yet exist. -static std::string getThinLTOOutputFile(const std::string &Path, - const std::string &OldPrefix, - const std::string &NewPrefix) { +static std::string getThinLTOOutputFile(StringRef Path, StringRef OldPrefix, + StringRef NewPrefix) { if (OldPrefix.empty() && NewPrefix.empty()) - return Path; + return std::string(Path); SmallString<128> NewPath(Path); llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix); StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str()); diff --git a/contrib/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp b/contrib/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp index 09c74fc586f5..81c97a994038 100644 --- a/contrib/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -167,10 +167,6 @@ static cl::opt<bool> cl::desc("Run PGO context sensitive IR instrumentation"), cl::Hidden); -static cl::opt<bool> LtoOpaquePointers("lto-opaque-pointers", - cl::desc("Enable opaque pointer types"), - cl::init(true), cl::Hidden); - static cl::opt<bool> DebugPassManager("debug-pass-manager", cl::Hidden, cl::desc("Print pass management debugging information")); @@ -182,6 +178,10 @@ static cl::list<std::string> PassPlugins("load-pass-plugin", cl::desc("Load passes from plugin library")); +static cl::opt<std::string> UnifiedLTOMode("unified-lto", cl::Optional, + cl::desc("Set LTO mode"), + cl::value_desc("mode")); + static cl::opt<bool> EnableFreestanding( "lto-freestanding", cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"), @@ -321,15 +321,15 @@ static int run(int argc, char **argv) { Conf.StatsFile = StatsFile; Conf.PTO.LoopVectorization = Conf.OptLevel > 1; Conf.PTO.SLPVectorization = Conf.OptLevel > 1; - Conf.OpaquePointers = LtoOpaquePointers; ThinBackend Backend; if (ThinLTODistributedIndexes) - Backend = - createWriteIndexesThinBackend(/* OldPrefix */ "", - /* NewPrefix */ "", ThinLTOEmitImports, - /* LinkedObjectsFile */ nullptr, - /* OnWrite */ {}); + Backend = createWriteIndexesThinBackend(/*OldPrefix=*/"", + /*NewPrefix=*/"", + /*NativeObjectPrefix=*/"", + ThinLTOEmitImports, + /*LinkedObjectsFile=*/nullptr, + /*OnWrite=*/{}); else Backend = createInProcessThinBackend( llvm::heavyweight_hardware_concurrency(Threads), @@ -352,7 +352,20 @@ static int run(int argc, char **argv) { HasErrors = true; }; - LTO Lto(std::move(Conf), std::move(Backend)); + LTO::LTOKind LTOMode = LTO::LTOK_Default; + + if (UnifiedLTOMode == "full") { + LTOMode = LTO::LTOK_UnifiedRegular; + } else if (UnifiedLTOMode == "thin") { + LTOMode = LTO::LTOK_UnifiedThin; + } else if (UnifiedLTOMode == "default") { + LTOMode = LTO::LTOK_Default; + } else if (!UnifiedLTOMode.empty()) { + llvm::errs() << "invalid LTO mode\n"; + return 1; + } + + LTO Lto(std::move(Conf), std::move(Backend), 1, LTOMode); for (std::string F : InputFilenames) { std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F); diff --git a/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp b/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp index 2d1833429718..7456a2f2c915 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "Disassembler.h" -#include "llvm/ADT/Triple.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" @@ -25,6 +24,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" using namespace llvm; diff --git a/contrib/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp b/contrib/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp index dd5a66a6eb7d..572723afb79e 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp @@ -31,13 +31,13 @@ #include "llvm/Support/Compression.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/FormattedStream.h" -#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/WithColor.h" +#include "llvm/TargetParser/Host.h" using namespace llvm; diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp index c91ed759ee77..ba5188076c2e 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp @@ -115,7 +115,7 @@ void AnalysisRegions::endRegion(StringRef Description, SMLoc Loc) { InstrumentRegions::InstrumentRegions(llvm::SourceMgr &S) : CodeRegions(S) {} void InstrumentRegions::beginRegion(StringRef Description, SMLoc Loc, - SharedInstrument I) { + UniqueInstrument I) { if (Description.empty()) { SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error, "anonymous instrumentation regions are not permitted"); @@ -137,7 +137,8 @@ void InstrumentRegions::beginRegion(StringRef Description, SMLoc Loc, } ActiveRegions[Description] = Regions.size(); - Regions.emplace_back(std::make_unique<InstrumentRegion>(Description, Loc, I)); + Regions.emplace_back( + std::make_unique<InstrumentRegion>(Description, Loc, std::move(I))); } void InstrumentRegions::endRegion(StringRef Description, SMLoc Loc) { @@ -158,13 +159,13 @@ void InstrumentRegions::endRegion(StringRef Description, SMLoc Loc) { } } -const SmallVector<SharedInstrument> +const SmallVector<Instrument *> InstrumentRegions::getActiveInstruments(SMLoc Loc) const { - SmallVector<SharedInstrument> AI; + SmallVector<Instrument *> AI; for (auto &R : Regions) { if (R->isLocInRange(Loc)) { InstrumentRegion *IR = static_cast<InstrumentRegion *>(R.get()); - AI.emplace_back(IR->getInstrument()); + AI.push_back(IR->getInstrument()); } } return AI; diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.h b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.h index b5b2f3a0d118..ce107fd8f3b6 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.h +++ b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.h @@ -91,6 +91,8 @@ public: CodeRegion(llvm::StringRef Desc, llvm::SMLoc Start) : Description(Desc), RangeStart(Start) {} + virtual ~CodeRegion() = default; + void addInstruction(const llvm::MCInst &Instruction) { Instructions.emplace_back(Instruction); } @@ -115,14 +117,14 @@ using AnalysisRegion = CodeRegion; /// in analysis of the region. class InstrumentRegion : public CodeRegion { /// Instrument for this region. - SharedInstrument Instrument; + UniqueInstrument I; public: - InstrumentRegion(llvm::StringRef Desc, llvm::SMLoc Start, SharedInstrument I) - : CodeRegion(Desc, Start), Instrument(I) {} + InstrumentRegion(llvm::StringRef Desc, llvm::SMLoc Start, UniqueInstrument I) + : CodeRegion(Desc, Start), I(std::move(I)) {} public: - SharedInstrument getInstrument() const { return Instrument; } + Instrument *getInstrument() const { return I.get(); } }; class CodeRegionParseError final : public Error {}; @@ -142,6 +144,7 @@ protected: public: CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {} + virtual ~CodeRegions() = default; typedef std::vector<UniqueCodeRegion>::iterator iterator; typedef std::vector<UniqueCodeRegion>::const_iterator const_iterator; @@ -167,26 +170,34 @@ public: bool isValid() const { return !FoundErrors; } bool isRegionActive(llvm::StringRef Description) const { - return ActiveRegions.find(Description) != ActiveRegions.end(); + return ActiveRegions.contains(Description); } + + virtual void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) = 0; + virtual void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc, + UniqueInstrument Instrument) = 0; + virtual void endRegion(llvm::StringRef Description, llvm::SMLoc Loc) = 0; }; struct AnalysisRegions : public CodeRegions { AnalysisRegions(llvm::SourceMgr &S); - void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc); - void endRegion(llvm::StringRef Description, llvm::SMLoc Loc); + void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) override; + void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc, + UniqueInstrument Instrument) override {} + void endRegion(llvm::StringRef Description, llvm::SMLoc Loc) override; }; struct InstrumentRegions : public CodeRegions { + InstrumentRegions(llvm::SourceMgr &S); + void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) override{}; void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc, - SharedInstrument Instrument); - void endRegion(llvm::StringRef Description, llvm::SMLoc Loc); + UniqueInstrument Instrument) override; + void endRegion(llvm::StringRef Description, llvm::SMLoc Loc) override; - const SmallVector<SharedInstrument> - getActiveInstruments(llvm::SMLoc Loc) const; + const SmallVector<Instrument *> getActiveInstruments(llvm::SMLoc Loc) const; }; } // namespace mca diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp index b8e10fa69c2d..5241b584b746 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" -#include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/Error.h" #include "llvm/Support/SMLoc.h" @@ -29,46 +28,12 @@ namespace mca { // This virtual dtor serves as the anchor for the CodeRegionGenerator class. CodeRegionGenerator::~CodeRegionGenerator() {} -// This class provides the callbacks that occur when parsing input assembly. -class MCStreamerWrapper final : public MCStreamer { - CodeRegions &Regions; - -public: - MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) - : MCStreamer(Context), Regions(R) {} - - // We only want to intercept the emission of new instructions. - void emitInstruction(const MCInst &Inst, - const MCSubtargetInfo & /* unused */) override { - Regions.addInstruction(Inst); - } - - bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { - return true; - } - - void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - Align ByteAlignment) override {} - void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, - uint64_t Size = 0, Align ByteAlignment = Align(1), - SMLoc Loc = SMLoc()) override {} - void emitGPRel32Value(const MCExpr *Value) override {} - void beginCOFFSymbolDef(const MCSymbol *Symbol) override {} - void emitCOFFSymbolStorageClass(int StorageClass) override {} - void emitCOFFSymbolType(int Type) override {} - void endCOFFSymbolDef() override {} - - ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const { - return Regions.getInstructionSequence(Index); - } -}; - Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions( const std::unique_ptr<MCInstPrinter> &IP) { MCTargetOptions Opts; Opts.PreserveAsmComments = false; CodeRegions &Regions = getRegions(); - MCStreamerWrapper Str(Ctx, Regions); + MCStreamerWrapper *Str = getMCStreamer(); // Need to initialize an MCTargetStreamer otherwise // certain asm directives will cause a segfault. @@ -76,13 +41,13 @@ Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions( // doesn't show up in the llvm-mca output. raw_ostream &OSRef = nulls(); formatted_raw_ostream FOSRef(OSRef); - TheTarget.createAsmTargetStreamer(Str, FOSRef, IP.get(), + TheTarget.createAsmTargetStreamer(*Str, FOSRef, IP.get(), /*IsVerboseAsm=*/true); // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM // comments. std::unique_ptr<MCAsmParser> Parser( - createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI)); + createMCAsmParser(Regions.getSourceMgr(), Ctx, *Str, MAI)); MCAsmLexer &Lexer = Parser->getLexer(); MCACommentConsumer *CCP = getCommentConsumer(); Lexer.setCommentConsumer(CCP); @@ -184,7 +149,7 @@ void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc, return; } - SharedInstrument I = IM.createInstrument(InstrumentKind, Data); + UniqueInstrument I = IM.createInstrument(InstrumentKind, Data); if (!I) { if (Data.empty()) SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error, @@ -202,7 +167,7 @@ void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc, if (Regions.isRegionActive(InstrumentKind)) Regions.endRegion(InstrumentKind, Loc); // Start new instrumentation region - Regions.beginRegion(InstrumentKind, Loc, I); + Regions.beginRegion(InstrumentKind, Loc, std::move(I)); } } // namespace mca diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.h b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.h index 88621ed856c5..68da567f3e0f 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.h +++ b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.h @@ -20,6 +20,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/MCA/CustomBehaviour.h" @@ -32,10 +33,10 @@ namespace mca { class MCACommentConsumer : public AsmCommentConsumer { protected: - bool FoundError; + bool FoundError = false; public: - MCACommentConsumer() : FoundError(false) {} + MCACommentConsumer() = default; bool hadErr() const { return FoundError; } }; @@ -77,6 +78,67 @@ public: /// region of type INSTRUMENATION_TYPE, then it will end the active /// one and begin a new one using the new data. void HandleComment(SMLoc Loc, StringRef CommentText) override; + + InstrumentManager &getInstrumentManager() { return IM; } +}; + +// This class provides the callbacks that occur when parsing input assembly. +class MCStreamerWrapper : public MCStreamer { +protected: + CodeRegions &Regions; + +public: + MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) + : MCStreamer(Context), Regions(R) {} + + // We only want to intercept the emission of new instructions. + void emitInstruction(const MCInst &Inst, + const MCSubtargetInfo & /* unused */) override { + Regions.addInstruction(Inst); + } + + bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { + return true; + } + + void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + Align ByteAlignment) override {} + void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, + uint64_t Size = 0, Align ByteAlignment = Align(1), + SMLoc Loc = SMLoc()) override {} + void emitGPRel32Value(const MCExpr *Value) override {} + void beginCOFFSymbolDef(const MCSymbol *Symbol) override {} + void emitCOFFSymbolStorageClass(int StorageClass) override {} + void emitCOFFSymbolType(int Type) override {} + void endCOFFSymbolDef() override {} + + ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const { + return Regions.getInstructionSequence(Index); + } +}; + +class InstrumentMCStreamer : public MCStreamerWrapper { + InstrumentManager &IM; + +public: + InstrumentMCStreamer(MCContext &Context, mca::InstrumentRegions &R, + InstrumentManager &IM) + : MCStreamerWrapper(Context, R), IM(IM) {} + + void emitInstruction(const MCInst &Inst, + const MCSubtargetInfo &MCSI) override { + MCStreamerWrapper::emitInstruction(Inst, MCSI); + + // We know that Regions is an InstrumentRegions by the constructor. + for (UniqueInstrument &I : IM.createInstruments(Inst)) { + StringRef InstrumentKind = I.get()->getDesc(); + // End InstrumentType region if one is open + if (Regions.isRegionActive(InstrumentKind)) + Regions.endRegion(InstrumentKind, Inst.getLoc()); + // Start new instrumentation region + Regions.beginRegion(InstrumentKind, Inst.getLoc(), std::move(I)); + } + } }; /// This abstract class is responsible for parsing the input given to @@ -121,19 +183,22 @@ public: /// generating a CodeRegions instance. class AsmCodeRegionGenerator : public virtual CodeRegionGenerator { const Target &TheTarget; - MCContext &Ctx; const MCAsmInfo &MAI; const MCSubtargetInfo &STI; const MCInstrInfo &MCII; unsigned AssemblerDialect; // This is set during parsing. +protected: + MCContext &Ctx; + public: AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A, const MCSubtargetInfo &S, const MCInstrInfo &I) - : TheTarget(T), Ctx(C), MAI(A), STI(S), MCII(I), AssemblerDialect(0) {} + : TheTarget(T), MAI(A), STI(S), MCII(I), AssemblerDialect(0), Ctx(C) {} virtual MCACommentConsumer *getCommentConsumer() = 0; virtual CodeRegions &getRegions() = 0; + virtual MCStreamerWrapper *getMCStreamer() = 0; unsigned getAssemblerDialect() const { return AssemblerDialect; } Expected<const CodeRegions &> @@ -143,16 +208,18 @@ public: class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator, public AsmCodeRegionGenerator { AnalysisRegionCommentConsumer CC; + MCStreamerWrapper Streamer; public: AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C, const MCAsmInfo &A, const MCSubtargetInfo &S, const MCInstrInfo &I) : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I), - CC(Regions) {} + CC(Regions), Streamer(Ctx, Regions) {} MCACommentConsumer *getCommentConsumer() override { return &CC; }; CodeRegions &getRegions() override { return Regions; }; + MCStreamerWrapper *getMCStreamer() override { return &Streamer; } Expected<const AnalysisRegions &> parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) override { @@ -172,6 +239,7 @@ public: class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator, public AsmCodeRegionGenerator { InstrumentRegionCommentConsumer CC; + InstrumentMCStreamer Streamer; public: AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM, @@ -179,10 +247,11 @@ public: const MCSubtargetInfo &S, const MCInstrInfo &I, InstrumentManager &IM) : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I), - CC(SM, Regions, IM) {} + CC(SM, Regions, IM), Streamer(Ctx, Regions, IM) {} MCACommentConsumer *getCommentConsumer() override { return &CC; }; CodeRegions &getRegions() override { return Regions; }; + MCStreamerWrapper *getMCStreamer() override { return &Streamer; } Expected<const InstrumentRegions &> parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) override { diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp index dc0a07e75e48..b254ccd6670f 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp @@ -52,7 +52,7 @@ void PressureTracker::getResourceUsers(uint64_t ResourceMask, const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID); for (unsigned I = 0, E = PRDesc.NumUnits; I < E; ++I) { const User U = getResourceUser(ProcResID, I); - if (U.second && IPI.find(U.first) != IPI.end()) + if (U.second && IPI.contains(U.first)) Users.emplace_back(U); } } @@ -69,7 +69,7 @@ void PressureTracker::handleInstructionIssuedEvent( for (const ResourceUse &Use : Event.UsedResources) { const ResourceRef &RR = Use.first; unsigned Index = ProcResID2ResourceUsersIndex[RR.first]; - Index += countTrailingZeros(RR.second); + Index += llvm::countr_zero(RR.second); ResourceUsers[Index] = std::make_pair(IID, Use.second.getNumerator()); } } diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h b/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h index cd5af0afcf5b..e709b25c3f76 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h @@ -146,19 +146,19 @@ public: SmallVectorImpl<User> &Users) const; unsigned getRegisterPressureCycles(unsigned IID) const { - assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!"); + assert(IPI.contains(IID) && "Instruction is not tracked!"); const InstructionPressureInfo &Info = IPI.find(IID)->second; return Info.RegisterPressureCycles; } unsigned getMemoryPressureCycles(unsigned IID) const { - assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!"); + assert(IPI.contains(IID) && "Instruction is not tracked!"); const InstructionPressureInfo &Info = IPI.find(IID)->second; return Info.MemoryPressureCycles; } unsigned getResourcePressureCycles(unsigned IID) const { - assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!"); + assert(IPI.contains(IID) && "Instruction is not tracked!"); const InstructionPressureInfo &Info = IPI.find(IID)->second; return Info.ResourcePressureCycles; } diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp index 257fdca8cb36..fea0c9b8455c 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp @@ -55,10 +55,7 @@ void InstructionInfoView::printView(raw_ostream &OS) const { } } - int Index = 0; - for (const auto &I : enumerate(zip(IIVD, Source))) { - const InstructionInfoViewData &IIVDEntry = std::get<0>(I.value()); - + for (const auto &[Index, IIVDEntry, Inst] : enumerate(IIVD, Source)) { TempStream << ' ' << IIVDEntry.NumMicroOpcodes << " "; if (IIVDEntry.NumMicroOpcodes < 10) TempStream << " "; @@ -92,7 +89,7 @@ void InstructionInfoView::printView(raw_ostream &OS) const { } if (PrintEncodings) { - StringRef Encoding(CE.getEncoding(I.index())); + StringRef Encoding(CE.getEncoding(Index)); unsigned EncodingSize = Encoding.size(); TempStream << " " << EncodingSize << (EncodingSize < 10 ? " " : " "); @@ -104,9 +101,7 @@ void InstructionInfoView::printView(raw_ostream &OS) const { FOS.flush(); } - const MCInst &Inst = std::get<1>(I.value()); TempStream << printInstructionString(Inst) << '\n'; - ++Index; } TempStream.flush(); @@ -122,8 +117,13 @@ void InstructionInfoView::collectData( InstructionInfoViewData &IIVDEntry = std::get<1>(I); const MCInstrDesc &MCDesc = MCII.get(Inst.getOpcode()); - // Obtain the scheduling class information from the instruction. - unsigned SchedClassID = MCDesc.getSchedClass(); + // Obtain the scheduling class information from the instruction + // and instruments. + auto IVecIt = InstToInstruments.find(&Inst); + unsigned SchedClassID = + IVecIt == InstToInstruments.end() + ? MCDesc.getSchedClass() + : IM.getSchedClassID(MCII, Inst, IVecIt->second); unsigned CPUID = SM.getProcessorID(); // Try to solve variant scheduling classes. diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h b/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h index bddd01a086b5..3befafda90a3 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h @@ -42,6 +42,7 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MCA/CodeEmitter.h" +#include "llvm/MCA/CustomBehaviour.h" #include "llvm/Support/raw_ostream.h" #define DEBUG_TYPE "llvm-mca" @@ -57,6 +58,10 @@ class InstructionInfoView : public InstructionView { bool PrintBarriers; using UniqueInst = std::unique_ptr<Instruction>; ArrayRef<UniqueInst> LoweredInsts; + const InstrumentManager &IM; + using InstToInstrumentsT = + DenseMap<const MCInst *, SmallVector<mca::Instrument *>>; + const InstToInstrumentsT &InstToInstruments; struct InstructionInfoViewData { unsigned NumMicroOpcodes = 0; @@ -77,10 +82,12 @@ public: bool ShouldPrintEncodings, llvm::ArrayRef<llvm::MCInst> S, llvm::MCInstPrinter &IP, ArrayRef<UniqueInst> LoweredInsts, - bool ShouldPrintBarriers) + bool ShouldPrintBarriers, const InstrumentManager &IM, + const InstToInstrumentsT &InstToInstruments) : InstructionView(ST, IP, S), MCII(II), CE(C), PrintEncodings(ShouldPrintEncodings), - PrintBarriers(ShouldPrintBarriers), LoweredInsts(LoweredInsts) {} + PrintBarriers(ShouldPrintBarriers), LoweredInsts(LoweredInsts), IM(IM), + InstToInstruments(InstToInstruments) {} void printView(llvm::raw_ostream &OS) const override; StringRef getNameAsString() const override { return "InstructionInfoView"; } diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp index 77b3ba0b7c8d..0f059bcc0a06 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp @@ -57,9 +57,9 @@ void ResourcePressureView::onEvent(const HWInstructionEvent &Event) { for (const std::pair<ResourceRef, ResourceCycles> &Use : IssueEvent.UsedResources) { const ResourceRef &RR = Use.first; - assert(Resource2VecIndex.find(RR.first) != Resource2VecIndex.end()); + assert(Resource2VecIndex.contains(RR.first)); unsigned R2VIndex = Resource2VecIndex[RR.first]; - R2VIndex += countTrailingZeros(RR.second); + R2VIndex += llvm::countr_zero(RR.second); ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second; ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second; } diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp index 5c05edbdea68..2eca48aadfd7 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp @@ -315,6 +315,10 @@ json::Value TimelineView::toJSON() const { json::Array TimelineInfo; for (const TimelineViewEntry &TLE : Timeline) { + // Check if the timeline-max-cycles has been reached. + if (!TLE.CycleRetired && TLE.CycleExecuted) + break; + TimelineInfo.push_back( json::Object({{"CycleDispatched", TLE.CycleDispatched}, {"CycleReady", TLE.CycleReady}, diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp index 33adf15fccaf..eb71cffba6dd 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp @@ -53,13 +53,13 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/WithColor.h" +#include "llvm/TargetParser/Host.h" using namespace llvm; @@ -571,11 +571,14 @@ int main(int argc, char **argv) { IPP->resetState(); + DenseMap<const MCInst *, SmallVector<mca::Instrument *>> + InstToInstruments; SmallVector<std::unique_ptr<mca::Instruction>> LoweredSequence; for (const MCInst &MCI : Insts) { SMLoc Loc = MCI.getLoc(); - const SmallVector<mca::SharedInstrument> Instruments = + const SmallVector<mca::Instrument *> Instruments = InstrumentRegions.getActiveInstruments(Loc); + InstToInstruments.insert({&MCI, Instruments}); Expected<std::unique_ptr<mca::Instruction>> Inst = IB.createInstruction(MCI, Instruments); @@ -621,7 +624,7 @@ int main(int argc, char **argv) { if (PrintInstructionInfoView) { Printer.addView(std::make_unique<mca::InstructionInfoView>( *STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence, - ShowBarriers)); + ShowBarriers, *IM, InstToInstruments)); } Printer.addView( std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts)); @@ -698,7 +701,7 @@ int main(int argc, char **argv) { if (PrintInstructionInfoView) Printer.addView(std::make_unique<mca::InstructionInfoView>( *STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence, - ShowBarriers)); + ShowBarriers, *IM, InstToInstruments)); // Fetch custom Views that are to be placed after the InstructionInfoView. // Refer to the comment paired with the CB->getStartViews(*IP, Insts); line diff --git a/contrib/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp b/contrib/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp index 55319d0e4c72..1f6a5d1ab806 100644 --- a/contrib/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp @@ -16,7 +16,6 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/XCOFF.h" #include "llvm/Demangle/Demangle.h" @@ -40,14 +39,16 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" -#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" #include <vector> using namespace llvm; @@ -293,22 +294,6 @@ bool operator==(const NMSymbol &A, const NMSymbol &B) { } } // anonymous namespace -static char isSymbolList64Bit(SymbolicFile &Obj) { - if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj)) - return Triple(IRObj->getTargetTriple()).isArch64Bit(); - if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj)) - return false; - if (XCOFFObjectFile *XCOFFObj = dyn_cast<XCOFFObjectFile>(&Obj)) - return XCOFFObj->is64Bit(); - if (isa<WasmObjectFile>(Obj)) - return false; - if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj)) - return Tapi->is64Bit(); - if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj)) - return MachO->is64Bit(); - return cast<ELFObjectFileBase>(Obj).getBytesInAddress() == 8; -} - static StringRef CurrentFilename; static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I); @@ -654,7 +639,7 @@ static void darwinPrintStab(MachOObjectFile *MachO, const NMSymbol &S) { static std::optional<std::string> demangle(StringRef Name) { std::string Demangled; - if (nonMicrosoftDemangle(Name.str().c_str(), Demangled)) + if (nonMicrosoftDemangle(Name, Demangled)) return Demangled; return std::nullopt; } @@ -722,7 +707,7 @@ static void printSymbolList(SymbolicFile &Obj, outs() << '\n' << CurrentFilename << ":\n"; } else if (OutputFormat == sysv) { outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n"; - if (isSymbolList64Bit(Obj)) + if (Obj.is64Bit()) outs() << "Name Value Class Type" << " Size Line Section\n"; else @@ -732,7 +717,7 @@ static void printSymbolList(SymbolicFile &Obj, } const char *printBlanks, *printDashes, *printFormat; - if (isSymbolList64Bit(Obj)) { + if (Obj.is64Bit()) { printBlanks = " "; printDashes = "----------------"; switch (AddressRadix) { @@ -1044,7 +1029,15 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { } static char getSymbolNMTypeChar(TapiFile &Obj, basic_symbol_iterator I) { - return 's'; + auto Type = cantFail(Obj.getSymbolType(I->getRawDataRefImpl())); + switch (Type) { + case SymbolRef::ST_Data: + return 'd'; + case SymbolRef::ST_Function: + return 't'; + default: + return 's'; + } } static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) { @@ -1671,8 +1664,8 @@ static bool shouldDump(SymbolicFile &Obj) { !isa<IRObjectFile>(Obj)) return true; - return isSymbolList64Bit(Obj) ? BitMode != BitModeTy::Bit32 - : BitMode != BitModeTy::Bit64; + return Obj.is64Bit() ? BitMode != BitModeTy::Bit32 + : BitMode != BitModeTy::Bit64; } static void getXCOFFExports(XCOFFObjectFile *XCOFFObj, @@ -1961,26 +1954,39 @@ static bool checkMachOAndArchFlags(SymbolicFile *O, StringRef Filename) { return true; } +static void printArchiveMap(iterator_range<Archive::symbol_iterator> &map, + StringRef Filename) { + for (auto I : map) { + Expected<Archive::Child> C = I.getMember(); + if (!C) { + error(C.takeError(), Filename); + break; + } + Expected<StringRef> FileNameOrErr = C->getName(); + if (!FileNameOrErr) { + error(FileNameOrErr.takeError(), Filename); + break; + } + StringRef SymName = I.getName(); + outs() << SymName << " in " << FileNameOrErr.get() << "\n"; + } + + outs() << "\n"; +} + static void dumpArchiveMap(Archive *A, StringRef Filename) { - Archive::symbol_iterator I = A->symbol_begin(); - Archive::symbol_iterator E = A->symbol_end(); - if (I != E) { + auto Map = A->symbols(); + if (!Map.empty()) { outs() << "Archive map\n"; - for (; I != E; ++I) { - Expected<Archive::Child> C = I->getMember(); - if (!C) { - error(C.takeError(), Filename); - break; - } - Expected<StringRef> FileNameOrErr = C->getName(); - if (!FileNameOrErr) { - error(FileNameOrErr.takeError(), Filename); - break; - } - StringRef SymName = I->getName(); - outs() << SymName << " in " << FileNameOrErr.get() << "\n"; - } - outs() << "\n"; + printArchiveMap(Map, Filename); + } + + auto ECMap = A->ec_symbols(); + if (!ECMap) { + warn(ECMap.takeError(), Filename); + } else if (!ECMap->empty()) { + outs() << "Archive EC map\n"; + printArchiveMap(*ECMap, Filename); } } @@ -2261,11 +2267,7 @@ static std::vector<NMSymbol> dumpSymbolNamesFromFile(StringRef Filename) { if (error(BufferOrErr.getError(), Filename)) return SymbolList; - // Always enable opaque pointers, to handle archives with mixed typed and - // opaque pointer bitcode files gracefully. As we're only reading symbols, - // the used pointer types don't matter. LLVMContext Context; - Context.setOpaquePointers(true); LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context; Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr); @@ -2302,7 +2304,7 @@ exportSymbolNamesFromFiles(const std::vector<std::string> &InputFilenames) { printExportSymbolList(SymbolList); } -int llvm_nm_main(int argc, char **argv) { +int llvm_nm_main(int argc, char **argv, const llvm::ToolContext &) { InitLLVM X(argc, argv); BumpPtrAllocator A; StringSaver Saver(A); diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp index 577b837320ae..265e4fc6073c 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -8,6 +8,7 @@ #include "ObjcopyOptions.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/COFF.h" @@ -331,7 +332,11 @@ static const StringMap<MachineInfo> TargetMap{ // SPARC {"elf32-sparc", {ELF::EM_SPARC, false, false}}, {"elf32-sparcel", {ELF::EM_SPARC, false, true}}, + // Hexagon {"elf32-hexagon", {ELF::EM_HEXAGON, false, true}}, + // LoongArch + {"elf32-loongarch", {ELF::EM_LOONGARCH, false, true}}, + {"elf64-loongarch", {ELF::EM_LOONGARCH, true, true}}, }; static Expected<TargetInfo> diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td index 0fddd443a4cc..a7e4263271d3 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td @@ -27,7 +27,7 @@ def O : JoinedOrSeparate<["-"], "O">, defm new_symbol_visibility : Eq<"new-symbol-visibility", "Visibility of " "symbols generated for binary input or added" " with --add-symbol unless otherwise" - " specified. The default value is 'default'.">; + " specified. The default value is 'default'">; def compress_debug_sections : Joined<["--"], "compress-debug-sections=">, @@ -37,7 +37,7 @@ def compress_debug_sections def : Flag<["--"], "compress-debug-sections">, Alias<compress_debug_sections>, AliasArgs<["zlib"]>; def decompress_debug_sections : Flag<["--"], "decompress-debug-sections">, - HelpText<"Decompress DWARF debug sections.">; + HelpText<"Decompress DWARF debug sections">; defm split_dwo : Eq<"split-dwo", "Equivalent to extract-dwo on the input file to " "<dwo-file>, then strip-dwo on the input file">, @@ -52,7 +52,7 @@ defm rename_section "Renames a section from old to new, optionally with specified flags. " "Flags supported for GNU compatibility: alloc, load, noload, " "readonly, exclude, debug, code, data, rom, share, contents, merge, " - "strings.">, + "strings">, MetaVarName<"old=new[,flag1,...]">; defm redefine_symbol : Eq<"redefine-sym", "Change the name of a symbol old to new">, @@ -64,7 +64,7 @@ defm redefine_symbols "contains two symbols per line separated with whitespace and may " "contain comments beginning with '#'. Leading and trailing " "whitespace is stripped from each line. May be repeated to read " - "symbols from many files.">, + "symbols from many files">, MetaVarName<"filename">; defm only_section : Eq<"only-section", "Remove all but <section>">, @@ -74,18 +74,18 @@ def j : JoinedOrSeparate<["-"], "j">, HelpText<"Alias for --only-section">; defm add_section : Eq<"add-section", - "Make a section named <section> with the contents of <file>.">, + "Make a section named <section> with the contents of <file>">, MetaVarName<"section=file">; defm set_section_alignment - : Eq<"set-section-alignment", "Set alignment for a given section.">, + : Eq<"set-section-alignment", "Set alignment for a given section">, MetaVarName<"section=align">; defm set_section_flags : Eq<"set-section-flags", "Set section flags for a given section. Flags supported for GNU " "compatibility: alloc, load, noload, readonly, exclude, debug, code, " - "data, rom, share, contents, merge, strings.">, + "data, rom, share, contents, merge, strings">, MetaVarName<"section=flag1[,flag2,...]">; defm set_section_type @@ -136,7 +136,7 @@ defm localize_symbol : Eq<"localize-symbol", "Mark <symbol> as local">, MetaVarName<"symbol">; defm localize_symbols : Eq<"localize-symbols", - "Reads a list of symbols from <filename> and marks them local.">, + "Reads a list of symbols from <filename> and marks them local">, MetaVarName<"filename">; def L : JoinedOrSeparate<["-"], "L">, @@ -148,13 +148,13 @@ defm globalize_symbol : Eq<"globalize-symbol", "Mark <symbol> as global">, defm globalize_symbols : Eq<"globalize-symbols", - "Reads a list of symbols from <filename> and marks them global.">, + "Reads a list of symbols from <filename> and marks them global">, MetaVarName<"filename">; defm keep_global_symbol : Eq<"keep-global-symbol", "Convert all symbols except <symbol> to local. May be repeated to " - "convert all except a set of symbols to local.">, + "convert all except a set of symbols to local">, MetaVarName<"symbol">; def G : JoinedOrSeparate<["-"], "G">, Alias<keep_global_symbol>, @@ -166,14 +166,14 @@ defm keep_global_symbols "--keep-global-symbol=<symbol> is set for each one. <filename> " "contains one symbol per line and may contain comments beginning with " "'#'. Leading and trailing whitespace is stripped from each line. May " - "be repeated to read symbols from many files.">, + "be repeated to read symbols from many files">, MetaVarName<"filename">; defm weaken_symbol : Eq<"weaken-symbol", "Mark <symbol> as weak">, MetaVarName<"symbol">; defm weaken_symbols : Eq<"weaken-symbols", - "Reads a list of symbols from <filename> and marks them weak.">, + "Reads a list of symbols from <filename> and marks them weak">, MetaVarName<"filename">; def W : JoinedOrSeparate<["-"], "W">, @@ -184,7 +184,7 @@ def weaken : Flag<["--"], "weaken">, defm strip_symbols : Eq<"strip-symbols", - "Reads a list of symbols from <filename> and removes them.">, + "Reads a list of symbols from <filename> and removes them">, MetaVarName<"filename">; defm keep_symbols @@ -193,7 +193,7 @@ defm keep_symbols "--keep-symbol=<symbol> is set for each one. <filename> " "contains one symbol per line and may contain comments beginning with " "'#'. Leading and trailing whitespace is stripped from each line. May " - "be repeated to read symbols from many files.">, + "be repeated to read symbols from many files">, MetaVarName<"filename">; defm dump_section @@ -209,11 +209,11 @@ defm prefix_alloc_sections MetaVarName<"prefix">; defm set_start : Eq<"set-start", "Set the start address to <addr>. Overrides " - "any previous --change-start or --adjust-start values.">, + "any previous --change-start or --adjust-start values">, MetaVarName<"addr">; defm change_start : Eq<"change-start", "Add <incr> to the start address. Can be " "specified multiple times, all values will be applied " - "cumulatively.">, + "cumulatively">, MetaVarName<"incr">; def adjust_start : JoinedOrSeparate<["--"], "adjust-start">, Alias<change_start>, @@ -224,9 +224,9 @@ defm add_symbol "global, local, weak, default, hidden, protected, file, section, object, " "function, indirect-function. Accepted but ignored for " "compatibility: debug, constructor, warning, indirect, synthetic, " - "unique-object, before.">, + "unique-object, before">, MetaVarName<"name=[section:]value[,flags]">; defm update_section - : Eq<"update-section", "Replace the contents of section <name> with contents from a file <file>.">, + : Eq<"update-section", "Replace the contents of section <name> with contents from a file <file>">, MetaVarName<"name=file">; diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp index a24cd889b83f..2afa97601f5c 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -42,8 +42,8 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileUtilities.h" -#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/Memory.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" @@ -51,6 +51,7 @@ #include "llvm/Support/StringSaver.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" #include <algorithm> #include <cassert> #include <cstdlib> @@ -223,7 +224,7 @@ static Error executeObjcopy(ConfigManager &ConfigMgr) { return Error::success(); } -int llvm_objcopy_main(int argc, char **argv) { +int llvm_objcopy_main(int argc, char **argv, const llvm::ToolContext &) { InitLLVM X(argc, argv); ToolName = argv[0]; diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp index 3bc7d3ce33b0..e1b38471c77f 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp @@ -37,13 +37,15 @@ template <typename T> struct EnumEntry { StringRef Name; }; -class COFFDumper { +class COFFDumper : public Dumper { public: - explicit COFFDumper(const llvm::object::COFFObjectFile &Obj) : Obj(Obj) { + explicit COFFDumper(const llvm::object::COFFObjectFile &O) + : Dumper(O), Obj(O) { Is64 = !Obj.getPE32Header(); } template <class PEHeader> void printPEHeader(const PEHeader &Hdr) const; + void printPrivateHeaders(bool MachOOnlyFirst) override; private: template <typename T> FormattedNumber formatAddr(T V) const { @@ -59,6 +61,11 @@ private: }; } // namespace +std::unique_ptr<Dumper> +objdump::createCOFFDumper(const object::COFFObjectFile &Obj) { + return std::make_unique<COFFDumper>(Obj); +} + constexpr EnumEntry<uint16_t> PEHeaderMagic[] = { {uint16_t(COFF::PE32Header::PE32), "PE32"}, {uint16_t(COFF::PE32Header::PE32_PLUS), "PE32+"}, @@ -545,12 +552,18 @@ static void printExportTable(const COFFObjectFile *Obj) { outs() << " Ordinal base: " << OrdinalBase << "\n"; outs() << " Ordinal RVA Name\n"; for (; I != E; I = ++I) { - uint32_t Ordinal; - if (I->getOrdinal(Ordinal)) - return; uint32_t RVA; if (I->getExportRVA(RVA)) return; + StringRef Name; + if (I->getSymbolName(Name)) + continue; + if (!RVA && Name.empty()) + continue; + + uint32_t Ordinal; + if (I->getOrdinal(Ordinal)) + return; bool IsForwarder; if (I->isForwarder(IsForwarder)) return; @@ -559,14 +572,11 @@ static void printExportTable(const COFFObjectFile *Obj) { // Export table entries can be used to re-export symbols that // this COFF file is imported from some DLLs. This is rare. // In most cases IsForwarder is false. - outs() << format(" % 4d ", Ordinal); + outs() << format(" %5d ", Ordinal); } else { - outs() << format(" % 4d %# 8x", Ordinal, RVA); + outs() << format(" %5d %# 8x", Ordinal, RVA); } - StringRef Name; - if (I->getSymbolName(Name)) - continue; if (!Name.empty()) outs() << " " << Name; if (IsForwarder) { @@ -761,7 +771,7 @@ void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) { } } -void objdump::printCOFFFileHeader(const COFFObjectFile &Obj) { +void COFFDumper::printPrivateHeaders(bool MachOOnlyFirst) { COFFDumper CD(Obj); const uint16_t Cha = Obj.getCharacteristics(); outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n'; @@ -849,8 +859,7 @@ void objdump::printCOFFSymbolTable(const COFFObjectFile &coff) { << Name; if (Demangle && Name.startswith("?")) { int Status = -1; - char *DemangledSymbol = - microsoftDemangle(Name.data(), nullptr, nullptr, nullptr, &Status); + char *DemangledSymbol = microsoftDemangle(Name, nullptr, &Status); if (Status == 0 && DemangledSymbol) { outs() << " (" << StringRef(DemangledSymbol) << ")"; diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp index b98b45e3015a..5b08a4b12858 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp @@ -24,6 +24,39 @@ using namespace llvm; using namespace llvm::object; using namespace llvm::objdump; +namespace { +template <typename ELFT> class ELFDumper : public Dumper { +public: + ELFDumper(const ELFObjectFile<ELFT> &O) : Dumper(O), Obj(O) {} + void printPrivateHeaders(bool MachOOnlyFirst) override; + void printDynamicRelocations() override; + +private: + const ELFObjectFile<ELFT> &Obj; + + const ELFFile<ELFT> &getELFFile() const { return Obj.getELFFile(); } + void printDynamicSection(); + void printProgramHeaders(); + void printSymbolVersion(); +}; +} // namespace + +template <class ELFT> +static std::unique_ptr<Dumper> createDumper(const ELFObjectFile<ELFT> &Obj) { + return std::make_unique<ELFDumper<ELFT>>(Obj); +} + +std::unique_ptr<Dumper> +objdump::createELFDumper(const object::ELFObjectFileBase &Obj) { + if (const auto *O = dyn_cast<ELF32LEObjectFile>(&Obj)) + return createDumper(*O); + if (const auto *O = dyn_cast<ELF32BEObjectFile>(&Obj)) + return createDumper(*O); + if (const auto *O = dyn_cast<ELF64LEObjectFile>(&Obj)) + return createDumper(*O); + return createDumper(cast<ELF64BEObjectFile>(Obj)); +} + template <class ELFT> static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> &Elf) { auto DynamicEntriesOrError = Elf.dynamicEntries(); @@ -108,10 +141,7 @@ static Error getRelocationValueString(const ELFObjectFile<ELFT> *Obj, Expected<StringRef> SymName = SI->getName(); if (!SymName) return SymName.takeError(); - if (Demangle) - Fmt << demangle(std::string(*SymName)); - else - Fmt << *SymName; + Fmt << (Demangle ? demangle(*SymName) : *SymName); } } else { Fmt << "*ABS*"; @@ -169,11 +199,11 @@ uint64_t objdump::getELFSectionLMA(const object::ELFSectionRef &Sec) { return getSectionLMA(ELFObj->getELFFile(), Sec); } -template <class ELFT> -static void printDynamicSection(const ELFFile<ELFT> &Elf, StringRef Filename) { +template <class ELFT> void ELFDumper<ELFT>::printDynamicSection() { + const ELFFile<ELFT> &Elf = getELFFile(); auto DynamicEntriesOrErr = Elf.dynamicEntries(); if (!DynamicEntriesOrErr) { - reportWarning(toString(DynamicEntriesOrErr.takeError()), Filename); + reportWarning(toString(DynamicEntriesOrErr.takeError()), Obj.getFileName()); return; } ArrayRef<typename ELFT::Dyn> DynamicEntries = *DynamicEntriesOrErr; @@ -203,21 +233,20 @@ static void printDynamicSection(const ELFFile<ELFT> &Elf, StringRef Filename) { outs() << (Data + Dyn.d_un.d_val) << "\n"; continue; } - reportWarning(toString(StrTabOrErr.takeError()), Filename); + reportWarning(toString(StrTabOrErr.takeError()), Obj.getFileName()); consumeError(StrTabOrErr.takeError()); } outs() << format(Fmt, (uint64_t)Dyn.d_un.d_val); } } -template <class ELFT> -static void printProgramHeaders(const ELFFile<ELFT> &Obj, StringRef FileName) { +template <class ELFT> void ELFDumper<ELFT>::printProgramHeaders() { outs() << "\nProgram Header:\n"; - auto ProgramHeaderOrError = Obj.program_headers(); + auto ProgramHeaderOrError = getELFFile().program_headers(); if (!ProgramHeaderOrError) { reportWarning("unable to read program headers: " + toString(ProgramHeaderOrError.takeError()), - FileName); + Obj.getFileName()); return; } @@ -274,8 +303,7 @@ static void printProgramHeaders(const ELFFile<ELFT> &Obj, StringRef FileName) { outs() << "off " << format(Fmt, (uint64_t)Phdr.p_offset) << "vaddr " << format(Fmt, (uint64_t)Phdr.p_vaddr) << "paddr " << format(Fmt, (uint64_t)Phdr.p_paddr) - << format("align 2**%u\n", - countTrailingZeros<uint64_t>(Phdr.p_align)) + << format("align 2**%u\n", llvm::countr_zero<uint64_t>(Phdr.p_align)) << " filesz " << format(Fmt, (uint64_t)Phdr.p_filesz) << "memsz " << format(Fmt, (uint64_t)Phdr.p_memsz) << "flags " << ((Phdr.p_flags & ELF::PF_R) ? "r" : "-") @@ -284,6 +312,39 @@ static void printProgramHeaders(const ELFFile<ELFT> &Obj, StringRef FileName) { } } +template <typename ELFT> void ELFDumper<ELFT>::printDynamicRelocations() { + if (!any_of(Obj.sections(), [](const ELFSectionRef Sec) { + return Sec.getType() == ELF::SHT_DYNAMIC; + })) { + reportError(Obj.getFileName(), "not a dynamic object"); + return; + } + + std::vector<SectionRef> DynRelSec = + cast<ObjectFile>(Obj).dynamic_relocation_sections(); + if (DynRelSec.empty()) + return; + + outs() << "\nDYNAMIC RELOCATION RECORDS\n"; + const uint32_t OffsetPadding = (Obj.getBytesInAddress() > 4 ? 16 : 8); + const uint32_t TypePadding = 24; + outs() << left_justify("OFFSET", OffsetPadding) << ' ' + << left_justify("TYPE", TypePadding) << " VALUE\n"; + + StringRef Fmt = Obj.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; + for (const SectionRef &Section : DynRelSec) + for (const RelocationRef &Reloc : Section.relocations()) { + uint64_t Address = Reloc.getOffset(); + SmallString<32> RelocName; + SmallString<32> ValueStr; + Reloc.getTypeName(RelocName); + if (Error E = getELFRelocationValueString(&Obj, Reloc, ValueStr)) + reportError(std::move(E), Obj.getFileName()); + outs() << format(Fmt.data(), Address) << ' ' + << left_justify(RelocName, TypePadding) << ' ' << ValueStr << '\n'; + } +} + template <class ELFT> static void printSymbolVersionDependency(StringRef FileName, const ELFFile<ELFT> &Obj, @@ -342,9 +403,9 @@ static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr, } } -template <class ELFT> -static void printSymbolVersionInfo(const ELFFile<ELFT> &Elf, - StringRef FileName) { +template <class ELFT> void ELFDumper<ELFT>::printSymbolVersion() { + const ELFFile<ELFT> &Elf = getELFFile(); + StringRef FileName = Obj.getFileName(); ArrayRef<typename ELFT::Shdr> Sections = unwrapOrError(Elf.sections(), FileName); for (const typename ELFT::Shdr &Shdr : Sections) { @@ -365,35 +426,8 @@ static void printSymbolVersionInfo(const ELFFile<ELFT> &Elf, } } -void objdump::printELFFileHeader(const object::ObjectFile *Obj) { - if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) - printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) - printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) - printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) - printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName()); -} - -void objdump::printELFDynamicSection(const object::ObjectFile *Obj) { - if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) - printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) - printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) - printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) - printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); -} - -void objdump::printELFSymbolVersionInfo(const object::ObjectFile *Obj) { - if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) - printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) - printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) - printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) - printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); +template <class ELFT> void ELFDumper<ELFT>::printPrivateHeaders(bool) { + printProgramHeaders(); + printDynamicSection(); + printSymbolVersion(); } diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.h b/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.h index 9b6b1f341cf3..205c3d256e2b 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.h +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.h @@ -30,8 +30,6 @@ Error getELFRelocationValueString(const object::ELFObjectFileBase *Obj, uint64_t getELFSectionLMA(const object::ELFSectionRef &Sec); void printELFFileHeader(const object::ObjectFile *O); -void printELFDynamicSection(const object::ObjectFile *Obj); -void printELFSymbolVersionInfo(const object::ObjectFile *Obj); } // namespace objdump } // namespace llvm diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp index fadc8367a8c1..11fb1cb41a9f 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp @@ -17,7 +17,6 @@ #include "llvm-c/Disassembler.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Config/config.h" #include "llvm/DebugInfo/DIContext.h" @@ -49,6 +48,7 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" #include <algorithm> #include <cstring> #include <system_error> @@ -191,8 +191,21 @@ struct SymbolSorter { return AAddr < BAddr; } }; + +class MachODumper : public Dumper { + const object::MachOObjectFile &Obj; + +public: + MachODumper(const object::MachOObjectFile &O) : Dumper(O), Obj(O) {} + void printPrivateHeaders(bool OnlyFirst) override; +}; } // namespace +std::unique_ptr<Dumper> +objdump::createMachODumper(const object::MachOObjectFile &Obj) { + return std::make_unique<MachODumper>(Obj); +} + // Types for the storted data in code table that is built before disassembly // and the predicate function to sort them. typedef std::pair<uint64_t, DiceRef> DiceTableEntry; @@ -2142,6 +2155,8 @@ static void printObjcMetaData(MachOObjectFile *O, bool verbose); static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF, StringRef ArchiveMemberName = StringRef(), StringRef ArchitectureName = StringRef()) { + std::unique_ptr<Dumper> D = createMachODumper(*MachOOF); + // If we are doing some processing here on the Mach-O file print the header // info. And don't print it otherwise like in the case of printing the // UniversalHeaders or ArchiveHeaders. @@ -2227,7 +2242,7 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF, if (DylibId) PrintDylibs(MachOOF, true); if (SymbolTable) - printSymbolTable(*MachOOF, ArchiveName, ArchitectureName); + D->printSymbolTable(ArchiveName, ArchitectureName); if (UnwindInfo) printMachOUnwindInfo(MachOOF); if (PrivateHeaders) { @@ -7280,9 +7295,7 @@ static const char *SymbolizerSymbolLookUp(void *DisInfo, } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) { if (info->demangled_name != nullptr) free(info->demangled_name); - int status; - info->demangled_name = - itaniumDemangle(SymbolName + 1, nullptr, nullptr, &status); + info->demangled_name = itaniumDemangle(SymbolName + 1); if (info->demangled_name != nullptr) { *ReferenceName = info->demangled_name; *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name; @@ -7380,9 +7393,7 @@ static const char *SymbolizerSymbolLookUp(void *DisInfo, } else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) { if (info->demangled_name != nullptr) free(info->demangled_name); - int status; - info->demangled_name = - itaniumDemangle(SymbolName + 1, nullptr, nullptr, &status); + info->demangled_name = itaniumDemangle(SymbolName + 1); if (info->demangled_name != nullptr) { *ReferenceName = info->demangled_name; *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name; @@ -10362,6 +10373,8 @@ static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld, outs() << " cmd LC_DYLD_EXPORTS_TRIE\n"; else if (ld.cmd == MachO::LC_DYLD_CHAINED_FIXUPS) outs() << " cmd LC_DYLD_CHAINED_FIXUPS\n"; + else if (ld.cmd == MachO::LC_ATOM_INFO) + outs() << " cmd LC_ATOM_INFO\n"; else outs() << " cmd " << ld.cmd << " (?)\n"; outs() << " cmdsize " << ld.cmdsize; @@ -10507,7 +10520,8 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype, Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS || Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT || Command.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE || - Command.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS) { + Command.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS || + Command.C.cmd == MachO::LC_ATOM_INFO) { MachO::linkedit_data_command Ld = Obj->getLinkeditDataLoadCommand(Command); PrintLinkEditDataCommand(Ld, Buf.size()); @@ -10540,6 +10554,12 @@ void objdump::printMachOFileHeader(const object::ObjectFile *Obj) { PrintMachHeader(file, Verbose); } +void MachODumper::printPrivateHeaders(bool OnlyFirst) { + printMachOFileHeader(&Obj); + if (!OnlyFirst) + printMachOLoadCommands(&Obj); +} + void objdump::printMachOLoadCommands(const object::ObjectFile *Obj) { const MachOObjectFile *file = cast<const MachOObjectFile>(Obj); uint32_t filetype = 0; diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td b/contrib/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td index c6627c75157b..e3e74762420d 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/ObjdumpOpts.td @@ -65,7 +65,11 @@ def : Flag<["-"], "D">, Alias<disassemble_all>, def symbol_description : Flag<["--"], "symbol-description">, HelpText<"Add symbol description for disassembly. This " - "option is for XCOFF files only.">; + "option is for XCOFF files only">; + +def traceback_table : Flag<["--"], "traceback-table">, + HelpText<"Decode traceback table in disassembly. Implies --disassemble. " + "This option is for XCOFF files only">; def disassemble_symbols_EQ : Joined<["--"], "disassemble-symbols=">, HelpText<"List of symbols to disassemble. " diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp index 6736cbc9ad5f..b2fe56cf2e1c 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.cpp @@ -26,10 +26,6 @@ namespace llvm { namespace objdump { -unsigned getInstStartColumn(const MCSubtargetInfo &STI) { - return !ShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24; -} - bool LiveVariable::liveAtAddress(object::SectionedAddress Addr) { if (LocExpr.Range == std::nullopt) return false; @@ -452,6 +448,34 @@ void SourcePrinter::printLines(formatted_raw_ostream &OS, } } +// Get the source line text for LineInfo: +// - use LineInfo::LineSource if available; +// - use LineCache if LineInfo::Source otherwise. +StringRef SourcePrinter::getLine(const DILineInfo &LineInfo, + StringRef ObjectFilename) { + if (LineInfo.LineSource) + return LineInfo.LineSource.value(); + + if (SourceCache.find(LineInfo.FileName) == SourceCache.end()) + if (!cacheSource(LineInfo)) + return {}; + + auto LineBuffer = LineCache.find(LineInfo.FileName); + if (LineBuffer == LineCache.end()) + return {}; + + if (LineInfo.Line > LineBuffer->second.size()) { + reportWarning( + formatv("debug info line number {0} exceeds the number of lines in {1}", + LineInfo.Line, LineInfo.FileName), + ObjectFilename); + return {}; + } + + // Vector begins at 0, line numbers are non-zero + return LineBuffer->second[LineInfo.Line - 1]; +} + void SourcePrinter::printSources(formatted_raw_ostream &OS, const DILineInfo &LineInfo, StringRef ObjectFilename, StringRef Delimiter, @@ -461,21 +485,9 @@ void SourcePrinter::printSources(formatted_raw_ostream &OS, OldLineInfo.FileName == LineInfo.FileName)) return; - if (SourceCache.find(LineInfo.FileName) == SourceCache.end()) - if (!cacheSource(LineInfo)) - return; - auto LineBuffer = LineCache.find(LineInfo.FileName); - if (LineBuffer != LineCache.end()) { - if (LineInfo.Line > LineBuffer->second.size()) { - reportWarning( - formatv( - "debug info line number {0} exceeds the number of lines in {1}", - LineInfo.Line, LineInfo.FileName), - ObjectFilename); - return; - } - // Vector begins at 0, line numbers are non-zero - OS << Delimiter << LineBuffer->second[LineInfo.Line - 1]; + StringRef Line = getLine(LineInfo, ObjectFilename); + if (!Line.empty()) { + OS << Delimiter << Line; LVP.printBetweenInsts(OS, true); } } diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.h b/contrib/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.h index 6209bb0e43e4..fc67fc650744 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.h +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.h @@ -151,6 +151,10 @@ private: StringRef ObjectFilename, StringRef Delimiter, LiveVariablePrinter &LVP); + // Returns line source code corresponding to `LineInfo`. + // Returns empty string if source code cannot be found. + StringRef getLine(const DILineInfo &LineInfo, StringRef ObjectFilename); + public: SourcePrinter() = default; SourcePrinter(const object::ObjectFile *Obj, StringRef DefaultArch); diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/WasmDump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/WasmDump.cpp index df0a08e5b1dd..a1d767d81003 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/WasmDump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/WasmDump.cpp @@ -19,12 +19,25 @@ using namespace llvm; using namespace llvm::object; -void objdump::printWasmFileHeader(const object::ObjectFile *Obj) { - const auto *File = cast<const WasmObjectFile>(Obj); +namespace { +class WasmDumper : public objdump::Dumper { + const WasmObjectFile &Obj; +public: + WasmDumper(const WasmObjectFile &O) : Dumper(O), Obj(O) {} + void printPrivateHeaders(bool MachOOnlyFirst) override; +}; +} // namespace + +std::unique_ptr<objdump::Dumper> +objdump::createWasmDumper(const object::WasmObjectFile &Obj) { + return std::make_unique<WasmDumper>(Obj); +} + +void WasmDumper::printPrivateHeaders(bool) { outs() << "Program Header:\n"; outs() << "Version: 0x"; - outs().write_hex(File->getHeader().Version); + outs().write_hex(Obj.getHeader().Version); outs() << "\n"; } diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp index 7171e2eb6eb3..87b1679a7969 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp @@ -14,10 +14,34 @@ #include "XCOFFDump.h" #include "llvm-objdump.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/FormattedStream.h" +#include <algorithm> using namespace llvm; using namespace llvm::object; +using namespace llvm::XCOFF; +using namespace llvm::support; + +namespace { +class XCOFFDumper : public objdump::Dumper { +public: + XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O) {} + void printPrivateHeaders(bool MachOOnlyFirst) override; +}; +} // namespace + +std::unique_ptr<objdump::Dumper> +objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) { + return std::make_unique<XCOFFDumper>(Obj); +} + +void XCOFFDumper::printPrivateHeaders(bool) {} Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj, const RelocationRef &Rel, @@ -32,10 +56,8 @@ Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj, if (!SymNameOrErr) return SymNameOrErr.takeError(); - std::string SymName = (*SymNameOrErr).str(); - if (Demangle) - SymName = demangle(SymName); - + std::string SymName = + Demangle ? demangle(*SymNameOrErr) : SymNameOrErr->str(); if (SymbolDescription) SymName = getXCOFFSymbolDescription(createSymbolInfo(Obj, *SymI), SymName); @@ -109,3 +131,299 @@ std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo, return Result; } + +#define PRINTBOOL(Prefix, Obj, Field) \ + OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field + +#define PRINTGET(Prefix, Obj, Field) \ + OS << Prefix << " " << #Field << " = " \ + << static_cast<unsigned>(Obj.get##Field()) + +#define PRINTOPTIONAL(Field) \ + if (TbTable.get##Field()) { \ + OS << '\n'; \ + printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); \ + Index += 4; \ + OS << "\t# " << #Field << " = " << *TbTable.get##Field(); \ + } + +void objdump::dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address, + formatted_raw_ostream &OS, uint64_t End, + const MCSubtargetInfo &STI, + const XCOFFObjectFile *Obj) { + uint64_t Index = 0; + unsigned TabStop = getInstStartColumn(STI) - 1; + // Print traceback table boundary. + printRawData(Bytes.slice(Index, 4), Address, OS, STI); + OS << "\t# Traceback table start\n"; + Index += 4; + + uint64_t Size = End - Address; + bool Is64Bit = Obj->is64Bit(); + + // XCOFFTracebackTable::create modifies the size parameter, so ensure Size + // isn't changed. + uint64_t SizeCopy = End - Address; + Expected<XCOFFTracebackTable> TTOrErr = + XCOFFTracebackTable::create(Bytes.data() + Index, SizeCopy, Is64Bit); + + if (!TTOrErr) { + std::string WarningMsgStr; + raw_string_ostream WarningStream(WarningMsgStr); + WarningStream << "failure parsing traceback table with address: 0x" + << utohexstr(Address) + "\n>>> " + << toString(TTOrErr.takeError()) + << "\n>>> Raw traceback table data is:\n"; + + uint64_t LastNonZero = Index; + for (uint64_t I = Index; I < Size; I += 4) + if (support::endian::read32be(Bytes.slice(I, 4).data()) != 0) + LastNonZero = I + 4 > Size ? Size : I + 4; + + if (Size - LastNonZero <= 4) + LastNonZero = Size; + + formatted_raw_ostream FOS(WarningStream); + while (Index < LastNonZero) { + printRawData(Bytes.slice(Index, 4), Address + Index, FOS, STI); + Index += 4; + WarningStream << '\n'; + } + + // Print all remaining zeroes as ... + if (Size - LastNonZero >= 8) + WarningStream << "\t\t...\n"; + + reportWarning(WarningMsgStr, Obj->getFileName()); + return; + } + + auto PrintBytes = [&](uint64_t N) { + printRawData(Bytes.slice(Index, N), Address + Index, OS, STI); + Index += N; + }; + + XCOFFTracebackTable TbTable = *TTOrErr; + // Print the first of the 8 bytes of mandatory fields. + PrintBytes(1); + OS << format("\t# Version = %i", TbTable.getVersion()) << '\n'; + + // Print the second of the 8 bytes of mandatory fields. + PrintBytes(1); + TracebackTable::LanguageID LangId = + static_cast<TracebackTable::LanguageID>(TbTable.getLanguageID()); + OS << "\t# Language = " << getNameForTracebackTableLanguageId(LangId) << '\n'; + + auto Split = [&]() { + OS << '\n'; + OS.indent(TabStop); + }; + + // Print the third of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTBOOL("\t#", TbTable, isGlobalLinkage); + PRINTBOOL(",", TbTable, isOutOfLineEpilogOrPrologue); + Split(); + PRINTBOOL("\t ", TbTable, hasTraceBackTableOffset); + PRINTBOOL(",", TbTable, isInternalProcedure); + Split(); + PRINTBOOL("\t ", TbTable, hasControlledStorage); + PRINTBOOL(",", TbTable, isTOCless); + Split(); + PRINTBOOL("\t ", TbTable, isFloatingPointPresent); + Split(); + PRINTBOOL("\t ", TbTable, isFloatingPointOperationLogOrAbortEnabled); + OS << '\n'; + + // Print the 4th of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTBOOL("\t#", TbTable, isInterruptHandler); + PRINTBOOL(",", TbTable, isFuncNamePresent); + PRINTBOOL(",", TbTable, isAllocaUsed); + Split(); + PRINTGET("\t ", TbTable, OnConditionDirective); + PRINTBOOL(",", TbTable, isCRSaved); + PRINTBOOL(",", TbTable, isLRSaved); + OS << '\n'; + + // Print the 5th of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTBOOL("\t#", TbTable, isBackChainStored); + PRINTBOOL(",", TbTable, isFixup); + PRINTGET(",", TbTable, NumOfFPRsSaved); + OS << '\n'; + + // Print the 6th of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTBOOL("\t#", TbTable, hasExtensionTable); + PRINTBOOL(",", TbTable, hasVectorInfo); + PRINTGET(",", TbTable, NumOfGPRsSaved); + OS << '\n'; + + // Print the 7th of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTGET("\t#", TbTable, NumberOfFixedParms); + OS << '\n'; + + // Print the 8th of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTGET("\t#", TbTable, NumberOfFPParms); + PRINTBOOL(",", TbTable, hasParmsOnStack); + + PRINTOPTIONAL(ParmsType); + PRINTOPTIONAL(TraceBackTableOffset); + PRINTOPTIONAL(HandlerMask); + PRINTOPTIONAL(NumOfCtlAnchors); + + if (TbTable.getControlledStorageInfoDisp()) { + SmallVector<uint32_t, 8> Disp = *TbTable.getControlledStorageInfoDisp(); + for (unsigned I = 0; I < Disp.size(); ++I) { + OS << '\n'; + PrintBytes(4); + OS << "\t" << (I ? " " : "#") << " ControlledStorageInfoDisp[" << I + << "] = " << Disp[I]; + } + } + + // If there is a name, print the function name and function name length. + if (TbTable.isFuncNamePresent()) { + uint16_t FunctionNameLen = TbTable.getFunctionName()->size(); + if (FunctionNameLen == 0) { + OS << '\n'; + reportWarning( + "the length of the function name must be greater than zero if the " + "isFuncNamePresent bit is set in the traceback table", + Obj->getFileName()); + return; + } + + OS << '\n'; + PrintBytes(2); + OS << "\t# FunctionNameLen = " << FunctionNameLen; + + uint16_t RemainingBytes = FunctionNameLen; + bool HasPrinted = false; + while (RemainingBytes > 0) { + OS << '\n'; + uint16_t PrintLen = RemainingBytes >= 4 ? 4 : RemainingBytes; + printRawData(Bytes.slice(Index, PrintLen), Address + Index, OS, STI); + Index += PrintLen; + RemainingBytes -= PrintLen; + + if (!HasPrinted) { + OS << "\t# FunctionName = " << *TbTable.getFunctionName(); + HasPrinted = true; + } + } + } + + if (TbTable.isAllocaUsed()) { + OS << '\n'; + PrintBytes(1); + OS << format("\t# AllocaRegister = %u", *TbTable.getAllocaRegister()); + } + + if (TbTable.getVectorExt()) { + OS << '\n'; + TBVectorExt VecExt = *TbTable.getVectorExt(); + // Print first byte of VectorExt. + PrintBytes(1); + PRINTGET("\t#", VecExt, NumberOfVRSaved); + PRINTBOOL(",", VecExt, isVRSavedOnStack); + PRINTBOOL(",", VecExt, hasVarArgs); + OS << '\n'; + + // Print the second byte of VectorExt. + PrintBytes(1); + PRINTGET("\t#", VecExt, NumberOfVectorParms); + PRINTBOOL(",", VecExt, hasVMXInstruction); + OS << '\n'; + + PrintBytes(4); + OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfo(); + + // There are two bytes of padding after vector info. + OS << '\n'; + PrintBytes(2); + OS << "\t# Padding"; + } + + if (TbTable.getExtensionTable()) { + OS << '\n'; + PrintBytes(1); + ExtendedTBTableFlag Flag = + static_cast<ExtendedTBTableFlag>(*TbTable.getExtensionTable()); + OS << "\t# ExtensionTable = " << getExtendedTBTableFlagString(Flag); + } + + if (TbTable.getEhInfoDisp()) { + // There are 4 bytes alignment before eh info displacement. + if (Index % 4) { + OS << '\n'; + PrintBytes(4 - Index % 4); + OS << "\t# Alignment padding for eh info displacement"; + } + OS << '\n'; + // The size of the displacement (address) is 4 bytes in 32-bit object files, + // and 8 bytes in 64-bit object files. + PrintBytes(4); + OS << "\t# EH info displacement"; + if (Is64Bit) { + OS << '\n'; + PrintBytes(4); + } + } + + OS << '\n'; + if (End == Address + Index) + return; + + Size = End - Address; + + const char *LineSuffix = "\t# Padding\n"; + auto IsWordZero = [&](uint64_t WordPos) { + if (WordPos >= Size) + return false; + uint64_t LineLength = std::min(4 - WordPos % 4, Size - WordPos); + return std::all_of(Bytes.begin() + WordPos, + Bytes.begin() + WordPos + LineLength, + [](uint8_t Byte) { return Byte == 0; }); + }; + + bool AreWordsZero[] = {IsWordZero(Index), IsWordZero(alignTo(Index, 4) + 4), + IsWordZero(alignTo(Index, 4) + 8)}; + bool ShouldPrintLine = true; + while (true) { + // Determine the length of the line (4, except for the first line, which + // will be just enough to align to the word boundary, and the last line, + // which will be the remainder of the data). + uint64_t LineLength = std::min(4 - Index % 4, Size - Index); + if (ShouldPrintLine) { + // Print the line. + printRawData(Bytes.slice(Index, LineLength), Address + Index, OS, STI); + OS << LineSuffix; + LineSuffix = "\n"; + } + + Index += LineLength; + if (Index == Size) + return; + + // For 3 or more consecutive lines of zeros, skip all but the first one, and + // replace them with "...". + if (AreWordsZero[0] && AreWordsZero[1] && AreWordsZero[2]) { + if (ShouldPrintLine) + OS << std::string(8, ' ') << "...\n"; + ShouldPrintLine = false; + } else if (!AreWordsZero[1]) { + // We have reached the end of a skipped block of zeros. + ShouldPrintLine = true; + } + AreWordsZero[0] = AreWordsZero[1]; + AreWordsZero[1] = AreWordsZero[2]; + AreWordsZero[2] = IsWordZero(Index + 8); + } +} +#undef PRINTBOOL +#undef PRINTGET +#undef PRINTOPTIONAL diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h b/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h index 35d1c0f1ebbe..cf5b19f910ea 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.h @@ -13,6 +13,8 @@ namespace llvm { +class formatted_raw_ostream; +class MCSubtargetInfo; struct SymbolInfoTy; namespace objdump { @@ -32,6 +34,11 @@ std::string getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo, Error getXCOFFRelocationValueString(const object::XCOFFObjectFile &Obj, const object::RelocationRef &RelRef, llvm::SmallVectorImpl<char> &Result); + +void dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address, + formatted_raw_ostream &OS, uint64_t End, + const MCSubtargetInfo &STI, + const object::XCOFFObjectFile *Obj); } // namespace objdump } // namespace llvm #endif diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp index 9979a26cf115..bd45ed199767 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -30,7 +30,6 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" @@ -49,7 +48,6 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Object/Archive.h" @@ -74,7 +72,6 @@ #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/GraphWriter.h" -#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" @@ -82,6 +79,8 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" #include <algorithm> #include <cctype> #include <cstring> @@ -196,6 +195,7 @@ bool objdump::Demangle; bool objdump::Disassemble; bool objdump::DisassembleAll; bool objdump::SymbolDescription; +bool objdump::TracebackTable; static std::vector<std::string> DisassembleSymbols; static bool DisassembleZeroes; static std::vector<std::string> DisassemblerOptions; @@ -247,6 +247,31 @@ static StringRef ToolName; std::unique_ptr<BuildIDFetcher> BIDFetcher; ExitOnError ExitOnErr; +void Dumper::reportUniqueWarning(Error Err) { + reportUniqueWarning(toString(std::move(Err))); +} + +void Dumper::reportUniqueWarning(const Twine &Msg) { + if (Warnings.insert(StringRef(Msg.str())).second) + reportWarning(Msg, O.getFileName()); +} + +static Expected<std::unique_ptr<Dumper>> createDumper(const ObjectFile &Obj) { + if (const auto *O = dyn_cast<COFFObjectFile>(&Obj)) + return createCOFFDumper(*O); + if (const auto *O = dyn_cast<ELFObjectFileBase>(&Obj)) + return createELFDumper(*O); + if (const auto *O = dyn_cast<MachOObjectFile>(&Obj)) + return createMachODumper(*O); + if (const auto *O = dyn_cast<WasmObjectFile>(&Obj)) + return createWasmDumper(*O); + if (const auto *O = dyn_cast<XCOFFObjectFile>(&Obj)) + return createXCOFFDumper(*O); + + return createStringError(errc::invalid_argument, + "unsupported object file format"); +} + namespace { struct FilterResult { // True if the section should not be skipped. @@ -442,14 +467,36 @@ static bool getHidden(RelocationRef RelRef) { return false; } -namespace { - /// Get the column at which we want to start printing the instruction /// disassembly, taking into account anything which appears to the left of it. -unsigned getInstStartColumn(const MCSubtargetInfo &STI) { +unsigned objdump::getInstStartColumn(const MCSubtargetInfo &STI) { return !ShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24; } +static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI, + raw_ostream &OS) { + // The output of printInst starts with a tab. Print some spaces so that + // the tab has 1 column and advances to the target tab stop. + unsigned TabStop = getInstStartColumn(STI); + unsigned Column = OS.tell() - Start; + OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); +} + +void objdump::printRawData(ArrayRef<uint8_t> Bytes, uint64_t Address, + formatted_raw_ostream &OS, + MCSubtargetInfo const &STI) { + size_t Start = OS.tell(); + if (LeadingAddr) + OS << format("%8" PRIx64 ":", Address); + if (ShowRawInsn) { + OS << ' '; + dumpBytes(Bytes, OS); + } + AlignToInstStartColumn(Start, STI, OS); +} + +namespace { + static bool isAArch64Elf(const ObjectFile &Obj) { const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj); return Elf && Elf->getEMachine() == ELF::EM_AARCH64; @@ -489,15 +536,6 @@ static void printRelocation(formatted_raw_ostream &OS, StringRef FileName, OS << Name << "\t" << Val; } -static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI, - raw_ostream &OS) { - // The output of printInst starts with a tab. Print some spaces so that - // the tab has 1 column and advances to the target tab stop. - unsigned TabStop = getInstStartColumn(STI); - unsigned Column = OS.tell() - Start; - OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); -} - class PrettyPrinter { public: virtual ~PrettyPrinter() = default; @@ -511,15 +549,7 @@ public: SP->printSourceLine(OS, Address, ObjectFilename, LVP); LVP.printBetweenInsts(OS, false); - size_t Start = OS.tell(); - if (LeadingAddr) - OS << format("%8" PRIx64 ":", Address.Address); - if (ShowRawInsn) { - OS << ' '; - dumpBytes(Bytes, OS); - } - - AlignToInstStartColumn(Start, STI, OS); + printRawData(Bytes, Address.Address, OS, STI); if (MI) { // See MCInstPrinter::printInst. On targets where a PC relative immediate @@ -806,7 +836,7 @@ PrettyPrinter &selectPrettyPrinter(Triple const &Triple) { return AArch64PrettyPrinterInst; } } -} +} // namespace static uint8_t getElfSymbolType(const ObjectFile &Obj, const SymbolRef &Sym) { assert(Obj.isELF()); @@ -914,38 +944,35 @@ addMissingWasmCodeSymbols(const WasmObjectFile &Obj, static void addPltEntries(const ObjectFile &Obj, std::map<SectionRef, SectionSymbolsTy> &AllSymbols, StringSaver &Saver) { - std::optional<SectionRef> Plt; - for (const SectionRef &Section : Obj.sections()) { + auto *ElfObj = dyn_cast<ELFObjectFileBase>(&Obj); + if (!ElfObj) + return; + DenseMap<StringRef, SectionRef> Sections; + for (SectionRef Section : Obj.sections()) { Expected<StringRef> SecNameOrErr = Section.getName(); if (!SecNameOrErr) { consumeError(SecNameOrErr.takeError()); continue; } - if (*SecNameOrErr == ".plt") - Plt = Section; - } - if (!Plt) - return; - if (auto *ElfObj = dyn_cast<ELFObjectFileBase>(&Obj)) { - for (auto PltEntry : ElfObj->getPltAddresses()) { - if (PltEntry.first) { - SymbolRef Symbol(*PltEntry.first, ElfObj); - uint8_t SymbolType = getElfSymbolType(Obj, Symbol); - if (Expected<StringRef> NameOrErr = Symbol.getName()) { - if (!NameOrErr->empty()) - AllSymbols[*Plt].emplace_back( - PltEntry.second, Saver.save((*NameOrErr + "@plt").str()), - SymbolType); - continue; - } else { - // The warning has been reported in disassembleObject(). - consumeError(NameOrErr.takeError()); - } + Sections[*SecNameOrErr] = Section; + } + for (auto Plt : ElfObj->getPltEntries()) { + if (Plt.Symbol) { + SymbolRef Symbol(*Plt.Symbol, ElfObj); + uint8_t SymbolType = getElfSymbolType(Obj, Symbol); + if (Expected<StringRef> NameOrErr = Symbol.getName()) { + if (!NameOrErr->empty()) + AllSymbols[Sections[Plt.Section]].emplace_back( + Plt.Address, Saver.save((*NameOrErr + "@plt").str()), SymbolType); + continue; + } else { + // The warning has been reported in disassembleObject(). + consumeError(NameOrErr.takeError()); } - reportWarning("PLT entry at 0x" + Twine::utohexstr(PltEntry.second) + - " references an invalid symbol", - Obj.getFileName()); } + reportWarning("PLT entry at 0x" + Twine::utohexstr(Plt.Address) + + " references an invalid symbol", + Obj.getFileName()); } } @@ -1090,7 +1117,7 @@ SymbolInfoTy objdump::createSymbolInfo(const ObjectFile &Obj, const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); const StringRef Name = unwrapOrError(Symbol.getName(), FileName); - if (Obj.isXCOFF() && SymbolDescription) { + if (Obj.isXCOFF() && (SymbolDescription || TracebackTable)) { const auto &XCOFFObj = cast<XCOFFObjectFile>(Obj); DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl(); @@ -1111,7 +1138,7 @@ SymbolInfoTy objdump::createSymbolInfo(const ObjectFile &Obj, static SymbolInfoTy createDummySymbolInfo(const ObjectFile &Obj, const uint64_t Addr, StringRef &Name, uint8_t Type) { - if (Obj.isXCOFF() && SymbolDescription) + if (Obj.isXCOFF() && (SymbolDescription || TracebackTable)) return SymbolInfoTy(Addr, Name, std::nullopt, std::nullopt, false); else return SymbolInfoTy(Addr, Name, Type); @@ -1129,11 +1156,11 @@ collectBBAddrMapLabels(const std::unordered_map<uint64_t, BBAddrMap> &AddrToBBAd auto Iter = AddrToBBAddrMap.find(StartAddress); if (Iter == AddrToBBAddrMap.end()) return; - for (unsigned I = 0, Size = Iter->second.BBEntries.size(); I < Size; ++I) { - uint64_t BBAddress = Iter->second.BBEntries[I].Offset + Iter->second.Addr; + for (const BBAddrMap::BBEntry &BBEntry : Iter->second.BBEntries) { + uint64_t BBAddress = BBEntry.Offset + Iter->second.Addr; if (BBAddress >= EndAddress) continue; - Labels[BBAddress].push_back(("BB" + Twine(I)).str()); + Labels[BBAddress].push_back(("BB" + Twine(BBEntry.ID)).str()); } } @@ -1285,10 +1312,10 @@ static void createFakeELFSections(ObjectFile &Obj) { // Build ID. Returns std::nullopt if nothing was found. static std::optional<OwningBinary<Binary>> fetchBinaryByBuildID(const ObjectFile &Obj) { - std::optional<object::BuildIDRef> BuildID = getBuildID(&Obj); - if (!BuildID) + object::BuildIDRef BuildID = getBuildID(&Obj); + if (BuildID.empty()) return std::nullopt; - std::optional<std::string> Path = BIDFetcher->fetch(*BuildID); + std::optional<std::string> Path = BIDFetcher->fetch(BuildID); if (!Path) return std::nullopt; Expected<OwningBinary<Binary>> DebugBinary = createBinary(*Path); @@ -1439,8 +1466,10 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj, AddrToBBAddrMap.clear(); if (const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) { auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex); - if (!BBAddrMapsOrErr) + if (!BBAddrMapsOrErr) { reportWarning(toString(BBAddrMapsOrErr.takeError()), Obj.getFileName()); + return; + } for (auto &FunctionBBAddrMap : *BBAddrMapsOrErr) AddrToBBAddrMap.emplace(FunctionBBAddrMap.Addr, std::move(FunctionBBAddrMap)); @@ -1546,7 +1575,7 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj, if (Demangle) { // Fetch the demangled names and store them locally. for (const SymbolInfoTy &Symbol : SymbolsHere) - DemangledSymNamesHere.push_back(demangle(Symbol.Name.str())); + DemangledSymNamesHere.push_back(demangle(Symbol.Name)); // Now we've finished modifying that vector, it's safe to make // a vector of StringRefs pointing into it. SymNamesHere.insert(SymNamesHere.begin(), DemangledSymNamesHere.begin(), @@ -1714,8 +1743,9 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj, // distance to the next symbol, and sometimes it will be just a // prologue and we should start disassembling instructions from where // it left off. - outs() << "// Error in decoding " << SymNamesHere[SHI] - << " : Decoding failed region as bytes.\n"; + outs() << Ctx.getAsmInfo()->getCommentString() + << " error in decoding " << SymNamesHere[SHI] + << " : decoding failed region as bytes.\n"; for (uint64_t I = 0; I < Size; ++I) { outs() << "\t.byte\t " << format_hex(Bytes[I], 1, /*Upper=*/true) << "\n"; @@ -1736,6 +1766,11 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj, } bool DumpARMELFData = false; + bool DumpTracebackTableForXCOFFFunction = + Obj.isXCOFF() && Section.isText() && TracebackTable && + Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass && + (*Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass == XCOFF::XMC_PR); + formatted_raw_ostream FOS(outs()); std::unordered_map<uint64_t, std::string> AllLabels; @@ -1788,6 +1823,16 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj, } } + if (DumpTracebackTableForXCOFFFunction && + doesXCOFFTracebackTableBegin(Bytes.slice(Index, 4))) { + dumpTracebackTable(Bytes.slice(Index), + SectionAddr + Index + VMAAdjustment, FOS, + SectionAddr + End + VMAAdjustment, *STI, + cast<XCOFFObjectFile>(&Obj)); + Index = End; + continue; + } + // Print local label if there's any. auto Iter1 = BBAddrMapLabels.find(SectionAddr + Index); if (Iter1 != BBAddrMapLabels.end()) { @@ -1907,9 +1952,8 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj, if (TargetSym != nullptr) { uint64_t TargetAddress = TargetSym->Addr; uint64_t Disp = Target - TargetAddress; - std::string TargetName = TargetSym->Name.str(); - if (Demangle) - TargetName = demangle(TargetName); + std::string TargetName = Demangle ? demangle(TargetSym->Name) + : TargetSym->Name.str(); *TargetOS << " <"; if (!Disp) { @@ -2149,23 +2193,22 @@ static void disassembleObject(ObjectFile *Obj, bool InlineRelocs) { SecondarySTI.get(), PIP, SP, InlineRelocs); } -void objdump::printRelocations(const ObjectFile *Obj) { - StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : - "%08" PRIx64; +void Dumper::printRelocations() { + StringRef Fmt = O.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; // Build a mapping from relocation target to a vector of relocation // sections. Usually, there is an only one relocation section for // each relocated section. MapVector<SectionRef, std::vector<SectionRef>> SecToRelSec; uint64_t Ndx; - for (const SectionRef &Section : ToolSectionFilter(*Obj, &Ndx)) { - if (Obj->isELF() && (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC)) + for (const SectionRef &Section : ToolSectionFilter(O, &Ndx)) { + if (O.isELF() && (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC)) continue; if (Section.relocation_begin() == Section.relocation_end()) continue; Expected<section_iterator> SecOrErr = Section.getRelocatedSection(); if (!SecOrErr) - reportError(Obj->getFileName(), + reportError(O.getFileName(), "section (" + Twine(Ndx) + "): unable to get a relocation target: " + toString(SecOrErr.takeError())); @@ -2173,9 +2216,9 @@ void objdump::printRelocations(const ObjectFile *Obj) { } for (std::pair<SectionRef, std::vector<SectionRef>> &P : SecToRelSec) { - StringRef SecName = unwrapOrError(P.first.getName(), Obj->getFileName()); + StringRef SecName = unwrapOrError(P.first.getName(), O.getFileName()); outs() << "\nRELOCATION RECORDS FOR [" << SecName << "]:\n"; - uint32_t OffsetPadding = (Obj->getBytesInAddress() > 4 ? 16 : 8); + uint32_t OffsetPadding = (O.getBytesInAddress() > 4 ? 16 : 8); uint32_t TypePadding = 24; outs() << left_justify("OFFSET", OffsetPadding) << " " << left_justify("TYPE", TypePadding) << " " @@ -2190,7 +2233,7 @@ void objdump::printRelocations(const ObjectFile *Obj) { continue; Reloc.getTypeName(RelocName); if (Error E = getRelocationValueString(Reloc, ValueStr)) - reportError(std::move(E), Obj->getFileName()); + reportUniqueWarning(std::move(E)); outs() << format(Fmt.data(), Address) << " " << left_justify(RelocName, TypePadding) << " " << ValueStr @@ -2200,43 +2243,6 @@ void objdump::printRelocations(const ObjectFile *Obj) { } } -void objdump::printDynamicRelocations(const ObjectFile *Obj) { - // For the moment, this option is for ELF only - if (!Obj->isELF()) - return; - - const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj); - if (!Elf || !any_of(Elf->sections(), [](const ELFSectionRef Sec) { - return Sec.getType() == ELF::SHT_DYNAMIC; - })) { - reportError(Obj->getFileName(), "not a dynamic object"); - return; - } - - std::vector<SectionRef> DynRelSec = Obj->dynamic_relocation_sections(); - if (DynRelSec.empty()) - return; - - outs() << "\nDYNAMIC RELOCATION RECORDS\n"; - const uint32_t OffsetPadding = (Obj->getBytesInAddress() > 4 ? 16 : 8); - const uint32_t TypePadding = 24; - outs() << left_justify("OFFSET", OffsetPadding) << ' ' - << left_justify("TYPE", TypePadding) << " VALUE\n"; - - StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; - for (const SectionRef &Section : DynRelSec) - for (const RelocationRef &Reloc : Section.relocations()) { - uint64_t Address = Reloc.getOffset(); - SmallString<32> RelocName; - SmallString<32> ValueStr; - Reloc.getTypeName(RelocName); - if (Error E = getRelocationValueString(Reloc, ValueStr)) - reportError(std::move(E), Obj->getFileName()); - outs() << format(Fmt.data(), Address) << ' ' - << left_justify(RelocName, TypePadding) << ' ' << ValueStr << '\n'; - } -} - // Returns true if we need to show LMA column when dumping section headers. We // show it only when the platform is ELF and either we have at least one section // whose VMA and LMA are different and/or when --show-lma flag is used. @@ -2355,8 +2361,8 @@ void objdump::printSectionContents(const ObjectFile *Obj) { } } -void objdump::printSymbolTable(const ObjectFile &O, StringRef ArchiveName, - StringRef ArchitectureName, bool DumpDynamic) { +void Dumper::printSymbolTable(StringRef ArchiveName, StringRef ArchitectureName, + bool DumpDynamic) { if (O.isCOFF() && !DumpDynamic) { outs() << "\nSYMBOL TABLE:\n"; printCOFFSymbolTable(cast<const COFFObjectFile>(O)); @@ -2368,8 +2374,7 @@ void objdump::printSymbolTable(const ObjectFile &O, StringRef ArchiveName, if (!DumpDynamic) { outs() << "\nSYMBOL TABLE:\n"; for (auto I = O.symbol_begin(); I != O.symbol_end(); ++I) - printSymbol(O, *I, {}, FileName, ArchiveName, ArchitectureName, - DumpDynamic); + printSymbol(*I, {}, FileName, ArchiveName, ArchitectureName, DumpDynamic); return; } @@ -2391,17 +2396,21 @@ void objdump::printSymbolTable(const ObjectFile &O, StringRef ArchiveName, (void)!SymbolVersionsOrErr; } for (auto &Sym : Symbols) - printSymbol(O, Sym, *SymbolVersionsOrErr, FileName, ArchiveName, + printSymbol(Sym, *SymbolVersionsOrErr, FileName, ArchiveName, ArchitectureName, DumpDynamic); } -void objdump::printSymbol(const ObjectFile &O, const SymbolRef &Symbol, - ArrayRef<VersionEntry> SymbolVersions, - StringRef FileName, StringRef ArchiveName, - StringRef ArchitectureName, bool DumpDynamic) { +void Dumper::printSymbol(const SymbolRef &Symbol, + ArrayRef<VersionEntry> SymbolVersions, + StringRef FileName, StringRef ArchiveName, + StringRef ArchitectureName, bool DumpDynamic) { const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&O); - uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName, ArchiveName, - ArchitectureName); + Expected<uint64_t> AddrOrErr = Symbol.getAddress(); + if (!AddrOrErr) { + reportUniqueWarning(AddrOrErr.takeError()); + return; + } + uint64_t Address = *AddrOrErr; if ((Address < StartAddress) || (Address > StopAddress)) return; SymbolRef::Type Type = @@ -2509,10 +2518,8 @@ void objdump::printSymbol(const ObjectFile &O, const SymbolRef &Symbol, if (NameOrErr) { outs() << " (csect:"; - std::string SymName(NameOrErr.get()); - - if (Demangle) - SymName = demangle(SymName); + std::string SymName = + Demangle ? demangle(*NameOrErr) : NameOrErr->str(); if (SymbolDescription) SymName = getXCOFFSymbolDescription(createSymbolInfo(O, *SymRef), @@ -2566,10 +2573,7 @@ void objdump::printSymbol(const ObjectFile &O, const SymbolRef &Symbol, outs() << " .hidden"; } - std::string SymName(Name); - if (Demangle) - SymName = demangle(SymName); - + std::string SymName = Demangle ? demangle(Name) : Name.str(); if (O.isXCOFF() && SymbolDescription) SymName = getXCOFFSymbolDescription(createSymbolInfo(O, Symbol), SymName); @@ -2672,24 +2676,8 @@ static void printFaultMaps(const ObjectFile *Obj) { outs() << FMP; } -static void printPrivateFileHeaders(const ObjectFile *O, bool OnlyFirst) { - if (O->isELF()) { - printELFFileHeader(O); - printELFDynamicSection(O); - printELFSymbolVersionInfo(O); - return; - } - if (O->isCOFF()) - return printCOFFFileHeader(cast<object::COFFObjectFile>(*O)); - if (O->isWasm()) - return printWasmFileHeader(O); - if (O->isMachO()) { - printMachOFileHeader(O); - if (!OnlyFirst) - printMachOLoadCommands(O); - return; - } - reportError(O->getFileName(), "Invalid/Unsupported object file format"); +void Dumper::printPrivateHeaders(bool) { + reportError(O.getFileName(), "Invalid/Unsupported object file format"); } static void printFileHeaders(const ObjectFile *O) { @@ -2792,6 +2780,14 @@ static void checkForInvalidStartStopAddress(ObjectFile *Obj, static void dumpObject(ObjectFile *O, const Archive *A = nullptr, const Archive::Child *C = nullptr) { + Expected<std::unique_ptr<Dumper>> DumperOrErr = createDumper(*O); + if (!DumperOrErr) { + reportError(DumperOrErr.takeError(), O->getFileName(), + A ? A->getFileName() : ""); + return; + } + Dumper &D = **DumperOrErr; + // Avoid other output when using a raw option. if (!RawClangAST) { outs() << '\n'; @@ -2805,6 +2801,9 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr, if (HasStartAddressFlag || HasStopAddressFlag) checkForInvalidStartStopAddress(O, StartAddress, StopAddress); + // TODO: Change print* free functions to Dumper member functions to utilitize + // stateful functions like reportUniqueWarning. + // Note: the order here matches GNU objdump for compatability. StringRef ArchiveName = A ? A->getFileName() : ""; if (ArchiveHeaders && !MachOOpt && C) @@ -2812,14 +2811,14 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr, if (FileHeaders) printFileHeaders(O); if (PrivateHeaders || FirstPrivateHeader) - printPrivateFileHeaders(O, FirstPrivateHeader); + D.printPrivateHeaders(FirstPrivateHeader); if (SectionHeaders) printSectionHeaders(*O); if (SymbolTable) - printSymbolTable(*O, ArchiveName); + D.printSymbolTable(ArchiveName); if (DynamicSymbolTable) - printSymbolTable(*O, ArchiveName, /*ArchitectureName=*/"", - /*DumpDynamic=*/true); + D.printSymbolTable(ArchiveName, /*ArchitectureName=*/"", + /*DumpDynamic=*/true); if (DwarfDumpType != DIDT_Null) { std::unique_ptr<DIContext> DICtx = DWARFContext::create(*O); // Dump the complete DWARF structure. @@ -2828,9 +2827,9 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr, DICtx->dump(outs(), DumpOpts); } if (Relocations && !Disassemble) - printRelocations(O); + D.printRelocations(); if (DynamicRelocations) - printDynamicRelocations(O); + D.printDynamicRelocations(); if (SectionContents) printSectionContents(O); if (Disassemble) @@ -2941,13 +2940,11 @@ static void parseIntArg(const llvm::opt::InputArgList &InputArgs, int ID, static object::BuildID parseBuildIDArg(const opt::Arg *A) { StringRef V(A->getValue()); - std::string Bytes; - if (!tryGetFromHex(V, Bytes)) + object::BuildID BID = parseBuildID(V); + if (BID.empty()) reportCmdLineError(A->getSpelling() + ": expected a build ID, but got '" + V + "'"); - ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()), - Bytes.size()); - return object::BuildID(BuildID.begin(), BuildID.end()); + return BID; } void objdump::invalidArgValue(const opt::Arg *A) { @@ -3027,6 +3024,7 @@ static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) { Disassemble = InputArgs.hasArg(OBJDUMP_disassemble); DisassembleAll = InputArgs.hasArg(OBJDUMP_disassemble_all); SymbolDescription = InputArgs.hasArg(OBJDUMP_symbol_description); + TracebackTable = InputArgs.hasArg(OBJDUMP_traceback_table); DisassembleSymbols = commaSeparatedValues(InputArgs, OBJDUMP_disassemble_symbols_EQ); DisassembleZeroes = InputArgs.hasArg(OBJDUMP_disassemble_zeroes); @@ -3227,7 +3225,7 @@ int main(int argc, char **argv) { ArchiveHeaders = FileHeaders = PrivateHeaders = Relocations = SectionHeaders = SymbolTable = true; - if (DisassembleAll || PrintSource || PrintLines || + if (DisassembleAll || PrintSource || PrintLines || TracebackTable || !DisassembleSymbols.empty()) Disassemble = true; diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h b/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h index efb445195259..b3136f0374d2 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h @@ -12,9 +12,13 @@ #include "llvm/ADT/StringSet.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/FormattedStream.h" +#include <memory> namespace llvm { class StringRef; @@ -27,6 +31,12 @@ class Arg; namespace object { class RelocationRef; struct VersionEntry; + +class COFFObjectFile; +class ELFObjectFileBase; +class MachOObjectFile; +class WasmObjectFile; +class XCOFFObjectFile; } // namespace object namespace objdump { @@ -55,64 +65,41 @@ extern bool SectionHeaders; extern bool SectionContents; extern bool ShowRawInsn; extern bool SymbolDescription; +extern bool TracebackTable; extern bool SymbolTable; extern std::string TripleName; extern bool UnwindInfo; extern StringSet<> FoundSectionSet; -typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate; +class Dumper { + const object::ObjectFile &O; + StringSet<> Warnings; -/// A filtered iterator for SectionRefs that skips sections based on some given -/// predicate. -class SectionFilterIterator { public: - SectionFilterIterator(FilterPredicate P, - llvm::object::section_iterator const &I, - llvm::object::section_iterator const &E) - : Predicate(std::move(P)), Iterator(I), End(E) { - ScanPredicate(); - } - const llvm::object::SectionRef &operator*() const { return *Iterator; } - SectionFilterIterator &operator++() { - ++Iterator; - ScanPredicate(); - return *this; - } - bool operator!=(SectionFilterIterator const &Other) const { - return Iterator != Other.Iterator; - } - -private: - void ScanPredicate() { - while (Iterator != End && !Predicate(*Iterator)) { - ++Iterator; - } - } - FilterPredicate Predicate; - llvm::object::section_iterator Iterator; - llvm::object::section_iterator End; + Dumper(const object::ObjectFile &O) : O(O) {} + virtual ~Dumper() {} + + void reportUniqueWarning(Error Err); + void reportUniqueWarning(const Twine &Msg); + + virtual void printPrivateHeaders(bool MachOOnlyFirst); + virtual void printDynamicRelocations() {} + void printSymbolTable(StringRef ArchiveName, + StringRef ArchitectureName = StringRef(), + bool DumpDynamic = false); + void printSymbol(const object::SymbolRef &Symbol, + ArrayRef<object::VersionEntry> SymbolVersions, + StringRef FileName, StringRef ArchiveName, + StringRef ArchitectureName, bool DumpDynamic); + void printRelocations(); }; -/// Creates an iterator range of SectionFilterIterators for a given Object and -/// predicate. -class SectionFilter { -public: - SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O) - : Predicate(std::move(P)), Object(O) {} - SectionFilterIterator begin() { - return SectionFilterIterator(Predicate, Object.section_begin(), - Object.section_end()); - } - SectionFilterIterator end() { - return SectionFilterIterator(Predicate, Object.section_end(), - Object.section_end()); - } - -private: - FilterPredicate Predicate; - llvm::object::ObjectFile const &Object; -}; +std::unique_ptr<Dumper> createCOFFDumper(const object::COFFObjectFile &Obj); +std::unique_ptr<Dumper> createELFDumper(const object::ELFObjectFileBase &Obj); +std::unique_ptr<Dumper> createMachODumper(const object::MachOObjectFile &Obj); +std::unique_ptr<Dumper> createWasmDumper(const object::WasmObjectFile &Obj); +std::unique_ptr<Dumper> createXCOFFDumper(const object::XCOFFObjectFile &Obj); // Various helper functions. @@ -122,21 +109,12 @@ private: /// Idx is an optional output parameter that keeps track of which section index /// this is. This may be different than the actual section number, as some /// sections may be filtered (e.g. symbol tables). -SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O, - uint64_t *Idx = nullptr); +object::SectionFilter ToolSectionFilter(const llvm::object::ObjectFile &O, + uint64_t *Idx = nullptr); bool isRelocAddressLess(object::RelocationRef A, object::RelocationRef B); -void printRelocations(const object::ObjectFile *O); -void printDynamicRelocations(const object::ObjectFile *O); void printSectionHeaders(object::ObjectFile &O); void printSectionContents(const object::ObjectFile *O); -void printSymbolTable(const object::ObjectFile &O, StringRef ArchiveName, - StringRef ArchitectureName = StringRef(), - bool DumpDynamic = false); -void printSymbol(const object::ObjectFile &O, const object::SymbolRef &Symbol, - ArrayRef<object::VersionEntry> SymbolVersions, - StringRef FileName, StringRef ArchiveName, - StringRef ArchitectureName, bool DumpDynamic); [[noreturn]] void reportError(StringRef File, const Twine &Message); [[noreturn]] void reportError(Error E, StringRef FileName, StringRef ArchiveName = "", @@ -156,6 +134,10 @@ std::string getFileNameForError(const object::Archive::Child &C, unsigned Index); SymbolInfoTy createSymbolInfo(const object::ObjectFile &Obj, const object::SymbolRef &Symbol); +unsigned getInstStartColumn(const MCSubtargetInfo &STI); +void printRawData(llvm::ArrayRef<uint8_t> Bytes, uint64_t Address, + llvm::formatted_raw_ostream &OS, + llvm::MCSubtargetInfo const &STI); } // namespace objdump } // end namespace llvm diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp index 4b604206fc98..447a9cb6b359 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -15,6 +15,7 @@ #include "llvm-pdbutil.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp index 8e17284871a9..96c3d49072b6 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp @@ -8,6 +8,7 @@ #include "MinimalSymbolDumper.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Formatters.h" @@ -210,6 +211,8 @@ static std::string formatSourceLanguage(SourceLanguage Lang) { RETURN_CASE(SourceLanguage, D, "d"); RETURN_CASE(SourceLanguage, Swift, "swift"); RETURN_CASE(SourceLanguage, Rust, "rust"); + RETURN_CASE(SourceLanguage, ObjC, "objc"); + RETURN_CASE(SourceLanguage, ObjCpp, "objc++"); } return formatUnknownEnum(Lang); } diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp index be7e487673fb..aaa430a9572e 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp @@ -11,6 +11,7 @@ #include "TypeReferenceTracker.h" #include "llvm-pdbutil.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp index 591bd4f93702..b347cfdfc392 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp @@ -11,6 +11,7 @@ #include "PrettyFunctionDumper.h" #include "llvm-pdbutil.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" diff --git a/contrib/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp b/contrib/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp index c8e5e6d1ad68..da10ddcc58c6 100644 --- a/contrib/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -23,6 +23,7 @@ #include "llvm/ProfileData/RawMemProfReader.h" #include "llvm/ProfileData/SampleProfReader.h" #include "llvm/ProfileData/SampleProfWriter.h" +#include "llvm/Support/BalancedPartitioning.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Discriminator.h" #include "llvm/Support/Errc.h" @@ -30,11 +31,13 @@ #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -51,7 +54,7 @@ const std::string DuplicateNameStr = "----"; enum ProfileFormat { PF_None = 0, PF_Text, - PF_Compact_Binary, + PF_Compact_Binary, // Deprecated PF_Ext_Binary, PF_GCC, PF_Binary @@ -214,9 +217,10 @@ struct WriterContext { SmallSet<instrprof_error, 4> &WriterErrorCodes; WriterContext(bool IsSparse, std::mutex &ErrLock, - SmallSet<instrprof_error, 4> &WriterErrorCodes) - : Writer(IsSparse), ErrLock(ErrLock), WriterErrorCodes(WriterErrorCodes) { - } + SmallSet<instrprof_error, 4> &WriterErrorCodes, + uint64_t ReservoirSize = 0, uint64_t MaxTraceLength = 0) + : Writer(IsSparse, ReservoirSize, MaxTraceLength), ErrLock(ErrLock), + WriterErrorCodes(WriterErrorCodes) {} }; /// Computer the overlap b/w profile BaseFilename and TestFileName, @@ -226,12 +230,14 @@ static void overlapInput(const std::string &BaseFilename, OverlapStats &Overlap, const OverlapFuncFilters &FuncFilter, raw_fd_ostream &OS, bool IsCS) { - auto ReaderOrErr = InstrProfReader::create(TestFilename); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = InstrProfReader::create(TestFilename, *FS); if (Error E = ReaderOrErr.takeError()) { // Skip the empty profiles by returning sliently. - instrprof_error IPE = InstrProfError::take(std::move(E)); - if (IPE != instrprof_error::empty_raw_profile) - WC->Errors.emplace_back(make_error<InstrProfError>(IPE), TestFilename); + auto [ErrorCode, Msg] = InstrProfError::take(std::move(E)); + if (ErrorCode != instrprof_error::empty_raw_profile) + WC->Errors.emplace_back(make_error<InstrProfError>(ErrorCode, Msg), + TestFilename); return; } @@ -276,8 +282,9 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper, } auto MemProfError = [&](Error E) { - instrprof_error IPE = InstrProfError::take(std::move(E)); - WC->Errors.emplace_back(make_error<InstrProfError>(IPE), Filename); + auto [ErrorCode, Msg] = InstrProfError::take(std::move(E)); + WC->Errors.emplace_back(make_error<InstrProfError>(ErrorCode, Msg), + Filename); }; // Add the frame mappings into the writer context. @@ -298,12 +305,14 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper, return; } - auto ReaderOrErr = InstrProfReader::create(Input.Filename, Correlator); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = InstrProfReader::create(Input.Filename, *FS, Correlator); if (Error E = ReaderOrErr.takeError()) { - // Skip the empty profiles by returning sliently. - instrprof_error IPE = InstrProfError::take(std::move(E)); - if (IPE != instrprof_error::empty_raw_profile) - WC->Errors.emplace_back(make_error<InstrProfError>(IPE), Filename); + // Skip the empty profiles by returning silently. + auto [ErrCode, Msg] = InstrProfError::take(std::move(E)); + if (ErrCode != instrprof_error::empty_raw_profile) + WC->Errors.emplace_back(make_error<InstrProfError>(ErrCode, Msg), + Filename); return; } @@ -330,14 +339,20 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper, } Reported = true; // Only show hint the first time an error occurs. - instrprof_error IPE = InstrProfError::take(std::move(E)); + auto [ErrCode, Msg] = InstrProfError::take(std::move(E)); std::unique_lock<std::mutex> ErrGuard{WC->ErrLock}; - bool firstTime = WC->WriterErrorCodes.insert(IPE).second; - handleMergeWriterError(make_error<InstrProfError>(IPE), Input.Filename, - FuncName, firstTime); + bool firstTime = WC->WriterErrorCodes.insert(ErrCode).second; + handleMergeWriterError(make_error<InstrProfError>(ErrCode, Msg), + Input.Filename, FuncName, firstTime); }); } + if (Reader->hasTemporalProfile()) { + auto &Traces = Reader->getTemporalProfTraces(Input.Weight); + if (!Traces.empty()) + WC->Writer.addTemporalProfileTraces( + Traces, Reader->getTemporalProfTraceStreamSize()); + } if (Reader->hasError()) { if (Error E = Reader->getError()) WC->Errors.emplace_back(std::move(E), Filename); @@ -359,11 +374,11 @@ static void mergeWriterContexts(WriterContext *Dst, WriterContext *Src) { exitWithError(std::move(E)); Dst->Writer.mergeRecordsFromWriter(std::move(Src->Writer), [&](Error E) { - instrprof_error IPE = InstrProfError::take(std::move(E)); + auto [ErrorCode, Msg] = InstrProfError::take(std::move(E)); std::unique_lock<std::mutex> ErrGuard{Dst->ErrLock}; - bool firstTime = Dst->WriterErrorCodes.insert(IPE).second; + bool firstTime = Dst->WriterErrorCodes.insert(ErrorCode).second; if (firstTime) - warn(toString(make_error<InstrProfError>(IPE))); + warn(toString(make_error<InstrProfError>(ErrorCode, Msg))); }); } @@ -388,15 +403,17 @@ static void writeInstrProfile(StringRef OutputFilename, } } -static void mergeInstrProfile(const WeightedFileVector &Inputs, - StringRef DebugInfoFilename, - SymbolRemapper *Remapper, - StringRef OutputFilename, - ProfileFormat OutputFormat, bool OutputSparse, - unsigned NumThreads, FailureMode FailMode, - const StringRef ProfiledBinary) { - if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary && - OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text) +static void +mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename, + SymbolRemapper *Remapper, StringRef OutputFilename, + ProfileFormat OutputFormat, uint64_t TraceReservoirSize, + uint64_t MaxTraceLength, bool OutputSparse, + unsigned NumThreads, FailureMode FailMode, + const StringRef ProfiledBinary) { + if (OutputFormat == PF_Compact_Binary) + exitWithError("Compact Binary is deprecated"); + if (OutputFormat != PF_Binary && OutputFormat != PF_Ext_Binary && + OutputFormat != PF_Text) exitWithError("unknown format is specified"); std::unique_ptr<InstrProfCorrelator> Correlator; @@ -420,7 +437,8 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs, SmallVector<std::unique_ptr<WriterContext>, 4> Contexts; for (unsigned I = 0; I < NumThreads; ++I) Contexts.emplace_back(std::make_unique<WriterContext>( - OutputSparse, ErrorLock, WriterErrorCodes)); + OutputSparse, ErrorLock, WriterErrorCodes, TraceReservoirSize, + MaxTraceLength)); if (NumThreads == 1) { for (const auto &Input : Inputs) @@ -631,7 +649,7 @@ adjustInstrProfile(std::unique_ptr<WriterContext> &WC, } } - if (StaticFuncMap.find(NewName) == StaticFuncMap.end()) { + if (!StaticFuncMap.contains(NewName)) { StaticFuncMap[NewName] = Name; } else { StaticFuncMap[NewName] = DuplicateNameStr; @@ -838,8 +856,9 @@ static void supplementInstrProfile( // Read sample profile. LLVMContext Context; + auto FS = vfs::getRealFileSystem(); auto ReaderOrErr = sampleprof::SampleProfileReader::create( - SampleFilename.str(), Context, FSDiscriminatorPassOption); + SampleFilename.str(), Context, *FS, FSDiscriminatorPassOption); if (std::error_code EC = ReaderOrErr.getError()) exitWithErrorCode(EC, SampleFilename); auto Reader = std::move(ReaderOrErr.get()); @@ -896,7 +915,7 @@ remapSamples(const sampleprof::FunctionSamples &Samples, static sampleprof::SampleProfileFormat FormatMap[] = { sampleprof::SPF_None, sampleprof::SPF_Text, - sampleprof::SPF_Compact_Binary, + sampleprof::SPF_None, sampleprof::SPF_Ext_Binary, sampleprof::SPF_GCC, sampleprof::SPF_Binary}; @@ -963,10 +982,11 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper, StringRef OutputFilename, ProfileFormat OutputFormat, StringRef ProfileSymbolListFile, bool CompressAllSections, - bool UseMD5, bool GenPartialProfile, bool GenCSNestedProfile, + bool UseMD5, bool GenPartialProfile, + SampleProfileLayout ProfileLayout, bool SampleMergeColdContext, bool SampleTrimColdContext, bool SampleColdContextFrameDepth, FailureMode FailMode, - bool DropProfileSymbolList) { + bool DropProfileSymbolList, size_t OutputSizeLimit) { using namespace sampleprof; SampleProfileMap ProfileMap; SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers; @@ -975,7 +995,8 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper, std::optional<bool> ProfileIsProbeBased; std::optional<bool> ProfileIsCS; for (const auto &Input : Inputs) { - auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context, + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context, *FS, FSDiscriminatorPassOption); if (std::error_code EC = ReaderOrErr.getError()) { warnOrExitGivenError(FailMode, EC, Input.Filename); @@ -1042,9 +1063,12 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper, SampleMergeColdContext, SampleColdContextFrameDepth, false); } - if (ProfileIsCS && GenCSNestedProfile) { - CSProfileConverter CSConverter(ProfileMap); - CSConverter.convertProfiles(); + if (ProfileLayout == llvm::sampleprof::SPL_Flat) { + ProfileConverter::flattenProfile(ProfileMap, FunctionSamples::ProfileIsCS); + ProfileIsCS = FunctionSamples::ProfileIsCS = false; + } else if (ProfileIsCS && ProfileLayout == llvm::sampleprof::SPL_Nest) { + ProfileConverter CSConverter(ProfileMap); + CSConverter.convertCSProfiles(); ProfileIsCS = FunctionSamples::ProfileIsCS = false; } @@ -1059,7 +1083,10 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper, auto Buffer = getInputFileBuf(ProfileSymbolListFile); handleExtBinaryWriter(*Writer, OutputFormat, Buffer.get(), WriterList, CompressAllSections, UseMD5, GenPartialProfile); - if (std::error_code EC = Writer->write(ProfileMap)) + + // If OutputSizeLimit is 0 (default), it is the same as write(). + if (std::error_code EC = + Writer->writeWithSizeLimit(ProfileMap, OutputSizeLimit)) exitWithErrorCode(std::move(EC)); } @@ -1156,12 +1183,11 @@ static int merge_main(int argc, const char *argv[]) { cl::values(clEnumVal(instr, "Instrumentation profile (default)"), clEnumVal(sample, "Sample profile"))); cl::opt<ProfileFormat> OutputFormat( - cl::desc("Format of output profile"), cl::init(PF_Binary), + cl::desc("Format of output profile"), cl::init(PF_Ext_Binary), cl::values( - clEnumValN(PF_Binary, "binary", "Binary encoding (default)"), - clEnumValN(PF_Compact_Binary, "compbinary", - "Compact binary encoding"), - clEnumValN(PF_Ext_Binary, "extbinary", "Extensible binary encoding"), + clEnumValN(PF_Binary, "binary", "Binary encoding"), + clEnumValN(PF_Ext_Binary, "extbinary", "Extensible binary encoding " + "(default)"), clEnumValN(PF_Text, "text", "Text encoding"), clEnumValN(PF_GCC, "gcc", "GCC encoding (only meaningful for -sample)"))); @@ -1202,6 +1228,11 @@ static int merge_main(int argc, const char *argv[]) { "sample-frame-depth-for-cold-context", cl::init(1), cl::desc("Keep the last K frames while merging cold profile. 1 means the " "context-less base profile")); + cl::opt<size_t> OutputSizeLimit( + "output-size-limit", cl::init(0), cl::Hidden, + cl::desc("Trim cold functions until profile size is below specified " + "limit in bytes. This uses a heursitic and functions may be " + "excessively trimmed")); cl::opt<bool> GenPartialProfile( "gen-partial-profile", cl::init(false), cl::Hidden, cl::desc("Generate a partial profile (only meaningful for -extbinary)")); @@ -1227,9 +1258,15 @@ static int merge_main(int argc, const char *argv[]) { "instr-prof-cold-threshold", cl::init(0), cl::Hidden, cl::desc("User specified cold threshold for instr profile which will " "override the cold threshold got from profile summary. ")); - cl::opt<bool> GenCSNestedProfile( - "gen-cs-nested-profile", cl::Hidden, cl::init(false), - cl::desc("Generate nested function profiles for CSSPGO")); + cl::opt<SampleProfileLayout> ProfileLayout( + "convert-sample-profile-layout", + cl::desc("Convert the generated profile to a profile with a new layout"), + cl::init(SPL_None), + cl::values( + clEnumValN(SPL_Nest, "nest", + "Nested profile, the input should be CS flat profile"), + clEnumValN(SPL_Flat, "flat", + "Profile with nested inlinee flatten out"))); cl::opt<std::string> DebugInfoFilename( "debug-info", cl::init(""), cl::desc("Use the provided debug info to correlate the raw profile.")); @@ -1240,6 +1277,17 @@ static int merge_main(int argc, const char *argv[]) { "drop-profile-symbol-list", cl::init(false), cl::Hidden, cl::desc("Drop the profile symbol list when merging AutoFDO profiles " "(only meaningful for -sample)")); + // WARNING: This reservoir size value is propagated to any input indexed + // profiles for simplicity. Changing this value between invocations could + // result in sample bias. + cl::opt<uint64_t> TemporalProfTraceReservoirSize( + "temporal-profile-trace-reservoir-size", cl::init(100), + cl::desc("The maximum number of stored temporal profile traces (default: " + "100)")); + cl::opt<uint64_t> TemporalProfMaxTraceLength( + "temporal-profile-max-trace-length", cl::init(10000), + cl::desc("The maximum length of a single temporal profile trace " + "(default: 10000)")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); @@ -1281,14 +1329,17 @@ static int merge_main(int argc, const char *argv[]) { if (ProfileKind == instr) mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(), - OutputFilename, OutputFormat, OutputSparse, NumThreads, + OutputFilename, OutputFormat, + TemporalProfTraceReservoirSize, + TemporalProfMaxTraceLength, OutputSparse, NumThreads, FailureMode, ProfiledBinary); else - mergeSampleProfile( - WeightedInputs, Remapper.get(), OutputFilename, OutputFormat, - ProfileSymbolListFile, CompressAllSections, UseMD5, GenPartialProfile, - GenCSNestedProfile, SampleMergeColdContext, SampleTrimColdContext, - SampleColdContextFrameDepth, FailureMode, DropProfileSymbolList); + mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename, + OutputFormat, ProfileSymbolListFile, CompressAllSections, + UseMD5, GenPartialProfile, ProfileLayout, + SampleMergeColdContext, SampleTrimColdContext, + SampleColdContextFrameDepth, FailureMode, + DropProfileSymbolList, OutputSizeLimit); return 0; } @@ -2189,12 +2240,13 @@ std::error_code SampleOverlapAggregator::loadProfiles() { using namespace sampleprof; LLVMContext Context; - auto BaseReaderOrErr = SampleProfileReader::create(BaseFilename, Context, + auto FS = vfs::getRealFileSystem(); + auto BaseReaderOrErr = SampleProfileReader::create(BaseFilename, Context, *FS, FSDiscriminatorPassOption); if (std::error_code EC = BaseReaderOrErr.getError()) exitWithErrorCode(EC, BaseFilename); - auto TestReaderOrErr = SampleProfileReader::create(TestFilename, Context, + auto TestReaderOrErr = SampleProfileReader::create(TestFilename, Context, *FS, FSDiscriminatorPassOption); if (std::error_code EC = TestReaderOrErr.getError()) exitWithErrorCode(EC, TestFilename); @@ -2358,21 +2410,20 @@ static void showValueSitesStats(raw_fd_ostream &OS, uint32_t VK, } } -static int showInstrProfile(const std::string &Filename, bool ShowCounts, - uint32_t TopN, bool ShowIndirectCallTargets, - bool ShowMemOPSizes, bool ShowDetailedSummary, - std::vector<uint32_t> DetailedSummaryCutoffs, - bool ShowAllFunctions, bool ShowCS, - uint64_t ValueCutoff, bool OnlyListBelow, - const std::string &ShowFunction, bool TextFormat, - bool ShowBinaryIds, bool ShowCovered, - bool ShowProfileVersion, ShowFormat SFormat, - raw_fd_ostream &OS) { +static int showInstrProfile( + const std::string &Filename, bool ShowCounts, uint32_t TopN, + bool ShowIndirectCallTargets, bool ShowMemOPSizes, bool ShowDetailedSummary, + std::vector<uint32_t> DetailedSummaryCutoffs, bool ShowAllFunctions, + bool ShowCS, uint64_t ValueCutoff, bool OnlyListBelow, + const std::string &ShowFunction, bool TextFormat, bool ShowBinaryIds, + bool ShowCovered, bool ShowProfileVersion, bool ShowTemporalProfTraces, + ShowFormat SFormat, raw_fd_ostream &OS) { if (SFormat == ShowFormat::Json) exitWithError("JSON output is not supported for instr profiles"); if (SFormat == ShowFormat::Yaml) exitWithError("YAML output is not supported for instr profiles"); - auto ReaderOrErr = InstrProfReader::create(Filename); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = InstrProfReader::create(Filename, *FS); std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs); if (ShowDetailedSummary && Cutoffs.empty()) { Cutoffs = ProfileSummaryBuilder::DefaultCutoffs; @@ -2583,6 +2634,19 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts, if (ShowProfileVersion) OS << "Profile version: " << Reader->getVersion() << "\n"; + + if (ShowTemporalProfTraces) { + auto &Traces = Reader->getTemporalProfTraces(); + OS << "Temporal Profile Traces (samples=" << Traces.size() + << " seen=" << Reader->getTemporalProfTraceStreamSize() << "):\n"; + for (unsigned i = 0; i < Traces.size(); i++) { + OS << " Temporal Profile Trace " << i << " (weight=" << Traces[i].Weight + << " count=" << Traces[i].FunctionNameRefs.size() << "):\n"; + for (auto &NameRef : Traces[i].FunctionNameRefs) + OS << " " << Reader->getSymtab().getFuncName(NameRef) << "\n"; + } + } + return 0; } @@ -2742,8 +2806,9 @@ static int showSampleProfile(const std::string &Filename, bool ShowCounts, exitWithError("YAML output is not supported for sample profiles"); using namespace sampleprof; LLVMContext Context; - auto ReaderOrErr = - SampleProfileReader::create(Filename, Context, FSDiscriminatorPassOption); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = SampleProfileReader::create(Filename, Context, *FS, + FSDiscriminatorPassOption); if (std::error_code EC = ReaderOrErr.getError()) exitWithErrorCode(EC, Filename); @@ -2917,6 +2982,9 @@ static int show_main(int argc, const char *argv[]) { "extbinary format")); cl::opt<bool> ShowBinaryIds("binary-ids", cl::init(false), cl::desc("Show binary ids in the profile. ")); + cl::opt<bool> ShowTemporalProfTraces( + "temporal-profile-traces", + cl::desc("Show temporal profile traces in the profile.")); cl::opt<std::string> DebugInfoFilename( "debug-info", cl::init(""), cl::desc("Read and extract profile metadata from debug info and show " @@ -2961,8 +3029,8 @@ static int show_main(int argc, const char *argv[]) { Filename, ShowCounts, TopNFunctions, ShowIndirectCallTargets, ShowMemOPSizes, ShowDetailedSummary, DetailedSummaryCutoffs, ShowAllFunctions, ShowCS, ValueCutoff, OnlyListBelow, ShowFunction, - TextFormat, ShowBinaryIds, ShowCovered, ShowProfileVersion, SFormat, - OS); + TextFormat, ShowBinaryIds, ShowCovered, ShowProfileVersion, + ShowTemporalProfTraces, SFormat, OS); if (ProfileKind == sample) return showSampleProfile(Filename, ShowCounts, TopNFunctions, ShowAllFunctions, ShowDetailedSummary, @@ -2971,20 +3039,73 @@ static int show_main(int argc, const char *argv[]) { return showMemProfProfile(Filename, ProfiledBinary, SFormat, OS); } -int llvm_profdata_main(int argc, char **argvNonConst) { +static int order_main(int argc, const char *argv[]) { + cl::opt<std::string> Filename(cl::Positional, cl::desc("<profdata-file>")); + cl::opt<std::string> OutputFilename("output", cl::value_desc("output"), + cl::init("-"), cl::desc("Output file")); + cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), + cl::aliasopt(OutputFilename)); + cl::ParseCommandLineOptions(argc, argv, "LLVM profile data order\n"); + + std::error_code EC; + raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF); + if (EC) + exitWithErrorCode(EC, OutputFilename); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = InstrProfReader::create(Filename, *FS); + if (Error E = ReaderOrErr.takeError()) + exitWithError(std::move(E), Filename); + + auto Reader = std::move(ReaderOrErr.get()); + for (auto &I : *Reader) { + // Read all entries + (void)I; + } + auto &Traces = Reader->getTemporalProfTraces(); + auto Nodes = TemporalProfTraceTy::createBPFunctionNodes(Traces); + BalancedPartitioningConfig Config; + BalancedPartitioning BP(Config); + BP.run(Nodes); + + WithColor::note() << "# Ordered " << Nodes.size() << " functions\n"; + for (auto &N : Nodes) { + auto FuncName = Reader->getSymtab().getFuncName(N.Id); + if (FuncName.contains(':')) { + // GlobalValue::getGlobalIdentifier() prefixes the filename if the symbol + // is local. This logic will break if there is a colon in the filename, + // but we cannot use rsplit() because ObjC symbols can have colons. + auto [Filename, ParsedFuncName] = FuncName.split(':'); + // Emit a comment describing where this symbol came from + OS << "# " << Filename << "\n"; + FuncName = ParsedFuncName; + } + OS << FuncName << "\n"; + } + return 0; +} + +typedef int (*llvm_profdata_subcommand)(int, const char *[]); + +static std::tuple<StringRef, llvm_profdata_subcommand> + llvm_profdata_subcommands[] = { + {"merge", merge_main}, + {"show", show_main}, + {"order", order_main}, + {"overlap", overlap_main}, +}; + +int llvm_profdata_main(int argc, char **argvNonConst, + const llvm::ToolContext &) { const char **argv = const_cast<const char **>(argvNonConst); InitLLVM X(argc, argv); StringRef ProgName(sys::path::filename(argv[0])); if (argc > 1) { - int (*func)(int, const char *[]) = nullptr; - if (strcmp(argv[1], "merge") == 0) - func = merge_main; - else if (strcmp(argv[1], "show") == 0) - func = show_main; - else if (strcmp(argv[1], "overlap") == 0) - func = overlap_main; + llvm_profdata_subcommand func = nullptr; + for (auto [subcmd_name, subcmd_action] : llvm_profdata_subcommands) + if (subcmd_name == argv[1]) + func = subcmd_action; if (func) { std::string Invocation(ProgName.str() + " " + argv[1]); @@ -2999,7 +3120,17 @@ int llvm_profdata_main(int argc, char **argvNonConst) { << "USAGE: " << ProgName << " <command> [args...]\n" << "USAGE: " << ProgName << " <command> -help\n\n" << "See each individual command --help for more details.\n" - << "Available commands: merge, show, overlap\n"; + << "Available commands: " + << join(map_range(llvm_profdata_subcommands, + [](auto const &KV) { return std::get<0>(KV); }), + ", ") + << "\n"; + return 0; + } + + if (strcmp(argv[1], "--version") == 0) { + outs() << ProgName << '\n'; + cl::PrintVersionMessage(); return 0; } } @@ -3009,6 +3140,10 @@ int llvm_profdata_main(int argc, char **argvNonConst) { else errs() << ProgName << ": Unknown command!\n"; - errs() << "USAGE: " << ProgName << " <merge|show|overlap> [args...]\n"; + errs() << "USAGE: " << ProgName << " <" + << join(map_range(llvm_profdata_subcommands, + [](auto const &KV) { return std::get<0>(KV); }), + "|") + << "> [args...]\n"; return 1; } diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp index 5279e5853cc5..0a5073d2d23f 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -344,6 +344,7 @@ const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = { LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64 ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64EC ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64X ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ), @@ -544,9 +545,10 @@ const EnumEntry<COFF::DebugType> ImageDebugType[] = { static const EnumEntry<COFF::WeakExternalCharacteristics> WeakExternalCharacteristics[] = { - { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY }, - { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY }, - { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } + { "NoLibrary" , COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY }, + { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY }, + { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS }, + { "AntiDependency" , COFF::IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY }, }; const EnumEntry<uint32_t> SubSectionTypes[] = { @@ -840,6 +842,93 @@ void COFFDumper::printCOFFLoadConfig() { else printCOFFLoadConfig(Obj->getLoadConfig32(), Tables); + if (auto CHPE = Obj->getCHPEMetadata()) { + ListScope LS(W, "CHPEMetadata"); + W.printHex("Version", CHPE->Version); + + if (CHPE->CodeMapCount) { + ListScope CMLS(W, "CodeMap"); + + uintptr_t CodeMapInt; + if (Error E = Obj->getRvaPtr(CHPE->CodeMap, CodeMapInt)) + reportError(std::move(E), Obj->getFileName()); + auto CodeMap = reinterpret_cast<const chpe_range_entry *>(CodeMapInt); + for (uint32_t i = 0; i < CHPE->CodeMapCount; i++) { + uint32_t Start = CodeMap[i].StartOffset & ~3; + W.startLine() << W.hex(Start) << " - " + << W.hex(Start + CodeMap[i].Length) << " "; + switch (CodeMap[i].StartOffset & 3) { + case CHPE_RANGE_ARM64: + W.getOStream() << "ARM64\n"; + break; + case CHPE_RANGE_ARM64EC: + W.getOStream() << "ARM64EC\n"; + break; + case CHPE_RANGE_AMD64: + W.getOStream() << "X64\n"; + break; + default: + W.getOStream() << W.hex(CodeMap[i].StartOffset & 3) << "\n"; + break; + } + } + } else { + W.printNumber("CodeMap", CHPE->CodeMap); + } + + if (CHPE->CodeRangesToEntryPointsCount) { + ListScope CRLS(W, "CodeRangesToEntryPoints"); + + uintptr_t CodeRangesInt; + if (Error E = + Obj->getRvaPtr(CHPE->CodeRangesToEntryPoints, CodeRangesInt)) + reportError(std::move(E), Obj->getFileName()); + auto CodeRanges = + reinterpret_cast<const chpe_code_range_entry *>(CodeRangesInt); + for (uint32_t i = 0; i < CHPE->CodeRangesToEntryPointsCount; i++) { + W.startLine() << W.hex(CodeRanges[i].StartRva) << " - " + << W.hex(CodeRanges[i].EndRva) << " -> " + << W.hex(CodeRanges[i].EntryPoint) << "\n"; + } + } else { + W.printNumber("CodeRangesToEntryPoints", CHPE->CodeRangesToEntryPoints); + } + + if (CHPE->RedirectionMetadataCount) { + ListScope RMLS(W, "RedirectionMetadata"); + + uintptr_t RedirMetadataInt; + if (Error E = Obj->getRvaPtr(CHPE->RedirectionMetadata, RedirMetadataInt)) + reportError(std::move(E), Obj->getFileName()); + auto RedirMetadata = + reinterpret_cast<const chpe_redirection_entry *>(RedirMetadataInt); + for (uint32_t i = 0; i < CHPE->RedirectionMetadataCount; i++) { + W.startLine() << W.hex(RedirMetadata[i].Source) << " -> " + << W.hex(RedirMetadata[i].Destination) << "\n"; + } + } else { + W.printNumber("RedirectionMetadata", CHPE->RedirectionMetadata); + } + + W.printHex("__os_arm64x_dispatch_call_no_redirect", + CHPE->__os_arm64x_dispatch_call_no_redirect); + W.printHex("__os_arm64x_dispatch_ret", CHPE->__os_arm64x_dispatch_ret); + W.printHex("__os_arm64x_dispatch_call", CHPE->__os_arm64x_dispatch_call); + W.printHex("__os_arm64x_dispatch_icall", CHPE->__os_arm64x_dispatch_icall); + W.printHex("__os_arm64x_dispatch_icall_cfg", + CHPE->__os_arm64x_dispatch_icall_cfg); + W.printHex("AlternateEntryPoint", CHPE->AlternateEntryPoint); + W.printHex("AuxiliaryIAT", CHPE->AuxiliaryIAT); + W.printHex("GetX64InformationFunctionPointer", + CHPE->GetX64InformationFunctionPointer); + W.printHex("SetX64InformationFunctionPointer", + CHPE->SetX64InformationFunctionPointer); + W.printHex("ExtraRFETable", CHPE->ExtraRFETable); + W.printHex("ExtraRFETableSize", CHPE->ExtraRFETableSize); + W.printHex("__os_arm64x_dispatch_fptr", CHPE->__os_arm64x_dispatch_fptr); + W.printHex("AuxiliaryIATCopy", CHPE->AuxiliaryIATCopy); + } + if (Tables.SEHTableVA) { ListScope LS(W, "SEHTable"); printRVATable(Tables.SEHTableVA, Tables.SEHTableCount, 4); @@ -919,7 +1008,7 @@ void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) { W.printHex("SecurityCookie", Conf->SecurityCookie); // Print the safe SEH table if present. - if (Conf->Size < offsetof(coff_load_configuration32, GuardCFCheckFunction)) + if (Conf->Size < offsetof(T, GuardCFCheckFunction)) return; W.printHex("SEHandlerTable", Conf->SEHandlerTable); W.printNumber("SEHandlerCount", Conf->SEHandlerCount); @@ -1670,6 +1759,7 @@ void COFFDumper::printUnwindInfo() { } case COFF::IMAGE_FILE_MACHINE_ARM64: case COFF::IMAGE_FILE_MACHINE_ARM64EC: + case COFF::IMAGE_FILE_MACHINE_ARM64X: case COFF::IMAGE_FILE_MACHINE_ARMNT: { ARM::WinEH::Decoder Decoder(W, Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_ARMNT); diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp index 45fff0cc4a76..aa924823e554 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -220,6 +220,15 @@ public: void printVersionInfo() override; void printArchSpecificInfo() override; void printStackMap() const override; + void printMemtag() override; + ArrayRef<uint8_t> getMemtagGlobalsSectionContents(uint64_t ExpectedAddr); + + // Hash histogram shows statistics of how efficient the hash was for the + // dynamic symbol table. The table shows the number of hash buckets for + // different lengths of chains as an absolute number and percentage of the + // total buckets, and the cumulative coverage of symbols for each set of + // buckets. + void printHashHistograms() override; const object::ELFObjectFile<ELFT> &getElfObject() const { return ObjF; }; @@ -234,6 +243,9 @@ public: return 4; } + std::vector<EnumEntry<unsigned>> + getOtherFlagsFromSymbol(const Elf_Ehdr &Header, const Elf_Sym &Symbol) const; + Elf_Dyn_Range dynamic_table() const { // A valid .dynamic section contains an array of entries terminated // with a DT_NULL entry. However, sometimes the section content may @@ -296,6 +308,17 @@ protected: virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0; virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; + virtual void printMemtag( + const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, + const ArrayRef<uint8_t> AndroidNoteDesc, + const ArrayRef<std::pair<uint64_t, uint64_t>> Descriptors) = 0; + + virtual void printHashHistogram(const Elf_Hash &HashTable) const; + virtual void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) const; + virtual void printHashHistogramStats(size_t NBucket, size_t MaxChain, + size_t TotalSyms, ArrayRef<size_t> Count, + bool IsGnu) const = 0; + Expected<ArrayRef<Elf_Versym>> getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab, StringRef *StrTab, const Elf_Shdr **SymTabSec) const; @@ -323,12 +346,6 @@ protected: void printRelocatableStackSizes(std::function<void()> PrintHeader); void printNonRelocatableStackSizes(std::function<void()> PrintHeader); - /// Retrieves sections with corresponding relocation sections based on - /// IsMatch. - void getSectionAndRelocations( - std::function<bool(const Elf_Shdr &)> IsMatch, - llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> &SecToRelocMap); - const object::ELFObjectFile<ELFT> &ObjF; const ELFFile<ELFT> &Obj; StringRef FileName; @@ -570,17 +587,21 @@ public: void printVersionSymbolSection(const Elf_Shdr *Sec) override; void printVersionDefinitionSection(const Elf_Shdr *Sec) override; void printVersionDependencySection(const Elf_Shdr *Sec) override; - void printHashHistograms() override; void printCGProfile() override; void printBBAddrMaps() override; void printAddrsig() override; void printNotes() override; void printELFLinkerOptions() override; void printStackSizes() override; + void printMemtag( + const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, + const ArrayRef<uint8_t> AndroidNoteDesc, + const ArrayRef<std::pair<uint64_t, uint64_t>> Descriptors) override; + void printHashHistogramStats(size_t NBucket, size_t MaxChain, + size_t TotalSyms, ArrayRef<size_t> Count, + bool IsGnu) const override; private: - void printHashHistogram(const Elf_Hash &HashTable); - void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable); void printHashTableSymbols(const Elf_Hash &HashTable); void printGnuHashTableSymbols(const Elf_GnuHash &GnuHashTable); @@ -674,21 +695,27 @@ public: void printVersionSymbolSection(const Elf_Shdr *Sec) override; void printVersionDefinitionSection(const Elf_Shdr *Sec) override; void printVersionDependencySection(const Elf_Shdr *Sec) override; - void printHashHistograms() override; void printCGProfile() override; void printBBAddrMaps() override; void printAddrsig() override; void printNotes() override; void printELFLinkerOptions() override; void printStackSizes() override; + void printMemtag( + const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, + const ArrayRef<uint8_t> AndroidNoteDesc, + const ArrayRef<std::pair<uint64_t, uint64_t>> Descriptors) override; + void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable) const; + void printHashHistogramStats(size_t NBucket, size_t MaxChain, + size_t TotalSyms, ArrayRef<size_t> Count, + bool IsGnu) const override; private: void printRelrReloc(const Elf_Relr &R) override; void printRelRelaReloc(const Relocation<ELFT> &R, const RelSymbol<ELFT> &RelSym) override; - void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, - DataRegion<Elf_Word> ShndxTable) const; void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, DataRegion<Elf_Word> ShndxTable, std::optional<StringRef> StrTable, bool IsDynamic, @@ -701,8 +728,22 @@ private: void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; void printMipsABIFlags() override; + virtual void printZeroSymbolOtherField(const Elf_Sym &Symbol) const; protected: + virtual std::string getGroupSectionHeaderName() const; + void printSymbolOtherField(const Elf_Sym &Symbol) const; + virtual void printExpandedRelRelaReloc(const Relocation<ELFT> &R, + StringRef SymbolName, + StringRef RelocName); + virtual void printDefaultRelRelaReloc(const Relocation<ELFT> &R, + StringRef SymbolName, + StringRef RelocName); + virtual void printRelocationSectionInfo(const Elf_Shdr &Sec, StringRef Name, + const unsigned SecNdx); + virtual void printSectionGroupMembers(StringRef Name, uint64_t Idx) const; + virtual void printEmptyGroupMessage() const; + ScopedPrinter &W; }; @@ -715,9 +756,23 @@ public: JSONELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer) : LLVMELFDumper<ELFT>(ObjF, Writer) {} + std::string getGroupSectionHeaderName() const override; + void printFileSummary(StringRef FileStr, ObjectFile &Obj, ArrayRef<std::string> InputFilenames, const Archive *A) override; + virtual void printZeroSymbolOtherField(const Elf_Sym &Symbol) const override; + + void printDefaultRelRelaReloc(const Relocation<ELFT> &R, + StringRef SymbolName, + StringRef RelocName) override; + + void printRelocationSectionInfo(const Elf_Shdr &Sec, StringRef Name, + const unsigned SecNdx) override; + + void printSectionGroupMembers(StringRef Name, uint64_t Idx) const override; + + void printEmptyGroupMessage() const override; private: std::unique_ptr<DictScope> FileScope; @@ -853,7 +908,7 @@ ELFDumper<ELFT>::getShndxTable(const Elf_Shdr *Symtab) const { } static std::string maybeDemangle(StringRef Name) { - return opts::Demangle ? demangle(std::string(Name)) : Name.str(); + return opts::Demangle ? demangle(Name) : Name.str(); } template <typename ELFT> @@ -1533,6 +1588,8 @@ const EnumEntry<unsigned> ElfHeaderAMDGPUFlagsABIVersion3[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90A), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90C), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX940), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX941), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX942), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012), @@ -1548,6 +1605,8 @@ const EnumEntry<unsigned> ElfHeaderAMDGPUFlagsABIVersion3[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1101), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1102), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1103), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1150), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1151), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_V3), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_V3) }; @@ -1593,6 +1652,8 @@ const EnumEntry<unsigned> ElfHeaderAMDGPUFlagsABIVersion4[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90A), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90C), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX940), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX941), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX942), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012), @@ -1608,6 +1669,8 @@ const EnumEntry<unsigned> ElfHeaderAMDGPUFlagsABIVersion4[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1101), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1102), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1103), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1150), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1151), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_ANY_V4), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_OFF_V4), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_ON_V4), @@ -2251,7 +2314,29 @@ std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type, case DT_AARCH64_BTI_PLT: case DT_AARCH64_PAC_PLT: case DT_AARCH64_VARIANT_PCS: + case DT_AARCH64_MEMTAG_GLOBALSSZ: return std::to_string(Value); + case DT_AARCH64_MEMTAG_MODE: + switch (Value) { + case 0: + return "Synchronous (0)"; + case 1: + return "Asynchronous (1)"; + default: + return (Twine("Unknown (") + Twine(Value) + ")").str(); + } + case DT_AARCH64_MEMTAG_HEAP: + case DT_AARCH64_MEMTAG_STACK: + switch (Value) { + case 0: + return "Disabled (0)"; + case 1: + return "Enabled (1)"; + default: + return (Twine("Unknown (") + Twine(Value) + ")").str(); + } + case DT_AARCH64_MEMTAG_GLOBALS: + return (Twine("0x") + utohexstr(Value, /*LowerCase=*/true)).str(); default: break; } @@ -2624,6 +2709,116 @@ void ELFDumper<ELFT>::printGnuHashTable() { W.printHexList("Values", *Chains); } +template <typename ELFT> void ELFDumper<ELFT>::printHashHistograms() { + // Print histogram for the .hash section. + if (this->HashTable) { + if (Error E = checkHashTable<ELFT>(*this, this->HashTable)) + this->reportUniqueWarning(std::move(E)); + else + printHashHistogram(*this->HashTable); + } + + // Print histogram for the .gnu.hash section. + if (this->GnuHashTable) { + if (Error E = checkGNUHashTable<ELFT>(this->Obj, this->GnuHashTable)) + this->reportUniqueWarning(std::move(E)); + else + printGnuHashHistogram(*this->GnuHashTable); + } +} + +template <typename ELFT> +void ELFDumper<ELFT>::printHashHistogram(const Elf_Hash &HashTable) const { + size_t NBucket = HashTable.nbucket; + size_t NChain = HashTable.nchain; + ArrayRef<Elf_Word> Buckets = HashTable.buckets(); + ArrayRef<Elf_Word> Chains = HashTable.chains(); + size_t TotalSyms = 0; + // If hash table is correct, we have at least chains with 0 length. + size_t MaxChain = 1; + + if (NChain == 0 || NBucket == 0) + return; + + std::vector<size_t> ChainLen(NBucket, 0); + // Go over all buckets and and note chain lengths of each bucket (total + // unique chain lengths). + for (size_t B = 0; B < NBucket; ++B) { + BitVector Visited(NChain); + for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) { + if (C == ELF::STN_UNDEF) + break; + if (Visited[C]) { + this->reportUniqueWarning( + ".hash section is invalid: bucket " + Twine(C) + + ": a cycle was detected in the linked chain"); + break; + } + Visited[C] = true; + if (MaxChain <= ++ChainLen[B]) + ++MaxChain; + } + TotalSyms += ChainLen[B]; + } + + if (!TotalSyms) + return; + + std::vector<size_t> Count(MaxChain, 0); + // Count how long is the chain for each bucket. + for (size_t B = 0; B < NBucket; B++) + ++Count[ChainLen[B]]; + // Print Number of buckets with each chain lengths and their cumulative + // coverage of the symbols. + printHashHistogramStats(NBucket, MaxChain, TotalSyms, Count, /*IsGnu=*/false); +} + +template <class ELFT> +void ELFDumper<ELFT>::printGnuHashHistogram( + const Elf_GnuHash &GnuHashTable) const { + Expected<ArrayRef<Elf_Word>> ChainsOrErr = + getGnuHashTableChains<ELFT>(this->DynSymRegion, &GnuHashTable); + if (!ChainsOrErr) { + this->reportUniqueWarning("unable to print the GNU hash table histogram: " + + toString(ChainsOrErr.takeError())); + return; + } + + ArrayRef<Elf_Word> Chains = *ChainsOrErr; + size_t Symndx = GnuHashTable.symndx; + size_t TotalSyms = 0; + size_t MaxChain = 1; + + size_t NBucket = GnuHashTable.nbuckets; + if (Chains.empty() || NBucket == 0) + return; + + ArrayRef<Elf_Word> Buckets = GnuHashTable.buckets(); + std::vector<size_t> ChainLen(NBucket, 0); + for (size_t B = 0; B < NBucket; ++B) { + if (!Buckets[B]) + continue; + size_t Len = 1; + for (size_t C = Buckets[B] - Symndx; + C < Chains.size() && (Chains[C] & 1) == 0; ++C) + if (MaxChain < ++Len) + ++MaxChain; + ChainLen[B] = Len; + TotalSyms += Len; + } + ++MaxChain; + + if (!TotalSyms) + return; + + std::vector<size_t> Count(MaxChain, 0); + for (size_t B = 0; B < NBucket; ++B) + ++Count[ChainLen[B]]; + // Print Number of buckets with each chain lengths and their cumulative + // coverage of the symbols. + printHashHistogramStats(NBucket, MaxChain, TotalSyms, Count, /*IsGnu=*/true); +} + template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { StringRef SOName = "<Not found>"; if (SONameOffset) @@ -3243,6 +3438,35 @@ void ELFDumper<ELFT>::printReloc(const Relocation<ELFT> &R, unsigned RelIndex, printRelRelaReloc(R, *Target); } +template <class ELFT> +std::vector<EnumEntry<unsigned>> +ELFDumper<ELFT>::getOtherFlagsFromSymbol(const Elf_Ehdr &Header, + const Elf_Sym &Symbol) const { + std::vector<EnumEntry<unsigned>> SymOtherFlags(std::begin(ElfSymOtherFlags), + std::end(ElfSymOtherFlags)); + if (Header.e_machine == EM_MIPS) { + // Someone in their infinite wisdom decided to make STO_MIPS_MIPS16 + // flag overlap with other ST_MIPS_xxx flags. So consider both + // cases separately. + if ((Symbol.st_other & STO_MIPS_MIPS16) == STO_MIPS_MIPS16) + SymOtherFlags.insert(SymOtherFlags.end(), + std::begin(ElfMips16SymOtherFlags), + std::end(ElfMips16SymOtherFlags)); + else + SymOtherFlags.insert(SymOtherFlags.end(), + std::begin(ElfMipsSymOtherFlags), + std::end(ElfMipsSymOtherFlags)); + } else if (Header.e_machine == EM_AARCH64) { + SymOtherFlags.insert(SymOtherFlags.end(), + std::begin(ElfAArch64SymOtherFlags), + std::end(ElfAArch64SymOtherFlags)); + } else if (Header.e_machine == EM_RISCV) { + SymOtherFlags.insert(SymOtherFlags.end(), std::begin(ElfRISCVSymOtherFlags), + std::end(ElfRISCVSymOtherFlags)); + } + return SymOtherFlags; +} + static inline void printFields(formatted_raw_ostream &OS, StringRef Str1, StringRef Str2) { OS.PadToColumn(2u); @@ -3537,15 +3761,18 @@ void GNUELFDumper<ELFT>::printRelRelaReloc(const Relocation<ELFT> &R, if (RelSym.Sym) Fields[3].Str = to_string(format_hex_no_prefix(RelSym.Sym->getValue(), Width)); + if (RelSym.Sym && RelSym.Name.empty()) + Fields[4].Str = "<null>"; + else + Fields[4].Str = std::string(RelSym.Name); - Fields[4].Str = std::string(RelSym.Name); for (const Field &F : Fields) printField(F); std::string Addend; if (std::optional<int64_t> A = R.Addend) { int64_t RelAddend = *A; - if (!RelSym.Name.empty()) { + if (!Fields[4].Str.empty()) { if (RelAddend < 0) { Addend = " - "; RelAddend = std::abs(RelAddend); @@ -4744,108 +4971,16 @@ void GNUELFDumper<ELFT>::printVersionDependencySection(const Elf_Shdr *Sec) { } template <class ELFT> -void GNUELFDumper<ELFT>::printHashHistogram(const Elf_Hash &HashTable) { - size_t NBucket = HashTable.nbucket; - size_t NChain = HashTable.nchain; - ArrayRef<Elf_Word> Buckets = HashTable.buckets(); - ArrayRef<Elf_Word> Chains = HashTable.chains(); - size_t TotalSyms = 0; - // If hash table is correct, we have at least chains with 0 length - size_t MaxChain = 1; - size_t CumulativeNonZero = 0; - - if (NChain == 0 || NBucket == 0) - return; - - std::vector<size_t> ChainLen(NBucket, 0); - // Go over all buckets and and note chain lengths of each bucket (total - // unique chain lengths). - for (size_t B = 0; B < NBucket; B++) { - BitVector Visited(NChain); - for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) { - if (C == ELF::STN_UNDEF) - break; - if (Visited[C]) { - this->reportUniqueWarning(".hash section is invalid: bucket " + - Twine(C) + - ": a cycle was detected in the linked chain"); - break; - } - Visited[C] = true; - if (MaxChain <= ++ChainLen[B]) - MaxChain++; - } - TotalSyms += ChainLen[B]; - } - - if (!TotalSyms) - return; - - std::vector<size_t> Count(MaxChain, 0); - // Count how long is the chain for each bucket - for (size_t B = 0; B < NBucket; B++) - ++Count[ChainLen[B]]; - // Print Number of buckets with each chain lengths and their cumulative - // coverage of the symbols - OS << "Histogram for bucket list length (total of " << NBucket - << " buckets)\n" - << " Length Number % of total Coverage\n"; - for (size_t I = 0; I < MaxChain; I++) { - CumulativeNonZero += Count[I] * I; - OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I], - (Count[I] * 100.0) / NBucket, - (CumulativeNonZero * 100.0) / TotalSyms); - } -} - -template <class ELFT> -void GNUELFDumper<ELFT>::printGnuHashHistogram( - const Elf_GnuHash &GnuHashTable) { - Expected<ArrayRef<Elf_Word>> ChainsOrErr = - getGnuHashTableChains<ELFT>(this->DynSymRegion, &GnuHashTable); - if (!ChainsOrErr) { - this->reportUniqueWarning("unable to print the GNU hash table histogram: " + - toString(ChainsOrErr.takeError())); - return; - } - - ArrayRef<Elf_Word> Chains = *ChainsOrErr; - size_t Symndx = GnuHashTable.symndx; - size_t TotalSyms = 0; - size_t MaxChain = 1; +void GNUELFDumper<ELFT>::printHashHistogramStats(size_t NBucket, + size_t MaxChain, + size_t TotalSyms, + ArrayRef<size_t> Count, + bool IsGnu) const { size_t CumulativeNonZero = 0; - - size_t NBucket = GnuHashTable.nbuckets; - if (Chains.empty() || NBucket == 0) - return; - - ArrayRef<Elf_Word> Buckets = GnuHashTable.buckets(); - std::vector<size_t> ChainLen(NBucket, 0); - for (size_t B = 0; B < NBucket; B++) { - if (!Buckets[B]) - continue; - size_t Len = 1; - for (size_t C = Buckets[B] - Symndx; - C < Chains.size() && (Chains[C] & 1) == 0; C++) - if (MaxChain < ++Len) - MaxChain++; - ChainLen[B] = Len; - TotalSyms += Len; - } - MaxChain++; - - if (!TotalSyms) - return; - - std::vector<size_t> Count(MaxChain, 0); - for (size_t B = 0; B < NBucket; B++) - ++Count[ChainLen[B]]; - // Print Number of buckets with each chain lengths and their cumulative - // coverage of the symbols - OS << "Histogram for `.gnu.hash' bucket list length (total of " << NBucket - << " buckets)\n" + OS << "Histogram for" << (IsGnu ? " `.gnu.hash'" : "") + << " bucket list length (total of " << NBucket << " buckets)\n" << " Length Number % of total Coverage\n"; - for (size_t I = 0; I < MaxChain; I++) { + for (size_t I = 0; I < MaxChain; ++I) { CumulativeNonZero += Count[I] * I; OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I], (Count[I] * 100.0) / NBucket, @@ -4853,28 +4988,6 @@ void GNUELFDumper<ELFT>::printGnuHashHistogram( } } -// Hash histogram shows statistics of how efficient the hash was for the -// dynamic symbol table. The table shows the number of hash buckets for -// different lengths of chains as an absolute number and percentage of the total -// buckets, and the cumulative coverage of symbols for each set of buckets. -template <class ELFT> void GNUELFDumper<ELFT>::printHashHistograms() { - // Print histogram for the .hash section. - if (this->HashTable) { - if (Error E = checkHashTable<ELFT>(*this, this->HashTable)) - this->reportUniqueWarning(std::move(E)); - else - printHashHistogram(*this->HashTable); - } - - // Print histogram for the .gnu.hash section. - if (this->GnuHashTable) { - if (Error E = checkGNUHashTable<ELFT>(this->Obj, this->GnuHashTable)) - this->reportUniqueWarning(std::move(E)); - else - printGnuHashHistogram(*this->GnuHashTable); - } -} - template <class ELFT> void GNUELFDumper<ELFT>::printCGProfile() { OS << "GNUStyle::printCGProfile not implemented\n"; } @@ -5194,10 +5307,36 @@ static bool printAndroidNote(raw_ostream &OS, uint32_t NoteType, return false; for (const auto &KV : Props) OS << " " << KV.first << ": " << KV.second << '\n'; - OS << '\n'; return true; } +template <class ELFT> +void GNUELFDumper<ELFT>::printMemtag( + const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, + const ArrayRef<uint8_t> AndroidNoteDesc, + const ArrayRef<std::pair<uint64_t, uint64_t>> Descriptors) { + OS << "Memtag Dynamic Entries:\n"; + if (DynamicEntries.empty()) + OS << " < none found >\n"; + for (const auto &DynamicEntryKV : DynamicEntries) + OS << " " << DynamicEntryKV.first << ": " << DynamicEntryKV.second + << "\n"; + + if (!AndroidNoteDesc.empty()) { + OS << "Memtag Android Note:\n"; + printAndroidNote(OS, ELF::NT_ANDROID_TYPE_MEMTAG, AndroidNoteDesc); + } + + if (Descriptors.empty()) + return; + + OS << "Memtag Global Descriptors:\n"; + for (const auto &[Addr, BytesToTag] : Descriptors) { + OS << " 0x" << utohexstr(Addr, /*LowerCase=*/true) << ": 0x" + << utohexstr(BytesToTag, /*LowerCase=*/true) << "\n"; + } +} + template <typename ELFT> static bool printLLVMOMPOFFLOADNote(raw_ostream &OS, uint32_t NoteType, ArrayRef<uint8_t> Desc) { @@ -5386,10 +5525,16 @@ static AMDGPUNote getAMDGPUNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) { if (!MsgPackDoc.readFromBlob(MsgPackString, /*Multi=*/false)) return {"", ""}; - AMDGPU::HSAMD::V3::MetadataVerifier Verifier(true); std::string MetadataString; - if (!Verifier.verify(MsgPackDoc.getRoot())) - MetadataString = "Invalid AMDGPU Metadata\n"; + + // FIXME: Metadata Verifier only works with AMDHSA. + // This is an ugly workaround to avoid the verifier for other MD + // formats (e.g. amdpal) + if (MsgPackString.find("amdhsa.") != StringRef::npos) { + AMDGPU::HSAMD::V3::MetadataVerifier Verifier(true); + if (!Verifier.verify(MsgPackDoc.getRoot())) + MetadataString = "Invalid AMDGPU Metadata\n"; + } raw_string_ostream StrOS(MetadataString); if (MsgPackDoc.getRoot().isScalar()) { @@ -5623,6 +5768,12 @@ const NoteType CoreNoteTypes[] = { "NT_ARM_HW_BREAK (AArch hardware breakpoint registers)"}, {ELF::NT_ARM_HW_WATCH, "NT_ARM_HW_WATCH (AArch hardware watchpoint registers)"}, + {ELF::NT_ARM_SVE, "NT_ARM_SVE (AArch64 SVE registers)"}, + {ELF::NT_ARM_PAC_MASK, + "NT_ARM_PAC_MASK (AArch64 Pointer Authentication code masks)"}, + {ELF::NT_ARM_SSVE, "NT_ARM_SSVE (AArch64 Streaming SVE registers)"}, + {ELF::NT_ARM_ZA, "NT_ARM_ZA (AArch64 SME ZA registers)"}, + {ELF::NT_ARM_ZT, "NT_ARM_ZT (AArch64 SME ZT registers)"}, {ELF::NT_FILE, "NT_FILE (mapped files)"}, {ELF::NT_PRXFPREG, "NT_PRXFPREG (user_xfpregs structure)"}, @@ -5681,10 +5832,10 @@ StringRef getNoteTypeName(const typename ELFT::Note &Note, unsigned ELFType) { } template <class ELFT> -static void printNotesHelper( +static void processNotesHelper( const ELFDumper<ELFT> &Dumper, llvm::function_ref<void(std::optional<StringRef>, typename ELFT::Off, - typename ELFT::Addr)> + typename ELFT::Addr, size_t)> StartNotesFn, llvm::function_ref<Error(const typename ELFT::Note &, bool)> ProcessNoteFn, llvm::function_ref<void()> FinishNotesFn) { @@ -5697,7 +5848,7 @@ static void printNotesHelper( if (S.sh_type != SHT_NOTE) continue; StartNotesFn(expectedToStdOptional(Obj.getSectionName(S)), S.sh_offset, - S.sh_size); + S.sh_size, S.sh_addralign); Error Err = Error::success(); size_t I = 0; for (const typename ELFT::Note Note : Obj.notes(S, Err)) { @@ -5728,7 +5879,7 @@ static void printNotesHelper( const typename ELFT::Phdr &P = (*PhdrsOrErr)[I]; if (P.p_type != PT_NOTE) continue; - StartNotesFn(/*SecName=*/std::nullopt, P.p_offset, P.p_filesz); + StartNotesFn(/*SecName=*/std::nullopt, P.p_offset, P.p_filesz, P.p_align); Error Err = Error::success(); size_t Index = 0; for (const typename ELFT::Note Note : Obj.notes(P, Err)) { @@ -5748,10 +5899,12 @@ static void printNotesHelper( } template <class ELFT> void GNUELFDumper<ELFT>::printNotes() { + size_t Align = 0; bool IsFirstHeader = true; auto PrintHeader = [&](std::optional<StringRef> SecName, const typename ELFT::Off Offset, - const typename ELFT::Addr Size) { + const typename ELFT::Addr Size, size_t Al) { + Align = std::max<size_t>(Al, 4); // Print a newline between notes sections to match GNU readelf. if (!IsFirstHeader) { OS << '\n'; @@ -5772,7 +5925,7 @@ template <class ELFT> void GNUELFDumper<ELFT>::printNotes() { auto ProcessNote = [&](const Elf_Note &Note, bool IsCore) -> Error { StringRef Name = Note.getName(); - ArrayRef<uint8_t> Descriptor = Note.getDesc(); + ArrayRef<uint8_t> Descriptor = Note.getDesc(Align); Elf_Word Type = Note.getType(); // Print the note owner/type. @@ -5837,7 +5990,132 @@ template <class ELFT> void GNUELFDumper<ELFT>::printNotes() { return Error::success(); }; - printNotesHelper(*this, PrintHeader, ProcessNote, []() {}); + processNotesHelper(*this, /*StartNotesFn=*/PrintHeader, + /*ProcessNoteFn=*/ProcessNote, /*FinishNotesFn=*/[]() {}); +} + +template <class ELFT> +ArrayRef<uint8_t> +ELFDumper<ELFT>::getMemtagGlobalsSectionContents(uint64_t ExpectedAddr) { + for (const typename ELFT::Shdr &Sec : cantFail(Obj.sections())) { + if (Sec.sh_type != SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC) + continue; + if (Sec.sh_addr != ExpectedAddr) { + reportUniqueWarning( + "SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section was unexpectedly at 0x" + + Twine::utohexstr(Sec.sh_addr) + + ", when DT_AARCH64_MEMTAG_GLOBALS says it should be at 0x" + + Twine::utohexstr(ExpectedAddr)); + return ArrayRef<uint8_t>(); + } + Expected<ArrayRef<uint8_t>> Contents = Obj.getSectionContents(Sec); + if (auto E = Contents.takeError()) { + reportUniqueWarning( + "couldn't get SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section contents: " + + toString(std::move(E))); + return ArrayRef<uint8_t>(); + } + return Contents.get(); + } + return ArrayRef<uint8_t>(); +} + +// Reserve the lower three bits of the first byte of the step distance when +// encoding the memtag descriptors. Found to be the best overall size tradeoff +// when compiling Android T with full MTE globals enabled. +constexpr uint64_t MemtagStepVarintReservedBits = 3; +constexpr uint64_t MemtagGranuleSize = 16; + +template <typename ELFT> void ELFDumper<ELFT>::printMemtag() { + if (Obj.getHeader().e_machine != EM_AARCH64) return; + std::vector<std::pair<std::string, std::string>> DynamicEntries; + uint64_t MemtagGlobalsSz = 0; + uint64_t MemtagGlobals = 0; + for (const typename ELFT::Dyn &Entry : dynamic_table()) { + uintX_t Tag = Entry.getTag(); + switch (Tag) { + case DT_AARCH64_MEMTAG_GLOBALSSZ: + MemtagGlobalsSz = Entry.getVal(); + DynamicEntries.emplace_back(Obj.getDynamicTagAsString(Tag), + getDynamicEntry(Tag, Entry.getVal())); + break; + case DT_AARCH64_MEMTAG_GLOBALS: + MemtagGlobals = Entry.getVal(); + DynamicEntries.emplace_back(Obj.getDynamicTagAsString(Tag), + getDynamicEntry(Tag, Entry.getVal())); + break; + case DT_AARCH64_MEMTAG_MODE: + case DT_AARCH64_MEMTAG_HEAP: + case DT_AARCH64_MEMTAG_STACK: + DynamicEntries.emplace_back(Obj.getDynamicTagAsString(Tag), + getDynamicEntry(Tag, Entry.getVal())); + break; + } + } + + ArrayRef<uint8_t> AndroidNoteDesc; + auto FindAndroidNote = [&](const Elf_Note &Note, bool IsCore) -> Error { + if (Note.getName() == "Android" && + Note.getType() == ELF::NT_ANDROID_TYPE_MEMTAG) + AndroidNoteDesc = Note.getDesc(4); + return Error::success(); + }; + + processNotesHelper( + *this, + /*StartNotesFn=*/ + [](std::optional<StringRef>, const typename ELFT::Off, + const typename ELFT::Addr, size_t) {}, + /*ProcessNoteFn=*/FindAndroidNote, /*FinishNotesFn=*/[]() {}); + + ArrayRef<uint8_t> Contents = getMemtagGlobalsSectionContents(MemtagGlobals); + if (Contents.size() != MemtagGlobalsSz) { + reportUniqueWarning( + "mismatch between DT_AARCH64_MEMTAG_GLOBALSSZ (0x" + + Twine::utohexstr(MemtagGlobalsSz) + + ") and SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section size (0x" + + Twine::utohexstr(Contents.size()) + ")"); + Contents = ArrayRef<uint8_t>(); + } + + std::vector<std::pair<uint64_t, uint64_t>> GlobalDescriptors; + uint64_t Address = 0; + // See the AArch64 MemtagABI document for a description of encoding scheme: + // https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#83encoding-of-sht_aarch64_memtag_globals_dynamic + for (size_t I = 0; I < Contents.size();) { + const char *Error = nullptr; + unsigned DecodedBytes = 0; + uint64_t Value = decodeULEB128(Contents.data() + I, &DecodedBytes, + Contents.end(), &Error); + I += DecodedBytes; + if (Error) { + reportUniqueWarning( + "error decoding distance uleb, " + Twine(DecodedBytes) + + " byte(s) into SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC: " + Twine(Error)); + GlobalDescriptors.clear(); + break; + } + uint64_t Distance = Value >> MemtagStepVarintReservedBits; + uint64_t GranulesToTag = Value & ((1 << MemtagStepVarintReservedBits) - 1); + if (GranulesToTag == 0) { + GranulesToTag = decodeULEB128(Contents.data() + I, &DecodedBytes, + Contents.end(), &Error) + + 1; + I += DecodedBytes; + if (Error) { + reportUniqueWarning( + "error decoding size-only uleb, " + Twine(DecodedBytes) + + " byte(s) into SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC: " + Twine(Error)); + GlobalDescriptors.clear(); + break; + } + } + Address += Distance * MemtagGranuleSize; + GlobalDescriptors.emplace_back(Address, GranulesToTag * MemtagGranuleSize); + Address += GranulesToTag * MemtagGranuleSize; + } + + printMemtag(DynamicEntries, AndroidNoteDesc, GlobalDescriptors); } template <class ELFT> void GNUELFDumper<ELFT>::printELFLinkerOptions() { @@ -6197,37 +6475,10 @@ void ELFDumper<ELFT>::printNonRelocatableStackSizes( } template <class ELFT> -void ELFDumper<ELFT>::getSectionAndRelocations( - std::function<bool(const Elf_Shdr &)> IsMatch, - llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> &SecToRelocMap) { - for (const Elf_Shdr &Sec : cantFail(Obj.sections())) { - if (IsMatch(Sec)) - if (SecToRelocMap.insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr)) - .second) - continue; - - if (Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_REL) - continue; - - Expected<const Elf_Shdr *> RelSecOrErr = Obj.getSection(Sec.sh_info); - if (!RelSecOrErr) { - reportUniqueWarning(describe(Sec) + - ": failed to get a relocated section: " + - toString(RelSecOrErr.takeError())); - continue; - } - const Elf_Shdr *ContentsSec = *RelSecOrErr; - if (IsMatch(*ContentsSec)) - SecToRelocMap[ContentsSec] = &Sec; - } -} - -template <class ELFT> void ELFDumper<ELFT>::printRelocatableStackSizes( std::function<void()> PrintHeader) { // Build a map between stack size sections and their corresponding relocation // sections. - llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> StackSizeRelocMap; auto IsMatch = [&](const Elf_Shdr &Sec) -> bool { StringRef SectionName; if (Expected<StringRef> NameOrErr = Obj.getSectionName(Sec)) @@ -6237,9 +6488,16 @@ void ELFDumper<ELFT>::printRelocatableStackSizes( return SectionName == ".stack_sizes"; }; - getSectionAndRelocations(IsMatch, StackSizeRelocMap); - for (const auto &StackSizeMapEntry : StackSizeRelocMap) { + Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> + StackSizeRelocMapOrErr = Obj.getSectionAndRelocations(IsMatch); + if (!StackSizeRelocMapOrErr) { + reportUniqueWarning("unable to get stack size map section(s): " + + toString(StackSizeRelocMapOrErr.takeError())); + return; + } + + for (const auto &StackSizeMapEntry : *StackSizeRelocMapOrErr) { PrintHeader(); const Elf_Shdr *StackSizesELFSec = StackSizeMapEntry.first; const Elf_Shdr *RelocSec = StackSizeMapEntry.second; @@ -6607,9 +6865,9 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printGroupSections() { W.printNumber("Link", G.Link); W.printNumber("Info", G.Info); W.printHex("Type", getGroupType(G.Type), G.Type); - W.startLine() << "Signature: " << G.Signature << "\n"; + W.printString("Signature", G.Signature); - ListScope L(W, "Section(s) in group"); + ListScope L(W, getGroupSectionHeaderName()); for (const GroupMember &GM : G.Members) { const GroupSection *MainGroup = Map[GM.Index]; if (MainGroup != &G) @@ -6619,12 +6877,23 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printGroupSections() { Twine(MainGroup->Index) + ", was also found in the group section with index " + Twine(G.Index)); - W.startLine() << GM.Name << " (" << GM.Index << ")\n"; + printSectionGroupMembers(GM.Name, GM.Index); } } if (V.empty()) - W.startLine() << "There are no group sections in the file.\n"; + printEmptyGroupMessage(); +} + +template <class ELFT> +std::string LLVMELFDumper<ELFT>::getGroupSectionHeaderName() const { + return "Section(s) in group"; +} + +template <class ELFT> +void LLVMELFDumper<ELFT>::printSectionGroupMembers(StringRef Name, + uint64_t Idx) const { + W.startLine() << Name << " (" << Idx << ")\n"; } template <class ELFT> void LLVMELFDumper<ELFT>::printRelocations() { @@ -6636,11 +6905,7 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printRelocations() { StringRef Name = this->getPrintableSectionName(Sec); unsigned SecNdx = &Sec - &cantFail(this->Obj.sections()).front(); - W.startLine() << "Section (" << SecNdx << ") " << Name << " {\n"; - W.indent(); - this->printRelocationsHelper(Sec); - W.unindent(); - W.startLine() << "}\n"; + printRelocationSectionInfo(Sec, Name, SecNdx); } } @@ -6650,26 +6915,54 @@ void LLVMELFDumper<ELFT>::printRelrReloc(const Elf_Relr &R) { } template <class ELFT> +void LLVMELFDumper<ELFT>::printExpandedRelRelaReloc(const Relocation<ELFT> &R, + StringRef SymbolName, + StringRef RelocName) { + DictScope Group(W, "Relocation"); + W.printHex("Offset", R.Offset); + W.printNumber("Type", RelocName, R.Type); + W.printNumber("Symbol", !SymbolName.empty() ? SymbolName : "-", R.Symbol); + if (R.Addend) + W.printHex("Addend", (uintX_t)*R.Addend); +} + +template <class ELFT> +void LLVMELFDumper<ELFT>::printDefaultRelRelaReloc(const Relocation<ELFT> &R, + StringRef SymbolName, + StringRef RelocName) { + raw_ostream &OS = W.startLine(); + OS << W.hex(R.Offset) << " " << RelocName << " " + << (!SymbolName.empty() ? SymbolName : "-"); + if (R.Addend) + OS << " " << W.hex((uintX_t)*R.Addend); + OS << "\n"; +} + +template <class ELFT> +void LLVMELFDumper<ELFT>::printRelocationSectionInfo(const Elf_Shdr &Sec, + StringRef Name, + const unsigned SecNdx) { + DictScope D(W, (Twine("Section (") + Twine(SecNdx) + ") " + Name).str()); + this->printRelocationsHelper(Sec); +} + +template <class ELFT> void LLVMELFDumper<ELFT>::printEmptyGroupMessage() const { + W.startLine() << "There are no group sections in the file.\n"; +} + +template <class ELFT> void LLVMELFDumper<ELFT>::printRelRelaReloc(const Relocation<ELFT> &R, const RelSymbol<ELFT> &RelSym) { StringRef SymbolName = RelSym.Name; + if (RelSym.Sym && RelSym.Name.empty()) + SymbolName = "<null>"; SmallString<32> RelocName; this->Obj.getRelocationTypeName(R.Type, RelocName); if (opts::ExpandRelocs) { - DictScope Group(W, "Relocation"); - W.printHex("Offset", R.Offset); - W.printNumber("Type", RelocName, R.Type); - W.printNumber("Symbol", !SymbolName.empty() ? SymbolName : "-", R.Symbol); - if (R.Addend) - W.printHex("Addend", (uintX_t)*R.Addend); + printExpandedRelRelaReloc(R, SymbolName, RelocName); } else { - raw_ostream &OS = W.startLine(); - OS << W.hex(R.Offset) << " " << RelocName << " " - << (!SymbolName.empty() ? SymbolName : "-"); - if (R.Addend) - OS << " " << W.hex((uintX_t)*R.Addend); - OS << "\n"; + printDefaultRelRelaReloc(R, SymbolName, RelocName); } } @@ -6785,6 +7078,22 @@ void LLVMELFDumper<ELFT>::printSymbolSection( } template <class ELFT> +void LLVMELFDumper<ELFT>::printSymbolOtherField(const Elf_Sym &Symbol) const { + std::vector<EnumEntry<unsigned>> SymOtherFlags = + this->getOtherFlagsFromSymbol(this->Obj.getHeader(), Symbol); + W.printFlags("Other", Symbol.st_other, ArrayRef(SymOtherFlags), 0x3u); +} + +template <class ELFT> +void LLVMELFDumper<ELFT>::printZeroSymbolOtherField( + const Elf_Sym &Symbol) const { + assert(Symbol.st_other == 0 && "non-zero Other Field"); + // Usually st_other flag is zero. Do not pollute the output + // by flags enumeration in that case. + W.printNumber("Other", 0); +} + +template <class ELFT> void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, DataRegion<Elf_Word> ShndxTable, std::optional<StringRef> StrTable, @@ -6805,35 +7114,9 @@ void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, else W.printEnum("Type", SymbolType, ArrayRef(ElfSymbolTypes)); if (Symbol.st_other == 0) - // Usually st_other flag is zero. Do not pollute the output - // by flags enumeration in that case. - W.printNumber("Other", 0); - else { - std::vector<EnumEntry<unsigned>> SymOtherFlags(std::begin(ElfSymOtherFlags), - std::end(ElfSymOtherFlags)); - if (this->Obj.getHeader().e_machine == EM_MIPS) { - // Someones in their infinite wisdom decided to make STO_MIPS_MIPS16 - // flag overlapped with other ST_MIPS_xxx flags. So consider both - // cases separately. - if ((Symbol.st_other & STO_MIPS_MIPS16) == STO_MIPS_MIPS16) - SymOtherFlags.insert(SymOtherFlags.end(), - std::begin(ElfMips16SymOtherFlags), - std::end(ElfMips16SymOtherFlags)); - else - SymOtherFlags.insert(SymOtherFlags.end(), - std::begin(ElfMipsSymOtherFlags), - std::end(ElfMipsSymOtherFlags)); - } else if (this->Obj.getHeader().e_machine == EM_AARCH64) { - SymOtherFlags.insert(SymOtherFlags.end(), - std::begin(ElfAArch64SymOtherFlags), - std::end(ElfAArch64SymOtherFlags)); - } else if (this->Obj.getHeader().e_machine == EM_RISCV) { - SymOtherFlags.insert(SymOtherFlags.end(), - std::begin(ElfRISCVSymOtherFlags), - std::end(ElfRISCVSymOtherFlags)); - } - W.printFlags("Other", Symbol.st_other, ArrayRef(SymOtherFlags), 0x3u); - } + printZeroSymbolOtherField(Symbol); + else + printSymbolOtherField(Symbol); printSymbolSection(Symbol, SymIndex, ShndxTable); } @@ -7009,8 +7292,27 @@ void LLVMELFDumper<ELFT>::printVersionDependencySection(const Elf_Shdr *Sec) { } } -template <class ELFT> void LLVMELFDumper<ELFT>::printHashHistograms() { - W.startLine() << "Hash Histogram not implemented!\n"; +template <class ELFT> +void LLVMELFDumper<ELFT>::printHashHistogramStats(size_t NBucket, + size_t MaxChain, + size_t TotalSyms, + ArrayRef<size_t> Count, + bool IsGnu) const { + StringRef HistName = IsGnu ? "GnuHashHistogram" : "HashHistogram"; + StringRef BucketName = IsGnu ? "Bucket" : "Chain"; + StringRef ListName = IsGnu ? "Buckets" : "Chains"; + DictScope Outer(W, HistName); + W.printNumber("TotalBuckets", NBucket); + ListScope Buckets(W, ListName); + size_t CumulativeNonZero = 0; + for (size_t I = 0; I < MaxChain; ++I) { + CumulativeNonZero += Count[I] * I; + DictScope Bucket(W, BucketName); + W.printNumber("Length", I); + W.printNumber("Count", Count[I]); + W.printNumber("Percentage", (float)(Count[I] * 100.0) / NBucket); + W.printNumber("Coverage", (float)(CumulativeNonZero * 100.0) / TotalSyms); + } } // Returns true if rel/rela section exists, and populates SymbolIndices. @@ -7063,14 +7365,19 @@ static bool getSymbolIndices(const typename ELFT::Shdr *CGRelSection, } template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() { - llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> SecToRelocMap; - auto IsMatch = [](const Elf_Shdr &Sec) -> bool { return Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE; }; - this->getSectionAndRelocations(IsMatch, SecToRelocMap); - for (const auto &CGMapEntry : SecToRelocMap) { + Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr = + this->Obj.getSectionAndRelocations(IsMatch); + if (!SecToRelocMapOrErr) { + this->reportUniqueWarning("unable to get CG Profile section(s): " + + toString(SecToRelocMapOrErr.takeError())); + return; + } + + for (const auto &CGMapEntry : *SecToRelocMapOrErr) { const Elf_Shdr *CGSection = CGMapEntry.first; const Elf_Shdr *CGRelSection = CGMapEntry.second; @@ -7109,21 +7416,35 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() { template <class ELFT> void LLVMELFDumper<ELFT>::printBBAddrMaps() { bool IsRelocatable = this->Obj.getHeader().e_type == ELF::ET_REL; - for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) { - if (Sec.sh_type != SHT_LLVM_BB_ADDR_MAP && - Sec.sh_type != SHT_LLVM_BB_ADDR_MAP_V0) { - continue; - } + using Elf_Shdr = typename ELFT::Shdr; + auto IsMatch = [](const Elf_Shdr &Sec) -> bool { + return Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP || + Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP_V0; + }; + Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecRelocMapOrErr = + this->Obj.getSectionAndRelocations(IsMatch); + if (!SecRelocMapOrErr) { + this->reportUniqueWarning( + "failed to get SHT_LLVM_BB_ADDR_MAP section(s): " + + toString(SecRelocMapOrErr.takeError())); + return; + } + for (auto const &[Sec, RelocSec] : *SecRelocMapOrErr) { std::optional<const Elf_Shdr *> FunctionSec; if (IsRelocatable) FunctionSec = - unwrapOrError(this->FileName, this->Obj.getSection(Sec.sh_link)); + unwrapOrError(this->FileName, this->Obj.getSection(Sec->sh_link)); ListScope L(W, "BBAddrMap"); + if (IsRelocatable && !RelocSec) { + this->reportUniqueWarning("unable to get relocation section for " + + this->describe(*Sec)); + continue; + } Expected<std::vector<BBAddrMap>> BBAddrMapOrErr = - this->Obj.decodeBBAddrMap(Sec); + this->Obj.decodeBBAddrMap(*Sec, RelocSec); if (!BBAddrMapOrErr) { - this->reportUniqueWarning("unable to dump " + this->describe(Sec) + ": " + - toString(BBAddrMapOrErr.takeError())); + this->reportUniqueWarning("unable to dump " + this->describe(*Sec) + + ": " + toString(BBAddrMapOrErr.takeError())); continue; } for (const BBAddrMap &AM : *BBAddrMapOrErr) { @@ -7135,7 +7456,7 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printBBAddrMaps() { if (FuncSymIndex.empty()) this->reportUniqueWarning( "could not identify function symbol for address (0x" + - Twine::utohexstr(AM.Addr) + ") in " + this->describe(Sec)); + Twine::utohexstr(AM.Addr) + ") in " + this->describe(*Sec)); else FuncName = this->getStaticSymbolName(FuncSymIndex.front()); W.printString("Name", FuncName); @@ -7146,10 +7467,11 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printBBAddrMaps() { W.printNumber("ID", BBE.ID); W.printHex("Offset", BBE.Offset); W.printHex("Size", BBE.Size); - W.printBoolean("HasReturn", BBE.HasReturn); - W.printBoolean("HasTailCall", BBE.HasTailCall); - W.printBoolean("IsEHPad", BBE.IsEHPad); - W.printBoolean("CanFallThrough", BBE.CanFallThrough); + W.printBoolean("HasReturn", BBE.hasReturn()); + W.printBoolean("HasTailCall", BBE.hasTailCall()); + W.printBoolean("IsEHPad", BBE.isEHPad()); + W.printBoolean("CanFallThrough", BBE.canFallThrough()); + W.printBoolean("HasIndirectBranch", BBE.MD.HasIndirectBranch); } } } @@ -7216,6 +7538,35 @@ static bool printAndroidNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc, return true; } +template <class ELFT> +void LLVMELFDumper<ELFT>::printMemtag( + const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, + const ArrayRef<uint8_t> AndroidNoteDesc, + const ArrayRef<std::pair<uint64_t, uint64_t>> Descriptors) { + { + ListScope L(W, "Memtag Dynamic Entries:"); + if (DynamicEntries.empty()) + W.printString("< none found >"); + for (const auto &DynamicEntryKV : DynamicEntries) + W.printString(DynamicEntryKV.first, DynamicEntryKV.second); + } + + if (!AndroidNoteDesc.empty()) { + ListScope L(W, "Memtag Android Note:"); + printAndroidNoteLLVMStyle(ELF::NT_ANDROID_TYPE_MEMTAG, AndroidNoteDesc, W); + } + + if (Descriptors.empty()) + return; + + { + ListScope L(W, "Memtag Global Descriptors:"); + for (const auto &[Addr, BytesToTag] : Descriptors) { + W.printHex("0x" + utohexstr(Addr), BytesToTag); + } + } +} + template <typename ELFT> static bool printLLVMOMPOFFLOADNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc, @@ -7251,9 +7602,11 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printNotes() { ListScope L(W, "Notes"); std::unique_ptr<DictScope> NoteScope; + size_t Align = 0; auto StartNotes = [&](std::optional<StringRef> SecName, const typename ELFT::Off Offset, - const typename ELFT::Addr Size) { + const typename ELFT::Addr Size, size_t Al) { + Align = std::max<size_t>(Al, 4); NoteScope = std::make_unique<DictScope>(W, "NoteSection"); W.printString("Name", SecName ? *SecName : "<?>"); W.printHex("Offset", Offset); @@ -7265,7 +7618,7 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printNotes() { auto ProcessNote = [&](const Elf_Note &Note, bool IsCore) -> Error { DictScope D2(W, "Note"); StringRef Name = Note.getName(); - ArrayRef<uint8_t> Descriptor = Note.getDesc(); + ArrayRef<uint8_t> Descriptor = Note.getDesc(Align); Elf_Word Type = Note.getType(); // Print the note owner/type. @@ -7328,7 +7681,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printNotes() { return Error::success(); }; - printNotesHelper(*this, StartNotes, ProcessNote, EndNotes); + processNotesHelper(*this, /*StartNotesFn=*/StartNotes, + /*ProcessNoteFn=*/ProcessNote, /*FinishNotesFn=*/EndNotes); } template <class ELFT> void LLVMELFDumper<ELFT>::printELFLinkerOptions() { @@ -7554,3 +7908,45 @@ void JSONELFDumper<ELFT>::printFileSummary(StringRef FileStr, ObjectFile &Obj, std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress()))); this->printLoadName(); } + +template <class ELFT> +void JSONELFDumper<ELFT>::printZeroSymbolOtherField( + const Elf_Sym &Symbol) const { + // We want the JSON format to be uniform, since it is machine readable, so + // always print the `Other` field the same way. + this->printSymbolOtherField(Symbol); +} + +template <class ELFT> +void JSONELFDumper<ELFT>::printDefaultRelRelaReloc(const Relocation<ELFT> &R, + StringRef SymbolName, + StringRef RelocName) { + this->printExpandedRelRelaReloc(R, SymbolName, RelocName); +} + +template <class ELFT> +void JSONELFDumper<ELFT>::printRelocationSectionInfo(const Elf_Shdr &Sec, + StringRef Name, + const unsigned SecNdx) { + DictScope Group(this->W); + this->W.printNumber("SectionIndex", SecNdx); + ListScope D(this->W, "Relocs"); + this->printRelocationsHelper(Sec); +} + +template <class ELFT> +std::string JSONELFDumper<ELFT>::getGroupSectionHeaderName() const { + return "GroupSections"; +} + +template <class ELFT> +void JSONELFDumper<ELFT>::printSectionGroupMembers(StringRef Name, + uint64_t Idx) const { + DictScope Grp(this->W); + this->W.printString("Name", Name); + this->W.printNumber("Index", Idx); +} + +template <class ELFT> void JSONELFDumper<ELFT>::printEmptyGroupMessage() const { + // JSON output does not need to print anything for empty groups +} diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h index 258d87240984..921792f886d0 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h @@ -136,6 +136,7 @@ public: virtual void printStackSizes() {} virtual void printSectionDetails() {} virtual void printArchSpecificInfo() {} + virtual void printMemtag() {} // Only implemented for PE/COFF. virtual void printCOFFImports() { } diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/Opts.td b/contrib/llvm-project/llvm/tools/llvm-readobj/Opts.td index 4f7b12f95a60..fec0adb5e6a6 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/Opts.td +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/Opts.td @@ -55,6 +55,7 @@ def section_groups : FF<"section-groups", "Display section groups">, Group<grp_e def gnu_hash_table : FF<"gnu-hash-table", "Display the GNU hash table for dynamic symbols">, Group<grp_elf>; def hash_symbols : FF<"hash-symbols", "Display the dynamic symbols derived from the hash section">, Group<grp_elf>; def hash_table : FF<"hash-table", "Display .hash section">, Group<grp_elf>; +def memtag : FF<"memtag", "Display memory tagging metadata (modes, Android notes, global descriptors)">, Group<grp_elf>; def needed_libs : FF<"needed-libs", "Display the needed libraries">, Group<grp_elf>; def notes : FF<"notes", "Display notes">, Group<grp_elf>; def program_headers : FF<"program-headers", "Display program headers">, Group<grp_elf>; diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp index 56f672b3c5aa..74ebcc4ec7d8 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -98,10 +98,11 @@ void XCOFFDumper::printFileHeaders() { // tests will let us know. time_t TimeDate = TimeStamp; - char FormattedTime[21] = {}; - size_t BytesWritten = - strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate)); - if (BytesWritten) + char FormattedTime[80] = {}; + + size_t BytesFormatted = + strftime(FormattedTime, sizeof(FormattedTime), "%F %T", gmtime(&TimeDate)); + if (BytesFormatted) W.printHex("TimeStamp", FormattedTime, TimeStamp); else W.printHex("Timestamp", TimeStamp); @@ -709,7 +710,7 @@ static StringRef GetSymbolValueName(XCOFF::StorageClass SC) { const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = { #define ECase(X) \ { #X, XCOFF::X } - ECase(TB_C), ECase(TB_CPLUSPLUS) + ECase(TB_C), ECase(TB_Fortran), ECase(TB_CPLUSPLUS) #undef ECase }; diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp index a11de35fcd76..d72eec04d06a 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -43,6 +43,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/WithColor.h" @@ -135,6 +136,7 @@ static bool GnuHashTable; static bool HashSymbols; static bool HashTable; static bool HashHistogram; +static bool Memtag; static bool NeededLibraries; static bool Notes; static bool ProgramHeaders; @@ -265,6 +267,7 @@ static void parseOptions(const opt::InputArgList &Args) { opts::HashSymbols = Args.hasArg(OPT_hash_symbols); opts::HashTable = Args.hasArg(OPT_hash_table); opts::HashHistogram = Args.hasArg(OPT_histogram); + opts::Memtag = Args.hasArg(OPT_memtag); opts::NeededLibraries = Args.hasArg(OPT_needed_libs); opts::Notes = Args.hasArg(OPT_notes); opts::PrettyPrint = Args.hasArg(OPT_pretty_print); @@ -472,6 +475,8 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer, Dumper->printAddrsig(); if (opts::Notes) Dumper->printNotes(); + if (opts::Memtag) + Dumper->printMemtag(); } if (Obj.isCOFF()) { if (opts::COFFImports) @@ -632,7 +637,7 @@ std::unique_ptr<ScopedPrinter> createWriter() { return std::make_unique<ScopedPrinter>(fouts()); } -int llvm_readobj_main(int argc, char **argv) { +int llvm_readobj_main(int argc, char **argv, const llvm::ToolContext &) { InitLLVM X(argc, argv); BumpPtrAllocator A; StringSaver Saver(A); @@ -683,6 +688,7 @@ int llvm_readobj_main(int argc, char **argv) { opts::Addrsig = true; opts::PrintStackSizes = true; } + opts::Memtag = true; } if (opts::Headers) { diff --git a/contrib/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp b/contrib/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp index 0412eae954ac..14af5d2842cf 100644 --- a/contrib/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-remarkutil/RemarkUtil.cpp @@ -38,6 +38,10 @@ static cl::SubCommand static cl::SubCommand InstructionCount( "instruction-count", "Function instruction count information (requires asm-printer remarks)"); +static cl::SubCommand + AnnotationCount("annotation-count", + "Collect count information from annotation remarks (uses " + "AnnotationRemarksPass)"); } // namespace subopts // Keep input + output help + names consistent across the various modes via a @@ -49,6 +53,23 @@ static cl::SubCommand InstructionCount( static cl::opt<std::string> OutputFileName( \ "o", cl::init("-"), cl::cat(RemarkUtilCategory), cl::desc("Output"), \ cl::value_desc("filename"), cl::sub(SUBOPT)); + +// Keep Input format and names consistent accross the modes via a macro. +#define INPUT_FORMAT_COMMAND_LINE_OPTIONS(SUBOPT) \ + static cl::opt<Format> InputFormat( \ + "parser", cl::desc("Input remark format to parse"), \ + cl::values(clEnumValN(Format::YAML, "yaml", "YAML"), \ + clEnumValN(Format::Bitstream, "bitstream", "Bitstream")), \ + cl::sub(SUBOPT)); + +#define DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(SUBOPT) \ + static cl::opt<bool> UseDebugLoc( \ + "use-debug-loc", \ + cl::desc( \ + "Add debug loc information when generating tables for " \ + "functions. The loc is represented as (path:line number:column " \ + "number)"), \ + cl::init(false), cl::sub(SUBOPT)); namespace yaml2bitstream { /// Remark format to parse. static constexpr Format InputFormat = Format::YAML; @@ -66,14 +87,20 @@ INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::Bitstream2YAML) } // namespace bitstream2yaml namespace instructioncount { -static cl::opt<Format> InputFormat( - "parser", cl::desc("Input remark format to parse"), - cl::values(clEnumValN(Format::YAML, "yaml", "YAML"), - clEnumValN(Format::Bitstream, "bitstream", "Bitstream")), - cl::sub(subopts::InstructionCount)); +INPUT_FORMAT_COMMAND_LINE_OPTIONS(subopts::InstructionCount) INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::InstructionCount) +DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(subopts::InstructionCount) } // namespace instructioncount +namespace annotationcount { +INPUT_FORMAT_COMMAND_LINE_OPTIONS(subopts::AnnotationCount) +static cl::opt<std::string> AnnotationTypeToCollect( + "annotation-type", cl::desc("annotation-type remark to collect count for"), + cl::sub(subopts::AnnotationCount)); +INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::AnnotationCount) +DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(subopts::AnnotationCount) +} // namespace annotationcount + /// \returns A MemoryBuffer for the input file on success, and an Error /// otherwise. static Expected<std::unique_ptr<MemoryBuffer>> @@ -115,6 +142,10 @@ getOutputFileForRemarks(StringRef OutputFileName, Format OutputFormat) { : sys::fs::OF_None); } +static bool shouldSkipRemark(bool UseDebugLoc, Remark &Remark) { + return UseDebugLoc && !Remark.Loc.has_value(); +} + namespace yaml2bitstream { /// Parses all remarks in the input YAML file. /// \p [out] ParsedRemarks - Filled with remarks parsed from the input file. @@ -229,6 +260,8 @@ static Error tryInstructionCount() { if (!MaybeParser) return MaybeParser.takeError(); // Emit CSV header. + if (UseDebugLoc) + OF->os() << "Source,"; OF->os() << "Function,InstructionCount\n"; // Parse all remarks. Whenever we see an instruction count remark, output // the file name and the number of instructions. @@ -238,11 +271,19 @@ static Error tryInstructionCount() { auto &Remark = **MaybeRemark; if (Remark.RemarkName != "InstructionCount") continue; + if (shouldSkipRemark(UseDebugLoc, Remark)) + continue; auto *InstrCountArg = find_if(Remark.Args, [](const Argument &Arg) { return Arg.Key == "NumInstructions"; }); assert(InstrCountArg != Remark.Args.end() && "Expected instruction count remarks to have a NumInstructions key?"); + if (UseDebugLoc) { + std::string Loc = Remark.Loc->SourceFilePath.str() + ":" + + std::to_string(Remark.Loc->SourceLine) + +":" + + std::to_string(Remark.Loc->SourceColumn); + OF->os() << Loc << ","; + } OF->os() << Remark.FunctionName << "," << InstrCountArg->Val << "\n"; } auto E = MaybeRemark.takeError(); @@ -254,6 +295,61 @@ static Error tryInstructionCount() { } } // namespace instructioncount +namespace annotationcount { +static Error tryAnnotationCount() { + // Create the output buffer. + auto MaybeOF = getOutputFileWithFlags(OutputFileName, + /*Flags = */ sys::fs::OF_TextWithCRLF); + if (!MaybeOF) + return MaybeOF.takeError(); + auto OF = std::move(*MaybeOF); + // Create a parser for the user-specified input format. + auto MaybeBuf = getInputMemoryBuffer(InputFileName); + if (!MaybeBuf) + return MaybeBuf.takeError(); + auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer()); + if (!MaybeParser) + return MaybeParser.takeError(); + // Emit CSV header. + if (UseDebugLoc) + OF->os() << "Source,"; + OF->os() << "Function,Count\n"; + // Parse all remarks. When we see the specified remark collect the count + // information. + auto &Parser = **MaybeParser; + auto MaybeRemark = Parser.next(); + for (; MaybeRemark; MaybeRemark = Parser.next()) { + auto &Remark = **MaybeRemark; + if (Remark.RemarkName != "AnnotationSummary") + continue; + if (shouldSkipRemark(UseDebugLoc, Remark)) + continue; + auto *RemarkNameArg = find_if(Remark.Args, [](const Argument &Arg) { + return Arg.Key == "type" && Arg.Val == AnnotationTypeToCollect; + }); + if (RemarkNameArg == Remark.Args.end()) + continue; + auto *CountArg = find_if( + Remark.Args, [](const Argument &Arg) { return Arg.Key == "count"; }); + assert(CountArg != Remark.Args.end() && + "Expected annotation-type remark to have a count key?"); + if (UseDebugLoc) { + std::string Loc = Remark.Loc->SourceFilePath.str() + ":" + + std::to_string(Remark.Loc->SourceLine) + +":" + + std::to_string(Remark.Loc->SourceColumn); + OF->os() << Loc << ","; + } + OF->os() << Remark.FunctionName << "," << CountArg->Val << "\n"; + } + auto E = MaybeRemark.takeError(); + if (!E.isA<EndOfFileError>()) + return E; + consumeError(std::move(E)); + OF->keep(); + return Error::success(); +} + +} // namespace annotationcount /// Handle user-specified suboptions (e.g. yaml2bitstream, bitstream2yaml). /// \returns An Error if the specified suboption fails or if no suboption was /// specified. Otherwise, Error::success(). @@ -264,6 +360,9 @@ static Error handleSuboptions() { return yaml2bitstream::tryYAML2Bitstream(); if (subopts::InstructionCount) return instructioncount::tryInstructionCount(); + if (subopts::AnnotationCount) + return annotationcount::tryAnnotationCount(); + return make_error<StringError>( "Please specify a subcommand. (See -help for options)", inconvertibleErrorCode()); diff --git a/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp b/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp index 32dbf3d489c0..048a98b9af7d 100644 --- a/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" @@ -869,7 +870,7 @@ static void printBerkeleyTotals() { << "(TOTALS)\n"; } -int llvm_size_main(int argc, char **argv) { +int llvm_size_main(int argc, char **argv, const llvm::ToolContext &) { InitLLVM X(argc, argv); BumpPtrAllocator A; StringSaver Saver(A); diff --git a/contrib/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp b/contrib/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp index 639506c7d488..d1cf1607b94b 100644 --- a/contrib/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp @@ -222,7 +222,7 @@ protected: } else if (Tp->isFloatingPointTy()) { if (getRandom() & 1) return ConstantFP::getAllOnesValue(Tp); - return ConstantFP::getNullValue(Tp); + return ConstantFP::getZero(Tp); } return UndefValue::get(Tp); } @@ -244,7 +244,7 @@ protected: } else if (Tp->isFloatingPointTy()) { if (getRandom() & 1) return ConstantFP::getAllOnesValue(Tp); - return ConstantFP::getNullValue(Tp); + return ConstantFP::getZero(Tp); } else if (auto *VTp = dyn_cast<FixedVectorType>(Tp)) { std::vector<Constant*> TempValues; TempValues.reserve(VTp->getNumElements()); @@ -341,9 +341,7 @@ struct LoadModifier: public Modifier { void Act() override { // Try to use predefined pointers. If non-exist, use undef pointer value; Value *Ptr = getRandomPointerValue(); - Type *Ty = Ptr->getType()->isOpaquePointerTy() - ? pickType() - : Ptr->getType()->getNonOpaquePointerElementType(); + Type *Ty = pickType(); Value *V = new LoadInst(Ty, Ptr, "L", BB->getTerminator()); PT->push_back(V); } @@ -356,9 +354,7 @@ struct StoreModifier: public Modifier { void Act() override { // Try to use predefined pointers. If non-exist, use undef pointer value; Value *Ptr = getRandomPointerValue(); - Type *ValTy = Ptr->getType()->isOpaquePointerTy() - ? pickType() - : Ptr->getType()->getNonOpaquePointerElementType(); + Type *ValTy = pickType(); // Do not store vectors of i1s because they are unsupported // by the codegen. @@ -442,7 +438,7 @@ struct ConstModifier: public Modifier { APFloat RandomFloat(Ty->getFltSemantics(), RandomInt); if (getRandom() & 1) - return PT->push_back(ConstantFP::getNullValue(Ty)); + return PT->push_back(ConstantFP::getZero(Ty)); return PT->push_back(ConstantFP::get(Ty->getContext(), RandomFloat)); } diff --git a/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp b/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp index f6d08a1988b7..d9bc34ee621a 100644 --- a/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Opts.inc" +#include "llvm/ADT/StringExtras.h" #include "llvm/Object/Binary.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" @@ -62,6 +63,7 @@ class StringsOptTable : public opt::GenericOptTable { public: StringsOptTable() : GenericOptTable(InfoTable) { setGroupedShortOptions(true); + setDashDashParsing(true); } }; } // namespace diff --git a/contrib/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/contrib/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp index ed24e8550291..3e342a4db9ce 100644 --- a/contrib/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -36,6 +36,7 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" #include "llvm/Support/StringSaver.h" +#include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstdio> @@ -83,6 +84,16 @@ public: }; } // namespace +static std::string ToolName; + +static void printError(const ErrorInfoBase &EI, StringRef Path) { + WithColor::error(errs(), ToolName); + if (!EI.isA<FileError>()) + errs() << "'" << Path << "': "; + EI.log(errs()); + errs() << '\n'; +} + template <typename T> static void print(const Request &Request, Expected<T> &ResOrErr, DIPrinter &Printer) { @@ -96,8 +107,7 @@ static void print(const Request &Request, Expected<T> &ResOrErr, bool PrintEmpty = true; handleAllErrors(std::move(ResOrErr.takeError()), [&](const ErrorInfoBase &EI) { - PrintEmpty = Printer.printError( - Request, EI, "LLVMSymbolizer: error reading file: "); + PrintEmpty = Printer.printError(Request, EI); }); if (PrintEmpty) @@ -125,15 +135,6 @@ static void enableDebuginfod(LLVMSymbolizer &Symbolizer, HTTPClient::initialize(); } -static object::BuildID parseBuildID(StringRef Str) { - std::string Bytes; - if (!tryGetFromHex(Str, Bytes)) - return {}; - ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()), - Bytes.size()); - return object::BuildID(BuildID.begin(), BuildID.end()); -} - static bool parseCommand(StringRef BinaryName, bool IsAddr2Line, StringRef InputString, Command &Cmd, std::string &ModuleName, object::BuildID &BuildID, @@ -218,17 +219,18 @@ void executeCommand(StringRef ModuleName, const T &ModuleSpec, Command Cmd, uint64_t AdjustedOffset = Offset - AdjustVMA; object::SectionedAddress Address = {AdjustedOffset, object::SectionedAddress::UndefSection}; + Request SymRequest = {ModuleName, Offset}; if (Cmd == Command::Data) { Expected<DIGlobal> ResOrErr = Symbolizer.symbolizeData(ModuleSpec, Address); - print({ModuleName, Offset}, ResOrErr, Printer); + print(SymRequest, ResOrErr, Printer); } else if (Cmd == Command::Frame) { Expected<std::vector<DILocal>> ResOrErr = Symbolizer.symbolizeFrame(ModuleSpec, Address); - print({ModuleName, Offset}, ResOrErr, Printer); + print(SymRequest, ResOrErr, Printer); } else if (ShouldInline) { Expected<DIInliningInfo> ResOrErr = Symbolizer.symbolizeInlinedCode(ModuleSpec, Address); - print({ModuleName, Offset}, ResOrErr, Printer); + print(SymRequest, ResOrErr, Printer); } else if (Style == OutputStyle::GNU) { // With PrintFunctions == FunctionNameKind::LinkageName (default) // and UseSymbolTable == true (also default), Symbolizer.symbolizeCode() @@ -243,11 +245,11 @@ void executeCommand(StringRef ModuleName, const T &ModuleSpec, Command Cmd, ? Expected<DILineInfo>(ResOrErr.takeError()) : ((ResOrErr->getNumberOfFrames() == 0) ? DILineInfo() : ResOrErr->getFrame(0)); - print({ModuleName, Offset}, Res0OrErr, Printer); + print(SymRequest, Res0OrErr, Printer); } else { Expected<DILineInfo> ResOrErr = Symbolizer.symbolizeCode(ModuleSpec, Address); - print({ModuleName, Offset}, ResOrErr, Printer); + print(SymRequest, ResOrErr, Printer); } Symbolizer.pruneCache(); } @@ -386,7 +388,8 @@ int main(int argc, char **argv) { InitLLVM X(argc, argv); sys::InitializeCOMRAII COM(sys::COMThreadingMode::MultiThreaded); - bool IsAddr2Line = sys::path::stem(argv[0]).contains("addr2line"); + ToolName = argv[0]; + bool IsAddr2Line = sys::path::stem(ToolName).contains("addr2line"); BumpPtrAllocator A; StringSaver Saver(A); SymbolizerOptTable Tbl; @@ -469,11 +472,25 @@ int main(int argc, char **argv) { std::unique_ptr<DIPrinter> Printer; if (Style == OutputStyle::GNU) - Printer = std::make_unique<GNUPrinter>(outs(), errs(), Config); + Printer = std::make_unique<GNUPrinter>(outs(), printError, Config); else if (Style == OutputStyle::JSON) Printer = std::make_unique<JSONPrinter>(outs(), Config); else - Printer = std::make_unique<LLVMPrinter>(outs(), errs(), Config); + Printer = std::make_unique<LLVMPrinter>(outs(), printError, Config); + + // When an input file is specified, exit immediately if the file cannot be + // read. If getOrCreateModuleInfo succeeds, symbolizeInput will reuse the + // cached file handle. + if (auto *Arg = Args.getLastArg(OPT_obj_EQ); Arg) { + auto Status = Symbolizer.getOrCreateModuleInfo(Arg->getValue()); + if (!Status) { + Request SymRequest = {Arg->getValue(), 0}; + handleAllErrors(Status.takeError(), [&](const ErrorInfoBase &EI) { + Printer->printError(SymRequest, EI); + }); + return EXIT_FAILURE; + } + } std::vector<std::string> InputAddresses = Args.getAllArgValues(OPT_INPUT); if (InputAddresses.empty()) { diff --git a/contrib/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp b/contrib/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp index 9ebaadbeec26..3e07bb94f4df 100644 --- a/contrib/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.cpp @@ -11,11 +11,13 @@ // //===----------------------------------------------------------------------===/ #include "DiffEngine.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TextAPI/InterfaceFile.h" #include "llvm/TextAPI/Symbol.h" #include "llvm/TextAPI/Target.h" +#include <iterator> using namespace llvm; using namespace MachO; @@ -74,43 +76,49 @@ StringLiteral SymScalar::getSymbolNamePrefix(MachO::SymbolKind Kind) { llvm_unreachable("Unknown llvm::MachO::SymbolKind enum"); } -std::string SymScalar::stringifySymbolFlag(MachO::SymbolFlags Flag) { - switch (Flag) { - case MachO::SymbolFlags::None: - return ""; - case MachO::SymbolFlags::ThreadLocalValue: - return "Thread-Local"; - case MachO::SymbolFlags::WeakDefined: - return "Weak-Defined"; - case MachO::SymbolFlags::WeakReferenced: - return "Weak-Referenced"; - case MachO::SymbolFlags::Undefined: - return "Undefined"; - case MachO::SymbolFlags::Rexported: - return "Reexported"; - } - llvm_unreachable("Unknown llvm::MachO::SymbolFlags enum"); +std::string SymScalar::getFlagString(const MachO::Symbol *Sym) { + if (Sym->getFlags() == SymbolFlags::None) + return {}; + SmallString<64> Flags(" - "); + if (Sym->isThreadLocalValue()) + Flags.append("Thread-Local "); + if (Sym->isWeakDefined()) + Flags.append("Weak-Defined "); + if (Sym->isWeakReferenced()) + Flags.append("Weak-Referenced "); + if (Sym->isUndefined()) + Flags.append("Undefined "); + if (Sym->isReexported()) + Flags.append("Reexported "); + if (Sym->isData()) + Flags.append("Data "); + if (Sym->isText()) + Flags.append("Text "); + + return std::string(Flags); } void SymScalar::print(raw_ostream &OS, std::string Indent, MachO::Target Targ) { if (Val->getKind() == MachO::SymbolKind::ObjectiveCClass) { if (Targ.Arch == MachO::AK_i386 && Targ.Platform == MachO::PLATFORM_MACOS) { OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ") - << ObjC1ClassNamePrefix << Val->getName() - << getFlagString(Val->getFlags()) << "\n"; + << ObjC1ClassNamePrefix << Val->getName() << getFlagString(Val) + << "\n"; return; } OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ") - << ObjC2ClassNamePrefix << Val->getName() - << getFlagString(Val->getFlags()) << "\n"; + << ObjC2ClassNamePrefix << Val->getName() << getFlagString(Val) << "\n"; } OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ") << getSymbolNamePrefix(Val->getKind()) << Val->getName() - << getFlagString(Val->getFlags()) << "\n"; + << getFlagString(Val) << "\n"; } bool checkSymbolEquality(llvm::MachO::InterfaceFile::const_symbol_range LHS, llvm::MachO::InterfaceFile::const_symbol_range RHS) { + if (std::distance(LHS.begin(), LHS.end()) != + std::distance(RHS.begin(), RHS.end())) + return false; return std::equal(LHS.begin(), LHS.end(), RHS.begin(), [&](auto LHS, auto RHS) { return *LHS == *RHS; }); } @@ -204,9 +212,6 @@ std::vector<DiffOutput> getSingleIF(InterfaceFile *Interface, diffAttribute("Swift ABI Version", Output, DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>( Order, Interface->getSwiftABIVersion())); - diffAttribute("InstallAPI", Output, - DiffScalarVal<bool, AD_Diff_Scalar_Bool>( - Order, Interface->isInstallAPI())); diffAttribute("Two Level Namespace", Output, DiffScalarVal<bool, AD_Diff_Scalar_Bool>( Order, Interface->isTwoLevelNamespace())); @@ -341,11 +346,6 @@ DiffEngine::findDifferences(const InterfaceFile *IFLHS, DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>( rhs, IFRHS->getSwiftABIVersion()), "Swift ABI Version")); - if (IFLHS->isInstallAPI() != IFRHS->isInstallAPI()) - Output.push_back(recordDifferences( - DiffScalarVal<bool, AD_Diff_Scalar_Bool>(lhs, IFLHS->isInstallAPI()), - DiffScalarVal<bool, AD_Diff_Scalar_Bool>(rhs, IFRHS->isInstallAPI()), - "InstallAPI")); if (IFLHS->isTwoLevelNamespace() != IFRHS->isTwoLevelNamespace()) Output.push_back(recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>( diff --git a/contrib/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h b/contrib/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h index e4864054fa11..27b72573d011 100644 --- a/contrib/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h +++ b/contrib/llvm-project/llvm/tools/llvm-tapi-diff/DiffEngine.h @@ -83,11 +83,7 @@ public: SymScalar(InterfaceInputOrder Order, const MachO::Symbol *Sym) : Order(Order), Val(Sym){}; - std::string getFlagString(MachO::SymbolFlags Flags) { - return Flags != MachO::SymbolFlags::None - ? " - " + stringifySymbolFlag(Flags) - : stringifySymbolFlag(Flags); - } + std::string getFlagString(const MachO::Symbol *Sym); void print(raw_ostream &OS, std::string Indent, MachO::Target Targ); @@ -99,7 +95,6 @@ private: InterfaceInputOrder Order; const MachO::Symbol *Val; StringLiteral getSymbolNamePrefix(MachO::SymbolKind Kind); - std::string stringifySymbolFlag(MachO::SymbolFlags Flag); }; class DiffStrVec : public AttributeDiff { diff --git a/contrib/llvm-project/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp b/contrib/llvm-project/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp index 179c42b60605..9cc18f80910d 100644 --- a/contrib/llvm-project/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp @@ -8,7 +8,6 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Config/llvm-config.h" #include "llvm/Demangle/Demangle.h" @@ -20,6 +19,7 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" #include "llvm/Support/WithColor.h" +#include "llvm/TargetParser/Triple.h" using namespace llvm; using namespace llvm::object; @@ -107,7 +107,7 @@ static std::string getPrintableName(StringRef Name) { std::string OutputName = "'"; OutputName += Name; OutputName += "'"; - std::string DemangledName(demangle(Name.str())); + std::string DemangledName(demangle(Name)); if (Name != DemangledName) { OutputName += " aka "; OutputName += DemangledName; diff --git a/contrib/llvm-project/llvm/tools/llvm-xray/xray-account.cpp b/contrib/llvm-project/llvm/tools/llvm-xray/xray-account.cpp index a9d91297b4e1..24a3552cfb91 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/xray-account.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/xray-account.cpp @@ -80,7 +80,7 @@ static cl::opt<SortField> AccountSortOutput( "sort", cl::desc("sort output by this field"), cl::value_desc("field"), cl::sub(Account), cl::init(SortField::FUNCID), cl::values(clEnumValN(SortField::FUNCID, "funcid", "function id"), - clEnumValN(SortField::COUNT, "count", "funciton call counts"), + clEnumValN(SortField::COUNT, "count", "function call counts"), clEnumValN(SortField::MIN, "min", "minimum function durations"), clEnumValN(SortField::MED, "med", "median function durations"), clEnumValN(SortField::PCT90, "90p", "90th percentile durations"), diff --git a/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp b/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp index b8328052f473..de67993d7590 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp @@ -200,7 +200,7 @@ static std::string escapeString(StringRef Label) { // example caused by tail call elimination and if the option is enabled then // then tries to recover from this. // -// This funciton will also error if the records are out of order, as the trace +// This function will also error if the records are out of order, as the trace // is expected to be sorted. // // The graph generated has an immaginary root for functions called by no-one at diff --git a/contrib/llvm-project/llvm/tools/opt/AnalysisWrappers.cpp b/contrib/llvm-project/llvm/tools/opt/AnalysisWrappers.cpp deleted file mode 100644 index 2ae1da84a9a0..000000000000 --- a/contrib/llvm-project/llvm/tools/opt/AnalysisWrappers.cpp +++ /dev/null @@ -1,71 +0,0 @@ -//===- AnalysisWrappers.cpp - Wrappers around non-pass analyses -----------===// -// -// 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 defines pass wrappers around LLVM analyses that don't make sense to -// be passes. It provides a nice standard pass interface to these classes so -// that they can be printed out by analyze. -// -// These classes are separated out of analyze.cpp so that it is more clear which -// code is the integral part of the analyze tool, and which part of the code is -// just making it so more passes are available. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Analysis/CallGraph.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/raw_ostream.h" -using namespace llvm; - -namespace { - /// ExternalFunctionsPassedConstants - This pass prints out call sites to - /// external functions that are called with constant arguments. This can be - /// useful when looking for standard library functions we should constant fold - /// or handle in alias analyses. - struct ExternalFunctionsPassedConstants : public ModulePass { - static char ID; // Pass ID, replacement for typeid - ExternalFunctionsPassedConstants() : ModulePass(ID) {} - bool runOnModule(Module &M) override { - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { - if (!I->isDeclaration()) continue; - - bool PrintedFn = false; - for (User *U : I->users()) { - Instruction *UI = dyn_cast<Instruction>(U); - if (!UI) continue; - - CallBase *CB = dyn_cast<CallBase>(UI); - if (!CB) - continue; - - for (auto AI = CB->arg_begin(), E = CB->arg_end(); AI != E; ++AI) { - if (!isa<Constant>(*AI)) continue; - - if (!PrintedFn) { - errs() << "Function '" << I->getName() << "':\n"; - PrintedFn = true; - } - errs() << *UI; - break; - } - } - } - - return false; - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } - }; -} - -char ExternalFunctionsPassedConstants::ID = 0; -static RegisterPass<ExternalFunctionsPassedConstants> - P1("print-externalfnconstants", - "Print external fn callsites passed constants"); diff --git a/contrib/llvm-project/llvm/tools/opt/BreakpointPrinter.cpp b/contrib/llvm-project/llvm/tools/opt/BreakpointPrinter.cpp deleted file mode 100644 index a57a8c43c264..000000000000 --- a/contrib/llvm-project/llvm/tools/opt/BreakpointPrinter.cpp +++ /dev/null @@ -1,71 +0,0 @@ -//===- BreakpointPrinter.cpp - Breakpoint location printer ----------------===// -// -// 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 -/// Breakpoint location printer. -/// -//===----------------------------------------------------------------------===// -#include "BreakpointPrinter.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/IR/DebugInfo.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -namespace { - -struct BreakpointPrinter : public ModulePass { - raw_ostream &Out; - static char ID; - - BreakpointPrinter(raw_ostream &out) : ModulePass(ID), Out(out) {} - - void getContextName(const DIScope *Context, std::string &N) { - if (auto *NS = dyn_cast<DINamespace>(Context)) { - if (!NS->getName().empty()) { - getContextName(NS->getScope(), N); - N = N + NS->getName().str() + "::"; - } - } else if (auto *TY = dyn_cast<DIType>(Context)) { - if (!TY->getName().empty()) { - getContextName(TY->getScope(), N); - N = N + TY->getName().str() + "::"; - } - } - } - - bool runOnModule(Module &M) override { - StringSet<> Processed; - if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp")) - for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { - std::string Name; - auto *SP = cast_or_null<DISubprogram>(NMD->getOperand(i)); - if (!SP) - continue; - getContextName(SP->getScope(), Name); - Name = Name + SP->getName().str(); - if (!Name.empty() && Processed.insert(Name).second) { - Out << Name << "\n"; - } - } - return false; - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } -}; - -char BreakpointPrinter::ID = 0; -} - -ModulePass *llvm::createBreakpointPrinter(raw_ostream &out) { - return new BreakpointPrinter(out); -} diff --git a/contrib/llvm-project/llvm/tools/opt/BreakpointPrinter.h b/contrib/llvm-project/llvm/tools/opt/BreakpointPrinter.h deleted file mode 100644 index 2877555f852c..000000000000 --- a/contrib/llvm-project/llvm/tools/opt/BreakpointPrinter.h +++ /dev/null @@ -1,24 +0,0 @@ -//===- BreakpointPrinter.h - Breakpoint location printer ------------------===// -// -// 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 -/// Breakpoint location printer. -/// -//===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_OPT_BREAKPOINTPRINTER_H -#define LLVM_TOOLS_OPT_BREAKPOINTPRINTER_H - -namespace llvm { - -class ModulePass; -class raw_ostream; - -ModulePass *createBreakpointPrinter(raw_ostream &out); -} - -#endif // LLVM_TOOLS_OPT_BREAKPOINTPRINTER_H diff --git a/contrib/llvm-project/llvm/tools/opt/NewPMDriver.cpp b/contrib/llvm-project/llvm/tools/opt/NewPMDriver.cpp index a8db0c62898e..6ae3f87099af 100644 --- a/contrib/llvm-project/llvm/tools/opt/NewPMDriver.cpp +++ b/contrib/llvm-project/llvm/tools/opt/NewPMDriver.cpp @@ -31,6 +31,7 @@ #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" @@ -175,6 +176,9 @@ static cl::opt<PGOKind> "Use sampled profile to guide PGO."))); static cl::opt<std::string> ProfileFile("profile-file", cl::desc("Path to the profile."), cl::Hidden); +static cl::opt<std::string> + MemoryProfileFile("memory-profile-file", + cl::desc("Path to the memory profile."), cl::Hidden); static cl::opt<CSPGOKind> CSPGOKindFlag( "cspgo-kind", cl::init(NoCSPGO), cl::Hidden, @@ -320,35 +324,38 @@ static void registerEPCallbacks(PassBuilder &PB) { llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); #include "llvm/Support/Extension.def" -bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, - TargetLibraryInfoImpl *TLII, ToolOutputFile *Out, - ToolOutputFile *ThinLTOLinkOut, - ToolOutputFile *OptRemarkFile, - StringRef PassPipeline, - ArrayRef<PassPlugin> PassPlugins, - OutputKind OK, VerifierKind VK, - bool ShouldPreserveAssemblyUseListOrder, - bool ShouldPreserveBitcodeUseListOrder, - bool EmitSummaryIndex, bool EmitModuleHash, - bool EnableDebugify, bool VerifyDIPreserve) { +bool llvm::runPassPipeline( + StringRef Arg0, Module &M, TargetMachine *TM, TargetLibraryInfoImpl *TLII, + ToolOutputFile *Out, ToolOutputFile *ThinLTOLinkOut, + ToolOutputFile *OptRemarkFile, StringRef PassPipeline, + ArrayRef<PassPlugin> PassPlugins, OutputKind OK, VerifierKind VK, + bool ShouldPreserveAssemblyUseListOrder, + bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, + bool EmitModuleHash, bool EnableDebugify, bool VerifyDIPreserve, + bool UnifiedLTO) { bool VerifyEachPass = VK == VK_VerifyEachPass; + auto FS = vfs::getRealFileSystem(); std::optional<PGOOptions> P; switch (PGOKindFlag) { case InstrGen: - P = PGOOptions(ProfileFile, "", "", PGOOptions::IRInstr); + P = PGOOptions(ProfileFile, "", "", MemoryProfileFile, FS, + PGOOptions::IRInstr); break; case InstrUse: - P = PGOOptions(ProfileFile, "", ProfileRemappingFile, PGOOptions::IRUse); + P = PGOOptions(ProfileFile, "", ProfileRemappingFile, MemoryProfileFile, FS, + PGOOptions::IRUse); break; case SampleUse: - P = PGOOptions(ProfileFile, "", ProfileRemappingFile, + P = PGOOptions(ProfileFile, "", ProfileRemappingFile, MemoryProfileFile, FS, PGOOptions::SampleUse); break; case NoPGO: - if (DebugInfoForProfiling || PseudoProbeForProfiling) - P = PGOOptions("", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction, - DebugInfoForProfiling, PseudoProbeForProfiling); + if (DebugInfoForProfiling || PseudoProbeForProfiling || + !MemoryProfileFile.empty()) + P = PGOOptions("", "", "", MemoryProfileFile, FS, PGOOptions::NoAction, + PGOOptions::NoCSAction, DebugInfoForProfiling, + PseudoProbeForProfiling); else P = std::nullopt; } @@ -368,7 +375,8 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, P->CSProfileGenFile = CSProfileGenFile; } else P = PGOOptions("", CSProfileGenFile, ProfileRemappingFile, - PGOOptions::NoAction, PGOOptions::CSIRInstr); + /*MemoryProfile=*/"", FS, PGOOptions::NoAction, + PGOOptions::CSIRInstr); } else /* CSPGOKindFlag == CSInstrUse */ { if (!P) { errs() << "CSInstrUse needs to be together with InstrUse"; @@ -391,20 +399,20 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, PrintPassOpts.SkipAnalyses = DebugPM == DebugLogging::Quiet; StandardInstrumentations SI(M.getContext(), DebugPM != DebugLogging::None, VerifyEachPass, PrintPassOpts); - SI.registerCallbacks(PIC, &FAM); + SI.registerCallbacks(PIC, &MAM); DebugifyEachInstrumentation Debugify; DebugifyStatsMap DIStatsMap; DebugInfoPerPass DebugInfoBeforePass; if (DebugifyEach) { Debugify.setDIStatsMap(DIStatsMap); Debugify.setDebugifyMode(DebugifyMode::SyntheticDebugInfo); - Debugify.registerCallbacks(PIC); + Debugify.registerCallbacks(PIC, MAM); } else if (VerifyEachDebugInfoPreserve) { Debugify.setDebugInfoBeforePass(DebugInfoBeforePass); Debugify.setDebugifyMode(DebugifyMode::OriginalDebugInfo); Debugify.setOrigDIVerifyBugsReportFilePath( VerifyDIPreserveExport); - Debugify.registerCallbacks(PIC); + Debugify.registerCallbacks(PIC, MAM); } PipelineTuningOptions PTO; @@ -412,6 +420,7 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, // to false above so we shouldn't necessarily need to check whether or not the // option has been enabled. PTO.LoopUnrolling = !DisableLoopUnrolling; + PTO.UnifiedLTO = UnifiedLTO; PassBuilder PB(TM, PTO, P, &PIC); registerEPCallbacks(PB); diff --git a/contrib/llvm-project/llvm/tools/opt/NewPMDriver.h b/contrib/llvm-project/llvm/tools/opt/NewPMDriver.h index a3cdd158d40f..3230c27c2d7a 100644 --- a/contrib/llvm-project/llvm/tools/opt/NewPMDriver.h +++ b/contrib/llvm-project/llvm/tools/opt/NewPMDriver.h @@ -67,13 +67,13 @@ void printPasses(raw_ostream &OS); bool runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, TargetLibraryInfoImpl *TLII, ToolOutputFile *Out, ToolOutputFile *ThinLinkOut, ToolOutputFile *OptRemarkFile, - StringRef PassPipeline, - ArrayRef<PassPlugin> PassPlugins, opt_tool::OutputKind OK, - opt_tool::VerifierKind VK, + StringRef PassPipeline, ArrayRef<PassPlugin> PassPlugins, + opt_tool::OutputKind OK, opt_tool::VerifierKind VK, bool ShouldPreserveAssemblyUseListOrder, bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, bool EmitModuleHash, - bool EnableDebugify, bool VerifyDIPreserve); + bool EnableDebugify, bool VerifyDIPreserve, + bool UnifiedLTO = false); } // namespace llvm #endif diff --git a/contrib/llvm-project/llvm/tools/opt/opt.cpp b/contrib/llvm-project/llvm/tools/opt/opt.cpp index 40632b43e73b..9c20e7784223 100644 --- a/contrib/llvm-project/llvm/tools/opt/opt.cpp +++ b/contrib/llvm-project/llvm/tools/opt/opt.cpp @@ -11,9 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "BreakpointPrinter.h" #include "NewPMDriver.h" -#include "llvm/ADT/Triple.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/LoopPass.h" @@ -37,13 +35,11 @@ #include "llvm/InitializePasses.h" #include "llvm/LinkAllIR.h" #include "llvm/LinkAllPasses.h" -#include "llvm/MC/SubtargetFeature.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Remarks/HotnessThresholdParser.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/SourceMgr.h" @@ -52,6 +48,9 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/SubtargetFeature.h" +#include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/IPO/WholeProgramDevirt.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Debugify.h" @@ -68,12 +67,12 @@ static codegen::RegisterCodeGenFlags CFG; static cl::list<const PassInfo *, bool, PassNameParser> PassList(cl::desc( "Optimizations available (use '-passes=' for the new pass manager)")); -static cl::opt<bool> EnableNewPassManager( - "enable-new-pm", - cl::desc("Enable the new pass manager, translating " - "'opt -foo' to 'opt -passes=foo'. This is strictly for the new PM " - "migration, use '-passes=' when possible."), - cl::init(true)); +static cl::opt<bool> EnableLegacyPassManager( + "bugpoint-enable-legacy-pm", + cl::desc( + "Enable the legacy pass manager. This is strictly for bugpoint " + "due to it not working with the new PM, please do not use otherwise."), + cl::init(false)); // This flag specifies a textual description of the optimization pass pipeline // to run over the module. This flag switches opt to use the new pass manager @@ -117,6 +116,12 @@ static cl::opt<bool> SplitLTOUnit("thinlto-split-lto-unit", cl::desc("Enable splitting of a ThinLTO LTOUnit")); +static cl::opt<bool> + UnifiedLTO("unified-lto", + cl::desc("Use unified LTO piplines. Ignored unless -thinlto-bc " + "is also specified."), + cl::Hidden, cl::init(false)); + static cl::opt<std::string> ThinLinkBitcodeFile( "thin-link-bitcode-file", cl::value_desc("filename"), cl::desc( @@ -203,10 +208,6 @@ static cl::opt<bool> VerifyDebugInfoPreserve( cl::desc("Start the pipeline with collecting and end it with checking of " "debug info preservation.")); -static cl::opt<bool> -PrintBreakpoints("print-breakpoints-for-testing", - cl::desc("Print select breakpoints location for testing")); - static cl::opt<std::string> ClDataLayout("data-layout", cl::desc("data layout string to use"), cl::value_desc("layout-string"), @@ -279,15 +280,6 @@ static cl::list<std::string> PassPlugins("load-pass-plugin", cl::desc("Load passes from plugin library")); -static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { - // Add the pass to the pass manager... - PM.add(P); - - // If we are verifying all of the intermediate steps, add the verifier... - if (VerifyEach) - PM.add(createVerifierPass()); -} - //===----------------------------------------------------------------------===// // CodeGen-related helper functions. // @@ -368,7 +360,6 @@ static bool shouldPinPassToLegacyPM(StringRef Pass) { "verify-safepoint-ir", "atomic-expand", "expandvp", - "hardware-loops", "mve-tail-predication", "interleaved-access", "global-merge", @@ -393,7 +384,8 @@ static bool shouldPinPassToLegacyPM(StringRef Pass) { "expand-large-div-rem", "structurizecfg", "fix-irreducible", - "expand-large-fp-convert" + "expand-large-fp-convert", + "callbrprepare", }; for (const auto &P : PassNamePrefix) if (Pass.startswith(P)) @@ -445,9 +437,9 @@ int main(int argc, char **argv) { initializeExpandMemCmpPassPass(Registry); initializeScalarizeMaskedMemIntrinLegacyPassPass(Registry); initializeSelectOptimizePass(Registry); + initializeCallBrPreparePass(Registry); initializeCodeGenPreparePass(Registry); initializeAtomicExpandPass(Registry); - initializeRewriteSymbolsLegacyPassPass(Registry); initializeWinEHPreparePass(Registry); initializeDwarfEHPrepareLegacyPassPass(Registry); initializeSafeStackLegacyPassPass(Registry); @@ -462,7 +454,6 @@ int main(int argc, char **argv) { initializeExpandVectorPredicationPass(Registry); initializeWasmEHPreparePass(Registry); initializeWriteBitcodePassPass(Registry); - initializeHardwareLoopsPass(Registry); initializeReplaceWithVeclibLegacyPass(Registry); initializeJMCInstrumenterPass(Registry); @@ -485,11 +476,8 @@ int main(int argc, char **argv) { LLVMContext Context; - // If `-passes=` is specified, use NPM. - // If `-enable-new-pm` is specified and there are no codegen passes, use NPM. - // e.g. `-enable-new-pm -sroa` will use NPM. - // but `-enable-new-pm -codegenprepare` will still revert to legacy PM. - const bool UseNPM = (EnableNewPassManager && !shouldForceLegacyPM()) || + // TODO: remove shouldForceLegacyPM(). + const bool UseNPM = (!EnableLegacyPassManager && !shouldForceLegacyPM()) || PassPipeline.getNumOccurrences() > 0; if (UseNPM && !PassList.empty()) { @@ -647,8 +635,11 @@ int main(int argc, char **argv) { if (CheckBitcodeOutputToConsole(Out->os())) NoOutput = true; - if (OutputThinLTOBC) + if (OutputThinLTOBC) { M->addModuleFlag(Module::Error, "EnableSplitLTOUnit", SplitLTOUnit); + if (UnifiedLTO) + M->addModuleFlag(Module::Error, "UnifiedLTO", 1); + } // Add an appropriate TargetLibraryInfo pass for the module's triple. TargetLibraryInfoImpl TLII(ModuleTriple); @@ -671,9 +662,8 @@ int main(int argc, char **argv) { if (UseNPM) { if (legacy::debugPassSpecified()) { - errs() - << "-debug-pass does not work with the new PM, either use " - "-debug-pass-manager, or use the legacy PM (-enable-new-pm=0)\n"; + errs() << "-debug-pass does not work with the new PM, either use " + "-debug-pass-manager, or use the legacy PM\n"; return 1; } auto NumOLevel = OptLevelO0 + OptLevelO1 + OptLevelO2 + OptLevelO3 + @@ -721,7 +711,7 @@ int main(int argc, char **argv) { PluginList, OK, VK, PreserveAssemblyUseListOrder, PreserveBitcodeUseListOrder, EmitSummaryIndex, EmitModuleHash, EnableDebugify, - VerifyDebugInfoPreserve) + VerifyDebugInfoPreserve, UnifiedLTO) ? 0 : 1; } @@ -781,26 +771,6 @@ int main(int argc, char **argv) { } } - std::unique_ptr<legacy::FunctionPassManager> FPasses; - - if (PrintBreakpoints) { - // Default to standard output. - if (!Out) { - if (OutputFilename.empty()) - OutputFilename = "-"; - - std::error_code EC; - Out = std::make_unique<ToolOutputFile>(OutputFilename, EC, - sys::fs::OF_None); - if (EC) { - errs() << EC.message() << '\n'; - return 1; - } - } - Passes.add(createBreakpointPrinter(Out->os())); - NoOutput = true; - } - if (TM) { // FIXME: We should dyn_cast this when supported. auto <M = static_cast<LLVMTargetMachine &>(*TM); @@ -811,21 +781,18 @@ int main(int argc, char **argv) { // Create a new optimization pass for each one specified on the command line for (unsigned i = 0; i < PassList.size(); ++i) { const PassInfo *PassInf = PassList[i]; - Pass *P = nullptr; - if (PassInf->getNormalCtor()) - P = PassInf->getNormalCtor()(); - else + if (PassInf->getNormalCtor()) { + Pass *P = PassInf->getNormalCtor()(); + if (P) { + // Add the pass to the pass manager. + Passes.add(P); + // If we are verifying all of the intermediate steps, add the verifier. + if (VerifyEach) + Passes.add(createVerifierPass()); + } + } else errs() << argv[0] << ": cannot create pass: " << PassInf->getPassName() << "\n"; - if (P) - addPass(Passes, P); - } - - if (FPasses) { - FPasses->doInitialization(); - for (Function &F : *M) - FPasses->run(F); - FPasses->doFinalization(); } // Check that the module is well formed on completion of optimization @@ -912,7 +879,7 @@ int main(int argc, char **argv) { exportDebugifyStats(DebugifyExport, Passes.getDebugifyStatsMap()); // Declare success. - if (!NoOutput || PrintBreakpoints) + if (!NoOutput) Out->keep(); if (RemarksFile) |