diff options
Diffstat (limited to 'contrib/llvm-project/llvm/tools')
116 files changed, 7517 insertions, 4131 deletions
diff --git a/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.h b/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.h index 75f166b21b2c..fe5201eb2e6c 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.h +++ b/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.h @@ -217,8 +217,7 @@ public:    /// returning the transformed module on success, or a null pointer on failure.    std::unique_ptr<Module> runPassesOn(Module *M,                                        const std::vector<std::string> &Passes, -                                      unsigned NumExtraArgs = 0, -                                      const char *const *ExtraArgs = nullptr); +                                      ArrayRef<std::string> ExtraArgs = {});    /// runPasses - Run the specified passes on Program, outputting a bitcode    /// file and writting the filename into OutputFile if successful.  If the @@ -231,8 +230,8 @@ public:    ///    bool runPasses(Module &Program, const std::vector<std::string> &PassesToRun,                   std::string &OutputFilename, bool DeleteOutput = false, -                 bool Quiet = false, unsigned NumExtraArgs = 0, -                 const char *const *ExtraArgs = nullptr) const; +                 bool Quiet = false, +                 ArrayRef<std::string> ExtraArgs = {}) const;    /// runPasses - Just like the method above, but this just returns true or    /// false indicating whether or not the optimizer crashed on the specified diff --git a/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp b/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp index aab9debf9b59..aa88a06a6df0 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp @@ -16,11 +16,11 @@  #include "llvm/ADT/SmallPtrSet.h"  #include "llvm/ADT/StringSet.h"  #include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/Transforms/Utils/Local.h"  #include "llvm/IR/CFG.h"  #include "llvm/IR/Constants.h"  #include "llvm/IR/DebugInfo.h"  #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/InstIterator.h"  #include "llvm/IR/Instructions.h"  #include "llvm/IR/LegacyPassManager.h"  #include "llvm/IR/Module.h" @@ -32,6 +32,7 @@  #include "llvm/Transforms/Scalar.h"  #include "llvm/Transforms/Utils/BasicBlockUtils.h"  #include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/Local.h"  #include <set>  using namespace llvm; @@ -43,6 +44,10 @@ cl::opt<bool> NoGlobalRM("disable-global-remove",                           cl::desc("Do not remove global variables"),                           cl::init(false)); +cl::opt<bool> NoAttributeRM("disable-attribute-remove", +                         cl::desc("Do not remove function attributes"), +                         cl::init(false)); +  cl::opt<bool> ReplaceFuncsWithNull(      "replace-funcs-with-null",      cl::desc("When stubbing functions, replace all uses will null"), @@ -359,6 +364,11 @@ bool ReduceCrashingFunctionAttributes::TestFuncAttrs(    // Set this new list of attributes on the function.    F->setAttributes(NewAttrs); +  // If the attribute list includes "optnone" we need to make sure it also +  // includes "noinline" otherwise we will get a verifier failure. +  if (F->hasFnAttribute(Attribute::OptimizeNone)) +    F->addFnAttr(Attribute::NoInline); +    // Try running on the hacked up program...    if (TestFn(BD, M.get())) {      BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version... @@ -806,6 +816,78 @@ bool ReduceCrashingInstructions::TestInsts(  }  namespace { +/// ReduceCrashingMetadata reducer - This works by removing all metadata from +/// the specified instructions. +/// +class ReduceCrashingMetadata : public ListReducer<Instruction *> { +  BugDriver &BD; +  BugTester TestFn; + +public: +  ReduceCrashingMetadata(BugDriver &bd, BugTester testFn) +      : BD(bd), TestFn(testFn) {} + +  Expected<TestResult> doTest(std::vector<Instruction *> &Prefix, +                              std::vector<Instruction *> &Kept) override { +    if (!Kept.empty() && TestInsts(Kept)) +      return KeepSuffix; +    if (!Prefix.empty() && TestInsts(Prefix)) +      return KeepPrefix; +    return NoFailure; +  } + +  bool TestInsts(std::vector<Instruction *> &Prefix); +}; +} // namespace + +bool ReduceCrashingMetadata::TestInsts(std::vector<Instruction *> &Insts) { +  // Clone the program to try hacking it apart... +  ValueToValueMapTy VMap; +  std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap); + +  // Convert list to set for fast lookup... +  SmallPtrSet<Instruction *, 32> Instructions; +  for (Instruction *I : Insts) +    Instructions.insert(cast<Instruction>(VMap[I])); + +  outs() << "Checking for crash with metadata retained from " +         << Instructions.size(); +  if (Instructions.size() == 1) +    outs() << " instruction: "; +  else +    outs() << " instructions: "; + +  // Try to drop instruction metadata from all instructions, except the ones +  // selected in Instructions. +  for (Function &F : *M) +    for (Instruction &Inst : instructions(F)) { +      if (Instructions.find(&Inst) == Instructions.end()) { +        Inst.dropUnknownNonDebugMetadata(); +        Inst.setDebugLoc({}); +      } +    } + +  // Verify that this is still valid. +  legacy::PassManager Passes; +  Passes.add(createVerifierPass(/*FatalErrors=*/false)); +  Passes.run(*M); + +  // Try running on the hacked up program... +  if (TestFn(BD, M.get())) { +    BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version... + +    // Make sure to use instruction pointers that point into the now-current +    // module, and that they don't include any deleted blocks. +    Insts.clear(); +    for (Instruction *I : Instructions) +      Insts.push_back(I); +    return true; +  } +  // It didn't crash, try something else. +  return false; +} + +namespace {  // Reduce the list of Named Metadata nodes. We keep this as a list of  // names to avoid having to convert back and forth every time.  class ReduceCrashingNamedMD : public ListReducer<std::string> { @@ -1081,6 +1163,21 @@ static Error ReduceInsts(BugDriver &BD, BugTester TestFn) {      }    } while (Simplification); + +  // Attempt to drop metadata from instructions that does not contribute to the +  // crash. +  if (!BugpointIsInterrupted) { +    std::vector<Instruction *> Insts; +    for (Function &F : BD.getProgram()) +      for (Instruction &I : instructions(F)) +        Insts.push_back(&I); + +    Expected<bool> Result = +        ReduceCrashingMetadata(BD, TestFn).reduceList(Insts); +    if (Error E = Result.takeError()) +      return E; +  } +    BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");    return Error::success();  } @@ -1115,36 +1212,38 @@ static Error DebugACrash(BugDriver &BD, BugTester TestFn) {        BD.EmitProgressBitcode(BD.getProgram(), "reduced-function");    } -  // For each remaining function, try to reduce that function's attributes. -  std::vector<std::string> FunctionNames; -  for (Function &F : BD.getProgram()) -    FunctionNames.push_back(F.getName()); +  if (!NoAttributeRM) { +    // For each remaining function, try to reduce that function's attributes. +    std::vector<std::string> FunctionNames; +    for (Function &F : BD.getProgram()) +      FunctionNames.push_back(F.getName()); -  if (!FunctionNames.empty() && !BugpointIsInterrupted) { -    outs() << "\n*** Attempting to reduce the number of function attributes in " -              "the testcase\n"; +    if (!FunctionNames.empty() && !BugpointIsInterrupted) { +      outs() << "\n*** Attempting to reduce the number of function attributes" +                " in the testcase\n"; -    unsigned OldSize = 0; -    unsigned NewSize = 0; -    for (std::string &Name : FunctionNames) { -      Function *Fn = BD.getProgram().getFunction(Name); -      assert(Fn && "Could not find funcion?"); +      unsigned OldSize = 0; +      unsigned NewSize = 0; +      for (std::string &Name : FunctionNames) { +        Function *Fn = BD.getProgram().getFunction(Name); +        assert(Fn && "Could not find funcion?"); -      std::vector<Attribute> Attrs; -      for (Attribute A : Fn->getAttributes().getFnAttributes()) -        Attrs.push_back(A); +        std::vector<Attribute> Attrs; +        for (Attribute A : Fn->getAttributes().getFnAttributes()) +          Attrs.push_back(A); -      OldSize += Attrs.size(); -      Expected<bool> Result = +        OldSize += Attrs.size(); +        Expected<bool> Result =            ReduceCrashingFunctionAttributes(BD, Name, TestFn).reduceList(Attrs); -      if (Error E = Result.takeError()) -        return E; +        if (Error E = Result.takeError()) +          return E; -      NewSize += Attrs.size(); -    } +        NewSize += Attrs.size(); +      } -    if (OldSize < NewSize) -      BD.EmitProgressBitcode(BD.getProgram(), "reduced-function-attributes"); +      if (OldSize < NewSize) +        BD.EmitProgressBitcode(BD.getProgram(), "reduced-function-attributes"); +    }    }    // Attempt to change conditional branches into unconditional branches to @@ -1289,7 +1388,21 @@ Error BugDriver::debugOptimizerCrash(const std::string &ID) {    EmitProgressBitcode(*Program, ID); -  return DebugACrash(*this, TestForOptimizerCrash); +  auto Res = DebugACrash(*this, TestForOptimizerCrash); +  if (Res || DontReducePassList) +    return Res; +  // Try to reduce the pass list again. This covers additional cases +  // we failed to reduce earlier, because of more complex pass dependencies +  // triggering the crash. +  auto SecondRes = ReducePassList(*this).reduceList(PassesToRun); +  if (Error E = SecondRes.takeError()) +    return E; +  outs() << "\n*** Found crashing pass" +         << (PassesToRun.size() == 1 ? ": " : "es: ") +         << getPassesString(PassesToRun) << '\n'; + +  EmitProgressBitcode(getProgram(), "reduced-simplified"); +  return Res;  }  static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) { diff --git a/contrib/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp b/contrib/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp index 105702de3f1d..d9047acd30e1 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp @@ -407,11 +407,10 @@ BugDriver::extractMappedBlocksFromModule(const std::vector<BasicBlock *> &BBs,    std::string uniqueFN = "--extract-blocks-file=";    uniqueFN += Temp->TmpName; -  const char *ExtraArg = uniqueFN.c_str();    std::vector<std::string> PI;    PI.push_back("extract-blocks"); -  std::unique_ptr<Module> Ret = runPassesOn(M, PI, 1, &ExtraArg); +  std::unique_ptr<Module> Ret = runPassesOn(M, PI, {uniqueFN});    if (!Ret) {      outs() << "*** Basic Block extraction failed, please report a bug!\n"; diff --git a/contrib/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp b/contrib/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp index 562de7952388..64af81fcc8a1 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp @@ -79,7 +79,7 @@ bool BugDriver::writeProgramToFile(int FD, const Module &M) const {  bool BugDriver::writeProgramToFile(const std::string &Filename,                                     const Module &M) const {    std::error_code EC; -  ToolOutputFile Out(Filename, EC, sys::fs::F_None); +  ToolOutputFile Out(Filename, EC, sys::fs::OF_None);    if (!EC)      return writeProgramToFileAux(Out, M);    return true; @@ -130,8 +130,7 @@ static cl::list<std::string> OptArgs("opt-args", cl::Positional,  bool BugDriver::runPasses(Module &Program,                            const std::vector<std::string> &Passes,                            std::string &OutputFilename, bool DeleteOutput, -                          bool Quiet, unsigned NumExtraArgs, -                          const char *const *ExtraArgs) const { +                          bool Quiet, ArrayRef<std::string> ExtraArgs) const {    // setup the output file name    outs().flush();    SmallString<128> UniqueFilename; @@ -223,8 +222,7 @@ bool BugDriver::runPasses(Module &Program,         I != E; ++I)      Args.push_back(I->c_str());    Args.push_back(Temp->TmpName.c_str()); -  for (unsigned i = 0; i < NumExtraArgs; ++i) -    Args.push_back(*ExtraArgs); +  Args.append(ExtraArgs.begin(), ExtraArgs.end());    LLVM_DEBUG(errs() << "\nAbout to run:\t";               for (unsigned i = 0, e = Args.size() - 1; i != e; ++i) errs() @@ -268,10 +266,10 @@ bool BugDriver::runPasses(Module &Program,  std::unique_ptr<Module>  BugDriver::runPassesOn(Module *M, const std::vector<std::string> &Passes, -                       unsigned NumExtraArgs, const char *const *ExtraArgs) { +                       ArrayRef<std::string> ExtraArgs) {    std::string BitcodeResult;    if (runPasses(*M, Passes, BitcodeResult, false /*delete*/, true /*quiet*/, -                NumExtraArgs, ExtraArgs)) { +                ExtraArgs)) {      return nullptr;    } diff --git a/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp b/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp index da4244345e3b..19b2ea2c0181 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp @@ -170,7 +170,7 @@ Expected<int> LLI::ExecuteProgram(const std::string &Bitcode,                                    const std::vector<std::string> &SharedLibs,                                    unsigned Timeout, unsigned MemoryLimit) {    std::vector<StringRef> LLIArgs; -  LLIArgs.push_back(LLIPath.c_str()); +  LLIArgs.push_back(LLIPath);    LLIArgs.push_back("-force-interpreter=true");    for (std::vector<std::string>::const_iterator i = SharedLibs.begin(), @@ -266,15 +266,15 @@ Error CustomCompiler::compileProgram(const std::string &Bitcode,                                       unsigned Timeout, unsigned MemoryLimit) {    std::vector<StringRef> ProgramArgs; -  ProgramArgs.push_back(CompilerCommand.c_str()); +  ProgramArgs.push_back(CompilerCommand); -  for (std::size_t i = 0; i < CompilerArgs.size(); ++i) -    ProgramArgs.push_back(CompilerArgs.at(i).c_str()); +  for (const auto &Arg : CompilerArgs) +    ProgramArgs.push_back(Arg);    ProgramArgs.push_back(Bitcode);    // Add optional parameters to the running program from Argv -  for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i) -    ProgramArgs.push_back(CompilerArgs[i].c_str()); +  for (const auto &Arg : CompilerArgs) +    ProgramArgs.push_back(Arg);    if (RunProgramWithTimeout(CompilerCommand, ProgramArgs, "", "", "", Timeout,                              MemoryLimit)) @@ -559,7 +559,7 @@ Expected<int> JIT::ExecuteProgram(const std::string &Bitcode,                                    unsigned Timeout, unsigned MemoryLimit) {    // Construct a vector of parameters, incorporating those from the command-line    std::vector<StringRef> JITArgs; -  JITArgs.push_back(LLIPath.c_str()); +  JITArgs.push_back(LLIPath);    JITArgs.push_back("-force-interpreter=false");    // Add any extra LLI args. @@ -570,7 +570,7 @@ Expected<int> JIT::ExecuteProgram(const std::string &Bitcode,      JITArgs.push_back("-load");      JITArgs.push_back(SharedLibs[i]);    } -  JITArgs.push_back(Bitcode.c_str()); +  JITArgs.push_back(Bitcode);    // Add optional parameters to the running program from Argv    for (unsigned i = 0, e = Args.size(); i != e; ++i)      JITArgs.push_back(Args[i]); diff --git a/contrib/llvm-project/llvm/tools/bugpoint/bugpoint.cpp b/contrib/llvm-project/llvm/tools/bugpoint/bugpoint.cpp index 2d5322a351ad..d29a79ee3e13 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/bugpoint.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/bugpoint.cpp @@ -18,8 +18,10 @@  #include "llvm/IR/LLVMContext.h"  #include "llvm/IR/LegacyPassManager.h"  #include "llvm/IR/LegacyPassNameParser.h" +#include "llvm/InitializePasses.h"  #include "llvm/LinkAllIR.h"  #include "llvm/LinkAllPasses.h" +#include "llvm/Passes/PassPlugin.h"  #include "llvm/Support/CommandLine.h"  #include "llvm/Support/InitLLVM.h"  #include "llvm/Support/ManagedStatic.h" @@ -81,6 +83,10 @@ static cl::opt<bool> OptLevelOs(          "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> @@ -109,11 +115,29 @@ public:  };  } -#ifdef LINK_POLLY_INTO_TOOLS -namespace polly { -void initializePollyPasses(llvm::PassRegistry &Registry); +// 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);  } -#endif + +#define HANDLE_EXTENSION(Ext)                                                  \ +  llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); +#include "llvm/Support/Extension.def"  int main(int argc, char **argv) {  #ifndef DEBUG_BUGPOINT @@ -134,10 +158,6 @@ int main(int argc, char **argv) {    initializeInstrumentation(Registry);    initializeTarget(Registry); -#ifdef LINK_POLLY_INTO_TOOLS -  polly::initializePollyPasses(Registry); -#endif -    if (std::getenv("bar") == (char*) -1) {      InitializeAllTargets();      InitializeAllTargetMCs(); @@ -189,18 +209,16 @@ int main(int argc, char **argv) {      Builder.populateLTOPassManager(PM);    } -  if (OptLevelO1 || OptLevelO2 || OptLevelO3) { -    PassManagerBuilder Builder; -    if (OptLevelO1) -      Builder.Inliner = createAlwaysInlinerLegacyPass(); -    else if (OptLevelOs || OptLevelO2) -      Builder.Inliner = createFunctionInliningPass( -          2, OptLevelOs ? 1 : 0, false); -    else -      Builder.Inliner = createFunctionInliningPass(275); -    Builder.populateFunctionPassManager(PM); -    Builder.populateModulePassManager(PM); -  } +  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(PI->getPassArgument()); @@ -211,6 +229,13 @@ int main(int argc, char **argv) {    sys::Process::PreventCoreFiles();  #endif +// Needed to pull in symbols from statically linked extensions, including static +// registration. It is unused otherwise because bugpoint has no support for +// NewPM. +#define HANDLE_EXTENSION(Ext)                                                  \ +  (void)get##Ext##PluginInfo(); +#include "llvm/Support/Extension.def" +    if (Error E = D.run()) {      errs() << toString(std::move(E));      return 1; diff --git a/contrib/llvm-project/llvm/tools/llc/llc.cpp b/contrib/llvm-project/llvm/tools/llc/llc.cpp index 76da843f065e..b35f8e853c30 100644 --- a/contrib/llvm-project/llvm/tools/llc/llc.cpp +++ b/contrib/llvm-project/llvm/tools/llc/llc.cpp @@ -34,6 +34,7 @@  #include "llvm/IR/RemarkStreamer.h"  #include "llvm/IR/Verifier.h"  #include "llvm/IRReader/IRReader.h" +#include "llvm/InitializePasses.h"  #include "llvm/MC/SubtargetFeature.h"  #include "llvm/Pass.h"  #include "llvm/Support/CommandLine.h" @@ -202,7 +203,7 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName,          OutputFilename = IFN;        switch (FileType) { -      case TargetMachine::CGFT_AssemblyFile: +      case CGFT_AssemblyFile:          if (TargetName[0] == 'c') {            if (TargetName[1] == 0)              OutputFilename += ".cbe.c"; @@ -213,13 +214,13 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName,          } else            OutputFilename += ".s";          break; -      case TargetMachine::CGFT_ObjectFile: +      case CGFT_ObjectFile:          if (OS == Triple::Win32)            OutputFilename += ".obj";          else            OutputFilename += ".o";          break; -      case TargetMachine::CGFT_Null: +      case CGFT_Null:          OutputFilename += ".null";          break;        } @@ -229,20 +230,20 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName,    // Decide if we need "binary" output.    bool Binary = false;    switch (FileType) { -  case TargetMachine::CGFT_AssemblyFile: +  case CGFT_AssemblyFile:      break; -  case TargetMachine::CGFT_ObjectFile: -  case TargetMachine::CGFT_Null: +  case CGFT_ObjectFile: +  case CGFT_Null:      Binary = true;      break;    }    // Open the file.    std::error_code EC; -  sys::fs::OpenFlags OpenFlags = sys::fs::F_None; +  sys::fs::OpenFlags OpenFlags = sys::fs::OF_None;    if (!Binary) -    OpenFlags |= sys::fs::F_Text; -  auto FDOut = llvm::make_unique<ToolOutputFile>(OutputFilename, EC, OpenFlags); +    OpenFlags |= sys::fs::OF_Text; +  auto FDOut = std::make_unique<ToolOutputFile>(OutputFilename, EC, OpenFlags);    if (EC) {      WithColor::error() << EC.message() << '\n';      return nullptr; @@ -329,7 +330,7 @@ int main(int argc, char **argv) {    // Set a diagnostic handler that doesn't exit on the first error    bool HasError = false;    Context.setDiagnosticHandler( -      llvm::make_unique<LLCDiagnosticHandler>(&HasError)); +      std::make_unique<LLCDiagnosticHandler>(&HasError));    Context.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, &HasError);    Expected<std::unique_ptr<ToolOutputFile>> RemarksFileOrErr = @@ -394,6 +395,12 @@ static int compileModule(char **argv, LLVMContext &Context) {    std::unique_ptr<Module> M;    std::unique_ptr<MIRParser> MIR;    Triple TheTriple; +  std::string CPUStr = getCPUStr(), FeaturesStr = getFeaturesStr(); + +  // Set attributes on functions as loaded from MIR from command line arguments. +  auto setMIRFunctionAttributes = [&CPUStr, &FeaturesStr](Function &F) { +    setFunctionAttributes(CPUStr, FeaturesStr, F); +  };    bool SkipModule = MCPU == "help" ||                      (!MAttrs.empty() && MAttrs.front() == "help"); @@ -402,7 +409,8 @@ static int compileModule(char **argv, LLVMContext &Context) {    if (!SkipModule) {      if (InputLanguage == "mir" ||          (InputLanguage == "" && StringRef(InputFilename).endswith(".mir"))) { -      MIR = createMIRParserFromFile(InputFilename, Err, Context); +      MIR = createMIRParserFromFile(InputFilename, Err, Context, +                                    setMIRFunctionAttributes);        if (MIR)          M = MIR->parseIRModule();      } else @@ -432,8 +440,6 @@ static int compileModule(char **argv, LLVMContext &Context) {      return 1;    } -  std::string CPUStr = getCPUStr(), FeaturesStr = getFeaturesStr(); -    CodeGenOpt::Level OLvl = CodeGenOpt::Default;    switch (OptLevel) {    default: @@ -479,8 +485,8 @@ static int compileModule(char **argv, LLVMContext &Context) {    std::unique_ptr<ToolOutputFile> DwoOut;    if (!SplitDwarfOutputFile.empty()) {      std::error_code EC; -    DwoOut = llvm::make_unique<ToolOutputFile>(SplitDwarfOutputFile, EC, -                                               sys::fs::F_None); +    DwoOut = std::make_unique<ToolOutputFile>(SplitDwarfOutputFile, EC, +                                               sys::fs::OF_None);      if (EC) {        WithColor::error(errs(), argv[0]) << EC.message() << '\n';        return 1; @@ -519,7 +525,7 @@ static int compileModule(char **argv, LLVMContext &Context) {    setFunctionAttributes(CPUStr, FeaturesStr, *M);    if (RelaxAll.getNumOccurrences() > 0 && -      FileType != TargetMachine::CGFT_ObjectFile) +      FileType != CGFT_ObjectFile)      WithColor::warning(errs(), argv[0])          << ": warning: ignoring -mc-relax-all because filetype != obj"; @@ -530,16 +536,17 @@ static int compileModule(char **argv, LLVMContext &Context) {      // so we can memcmp the contents in CompileTwice mode      SmallVector<char, 0> Buffer;      std::unique_ptr<raw_svector_ostream> BOS; -    if ((FileType != TargetMachine::CGFT_AssemblyFile && +    if ((FileType != CGFT_AssemblyFile &&           !Out->os().supportsSeeking()) ||          CompileTwice) { -      BOS = make_unique<raw_svector_ostream>(Buffer); +      BOS = std::make_unique<raw_svector_ostream>(Buffer);        OS = BOS.get();      }      const char *argv0 = argv[0]; -    LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine&>(*Target); -    MachineModuleInfo *MMI = new MachineModuleInfo(&LLVMTM); +    LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine &>(*Target); +    MachineModuleInfoWrapperPass *MMIWP = +        new MachineModuleInfoWrapperPass(&LLVMTM);      // Construct a custom pass pipeline that starts after instruction      // selection. @@ -559,7 +566,7 @@ static int compileModule(char **argv, LLVMContext &Context) {        TPC.setDisableVerify(NoVerify);        PM.add(&TPC); -      PM.add(MMI); +      PM.add(MMIWP);        TPC.printAndVerify("");        for (const std::string &RunPassName : *RunPassNames) {          if (addPass(PM, argv0, RunPassName, TPC)) @@ -570,7 +577,7 @@ static int compileModule(char **argv, LLVMContext &Context) {        PM.add(createFreeMachineFunctionPass());      } else if (Target->addPassesToEmitFile(PM, *OS,                                             DwoOut ? &DwoOut->os() : nullptr, -                                           FileType, NoVerify, MMI)) { +                                           FileType, NoVerify, MMIWP)) {        WithColor::warning(errs(), argv[0])            << "target does not support generation of this"            << " file type!\n"; @@ -578,8 +585,8 @@ static int compileModule(char **argv, LLVMContext &Context) {      }      if (MIR) { -      assert(MMI && "Forgot to create MMI?"); -      if (MIR->parseMachineFunctions(*M, *MMI)) +      assert(MMIWP && "Forgot to create MMIWP?"); +      if (MIR->parseMachineFunctions(*M, MMIWP->getMMI()))          return 1;      } diff --git a/contrib/llvm-project/llvm/tools/lli/RemoteJITUtils.h b/contrib/llvm-project/llvm/tools/lli/RemoteJITUtils.h index 8e80e73c8082..cc93294af0cf 100644 --- a/contrib/llvm-project/llvm/tools/lli/RemoteJITUtils.h +++ b/contrib/llvm-project/llvm/tools/lli/RemoteJITUtils.h @@ -13,7 +13,7 @@  #ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H  #define LLVM_TOOLS_LLI_REMOTEJITUTILS_H -#include "llvm/ExecutionEngine/Orc/RawByteChannel.h" +#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"  #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"  #include <mutex> diff --git a/contrib/llvm-project/llvm/tools/lli/lli.cpp b/contrib/llvm-project/llvm/tools/lli/lli.cpp index 8c8cd88c9711..0efd0df2c12b 100644 --- a/contrib/llvm-project/llvm/tools/lli/lli.cpp +++ b/contrib/llvm-project/llvm/tools/lli/lli.cpp @@ -197,6 +197,11 @@ namespace {      cl::desc("Generate software floating point library calls"),      cl::init(false)); +  cl::opt<bool> NoProcessSymbols( +      "no-process-syms", +      cl::desc("Do not resolve lli process symbols in JIT'd code"), +      cl::init(false)); +    enum class DumpKind {      NoDump,      DumpFuncsToStdOut, @@ -251,7 +256,7 @@ public:        sys::fs::create_directories(Twine(dir));      }      std::error_code EC; -    raw_fd_ostream outfile(CacheName, EC, sys::fs::F_None); +    raw_fd_ostream outfile(CacheName, EC, sys::fs::OF_None);      outfile.write(Obj.getBufferStart(), Obj.getBufferSize());      outfile.close();    } @@ -308,7 +313,7 @@ static void addCygMingExtraModule(ExecutionEngine &EE, LLVMContext &Context,    Triple TargetTriple(TargetTripleStr);    // Create a new module. -  std::unique_ptr<Module> M = make_unique<Module>("CygMingHelper", Context); +  std::unique_ptr<Module> M = std::make_unique<Module>("CygMingHelper", Context);    M->setTargetTriple(TargetTripleStr);    // Create an empty function named "__main". @@ -695,18 +700,16 @@ int main(int argc, char **argv, char * const *envp) {    return Result;  } -static orc::IRTransformLayer::TransformFunction createDebugDumper() { +static std::function<void(Module &)> createDebugDumper() {    switch (OrcDumpKind) {    case DumpKind::NoDump: -    return [](orc::ThreadSafeModule TSM, -              const orc::MaterializationResponsibility &R) { return TSM; }; +    return [](Module &M) {};    case DumpKind::DumpFuncsToStdOut: -    return [](orc::ThreadSafeModule TSM, -              const orc::MaterializationResponsibility &R) { +    return [](Module &M) {        printf("[ "); -      for (const auto &F : *TSM.getModule()) { +      for (const auto &F : M) {          if (F.isDeclaration())            continue; @@ -718,31 +721,23 @@ static orc::IRTransformLayer::TransformFunction createDebugDumper() {        }        printf("]\n"); -      return TSM;      };    case DumpKind::DumpModsToStdOut: -    return [](orc::ThreadSafeModule TSM, -              const orc::MaterializationResponsibility &R) { -      outs() << "----- Module Start -----\n" -             << *TSM.getModule() << "----- Module End -----\n"; - -      return TSM; +    return [](Module &M) { +      outs() << "----- Module Start -----\n" << M << "----- Module End -----\n";      };    case DumpKind::DumpModsToDisk: -    return [](orc::ThreadSafeModule TSM, -              const orc::MaterializationResponsibility &R) { +    return [](Module &M) {        std::error_code EC; -      raw_fd_ostream Out(TSM.getModule()->getModuleIdentifier() + ".ll", EC, -                         sys::fs::F_Text); +      raw_fd_ostream Out(M.getModuleIdentifier() + ".ll", EC, sys::fs::OF_Text);        if (EC) { -        errs() << "Couldn't open " << TSM.getModule()->getModuleIdentifier() +        errs() << "Couldn't open " << M.getModuleIdentifier()                 << " for dumping.\nError:" << EC.message() << "\n";          exit(1);        } -      Out << *TSM.getModule(); -      return TSM; +      Out << M;      };    }    llvm_unreachable("Unknown DumpKind"); @@ -754,14 +749,13 @@ int runOrcLazyJIT(const char *ProgName) {    // Start setting up the JIT environment.    // Parse the main module. -  orc::ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>()); +  orc::ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());    SMDiagnostic Err; -  auto MainModule = orc::ThreadSafeModule( -      parseIRFile(InputFile, Err, *TSCtx.getContext()), TSCtx); +  auto MainModule = parseIRFile(InputFile, Err, *TSCtx.getContext());    if (!MainModule)      reportError(Err, ProgName); -  const auto &TT = MainModule.getModule()->getTargetTriple(); +  const auto &TT = MainModule->getTargetTriple();    orc::LLLazyJITBuilder Builder;    Builder.setJITTargetMachineBuilder( @@ -794,22 +788,34 @@ int runOrcLazyJIT(const char *ProgName) {    J->setLazyCompileTransform([&](orc::ThreadSafeModule TSM,                                   const orc::MaterializationResponsibility &R) { -    if (verifyModule(*TSM.getModule(), &dbgs())) { -      dbgs() << "Bad module: " << *TSM.getModule() << "\n"; -      exit(1); -    } -    return Dump(std::move(TSM), R); +    TSM.withModuleDo([&](Module &M) { +      if (verifyModule(M, &dbgs())) { +        dbgs() << "Bad module: " << &M << "\n"; +        exit(1); +      } +      Dump(M); +    }); +    return TSM;    }); -  J->getMainJITDylib().setGenerator( -      ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( -          J->getDataLayout().getGlobalPrefix())));    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; +            }))); +    orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides;    ExitOnErr(CXXRuntimeOverrides.enable(J->getMainJITDylib(), Mangle));    // Add the main module. -  ExitOnErr(J->addLazyIRModule(std::move(MainModule))); +  ExitOnErr( +      J->addLazyIRModule(orc::ThreadSafeModule(std::move(MainModule), TSCtx)));    // Create JITDylibs and add any extra modules.    { @@ -839,6 +845,16 @@ int runOrcLazyJIT(const char *ProgName) {        ExitOnErr(            J->addLazyIRModule(JD, orc::ThreadSafeModule(std::move(M), TSCtx)));      } + +    for (auto EAItr = ExtraArchives.begin(), EAEnd = ExtraArchives.end(); +         EAItr != EAEnd; ++EAItr) { +      auto EAIdx = ExtraArchives.getPosition(EAItr - ExtraArchives.begin()); +      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()))); +    }    }    // Add the objects. @@ -847,12 +863,6 @@ int runOrcLazyJIT(const char *ProgName) {      ExitOnErr(J->addObjectFile(std::move(Obj)));    } -  // Generate a argument string. -  std::vector<std::string> Args; -  Args.push_back(InputFile); -  for (auto &Arg : InputArgv) -    Args.push_back(Arg); -    // Run any static constructors.    ExitOnErr(J->runConstructors()); @@ -868,16 +878,11 @@ int runOrcLazyJIT(const char *ProgName) {    // Run main.    auto MainSym = ExitOnErr(J->lookup("main")); -  typedef int (*MainFnPtr)(int, const char *[]); -  std::vector<const char *> ArgV; -  for (auto &Arg : Args) -    ArgV.push_back(Arg.c_str()); -  ArgV.push_back(nullptr); -  int ArgC = ArgV.size() - 1; -  auto Main = -      reinterpret_cast<MainFnPtr>(static_cast<uintptr_t>(MainSym.getAddress())); -  auto Result = Main(ArgC, (const char **)ArgV.data()); +  typedef int (*MainFnPtr)(int, char *[]); +  auto Result = orc::runAsMain( +      jitTargetAddressToFunction<MainFnPtr>(MainSym.getAddress()), InputArgv, +      StringRef(InputFile));    // Wait for -entry-point threads.    for (auto &AltEntryThread : AltEntryThreads) @@ -959,6 +964,6 @@ std::unique_ptr<FDRawChannel> launchRemote() {    close(PipeFD[1][1]);    // Return an RPC channel connected to our end of the pipes. -  return llvm::make_unique<FDRawChannel>(PipeFD[1][0], PipeFD[0][1]); +  return std::make_unique<FDRawChannel>(PipeFD[1][0], PipeFD[0][1]);  #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 91746d0fab37..c339dfe1f33e 100644 --- a/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp @@ -11,6 +11,7 @@  //  //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringExtras.h"  #include "llvm/ADT/StringSwitch.h"  #include "llvm/ADT/Triple.h"  #include "llvm/IR/LLVMContext.h" @@ -43,6 +44,11 @@  #include <io.h>  #endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif +  using namespace llvm;  // The name this program was invoked as. @@ -51,33 +57,33 @@ static StringRef ToolName;  // The basename of this program.  static StringRef Stem; -const char RanlibHelp[] = R"( -OVERVIEW: LLVM Ranlib (llvm-ranlib) +const char RanlibHelp[] = R"(OVERVIEW: LLVM Ranlib (llvm-ranlib)    This program generates an index to speed access to archives  USAGE: llvm-ranlib <archive-file>  OPTIONS: -  -help                             - Display available options -  -version                          - Display the version of this program +  -h --help             - Display available options +  -v --version          - Display the version of this program +  -D                    - Use zero for timestamps and uids/gids (default) +  -U                    - Use actual timestamps and uids/gids  )"; -const char ArHelp[] = R"( -OVERVIEW: LLVM Archiver +const char ArHelp[] = R"(OVERVIEW: LLVM Archiver  USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] [count] <archive> [files]         llvm-ar -M [<mri-script]  OPTIONS: -  --format              - Archive format to create +  --format              - archive format to create      =default            -   default      =gnu                -   gnu      =darwin             -   darwin      =bsd                -   bsd -  --plugin=<string>     - Ignored for compatibility -  --help                - Display available options -  --version             - Display the version of this program +  --plugin=<string>     - ignored for compatibility +  -h --help             - display this help and exit +  --version             - print the version and exit    @<file>               - read options from <file>  OPERATIONS: @@ -95,11 +101,13 @@ MODIFIERS:    [b] - put [files] before [relpos] (same as [i])    [c] - do not warn if archive had to be created    [D] - use zero for timestamps and uids/gids (default) +  [h] - display this help and exit    [i] - put [files] before [relpos] (same as [b])    [l] - ignored for compatibility    [L] - add archive's contents    [N] - use instance [count] of name    [o] - preserve original dates +  [O] - display member offsets    [P] - use full names when matching (implied for thin archives)    [s] - create an archive index (cf. ranlib)    [S] - do not build a symbol table @@ -107,6 +115,7 @@ MODIFIERS:    [u] - update only [files] newer than archive contents    [U] - use actual timestamps and uids/gids    [v] - be verbose about actions taken +  [V] - display the version and exit  )";  void printHelpMessage() { @@ -116,10 +125,24 @@ void printHelpMessage() {      outs() << ArHelp;  } +static unsigned MRILineNumber; +static bool ParsingMRIScript; + +// Show the error plus the usage message, and exit. +LLVM_ATTRIBUTE_NORETURN static void badUsage(Twine Error) { +  WithColor::error(errs(), ToolName) << Error << "\n"; +  printHelpMessage(); +  exit(1); +} +  // Show the error message and exit.  LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { -  WithColor::error(errs(), ToolName) << Error << ".\n"; -  printHelpMessage(); +  if (ParsingMRIScript) { +    WithColor::error(errs(), ToolName) +        << "script line " << MRILineNumber << ": " << Error << "\n"; +  } else { +    WithColor::error(errs(), ToolName) << Error << "\n"; +  }    exit(1);  } @@ -171,17 +194,18 @@ enum ArchiveOperation {  };  // Modifiers to follow operation to vary behavior -static bool AddAfter = false;        ///< 'a' modifier -static bool AddBefore = false;       ///< 'b' modifier -static bool Create = false;          ///< 'c' modifier -static bool OriginalDates = false;   ///< 'o' modifier -static bool CompareFullPath = false; ///< 'P' modifier -static bool OnlyUpdate = false;      ///< 'u' modifier -static bool Verbose = false;         ///< 'v' modifier -static bool Symtab = true;           ///< 's' modifier -static bool Deterministic = true;    ///< 'D' and 'U' modifiers -static bool Thin = false;            ///< 'T' modifier -static bool AddLibrary = false;      ///< 'L' modifier +static bool AddAfter = false;             ///< 'a' modifier +static bool AddBefore = false;            ///< 'b' modifier +static bool Create = false;               ///< 'c' modifier +static bool OriginalDates = false;        ///< 'o' modifier +static bool DisplayMemberOffsets = false; ///< 'O' modifier +static bool CompareFullPath = false;      ///< 'P' modifier +static bool OnlyUpdate = false;           ///< 'u' modifier +static bool Verbose = false;              ///< 'v' modifier +static bool Symtab = true;                ///< 's' modifier +static bool Deterministic = true;         ///< 'D' and 'U' modifiers +static bool Thin = false;                 ///< 'T' modifier +static bool AddLibrary = false;           ///< 'L' modifier  // Relative Positional Argument (for insert/move). This variable holds  // the name of the archive member to which the 'a', 'b' or 'i' modifier @@ -198,6 +222,9 @@ static int CountParam = 0;  // command line.  static std::string ArchiveName; +static std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers; +static std::vector<std::unique_ptr<object::Archive>> Archives; +  // This variable holds the list of member files to proecess, as given  // on the command line.  static std::vector<StringRef> Members; @@ -209,7 +236,7 @@ static BumpPtrAllocator Alloc;  // associated with a, b, and i modifiers  static void getRelPos() {    if (PositionalArgs.empty()) -    fail("Expected [relpos] for a, b, or i modifier"); +    fail("expected [relpos] for 'a', 'b', or 'i' modifier");    RelPos = PositionalArgs[0];    PositionalArgs.erase(PositionalArgs.begin());  } @@ -218,40 +245,31 @@ static void getRelPos() {  // associated with the N modifier  static void getCountParam() {    if (PositionalArgs.empty()) -    fail("Expected [count] for N modifier"); +    badUsage("expected [count] for 'N' modifier");    auto CountParamArg = StringRef(PositionalArgs[0]);    if (CountParamArg.getAsInteger(10, CountParam)) -    fail("Value for [count] must be numeric, got: " + CountParamArg); +    badUsage("value for [count] must be numeric, got: " + CountParamArg);    if (CountParam < 1) -    fail("Value for [count] must be positive, got: " + CountParamArg); +    badUsage("value for [count] must be positive, got: " + CountParamArg);    PositionalArgs.erase(PositionalArgs.begin());  }  // Get the archive file name from the command line  static void getArchive() {    if (PositionalArgs.empty()) -    fail("An archive name must be specified"); +    badUsage("an archive name must be specified");    ArchiveName = PositionalArgs[0];    PositionalArgs.erase(PositionalArgs.begin());  } -// Copy over remaining items in PositionalArgs to our Members vector -static void getMembers() { -  for (auto &Arg : PositionalArgs) -    Members.push_back(Arg); -} - -std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers; -std::vector<std::unique_ptr<object::Archive>> Archives; -  static object::Archive &readLibrary(const Twine &Library) {    auto BufOrErr = MemoryBuffer::getFile(Library, -1, false); -  failIfError(BufOrErr.getError(), "Could not open library " + Library); +  failIfError(BufOrErr.getError(), "could not open library " + Library);    ArchiveBuffers.push_back(std::move(*BufOrErr));    auto LibOrErr =        object::Archive::create(ArchiveBuffers.back()->getMemBufferRef());    failIfError(errorToErrorCode(LibOrErr.takeError()), -              "Could not parse library"); +              "could not parse library");    Archives.push_back(std::move(*LibOrErr));    return *Archives.back();  } @@ -264,7 +282,7 @@ static void runMRIScript();  static ArchiveOperation parseCommandLine() {    if (MRI) {      if (!PositionalArgs.empty() || !Options.empty()) -      fail("Cannot mix -M and other options"); +      badUsage("cannot mix -M and other options");      runMRIScript();    } @@ -319,6 +337,9 @@ static ArchiveOperation parseCommandLine() {      case 'o':        OriginalDates = true;        break; +    case 'O': +      DisplayMemberOffsets = true; +      break;      case 'P':        CompareFullPath = true;        break; @@ -367,8 +388,14 @@ static ArchiveOperation parseCommandLine() {      case 'L':        AddLibrary = true;        break; +    case 'V': +      cl::PrintVersionMessage(); +      exit(0); +    case 'h': +      printHelpMessage(); +      exit(0);      default: -      fail(std::string("unknown option ") + Options[i]); +      badUsage(std::string("unknown option ") + Options[i]);      }    } @@ -377,37 +404,37 @@ static ArchiveOperation parseCommandLine() {    getArchive();    // Everything on the command line at this point is a member. -  getMembers(); +  Members.assign(PositionalArgs.begin(), PositionalArgs.end());    if (NumOperations == 0 && MaybeJustCreateSymTab) {      NumOperations = 1;      Operation = CreateSymTab;      if (!Members.empty()) -      fail("The s operation takes only an archive as argument"); +      badUsage("the 's' operation takes only an archive as argument");    }    // Perform various checks on the operation/modifier specification    // to make sure we are dealing with a legal request.    if (NumOperations == 0) -    fail("You must specify at least one of the operations"); +    badUsage("you must specify at least one of the operations");    if (NumOperations > 1) -    fail("Only one operation may be specified"); +    badUsage("only one operation may be specified");    if (NumPositional > 1) -    fail("You may only specify one of a, b, and i modifiers"); +    badUsage("you may only specify one of 'a', 'b', and 'i' modifiers");    if (AddAfter || AddBefore)      if (Operation != Move && Operation != ReplaceOrInsert) -      fail("The 'a', 'b' and 'i' modifiers can only be specified with " -           "the 'm' or 'r' operations"); +      badUsage("the 'a', 'b' and 'i' modifiers can only be specified with " +               "the 'm' or 'r' operations");    if (CountParam)      if (Operation != Extract && Operation != Delete) -      fail("The 'N' modifier can only be specified with the 'x' or 'd' " -           "operations"); +      badUsage("the 'N' modifier can only be specified with the 'x' or 'd' " +               "operations");    if (OriginalDates && Operation != Extract) -    fail("The 'o' modifier is only applicable to the 'x' operation"); +    badUsage("the 'o' modifier is only applicable to the 'x' operation");    if (OnlyUpdate && Operation != ReplaceOrInsert) -    fail("The 'u' modifier is only applicable to the 'r' operation"); +    badUsage("the 'u' modifier is only applicable to the 'r' operation");    if (AddLibrary && Operation != QuickAppend) -    fail("The 'L' modifier is only applicable to the 'q' operation"); +    badUsage("the 'L' modifier is only applicable to the 'q' operation");    // Return the parsed operation to the caller    return Operation; @@ -470,12 +497,35 @@ static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {        if (!ParentDir.empty())          outs() << sys::path::convert_to_slash(ParentDir) << '/';      } +    outs() << Name; +  } else { +    outs() << Name; +    if (DisplayMemberOffsets) +      outs() << " 0x" << utohexstr(C.getDataOffset(), true);    } -  outs() << Name << "\n"; +  outs() << '\n';  } -static StringRef normalizePath(StringRef Path) { -  return CompareFullPath ? Path : sys::path::filename(Path); +static std::string normalizePath(StringRef Path) { +  return CompareFullPath ? sys::path::convert_to_slash(Path) +                         : std::string(sys::path::filename(Path)); +} + +static bool comparePaths(StringRef Path1, StringRef Path2) { +// When on Windows this function calls CompareStringOrdinal +// as Windows file paths are case-insensitive.  +// CompareStringOrdinal compares two Unicode strings for +// binary equivalence and allows for case insensitivity. +#ifdef _WIN32 +  SmallVector<wchar_t, 128> WPath1, WPath2; +  failIfError(sys::path::widenPath(normalizePath(Path1), WPath1)); +  failIfError(sys::path::widenPath(normalizePath(Path2), WPath2)); + +  return CompareStringOrdinal(WPath1.data(), WPath1.size(), WPath2.data(), +                              WPath2.size(), true) == CSTR_EQUAL; +#else +  return normalizePath(Path1) == normalizePath(Path2); +#endif  }  // Implement the 'x' operation. This function extracts files back to the file @@ -486,10 +536,14 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) {    failIfError(ModeOrErr.takeError());    sys::fs::perms Mode = ModeOrErr.get(); +  llvm::StringRef outputFilePath = sys::path::filename(Name); +  if (Verbose) +    outs() << "x - " << outputFilePath << '\n'; +    int FD; -  failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD, +  failIfError(sys::fs::openFileForWrite(outputFilePath, FD,                                          sys::fs::CD_CreateAlways, -                                        sys::fs::F_None, Mode), +                                        sys::fs::OF_None, Mode),                Name);    { @@ -551,7 +605,7 @@ static void performReadOperation(ArchiveOperation Operation,        if (Filter) {          auto I = find_if(Members, [Name](StringRef Path) { -          return Name == normalizePath(Path); +          return comparePaths(Name, Path);          });          if (I == Members.end())            continue; @@ -588,7 +642,7 @@ static void addChildMember(std::vector<NewArchiveMember> &Members,                             const object::Archive::Child &M,                             bool FlattenArchive = false) {    if (Thin && !M.getParent()->isThin()) -    fail("Cannot convert a regular archive to a thin one"); +    fail("cannot convert a regular archive to a thin one");    Expected<NewArchiveMember> NMOrErr =        NewArchiveMember::getOldMember(M, Deterministic);    failIfError(NMOrErr.takeError()); @@ -681,7 +735,7 @@ static InsertAction computeInsertAction(ArchiveOperation Operation,    if (Operation == QuickAppend || Members.empty())      return IA_AddOldMember;    auto MI = find_if( -      Members, [Name](StringRef Path) { return Name == normalizePath(Path); }); +      Members, [Name](StringRef Path) { return comparePaths(Name, Path); });    if (MI == Members.end())      return IA_AddOldMember; @@ -698,9 +752,8 @@ static InsertAction computeInsertAction(ArchiveOperation Operation,      return IA_MoveOldMember;    if (Operation == ReplaceOrInsert) { -    StringRef PosName = normalizePath(RelPos);      if (!OnlyUpdate) { -      if (PosName.empty()) +      if (RelPos.empty())          return IA_AddNewMember;        return IA_MoveNewMember;      } @@ -712,12 +765,12 @@ static InsertAction computeInsertAction(ArchiveOperation Operation,      auto ModTimeOrErr = Member.getLastModified();      failIfError(ModTimeOrErr.takeError());      if (Status.getLastModificationTime() < ModTimeOrErr.get()) { -      if (PosName.empty()) +      if (RelPos.empty())          return IA_AddOldMember;        return IA_MoveOldMember;      } -    if (PosName.empty()) +    if (RelPos.empty())        return IA_AddNewMember;      return IA_MoveNewMember;    } @@ -732,7 +785,6 @@ computeNewArchiveMembers(ArchiveOperation Operation,    std::vector<NewArchiveMember> Ret;    std::vector<NewArchiveMember> Moved;    int InsertPos = -1; -  StringRef PosName = normalizePath(RelPos);    if (OldArchive) {      Error Err = Error::success();      StringMap<int> MemberCount; @@ -740,8 +792,8 @@ computeNewArchiveMembers(ArchiveOperation Operation,        int Pos = Ret.size();        Expected<StringRef> NameOrErr = Child.getName();        failIfError(NameOrErr.takeError()); -      StringRef Name = NameOrErr.get(); -      if (Name == PosName) { +      std::string Name = NameOrErr.get(); +      if (comparePaths(Name, RelPos)) {          assert(AddAfter || AddBefore);          if (AddBefore)            InsertPos = Pos; @@ -783,7 +835,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,      return Ret;    if (!RelPos.empty() && InsertPos == -1) -    fail("Insertion point not found"); +    fail("insertion point not found");    if (RelPos.empty())      InsertPos = Ret.size(); @@ -859,12 +911,12 @@ static void performWriteOperation(ArchiveOperation Operation,      break;    case BSD:      if (Thin) -      fail("Only the gnu format has a thin mode"); +      fail("only the gnu format has a thin mode");      Kind = object::Archive::K_BSD;      break;    case DARWIN:      if (Thin) -      fail("Only the gnu format has a thin mode"); +      fail("only the gnu format has a thin mode");      Kind = object::Archive::K_DARWIN;      break;    case Unknown: @@ -922,14 +974,12 @@ static int performOperation(ArchiveOperation Operation,        MemoryBuffer::getFile(ArchiveName, -1, false);    std::error_code EC = Buf.getError();    if (EC && EC != errc::no_such_file_or_directory) -    fail("error opening '" + ArchiveName + "': " + EC.message() + "!"); +    fail("error opening '" + ArchiveName + "': " + EC.message());    if (!EC) {      Error Err = Error::success();      object::Archive Archive(Buf.get()->getMemBufferRef(), Err); -    EC = errorToErrorCode(std::move(Err)); -    failIfError(EC, -                "error loading '" + ArchiveName + "': " + EC.message() + "!"); +    failIfError(std::move(Err), "unable to load '" + ArchiveName + "'");      if (Archive.isThin())        CompareFullPath = true;      performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers); @@ -960,8 +1010,10 @@ static void runMRIScript() {    const MemoryBuffer &Ref = *Buf.get();    bool Saved = false;    std::vector<NewArchiveMember> NewMembers; +  ParsingMRIScript = true;    for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) { +    ++MRILineNumber;      StringRef Line = *I;      Line = Line.split(';').first;      Line = Line.split('*').first; @@ -1003,15 +1055,15 @@ static void runMRIScript() {      case MRICommand::Create:        Create = true;        if (!ArchiveName.empty()) -        fail("Editing multiple archives not supported"); +        fail("editing multiple archives not supported");        if (Saved) -        fail("File already saved"); +        fail("file already saved");        ArchiveName = Rest;        break;      case MRICommand::Delete: { -      StringRef Name = normalizePath(Rest); -      llvm::erase_if(NewMembers, -                     [=](NewArchiveMember &M) { return M.MemberName == Name; }); +      llvm::erase_if(NewMembers, [=](NewArchiveMember &M) { +        return comparePaths(M.MemberName, Rest); +      });        break;      }      case MRICommand::Save: @@ -1020,10 +1072,12 @@ static void runMRIScript() {      case MRICommand::End:        break;      case MRICommand::Invalid: -      fail("Unknown command: " + CommandStr); +      fail("unknown command: " + CommandStr);      }    } - +   +  ParsingMRIScript = false; +      // Nothing to do if not saved.    if (Saved)      performOperation(ReplaceOrInsert, &NewMembers); @@ -1031,7 +1085,7 @@ static void runMRIScript() {  }  static bool handleGenericOption(StringRef arg) { -  if (arg == "-help" || arg == "--help") { +  if (arg == "-help" || arg == "--help" || arg == "-h") {      printHelpMessage();      return true;    } @@ -1048,7 +1102,7 @@ static int ar_main(int argc, char **argv) {    cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);    for (size_t i = 1; i < Argv.size(); ++i) {      StringRef Arg = Argv[i]; -    const char *match; +    const char *match = nullptr;      auto MatchFlagWithArg = [&](const char *expected) {        size_t len = strlen(expected);        if (Arg == expected) { @@ -1104,15 +1158,38 @@ static int ar_main(int argc, char **argv) {  static int ranlib_main(int argc, char **argv) {    bool ArchiveSpecified = false;    for (int i = 1; i < argc; ++i) { -    if (handleGenericOption(argv[i])) { +    StringRef arg(argv[i]); +    if (handleGenericOption(arg)) {        return 0; +    } else if (arg.consume_front("-")) { +      // Handle the -D/-U flag +      while (!arg.empty()) { +        if (arg.front() == 'D') { +          Deterministic = true; +        } else if (arg.front() == 'U') { +          Deterministic = false; +        } else if (arg.front() == 'h') { +          printHelpMessage(); +          return 0; +        } else if (arg.front() == 'v') { +          cl::PrintVersionMessage(); +          return 0; +        } else { +          // TODO: GNU ranlib also supports a -t flag +          fail("Invalid option: '-" + arg + "'"); +        } +        arg = arg.drop_front(1); +      }      } else {        if (ArchiveSpecified) -        fail("Exactly one archive should be specified"); +        fail("exactly one archive should be specified");        ArchiveSpecified = true; -      ArchiveName = argv[i]; +      ArchiveName = arg.str();      }    } +  if (!ArchiveSpecified) { +    badUsage("an archive name must be specified"); +  }    return performOperation(CreateSymTab, nullptr);  } @@ -1125,16 +1202,25 @@ int main(int argc, char **argv) {    llvm::InitializeAllAsmParsers();    Stem = sys::path::stem(ToolName); -  if (Stem.contains_lower("dlltool")) +  auto Is = [](StringRef Tool) { +    // We need to recognize the following filenames. +    // +    // Lib.exe -> lib (see D44808, MSBuild runs Lib.exe) +    // dlltool.exe -> dlltool +    // arm-pokymllib32-linux-gnueabi-llvm-ar-10 -> ar +    auto I = Stem.rfind_lower(Tool); +    return I != StringRef::npos && +           (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); +  }; + +  if (Is("dlltool"))      return dlltoolDriverMain(makeArrayRef(argv, argc)); - -  if (Stem.contains_lower("ranlib")) +  if (Is("ranlib"))      return ranlib_main(argc, argv); - -  if (Stem.contains_lower("lib")) +  if (Is("lib"))      return libDriverMain(makeArrayRef(argv, argc)); - -  if (Stem.contains_lower("ar")) +  if (Is("ar"))      return ar_main(argc, argv); -  fail("Not ranlib, ar, lib or dlltool!"); + +  fail("not ranlib, ar, lib or dlltool");  } diff --git a/contrib/llvm-project/llvm/tools/llvm-as/llvm-as.cpp b/contrib/llvm-project/llvm/tools/llvm-as/llvm-as.cpp index 234fef907a38..c9f50e38fc61 100644 --- a/contrib/llvm-project/llvm/tools/llvm-as/llvm-as.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-as/llvm-as.cpp @@ -82,7 +82,7 @@ static void WriteOutputFile(const Module *M, const ModuleSummaryIndex *Index) {    std::error_code EC;    std::unique_ptr<ToolOutputFile> Out( -      new ToolOutputFile(OutputFilename, EC, sys::fs::F_None)); +      new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None));    if (EC) {      errs() << EC.message() << '\n';      exit(1); diff --git a/contrib/llvm-project/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/contrib/llvm-project/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 01cba1f6e3c9..639a6d1ec02c 100644 --- a/contrib/llvm-project/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -102,8 +102,9 @@ int main(int argc, char **argv) {    O.Symbolic = !NonSymbolic;    O.ShowBinaryBlobs = ShowBinaryBlobs; -  ExitOnErr( -      BA.analyze(O, CheckHash.empty() ? None : Optional<StringRef>(CheckHash))); +  ExitOnErr(BA.analyze( +      Dump ? Optional<BCDumpOptions>(O) : Optional<BCDumpOptions>(None), +      CheckHash.empty() ? None : Optional<StringRef>(CheckHash)));    if (Dump)      outs() << "\n\n"; diff --git a/contrib/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp b/contrib/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp index f707e3c7ab53..5f1e23f20d77 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -36,6 +36,7 @@  #include "llvm/Support/ThreadPool.h"  #include "llvm/Support/Threading.h"  #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h"  #include <functional>  #include <map> @@ -704,23 +705,23 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {      // Read in -name-whitelist files.      if (!NameFilterFiles.empty()) {        std::string SpecialCaseListErr; -      NameWhitelist = -          SpecialCaseList::create(NameFilterFiles, SpecialCaseListErr); +      NameWhitelist = SpecialCaseList::create( +          NameFilterFiles, *vfs::getRealFileSystem(), SpecialCaseListErr);        if (!NameWhitelist)          error(SpecialCaseListErr);      }      // Create the function filters      if (!NameFilters.empty() || NameWhitelist || !NameRegexFilters.empty()) { -      auto NameFilterer = llvm::make_unique<CoverageFilters>(); +      auto NameFilterer = std::make_unique<CoverageFilters>();        for (const auto &Name : NameFilters) -        NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name)); +        NameFilterer->push_back(std::make_unique<NameCoverageFilter>(Name));        if (NameWhitelist)          NameFilterer->push_back( -            llvm::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist)); +            std::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist));        for (const auto &Regex : NameRegexFilters)          NameFilterer->push_back( -            llvm::make_unique<NameRegexCoverageFilter>(Regex)); +            std::make_unique<NameRegexCoverageFilter>(Regex));        Filters.push_back(std::move(NameFilterer));      } @@ -728,18 +729,18 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {          RegionCoverageGtFilter.getNumOccurrences() ||          LineCoverageLtFilter.getNumOccurrences() ||          LineCoverageGtFilter.getNumOccurrences()) { -      auto StatFilterer = llvm::make_unique<CoverageFilters>(); +      auto StatFilterer = std::make_unique<CoverageFilters>();        if (RegionCoverageLtFilter.getNumOccurrences()) -        StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>( +        StatFilterer->push_back(std::make_unique<RegionCoverageFilter>(              RegionCoverageFilter::LessThan, RegionCoverageLtFilter));        if (RegionCoverageGtFilter.getNumOccurrences()) -        StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>( +        StatFilterer->push_back(std::make_unique<RegionCoverageFilter>(              RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));        if (LineCoverageLtFilter.getNumOccurrences()) -        StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>( +        StatFilterer->push_back(std::make_unique<LineCoverageFilter>(              LineCoverageFilter::LessThan, LineCoverageLtFilter));        if (LineCoverageGtFilter.getNumOccurrences()) -        StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>( +        StatFilterer->push_back(std::make_unique<LineCoverageFilter>(              RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));        Filters.push_back(std::move(StatFilterer));      } @@ -747,7 +748,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {      // Create the ignore filename filters.      for (const auto &RE : IgnoreFilenameRegexFilters)        IgnoreFilenameFilters.push_back( -          llvm::make_unique<NameRegexCoverageFilter>(RE)); +          std::make_unique<NameRegexCoverageFilter>(RE));      if (!Arches.empty()) {        for (const std::string &Arch : Arches) { @@ -1040,7 +1041,7 @@ int CodeCoverageTool::doExport(int argc, const char **argv,    switch (ViewOpts.Format) {    case CoverageViewOptions::OutputFormat::Text: -    Exporter = llvm::make_unique<CoverageExporterJson>(*Coverage.get(), +    Exporter = std::make_unique<CoverageExporterJson>(*Coverage.get(),                                                         ViewOpts, outs());      break;    case CoverageViewOptions::OutputFormat::HTML: @@ -1048,7 +1049,7 @@ int CodeCoverageTool::doExport(int argc, const char **argv,      // above.      llvm_unreachable("Export in HTML is not supported!");    case CoverageViewOptions::OutputFormat::Lcov: -    Exporter = llvm::make_unique<CoverageExporterLcov>(*Coverage.get(), +    Exporter = std::make_unique<CoverageExporterLcov>(*Coverage.get(),                                                         ViewOpts, outs());      break;    } diff --git a/contrib/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/contrib/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp index 181d428ed9d8..216b5e3fd226 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp @@ -48,6 +48,7 @@  #include "llvm/Support/ThreadPool.h"  #include "llvm/Support/Threading.h"  #include <algorithm> +#include <limits>  #include <mutex>  #include <utility> @@ -61,14 +62,23 @@ using namespace llvm;  namespace { +// The JSON library accepts int64_t, but profiling counts are stored as uint64_t. +// Therefore we need to explicitly convert from unsigned to signed, since a naive +// cast is implementation-defined behavior when the unsigned value cannot be +// represented as a signed value. We choose to clamp the values to preserve the +// invariant that counts are always >= 0. +int64_t clamp_uint64_to_int64(uint64_t u) { +  return std::min(u, static_cast<uint64_t>(std::numeric_limits<int64_t>::max())); +} +  json::Array renderSegment(const coverage::CoverageSegment &Segment) { -  return json::Array({Segment.Line, Segment.Col, int64_t(Segment.Count), +  return json::Array({Segment.Line, Segment.Col, clamp_uint64_to_int64(Segment.Count),                        Segment.HasCount, Segment.IsRegionEntry});  }  json::Array renderRegion(const coverage::CountedRegion &Region) {    return json::Array({Region.LineStart, Region.ColumnStart, Region.LineEnd, -                      Region.ColumnEnd, int64_t(Region.ExecutionCount), +                      Region.ColumnEnd, clamp_uint64_to_int64(Region.ExecutionCount),                        Region.FileID, Region.ExpandedFileID,                        int64_t(Region.Kind)});  } @@ -182,7 +192,7 @@ json::Array renderFunctions(    for (const auto &F : Functions)      FunctionArray.push_back(          json::Object({{"name", F.Name}, -                      {"count", int64_t(F.ExecutionCount)}, +                      {"count", clamp_uint64_to_int64(F.ExecutionCount)},                        {"regions", renderRegions(F.CountedRegions)},                        {"filenames", json::Array(F.Filenames)}}));    return FunctionArray; diff --git a/contrib/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp b/contrib/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp index 616f667e2c84..0e20ea63cd6f 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp @@ -76,9 +76,9 @@ std::unique_ptr<CoveragePrinter>  CoveragePrinter::create(const CoverageViewOptions &Opts) {    switch (Opts.Format) {    case CoverageViewOptions::OutputFormat::Text: -    return llvm::make_unique<CoveragePrinterText>(Opts); +    return std::make_unique<CoveragePrinterText>(Opts);    case CoverageViewOptions::OutputFormat::HTML: -    return llvm::make_unique<CoveragePrinterHTML>(Opts); +    return std::make_unique<CoveragePrinterHTML>(Opts);    case CoverageViewOptions::OutputFormat::Lcov:      // Unreachable because CodeCoverage.cpp should terminate with an error      // before we get here. @@ -141,10 +141,10 @@ SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,                             CoverageData &&CoverageInfo) {    switch (Options.Format) {    case CoverageViewOptions::OutputFormat::Text: -    return llvm::make_unique<SourceCoverageViewText>( +    return std::make_unique<SourceCoverageViewText>(          SourceName, File, Options, std::move(CoverageInfo));    case CoverageViewOptions::OutputFormat::HTML: -    return llvm::make_unique<SourceCoverageViewHTML>( +    return std::make_unique<SourceCoverageViewHTML>(          SourceName, File, Options, std::move(CoverageInfo));    case CoverageViewOptions::OutputFormat::Lcov:      // Unreachable because CodeCoverage.cpp should terminate with an error diff --git a/contrib/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp b/contrib/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp index 3ee318c9c640..b99bd83157d0 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp @@ -8,6 +8,7 @@  #include "llvm/Object/ObjectFile.h"  #include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/Alignment.h"  #include "llvm/Support/CommandLine.h"  #include "llvm/Support/LEB128.h"  #include "llvm/Support/raw_ostream.h" @@ -50,8 +51,13 @@ int convertForTestingMain(int argc, const char *argv[]) {    auto ObjFormat = OF->getTripleObjectFormat();    for (const auto &Section : OF->sections()) {      StringRef Name; -    if (Section.getName(Name)) +    if (Expected<StringRef> NameOrErr = Section.getName()) { +      Name = *NameOrErr; +    } else { +      consumeError(NameOrErr.takeError());        return 1; +    } +      if (Name == llvm::getInstrProfSectionName(IPSK_name, ObjFormat,                                                /*AddSegmentInfo=*/false)) {        ProfileNames = Section; @@ -94,7 +100,7 @@ int convertForTestingMain(int argc, const char *argv[]) {    encodeULEB128(ProfileNamesAddress, OS);    OS << ProfileNamesData;    // Coverage mapping data is expected to have an alignment of 8. -  for (unsigned Pad = OffsetToAlignment(OS.tell(), 8); Pad; --Pad) +  for (unsigned Pad = offsetToAlignment(OS.tell(), Align(8)); Pad; --Pad)      OS.write(uint8_t(0));    OS << CoverageMappingData; diff --git a/contrib/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp b/contrib/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp index 833312655788..03e1bab9417e 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp @@ -174,7 +174,11 @@ static void dumpCXXData(const ObjectFile *Obj) {    SectionRelocMap.clear();    for (const SectionRef &Section : Obj->sections()) { -    section_iterator Sec2 = Section.getRelocatedSection(); +    Expected<section_iterator> ErrOrSec = Section.getRelocatedSection(); +    if (!ErrOrSec) +      error(ErrOrSec.takeError()); + +    section_iterator Sec2 = *ErrOrSec;      if (Sec2 != Obj->section_end())        SectionRelocMap[*Sec2].push_back(Section);    } 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 9ac8bcf0ff01..6de512fc18dc 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp @@ -7,8 +7,10 @@  //===----------------------------------------------------------------------===//  #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h"  #include "llvm/Demangle/Demangle.h"  #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Host.h"  #include "llvm/Support/InitLLVM.h"  #include "llvm/Support/raw_ostream.h"  #include <cstdlib> @@ -41,6 +43,13 @@ static cl::opt<bool> StripUnderscore("strip-underscore",  static cl::alias StripUnderscoreShort("_",                                        cl::desc("alias for --strip-underscore"),                                        cl::aliasopt(StripUnderscore)); +static cl::opt<bool> +    NoStripUnderscore("no-strip-underscore", +                      cl::desc("do not strip the leading underscore"), +                      cl::init(false)); +static cl::alias +    NoStripUnderscoreShort("n", cl::desc("alias for --no-strip-underscore"), +                           cl::aliasopt(NoStripUnderscore));  static cl::opt<bool>      Types("types", @@ -55,11 +64,22 @@ Decorated(cl::Positional, cl::desc("<mangled>"), cl::ZeroOrMore);  static cl::extrahelp      HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); -static std::string demangle(llvm::raw_ostream &OS, const std::string &Mangled) { +static bool shouldStripUnderscore() { +  if (StripUnderscore) +    return true; +  if (NoStripUnderscore) +    return false; +  // If none of them are set, use the default value for platform. +  // macho has symbols prefix with "_" so strip by default. +  return Triple(sys::getProcessTriple()).isOSBinFormatMachO(); +} + +static std::string demangle(const std::string &Mangled) {    int Status; +  std::string Prefix;    const char *DecoratedStr = Mangled.c_str(); -  if (StripUnderscore) +  if (shouldStripUnderscore())      if (DecoratedStr[0] == '_')        ++DecoratedStr;    size_t DecoratedLength = strlen(DecoratedStr); @@ -73,11 +93,11 @@ static std::string demangle(llvm::raw_ostream &OS, const std::string &Mangled) {    if (!Undecorated &&        (DecoratedLength > 6 && strncmp(DecoratedStr, "__imp_", 6) == 0)) { -    OS << "import thunk for "; +    Prefix = "import thunk for ";      Undecorated = itaniumDemangle(DecoratedStr + 6, nullptr, nullptr, &Status);    } -  std::string Result(Undecorated ? Undecorated : Mangled); +  std::string Result(Undecorated ? Prefix + Undecorated : Mangled);    free(Undecorated);    return Result;  } @@ -125,9 +145,9 @@ static void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) {      SmallVector<std::pair<StringRef, StringRef>, 16> Words;      SplitStringDelims(Mangled, Words, IsLegalItaniumChar);      for (const auto &Word : Words) -      Result += demangle(OS, Word.first) + Word.second.str(); +      Result += ::demangle(Word.first) + Word.second.str();    } else -    Result = demangle(OS, Mangled); +    Result = ::demangle(Mangled);    OS << Result << '\n';    OS.flush();  } diff --git a/contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp b/contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp index 87d4d06bbc96..b53a6364c89e 100644 --- a/contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp @@ -145,7 +145,7 @@ int main(int argc, const char *argv[]) {      exitWithErrorCode(RemappingBufOrError.getError(), RemappingFile);    std::error_code EC; -  raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text); +  raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_Text);    if (EC)      exitWithErrorCode(EC, OutputFilename); diff --git a/contrib/llvm-project/llvm/tools/llvm-diff/DifferenceEngine.cpp b/contrib/llvm-project/llvm/tools/llvm-diff/DifferenceEngine.cpp index bc93ece86490..564ce7870592 100644 --- a/contrib/llvm-project/llvm/tools/llvm-diff/DifferenceEngine.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-diff/DifferenceEngine.cpp @@ -732,5 +732,14 @@ void DifferenceEngine::diff(Module *L, Module *R) {  bool DifferenceEngine::equivalentAsOperands(GlobalValue *L, GlobalValue *R) {    if (globalValueOracle) return (*globalValueOracle)(L, R); + +  if (isa<GlobalVariable>(L) && isa<GlobalVariable>(R)) { +    GlobalVariable *GVL = cast<GlobalVariable>(L); +    GlobalVariable *GVR = cast<GlobalVariable>(R); +    if (GVL->hasLocalLinkage() && GVL->hasUniqueInitializer() && +        GVR->hasLocalLinkage() && GVR->hasUniqueInitializer()) +      return GVL->getInitializer() == GVR->getInitializer(); +  } +    return L->getName() == R->getName();  } diff --git a/contrib/llvm-project/llvm/tools/llvm-dis/llvm-dis.cpp b/contrib/llvm-project/llvm/tools/llvm-dis/llvm-dis.cpp index 3f337b874b16..5d609468a380 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dis/llvm-dis.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-dis/llvm-dis.cpp @@ -153,58 +153,76 @@ int main(int argc, char **argv) {    LLVMContext Context;    Context.setDiagnosticHandler( -      llvm::make_unique<LLVMDisDiagnosticHandler>(argv[0])); +      std::make_unique<LLVMDisDiagnosticHandler>(argv[0]));    cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n");    std::unique_ptr<MemoryBuffer> MB =        ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFilename))); -  std::unique_ptr<Module> M = ExitOnErr(getLazyBitcodeModule( -      *MB, Context, /*ShouldLazyLoadMetadata=*/true, SetImporting)); -  if (MaterializeMetadata) -    ExitOnErr(M->materializeMetadata()); -  else -    ExitOnErr(M->materializeAll()); - -  BitcodeLTOInfo LTOInfo = ExitOnErr(getBitcodeLTOInfo(*MB)); -  std::unique_ptr<ModuleSummaryIndex> Index; -  if (LTOInfo.HasSummary) -    Index = ExitOnErr(getModuleSummaryIndex(*MB)); - -  // Just use stdout.  We won't actually print anything on it. -  if (DontPrint) -    OutputFilename = "-"; - -  if (OutputFilename.empty()) { // Unspecified output, infer it. -    if (InputFilename == "-") { -      OutputFilename = "-"; + +  BitcodeFileContents IF = ExitOnErr(llvm::getBitcodeFileContents(*MB)); + +  const size_t N = IF.Mods.size(); + +  if (OutputFilename == "-" && N > 1) +      errs() << "only single module bitcode files can be written to stdout\n"; + +  for (size_t i = 0; i < N; ++i) { +    BitcodeModule MB = IF.Mods[i]; +    std::unique_ptr<Module> M = ExitOnErr(MB.getLazyModule(Context, MaterializeMetadata, +                                          SetImporting)); +    if (MaterializeMetadata) +      ExitOnErr(M->materializeMetadata()); +    else +      ExitOnErr(M->materializeAll()); + +    BitcodeLTOInfo LTOInfo = ExitOnErr(MB.getLTOInfo()); +    std::unique_ptr<ModuleSummaryIndex> Index; +    if (LTOInfo.HasSummary) +      Index = ExitOnErr(MB.getSummary()); + +    std::string FinalFilename(OutputFilename); + +    // Just use stdout.  We won't actually print anything on it. +    if (DontPrint) +      FinalFilename = "-"; + +    if (FinalFilename.empty()) { // Unspecified output, infer it. +      if (InputFilename == "-") { +        FinalFilename = "-"; +      } else { +        StringRef IFN = InputFilename; +        FinalFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str(); +        if (N > 1) +          FinalFilename += std::string(".") + std::to_string(i); +        FinalFilename += ".ll"; +      }      } else { -      StringRef IFN = InputFilename; -      OutputFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str(); -      OutputFilename += ".ll"; +      if (N > 1) +        FinalFilename += std::string(".") + std::to_string(i);      } -  } -  std::error_code EC; -  std::unique_ptr<ToolOutputFile> Out( -      new ToolOutputFile(OutputFilename, EC, sys::fs::F_None)); -  if (EC) { -    errs() << EC.message() << '\n'; -    return 1; -  } +    std::error_code EC; +    std::unique_ptr<ToolOutputFile> Out( +        new ToolOutputFile(FinalFilename, EC, sys::fs::OF_Text)); +    if (EC) { +      errs() << EC.message() << '\n'; +      return 1; +    } -  std::unique_ptr<AssemblyAnnotationWriter> Annotator; -  if (ShowAnnotations) -    Annotator.reset(new CommentWriter()); +    std::unique_ptr<AssemblyAnnotationWriter> Annotator; +    if (ShowAnnotations) +      Annotator.reset(new CommentWriter()); -  // All that llvm-dis does is write the assembly to a file. -  if (!DontPrint) { -    M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder); -    if (Index) -      Index->print(Out->os()); -  } +    // All that llvm-dis does is write the assembly to a file. +    if (!DontPrint) { +      M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder); +      if (Index) +        Index->print(Out->os()); +    } -  // Declare success. -  Out->keep(); +    // Declare success. +    Out->keep(); +  }    return 0;  } diff --git a/contrib/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp b/contrib/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp index f26369b935cb..5bef4d5148ca 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp @@ -5,11 +5,18 @@  #include "llvm/DebugInfo/DWARF/DWARFContext.h"  #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"  #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/JSON.h"  #define DEBUG_TYPE "dwarfdump"  using namespace llvm;  using namespace object; +/// This represents the number of categories of debug location coverage being +/// calculated. The first category is the number of variables with 0% location +/// coverage, but the last category is the number of variables with 100% +/// location coverage. +constexpr int NumOfCoverageCategories = 12; +  /// Holds statistics for one function (or other entity that has a PC range and  /// contains variables, such as a compile unit).  struct PerFunctionStats { @@ -43,9 +50,9 @@ struct PerFunctionStats {    unsigned NumVars = 0;    /// Number of variables with source location.    unsigned NumVarSourceLocations = 0; -  /// Number of variables wtih type. +  /// Number of variables with type.    unsigned NumVarTypes = 0; -  /// Number of variables wtih DW_AT_location. +  /// Number of variables with DW_AT_location.    unsigned NumVarLocations = 0;  }; @@ -53,55 +60,134 @@ struct PerFunctionStats {  struct GlobalStats {    /// Total number of PC range bytes covered by DW_AT_locations.    unsigned ScopeBytesCovered = 0; -  /// Total number of PC range bytes in each variable's enclosing scope, -  /// starting from the first definition of the variable. -  unsigned ScopeBytesFromFirstDefinition = 0; -  /// Total number of call site entries (DW_TAG_call_site) or -  /// (DW_AT_call_file & DW_AT_call_line). +  /// Total number of PC range bytes in each variable's enclosing scope. +  unsigned ScopeBytes = 0; +  /// Total number of PC range bytes covered by DW_AT_locations with +  /// the debug entry values (DW_OP_entry_value). +  unsigned ScopeEntryValueBytesCovered = 0; +  /// Total number of PC range bytes covered by DW_AT_locations of +  /// formal parameters. +  unsigned ParamScopeBytesCovered = 0; +  /// Total number of PC range bytes in each variable's enclosing scope +  /// (only for parameters). +  unsigned ParamScopeBytes = 0; +  /// Total number of PC range bytes covered by DW_AT_locations with +  /// the debug entry values (DW_OP_entry_value) (only for parameters). +  unsigned ParamScopeEntryValueBytesCovered = 0; +  /// Total number of PC range bytes covered by DW_AT_locations (only for local +  /// variables). +  unsigned VarScopeBytesCovered = 0; +  /// Total number of PC range bytes in each variable's enclosing scope +  /// (only for local variables). +  unsigned VarScopeBytes = 0; +  /// Total number of PC range bytes covered by DW_AT_locations with +  /// the debug entry values (DW_OP_entry_value) (only for local variables). +  unsigned VarScopeEntryValueBytesCovered = 0; +  /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).    unsigned CallSiteEntries = 0; +  /// Total number of call site DIEs (DW_TAG_call_site). +  unsigned CallSiteDIEs = 0; +  /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter). +  unsigned CallSiteParamDIEs = 0;    /// Total byte size of concrete functions. This byte size includes    /// inline functions contained in the concrete functions. -  uint64_t FunctionSize = 0; +  unsigned FunctionSize = 0;    /// Total byte size of inlined functions. This is the total number of bytes    /// for the top inline functions within concrete functions. This can help    /// tune the inline settings when compiling to match user expectations. -  uint64_t InlineFunctionSize = 0; +  unsigned InlineFunctionSize = 0; +}; + +/// Holds accumulated debug location statistics about local variables and +/// formal parameters. +struct LocationStats { +  /// Map the scope coverage decile to the number of variables in the decile. +  /// The first element of the array (at the index zero) represents the number +  /// of variables with the no debug location at all, but the last element +  /// in the vector represents the number of fully covered variables within +  /// its scope. +  std::vector<unsigned> VarParamLocStats{ +      std::vector<unsigned>(NumOfCoverageCategories, 0)}; +  /// Map non debug entry values coverage. +  std::vector<unsigned> VarParamNonEntryValLocStats{ +      std::vector<unsigned>(NumOfCoverageCategories, 0)}; +  /// The debug location statistics for formal parameters. +  std::vector<unsigned> ParamLocStats{ +      std::vector<unsigned>(NumOfCoverageCategories, 0)}; +  /// Map non debug entry values coverage for formal parameters. +  std::vector<unsigned> ParamNonEntryValLocStats{ +      std::vector<unsigned>(NumOfCoverageCategories, 0)}; +  /// The debug location statistics for local variables. +  std::vector<unsigned> VarLocStats{ +      std::vector<unsigned>(NumOfCoverageCategories, 0)}; +  /// Map non debug entry values coverage for local variables. +  std::vector<unsigned> VarNonEntryValLocStats{ +      std::vector<unsigned>(NumOfCoverageCategories, 0)}; +  /// Total number of local variables and function parameters processed. +  unsigned NumVarParam = 0; +  /// Total number of formal parameters processed. +  unsigned NumParam = 0; +  /// Total number of local variables processed. +  unsigned NumVar = 0;  }; -/// Extract the low pc from a Die. -static uint64_t getLowPC(DWARFDie Die) { -  auto RangesOrError = Die.getAddressRanges(); -  DWARFAddressRangesVector Ranges; -  if (RangesOrError) -    Ranges = RangesOrError.get(); -  else -    llvm::consumeError(RangesOrError.takeError()); -  if (Ranges.size()) -    return Ranges[0].LowPC; -  return dwarf::toAddress(Die.find(dwarf::DW_AT_low_pc), 0); +/// Collect debug location statistics for one DIE. +static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope, +                            std::vector<unsigned> &VarParamLocStats, +                            std::vector<unsigned> &ParamLocStats, +                            std::vector<unsigned> &VarLocStats, bool IsParam, +                            bool IsLocalVar) { +  auto getCoverageBucket = [BytesCovered, BytesInScope]() -> unsigned { +    // No debug location at all for the variable. +    if (BytesCovered == 0) +      return 0; +    // Fully covered variable within its scope. +    if (BytesCovered >= BytesInScope) +      return NumOfCoverageCategories - 1; +    // Get covered range (e.g. 20%-29%). +    unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope; +    LocBucket /= 10; +    return LocBucket + 1; +  }; + +  unsigned CoverageBucket = getCoverageBucket(); +  VarParamLocStats[CoverageBucket]++; +  if (IsParam) +    ParamLocStats[CoverageBucket]++; +  else if (IsLocalVar) +    VarLocStats[CoverageBucket]++;  }  /// Collect debug info quality metrics for one DIE.  static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, -                               std::string VarPrefix, uint64_t ScopeLowPC, -                               uint64_t BytesInScope, uint32_t InlineDepth, +                               std::string VarPrefix, uint64_t BytesInScope, +                               uint32_t InlineDepth,                                 StringMap<PerFunctionStats> &FnStatMap, -                               GlobalStats &GlobalStats) { +                               GlobalStats &GlobalStats, +                               LocationStats &LocStats) {    bool HasLoc = false;    bool HasSrcLoc = false;    bool HasType = false;    bool IsArtificial = false;    uint64_t BytesCovered = 0; -  uint64_t OffsetToFirstDefinition = 0; +  uint64_t BytesEntryValuesCovered = 0; +  auto &FnStats = FnStatMap[FnPrefix]; +  bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter; +  bool IsLocalVar = Die.getTag() == dwarf::DW_TAG_variable; + +  if (Die.getTag() == dwarf::DW_TAG_call_site || +      Die.getTag() == dwarf::DW_TAG_GNU_call_site) { +    GlobalStats.CallSiteDIEs++; +    return; +  } -  if (Die.getTag() == dwarf::DW_TAG_call_site) { -    GlobalStats.CallSiteEntries++; +  if (Die.getTag() == dwarf::DW_TAG_call_site_parameter || +      Die.getTag() == dwarf::DW_TAG_GNU_call_site_parameter) { +    GlobalStats.CallSiteParamDIEs++;      return;    } -  if (Die.getTag() != dwarf::DW_TAG_formal_parameter && -      Die.getTag() != dwarf::DW_TAG_variable && -      Die.getTag() != dwarf::DW_TAG_member) { +  if (!IsParam && !IsLocalVar && Die.getTag() != dwarf::DW_TAG_member) {      // Not a variable or constant member.      return;    } @@ -116,6 +202,19 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,    if (Die.find(dwarf::DW_AT_artificial))      IsArtificial = true; +  auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool { +    DWARFUnit *U = Die.getDwarfUnit(); +    DataExtractor Data(toStringRef(D), +                       Die.getDwarfUnit()->getContext().isLittleEndian(), 0); +    DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize()); +    // Consider the expression containing the DW_OP_entry_value as +    // an entry value. +    return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) { +      return Op.getCode() == dwarf::DW_OP_entry_value || +             Op.getCode() == dwarf::DW_OP_GNU_entry_value; +    }); +  }; +    if (Die.find(dwarf::DW_AT_const_value)) {      // This catches constant members *and* variables.      HasLoc = true; @@ -126,36 +225,48 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,        return;      }      // Handle variables and function arguments. -    auto FormValue = Die.find(dwarf::DW_AT_location); -    HasLoc = FormValue.hasValue(); -    if (HasLoc) { +    Expected<std::vector<DWARFLocationExpression>> Loc = +        Die.getLocations(dwarf::DW_AT_location); +    if (!Loc) { +      consumeError(Loc.takeError()); +    } else { +      HasLoc = true;        // Get PC coverage. -      if (auto DebugLocOffset = FormValue->getAsSectionOffset()) { -        auto *DebugLoc = Die.getDwarfUnit()->getContext().getDebugLoc(); -        if (auto List = DebugLoc->getLocationListAtOffset(*DebugLocOffset)) { -          for (auto Entry : List->Entries) -            BytesCovered += Entry.End - Entry.Begin; -          if (List->Entries.size()) { -            uint64_t FirstDef = List->Entries[0].Begin; -            uint64_t UnitOfs = getLowPC(Die.getDwarfUnit()->getUnitDIE()); -            // Ranges sometimes start before the lexical scope. -            if (UnitOfs + FirstDef >= ScopeLowPC) -              OffsetToFirstDefinition = UnitOfs + FirstDef - ScopeLowPC; -            // Or even after it. Count that as a failure. -            if (OffsetToFirstDefinition > BytesInScope) -              OffsetToFirstDefinition = 0; -          } -        } -        assert(BytesInScope); -      } else { +      auto Default = find_if( +          *Loc, [](const DWARFLocationExpression &L) { return !L.Range; }); +      if (Default != Loc->end()) {          // Assume the entire range is covered by a single location.          BytesCovered = BytesInScope; +      } else { +        for (auto Entry : *Loc) { +          uint64_t BytesEntryCovered = Entry.Range->HighPC - Entry.Range->LowPC; +          BytesCovered += BytesEntryCovered; +          if (IsEntryValue(Entry.Expr)) +            BytesEntryValuesCovered += BytesEntryCovered; +        }        }      }    } +  // Calculate the debug location statistics. +  if (BytesInScope) { +    LocStats.NumVarParam++; +    if (IsParam) +      LocStats.NumParam++; +    else if (IsLocalVar) +      LocStats.NumVar++; + +    collectLocStats(BytesCovered, BytesInScope, LocStats.VarParamLocStats, +                    LocStats.ParamLocStats, LocStats.VarLocStats, IsParam, +                    IsLocalVar); +    // Non debug entry values coverage statistics. +    collectLocStats(BytesCovered - BytesEntryValuesCovered, BytesInScope, +                    LocStats.VarParamNonEntryValLocStats, +                    LocStats.ParamNonEntryValLocStats, +                    LocStats.VarNonEntryValLocStats, IsParam, IsLocalVar); +  } +    // Collect PC range coverage data. -  auto &FnStats = FnStatMap[FnPrefix];    if (DWARFDie D =            Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))      Die = D; @@ -165,21 +276,28 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,    FnStats.VarsInFunction.insert(VarPrefix + VarName);    if (BytesInScope) {      FnStats.TotalVarWithLoc += (unsigned)HasLoc; -    // Adjust for the fact the variables often start their lifetime in the -    // middle of the scope. -    BytesInScope -= OffsetToFirstDefinition;      // Turns out we have a lot of ranges that extend past the lexical scope.      GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered); -    GlobalStats.ScopeBytesFromFirstDefinition += BytesInScope; -    assert(GlobalStats.ScopeBytesCovered <= -           GlobalStats.ScopeBytesFromFirstDefinition); +    GlobalStats.ScopeBytes += BytesInScope; +    GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered; +    if (IsParam) { +      GlobalStats.ParamScopeBytesCovered += +          std::min(BytesInScope, BytesCovered); +      GlobalStats.ParamScopeBytes += BytesInScope; +      GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered; +    } else if (IsLocalVar) { +      GlobalStats.VarScopeBytesCovered += std::min(BytesInScope, BytesCovered); +      GlobalStats.VarScopeBytes += BytesInScope; +      GlobalStats.VarScopeEntryValueBytesCovered += BytesEntryValuesCovered; +    } +    assert(GlobalStats.ScopeBytesCovered <= GlobalStats.ScopeBytes);    } else if (Die.getTag() == dwarf::DW_TAG_member) {      FnStats.ConstantMembers++;    } else {      FnStats.TotalVarWithLoc += (unsigned)HasLoc;    }    if (!IsArtificial) { -    if (Die.getTag() == dwarf::DW_TAG_formal_parameter) { +    if (IsParam) {        FnStats.NumParams++;        if (HasType)          FnStats.NumParamTypes++; @@ -187,7 +305,7 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,          FnStats.NumParamSourceLocations++;        if (HasLoc)          FnStats.NumParamLocations++; -    } else if (Die.getTag() == dwarf::DW_TAG_variable) { +    } else if (IsLocalVar) {        FnStats.NumVars++;        if (HasType)          FnStats.NumVarTypes++; @@ -201,10 +319,11 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,  /// Recursively collect debug info quality metrics.  static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix, -                                  std::string VarPrefix, uint64_t ScopeLowPC, -                                  uint64_t BytesInScope, uint32_t InlineDepth, +                                  std::string VarPrefix, uint64_t BytesInScope, +                                  uint32_t InlineDepth,                                    StringMap<PerFunctionStats> &FnStatMap, -                                  GlobalStats &GlobalStats) { +                                  GlobalStats &GlobalStats, +                                  LocationStats &LocStats) {    // Handle any kind of lexical scope.    const dwarf::Tag Tag = Die.getTag();    const bool IsFunction = Tag == dwarf::DW_TAG_subprogram; @@ -236,7 +355,6 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,      uint64_t BytesInThisScope = 0;      for (auto Range : Ranges)        BytesInThisScope += Range.HighPC - Range.LowPC; -    ScopeLowPC = getLowPC(Die);      // Count the function.      if (!IsBlock) { @@ -272,8 +390,8 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,      }    } else {      // Not a scope, visit the Die itself. It could be a variable. -    collectStatsForDie(Die, FnPrefix, VarPrefix, ScopeLowPC, BytesInScope, -                       InlineDepth, FnStatMap, GlobalStats); +    collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth, +                       FnStatMap, GlobalStats, LocStats);    }    // Set InlineDepth correctly for child recursion @@ -290,8 +408,8 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,      if (Child.getTag() == dwarf::DW_TAG_lexical_block)        ChildVarPrefix += toHex(LexicalBlockIndex++) + '.'; -    collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, ScopeLowPC, -                          BytesInScope, InlineDepth, FnStatMap, GlobalStats); +    collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, BytesInScope, +                          InlineDepth, FnStatMap, GlobalStats, LocStats);      Child = Child.getSibling();    }  } @@ -299,14 +417,33 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,  /// Print machine-readable output.  /// The machine-readable format is single-line JSON output.  /// \{ -static void printDatum(raw_ostream &OS, const char *Key, StringRef Value) { -  OS << ",\"" << Key << "\":\"" << Value << '"'; -  LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n'); -} -static void printDatum(raw_ostream &OS, const char *Key, uint64_t Value) { +static void printDatum(raw_ostream &OS, const char *Key, json::Value Value) {    OS << ",\"" << Key << "\":" << Value;    LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n');  } +static void printLocationStats(raw_ostream &OS, +                               const char *Key, +                               std::vector<unsigned> &LocationStats) { +  OS << ",\"" << Key << " with 0% of its scope covered\":" +     << LocationStats[0]; +  LLVM_DEBUG(llvm::dbgs() << Key << " with 0% of its scope covered: " +                          << LocationStats[0] << '\n'); +  OS << ",\"" << Key << " with (0%,10%) of its scope covered\":" +     << LocationStats[1]; +  LLVM_DEBUG(llvm::dbgs() << Key << " with (0%,10%) of its scope covered: " +                          << LocationStats[1] << '\n'); +  for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) { +    OS << ",\"" << Key << " with [" << (i - 1) * 10 << "%," << i * 10 +       << "%) of its scope covered\":" << LocationStats[i]; +    LLVM_DEBUG(llvm::dbgs() +               << Key << " with [" << (i - 1) * 10 << "%," << i * 10 +               << "%) of its scope covered: " << LocationStats[i]); +  } +  OS << ",\"" << Key << " with 100% of its scope covered\":" +     << LocationStats[NumOfCoverageCategories - 1]; +  LLVM_DEBUG(llvm::dbgs() << Key << " with 100% of its scope covered: " +                          << LocationStats[NumOfCoverageCategories - 1]); +}  /// \}  /// Collect debug info quality metrics for an entire DIContext. @@ -321,15 +458,17 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,                                 Twine Filename, raw_ostream &OS) {    StringRef FormatName = Obj.getFileFormatName();    GlobalStats GlobalStats; +  LocationStats LocStats;    StringMap<PerFunctionStats> Statistics;    for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units())      if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) -      collectStatsRecursive(CUDie, "/", "g", 0, 0, 0, Statistics, GlobalStats); +      collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats, +                            LocStats);    /// The version number should be increased every time the algorithm is changed    /// (including bug fixes). New metrics may be added without increasing the    /// version. -  unsigned Version = 3; +  unsigned Version = 4;    unsigned VarParamTotal = 0;    unsigned VarParamUnique = 0;    unsigned VarParamWithLoc = 0; @@ -387,9 +526,22 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,    printDatum(OS, "source variables", VarParamTotal);    printDatum(OS, "variables with location", VarParamWithLoc);    printDatum(OS, "call site entries", GlobalStats.CallSiteEntries); -  printDatum(OS, "scope bytes total", -             GlobalStats.ScopeBytesFromFirstDefinition); +  printDatum(OS, "call site DIEs", GlobalStats.CallSiteDIEs); +  printDatum(OS, "call site parameter DIEs", GlobalStats.CallSiteParamDIEs); +  printDatum(OS, "scope bytes total", GlobalStats.ScopeBytes);    printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered); +  printDatum(OS, "entry value scope bytes covered", +             GlobalStats.ScopeEntryValueBytesCovered); +  printDatum(OS, "formal params scope bytes total", +             GlobalStats.ParamScopeBytes); +  printDatum(OS, "formal params scope bytes covered", +             GlobalStats.ParamScopeBytesCovered); +  printDatum(OS, "formal params entry value scope bytes covered", +             GlobalStats.ParamScopeEntryValueBytesCovered); +  printDatum(OS, "vars scope bytes total", GlobalStats.VarScopeBytes); +  printDatum(OS, "vars scope bytes covered", GlobalStats.VarScopeBytesCovered); +  printDatum(OS, "vars entry value scope bytes covered", +             GlobalStats.VarScopeEntryValueBytesCovered);    printDatum(OS, "total function size", GlobalStats.FunctionSize);    printDatum(OS, "total inlined function size", GlobalStats.InlineFunctionSize);    printDatum(OS, "total formal params", ParamTotal); @@ -400,6 +552,20 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,    printDatum(OS, "vars with source location", VarWithSrcLoc);    printDatum(OS, "vars with type", VarWithType);    printDatum(OS, "vars with binary location", VarWithLoc); +  printDatum(OS, "total variables procesed by location statistics", +             LocStats.NumVarParam); +  printLocationStats(OS, "variables", LocStats.VarParamLocStats); +  printLocationStats(OS, "variables (excluding the debug entry values)", +                     LocStats.VarParamNonEntryValLocStats); +  printDatum(OS, "total params procesed by location statistics", +             LocStats.NumParam); +  printLocationStats(OS, "params", LocStats.ParamLocStats); +  printLocationStats(OS, "params (excluding the debug entry values)", +                     LocStats.ParamNonEntryValLocStats); +  printDatum(OS, "total vars procesed by location statistics", LocStats.NumVar); +  printLocationStats(OS, "vars", LocStats.VarLocStats); +  printLocationStats(OS, "vars (excluding the debug entry values)", +                     LocStats.VarNonEntryValLocStats);    OS << "}\n";    LLVM_DEBUG(        llvm::dbgs() << "Total Availability: " @@ -407,7 +573,7 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,                     << "%\n";        llvm::dbgs() << "PC Ranges covered: "                     << (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) / -                                      GlobalStats.ScopeBytesFromFirstDefinition) +                                      GlobalStats.ScopeBytes)                     << "%\n");    return true;  } diff --git a/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index 05a7aef67ece..374bdd482a8d 100644 --- a/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -271,7 +271,7 @@ static bool filterArch(ObjectFile &Obj) {            return true;        // Match as name. -      if (MachO->getArchTriple().getArch() == Triple(Arch).getArch()) +      if (MachO->getArchTriple().getArchName() == Triple(Arch).getArchName())          return true;      }    } @@ -584,7 +584,7 @@ int main(int argc, char **argv) {    }    std::error_code EC; -  ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_None); +  ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_Text);    error("Unable to open output file" + OutputFilename, EC);    // Don't remove output file if we exit with an error.    OutputFile.keep(); diff --git a/contrib/llvm-project/llvm/tools/llvm-extract/llvm-extract.cpp b/contrib/llvm-project/llvm/tools/llvm-extract/llvm-extract.cpp index 300bc0b4bd52..dddc0d9baa08 100644 --- a/contrib/llvm-project/llvm/tools/llvm-extract/llvm-extract.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-extract/llvm-extract.cpp @@ -74,8 +74,18 @@ static cl::list<std::string>  // ExtractBlocks - The blocks to extract from the module.  static cl::list<std::string> ExtractBlocks( -    "bb", cl::desc("Specify <function, basic block> pairs to extract"), -    cl::ZeroOrMore, cl::value_desc("function:bb"), cl::cat(ExtractCat)); +    "bb", +    cl::desc( +        "Specify <function, basic block1[;basic block2...]> pairs to extract.\n" +        "Each pair will create a function.\n" +        "If multiple basic blocks are specified in one pair,\n" +        "the first block in the sequence should dominate the rest.\n" +        "eg:\n" +        "  --bb=f:bb1;bb2 will extract one function with both bb1 and bb2;\n" +        "  --bb=f:bb1 --bb=f:bb2 will extract two functions, one with bb1, one " +        "with bb2."), +    cl::ZeroOrMore, cl::value_desc("function:bb1[;bb2...]"), +    cl::cat(ExtractCat));  // ExtractAlias - The alias to extract from the module.  static cl::list<std::string> @@ -350,7 +360,7 @@ int main(int argc, char **argv) {    Passes.add(createStripDeadPrototypesPass());   // Remove dead func decls    std::error_code EC; -  ToolOutputFile Out(OutputFilename, EC, sys::fs::F_None); +  ToolOutputFile Out(OutputFilename, EC, sys::fs::OF_None);    if (EC) {      errs() << EC.message() << '\n';      return 1; diff --git a/contrib/llvm-project/llvm/tools/llvm-link/llvm-link.cpp b/contrib/llvm-project/llvm/tools/llvm-link/llvm-link.cpp index 50ba57178d02..fa36e083b6f8 100644 --- a/contrib/llvm-project/llvm/tools/llvm-link/llvm-link.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-link/llvm-link.cpp @@ -351,13 +351,13 @@ int main(int argc, char **argv) {    LLVMContext Context;    Context.setDiagnosticHandler( -    llvm::make_unique<LLVMLinkDiagnosticHandler>(), true); +    std::make_unique<LLVMLinkDiagnosticHandler>(), true);    cl::ParseCommandLineOptions(argc, argv, "llvm linker\n");    if (!DisableDITypeMap)      Context.enableDebugTypeODRUniquing(); -  auto Composite = make_unique<Module>("llvm-link", Context); +  auto Composite = std::make_unique<Module>("llvm-link", Context);    Linker L(*Composite);    unsigned Flags = Linker::Flags::None; @@ -381,7 +381,7 @@ int main(int argc, char **argv) {      errs() << "Here's the assembly:\n" << *Composite;    std::error_code EC; -  ToolOutputFile Out(OutputFilename, EC, sys::fs::F_None); +  ToolOutputFile Out(OutputFilename, EC, sys::fs::OF_None);    if (EC) {      WithColor::error() << EC.message() << '\n';      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 585207b25185..b47e68e82850 100644 --- a/contrib/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp @@ -315,8 +315,8 @@ getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,    error(BufferOrErr, "error loading file '" + Path + "'");    Buffer = std::move(BufferOrErr.get());    CurrentActivity = ("loading file '" + Path + "'").str(); -  std::unique_ptr<LLVMContext> Context = llvm::make_unique<LLVMContext>(); -  Context->setDiagnosticHandler(llvm::make_unique<LLVMLTODiagnosticHandler>(), +  std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>(); +  Context->setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),                                  true);    ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(        std::move(Context), Buffer->getBufferStart(), Buffer->getBufferSize(), @@ -420,7 +420,7 @@ static void createCombinedModuleSummaryIndex() {    std::error_code EC;    assert(!OutputFilename.empty());    raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC, -                    sys::fs::OpenFlags::F_None); +                    sys::fs::OpenFlags::OF_None);    error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'");    WriteIndexToFile(CombinedIndex, OS);    OS.close(); @@ -510,7 +510,7 @@ static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile &File,  static void writeModuleToFile(Module &TheModule, StringRef Filename) {    std::error_code EC; -  raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::F_None); +  raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::OF_None);    error(EC, "error opening the file '" + Filename + "'");    maybeVerifyModule(TheModule);    WriteBitcodeToFile(TheModule, OS, /* ShouldPreserveUseListOrder */ true); @@ -581,7 +581,7 @@ private:      if (!CombinedIndex)        report_fatal_error("ThinLink didn't create an index");      std::error_code EC; -    raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::F_None); +    raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::OF_None);      error(EC, "error opening the file '" + OutputFilename + "'");      WriteIndexToFile(*CombinedIndex, OS);    } @@ -619,7 +619,7 @@ private:        }        OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);        std::error_code EC; -      raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::F_None); +      raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);        error(EC, "error opening the file '" + OutputName + "'");        WriteIndexToFile(*Index, OS, &ModuleToSummariesForIndex);      } @@ -802,7 +802,7 @@ private:        }        std::error_code EC; -      raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::F_None); +      raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);        error(EC, "error opening the file '" + OutputName + "'");        OS << std::get<0>(BinName)->getBuffer();      } @@ -848,7 +848,7 @@ private:      for (unsigned BufID = 0; BufID < Binaries.size(); ++BufID) {        auto OutputName = InputFilenames[BufID] + ".thinlto.o";        std::error_code EC; -      raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::F_None); +      raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);        error(EC, "error opening the file '" + OutputName + "'");        OS << Binaries[BufID]->getBuffer();      } @@ -921,7 +921,7 @@ int main(int argc, char **argv) {    unsigned BaseArg = 0;    LLVMContext Context; -  Context.setDiagnosticHandler(llvm::make_unique<LLVMLTODiagnosticHandler>(), +  Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),                                 true);    LTOCodeGenerator CodeGen(Context); @@ -1020,7 +1020,7 @@ int main(int argc, char **argv) {        if (Parallelism != 1)          PartFilename += "." + utostr(I);        std::error_code EC; -      OSs.emplace_back(PartFilename, EC, sys::fs::F_None); +      OSs.emplace_back(PartFilename, EC, sys::fs::OF_None);        if (EC)          error("error opening the file '" + PartFilename + "': " + EC.message());        OSPtrs.push_back(&OSs.back().os()); 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 0bd9289dc938..67a677dd45fb 100644 --- a/contrib/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -270,6 +270,8 @@ static int run(int argc, char **argv) {    Conf.OverrideTriple = OverrideTriple;    Conf.DefaultTriple = DefaultTriple;    Conf.StatsFile = StatsFile; +  Conf.PTO.LoopVectorization = Conf.OptLevel > 1; +  Conf.PTO.SLPVectorization = Conf.OptLevel > 1;    ThinBackend Backend;    if (ThinLTODistributedIndexes) @@ -291,6 +293,14 @@ static int run(int argc, char **argv) {      std::vector<SymbolResolution> Res;      for (const InputFile::Symbol &Sym : Input->symbols()) {        auto I = CommandLineResolutions.find({F, Sym.getName()}); +      // If it isn't found, look for "$", which would have been added +      // (followed by a hash) when the symbol was promoted during module +      // splitting if it was defined in one part and used in the other. +      // Try looking up the symbol name before the "$". +      if (I == CommandLineResolutions.end()) { +        auto SplitName = Sym.getName().rsplit("$"); +        I = CommandLineResolutions.find({F, SplitName.first}); +      }        if (I == CommandLineResolutions.end()) {          llvm::errs() << argv[0] << ": missing symbol resolution for " << F                       << ',' << Sym.getName() << '\n'; @@ -325,9 +335,9 @@ static int run(int argc, char **argv) {      std::string Path = OutputFilename + "." + utostr(Task);      std::error_code EC; -    auto S = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None); +    auto S = std::make_unique<raw_fd_ostream>(Path, EC, sys::fs::OF_None);      check(EC, Path); -    return llvm::make_unique<lto::NativeObjectStream>(std::move(S)); +    return std::make_unique<lto::NativeObjectStream>(std::move(S));    };    auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) { diff --git a/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp b/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp index e2af2e7f2e32..e286c0fff6e1 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp @@ -17,6 +17,7 @@  #include "llvm/MC/MCContext.h"  #include "llvm/MC/MCDisassembler/MCDisassembler.h"  #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectFileInfo.h"  #include "llvm/MC/MCRegisterInfo.h"  #include "llvm/MC/MCStreamer.h"  #include "llvm/MC/MCSubtargetInfo.h" @@ -45,8 +46,7 @@ static bool PrintInsts(const MCDisassembler &DisAsm,      MCInst Inst;      MCDisassembler::DecodeStatus S; -    S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, -                              /*REMOVE*/ nulls(), nulls()); +    S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls());      switch (S) {      case MCDisassembler::Fail:        SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]), @@ -129,13 +129,11 @@ static bool ByteArrayFromString(ByteArrayTy &ByteArray,    return false;  } -int Disassembler::disassemble(const Target &T, -                              const std::string &Triple, -                              MCSubtargetInfo &STI, -                              MCStreamer &Streamer, -                              MemoryBuffer &Buffer, -                              SourceMgr &SM, -                              raw_ostream &Out) { +int Disassembler::disassemble(const Target &T, const std::string &Triple, +                              MCSubtargetInfo &STI, MCStreamer &Streamer, +                              MemoryBuffer &Buffer, SourceMgr &SM, +                              MCContext &Ctx, raw_ostream &Out, +                              const MCTargetOptions &MCOptions) {    std::unique_ptr<const MCRegisterInfo> MRI(T.createMCRegInfo(Triple));    if (!MRI) { @@ -143,15 +141,13 @@ int Disassembler::disassemble(const Target &T,      return -1;    } -  std::unique_ptr<const MCAsmInfo> MAI(T.createMCAsmInfo(*MRI, Triple)); +  std::unique_ptr<const MCAsmInfo> MAI( +      T.createMCAsmInfo(*MRI, Triple, MCOptions));    if (!MAI) {      errs() << "error: no assembly info for target " << Triple << "\n";      return -1;    } -  // Set up the MCContext for creating symbols and MCExpr's. -  MCContext Ctx(MAI.get(), MRI.get(), nullptr); -    std::unique_ptr<const MCDisassembler> DisAsm(      T.createMCDisassembler(STI, Ctx));    if (!DisAsm) { diff --git a/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.h b/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.h index 11b685233abc..a1603e584980 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.h +++ b/contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.h @@ -22,18 +22,17 @@ class MemoryBuffer;  class Target;  class raw_ostream;  class SourceMgr; +class MCContext;  class MCSubtargetInfo;  class MCStreamer; +class MCTargetOptions;  class Disassembler {  public: -  static int disassemble(const Target &T, -                         const std::string &Triple, -                         MCSubtargetInfo &STI, -                         MCStreamer &Streamer, -                         MemoryBuffer &Buffer, -                         SourceMgr &SM, -                         raw_ostream &Out); +  static int disassemble(const Target &T, const std::string &Triple, +                         MCSubtargetInfo &STI, MCStreamer &Streamer, +                         MemoryBuffer &Buffer, SourceMgr &SM, MCContext &Ctx, +                         raw_ostream &Out, const MCTargetOptions &MCOptions);  };  } // 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 ec189c297860..6aa347d98be2 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp @@ -209,9 +209,10 @@ static const Target *GetTarget(const char *ProgName) {    return TheTarget;  } -static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path) { +static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path, +    sys::fs::OpenFlags Flags) {    std::error_code EC; -  auto Out = llvm::make_unique<ToolOutputFile>(Path, EC, sys::fs::F_None); +  auto Out = std::make_unique<ToolOutputFile>(Path, EC, Flags);    if (EC) {      WithColor::error() << EC.message() << '\n';      return nullptr; @@ -279,7 +280,7 @@ static int fillCommandLineSymbols(MCAsmParser &Parser) {  static int AssembleInput(const char *ProgName, const Target *TheTarget,                           SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,                           MCAsmInfo &MAI, MCSubtargetInfo &STI, -                         MCInstrInfo &MCII, MCTargetOptions &MCOptions) { +                         MCInstrInfo &MCII, MCTargetOptions const &MCOptions) {    std::unique_ptr<MCAsmParser> Parser(        createMCAsmParser(SrcMgr, Ctx, Str, MAI));    std::unique_ptr<MCTargetAsmParser> TAP( @@ -316,7 +317,7 @@ int main(int argc, char **argv) {    cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);    cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n"); -  MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); +  const MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();    setDwarfDebugFlags(argc, argv);    setDwarfDebugProducer(); @@ -350,7 +351,8 @@ int main(int argc, char **argv) {    std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));    assert(MRI && "Unable to create target register info!"); -  std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); +  std::unique_ptr<MCAsmInfo> MAI( +      TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));    assert(MAI && "Unable to create target asm info!");    MAI->setRelaxELFRelocations(RelaxELFRel); @@ -368,7 +370,7 @@ int main(int argc, char **argv) {    // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and    // MCObjectFileInfo needs a MCContext reference in order to initialize itself.    MCObjectFileInfo MOFI; -  MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr); +  MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr, &MCOptions);    MOFI.InitMCObjectFileInfo(TheTriple, PIC, Ctx, LargeCodeModel);    if (SaveTempLabels) @@ -413,7 +415,9 @@ int main(int argc, char **argv) {      FeaturesStr = Features.getString();    } -  std::unique_ptr<ToolOutputFile> Out = GetOutputStream(OutputFilename); +  sys::fs::OpenFlags Flags = (FileType == OFT_AssemblyFile) ? sys::fs::OF_Text +                                                            : sys::fs::OF_None; +  std::unique_ptr<ToolOutputFile> Out = GetOutputStream(OutputFilename, Flags);    if (!Out)      return 1; @@ -423,7 +427,7 @@ int main(int argc, char **argv) {        WithColor::error() << "dwo output only supported with object files\n";        return 1;      } -    DwoOut = GetOutputStream(SplitDwarfFile); +    DwoOut = GetOutputStream(SplitDwarfFile, sys::fs::OF_None);      if (!DwoOut)        return 1;    } @@ -459,7 +463,7 @@ int main(int argc, char **argv) {      std::unique_ptr<MCAsmBackend> MAB(          TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions)); -    auto FOut = llvm::make_unique<formatted_raw_ostream>(*OS); +    auto FOut = std::make_unique<formatted_raw_ostream>(*OS);      Str.reset(          TheTarget->createAsmStreamer(Ctx, std::move(FOut), /*asmverbose*/ true,                                       /*useDwarfDirectory*/ true, IP, @@ -474,7 +478,7 @@ int main(int argc, char **argv) {      Ctx.setUseNamesOnTempLabels(false);      if (!Out->os().supportsSeeking()) { -      BOS = make_unique<buffer_ostream>(Out->os()); +      BOS = std::make_unique<buffer_ostream>(Out->os());        OS = BOS.get();      } @@ -506,7 +510,7 @@ int main(int argc, char **argv) {      break;    case AC_MDisassemble:      assert(IP && "Expected assembly output"); -    IP->setUseMarkup(1); +    IP->setUseMarkup(true);      disassemble = true;      break;    case AC_Disassemble: @@ -514,8 +518,8 @@ int main(int argc, char **argv) {      break;    }    if (disassemble) -    Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, -                                    *Buffer, SrcMgr, Out->os()); +    Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, *Buffer, +                                    SrcMgr, Ctx, Out->os(), MCOptions);    // Keep output if no errors.    if (Res == 0) { diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp index bf592f67245e..e05517c1ac95 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp @@ -18,7 +18,7 @@ namespace mca {  CodeRegions::CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {    // Create a default region for the input code sequence. -  Regions.emplace_back(make_unique<CodeRegion>("", SMLoc())); +  Regions.emplace_back(std::make_unique<CodeRegion>("", SMLoc()));  }  bool CodeRegion::isLocInRange(SMLoc Loc) const { @@ -36,7 +36,7 @@ void CodeRegions::beginRegion(StringRef Description, SMLoc Loc) {      if (Regions.size() == 1 && !Regions[0]->startLoc().isValid() &&          !Regions[0]->endLoc().isValid()) {        ActiveRegions[Description] = 0; -      Regions[0] = make_unique<CodeRegion>(Description, Loc); +      Regions[0] = std::make_unique<CodeRegion>(Description, Loc);        return;      }    } else { @@ -62,7 +62,7 @@ void CodeRegions::beginRegion(StringRef Description, SMLoc Loc) {    }    ActiveRegions[Description] = Regions.size(); -  Regions.emplace_back(make_unique<CodeRegion>(Description, Loc)); +  Regions.emplace_back(std::make_unique<CodeRegion>(Description, Loc));    return;  } diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp index c793169e64e0..8ddcd2f4abe2 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp @@ -118,6 +118,8 @@ Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions() {    MCAsmLexer &Lexer = Parser->getLexer();    MCACommentConsumer CC(Regions);    Lexer.setCommentConsumer(&CC); +  // Enable support for MASM literal numbers (example: 05h, 101b). +  Lexer.setLexMasmIntegers(true);    std::unique_ptr<MCTargetAsmParser> TAP(        TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts)); 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 560c6c6e8a33..99deed6eae97 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp @@ -165,10 +165,33 @@ void DependencyGraph::dumpDependencyEdge(raw_ostream &OS,             "Unsupported dependency type!");      OS << " - RESOURCE MASK: " << DE.ResourceOrRegID;    } -  OS << " - CYCLES: " << DE.Cost << '\n'; +  OS << " - COST: " << DE.Cost << '\n';  }  #endif // NDEBUG +void DependencyGraph::pruneEdges(unsigned Iterations) { +  for (DGNode &N : Nodes) { +    unsigned NumPruned = 0; +    const unsigned Size = N.OutgoingEdges.size(); +    // Use a cut-off threshold to prune edges with a low frequency. +    for (unsigned I = 0, E = Size; I < E; ++I) { +      DependencyEdge &Edge = N.OutgoingEdges[I]; +      if (Edge.Frequency == Iterations) +        continue; +      double Factor = (double)Edge.Frequency / Iterations; +      if (0.10 < Factor) +        continue; +      Nodes[Edge.ToIID].NumPredecessors--; +      std::swap(Edge, N.OutgoingEdges[E - 1]); +      --E; +      ++NumPruned; +    } + +    if (NumPruned) +      N.OutgoingEdges.resize(Size - NumPruned); +  } +} +  void DependencyGraph::initializeRootSet(      SmallVectorImpl<unsigned> &RootSet) const {    for (unsigned I = 0, E = Nodes.size(); I < E; ++I) { @@ -179,7 +202,7 @@ void DependencyGraph::initializeRootSet(  }  void DependencyGraph::propagateThroughEdges( -    SmallVectorImpl<unsigned> &RootSet) { +    SmallVectorImpl<unsigned> &RootSet, unsigned Iterations) {    SmallVector<unsigned, 8> ToVisit;    // A critical sequence is computed as the longest path from a node of the @@ -189,6 +212,10 @@ void DependencyGraph::propagateThroughEdges(    // Each node of the graph starts with an initial default cost of zero.  The    // cost of a node is a measure of criticality: the higher the cost, the bigger    // is the performance impact. +  // For register and memory dependencies, the cost is a function of the write +  // latency as well as the actual delay (in cycles) caused to users. +  // For processor resource dependencies, the cost is a function of the resource +  // pressure. Resource interferences with low frequency values are ignored.    //    // This algorithm is very similar to a (reverse) Dijkstra.  Every iteration of    // the inner loop selects (i.e. visits) a node N from a set of `unvisited @@ -266,7 +293,7 @@ static void printInstruction(formatted_raw_ostream &FOS,    FOS.PadToColumn(14); -  MCIP.printInst(&MCI, InstrStream, "", STI); +  MCIP.printInst(&MCI, 0, "", STI, InstrStream);    InstrStream.flush();    if (UseDifferentColor) @@ -277,6 +304,10 @@ static void printInstruction(formatted_raw_ostream &FOS,  }  void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const { +  // Early exit if no bottlenecks were found during the simulation. +  if (!SeenStallCycles || !BPI.PressureIncreaseCycles) +    return; +    SmallVector<const DependencyEdge *, 16> Seq;    DG.getCriticalSequence(Seq);    if (Seq.empty()) @@ -432,7 +463,6 @@ void BottleneckAnalysis::addRegisterDep(unsigned From, unsigned To,    bool IsLoopCarried = From >= To;    unsigned SourceSize = Source.size();    if (IsLoopCarried) { -    Cost *= Iterations / 2;      DG.addRegisterDep(From, To + SourceSize, RegID, Cost);      DG.addRegisterDep(From + SourceSize, To + (SourceSize * 2), RegID, Cost);      return; @@ -445,7 +475,6 @@ void BottleneckAnalysis::addMemoryDep(unsigned From, unsigned To,    bool IsLoopCarried = From >= To;    unsigned SourceSize = Source.size();    if (IsLoopCarried) { -    Cost *= Iterations / 2;      DG.addMemoryDep(From, To + SourceSize, Cost);      DG.addMemoryDep(From + SourceSize, To + (SourceSize * 2), Cost);      return; @@ -458,7 +487,6 @@ void BottleneckAnalysis::addResourceDep(unsigned From, unsigned To,    bool IsLoopCarried = From >= To;    unsigned SourceSize = Source.size();    if (IsLoopCarried) { -    Cost *= Iterations / 2;      DG.addResourceDep(From, To + SourceSize, Mask, Cost);      DG.addResourceDep(From + SourceSize, To + (SourceSize * 2), Mask, Cost);      return; @@ -514,7 +542,7 @@ void BottleneckAnalysis::onEvent(const HWInstructionEvent &Event) {    // Check if this is the last simulated instruction.    if (IID == ((Iterations * Source.size()) - 1)) -    DG.finalizeGraph(); +    DG.finalizeGraph(Iterations);  }  void BottleneckAnalysis::onEvent(const HWPressureEvent &Event) { 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 7564b1a48206..9e3bd5978f09 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h @@ -236,8 +236,9 @@ class DependencyGraph {    void addDependency(unsigned From, unsigned To,                       DependencyEdge::Dependency &&DE); +  void pruneEdges(unsigned Iterations);    void initializeRootSet(SmallVectorImpl<unsigned> &RootSet) const; -  void propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet); +  void propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet, unsigned Iterations);  #ifndef NDEBUG    void dumpDependencyEdge(raw_ostream &OS, const DependencyEdge &DE, @@ -263,10 +264,11 @@ public:    // Called by the bottleneck analysis at the end of simulation to propagate    // costs through the edges of the graph, and compute a critical path. -  void finalizeGraph() { +  void finalizeGraph(unsigned Iterations) {      SmallVector<unsigned, 16> RootSet; +    pruneEdges(Iterations);      initializeRootSet(RootSet); -    propagateThroughEdges(RootSet); +    propagateThroughEdges(RootSet, Iterations);    }    // Returns a sequence of edges representing the critical sequence based on the diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp index 557b8ba17b17..a1c0cf208d35 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp @@ -37,7 +37,8 @@ void DispatchStatistics::printDispatchHistogram(raw_ostream &OS) const {    TempStream << "\n\nDispatch Logic - "               << "number of cycles where we saw N micro opcodes dispatched:\n";    TempStream << "[# dispatched], [# cycles]\n"; -  for (const std::pair<unsigned, unsigned> &Entry : DispatchGroupSizePerCycle) { +  for (const std::pair<const unsigned, unsigned> &Entry : +       DispatchGroupSizePerCycle) {      double Percentage = ((double)Entry.second / NumCycles) * 100.0;      TempStream << " " << Entry.first << ",              " << Entry.second                 << "  (" << format("%.1f", floor((Percentage * 10) + 0.5) / 10) diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp index 1fbffa3e5b69..fbe9d9021554 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp @@ -12,6 +12,7 @@  //===----------------------------------------------------------------------===//  #include "Views/InstructionInfoView.h" +#include "llvm/Support/FormattedStream.h"  namespace llvm {  namespace mca { @@ -26,10 +27,17 @@ void InstructionInfoView::printView(raw_ostream &OS) const {    TempStream << "\n\nInstruction Info:\n";    TempStream << "[1]: #uOps\n[2]: Latency\n[3]: RThroughput\n" -             << "[4]: MayLoad\n[5]: MayStore\n[6]: HasSideEffects (U)\n\n"; +             << "[4]: MayLoad\n[5]: MayStore\n[6]: HasSideEffects (U)\n"; +  if (PrintEncodings) { +    TempStream << "[7]: Encoding Size\n"; +    TempStream << "\n[1]    [2]    [3]    [4]    [5]    [6]    [7]    " +               << "Encodings:                    Instructions:\n"; +  } else { +    TempStream << "\n[1]    [2]    [3]    [4]    [5]    [6]    Instructions:\n"; +  } -  TempStream << "[1]    [2]    [3]    [4]    [5]    [6]    Instructions:\n"; -  for (const MCInst &Inst : Source) { +  for (unsigned I = 0, E = Source.size(); I < E; ++I) { +    const MCInst &Inst = Source[I];      const MCInstrDesc &MCDesc = MCII.get(Inst.getOpcode());      // Obtain the scheduling class information from the instruction. @@ -72,15 +80,28 @@ void InstructionInfoView::printView(raw_ostream &OS) const {      }      TempStream << (MCDesc.mayLoad() ? " *     " : "       ");      TempStream << (MCDesc.mayStore() ? " *     " : "       "); -    TempStream << (MCDesc.hasUnmodeledSideEffects() ? " U " : "   "); +    TempStream << (MCDesc.hasUnmodeledSideEffects() ? " U     " : "       "); + +    if (PrintEncodings) { +      StringRef Encoding(CE.getEncoding(I)); +      unsigned EncodingSize = Encoding.size(); +      TempStream << " " << EncodingSize +                 << (EncodingSize < 10 ? "     " : "    "); +      TempStream.flush(); +      formatted_raw_ostream FOS(TempStream); +      for (unsigned i = 0, e = Encoding.size(); i != e; ++i) +        FOS << format("%02x ", (uint8_t)Encoding[i]); +      FOS.PadToColumn(30); +      FOS.flush(); +    } -    MCIP.printInst(&Inst, InstrStream, "", STI); +    MCIP.printInst(&Inst, 0, "", STI, InstrStream);      InstrStream.flush();      // Consume any tabs or spaces at the beginning of the string.      StringRef Str(Instruction);      Str = Str.ltrim(); -    TempStream << "    " << Str << '\n'; +    TempStream << Str << '\n';      Instruction = "";    } 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 640d87383436..0e948304119f 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h @@ -40,6 +40,7 @@  #include "llvm/MC/MCInstPrinter.h"  #include "llvm/MC/MCInstrInfo.h"  #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MCA/CodeEmitter.h"  #include "llvm/Support/raw_ostream.h"  #define DEBUG_TYPE "llvm-mca" @@ -51,14 +52,18 @@ namespace mca {  class InstructionInfoView : public View {    const llvm::MCSubtargetInfo &STI;    const llvm::MCInstrInfo &MCII; +  CodeEmitter &CE; +  bool PrintEncodings;    llvm::ArrayRef<llvm::MCInst> Source;    llvm::MCInstPrinter &MCIP;  public: -  InstructionInfoView(const llvm::MCSubtargetInfo &sti, -                      const llvm::MCInstrInfo &mcii, -                      llvm::ArrayRef<llvm::MCInst> S, llvm::MCInstPrinter &IP) -      : STI(sti), MCII(mcii), Source(S), MCIP(IP) {} +  InstructionInfoView(const llvm::MCSubtargetInfo &ST, +                      const llvm::MCInstrInfo &II, CodeEmitter &C, +                      bool ShouldPrintEncodings, llvm::ArrayRef<llvm::MCInst> S, +                      llvm::MCInstPrinter &IP) +      : STI(ST), MCII(II), CE(C), PrintEncodings(ShouldPrintEncodings), +        Source(S), MCIP(IP) {}    void printView(llvm::raw_ostream &OS) const override;  }; 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 38a2478cf4fe..bdb9dc21247b 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp @@ -163,7 +163,7 @@ void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {        printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);      } -    MCIP.printInst(&MCI, InstrStream, "", STI); +    MCIP.printInst(&MCI, 0, "", STI, InstrStream);      InstrStream.flush();      StringRef Str(Instruction); diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp index cb4fbae78039..61c115b27be1 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp @@ -59,7 +59,7 @@ void RetireControlUnitStatistics::printView(raw_ostream &OS) const {               << "number of cycles where we saw N instructions retired:\n";    TempStream << "[# retired], [# cycles]\n"; -  for (const std::pair<unsigned, unsigned> &Entry : RetiredPerCycle) { +  for (const std::pair<const unsigned, unsigned> &Entry : RetiredPerCycle) {      TempStream << " " << Entry.first;      if (Entry.first < 10)        TempStream << ",           "; diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp index bd0ba350ab68..7a341d4c2079 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp @@ -107,7 +107,7 @@ void SchedulerStatistics::printSchedulerStats(raw_ostream &OS) const {    bool HasColors = OS.has_colors();    const auto It =        std::max_element(IssueWidthPerCycle.begin(), IssueWidthPerCycle.end()); -  for (const std::pair<unsigned, unsigned> &Entry : IssueWidthPerCycle) { +  for (const std::pair<const unsigned, unsigned> &Entry : IssueWidthPerCycle) {      unsigned NumIssued = Entry.first;      if (NumIssued == It->first && HasColors)        OS.changeColor(raw_ostream::SAVEDCOLOR, true, false); diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/SummaryView.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/SummaryView.cpp index ef5550048f4c..f0e75f7b13ae 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/SummaryView.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/SummaryView.cpp @@ -54,7 +54,7 @@ void SummaryView::onEvent(const HWInstructionEvent &Event) {    const Instruction &Inst = *Event.IR.getInstruction();    const InstrDesc &Desc = Inst.getDesc();    NumMicroOps += Desc.NumMicroOps; -  for (const std::pair<uint64_t, const ResourceUsage> &RU : Desc.Resources) { +  for (const std::pair<uint64_t, ResourceUsage> &RU : Desc.Resources) {      if (RU.second.size()) {        unsigned ProcResID = ResIdx2ProcResID[getResourceStateIndex(RU.first)];        ProcResourceUsage[ProcResID] += RU.second.size(); diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp b/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp index fe3f16ba344c..cf5b48e811b8 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp @@ -12,6 +12,7 @@  //===----------------------------------------------------------------------===//  #include "Views/TimelineView.h" +#include <numeric>  namespace llvm {  namespace mca { @@ -132,25 +133,38 @@ void TimelineView::printWaitTimeEntry(formatted_raw_ostream &OS,                                        const WaitTimeEntry &Entry,                                        unsigned SourceIndex,                                        unsigned Executions) const { -  OS << SourceIndex << '.'; +  bool PrintingTotals = SourceIndex == Source.size(); +  unsigned CumulativeExecutions = PrintingTotals ? Timeline.size() : Executions; + +  if (!PrintingTotals) +    OS << SourceIndex << '.'; +    OS.PadToColumn(7);    double AverageTime1, AverageTime2, AverageTime3; -  AverageTime1 = (double)Entry.CyclesSpentInSchedulerQueue / Executions; -  AverageTime2 = (double)Entry.CyclesSpentInSQWhileReady / Executions; -  AverageTime3 = (double)Entry.CyclesSpentAfterWBAndBeforeRetire / Executions; +  AverageTime1 = +      (double)Entry.CyclesSpentInSchedulerQueue / CumulativeExecutions; +  AverageTime2 = (double)Entry.CyclesSpentInSQWhileReady / CumulativeExecutions; +  AverageTime3 = +      (double)Entry.CyclesSpentAfterWBAndBeforeRetire / CumulativeExecutions;    OS << Executions;    OS.PadToColumn(13); -  int BufferSize = UsedBuffer[SourceIndex].second; -  tryChangeColor(OS, Entry.CyclesSpentInSchedulerQueue, Executions, BufferSize); + +  int BufferSize = PrintingTotals ? 0 : UsedBuffer[SourceIndex].second; +  if (!PrintingTotals) +    tryChangeColor(OS, Entry.CyclesSpentInSchedulerQueue, CumulativeExecutions, +                   BufferSize);    OS << format("%.1f", floor((AverageTime1 * 10) + 0.5) / 10);    OS.PadToColumn(20); -  tryChangeColor(OS, Entry.CyclesSpentInSQWhileReady, Executions, BufferSize); +  if (!PrintingTotals) +    tryChangeColor(OS, Entry.CyclesSpentInSQWhileReady, CumulativeExecutions, +                   BufferSize);    OS << format("%.1f", floor((AverageTime2 * 10) + 0.5) / 10);    OS.PadToColumn(27); -  tryChangeColor(OS, Entry.CyclesSpentAfterWBAndBeforeRetire, Executions, -                 STI.getSchedModel().MicroOpBufferSize); +  if (!PrintingTotals) +    tryChangeColor(OS, Entry.CyclesSpentAfterWBAndBeforeRetire, +                   CumulativeExecutions, STI.getSchedModel().MicroOpBufferSize);    OS << format("%.1f", floor((AverageTime3 * 10) + 0.5) / 10);    if (OS.has_colors()) @@ -178,7 +192,7 @@ void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {    for (const MCInst &Inst : Source) {      printWaitTimeEntry(FOS, WaitTime[IID], IID, Executions);      // Append the instruction info at the end of the line. -    MCIP.printInst(&Inst, InstrStream, "", STI); +    MCIP.printInst(&Inst, 0, "", STI, InstrStream);      InstrStream.flush();      // Consume any tabs or spaces at the beginning of the string. @@ -190,6 +204,24 @@ void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {      ++IID;    } + +  // If the timeline contains more than one instruction, +  // let's also print global averages. +  if (Source.size() != 1) { +    WaitTimeEntry TotalWaitTime = std::accumulate( +        WaitTime.begin(), WaitTime.end(), WaitTimeEntry{0, 0, 0}, +        [](const WaitTimeEntry &A, const WaitTimeEntry &B) { +          return WaitTimeEntry{ +              A.CyclesSpentInSchedulerQueue + B.CyclesSpentInSchedulerQueue, +              A.CyclesSpentInSQWhileReady + B.CyclesSpentInSQWhileReady, +              A.CyclesSpentAfterWBAndBeforeRetire + +                  B.CyclesSpentAfterWBAndBeforeRetire}; +        }); +    printWaitTimeEntry(FOS, TotalWaitTime, IID, Executions); +    FOS << "   " +        << "<total>" << '\n'; +    InstrStream.flush(); +  }  }  void TimelineView::printTimelineViewEntry(formatted_raw_ostream &OS, @@ -275,7 +307,7 @@ void TimelineView::printTimeline(raw_ostream &OS) const {        unsigned SourceIndex = IID % Source.size();        printTimelineViewEntry(FOS, Entry, Iteration, SourceIndex);        // Append the instruction info at the end of the line. -      MCIP.printInst(&Inst, InstrStream, "", STI); +      MCIP.printInst(&Inst, 0, "", STI, InstrStream);        InstrStream.flush();        // Consume any tabs or spaces at the beginning of the string. diff --git a/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.h b/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.h index b63b234293cd..9bec3b87db45 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.h +++ b/contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.h @@ -84,6 +84,7 @@  /// 3.	 2	1.5	0.5	1.0	vaddss  %xmm1, %xmm0, %xmm3  /// 4.	 2	3.5	0.0	0.0	vaddss  %xmm3, %xmm2, %xmm4  /// 5.	 2	6.5	0.0	0.0	vaddss  %xmm4, %xmm5, %xmm6 +///      2	2.4	0.6	1.6     <total>  ///  /// By comparing column [2] with column [1], we get an idea about how many  /// cycles were spent in the scheduler's queue due to data dependencies. 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 b3590b5910ec..fff5906bb59b 100644 --- a/contrib/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp @@ -32,11 +32,17 @@  #include "Views/SchedulerStatistics.h"  #include "Views/SummaryView.h"  #include "Views/TimelineView.h" +#include "llvm/MC/MCAsmBackend.h"  #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h"  #include "llvm/MC/MCContext.h"  #include "llvm/MC/MCObjectFileInfo.h"  #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptionsCommandFlags.inc" +#include "llvm/MCA/CodeEmitter.h"  #include "llvm/MCA/Context.h" +#include "llvm/MCA/InstrBuilder.h"  #include "llvm/MCA/Pipeline.h"  #include "llvm/MCA/Stages/EntryStage.h"  #include "llvm/MCA/Stages/InstructionTables.h" @@ -83,11 +89,20 @@ static cl::opt<std::string>           cl::desc("Target a specific cpu type (-mcpu=help for details)"),           cl::value_desc("cpu-name"), cl::cat(ToolOptions), cl::init("native")); +static cl::opt<std::string> +    MATTR("mattr", +          cl::desc("Additional target features."), +          cl::cat(ToolOptions)); +  static cl::opt<int>      OutputAsmVariant("output-asm-variant",                       cl::desc("Syntax variant to use for output printing"),                       cl::cat(ToolOptions), cl::init(-1)); +static cl::opt<bool> +    PrintImmHex("print-imm-hex", cl::cat(ToolOptions), cl::init(false), +                cl::desc("Prefer hex format when printing immediate values")); +  static cl::opt<unsigned> Iterations("iterations",                                      cl::desc("Number of iterations to run"),                                      cl::cat(ToolOptions), cl::init(0)); @@ -193,6 +208,11 @@ static cl::opt<bool> EnableBottleneckAnalysis(      cl::desc("Enable bottleneck analysis (disabled by default)"),      cl::cat(ViewOptions), cl::init(false)); +static cl::opt<bool> ShowEncoding( +    "show-encoding", +    cl::desc("Print encoding information in the instruction info view"), +    cl::cat(ViewOptions), cl::init(false)); +  namespace {  const Target *getTarget(const char *ProgName) { @@ -218,7 +238,7 @@ ErrorOr<std::unique_ptr<ToolOutputFile>> getOutputStream() {      OutputFilename = "-";    std::error_code EC;    auto Out = -      llvm::make_unique<ToolOutputFile>(OutputFilename, EC, sys::fs::F_None); +      std::make_unique<ToolOutputFile>(OutputFilename, EC, sys::fs::OF_Text);    if (!EC)      return std::move(Out);    return EC; @@ -303,33 +323,11 @@ int main(int argc, char **argv) {    // Apply overrides to llvm-mca specific options.    processViewOptions(); -  SourceMgr SrcMgr; - -  // Tell SrcMgr about this buffer, which is what the parser will pick up. -  SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc()); - -  std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); -  assert(MRI && "Unable to create target register info!"); - -  std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); -  assert(MAI && "Unable to create target asm info!"); - -  MCObjectFileInfo MOFI; -  MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr); -  MOFI.InitMCObjectFileInfo(TheTriple, /* PIC= */ false, Ctx); - -  std::unique_ptr<buffer_ostream> BOS; - -  std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); - -  std::unique_ptr<MCInstrAnalysis> MCIA( -      TheTarget->createMCInstrAnalysis(MCII.get())); -    if (!MCPU.compare("native"))      MCPU = llvm::sys::getHostCPUName();    std::unique_ptr<MCSubtargetInfo> STI( -      TheTarget->createMCSubtargetInfo(TripleName, MCPU, /* FeaturesStr */ "")); +      TheTarget->createMCSubtargetInfo(TripleName, MCPU, MATTR));    if (!STI->isCPUStringValid(MCPU))      return 1; @@ -352,6 +350,31 @@ int main(int argc, char **argv) {      return 1;    } +  std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); +  assert(MRI && "Unable to create target register info!"); + +  MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); +  std::unique_ptr<MCAsmInfo> MAI( +      TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); +  assert(MAI && "Unable to create target asm info!"); + +  MCObjectFileInfo MOFI; +  SourceMgr SrcMgr; + +  // Tell SrcMgr about this buffer, which is what the parser will pick up. +  SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc()); + +  MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr); + +  MOFI.InitMCObjectFileInfo(TheTriple, /* PIC= */ false, Ctx); + +  std::unique_ptr<buffer_ostream> BOS; + +  std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); + +  std::unique_ptr<MCInstrAnalysis> MCIA( +      TheTarget->createMCInstrAnalysis(MCII.get())); +    // Parse the input and create CodeRegions that llvm-mca can analyze.    mca::AsmCodeRegionGenerator CRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI, *MCII);    Expected<const mca::CodeRegions &> RegionsOrErr = CRG.parseCodeRegions(); @@ -396,6 +419,9 @@ int main(int argc, char **argv) {      return 1;    } +  // Set the display preference for hex vs. decimal immediates. +  IP->setPrintImmHex(PrintImmHex); +    std::unique_ptr<ToolOutputFile> TOF = std::move(*OF);    const MCSchedModel &SM = STI->getSchedModel(); @@ -413,6 +439,12 @@ int main(int argc, char **argv) {    // Number each region in the sequence.    unsigned RegionIdx = 0; +  std::unique_ptr<MCCodeEmitter> MCE( +      TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx)); + +  std::unique_ptr<MCAsmBackend> MAB(TheTarget->createMCAsmBackend( +      *STI, *MRI, InitMCTargetOptionsFromFlags())); +    for (const std::unique_ptr<mca::CodeRegion> &Region : Regions) {      // Skip empty code regions.      if (Region->empty()) @@ -430,6 +462,7 @@ int main(int argc, char **argv) {      // Lower the MCInst sequence into an mca::Instruction sequence.      ArrayRef<MCInst> Insts = Region->getInstructions(); +    mca::CodeEmitter CE(*STI, *MAB, *MCE, Insts);      std::vector<std::unique_ptr<mca::Instruction>> LoweredSequence;      for (const MCInst &MCI : Insts) {        Expected<std::unique_ptr<mca::Instruction>> Inst = @@ -441,7 +474,7 @@ int main(int argc, char **argv) {                    std::string InstructionStr;                    raw_string_ostream SS(InstructionStr);                    WithColor::error() << IE.Message << '\n'; -                  IP->printInst(&IE.Inst, SS, "", *STI); +                  IP->printInst(&IE.Inst, 0, "", *STI, SS);                    SS.flush();                    WithColor::note()                        << "instruction: " << InstructionStr << '\n'; @@ -459,18 +492,18 @@ int main(int argc, char **argv) {      if (PrintInstructionTables) {        //  Create a pipeline, stages, and a printer. -      auto P = llvm::make_unique<mca::Pipeline>(); -      P->appendStage(llvm::make_unique<mca::EntryStage>(S)); -      P->appendStage(llvm::make_unique<mca::InstructionTables>(SM)); +      auto P = std::make_unique<mca::Pipeline>(); +      P->appendStage(std::make_unique<mca::EntryStage>(S)); +      P->appendStage(std::make_unique<mca::InstructionTables>(SM));        mca::PipelinePrinter Printer(*P);        // Create the views for this pipeline, execute, and emit a report.        if (PrintInstructionInfoView) { -        Printer.addView(llvm::make_unique<mca::InstructionInfoView>( -            *STI, *MCII, Insts, *IP)); +        Printer.addView(std::make_unique<mca::InstructionInfoView>( +            *STI, *MCII, CE, ShowEncoding, Insts, *IP));        }        Printer.addView( -          llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts)); +          std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));        if (!runPipeline(*P))          return 1; @@ -480,42 +513,42 @@ int main(int argc, char **argv) {      }      // Create a basic pipeline simulating an out-of-order backend. -    auto P = MCA.createDefaultPipeline(PO, IB, S); +    auto P = MCA.createDefaultPipeline(PO, S);      mca::PipelinePrinter Printer(*P);      if (PrintSummaryView)        Printer.addView( -          llvm::make_unique<mca::SummaryView>(SM, Insts, DispatchWidth)); +          std::make_unique<mca::SummaryView>(SM, Insts, DispatchWidth));      if (EnableBottleneckAnalysis) { -      Printer.addView(llvm::make_unique<mca::BottleneckAnalysis>( +      Printer.addView(std::make_unique<mca::BottleneckAnalysis>(            *STI, *IP, Insts, S.getNumIterations()));      }      if (PrintInstructionInfoView) -      Printer.addView( -          llvm::make_unique<mca::InstructionInfoView>(*STI, *MCII, Insts, *IP)); +      Printer.addView(std::make_unique<mca::InstructionInfoView>( +          *STI, *MCII, CE, ShowEncoding, Insts, *IP));      if (PrintDispatchStats) -      Printer.addView(llvm::make_unique<mca::DispatchStatistics>()); +      Printer.addView(std::make_unique<mca::DispatchStatistics>());      if (PrintSchedulerStats) -      Printer.addView(llvm::make_unique<mca::SchedulerStatistics>(*STI)); +      Printer.addView(std::make_unique<mca::SchedulerStatistics>(*STI));      if (PrintRetireStats) -      Printer.addView(llvm::make_unique<mca::RetireControlUnitStatistics>(SM)); +      Printer.addView(std::make_unique<mca::RetireControlUnitStatistics>(SM));      if (PrintRegisterFileStats) -      Printer.addView(llvm::make_unique<mca::RegisterFileStatistics>(*STI)); +      Printer.addView(std::make_unique<mca::RegisterFileStatistics>(*STI));      if (PrintResourcePressureView)        Printer.addView( -          llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts)); +          std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));      if (PrintTimelineView) {        unsigned TimelineIterations =            TimelineMaxIterations ? TimelineMaxIterations : 10; -      Printer.addView(llvm::make_unique<mca::TimelineView>( +      Printer.addView(std::make_unique<mca::TimelineView>(            *STI, *IP, Insts, std::min(TimelineIterations, S.getNumIterations()),            TimelineMaxCycles));      } diff --git a/contrib/llvm-project/llvm/tools/llvm-modextract/llvm-modextract.cpp b/contrib/llvm-project/llvm/tools/llvm-modextract/llvm-modextract.cpp index 3adefc5f0d3e..7c4099625842 100644 --- a/contrib/llvm-project/llvm/tools/llvm-modextract/llvm-modextract.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-modextract/llvm-modextract.cpp @@ -54,7 +54,7 @@ int main(int argc, char **argv) {    std::error_code EC;    std::unique_ptr<ToolOutputFile> Out( -      new ToolOutputFile(OutputFilename, EC, sys::fs::F_None)); +      new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None));    ExitOnErr(errorCodeToError(EC));    if (BinaryExtract) { 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 aa62e6f0209b..107d62b1f2b9 100644 --- a/contrib/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp @@ -711,17 +711,21 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,                                     const std::string &ArchiveName,                                     const std::string &ArchitectureName) {    if (!NoSort) { -    std::function<bool(const NMSymbol &, const NMSymbol &)> Cmp; +    using Comparator = bool (*)(const NMSymbol &, const NMSymbol &); +    Comparator Cmp;      if (NumericSort) -      Cmp = compareSymbolAddress; +      Cmp = &compareSymbolAddress;      else if (SizeSort) -      Cmp = compareSymbolSize; +      Cmp = &compareSymbolSize;      else -      Cmp = compareSymbolName; +      Cmp = &compareSymbolName;      if (ReverseSort) -      Cmp = [=](const NMSymbol &A, const NMSymbol &B) { return Cmp(B, A); }; -    llvm::sort(SymbolList, Cmp); +      llvm::sort(SymbolList, [=](const NMSymbol &A, const NMSymbol &B) -> bool { +        return Cmp(B, A); +      }); +    else +      llvm::sort(SymbolList, Cmp);    }    if (!PrintFileName) { @@ -913,10 +917,12 @@ static char getSymbolNMTypeChar(ELFObjectFileBase &Obj,      if (Flags & ELF::SHF_ALLOC)        return Flags & ELF::SHF_WRITE ? 'd' : 'r'; -    StringRef SecName; -    if (SecI->getName(SecName)) +    auto NameOrErr = SecI->getName(); +    if (!NameOrErr) { +      consumeError(NameOrErr.takeError());        return '?'; -    if (SecName.startswith(".debug")) +    } +    if ((*NameOrErr).startswith(".debug"))        return 'N';      if (!(Flags & ELF::SHF_WRITE))        return 'n'; @@ -1076,7 +1082,7 @@ static StringRef getNMTypeName(SymbolicFile &Obj, basic_symbol_iterator I) {  static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I,                                     StringRef &SecName) {    uint32_t Symflags = I->getFlags(); -  if (isa<ELFObjectFileBase>(&Obj)) { +  if (ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) {      if (Symflags & object::SymbolRef::SF_Absolute)        SecName = "*ABS*";      else if (Symflags & object::SymbolRef::SF_Common) @@ -1090,8 +1096,16 @@ static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I,          consumeError(SecIOrErr.takeError());          return '?';        } -      elf_section_iterator secT = *SecIOrErr; -      secT->getName(SecName); + +      if (*SecIOrErr == ELFObj->section_end()) +        return '?'; + +      Expected<StringRef> NameOrErr = (*SecIOrErr)->getName(); +      if (!NameOrErr) { +        consumeError(NameOrErr.takeError()); +        return '?'; +      } +      SecName = *NameOrErr;      }    } @@ -1119,15 +1133,18 @@ static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I,      Ret = getSymbolNMTypeChar(*MachO, I);    else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj))      Ret = getSymbolNMTypeChar(*Wasm, I); -  else -    Ret = getSymbolNMTypeChar(cast<ELFObjectFileBase>(Obj), I); +  else if (ELFObjectFileBase *ELF = dyn_cast<ELFObjectFileBase>(&Obj)) { +    if (ELFSymbolRef(*I).getELFType() == ELF::STT_GNU_IFUNC) +      return 'i'; +    Ret = getSymbolNMTypeChar(*ELF, I); +    if (ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE) +      return Ret; +  } else +    llvm_unreachable("unknown binary format");    if (!(Symflags & object::SymbolRef::SF_Global))      return Ret; -  if (Obj.isELF() && ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE) -    return Ret; -    return toupper(Ret);  } @@ -1347,7 +1364,12 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,              StringRef SectionName = StringRef();              for (const SectionRef &Section : MachO->sections()) {                S.NSect++; -              Section.getName(SectionName); +  +              if (Expected<StringRef> NameOrErr = Section.getName()) +                SectionName = *NameOrErr; +              else +                consumeError(NameOrErr.takeError()); +                SegmentName = MachO->getSectionFinalSegmentName(                                                    Section.getRawDataRefImpl());                if (S.Address >= Section.getAddress() && @@ -1667,7 +1689,11 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,            StringRef SegmentName = StringRef();            StringRef SectionName = StringRef();            for (const SectionRef &Section : MachO->sections()) { -            Section.getName(SectionName); +            if (Expected<StringRef> NameOrErr = Section.getName()) +              SectionName = *NameOrErr; +            else +              consumeError(NameOrErr.takeError()); +              SegmentName = MachO->getSectionFinalSegmentName(                                                  Section.getRawDataRefImpl());              F.NSect++; diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp index 4ae46851a66f..b172fae527eb 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -16,8 +16,8 @@  #include "llvm/Object/Binary.h"  #include "llvm/Object/COFF.h" +#include "llvm/Support/CRC.h"  #include "llvm/Support/Errc.h" -#include "llvm/Support/JamCRC.h"  #include "llvm/Support/Path.h"  #include <cassert> @@ -40,22 +40,13 @@ static uint64_t getNextRVA(const Object &Obj) {                   Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1);  } -static uint32_t getCRC32(StringRef Data) { -  JamCRC CRC; -  CRC.update(ArrayRef<char>(Data.data(), Data.size())); -  // The CRC32 value needs to be complemented because the JamCRC dosn't -  // finalize the CRC32 value. It also dosn't negate the initial CRC32 value -  // but it starts by default at 0xFFFFFFFF which is the complement of zero. -  return ~CRC.getCRC(); -} -  static std::vector<uint8_t> createGnuDebugLinkSectionContents(StringRef File) {    ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =        MemoryBuffer::getFile(File);    if (!LinkTargetOrErr)      error("'" + File + "': " + LinkTargetOrErr.getError().message());    auto LinkTarget = std::move(*LinkTargetOrErr); -  uint32_t CRC32 = getCRC32(LinkTarget->getBuffer()); +  uint32_t CRC32 = llvm::crc32(arrayRefFromStringRef(LinkTarget->getBuffer()));    StringRef FileName = sys::path::filename(File);    size_t CRCPos = alignTo(FileName.size() + 1, 4); @@ -65,26 +56,37 @@ static std::vector<uint8_t> createGnuDebugLinkSectionContents(StringRef File) {    return Data;  } -static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) { -  uint32_t StartRVA = getNextRVA(Obj); +// Adds named section with given contents to the object. +static void addSection(Object &Obj, StringRef Name, ArrayRef<uint8_t> Contents, +                       uint32_t Characteristics) { +  bool NeedVA = Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | +                                   IMAGE_SCN_MEM_WRITE); -  std::vector<Section> Sections;    Section Sec; -  Sec.setOwnedContents(createGnuDebugLinkSectionContents(DebugLinkFile)); -  Sec.Name = ".gnu_debuglink"; -  Sec.Header.VirtualSize = Sec.getContents().size(); -  Sec.Header.VirtualAddress = StartRVA; -  Sec.Header.SizeOfRawData = alignTo(Sec.Header.VirtualSize, -                                     Obj.IsPE ? Obj.PeHeader.FileAlignment : 1); +  Sec.setOwnedContents(Contents); +  Sec.Name = Name; +  Sec.Header.VirtualSize = NeedVA ? Sec.getContents().size() : 0u; +  Sec.Header.VirtualAddress = NeedVA ? getNextRVA(Obj) : 0u; +  Sec.Header.SizeOfRawData = +      NeedVA ? alignTo(Sec.Header.VirtualSize, +                       Obj.IsPE ? Obj.PeHeader.FileAlignment : 1) +             : Sec.getContents().size();    // Sec.Header.PointerToRawData is filled in by the writer.    Sec.Header.PointerToRelocations = 0;    Sec.Header.PointerToLinenumbers = 0;    // Sec.Header.NumberOfRelocations is filled in by the writer.    Sec.Header.NumberOfLinenumbers = 0; -  Sec.Header.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | -                               IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE; -  Sections.push_back(Sec); -  Obj.addSections(Sections); +  Sec.Header.Characteristics = Characteristics; + +  Obj.addSections(Sec); +} + +static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) { +  std::vector<uint8_t> Contents = +      createGnuDebugLinkSectionContents(DebugLinkFile); +  addSection(Obj, ".gnu_debuglink", Contents, +             IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | +                 IMAGE_SCN_MEM_DISCARDABLE);  }  static Error handleArgs(const CopyConfig &Config, Object &Obj) { @@ -92,8 +94,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {    Obj.removeSections([&Config](const Section &Sec) {      // Contrary to --only-keep-debug, --only-section fully removes sections that      // aren't mentioned. -    if (!Config.OnlySection.empty() && -        !is_contained(Config.OnlySection, Sec.Name)) +    if (!Config.OnlySection.empty() && !Config.OnlySection.matches(Sec.Name))        return true;      if (Config.StripDebug || Config.StripAll || Config.StripAllGNU || @@ -103,7 +104,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {          return true;      } -    if (is_contained(Config.ToRemove, Sec.Name)) +    if (Config.ToRemove.matches(Sec.Name))        return true;      return false; @@ -130,6 +131,12 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {      if (Error E = Obj.markSymbols())        return E; +  for (Symbol &Sym : Obj.getMutableSymbols()) { +    auto I = Config.SymbolsToRename.find(Sym.Name); +    if (I != Config.SymbolsToRename.end()) +      Sym.Name = I->getValue(); +  } +    // Actually do removals of symbols.    Obj.removeSymbols([&](const Symbol &Sym) {      // For StripAll, all relocations have been stripped and we remove all @@ -137,7 +144,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {      if (Config.StripAll || Config.StripAllGNU)        return true; -    if (is_contained(Config.SymbolsToRemove, Sym.Name)) { +    if (Config.SymbolsToRemove.matches(Sym.Name)) {        // Explicitly removing a referenced symbol is an error.        if (Sym.Referenced)          reportError(Config.OutputFilename, @@ -156,7 +163,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {        if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||            Sym.Sym.SectionNumber == 0)          if (Config.StripUnneeded || -            is_contained(Config.UnneededSymbolsToRemove, Sym.Name)) +            Config.UnneededSymbolsToRemove.matches(Sym.Name))            return true;        // GNU objcopy keeps referenced local symbols and external symbols @@ -171,18 +178,34 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {      return false;    }); +  for (const auto &Flag : Config.AddSection) { +    StringRef SecName, FileName; +    std::tie(SecName, FileName) = Flag.split("="); + +    auto BufOrErr = MemoryBuffer::getFile(FileName); +    if (!BufOrErr) +      return createFileError(FileName, errorCodeToError(BufOrErr.getError())); +    auto Buf = std::move(*BufOrErr); + +    addSection( +        Obj, SecName, +        makeArrayRef(reinterpret_cast<const uint8_t *>(Buf->getBufferStart()), +                     Buf->getBufferSize()), +        IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES); +  } +    if (!Config.AddGnuDebugLink.empty())      addGnuDebugLink(Obj, Config.AddGnuDebugLink);    if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||        Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||        !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() || -      !Config.AllocSectionsPrefix.empty() || !Config.AddSection.empty() || -      !Config.DumpSection.empty() || !Config.KeepSection.empty() || +      !Config.AllocSectionsPrefix.empty() || !Config.DumpSection.empty() || +      !Config.KeepSection.empty() || Config.NewSymbolVisibility ||        !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||        !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||        !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || -      !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty() || +      !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() ||        Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden ||        Config.PreserveDates || Config.StripDWO || Config.StripNonAlloc ||        Config.StripSections || Config.Weaken || Config.DecompressDebugSections || diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Object.h b/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Object.h index 21475b068629..78f8da00b8cd 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Object.h +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Object.h @@ -25,11 +25,11 @@ namespace objcopy {  namespace coff {  struct Relocation { -  Relocation() {} +  Relocation() = default;    Relocation(const object::coff_relocation& R) : Reloc(R) {}    object::coff_relocation Reloc; -  size_t Target; +  size_t Target = 0;    StringRef TargetName; // Used for diagnostics only  }; @@ -124,7 +124,7 @@ struct Object {    ArrayRef<Section> getSections() const { return Sections; }    // This allows mutating individual Sections, but not mutating the list -  // of symbols itself. +  // of sections itself.    iterator_range<std::vector<Section>::iterator> getMutableSections() {      return make_range(Sections.begin(), Sections.end());    } diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Reader.cpp index 1f0ec9fa9691..7be9cce2be3d 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Reader.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Reader.cpp @@ -36,14 +36,9 @@ Error COFFReader::readExecutableHeaders(Object &Obj) const {                                      DH->AddressOfNewExeHeader - sizeof(*DH));    if (COFFObj.is64()) { -    const pe32plus_header *PE32Plus = nullptr; -    if (auto EC = COFFObj.getPE32PlusHeader(PE32Plus)) -      return errorCodeToError(EC); -    Obj.PeHeader = *PE32Plus; +    Obj.PeHeader = *COFFObj.getPE32PlusHeader();    } else { -    const pe32_header *PE32 = nullptr; -    if (auto EC = COFFObj.getPE32Header(PE32)) -      return errorCodeToError(EC); +    const pe32_header *PE32 = COFFObj.getPE32Header();      copyPeHeader(Obj.PeHeader, *PE32);      // The pe32plus_header (stored in Object) lacks the BaseOfData field.      Obj.BaseOfData = PE32->BaseOfData; @@ -68,6 +63,7 @@ Error COFFReader::readSections(Object &Obj) const {      Sections.push_back(Section());      Section &S = Sections.back();      S.Header = *Sec; +    S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL;      ArrayRef<uint8_t> Contents;      if (Error E = COFFObj.getSectionContents(Sec, Contents))        return E; @@ -79,9 +75,6 @@ Error COFFReader::readSections(Object &Obj) const {        S.Name = *NameOrErr;      else        return NameOrErr.takeError(); -    if (Sec->hasExtendedRelocations()) -      return createStringError(object_error::parse_failed, -                               "extended relocations not supported yet");    }    Obj.addSections(Sections);    return Error::success(); @@ -196,16 +189,13 @@ Error COFFReader::setSymbolTargets(Object &Obj) const {  }  Expected<std::unique_ptr<Object>> COFFReader::create() const { -  auto Obj = llvm::make_unique<Object>(); +  auto Obj = std::make_unique<Object>(); -  const coff_file_header *CFH = nullptr; -  const coff_bigobj_file_header *CBFH = nullptr; -  COFFObj.getCOFFHeader(CFH); -  COFFObj.getCOFFBigObjHeader(CBFH);    bool IsBigObj = false; -  if (CFH) { +  if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) {      Obj->CoffFileHeader = *CFH;    } else { +    const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader();      if (!CBFH)        return createStringError(object_error::parse_failed,                                 "no COFF file header returned"); diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Writer.cpp index f3bb1ce331f2..e35e0474a36d 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Writer.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Writer.cpp @@ -97,9 +97,16 @@ void COFFWriter::layoutSections() {        S.Header.PointerToRawData = FileSize;      FileSize += S.Header.SizeOfRawData; // For executables, this is already                                          // aligned to FileAlignment. -    S.Header.NumberOfRelocations = S.Relocs.size(); -    S.Header.PointerToRelocations = -        S.Header.NumberOfRelocations > 0 ? FileSize : 0; +    if (S.Relocs.size() >= 0xffff) { +      S.Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL; +      S.Header.NumberOfRelocations = 0xffff; +      S.Header.PointerToRelocations = FileSize; +      FileSize += sizeof(coff_relocation); +    } else { +      S.Header.NumberOfRelocations = S.Relocs.size(); +      S.Header.PointerToRelocations = S.Relocs.size() ? FileSize : 0; +    } +      FileSize += S.Relocs.size() * sizeof(coff_relocation);      FileSize = alignTo(FileSize, FileAlignment); @@ -120,12 +127,12 @@ size_t COFFWriter::finalizeStringTable() {    StrTabBuilder.finalize();    for (auto &S : Obj.getMutableSections()) { +    memset(S.Header.Name, 0, sizeof(S.Header.Name));      if (S.Name.size() > COFF::NameSize) { -      memset(S.Header.Name, 0, sizeof(S.Header.Name));        snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d",                 (int)StrTabBuilder.getOffset(S.Name));      } else { -      strncpy(S.Header.Name, S.Name.data(), COFF::NameSize); +      memcpy(S.Header.Name, S.Name.data(), S.Name.size());      }    }    for (auto &S : Obj.getMutableSymbols()) { @@ -307,6 +314,15 @@ void COFFWriter::writeSections() {               S.Header.SizeOfRawData - Contents.size());      Ptr += S.Header.SizeOfRawData; + +    if (S.Relocs.size() >= 0xffff) { +      object::coff_relocation R; +      R.VirtualAddress = S.Relocs.size() + 1; +      R.SymbolTableIndex = 0; +      R.Type = 0; +      memcpy(Ptr, &R, sizeof(R)); +      Ptr += sizeof(R); +    }      for (const auto &R : S.Relocs) {        memcpy(Ptr, &R.Reloc, sizeof(R.Reloc));        Ptr += sizeof(R.Reloc); diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/CommonOpts.td b/contrib/llvm-project/llvm/tools/llvm-objcopy/CommonOpts.td new file mode 100644 index 000000000000..6481d1d1df05 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/CommonOpts.td @@ -0,0 +1,125 @@ +include "llvm/Option/OptParser.td" + +multiclass Eq<string name, string help> { +  def NAME : Separate<["--"], name>; +  def NAME #_eq : Joined<["--"], name #"=">, +                  Alias<!cast<Separate>(NAME)>, +                  HelpText<help>; +} + +def help : Flag<["--"], "help">; +def h : Flag<["-"], "h">, Alias<help>; + +def allow_broken_links +    : Flag<["--"], "allow-broken-links">, +      HelpText<"Allow the tool to remove sections even if it would leave " +               "invalid section references. The appropriate sh_link fields " +               "will be set to zero.">; + +def enable_deterministic_archives +    : Flag<["--"], "enable-deterministic-archives">, +      HelpText<"Enable deterministic mode when operating on archives (use " +               "zero for UIDs, GIDs, and timestamps).">; +def D : Flag<["-"], "D">, +        Alias<enable_deterministic_archives>, +        HelpText<"Alias for --enable-deterministic-archives">; + +def disable_deterministic_archives +    : Flag<["--"], "disable-deterministic-archives">, +      HelpText<"Disable deterministic mode when operating on archives (use " +               "real values for UIDs, GIDs, and timestamps).">; +def U : Flag<["-"], "U">, +        Alias<disable_deterministic_archives>, +        HelpText<"Alias for --disable-deterministic-archives">; + +def preserve_dates : Flag<["--"], "preserve-dates">, +                     HelpText<"Preserve access and modification timestamps">; +def p : Flag<["-"], "p">, +        Alias<preserve_dates>, +        HelpText<"Alias for --preserve-dates">; + +def strip_all : Flag<["--"], "strip-all">, +                HelpText<"Remove non-allocated sections outside segments. " +                         ".gnu.warning* and .ARM.attribute sections are not " +                         "removed">; + +def strip_all_gnu +    : Flag<["--"], "strip-all-gnu">, +      HelpText<"Compatible with GNU's --strip-all">; + +def strip_debug : Flag<["--"], "strip-debug">, +                  HelpText<"Remove all debug sections">; +def g : Flag<["-"], "g">, +        Alias<strip_debug>, +        HelpText<"Alias for --strip-debug">; + +def strip_unneeded : Flag<["--"], "strip-unneeded">, +                     HelpText<"Remove all symbols not needed by relocations">; + +defm remove_section : Eq<"remove-section", "Remove <section>">, +                      MetaVarName<"section">; +def R : JoinedOrSeparate<["-"], "R">, +        Alias<remove_section>, +        HelpText<"Alias for --remove-section">; + +def strip_sections +    : Flag<["--"], "strip-sections">, +      HelpText<"Remove all section headers and all sections not in segments">; + +defm strip_symbol : Eq<"strip-symbol", "Strip <symbol>">, +                    MetaVarName<"symbol">; +def N : JoinedOrSeparate<["-"], "N">, +        Alias<strip_symbol>, +        HelpText<"Alias for --strip-symbol">; + +defm keep_section : Eq<"keep-section", "Keep <section>">, +                    MetaVarName<"section">; + +defm keep_symbol : Eq<"keep-symbol", "Do not remove symbol <symbol>">, +                   MetaVarName<"symbol">; +def K : JoinedOrSeparate<["-"], "K">, +        Alias<keep_symbol>, +        HelpText<"Alias for --keep-symbol">; + +def keep_file_symbols : Flag<["--"], "keep-file-symbols">, +                        HelpText<"Do not remove file symbols">; + +def only_keep_debug +    : Flag<["--"], "only-keep-debug">, +      HelpText< +          "Produce a debug file as the output that only preserves contents of " +          "sections useful for debugging purposes">; + +def discard_locals : Flag<["--"], "discard-locals">, +                     HelpText<"Remove compiler-generated local symbols, (e.g. " +                              "symbols starting with .L)">; +def X : Flag<["-"], "X">, +        Alias<discard_locals>, +        HelpText<"Alias for --discard-locals">; + +def discard_all +    : Flag<["--"], "discard-all">, +      HelpText<"Remove all local symbols except file and section symbols">; +def x : Flag<["-"], "x">, +        Alias<discard_all>, +        HelpText<"Alias for --discard-all">; + +def regex +    : Flag<["--"], "regex">, +      HelpText<"Permit regular expressions in name comparison">; + +def version : Flag<["--"], "version">, +              HelpText<"Print the version and exit.">; +def V : Flag<["-"], "V">, +        Alias<version>, +        HelpText<"Alias for --version">; + +def wildcard +    : Flag<["--"], "wildcard">, +      HelpText<"Allow wildcard syntax for symbol-related flags. Incompatible " +               "with --regex. Allows using '*' to match any number of " +               "characters, '?' to match any single character, '\' to escape " +               "special characters, and '[]' to define character classes. " +               "Wildcards beginning with '!' will prevent a match, for example " +               "\"-N '*' -N '!x'\" will strip all symbols except for \"x\".">; +def w : Flag<["-"], "w">, Alias<wildcard>, HelpText<"Alias for --wildcard">; diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.cpp index 8d6431b3044f..73ed00b5cb2a 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -14,10 +14,10 @@  #include "llvm/ADT/StringSet.h"  #include "llvm/Option/Arg.h"  #include "llvm/Option/ArgList.h" +#include "llvm/Support/CRC.h"  #include "llvm/Support/CommandLine.h"  #include "llvm/Support/Compression.h"  #include "llvm/Support/Errc.h" -#include "llvm/Support/JamCRC.h"  #include "llvm/Support/MemoryBuffer.h"  #include "llvm/Support/StringSaver.h"  #include <memory> @@ -63,6 +63,44 @@ public:    ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {}  }; +enum InstallNameToolID { +  INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \ +               HELPTEXT, METAVAR, VALUES)                                      \ +  INSTALL_NAME_TOOL_##ID, +#include "InstallNameToolOpts.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE)                                                    \ +  const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE; +#include "InstallNameToolOpts.inc" +#undef PREFIX + +static const opt::OptTable::Info InstallNameToolInfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \ +               HELPTEXT, METAVAR, VALUES)                                      \ +  {INSTALL_NAME_TOOL_##PREFIX,                                                 \ +   NAME,                                                                       \ +   HELPTEXT,                                                                   \ +   METAVAR,                                                                    \ +   INSTALL_NAME_TOOL_##ID,                                                     \ +   opt::Option::KIND##Class,                                                   \ +   PARAM,                                                                      \ +   FLAGS,                                                                      \ +   INSTALL_NAME_TOOL_##GROUP,                                                  \ +   INSTALL_NAME_TOOL_##ALIAS,                                                  \ +   ALIASARGS,                                                                  \ +   VALUES}, +#include "InstallNameToolOpts.inc" +#undef OPTION +}; + +class InstallNameToolOptTable : public opt::OptTable { +public: +  InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {} +}; +  enum StripID {    STRIP_INVALID = 0, // This is not an option ID.  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \ @@ -155,6 +193,25 @@ static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {    return SR;  } +static Expected<std::pair<StringRef, uint64_t>> +parseSetSectionAlignment(StringRef FlagValue) { +  if (!FlagValue.contains('=')) +    return createStringError( +        errc::invalid_argument, +        "bad format for --set-section-alignment: missing '='"); +  auto Split = StringRef(FlagValue).split('='); +  if (Split.first.empty()) +    return createStringError( +        errc::invalid_argument, +        "bad format for --set-section-alignment: missing section name"); +  uint64_t NewAlign; +  if (Split.second.getAsInteger(0, NewAlign)) +    return createStringError(errc::invalid_argument, +                             "invalid alignment for --set-section-alignment: '%s'", +                             Split.second.str().c_str()); +  return std::make_pair(Split.first, NewAlign); +} +  static Expected<SectionFlagsUpdate>  parseSetSectionFlagValue(StringRef FlagValue) {    if (!StringRef(FlagValue).contains('=')) @@ -177,106 +234,6 @@ parseSetSectionFlagValue(StringRef FlagValue) {    return SFU;  } -static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) { -  // Parse value given with --add-symbol option and create the -  // new symbol if possible. The value format for --add-symbol is: -  // -  // <name>=[<section>:]<value>[,<flags>] -  // -  // where: -  // <name> - symbol name, can be empty string -  // <section> - optional section name. If not given ABS symbol is created -  // <value> - symbol value, can be decimal or hexadecimal number prefixed -  //           with 0x. -  // <flags> - optional flags affecting symbol type, binding or visibility: -  //           The following are currently supported: -  // -  //           global, local, weak, default, hidden, file, section, object, -  //           indirect-function. -  // -  //           The following flags are ignored and provided for GNU -  //           compatibility only: -  // -  //           warning, debug, constructor, indirect, synthetic, -  //           unique-object, before=<symbol>. -  NewSymbolInfo SI; -  StringRef Value; -  std::tie(SI.SymbolName, Value) = FlagValue.split('='); -  if (Value.empty()) -    return createStringError( -        errc::invalid_argument, -        "bad format for --add-symbol, missing '=' after '%s'", -        SI.SymbolName.str().c_str()); - -  if (Value.contains(':')) { -    std::tie(SI.SectionName, Value) = Value.split(':'); -    if (SI.SectionName.empty() || Value.empty()) -      return createStringError( -          errc::invalid_argument, -          "bad format for --add-symbol, missing section name or symbol value"); -  } - -  SmallVector<StringRef, 6> Flags; -  Value.split(Flags, ','); -  if (Flags[0].getAsInteger(0, SI.Value)) -    return createStringError(errc::invalid_argument, "bad symbol value: '%s'", -                             Flags[0].str().c_str()); - -  using Functor = std::function<void(void)>; -  SmallVector<StringRef, 6> UnsupportedFlags; -  for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) -    static_cast<Functor>( -        StringSwitch<Functor>(Flags[I]) -            .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; }) -            .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; }) -            .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; }) -            .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; }) -            .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; }) -            .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; }) -            .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; }) -            .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; }) -            .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; }) -            .CaseLower("indirect-function", -                       [&SI] { SI.Type = ELF::STT_GNU_IFUNC; }) -            .CaseLower("debug", [] {}) -            .CaseLower("constructor", [] {}) -            .CaseLower("warning", [] {}) -            .CaseLower("indirect", [] {}) -            .CaseLower("synthetic", [] {}) -            .CaseLower("unique-object", [] {}) -            .StartsWithLower("before", [] {}) -            .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))(); -  if (!UnsupportedFlags.empty()) -    return createStringError(errc::invalid_argument, -                             "unsupported flag%s for --add-symbol: '%s'", -                             UnsupportedFlags.size() > 1 ? "s" : "", -                             join(UnsupportedFlags, "', '").c_str()); -  return SI; -} - -static const StringMap<MachineInfo> ArchMap{ -    // Name, {EMachine, 64bit, LittleEndian} -    {"aarch64", {ELF::EM_AARCH64, true, true}}, -    {"arm", {ELF::EM_ARM, false, true}}, -    {"i386", {ELF::EM_386, false, true}}, -    {"i386:x86-64", {ELF::EM_X86_64, true, true}}, -    {"mips", {ELF::EM_MIPS, false, false}}, -    {"powerpc:common64", {ELF::EM_PPC64, true, true}}, -    {"riscv:rv32", {ELF::EM_RISCV, false, true}}, -    {"riscv:rv64", {ELF::EM_RISCV, true, true}}, -    {"sparc", {ELF::EM_SPARC, false, false}}, -    {"sparcel", {ELF::EM_SPARC, false, true}}, -    {"x86-64", {ELF::EM_X86_64, true, true}}, -}; - -static Expected<const MachineInfo &> getMachineInfo(StringRef Arch) { -  auto Iter = ArchMap.find(Arch); -  if (Iter == std::end(ArchMap)) -    return createStringError(errc::invalid_argument, -                             "invalid architecture: '%s'", Arch.str().c_str()); -  return Iter->getValue(); -} -  struct TargetInfo {    FileFormat Format;    MachineInfo Machine; @@ -341,9 +298,10 @@ getOutputTargetInfoByTargetName(StringRef TargetName) {    return {TargetInfo{Format, MI}};  } -static Error addSymbolsFromFile(std::vector<NameOrRegex> &Symbols, -                                BumpPtrAllocator &Alloc, StringRef Filename, -                                bool UseRegex) { +static Error +addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc, +                   StringRef Filename, MatchStyle MS, +                   llvm::function_ref<Error(Error)> ErrorCallback) {    StringSaver Saver(Alloc);    SmallVector<StringRef, 16> Lines;    auto BufOrErr = MemoryBuffer::getFile(Filename); @@ -356,21 +314,47 @@ static Error addSymbolsFromFile(std::vector<NameOrRegex> &Symbols,      // it's not empty.      auto TrimmedLine = Line.split('#').first.trim();      if (!TrimmedLine.empty()) -      Symbols.emplace_back(Saver.save(TrimmedLine), UseRegex); +      if (Error E = Symbols.addMatcher(NameOrPattern::create( +              Saver.save(TrimmedLine), MS, ErrorCallback))) +        return E;    }    return Error::success();  } -NameOrRegex::NameOrRegex(StringRef Pattern, bool IsRegex) { -  if (!IsRegex) { -    Name = Pattern; -    return; -  } +Expected<NameOrPattern> +NameOrPattern::create(StringRef Pattern, MatchStyle MS, +                      llvm::function_ref<Error(Error)> ErrorCallback) { +  switch (MS) { +  case MatchStyle::Literal: +    return NameOrPattern(Pattern); +  case MatchStyle::Wildcard: { +    SmallVector<char, 32> Data; +    bool IsPositiveMatch = true; +    if (Pattern[0] == '!') { +      IsPositiveMatch = false; +      Pattern = Pattern.drop_front(); +    } +    Expected<GlobPattern> GlobOrErr = GlobPattern::create(Pattern); + +    // If we couldn't create it as a glob, report the error, but try again with +    // a literal if the error reporting is non-fatal. +    if (!GlobOrErr) { +      if (Error E = ErrorCallback(GlobOrErr.takeError())) +        return std::move(E); +      return create(Pattern, MatchStyle::Literal, ErrorCallback); +    } -  SmallVector<char, 32> Data; -  R = std::make_shared<Regex>( -      ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data)); +    return NameOrPattern(std::make_shared<GlobPattern>(*GlobOrErr), +                         IsPositiveMatch); +  } +  case MatchStyle::Regex: { +    SmallVector<char, 32> Data; +    return NameOrPattern(std::make_shared<Regex>( +        ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data))); +  } +  } +  llvm_unreachable("Unhandled llvm.objcopy.MatchStyle enum");  }  static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename, @@ -407,10 +391,22 @@ template <class T> static ErrorOr<T> getAsInteger(StringRef Val) {    return Result;  } +static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS, +                      StringRef ToolName) { +  OptTable.PrintHelp(OS, (ToolName + " input [output]").str().c_str(), +                     (ToolName + " tool").str().c_str()); +  // TODO: Replace this with libOption call once it adds extrahelp support. +  // The CommandLine library has a cl::extrahelp class to support this, +  // but libOption does not have that yet. +  OS << "\nPass @FILE as argument to read options from FILE.\n"; +} +  // ParseObjcopyOptions returns the config and sets the input arguments. If a  // help flag is set then ParseObjcopyOptions will print the help messege and  // exit. -Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) { +Expected<DriverConfig> +parseObjcopyOptions(ArrayRef<const char *> ArgsArr, +                    llvm::function_ref<Error(Error)> ErrorCallback) {    DriverConfig DC;    ObjcopyOptTable T;    unsigned MissingArgumentIndex, MissingArgumentCount; @@ -418,12 +414,12 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {        T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);    if (InputArgs.size() == 0) { -    T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool"); +    printHelp(T, errs(), "llvm-objcopy");      exit(1);    }    if (InputArgs.hasArg(OBJCOPY_help)) { -    T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool"); +    printHelp(T, outs(), "llvm-objcopy");      exit(0);    } @@ -459,7 +455,18 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {          errc::invalid_argument,          "--target cannot be used with --input-target or --output-target"); -  bool UseRegex = InputArgs.hasArg(OBJCOPY_regex); +  if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard)) +    return createStringError(errc::invalid_argument, +                             "--regex and --wildcard are incompatible"); + +  MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex) +                                     ? MatchStyle::Regex +                                     : MatchStyle::Wildcard; +  MatchStyle SymbolMatchStyle = InputArgs.hasArg(OBJCOPY_regex) +                                    ? MatchStyle::Regex +                                    : InputArgs.hasArg(OBJCOPY_wildcard) +                                          ? MatchStyle::Wildcard +                                          : MatchStyle::Literal;    StringRef InputFormat, OutputFormat;    if (InputArgs.hasArg(OBJCOPY_target)) {      InputFormat = InputArgs.getLastArgValue(OBJCOPY_target); @@ -476,28 +483,26 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {                             .Case("binary", FileFormat::Binary)                             .Case("ihex", FileFormat::IHex)                             .Default(FileFormat::Unspecified); -  if (Config.InputFormat == FileFormat::Binary) { -    auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); -    if (BinaryArch.empty()) -      return createStringError( -          errc::invalid_argument, -          "specified binary input without specifiying an architecture"); -    Expected<const MachineInfo &> MI = getMachineInfo(BinaryArch); -    if (!MI) -      return MI.takeError(); -    Config.BinaryArch = *MI; -  } + +  if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) +    Config.NewSymbolVisibility = +        InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);    Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)                              .Case("binary", FileFormat::Binary)                              .Case("ihex", FileFormat::IHex)                              .Default(FileFormat::Unspecified); -  if (Config.OutputFormat == FileFormat::Unspecified && !OutputFormat.empty()) { -    Expected<TargetInfo> Target = getOutputTargetInfoByTargetName(OutputFormat); -    if (!Target) -      return Target.takeError(); -    Config.OutputFormat = Target->Format; -    Config.OutputArch = Target->Machine; +  if (Config.OutputFormat == FileFormat::Unspecified) { +    if (OutputFormat.empty()) { +      Config.OutputFormat = Config.InputFormat; +    } else { +      Expected<TargetInfo> Target = +          getOutputTargetInfoByTargetName(OutputFormat); +      if (!Target) +        return Target.takeError(); +      Config.OutputFormat = Target->Format; +      Config.OutputArch = Target->Machine; +    }    }    if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections, @@ -535,12 +540,8 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {      if (!DebugOrErr)        return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError());      auto Debug = std::move(*DebugOrErr); -    JamCRC CRC; -    CRC.update( -        ArrayRef<char>(Debug->getBuffer().data(), Debug->getBuffer().size())); -    // The CRC32 value needs to be complemented because the JamCRC doesn't -    // finalize the CRC32 value. -    Config.GnuDebugLinkCRC32 = ~CRC.getCRC(); +    Config.GnuDebugLinkCRC32 = +        llvm::crc32(arrayRefFromStringRef(Debug->getBuffer()));    }    Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);    if (InputArgs.hasArg(OBJCOPY_build_id_link_input)) @@ -582,6 +583,13 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {                                 "multiple renames of section '%s'",                                 SR->OriginalName.str().c_str());    } +  for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) { +    Expected<std::pair<StringRef, uint64_t>> NameAndAlign = +        parseSetSectionAlignment(Arg->getValue()); +    if (!NameAndAlign) +      return NameAndAlign.takeError(); +    Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second; +  }    for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {      Expected<SectionFlagsUpdate> SFU =          parseSetSectionFlagValue(Arg->getValue()); @@ -612,13 +620,28 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {    }    for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) -    Config.ToRemove.emplace_back(Arg->getValue(), UseRegex); +    if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create( +            Arg->getValue(), SectionMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section)) -    Config.KeepSection.emplace_back(Arg->getValue(), UseRegex); +    if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create( +            Arg->getValue(), SectionMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_only_section)) -    Config.OnlySection.emplace_back(Arg->getValue(), UseRegex); -  for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) -    Config.AddSection.push_back(Arg->getValue()); +    if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create( +            Arg->getValue(), SectionMatchStyle, ErrorCallback))) +      return std::move(E); +  for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) { +    StringRef ArgValue(Arg->getValue()); +    if (!ArgValue.contains('=')) +      return createStringError(errc::invalid_argument, +                               "bad format for --add-section: missing '='"); +    if (ArgValue.split("=").second.empty()) +      return createStringError( +          errc::invalid_argument, +          "bad format for --add-section: missing file name"); +    Config.AddSection.push_back(ArgValue); +  }    for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))      Config.DumpSection.push_back(Arg->getValue());    Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); @@ -645,53 +668,71 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {    if (Config.DiscardMode == DiscardType::All)      Config.StripDebug = true;    for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) -    Config.SymbolsToLocalize.emplace_back(Arg->getValue(), UseRegex); +    if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create( +            Arg->getValue(), SymbolMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))      if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc, -                                     Arg->getValue(), UseRegex)) +                                     Arg->getValue(), SymbolMatchStyle, +                                     ErrorCallback))        return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) -    Config.SymbolsToKeepGlobal.emplace_back(Arg->getValue(), UseRegex); +    if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create( +            Arg->getValue(), SymbolMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))      if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc, -                                     Arg->getValue(), UseRegex)) +                                     Arg->getValue(), SymbolMatchStyle, +                                     ErrorCallback))        return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) -    Config.SymbolsToGlobalize.emplace_back(Arg->getValue(), UseRegex); +    if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create( +            Arg->getValue(), SymbolMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))      if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc, -                                     Arg->getValue(), UseRegex)) +                                     Arg->getValue(), SymbolMatchStyle, +                                     ErrorCallback))        return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) -    Config.SymbolsToWeaken.emplace_back(Arg->getValue(), UseRegex); +    if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create( +            Arg->getValue(), SymbolMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))      if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc, -                                     Arg->getValue(), UseRegex)) +                                     Arg->getValue(), SymbolMatchStyle, +                                     ErrorCallback))        return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) -    Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegex); +    if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create( +            Arg->getValue(), SymbolMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))      if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc, -                                     Arg->getValue(), UseRegex)) +                                     Arg->getValue(), SymbolMatchStyle, +                                     ErrorCallback))        return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol)) -    Config.UnneededSymbolsToRemove.emplace_back(Arg->getValue(), UseRegex); +    if (Error E = +            Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create( +                Arg->getValue(), SymbolMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))      if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc, -                                     Arg->getValue(), UseRegex)) +                                     Arg->getValue(), SymbolMatchStyle, +                                     ErrorCallback))        return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) -    Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegex); +    if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( +            Arg->getValue(), SymbolMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols)) -    if (Error E = addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, -                                     Arg->getValue(), UseRegex)) +    if (Error E = +            addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(), +                               SymbolMatchStyle, ErrorCallback))        return std::move(E); -  for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) { -    Expected<NewSymbolInfo> NSI = parseNewSymbolInfo(Arg->getValue()); -    if (!NSI) -      return NSI.takeError(); -    Config.SymbolsToAdd.push_back(*NSI); -  } +  for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) +    Config.SymbolsToAdd.push_back(Arg->getValue());    Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); @@ -749,24 +790,75 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {    return std::move(DC);  } +// ParseInstallNameToolOptions returns the config and sets the input arguments. +// If a help flag is set then ParseInstallNameToolOptions will print the help +// messege and exit. +Expected<DriverConfig> +parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) { +  DriverConfig DC; +  CopyConfig Config; +  InstallNameToolOptTable T; +  unsigned MissingArgumentIndex, MissingArgumentCount; +  llvm::opt::InputArgList InputArgs = +      T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); + +  if (InputArgs.size() == 0) { +    printHelp(T, errs(), "llvm-install-name-tool"); +    exit(1); +  } + +  if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) { +    printHelp(T, outs(), "llvm-install-name-tool"); +    exit(0); +  } + +  if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) { +    outs() << "llvm-install-name-tool, compatible with cctools " +              "install_name_tool\n"; +    cl::PrintVersionMessage(); +    exit(0); +  } + +  for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath)) +    Config.RPathToAdd.push_back(Arg->getValue()); + +  SmallVector<StringRef, 2> Positional; +  for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN)) +    return createStringError(errc::invalid_argument, "unknown argument '%s'", +                             Arg->getAsString(InputArgs).c_str()); +  for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT)) +    Positional.push_back(Arg->getValue()); +  if (Positional.empty()) +    return createStringError(errc::invalid_argument, "no input file specified"); +  if (Positional.size() > 1) +    return createStringError( +        errc::invalid_argument, +        "llvm-install-name-tool expects a single input file"); +  Config.InputFilename = Positional[0]; +  Config.OutputFilename = Positional[0]; + +  DC.CopyConfigs.push_back(std::move(Config)); +  return std::move(DC); +} +  // ParseStripOptions returns the config and sets the input arguments. If a  // help flag is set then ParseStripOptions will print the help messege and  // exit.  Expected<DriverConfig>  parseStripOptions(ArrayRef<const char *> ArgsArr, -                  std::function<Error(Error)> ErrorCallback) { +                  llvm::function_ref<Error(Error)> ErrorCallback) {    StripOptTable T;    unsigned MissingArgumentIndex, MissingArgumentCount;    llvm::opt::InputArgList InputArgs =        T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);    if (InputArgs.size() == 0) { -    T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool"); +    printHelp(T, errs(), "llvm-strip");      exit(1);    }    if (InputArgs.hasArg(STRIP_help)) { -    T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool"); +    printHelp(T, outs(), "llvm-strip");      exit(0);    } @@ -792,7 +884,17 @@ parseStripOptions(ArrayRef<const char *> ArgsArr,          "multiple input files cannot be used in combination with -o");    CopyConfig Config; -  bool UseRegexp = InputArgs.hasArg(STRIP_regex); + +  if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard)) +    return createStringError(errc::invalid_argument, +                             "--regex and --wildcard are incompatible"); +  MatchStyle SectionMatchStyle = +      InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard; +  MatchStyle SymbolMatchStyle = InputArgs.hasArg(STRIP_regex) +                                    ? MatchStyle::Regex +                                    : InputArgs.hasArg(STRIP_wildcard) +                                          ? MatchStyle::Wildcard +                                          : MatchStyle::Literal;    Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);    Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); @@ -801,6 +903,7 @@ parseStripOptions(ArrayRef<const char *> ArgsArr,          InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals)              ? DiscardType::All              : DiscardType::Locals; +  Config.StripSections = InputArgs.hasArg(STRIP_strip_sections);    Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);    if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all))      Config.StripAll = Arg->getOption().getID() == STRIP_strip_all; @@ -809,16 +912,24 @@ parseStripOptions(ArrayRef<const char *> ArgsArr,    Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);    for (auto Arg : InputArgs.filtered(STRIP_keep_section)) -    Config.KeepSection.emplace_back(Arg->getValue(), UseRegexp); +    if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create( +            Arg->getValue(), SectionMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(STRIP_remove_section)) -    Config.ToRemove.emplace_back(Arg->getValue(), UseRegexp); +    if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create( +            Arg->getValue(), SectionMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(STRIP_strip_symbol)) -    Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegexp); +    if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create( +            Arg->getValue(), SymbolMatchStyle, ErrorCallback))) +      return std::move(E);    for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) -    Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegexp); +    if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( +            Arg->getValue(), SymbolMatchStyle, ErrorCallback))) +      return std::move(E);    if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&        !Config.StripUnneeded && Config.DiscardMode == DiscardType::None && diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.h b/contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.h index aff3631a487c..c262934b4a41 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.h @@ -9,6 +9,7 @@  #ifndef LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H  #define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H +#include "ELF/ELFConfig.h"  #include "llvm/ADT/ArrayRef.h"  #include "llvm/ADT/BitmaskEnum.h"  #include "llvm/ADT/Optional.h" @@ -18,6 +19,7 @@  #include "llvm/Object/ELFTypes.h"  #include "llvm/Support/Allocator.h"  #include "llvm/Support/Error.h" +#include "llvm/Support/GlobPattern.h"  #include "llvm/Support/Regex.h"  // Necessary for llvm::DebugCompressionType::None  #include "llvm/Target/TargetOptions.h" @@ -87,36 +89,71 @@ enum class DiscardType {    Locals, // --discard-locals (-X)  }; -class NameOrRegex { +enum class MatchStyle { +  Literal,  // Default for symbols. +  Wildcard, // Default for sections, or enabled with --wildcard (-w). +  Regex,    // Enabled with --regex. +}; + +class NameOrPattern {    StringRef Name;    // Regex is shared between multiple CopyConfig instances.    std::shared_ptr<Regex> R; +  std::shared_ptr<GlobPattern> G; +  bool IsPositiveMatch = true; + +  NameOrPattern(StringRef N) : Name(N) {} +  NameOrPattern(std::shared_ptr<Regex> R) : R(R) {} +  NameOrPattern(std::shared_ptr<GlobPattern> G, bool IsPositiveMatch) +      : G(G), IsPositiveMatch(IsPositiveMatch) {}  public: -  NameOrRegex(StringRef Pattern, bool IsRegex); -  bool operator==(StringRef S) const { return R ? R->match(S) : Name == S; } +  // ErrorCallback is used to handle recoverable errors. An Error returned +  // by the callback aborts the parsing and is then returned by this function. +  static Expected<NameOrPattern> +  create(StringRef Pattern, MatchStyle MS, +         llvm::function_ref<Error(Error)> ErrorCallback); + +  bool isPositiveMatch() const { return IsPositiveMatch; } +  bool operator==(StringRef S) const { +    return R ? R->match(S) : G ? G->match(S) : Name == S; +  }    bool operator!=(StringRef S) const { return !operator==(S); }  }; -struct NewSymbolInfo { -  StringRef SymbolName; -  StringRef SectionName; -  uint64_t Value = 0; -  uint8_t Type = ELF::STT_NOTYPE; -  uint8_t Bind = ELF::STB_GLOBAL; -  uint8_t Visibility = ELF::STV_DEFAULT; +// Matcher that checks symbol or section names against the command line flags +// provided for that option. +class NameMatcher { +  std::vector<NameOrPattern> PosMatchers; +  std::vector<NameOrPattern> NegMatchers; + +public: +  Error addMatcher(Expected<NameOrPattern> Matcher) { +    if (!Matcher) +      return Matcher.takeError(); +    if (Matcher->isPositiveMatch()) +      PosMatchers.push_back(std::move(*Matcher)); +    else +      NegMatchers.push_back(std::move(*Matcher)); +    return Error::success(); +  } +  bool matches(StringRef S) const { +    return is_contained(PosMatchers, S) && !is_contained(NegMatchers, S); +  } +  bool empty() const { return PosMatchers.empty() && NegMatchers.empty(); }  };  // Configuration for copying/stripping a single file.  struct CopyConfig { +  // Format-specific options to be initialized lazily when needed. +  Optional<elf::ELFCopyConfig> ELF; +    // Main input/output options    StringRef InputFilename; -  FileFormat InputFormat; +  FileFormat InputFormat = FileFormat::Unspecified;    StringRef OutputFilename; -  FileFormat OutputFormat; +  FileFormat OutputFormat = FileFormat::Unspecified; -  // Only applicable for --input-format=binary -  MachineInfo BinaryArch;    // Only applicable when --output-format!=binary (e.g. elf64-x86-64).    Optional<MachineInfo> OutputArch; @@ -132,24 +169,31 @@ struct CopyConfig {    StringRef SymbolsPrefix;    StringRef AllocSectionsPrefix;    DiscardType DiscardMode = DiscardType::None; +  Optional<StringRef> NewSymbolVisibility;    // Repeated options    std::vector<StringRef> AddSection;    std::vector<StringRef> DumpSection; -  std::vector<NewSymbolInfo> SymbolsToAdd; -  std::vector<NameOrRegex> KeepSection; -  std::vector<NameOrRegex> OnlySection; -  std::vector<NameOrRegex> SymbolsToGlobalize; -  std::vector<NameOrRegex> SymbolsToKeep; -  std::vector<NameOrRegex> SymbolsToLocalize; -  std::vector<NameOrRegex> SymbolsToRemove; -  std::vector<NameOrRegex> UnneededSymbolsToRemove; -  std::vector<NameOrRegex> SymbolsToWeaken; -  std::vector<NameOrRegex> ToRemove; -  std::vector<NameOrRegex> SymbolsToKeepGlobal; +  std::vector<StringRef> SymbolsToAdd; +  std::vector<StringRef> RPathToAdd; + +  // Section matchers +  NameMatcher KeepSection; +  NameMatcher OnlySection; +  NameMatcher ToRemove; + +  // Symbol matchers +  NameMatcher SymbolsToGlobalize; +  NameMatcher SymbolsToKeep; +  NameMatcher SymbolsToLocalize; +  NameMatcher SymbolsToRemove; +  NameMatcher UnneededSymbolsToRemove; +  NameMatcher SymbolsToWeaken; +  NameMatcher SymbolsToKeepGlobal;    // Map options    StringMap<SectionRename> SectionsToRename; +  StringMap<uint64_t> SetSectionAlignment;    StringMap<SectionFlagsUpdate> SetSectionFlags;    StringMap<StringRef> SymbolsToRename; @@ -178,6 +222,18 @@ struct CopyConfig {    bool Weaken = false;    bool DecompressDebugSections = false;    DebugCompressionType CompressionType = DebugCompressionType::None; + +  // parseELFConfig performs ELF-specific command-line parsing. Fills `ELF` on +  // success or returns an Error otherwise. +  Error parseELFConfig() { +    if (!ELF) { +      Expected<elf::ELFCopyConfig> ELFConfig = elf::parseConfig(*this); +      if (!ELFConfig) +        return ELFConfig.takeError(); +      ELF = *ELFConfig; +    } +    return Error::success(); +  }  };  // Configuration for the overall invocation of this tool. When invoked as @@ -190,8 +246,17 @@ struct DriverConfig {  // ParseObjcopyOptions returns the config and sets the input arguments. If a  // help flag is set then ParseObjcopyOptions will print the help messege and -// exit. -Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr); +// exit. ErrorCallback is used to handle recoverable errors. An Error returned +// by the callback aborts the parsing and is then returned by this function. +Expected<DriverConfig> +parseObjcopyOptions(ArrayRef<const char *> ArgsArr, +                    llvm::function_ref<Error(Error)> ErrorCallback); + +// ParseInstallNameToolOptions returns the config and sets the input arguments. +// If a help flag is set then ParseInstallNameToolOptions will print the help +// messege and exit. +Expected<DriverConfig> +parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr);  // ParseStripOptions returns the config and sets the input arguments. If a  // help flag is set then ParseStripOptions will print the help messege and @@ -199,8 +264,7 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr);  // by the callback aborts the parsing and is then returned by this function.  Expected<DriverConfig>  parseStripOptions(ArrayRef<const char *> ArgsArr, -                  std::function<Error(Error)> ErrorCallback); - +                  llvm::function_ref<Error(Error)> ErrorCallback);  } // namespace objcopy  } // namespace llvm diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp new file mode 100644 index 000000000000..40993760add7 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp @@ -0,0 +1,133 @@ +//===- ELFConfig.cpp ------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "CopyConfig.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace objcopy { +namespace elf { + +static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue, +                                                  uint8_t DefaultVisibility) { +  // Parse value given with --add-symbol option and create the +  // new symbol if possible. The value format for --add-symbol is: +  // +  // <name>=[<section>:]<value>[,<flags>] +  // +  // where: +  // <name> - symbol name, can be empty string +  // <section> - optional section name. If not given ABS symbol is created +  // <value> - symbol value, can be decimal or hexadecimal number prefixed +  //           with 0x. +  // <flags> - optional flags affecting symbol type, binding or visibility: +  //           The following are currently supported: +  // +  //           global, local, weak, default, hidden, file, section, object, +  //           indirect-function. +  // +  //           The following flags are ignored and provided for GNU +  //           compatibility only: +  // +  //           warning, debug, constructor, indirect, synthetic, +  //           unique-object, before=<symbol>. +  NewSymbolInfo SI; +  StringRef Value; +  std::tie(SI.SymbolName, Value) = FlagValue.split('='); +  if (Value.empty()) +    return createStringError( +        errc::invalid_argument, +        "bad format for --add-symbol, missing '=' after '%s'", +        SI.SymbolName.str().c_str()); + +  if (Value.contains(':')) { +    std::tie(SI.SectionName, Value) = Value.split(':'); +    if (SI.SectionName.empty() || Value.empty()) +      return createStringError( +          errc::invalid_argument, +          "bad format for --add-symbol, missing section name or symbol value"); +  } + +  SmallVector<StringRef, 6> Flags; +  Value.split(Flags, ','); +  if (Flags[0].getAsInteger(0, SI.Value)) +    return createStringError(errc::invalid_argument, "bad symbol value: '%s'", +                             Flags[0].str().c_str()); + +  SI.Visibility = DefaultVisibility; + +  using Functor = std::function<void(void)>; +  SmallVector<StringRef, 6> UnsupportedFlags; +  for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) +    static_cast<Functor>( +        StringSwitch<Functor>(Flags[I]) +            .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; }) +            .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; }) +            .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; }) +            .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; }) +            .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; }) +            .CaseLower("protected", +                       [&SI] { SI.Visibility = ELF::STV_PROTECTED; }) +            .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; }) +            .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; }) +            .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; }) +            .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; }) +            .CaseLower("indirect-function", +                       [&SI] { SI.Type = ELF::STT_GNU_IFUNC; }) +            .CaseLower("debug", [] {}) +            .CaseLower("constructor", [] {}) +            .CaseLower("warning", [] {}) +            .CaseLower("indirect", [] {}) +            .CaseLower("synthetic", [] {}) +            .CaseLower("unique-object", [] {}) +            .StartsWithLower("before", [] {}) +            .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))(); +  if (!UnsupportedFlags.empty()) +    return createStringError(errc::invalid_argument, +                             "unsupported flag%s for --add-symbol: '%s'", +                             UnsupportedFlags.size() > 1 ? "s" : "", +                             join(UnsupportedFlags, "', '").c_str()); +  return SI; +} + +Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config) { +  ELFCopyConfig ELFConfig; +  if (Config.NewSymbolVisibility) { +    const uint8_t Invalid = 0xff; +    ELFConfig.NewSymbolVisibility = +        StringSwitch<uint8_t>(*Config.NewSymbolVisibility) +            .Case("default", ELF::STV_DEFAULT) +            .Case("hidden", ELF::STV_HIDDEN) +            .Case("internal", ELF::STV_INTERNAL) +            .Case("protected", ELF::STV_PROTECTED) +            .Default(Invalid); + +    if (ELFConfig.NewSymbolVisibility == Invalid) +      return createStringError(errc::invalid_argument, +                               "'%s' is not a valid symbol visibility", +                               Config.NewSymbolVisibility->str().c_str()); +  } + +  for (StringRef Arg : Config.SymbolsToAdd) { +    Expected<elf::NewSymbolInfo> NSI = parseNewSymbolInfo( +        Arg, +        ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); +    if (!NSI) +      return NSI.takeError(); +    ELFConfig.SymbolsToAdd.push_back(*NSI); +  } + +  return ELFConfig; +} + +} // end namespace elf +} // end namespace objcopy +} // end namespace llvm diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFConfig.h b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFConfig.h new file mode 100644 index 000000000000..977efbc4166f --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFConfig.h @@ -0,0 +1,44 @@ +//===- ELFConfig.h ----------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OBJCOPY_ELFCONFIG_H +#define LLVM_TOOLS_OBJCOPY_ELFCONFIG_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Support/Error.h" +#include <vector> + +namespace llvm { +namespace objcopy { +struct CopyConfig; + +namespace elf { + +struct NewSymbolInfo { +  StringRef SymbolName; +  StringRef SectionName; +  uint64_t Value = 0; +  uint8_t Type = ELF::STT_NOTYPE; +  uint8_t Bind = ELF::STB_GLOBAL; +  uint8_t Visibility = ELF::STV_DEFAULT; +}; + +struct ELFCopyConfig { +  Optional<uint8_t> NewSymbolVisibility; +  std::vector<NewSymbolInfo> SymbolsToAdd; +}; + +Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config); + +} // namespace elf +} // namespace objcopy +} // namespace llvm + +#endif diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index 2e25a47dde01..a0cfd9a5ff86 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -136,17 +136,17 @@ static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,    // Depending on the initial ELFT and OutputFormat we need a different Writer.    switch (OutputElfType) {    case ELFT_ELF32LE: -    return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, -                                                 !Config.StripSections); +    return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections, +                                                Config.OnlyKeepDebug);    case ELFT_ELF64LE: -    return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, -                                                 !Config.StripSections); +    return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections, +                                                Config.OnlyKeepDebug);    case ELFT_ELF32BE: -    return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, -                                                 !Config.StripSections); +    return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections, +                                                Config.OnlyKeepDebug);    case ELFT_ELF64BE: -    return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, -                                                 !Config.StripSections); +    return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections, +                                                Config.OnlyKeepDebug);    }    llvm_unreachable("Invalid output format");  } @@ -156,9 +156,9 @@ static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,                                              ElfType OutputElfType) {    switch (Config.OutputFormat) {    case FileFormat::Binary: -    return llvm::make_unique<BinaryWriter>(Obj, Buf); +    return std::make_unique<BinaryWriter>(Obj, Buf);    case FileFormat::IHex: -    return llvm::make_unique<IHexWriter>(Obj, Buf); +    return std::make_unique<IHexWriter>(Obj, Buf);    default:      return createELFWriter(Config, Obj, Buf, OutputElfType);    } @@ -175,7 +175,7 @@ findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) {      if (Phdr.p_type != PT_NOTE)        continue;      Error Err = Error::success(); -    for (const auto &Note : In.notes(Phdr, Err)) +    for (auto Note : In.notes(Phdr, Err))        if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU)          return Note.getDesc();      if (Err) @@ -263,7 +263,7 @@ static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink,  static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader,                              StringRef File, ElfType OutputElfType) { -  auto DWOFile = Reader.create(); +  auto DWOFile = Reader.create(false);    auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) {      return onlyKeepDWOPred(*DWOFile, Sec);    }; @@ -305,9 +305,9 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,                             SecName.str().c_str());  } -static bool isCompressable(const SectionBase &Section) { -  return !(Section.Flags & ELF::SHF_COMPRESSED) && -         StringRef(Section.Name).startswith(".debug"); +static bool isCompressable(const SectionBase &Sec) { +  return !(Sec.Flags & ELF::SHF_COMPRESSED) && +         StringRef(Sec.Name).startswith(".debug");  }  static void replaceDebugSections( @@ -356,7 +356,7 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {      if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&          ((Config.LocalizeHidden &&            (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || -         is_contained(Config.SymbolsToLocalize, Sym.Name))) +         Config.SymbolsToLocalize.matches(Sym.Name)))        Sym.Binding = STB_LOCAL;      // Note: these two globalize flags have very similar names but different @@ -370,16 +370,15 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {      // --keep-global-symbol. Because of that, make sure to check      // --globalize-symbol second.      if (!Config.SymbolsToKeepGlobal.empty() && -        !is_contained(Config.SymbolsToKeepGlobal, Sym.Name) && +        !Config.SymbolsToKeepGlobal.matches(Sym.Name) &&          Sym.getShndx() != SHN_UNDEF)        Sym.Binding = STB_LOCAL; -    if (is_contained(Config.SymbolsToGlobalize, Sym.Name) && +    if (Config.SymbolsToGlobalize.matches(Sym.Name) &&          Sym.getShndx() != SHN_UNDEF)        Sym.Binding = STB_GLOBAL; -    if (is_contained(Config.SymbolsToWeaken, Sym.Name) && -        Sym.Binding == STB_GLOBAL) +    if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding == STB_GLOBAL)        Sym.Binding = STB_WEAK;      if (Config.Weaken && Sym.Binding == STB_GLOBAL && @@ -399,12 +398,12 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {    // symbols are still 'needed' and which are not.    if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() ||        !Config.OnlySection.empty()) { -    for (auto &Section : Obj.sections()) -      Section.markSymbols(); +    for (SectionBase &Sec : Obj.sections()) +      Sec.markSymbols();    }    auto RemoveSymbolsPred = [&](const Symbol &Sym) { -    if (is_contained(Config.SymbolsToKeep, Sym.Name) || +    if (Config.SymbolsToKeep.matches(Sym.Name) ||          (Config.KeepFileSymbols && Sym.Type == STT_FILE))        return false; @@ -418,12 +417,12 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {      if (Config.StripAll || Config.StripAllGNU)        return true; -    if (is_contained(Config.SymbolsToRemove, Sym.Name)) +    if (Config.SymbolsToRemove.matches(Sym.Name))        return true;      if ((Config.StripUnneeded || -         is_contained(Config.UnneededSymbolsToRemove, Sym.Name)) && -        isUnneededSymbol(Sym)) +         Config.UnneededSymbolsToRemove.matches(Sym.Name)) && +        (!Obj.isRelocatable() || isUnneededSymbol(Sym)))        return true;      // We want to remove undefined symbols if all references have been stripped. @@ -443,7 +442,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {    // Removes:    if (!Config.ToRemove.empty()) {      RemovePred = [&Config](const SectionBase &Sec) { -      return is_contained(Config.ToRemove, Sec.Name); +      return Config.ToRemove.matches(Sec.Name);      };    } @@ -481,7 +480,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {      };    } -  if (Config.StripDebug) { +  if (Config.StripDebug || Config.StripUnneeded) {      RemovePred = [RemovePred](const SectionBase &Sec) {        return RemovePred(Sec) || isDebugSection(Sec);      }; @@ -529,7 +528,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {    if (!Config.OnlySection.empty()) {      RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {        // Explicitly keep these sections regardless of previous removes. -      if (is_contained(Config.OnlySection, Sec.Name)) +      if (Config.OnlySection.matches(Sec.Name))          return false;        // Allow all implicit removes. @@ -551,7 +550,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {    if (!Config.KeepSection.empty()) {      RemovePred = [&Config, RemovePred](const SectionBase &Sec) {        // Explicitly keep these sections regardless of previous removes. -      if (is_contained(Config.KeepSection, Sec.Name)) +      if (Config.KeepSection.matches(Sec.Name))          return false;        // Otherwise defer to RemovePred.        return RemovePred(Sec); @@ -620,9 +619,8 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj,    if (Error E = updateAndRemoveSymbols(Config, Obj))      return E; -  if (!Config.SectionsToRename.empty() || !Config.AllocSectionsPrefix.empty()) { -    DenseSet<SectionBase *> PrefixedSections; -    for (auto &Sec : Obj.sections()) { +  if (!Config.SectionsToRename.empty()) { +    for (SectionBase &Sec : Obj.sections()) {        const auto Iter = Config.SectionsToRename.find(Sec.Name);        if (Iter != Config.SectionsToRename.end()) {          const SectionRename &SR = Iter->second; @@ -630,63 +628,62 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj,          if (SR.NewFlags.hasValue())            setSectionFlagsAndType(Sec, SR.NewFlags.getValue());        } +    } +  } -      // Add a prefix to allocated sections and their relocation sections. This -      // should be done after renaming the section by Config.SectionToRename to -      // imitate the GNU objcopy behavior. -      if (!Config.AllocSectionsPrefix.empty()) { -        if (Sec.Flags & SHF_ALLOC) { -          Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str(); -          PrefixedSections.insert(&Sec); - -          // Rename relocation sections associated to the allocated sections. -          // For example, if we rename .text to .prefix.text, we also rename -          // .rel.text to .rel.prefix.text. -          // -          // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled -          // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not -          // .rela.prefix.plt since GNU objcopy does so. -        } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) { -          auto *TargetSec = RelocSec->getSection(); -          if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) { -            StringRef prefix; -            switch (Sec.Type) { -            case SHT_REL: -              prefix = ".rel"; -              break; -            case SHT_RELA: -              prefix = ".rela"; -              break; -            default: -              continue; -            } - -            // If the relocation section comes *after* the target section, we -            // don't add Config.AllocSectionsPrefix because we've already added -            // the prefix to TargetSec->Name. Otherwise, if the relocation -            // section comes *before* the target section, we add the prefix. -            if (PrefixedSections.count(TargetSec)) { -              Sec.Name = (prefix + TargetSec->Name).str(); -            } else { -              const auto Iter = Config.SectionsToRename.find(TargetSec->Name); -              if (Iter != Config.SectionsToRename.end()) { -                // Both `--rename-section` and `--prefix-alloc-sections` are -                // given but the target section is not yet renamed. -                Sec.Name = -                    (prefix + Config.AllocSectionsPrefix + Iter->second.NewName) -                        .str(); -              } else { -                Sec.Name = -                    (prefix + Config.AllocSectionsPrefix + TargetSec->Name) -                        .str(); -              } -            } +  // Add a prefix to allocated sections and their relocation sections. This +  // should be done after renaming the section by Config.SectionToRename to +  // imitate the GNU objcopy behavior. +  if (!Config.AllocSectionsPrefix.empty()) { +    DenseSet<SectionBase *> PrefixedSections; +    for (SectionBase &Sec : Obj.sections()) { +      if (Sec.Flags & SHF_ALLOC) { +        Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str(); +        PrefixedSections.insert(&Sec); +      } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) { +        // Rename relocation sections associated to the allocated sections. +        // For example, if we rename .text to .prefix.text, we also rename +        // .rel.text to .rel.prefix.text. +        // +        // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled +        // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not +        // .rela.prefix.plt since GNU objcopy does so. +        const SectionBase *TargetSec = RelocSec->getSection(); +        if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) { +          StringRef prefix; +          switch (Sec.Type) { +          case SHT_REL: +            prefix = ".rel"; +            break; +          case SHT_RELA: +            prefix = ".rela"; +            break; +          default: +            llvm_unreachable("not a relocation section");            } + +          // If the relocation section comes *after* the target section, we +          // don't add Config.AllocSectionsPrefix because we've already added +          // the prefix to TargetSec->Name. Otherwise, if the relocation +          // section comes *before* the target section, we add the prefix. +          if (PrefixedSections.count(TargetSec)) +            Sec.Name = (prefix + TargetSec->Name).str(); +          else +            Sec.Name = +                (prefix + Config.AllocSectionsPrefix + TargetSec->Name).str();          }        }      }    } +  if (!Config.SetSectionAlignment.empty()) { +    for (SectionBase &Sec : Obj.sections()) { +      auto I = Config.SetSectionAlignment.find(Sec.Name); +      if (I != Config.SetSectionAlignment.end()) +        Sec.Align = I->second; +    } +  } +    if (!Config.SetSectionFlags.empty()) {      for (auto &Sec : Obj.sections()) {        const auto Iter = Config.SetSectionFlags.find(Sec.Name); @@ -697,6 +694,11 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj,      }    } +  if (Config.OnlyKeepDebug) +    for (auto &Sec : Obj.sections()) +      if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) +        Sec.Type = SHT_NOBITS; +    for (const auto &Flag : Config.AddSection) {      std::pair<StringRef, StringRef> SecPair = Flag.split("=");      StringRef SecName = SecPair.first; @@ -727,7 +729,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj,      Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,                                          Config.GnuDebugLinkCRC32); -  for (const NewSymbolInfo &SI : Config.SymbolsToAdd) { +  for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) {      SectionBase *Sec = Obj.findSection(SI.SectionName);      uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value;      Obj.SymbolTable->addSymbol( @@ -752,9 +754,9 @@ static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,  Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,                             Buffer &Out) {    IHexReader Reader(&In); -  std::unique_ptr<Object> Obj = Reader.create(); +  std::unique_ptr<Object> Obj = Reader.create(true);    const ElfType OutputElfType = -      getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch)); +    getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));    if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))      return E;    return writeOutput(Config, *Obj, Out, OutputElfType); @@ -762,13 +764,15 @@ Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,  Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,                                  Buffer &Out) { -  BinaryReader Reader(Config.BinaryArch, &In); -  std::unique_ptr<Object> Obj = Reader.create(); +  uint8_t NewSymbolVisibility = +      Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); +  BinaryReader Reader(&In, NewSymbolVisibility); +  std::unique_ptr<Object> Obj = Reader.create(true);    // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch    // (-B<arch>).    const ElfType OutputElfType = -      getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch)); +      getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));    if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))      return E;    return writeOutput(Config, *Obj, Out, OutputElfType); @@ -777,7 +781,7 @@ Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,  Error executeObjcopyOnBinary(const CopyConfig &Config,                               object::ELFObjectFileBase &In, Buffer &Out) {    ELFReader Reader(&In, Config.ExtractPartition); -  std::unique_ptr<Object> Obj = Reader.create(); +  std::unique_ptr<Object> Obj = Reader.create(!Config.SymbolsToAdd.empty());    // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.    const ElfType OutputElfType =        Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.cpp index fa696380e17c..ad53c75663ec 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -397,7 +397,7 @@ void SectionWriter::visit(const OwnedDataSection &Sec) {    llvm::copy(Sec.Data, Out.getBufferStart() + Sec.Offset);  } -static const std::vector<uint8_t> ZlibGnuMagic = {'Z', 'L', 'I', 'B'}; +static constexpr std::array<uint8_t, 4> ZlibGnuMagic = {{'Z', 'L', 'I', 'B'}};  static bool isDataGnuCompressed(ArrayRef<uint8_t> Data) {    return Data.size() > ZlibGnuMagic.size() && @@ -665,7 +665,7 @@ void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type,    Sym.Visibility = Visibility;    Sym.Size = SymbolSize;    Sym.Index = Symbols.size(); -  Symbols.emplace_back(llvm::make_unique<Symbol>(Sym)); +  Symbols.emplace_back(std::make_unique<Symbol>(Sym));    Size += this->EntrySize;  } @@ -815,7 +815,8 @@ Error RelocationSection::removeSectionReferences(    }    for (const Relocation &R : Relocations) { -    if (!R.RelocSymbol->DefinedIn || !ToRemove(R.RelocSymbol->DefinedIn)) +    if (!R.RelocSymbol || !R.RelocSymbol->DefinedIn || +        !ToRemove(R.RelocSymbol->DefinedIn))        continue;      return createStringError(llvm::errc::invalid_argument,                               "section '%s' cannot be removed: (%s+0x%" PRIx64 @@ -868,7 +869,8 @@ static void writeRel(const RelRange &Relocations, T *Buf) {    for (const auto &Reloc : Relocations) {      Buf->r_offset = Reloc.Offset;      setAddend(*Buf, Reloc.Addend); -    Buf->setSymbolAndType(Reloc.RelocSymbol->Index, Reloc.Type, false); +    Buf->setSymbolAndType(Reloc.RelocSymbol ? Reloc.RelocSymbol->Index : 0, +                          Reloc.Type, false);      ++Buf;    }  } @@ -893,7 +895,7 @@ void RelocationSection::accept(MutableSectionVisitor &Visitor) {  Error RelocationSection::removeSymbols(      function_ref<bool(const Symbol &)> ToRemove) {    for (const Relocation &Reloc : Relocations) -    if (ToRemove(*Reloc.RelocSymbol)) +    if (Reloc.RelocSymbol && ToRemove(*Reloc.RelocSymbol))        return createStringError(            llvm::errc::invalid_argument,            "not stripping symbol '%s' because it is named in a relocation", @@ -903,7 +905,8 @@ Error RelocationSection::removeSymbols(  void RelocationSection::markSymbols() {    for (const Relocation &Reloc : Relocations) -    Reloc.RelocSymbol->Referenced = true; +    if (Reloc.RelocSymbol) +      Reloc.RelocSymbol->Referenced = true;  }  void RelocationSection::replaceSectionReferences( @@ -1006,7 +1009,7 @@ void GnuDebugLinkSection::init(StringRef File) {    Size = alignTo(FileName.size() + 1, 4) + 4;    // The CRC32 will only be aligned if we align the whole section.    Align = 4; -  Type = ELF::SHT_PROGBITS; +  Type = OriginalType = ELF::SHT_PROGBITS;    Name = ".gnu_debuglink";    // For sections not found in segments, OriginalOffset is only used to    // establish the order that sections should go in. By using the maximum @@ -1055,29 +1058,28 @@ void GroupSection::accept(MutableSectionVisitor &Visitor) {  }  // Returns true IFF a section is wholly inside the range of a segment -static bool sectionWithinSegment(const SectionBase &Section, -                                 const Segment &Segment) { +static bool sectionWithinSegment(const SectionBase &Sec, const Segment &Seg) {    // If a section is empty it should be treated like it has a size of 1. This is    // to clarify the case when an empty section lies on a boundary between two    // segments and ensures that the section "belongs" to the second segment and    // not the first. -  uint64_t SecSize = Section.Size ? Section.Size : 1; +  uint64_t SecSize = Sec.Size ? Sec.Size : 1; -  if (Section.Type == SHT_NOBITS) { -    if (!(Section.Flags & SHF_ALLOC)) +  if (Sec.Type == SHT_NOBITS) { +    if (!(Sec.Flags & SHF_ALLOC))        return false; -    bool SectionIsTLS = Section.Flags & SHF_TLS; -    bool SegmentIsTLS = Segment.Type == PT_TLS; +    bool SectionIsTLS = Sec.Flags & SHF_TLS; +    bool SegmentIsTLS = Seg.Type == PT_TLS;      if (SectionIsTLS != SegmentIsTLS)        return false; -    return Segment.VAddr <= Section.Addr && -           Segment.VAddr + Segment.MemSize >= Section.Addr + SecSize; +    return Seg.VAddr <= Sec.Addr && +           Seg.VAddr + Seg.MemSize >= Sec.Addr + SecSize;    } -  return Segment.Offset <= Section.OriginalOffset && -         Segment.Offset + Segment.FileSize >= Section.OriginalOffset + SecSize; +  return Seg.Offset <= Sec.OriginalOffset && +         Seg.Offset + Seg.FileSize >= Sec.OriginalOffset + SecSize;  }  // Returns true IFF a segment's original offset is inside of another segment's @@ -1113,7 +1115,7 @@ void BasicELFBuilder::initFileHeader() {    Obj->OSABI = ELFOSABI_NONE;    Obj->ABIVersion = 0;    Obj->Entry = 0x0; -  Obj->Machine = EMachine; +  Obj->Machine = EM_NONE;    Obj->Version = 1;  } @@ -1141,8 +1143,8 @@ SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) {  }  void BasicELFBuilder::initSections() { -  for (auto &Section : Obj->sections()) -    Section.initialize(Obj->sections()); +  for (SectionBase &Sec : Obj->sections()) +    Sec.initialize(Obj->sections());  }  void BinaryELFBuilder::addData(SymbolTableSection *SymTab) { @@ -1161,11 +1163,12 @@ void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {    Twine Prefix = Twine("_binary_") + SanitizedFilename;    SymTab->addSymbol(Prefix + "_start", STB_GLOBAL, STT_NOTYPE, &DataSection, -                    /*Value=*/0, STV_DEFAULT, 0, 0); +                    /*Value=*/0, NewSymbolVisibility, 0, 0);    SymTab->addSymbol(Prefix + "_end", STB_GLOBAL, STT_NOTYPE, &DataSection, -                    /*Value=*/DataSection.Size, STV_DEFAULT, 0, 0); +                    /*Value=*/DataSection.Size, NewSymbolVisibility, 0, 0);    SymTab->addSymbol(Prefix + "_size", STB_GLOBAL, STT_NOTYPE, nullptr, -                    /*Value=*/DataSection.Size, STV_DEFAULT, SHN_ABS, 0); +                    /*Value=*/DataSection.Size, NewSymbolVisibility, SHN_ABS, +                    0);  }  std::unique_ptr<Object> BinaryELFBuilder::build() { @@ -1255,10 +1258,9 @@ template <class ELFT> void ELFBuilder<ELFT>::findEhdrOffset() {    if (!ExtractPartition)      return; -  for (const SectionBase &Section : Obj.sections()) { -    if (Section.Type == SHT_LLVM_PART_EHDR && -        Section.Name == *ExtractPartition) { -      EhdrOffset = Section.Offset; +  for (const SectionBase &Sec : Obj.sections()) { +    if (Sec.Type == SHT_LLVM_PART_EHDR && Sec.Name == *ExtractPartition) { +      EhdrOffset = Sec.Offset;        return;      }    } @@ -1287,15 +1289,12 @@ void ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &HeadersFile) {      Seg.MemSize = Phdr.p_memsz;      Seg.Align = Phdr.p_align;      Seg.Index = Index++; -    for (SectionBase &Section : Obj.sections()) { -      if (sectionWithinSegment(Section, Seg)) { -        Seg.addSection(&Section); -        if (!Section.ParentSegment || -            Section.ParentSegment->Offset > Seg.Offset) { -          Section.ParentSegment = &Seg; -        } +    for (SectionBase &Sec : Obj.sections()) +      if (sectionWithinSegment(Sec, Seg)) { +        Seg.addSection(&Sec); +        if (!Sec.ParentSegment || Sec.ParentSegment->Offset > Seg.Offset) +          Sec.ParentSegment = &Seg;        } -    }    }    auto &ElfHdr = Obj.ElfHdrSegment; @@ -1422,7 +1421,15 @@ static void initRelocations(RelocationSection *Relocs,      ToAdd.Offset = Rel.r_offset;      getAddend(ToAdd.Addend, Rel);      ToAdd.Type = Rel.getType(false); -    ToAdd.RelocSymbol = SymbolTable->getSymbolByIndex(Rel.getSymbol(false)); + +    if (uint32_t Sym = Rel.getSymbol(false)) { +      if (!SymbolTable) +        error("'" + Relocs->Name + +              "': relocation references symbol with index " + Twine(Sym) + +              ", but there is no symbol table"); +      ToAdd.RelocSymbol = SymbolTable->getSymbolByIndex(Sym); +    } +      Relocs->addRelocation(ToAdd);    }  } @@ -1514,8 +1521,8 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() {      }      auto &Sec = makeSection(Shdr);      Sec.Name = unwrapOrError(ElfFile.getSectionName(&Shdr)); -    Sec.Type = Shdr.sh_type; -    Sec.Flags = Shdr.sh_flags; +    Sec.Type = Sec.OriginalType = Shdr.sh_type; +    Sec.Flags = Sec.OriginalFlags = Shdr.sh_flags;      Sec.Addr = Shdr.sh_addr;      Sec.Offset = Shdr.sh_offset;      Sec.OriginalOffset = Shdr.sh_offset; @@ -1531,7 +1538,22 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() {    }  } -template <class ELFT> void ELFBuilder<ELFT>::readSections() { +template <class ELFT> void ELFBuilder<ELFT>::readSections(bool EnsureSymtab) { +  uint32_t ShstrIndex = ElfFile.getHeader()->e_shstrndx; +  if (ShstrIndex == SHN_XINDEX) +    ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link; + +  if (ShstrIndex == SHN_UNDEF) +    Obj.HadShdrs = false; +  else +    Obj.SectionNames = +        Obj.sections().template getSectionOfType<StringTableSection>( +            ShstrIndex, +            "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + +                " is invalid", +            "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + +                " does not reference a string table"); +    // If a section index table exists we'll need to initialize it before we    // initialize the symbol table because the symbol table might need to    // reference it. @@ -1544,16 +1566,38 @@ template <class ELFT> void ELFBuilder<ELFT>::readSections() {    if (Obj.SymbolTable) {      Obj.SymbolTable->initialize(Obj.sections());      initSymbolTable(Obj.SymbolTable); +  } else if (EnsureSymtab) { +    // Reuse an existing SHT_STRTAB section if it exists. +    StringTableSection *StrTab = nullptr; +    for (auto &Sec : Obj.sections()) { +      if (Sec.Type == ELF::SHT_STRTAB && !(Sec.Flags & SHF_ALLOC)) { +        StrTab = static_cast<StringTableSection *>(&Sec); + +        // Prefer a string table that is not the section header string table, if +        // such a table exists. +        if (Obj.SectionNames != &Sec) +          break; +      } +    } +    if (!StrTab) +      StrTab = &Obj.addSection<StringTableSection>(); + +    SymbolTableSection &SymTab = Obj.addSection<SymbolTableSection>(); +    SymTab.Name = ".symtab"; +    SymTab.Link = StrTab->Index; +    SymTab.initialize(Obj.sections()); +    SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0); +    Obj.SymbolTable = &SymTab;    }    // Now that all sections and symbols have been added we can add    // relocations that reference symbols and set the link and info fields for    // relocation sections. -  for (auto &Section : Obj.sections()) { -    if (&Section == Obj.SymbolTable) +  for (auto &Sec : Obj.sections()) { +    if (&Sec == Obj.SymbolTable)        continue; -    Section.initialize(Obj.sections()); -    if (auto RelSec = dyn_cast<RelocationSection>(&Section)) { +    Sec.initialize(Obj.sections()); +    if (auto RelSec = dyn_cast<RelocationSection>(&Sec)) {        auto Shdr = unwrapOrError(ElfFile.sections()).begin() + RelSec->Index;        if (RelSec->Type == SHT_REL)          initRelocations(RelSec, Obj.SymbolTable, @@ -1561,28 +1605,13 @@ template <class ELFT> void ELFBuilder<ELFT>::readSections() {        else          initRelocations(RelSec, Obj.SymbolTable,                          unwrapOrError(ElfFile.relas(Shdr))); -    } else if (auto GroupSec = dyn_cast<GroupSection>(&Section)) { +    } else if (auto GroupSec = dyn_cast<GroupSection>(&Sec)) {        initGroupSection(GroupSec);      }    } - -  uint32_t ShstrIndex = ElfFile.getHeader()->e_shstrndx; -  if (ShstrIndex == SHN_XINDEX) -    ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link; - -  if (ShstrIndex == SHN_UNDEF) -    Obj.HadShdrs = false; -  else -    Obj.SectionNames = -        Obj.sections().template getSectionOfType<StringTableSection>( -            ShstrIndex, -            "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + -                " is invalid", -            "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + -                " is not a string table");  } -template <class ELFT> void ELFBuilder<ELFT>::build() { +template <class ELFT> void ELFBuilder<ELFT>::build(bool EnsureSymtab) {    readSectionHeaders();    findEhdrOffset(); @@ -1601,7 +1630,7 @@ template <class ELFT> void ELFBuilder<ELFT>::build() {    Obj.Entry = Ehdr.e_entry;    Obj.Flags = Ehdr.e_flags; -  readSections(); +  readSections(EnsureSymtab);    readProgramHeaders(HeadersFile);  } @@ -1609,8 +1638,8 @@ Writer::~Writer() {}  Reader::~Reader() {} -std::unique_ptr<Object> BinaryReader::create() const { -  return BinaryELFBuilder(MInfo.EMachine, MemBuf).build(); +std::unique_ptr<Object> BinaryReader::create(bool /*EnsureSymtab*/) const { +  return BinaryELFBuilder(MemBuf, NewSymbolVisibility).build();  }  Expected<std::vector<IHexRecord>> IHexReader::parse() const { @@ -1639,28 +1668,28 @@ Expected<std::vector<IHexRecord>> IHexReader::parse() const {    return std::move(Records);  } -std::unique_ptr<Object> IHexReader::create() const { +std::unique_ptr<Object> IHexReader::create(bool /*EnsureSymtab*/) const {    std::vector<IHexRecord> Records = unwrapOrError(parse());    return IHexELFBuilder(Records).build();  } -std::unique_ptr<Object> ELFReader::create() const { -  auto Obj = llvm::make_unique<Object>(); +std::unique_ptr<Object> ELFReader::create(bool EnsureSymtab) const { +  auto Obj = std::make_unique<Object>();    if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {      ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition); -    Builder.build(); +    Builder.build(EnsureSymtab);      return Obj;    } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {      ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition); -    Builder.build(); +    Builder.build(EnsureSymtab);      return Obj;    } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {      ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition); -    Builder.build(); +    Builder.build(EnsureSymtab);      return Obj;    } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {      ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition); -    Builder.build(); +    Builder.build(EnsureSymtab);      return Obj;    }    error("invalid file type"); @@ -1693,7 +1722,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {    Ehdr.e_ehsize = sizeof(Elf_Ehdr);    if (WriteSectionHeaders && Obj.sections().size() != 0) {      Ehdr.e_shentsize = sizeof(Elf_Shdr); -    Ehdr.e_shoff = Obj.SHOffset; +    Ehdr.e_shoff = Obj.SHOff;      // """      // If the number of sections is greater than or equal to      // SHN_LORESERVE (0xff00), this member has the value zero and the actual @@ -1732,7 +1761,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {    // This reference serves to write the dummy section header at the begining    // of the file. It is not used for anything else    Elf_Shdr &Shdr = -      *reinterpret_cast<Elf_Shdr *>(Buf.getBufferStart() + Obj.SHOffset); +      *reinterpret_cast<Elf_Shdr *>(Buf.getBufferStart() + Obj.SHOff);    Shdr.sh_name = 0;    Shdr.sh_type = SHT_NULL;    Shdr.sh_flags = 0; @@ -1768,10 +1797,9 @@ template <class ELFT> void ELFWriter<ELFT>::writeSectionData() {  template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {    for (Segment &Seg : Obj.segments()) { -    uint8_t *B = Buf.getBufferStart() + Seg.Offset; -    assert(Seg.FileSize == Seg.getContents().size() && -           "Segment size must match contents size"); -    std::memcpy(B, Seg.getContents().data(), Seg.FileSize); +    size_t Size = std::min<size_t>(Seg.FileSize, Seg.getContents().size()); +    std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(), +                Size);    }    // Iterate over removed sections and overwrite their old data with zeroes. @@ -1786,8 +1814,10 @@ template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {  }  template <class ELFT> -ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH) -    : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs) {} +ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH, +                           bool OnlyKeepDebug) +    : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs), +      OnlyKeepDebug(OnlyKeepDebug) {}  Error Object::removeSections(bool AllowBrokenLinks,      std::function<bool(const SectionBase &)> ToRemove) { @@ -1862,26 +1892,13 @@ void Object::sortSections() {    });  } -static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) { -  // Calculate Diff such that (Offset + Diff) & -Align == Addr & -Align. -  if (Align == 0) -    Align = 1; -  auto Diff = -      static_cast<int64_t>(Addr % Align) - static_cast<int64_t>(Offset % Align); -  // We only want to add to Offset, however, so if Diff < 0 we can add Align and -  // (Offset + Diff) & -Align == Addr & -Align will still hold. -  if (Diff < 0) -    Diff += Align; -  return Offset + Diff; -} -  // Orders segments such that if x = y->ParentSegment then y comes before x.  static void orderSegments(std::vector<Segment *> &Segments) {    llvm::stable_sort(Segments, compareSegmentsByOffset);  }  // This function finds a consistent layout for a list of segments starting from -// an Offset. It assumes that Segments have been sorted by OrderSegments and +// an Offset. It assumes that Segments have been sorted by orderSegments and  // returns an Offset one past the end of the last segment.  static uint64_t layoutSegments(std::vector<Segment *> &Segments,                                 uint64_t Offset) { @@ -1902,8 +1919,8 @@ static uint64_t layoutSegments(std::vector<Segment *> &Segments,        Seg->Offset =            Parent->Offset + Seg->OriginalOffset - Parent->OriginalOffset;      } else { -      Offset = alignToAddr(Offset, Seg->VAddr, Seg->Align); -      Seg->Offset = Offset; +      Seg->Offset = +          alignTo(Offset, std::max<uint64_t>(Seg->Align, 1), Seg->VAddr);      }      Offset = std::max(Offset, Seg->Offset + Seg->FileSize);    } @@ -1925,22 +1942,94 @@ static uint64_t layoutSections(Range Sections, uint64_t Offset) {    // of the segment we can assign a new offset to the section. For sections not    // covered by segments we can just bump Offset to the next valid location.    uint32_t Index = 1; -  for (auto &Section : Sections) { -    Section.Index = Index++; -    if (Section.ParentSegment != nullptr) { -      auto Segment = *Section.ParentSegment; -      Section.Offset = -          Segment.Offset + (Section.OriginalOffset - Segment.OriginalOffset); +  for (auto &Sec : Sections) { +    Sec.Index = Index++; +    if (Sec.ParentSegment != nullptr) { +      auto Segment = *Sec.ParentSegment; +      Sec.Offset = +          Segment.Offset + (Sec.OriginalOffset - Segment.OriginalOffset);      } else { -      Offset = alignTo(Offset, Section.Align == 0 ? 1 : Section.Align); -      Section.Offset = Offset; -      if (Section.Type != SHT_NOBITS) -        Offset += Section.Size; +      Offset = alignTo(Offset, Sec.Align == 0 ? 1 : Sec.Align); +      Sec.Offset = Offset; +      if (Sec.Type != SHT_NOBITS) +        Offset += Sec.Size;      }    }    return Offset;  } +// Rewrite sh_offset after some sections are changed to SHT_NOBITS and thus +// occupy no space in the file. +static uint64_t layoutSectionsForOnlyKeepDebug(Object &Obj, uint64_t Off) { +  uint32_t Index = 1; +  for (auto &Sec : Obj.sections()) { +    Sec.Index = Index++; + +    auto *FirstSec = Sec.ParentSegment && Sec.ParentSegment->Type == PT_LOAD +                         ? Sec.ParentSegment->firstSection() +                         : nullptr; + +    // The first section in a PT_LOAD has to have congruent offset and address +    // modulo the alignment, which usually equals the maximum page size. +    if (FirstSec && FirstSec == &Sec) +      Off = alignTo(Off, Sec.ParentSegment->Align, Sec.Addr); + +    // sh_offset is not significant for SHT_NOBITS sections, but the congruence +    // rule must be followed if it is the first section in a PT_LOAD. Do not +    // advance Off. +    if (Sec.Type == SHT_NOBITS) { +      Sec.Offset = Off; +      continue; +    } + +    if (!FirstSec) { +      // FirstSec being nullptr generally means that Sec does not have the +      // SHF_ALLOC flag. +      Off = Sec.Align ? alignTo(Off, Sec.Align) : Off; +    } else if (FirstSec != &Sec) { +      // The offset is relative to the first section in the PT_LOAD segment. Use +      // sh_offset for non-SHF_ALLOC sections. +      Off = Sec.OriginalOffset - FirstSec->OriginalOffset + FirstSec->Offset; +    } +    Sec.Offset = Off; +    Off += Sec.Size; +  } +  return Off; +} + +// Rewrite p_offset and p_filesz of non-empty non-PT_PHDR segments after +// sh_offset values have been updated. +static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments, +                                               uint64_t HdrEnd) { +  uint64_t MaxOffset = 0; +  for (Segment *Seg : Segments) { +    const SectionBase *FirstSec = Seg->firstSection(); +    if (Seg->Type == PT_PHDR || !FirstSec) +      continue; + +    uint64_t Offset = FirstSec->Offset; +    uint64_t FileSize = 0; +    for (const SectionBase *Sec : Seg->Sections) { +      uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size; +      if (Sec->Offset + Size > Offset) +        FileSize = std::max(FileSize, Sec->Offset + Size - Offset); +    } + +    // If the segment includes EHDR and program headers, don't make it smaller +    // than the headers. +    if (Seg->Offset < HdrEnd && HdrEnd <= Seg->Offset + Seg->FileSize) { +      FileSize += Offset - Seg->Offset; +      Offset = Seg->Offset; +      FileSize = std::max(FileSize, HdrEnd - Offset); +    } + +    Seg->Offset = Offset; +    Seg->FileSize = FileSize; +    MaxOffset = std::max(MaxOffset, Offset + FileSize); +  } +  return MaxOffset; +} +  template <class ELFT> void ELFWriter<ELFT>::initEhdrSegment() {    Segment &ElfHdr = Obj.ElfHdrSegment;    ElfHdr.Type = PT_PHDR; @@ -1961,26 +2050,38 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() {    OrderedSegments.push_back(&Obj.ElfHdrSegment);    OrderedSegments.push_back(&Obj.ProgramHdrSegment);    orderSegments(OrderedSegments); -  // Offset is used as the start offset of the first segment to be laid out. -  // Since the ELF Header (ElfHdrSegment) must be at the start of the file, -  // we start at offset 0. -  uint64_t Offset = 0; -  Offset = layoutSegments(OrderedSegments, Offset); -  Offset = layoutSections(Obj.sections(), Offset); + +  uint64_t Offset; +  if (OnlyKeepDebug) { +    // For --only-keep-debug, the sections that did not preserve contents were +    // changed to SHT_NOBITS. We now rewrite sh_offset fields of sections, and +    // then rewrite p_offset/p_filesz of program headers. +    uint64_t HdrEnd = +        sizeof(Elf_Ehdr) + llvm::size(Obj.segments()) * sizeof(Elf_Phdr); +    Offset = layoutSectionsForOnlyKeepDebug(Obj, HdrEnd); +    Offset = std::max(Offset, +                      layoutSegmentsForOnlyKeepDebug(OrderedSegments, HdrEnd)); +  } else { +    // Offset is used as the start offset of the first segment to be laid out. +    // Since the ELF Header (ElfHdrSegment) must be at the start of the file, +    // we start at offset 0. +    Offset = layoutSegments(OrderedSegments, 0); +    Offset = layoutSections(Obj.sections(), Offset); +  }    // If we need to write the section header table out then we need to align the    // Offset so that SHOffset is valid.    if (WriteSectionHeaders)      Offset = alignTo(Offset, sizeof(Elf_Addr)); -  Obj.SHOffset = Offset; +  Obj.SHOff = Offset;  }  template <class ELFT> size_t ELFWriter<ELFT>::totalSize() const {    // We already have the section header offset so we can calculate the total    // size by just adding up the size of each section header.    if (!WriteSectionHeaders) -    return Obj.SHOffset; +    return Obj.SHOff;    size_t ShdrCount = Obj.sections().size() + 1; // Includes null shdr. -  return Obj.SHOffset + ShdrCount * sizeof(Elf_Shdr); +  return Obj.SHOff + ShdrCount * sizeof(Elf_Shdr);  }  template <class ELFT> Error ELFWriter<ELFT>::write() { @@ -1995,6 +2096,25 @@ template <class ELFT> Error ELFWriter<ELFT>::write() {    return Buf.commit();  } +static Error removeUnneededSections(Object &Obj) { +  // We can remove an empty symbol table from non-relocatable objects. +  // Relocatable objects typically have relocation sections whose +  // sh_link field points to .symtab, so we can't remove .symtab +  // even if it is empty. +  if (Obj.isRelocatable() || Obj.SymbolTable == nullptr || +      !Obj.SymbolTable->empty()) +    return Error::success(); + +  // .strtab can be used for section names. In such a case we shouldn't +  // remove it. +  auto *StrTab = Obj.SymbolTable->getStrTab() == Obj.SectionNames +                     ? nullptr +                     : Obj.SymbolTable->getStrTab(); +  return Obj.removeSections(false, [&](const SectionBase &Sec) { +    return &Sec == Obj.SymbolTable || &Sec == StrTab; +  }); +} +  template <class ELFT> Error ELFWriter<ELFT>::finalize() {    // It could happen that SectionNames has been removed and yet the user wants    // a section header table output. We need to throw an error if a user tries @@ -2004,6 +2124,8 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {                               "cannot write section header table because "                               "section header string table was removed"); +  if (Error E = removeUnneededSections(Obj)) +    return E;    Obj.sortSections();    // We need to assign indexes before we perform layout because we need to know @@ -2045,9 +2167,8 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {    // Make sure we add the names of all the sections. Importantly this must be    // done after we decide to add or remove SectionIndexes.    if (Obj.SectionNames != nullptr) -    for (const auto &Section : Obj.sections()) { -      Obj.SectionNames->addString(Section.Name); -    } +    for (const SectionBase &Sec : Obj.sections()) +      Obj.SectionNames->addString(Sec.Name);    initEhdrSegment(); @@ -2055,8 +2176,8 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {    // Also, the output arch may not be the same as the input arch, so fix up    // size-related fields before doing layout calculations.    uint64_t Index = 0; -  auto SecSizer = llvm::make_unique<ELFSectionSizer<ELFT>>(); -  for (auto &Sec : Obj.sections()) { +  auto SecSizer = std::make_unique<ELFSectionSizer<ELFT>>(); +  for (SectionBase &Sec : Obj.sections()) {      Sec.Index = Index++;      Sec.accept(*SecSizer);    } @@ -2082,40 +2203,36 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {    // Finally now that all offsets and indexes have been set we can finalize any    // remaining issues. -  uint64_t Offset = Obj.SHOffset + sizeof(Elf_Shdr); -  for (SectionBase &Section : Obj.sections()) { -    Section.HeaderOffset = Offset; +  uint64_t Offset = Obj.SHOff + sizeof(Elf_Shdr); +  for (SectionBase &Sec : Obj.sections()) { +    Sec.HeaderOffset = Offset;      Offset += sizeof(Elf_Shdr);      if (WriteSectionHeaders) -      Section.NameIndex = Obj.SectionNames->findIndex(Section.Name); -    Section.finalize(); +      Sec.NameIndex = Obj.SectionNames->findIndex(Sec.Name); +    Sec.finalize();    }    if (Error E = Buf.allocate(totalSize()))      return E; -  SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(Buf); +  SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf);    return Error::success();  }  Error BinaryWriter::write() { -  for (auto &Section : Obj.sections()) -    if (Section.Flags & SHF_ALLOC) -      Section.accept(*SecWriter); +  for (const SectionBase &Sec : Obj.allocSections()) +    Sec.accept(*SecWriter);    return Buf.commit();  }  Error BinaryWriter::finalize() { -  // TODO: Create a filter range to construct OrderedSegments from so that this -  // code can be deduped with assignOffsets above. This should also solve the -  // todo below for LayoutSections.    // We need a temporary list of segments that has a special order to it    // so that we know that anytime ->ParentSegment is set that segment has    // already had it's offset properly set. We only want to consider the segments    // that will affect layout of allocated sections so we only add those.    std::vector<Segment *> OrderedSegments; -  for (SectionBase &Section : Obj.sections()) -    if ((Section.Flags & SHF_ALLOC) != 0 && Section.ParentSegment != nullptr) -      OrderedSegments.push_back(Section.ParentSegment); +  for (const SectionBase &Sec : Obj.allocSections()) +    if (Sec.ParentSegment != nullptr) +      OrderedSegments.push_back(Sec.ParentSegment);    // For binary output, we're going to use physical addresses instead of    // virtual addresses, since a binary output is used for cases like ROM @@ -2130,56 +2247,38 @@ Error BinaryWriter::finalize() {    llvm::stable_sort(OrderedSegments, compareSegmentsByPAddr);    // Because we add a ParentSegment for each section we might have duplicate -  // segments in OrderedSegments. If there were duplicates then LayoutSegments +  // segments in OrderedSegments. If there were duplicates then layoutSegments    // would do very strange things.    auto End =        std::unique(std::begin(OrderedSegments), std::end(OrderedSegments));    OrderedSegments.erase(End, std::end(OrderedSegments)); -  uint64_t Offset = 0; - -  // Modify the first segment so that there is no gap at the start. This allows -  // our layout algorithm to proceed as expected while not writing out the gap -  // at the start. -  if (!OrderedSegments.empty()) { -    Segment *Seg = OrderedSegments[0]; -    const SectionBase *Sec = Seg->firstSection(); -    auto Diff = Sec->OriginalOffset - Seg->OriginalOffset; -    Seg->OriginalOffset += Diff; -    // The size needs to be shrunk as well. -    Seg->FileSize -= Diff; -    // The PAddr needs to be increased to remove the gap before the first -    // section. -    Seg->PAddr += Diff; -    uint64_t LowestPAddr = Seg->PAddr; -    for (Segment *Segment : OrderedSegments) { -      Segment->Offset = Segment->PAddr - LowestPAddr; -      Offset = std::max(Offset, Segment->Offset + Segment->FileSize); -    } +  // Compute the section LMA based on its sh_offset and the containing segment's +  // p_offset and p_paddr. Also compute the minimum LMA of all sections as +  // MinAddr. In the output, the contents between address 0 and MinAddr will be +  // skipped. +  uint64_t MinAddr = UINT64_MAX; +  for (SectionBase &Sec : Obj.allocSections()) { +    if (Sec.ParentSegment != nullptr) +      Sec.Addr = +          Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr; +    MinAddr = std::min(MinAddr, Sec.Addr);    } -  // TODO: generalize LayoutSections to take a range. Pass a special range -  // constructed from an iterator that skips values for which a predicate does -  // not hold. Then pass such a range to LayoutSections instead of constructing -  // AllocatedSections here. -  std::vector<SectionBase *> AllocatedSections; -  for (SectionBase &Section : Obj.sections()) -    if (Section.Flags & SHF_ALLOC) -      AllocatedSections.push_back(&Section); -  layoutSections(make_pointee_range(AllocatedSections), Offset); -    // Now that every section has been laid out we just need to compute the total    // file size. This might not be the same as the offset returned by -  // LayoutSections, because we want to truncate the last segment to the end of +  // layoutSections, because we want to truncate the last segment to the end of    // its last section, to match GNU objcopy's behaviour.    TotalSize = 0; -  for (SectionBase *Section : AllocatedSections) -    if (Section->Type != SHT_NOBITS) -      TotalSize = std::max(TotalSize, Section->Offset + Section->Size); +  for (SectionBase &Sec : Obj.allocSections()) { +    Sec.Offset = Sec.Addr - MinAddr; +    if (Sec.Type != SHT_NOBITS) +      TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size); +  }    if (Error E = Buf.allocate(TotalSize))      return E; -  SecWriter = llvm::make_unique<BinarySectionWriter>(Buf); +  SecWriter = std::make_unique<BinarySectionWriter>(Buf);    return Error::success();  } @@ -2259,17 +2358,17 @@ Error IHexWriter::finalize() {    // If any section we're to write has segment then we    // switch to using physical addresses. Otherwise we    // use section virtual address. -  for (auto &Section : Obj.sections()) -    if (ShouldWrite(Section) && IsInPtLoad(Section)) { +  for (const SectionBase &Sec : Obj.sections()) +    if (ShouldWrite(Sec) && IsInPtLoad(Sec)) {        UseSegments = true;        break;      } -  for (auto &Section : Obj.sections()) -    if (ShouldWrite(Section) && (!UseSegments || IsInPtLoad(Section))) { -      if (Error E = checkSection(Section)) +  for (const SectionBase &Sec : Obj.sections()) +    if (ShouldWrite(Sec) && (!UseSegments || IsInPtLoad(Sec))) { +      if (Error E = checkSection(Sec))          return E; -      Sections.insert(&Section); +      Sections.insert(&Sec);      }    IHexSectionWriterBase LengthCalc(Buf); diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h index f3df93b9662f..97702a66bc47 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h @@ -57,8 +57,8 @@ public:        : Sections(Secs) {}    SectionTableRef(const SectionTableRef &) = default; -  iterator begin() { return iterator(Sections.data()); } -  iterator end() { return iterator(Sections.data() + Sections.size()); } +  iterator begin() const { return iterator(Sections.data()); } +  iterator end() const { return iterator(Sections.data() + Sections.size()); }    size_t size() const { return Sections.size(); }    SectionBase *getSection(uint32_t Index, Twine ErrMsg); @@ -342,16 +342,20 @@ public:    virtual ~ELFWriter() {}    bool WriteSectionHeaders; +  // For --only-keep-debug, select an alternative section/segment layout +  // algorithm. +  bool OnlyKeepDebug; +    Error finalize() override;    Error write() override; -  ELFWriter(Object &Obj, Buffer &Buf, bool WSH); +  ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool OnlyKeepDebug);  };  class BinaryWriter : public Writer {  private:    std::unique_ptr<BinarySectionWriter> SecWriter; -  uint64_t TotalSize; +  uint64_t TotalSize = 0;  public:    ~BinaryWriter() {} @@ -366,7 +370,7 @@ class IHexWriter : public Writer {    };    std::set<const SectionBase *, SectionCompare> Sections; -  size_t TotalSize; +  size_t TotalSize = 0;    Error checkSection(const SectionBase &Sec);    uint64_t writeEntryPointRecord(uint8_t *Buf); @@ -383,11 +387,14 @@ class SectionBase {  public:    std::string Name;    Segment *ParentSegment = nullptr; -  uint64_t HeaderOffset; -  uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max(); -  uint32_t Index; +  uint64_t HeaderOffset = 0; +  uint32_t Index = 0;    bool HasSymbol = false; +  uint64_t OriginalFlags = 0; +  uint64_t OriginalType = ELF::SHT_NULL; +  uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max(); +    uint64_t Addr = 0;    uint64_t Align = 1;    uint32_t EntrySize = 0; @@ -432,25 +439,24 @@ private:      }    }; -  std::set<const SectionBase *, SectionCompare> Sections; -  public: -  uint32_t Type; -  uint32_t Flags; -  uint64_t Offset; -  uint64_t VAddr; -  uint64_t PAddr; -  uint64_t FileSize; -  uint64_t MemSize; -  uint64_t Align; - -  uint32_t Index; -  uint64_t OriginalOffset; +  uint32_t Type = 0; +  uint32_t Flags = 0; +  uint64_t Offset = 0; +  uint64_t VAddr = 0; +  uint64_t PAddr = 0; +  uint64_t FileSize = 0; +  uint64_t MemSize = 0; +  uint64_t Align = 0; + +  uint32_t Index = 0; +  uint64_t OriginalOffset = 0;    Segment *ParentSegment = nullptr;    ArrayRef<uint8_t> Contents; +  std::set<const SectionBase *, SectionCompare> Sections;    explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {} -  Segment() {} +  Segment() = default;    const SectionBase *firstSection() const {      if (!Sections.empty()) @@ -490,7 +496,7 @@ public:    OwnedDataSection(StringRef SecName, ArrayRef<uint8_t> Data)        : Data(std::begin(Data), std::end(Data)) {      Name = SecName.str(); -    Type = ELF::SHT_PROGBITS; +    Type = OriginalType = ELF::SHT_PROGBITS;      Size = Data.size();      OriginalOffset = std::numeric_limits<uint64_t>::max();    } @@ -498,9 +504,9 @@ public:    OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags,                     uint64_t SecOff) {      Name = SecName.str(); -    Type = ELF::SHT_PROGBITS; +    Type = OriginalType = ELF::SHT_PROGBITS;      Addr = SecAddr; -    Flags = SecFlags; +    Flags = OriginalFlags = SecFlags;      OriginalOffset = SecOff;    } @@ -530,7 +536,7 @@ public:    void accept(MutableSectionVisitor &Visitor) override;    static bool classof(const SectionBase *S) { -    return (S->Flags & ELF::SHF_COMPRESSED) || +    return (S->OriginalFlags & ELF::SHF_COMPRESSED) ||             (StringRef(S->Name).startswith(".zdebug"));    }  }; @@ -543,7 +549,7 @@ public:        : SectionBase(Sec) {      Size = Sec.getDecompressedSize();      Align = Sec.getDecompressedAlign(); -    Flags = (Flags & ~ELF::SHF_COMPRESSED); +    Flags = OriginalFlags = (Flags & ~ELF::SHF_COMPRESSED);      if (StringRef(Name).startswith(".zdebug"))        Name = "." + Name.substr(2);    } @@ -567,7 +573,7 @@ class StringTableSection : public SectionBase {  public:    StringTableSection() : StrTabBuilder(StringTableBuilder::ELF) { -    Type = ELF::SHT_STRTAB; +    Type = OriginalType = ELF::SHT_STRTAB;    }    void addString(StringRef Name); @@ -577,9 +583,9 @@ public:    void accept(MutableSectionVisitor &Visitor) override;    static bool classof(const SectionBase *S) { -    if (S->Flags & ELF::SHF_ALLOC) +    if (S->OriginalFlags & ELF::SHF_ALLOC)        return false; -    return S->Type == ELF::SHT_STRTAB; +    return S->OriginalType == ELF::SHT_STRTAB;    }  }; @@ -648,7 +654,7 @@ public:      Name = ".symtab_shndx";      Align = 4;      EntrySize = 4; -    Type = ELF::SHT_SYMTAB_SHNDX; +    Type = OriginalType = ELF::SHT_SYMTAB_SHNDX;    }  }; @@ -666,7 +672,7 @@ protected:    using SymPtr = std::unique_ptr<Symbol>;  public: -  SymbolTableSection() { Type = ELF::SHT_SYMTAB; } +  SymbolTableSection() { Type = OriginalType = ELF::SHT_SYMTAB; }    void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn,                   uint64_t Value, uint8_t Visibility, uint16_t Shndx, @@ -695,7 +701,7 @@ public:        const DenseMap<SectionBase *, SectionBase *> &FromTo) override;    static bool classof(const SectionBase *S) { -    return S->Type == ELF::SHT_SYMTAB; +    return S->OriginalType == ELF::SHT_SYMTAB;    }  }; @@ -724,7 +730,7 @@ public:    void setSection(SectionBase *Sec) { SecToApplyRel = Sec; }    static bool classof(const SectionBase *S) { -    return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; +    return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;    }  }; @@ -762,9 +768,9 @@ public:        const DenseMap<SectionBase *, SectionBase *> &FromTo) override;    static bool classof(const SectionBase *S) { -    if (S->Flags & ELF::SHF_ALLOC) +    if (S->OriginalFlags & ELF::SHF_ALLOC)        return false; -    return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; +    return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;    }  }; @@ -799,7 +805,7 @@ public:        const DenseMap<SectionBase *, SectionBase *> &FromTo) override;    static bool classof(const SectionBase *S) { -    return S->Type == ELF::SHT_GROUP; +    return S->OriginalType == ELF::SHT_GROUP;    }  }; @@ -808,7 +814,7 @@ public:    explicit DynamicSymbolTableSection(ArrayRef<uint8_t> Data) : Section(Data) {}    static bool classof(const SectionBase *S) { -    return S->Type == ELF::SHT_DYNSYM; +    return S->OriginalType == ELF::SHT_DYNSYM;    }  }; @@ -817,7 +823,7 @@ public:    explicit DynamicSection(ArrayRef<uint8_t> Data) : Section(Data) {}    static bool classof(const SectionBase *S) { -    return S->Type == ELF::SHT_DYNAMIC; +    return S->OriginalType == ELF::SHT_DYNAMIC;    }  }; @@ -838,9 +844,9 @@ public:        function_ref<bool(const SectionBase *)> ToRemove) override;    static bool classof(const SectionBase *S) { -    if (!(S->Flags & ELF::SHF_ALLOC)) +    if (!(S->OriginalFlags & ELF::SHF_ALLOC))        return false; -    return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; +    return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;    }  }; @@ -863,7 +869,7 @@ public:  class Reader {  public:    virtual ~Reader(); -  virtual std::unique_ptr<Object> create() const = 0; +  virtual std::unique_ptr<Object> create(bool EnsureSymtab) const = 0;  };  using object::Binary; @@ -873,7 +879,6 @@ using object::OwningBinary;  class BasicELFBuilder {  protected: -  uint16_t EMachine;    std::unique_ptr<Object> Obj;    void initFileHeader(); @@ -883,17 +888,18 @@ protected:    void initSections();  public: -  BasicELFBuilder(uint16_t EM) -      : EMachine(EM), Obj(llvm::make_unique<Object>()) {} +  BasicELFBuilder() : Obj(std::make_unique<Object>()) {}  };  class BinaryELFBuilder : public BasicELFBuilder {    MemoryBuffer *MemBuf; +  uint8_t NewSymbolVisibility;    void addData(SymbolTableSection *SymTab);  public: -  BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB) -      : BasicELFBuilder(EM), MemBuf(MB) {} +  BinaryELFBuilder(MemoryBuffer *MB, uint8_t NewSymbolVisibility) +      : BasicELFBuilder(), MemBuf(MB), +        NewSymbolVisibility(NewSymbolVisibility) {}    std::unique_ptr<Object> build();  }; @@ -905,7 +911,7 @@ class IHexELFBuilder : public BasicELFBuilder {  public:    IHexELFBuilder(const std::vector<IHexRecord> &Records) -      : BasicELFBuilder(ELF::EM_386), Records(Records) {} +      : BasicELFBuilder(), Records(Records) {}    std::unique_ptr<Object> build();  }; @@ -926,7 +932,7 @@ private:    void initGroupSection(GroupSection *GroupSec);    void initSymbolTable(SymbolTableSection *SymTab);    void readSectionHeaders(); -  void readSections(); +  void readSections(bool EnsureSymtab);    void findEhdrOffset();    SectionBase &makeSection(const Elf_Shdr &Shdr); @@ -936,17 +942,17 @@ public:        : ElfFile(*ElfObj.getELFFile()), Obj(Obj),          ExtractPartition(ExtractPartition) {} -  void build(); +  void build(bool EnsureSymtab);  };  class BinaryReader : public Reader { -  const MachineInfo &MInfo;    MemoryBuffer *MemBuf; +  uint8_t NewSymbolVisibility;  public: -  BinaryReader(const MachineInfo &MI, MemoryBuffer *MB) -      : MInfo(MI), MemBuf(MB) {} -  std::unique_ptr<Object> create() const override; +  BinaryReader(MemoryBuffer *MB, const uint8_t NewSymbolVisibility) +      : MemBuf(MB), NewSymbolVisibility(NewSymbolVisibility) {} +  std::unique_ptr<Object> create(bool EnsureSymtab) const override;  };  class IHexReader : public Reader { @@ -968,7 +974,7 @@ class IHexReader : public Reader {  public:    IHexReader(MemoryBuffer *MB) : MemBuf(MB) {} -  std::unique_ptr<Object> create() const override; +  std::unique_ptr<Object> create(bool EnsureSymtab) const override;  };  class ELFReader : public Reader { @@ -976,7 +982,7 @@ class ELFReader : public Reader {    Optional<StringRef> ExtractPartition;  public: -  std::unique_ptr<Object> create() const override; +  std::unique_ptr<Object> create(bool EnsureSymtab) const override;    explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition)        : Bin(B), ExtractPartition(ExtractPartition) {}  }; @@ -990,6 +996,10 @@ private:    std::vector<SegPtr> Segments;    std::vector<SecPtr> RemovedSections; +  static bool sectionIsAlloc(const SectionBase &Sec) { +    return Sec.Flags & ELF::SHF_ALLOC; +  }; +  public:    template <class T>    using Range = iterator_range< @@ -1011,13 +1021,14 @@ public:    uint8_t OSABI;    uint8_t ABIVersion;    uint64_t Entry; -  uint64_t SHOffset; +  uint64_t SHOff;    uint32_t Type;    uint32_t Machine;    uint32_t Version;    uint32_t Flags;    bool HadShdrs = true; +  bool MustBeRelocatable = false;    StringTableSection *SectionNames = nullptr;    SymbolTableSection *SymbolTable = nullptr;    SectionIndexSection *SectionIndexTable = nullptr; @@ -1027,6 +1038,13 @@ public:    ConstRange<SectionBase> sections() const {      return make_pointee_range(Sections);    } +  iterator_range< +      filter_iterator<pointee_iterator<std::vector<SecPtr>::const_iterator>, +                      decltype(§ionIsAlloc)>> +  allocSections() const { +    return make_filter_range(make_pointee_range(Sections), sectionIsAlloc); +  } +    SectionBase *findSection(StringRef Name) {      auto SecIt =          find_if(Sections, [&](const SecPtr &Sec) { return Sec->Name == Name; }); @@ -1041,16 +1059,20 @@ public:                         std::function<bool(const SectionBase &)> ToRemove);    Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove);    template <class T, class... Ts> T &addSection(Ts &&... Args) { -    auto Sec = llvm::make_unique<T>(std::forward<Ts>(Args)...); +    auto Sec = std::make_unique<T>(std::forward<Ts>(Args)...);      auto Ptr = Sec.get(); +    MustBeRelocatable |= isa<RelocationSection>(*Ptr);      Sections.emplace_back(std::move(Sec));      Ptr->Index = Sections.size();      return *Ptr;    }    Segment &addSegment(ArrayRef<uint8_t> Data) { -    Segments.emplace_back(llvm::make_unique<Segment>(Data)); +    Segments.emplace_back(std::make_unique<Segment>(Data));      return *Segments.back();    } +  bool isRelocatable() const { +    return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable; +  }  };  } // end namespace elf diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/InstallNameToolOpts.td b/contrib/llvm-project/llvm/tools/llvm-objcopy/InstallNameToolOpts.td new file mode 100644 index 000000000000..35047a57994c --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/InstallNameToolOpts.td @@ -0,0 +1,22 @@ +//===-- InstallNameToolOpts.td - llvm-install-name-tool options  --------*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file describes the command line options of llvm-install-name. +// +//===----------------------------------------------------------------------===// + +include "llvm/Option/OptParser.td" + +def help : Flag<["--"], "help">; +def h : Flag<["-"], "h">, Alias<help>; + +def add_rpath : Option<["-", "--"], "add_rpath", KIND_SEPARATE>, +                HelpText<"Add new rpath">; + +def version : Flag<["--"], "version">, +              HelpText<"Print the version and exit.">; diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp new file mode 100644 index 000000000000..380f2e989fe4 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp @@ -0,0 +1,355 @@ +//===- MachOLayoutBuilder.cpp -----------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "MachOLayoutBuilder.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { +namespace objcopy { +namespace macho { + +uint32_t MachOLayoutBuilder::computeSizeOfCmds() const { +  uint32_t Size = 0; +  for (const auto &LC : O.LoadCommands) { +    const MachO::macho_load_command &MLC = LC.MachOLoadCommand; +    auto cmd = MLC.load_command_data.cmd; +    switch (cmd) { +    case MachO::LC_SEGMENT: +      Size += sizeof(MachO::segment_command) + +              sizeof(MachO::section) * LC.Sections.size(); +      continue; +    case MachO::LC_SEGMENT_64: +      Size += sizeof(MachO::segment_command_64) + +              sizeof(MachO::section_64) * LC.Sections.size(); +      continue; +    } + +    switch (cmd) { +#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct)                         \ +  case MachO::LCName:                                                          \ +    Size += sizeof(MachO::LCStruct) + LC.Payload.size();                       \ +    break; +#include "llvm/BinaryFormat/MachO.def" +#undef HANDLE_LOAD_COMMAND +    } +  } + +  return Size; +} + +void MachOLayoutBuilder::constructStringTable() { +  for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols) +    StrTableBuilder.add(Sym->Name); +  StrTableBuilder.finalize(); +} + +void MachOLayoutBuilder::updateSymbolIndexes() { +  uint32_t Index = 0; +  for (auto &Symbol : O.SymTable.Symbols) +    Symbol->Index = Index++; +} + +// Updates the index and the number of local/external/undefined symbols. +void MachOLayoutBuilder::updateDySymTab(MachO::macho_load_command &MLC) { +  assert(MLC.load_command_data.cmd == MachO::LC_DYSYMTAB); +  // Make sure that nlist entries in the symbol table are sorted by the those +  // types. The order is: local < defined external < undefined external. +  assert(std::is_sorted(O.SymTable.Symbols.begin(), O.SymTable.Symbols.end(), +                        [](const std::unique_ptr<SymbolEntry> &A, +                           const std::unique_ptr<SymbolEntry> &B) { +                          bool AL = A->isLocalSymbol(), BL = B->isLocalSymbol(); +                          if (AL != BL) +                            return AL; +                          return !AL && !A->isUndefinedSymbol() && +                                         B->isUndefinedSymbol(); +                        }) && +         "Symbols are not sorted by their types."); + +  uint32_t NumLocalSymbols = 0; +  auto Iter = O.SymTable.Symbols.begin(); +  auto End = O.SymTable.Symbols.end(); +  for (; Iter != End; ++Iter) { +    if ((*Iter)->isExternalSymbol()) +      break; + +    ++NumLocalSymbols; +  } + +  uint32_t NumExtDefSymbols = 0; +  for (; Iter != End; ++Iter) { +    if ((*Iter)->isUndefinedSymbol()) +      break; + +    ++NumExtDefSymbols; +  } + +  MLC.dysymtab_command_data.ilocalsym = 0; +  MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols; +  MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols; +  MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols; +  MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols; +  MLC.dysymtab_command_data.nundefsym = +      O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols); +} + +// Recomputes and updates offset and size fields in load commands and sections +// since they could be modified. +uint64_t MachOLayoutBuilder::layoutSegments() { +  auto HeaderSize = +      Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); +  const bool IsObjectFile = +      O.Header.FileType == MachO::HeaderFileType::MH_OBJECT; +  uint64_t Offset = IsObjectFile ? (HeaderSize + O.Header.SizeOfCmds) : 0; +  for (auto &LC : O.LoadCommands) { +    auto &MLC = LC.MachOLoadCommand; +    StringRef Segname; +    uint64_t SegmentVmAddr; +    uint64_t SegmentVmSize; +    switch (MLC.load_command_data.cmd) { +    case MachO::LC_SEGMENT: +      SegmentVmAddr = MLC.segment_command_data.vmaddr; +      SegmentVmSize = MLC.segment_command_data.vmsize; +      Segname = StringRef(MLC.segment_command_data.segname, +                          strnlen(MLC.segment_command_data.segname, +                                  sizeof(MLC.segment_command_data.segname))); +      break; +    case MachO::LC_SEGMENT_64: +      SegmentVmAddr = MLC.segment_command_64_data.vmaddr; +      SegmentVmSize = MLC.segment_command_64_data.vmsize; +      Segname = StringRef(MLC.segment_command_64_data.segname, +                          strnlen(MLC.segment_command_64_data.segname, +                                  sizeof(MLC.segment_command_64_data.segname))); +      break; +    default: +      continue; +    } + +    if (Segname == "__LINKEDIT") { +      // We update the __LINKEDIT segment later (in layoutTail). +      assert(LC.Sections.empty() && "__LINKEDIT segment has sections"); +      LinkEditLoadCommand = &MLC; +      continue; +    } + +    // Update file offsets and sizes of sections. +    uint64_t SegOffset = Offset; +    uint64_t SegFileSize = 0; +    uint64_t VMSize = 0; +    for (auto &Sec : LC.Sections) { +      if (IsObjectFile) { +        if (Sec.isVirtualSection()) { +          Sec.Offset = 0; +        } else { +          uint64_t PaddingSize = +              offsetToAlignment(SegFileSize, Align(1ull << Sec.Align)); +          Sec.Offset = SegOffset + SegFileSize + PaddingSize; +          Sec.Size = Sec.Content.size(); +          SegFileSize += PaddingSize + Sec.Size; +        } +        VMSize = std::max(VMSize, Sec.Addr + Sec.Size); +      } else { +        if (Sec.isVirtualSection()) { +          Sec.Offset = 0; +          VMSize += Sec.Size; +        } else { +          uint32_t SectOffset = Sec.Addr - SegmentVmAddr; +          Sec.Offset = SegOffset + SectOffset; +          Sec.Size = Sec.Content.size(); +          SegFileSize = std::max(SegFileSize, SectOffset + Sec.Size); +          VMSize = std::max(VMSize, SegFileSize); +        } +      } +    } + +    if (IsObjectFile) { +      Offset += SegFileSize; +    } else { +      Offset = alignTo(Offset + SegFileSize, PageSize); +      SegFileSize = alignTo(SegFileSize, PageSize); +      // Use the original vmsize if the segment is __PAGEZERO. +      VMSize = +          Segname == "__PAGEZERO" ? SegmentVmSize : alignTo(VMSize, PageSize); +    } + +    switch (MLC.load_command_data.cmd) { +    case MachO::LC_SEGMENT: +      MLC.segment_command_data.cmdsize = +          sizeof(MachO::segment_command) + +          sizeof(MachO::section) * LC.Sections.size(); +      MLC.segment_command_data.nsects = LC.Sections.size(); +      MLC.segment_command_data.fileoff = SegOffset; +      MLC.segment_command_data.vmsize = VMSize; +      MLC.segment_command_data.filesize = SegFileSize; +      break; +    case MachO::LC_SEGMENT_64: +      MLC.segment_command_64_data.cmdsize = +          sizeof(MachO::segment_command_64) + +          sizeof(MachO::section_64) * LC.Sections.size(); +      MLC.segment_command_64_data.nsects = LC.Sections.size(); +      MLC.segment_command_64_data.fileoff = SegOffset; +      MLC.segment_command_64_data.vmsize = VMSize; +      MLC.segment_command_64_data.filesize = SegFileSize; +      break; +    } +  } + +  return Offset; +} + +uint64_t MachOLayoutBuilder::layoutRelocations(uint64_t Offset) { +  for (auto &LC : O.LoadCommands) +    for (auto &Sec : LC.Sections) { +      Sec.RelOff = Sec.Relocations.empty() ? 0 : Offset; +      Sec.NReloc = Sec.Relocations.size(); +      Offset += sizeof(MachO::any_relocation_info) * Sec.NReloc; +    } + +  return Offset; +} + +Error MachOLayoutBuilder::layoutTail(uint64_t Offset) { +  // The order of LINKEDIT elements is as follows: +  // rebase info, binding info, weak binding info, lazy binding info, export +  // trie, data-in-code, symbol table, indirect symbol table, symbol table +  // strings. +  uint64_t NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); +  uint64_t StartOfLinkEdit = Offset; +  uint64_t StartOfRebaseInfo = StartOfLinkEdit; +  uint64_t StartOfBindingInfo = StartOfRebaseInfo + O.Rebases.Opcodes.size(); +  uint64_t StartOfWeakBindingInfo = StartOfBindingInfo + O.Binds.Opcodes.size(); +  uint64_t StartOfLazyBindingInfo = +      StartOfWeakBindingInfo + O.WeakBinds.Opcodes.size(); +  uint64_t StartOfExportTrie = +      StartOfLazyBindingInfo + O.LazyBinds.Opcodes.size(); +  uint64_t StartOfFunctionStarts = StartOfExportTrie + O.Exports.Trie.size(); +  uint64_t StartOfDataInCode = +      StartOfFunctionStarts + O.FunctionStarts.Data.size(); +  uint64_t StartOfSymbols = StartOfDataInCode + O.DataInCode.Data.size(); +  uint64_t StartOfIndirectSymbols = +      StartOfSymbols + NListSize * O.SymTable.Symbols.size(); +  uint64_t StartOfSymbolStrings = +      StartOfIndirectSymbols + +      sizeof(uint32_t) * O.IndirectSymTable.Symbols.size(); +  uint64_t LinkEditSize = +      (StartOfSymbolStrings + StrTableBuilder.getSize()) - StartOfLinkEdit; + +  // Now we have determined the layout of the contents of the __LINKEDIT +  // segment. Update its load command. +  if (LinkEditLoadCommand) { +    MachO::macho_load_command *MLC = LinkEditLoadCommand; +    switch (LinkEditLoadCommand->load_command_data.cmd) { +    case MachO::LC_SEGMENT: +      MLC->segment_command_data.cmdsize = sizeof(MachO::segment_command); +      MLC->segment_command_data.fileoff = StartOfLinkEdit; +      MLC->segment_command_data.vmsize = alignTo(LinkEditSize, PageSize); +      MLC->segment_command_data.filesize = LinkEditSize; +      break; +    case MachO::LC_SEGMENT_64: +      MLC->segment_command_64_data.cmdsize = sizeof(MachO::segment_command_64); +      MLC->segment_command_64_data.fileoff = StartOfLinkEdit; +      MLC->segment_command_64_data.vmsize = alignTo(LinkEditSize, PageSize); +      MLC->segment_command_64_data.filesize = LinkEditSize; +      break; +    } +  } + +  for (auto &LC : O.LoadCommands) { +    auto &MLC = LC.MachOLoadCommand; +    auto cmd = MLC.load_command_data.cmd; +    switch (cmd) { +    case MachO::LC_SYMTAB: +      MLC.symtab_command_data.symoff = StartOfSymbols; +      MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size(); +      MLC.symtab_command_data.stroff = StartOfSymbolStrings; +      MLC.symtab_command_data.strsize = StrTableBuilder.getSize(); +      break; +    case MachO::LC_DYSYMTAB: { +      if (MLC.dysymtab_command_data.ntoc != 0 || +          MLC.dysymtab_command_data.nmodtab != 0 || +          MLC.dysymtab_command_data.nextrefsyms != 0 || +          MLC.dysymtab_command_data.nlocrel != 0 || +          MLC.dysymtab_command_data.nextrel != 0) +        return createStringError(llvm::errc::not_supported, +                                 "shared library is not yet supported"); + +      if (!O.IndirectSymTable.Symbols.empty()) { +        MLC.dysymtab_command_data.indirectsymoff = StartOfIndirectSymbols; +        MLC.dysymtab_command_data.nindirectsyms = +            O.IndirectSymTable.Symbols.size(); +      } + +      updateDySymTab(MLC); +      break; +    } +    case MachO::LC_DATA_IN_CODE: +      MLC.linkedit_data_command_data.dataoff = StartOfDataInCode; +      MLC.linkedit_data_command_data.datasize = O.DataInCode.Data.size(); +      break; +    case MachO::LC_FUNCTION_STARTS: +      MLC.linkedit_data_command_data.dataoff = StartOfFunctionStarts; +      MLC.linkedit_data_command_data.datasize = O.FunctionStarts.Data.size(); +      break; +    case MachO::LC_DYLD_INFO: +    case MachO::LC_DYLD_INFO_ONLY: +      MLC.dyld_info_command_data.rebase_off = +          O.Rebases.Opcodes.empty() ? 0 : StartOfRebaseInfo; +      MLC.dyld_info_command_data.rebase_size = O.Rebases.Opcodes.size(); +      MLC.dyld_info_command_data.bind_off = +          O.Binds.Opcodes.empty() ? 0 : StartOfBindingInfo; +      MLC.dyld_info_command_data.bind_size = O.Binds.Opcodes.size(); +      MLC.dyld_info_command_data.weak_bind_off = +          O.WeakBinds.Opcodes.empty() ? 0 : StartOfWeakBindingInfo; +      MLC.dyld_info_command_data.weak_bind_size = O.WeakBinds.Opcodes.size(); +      MLC.dyld_info_command_data.lazy_bind_off = +          O.LazyBinds.Opcodes.empty() ? 0 : StartOfLazyBindingInfo; +      MLC.dyld_info_command_data.lazy_bind_size = O.LazyBinds.Opcodes.size(); +      MLC.dyld_info_command_data.export_off = +          O.Exports.Trie.empty() ? 0 : StartOfExportTrie; +      MLC.dyld_info_command_data.export_size = O.Exports.Trie.size(); +      break; +    case MachO::LC_LOAD_DYLINKER: +    case MachO::LC_MAIN: +    case MachO::LC_RPATH: +    case MachO::LC_SEGMENT: +    case MachO::LC_SEGMENT_64: +    case MachO::LC_VERSION_MIN_MACOSX: +    case MachO::LC_VERSION_MIN_IPHONEOS: +    case MachO::LC_VERSION_MIN_TVOS: +    case MachO::LC_VERSION_MIN_WATCHOS: +    case MachO::LC_BUILD_VERSION: +    case MachO::LC_ID_DYLIB: +    case MachO::LC_LOAD_DYLIB: +    case MachO::LC_UUID: +    case MachO::LC_SOURCE_VERSION: +      // Nothing to update. +      break; +    default: +      // Abort if it's unsupported in order to prevent corrupting the object. +      return createStringError(llvm::errc::not_supported, +                               "unsupported load command (cmd=0x%x)", cmd); +    } +  } + +  return Error::success(); +} + +Error MachOLayoutBuilder::layout() { +  O.Header.NCmds = O.LoadCommands.size(); +  O.Header.SizeOfCmds = computeSizeOfCmds(); +  constructStringTable(); +  updateSymbolIndexes(); +  uint64_t Offset = layoutSegments(); +  Offset = layoutRelocations(Offset); +  return layoutTail(Offset); +} + +} // end namespace macho +} // end namespace objcopy +} // end namespace llvm diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.h b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.h new file mode 100644 index 000000000000..21cbe56605de --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.h @@ -0,0 +1,50 @@ +//===- MachOLayoutBuilder.h -------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJCOPY_MACHO_MACHOLAYOUTBUILDER_H +#define LLVM_OBJCOPY_MACHO_MACHOLAYOUTBUILDER_H + +#include "MachOObjcopy.h" +#include "Object.h" + +namespace llvm { +namespace objcopy { +namespace macho { + +class MachOLayoutBuilder { +  Object &O; +  bool Is64Bit; +  uint64_t PageSize; + +  // Points to the __LINKEDIT segment if it exists. +  MachO::macho_load_command *LinkEditLoadCommand = nullptr; +  StringTableBuilder StrTableBuilder{StringTableBuilder::MachO}; + +  uint32_t computeSizeOfCmds() const; +  void constructStringTable(); +  void updateSymbolIndexes(); +  void updateDySymTab(MachO::macho_load_command &MLC); +  uint64_t layoutSegments(); +  uint64_t layoutRelocations(uint64_t Offset); +  Error layoutTail(uint64_t Offset); + +public: +  MachOLayoutBuilder(Object &O, bool Is64Bit, uint64_t PageSize) +      : O(O), Is64Bit(Is64Bit), PageSize(PageSize) {} + +  // Recomputes and updates fields in the given object such as file offsets. +  Error layout(); + +  StringTableBuilder &getStringTableBuilder() { return StrTableBuilder; } +}; + +} // end namespace macho +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_OBJCOPY_MACHO_MACHOLAYOUTBUILDER_H diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp index 19343b65dd1e..4578d0bb75d4 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -18,29 +18,209 @@ namespace objcopy {  namespace macho {  using namespace object; +using SectionPred = std::function<bool(const Section &Sec)>; + +static void removeSections(const CopyConfig &Config, Object &Obj) { +  SectionPred RemovePred = [](const Section &) { return false; }; + +  if (!Config.ToRemove.empty()) { +    RemovePred = [&Config, RemovePred](const Section &Sec) { +      return Config.ToRemove.matches(Sec.CanonicalName); +    }; +  } + +  if (Config.StripAll || Config.StripDebug) { +    // Remove all debug sections. +    RemovePred = [RemovePred](const Section &Sec) { +      if (Sec.Segname == "__DWARF") +        return true; + +      return RemovePred(Sec); +    }; +  } + +  if (!Config.OnlySection.empty()) { +    // Overwrite RemovePred because --only-section takes priority. +    RemovePred = [&Config](const Section &Sec) { +      return !Config.OnlySection.matches(Sec.CanonicalName); +    }; +  } + +  return Obj.removeSections(RemovePred); +} + +static void markSymbols(const CopyConfig &Config, Object &Obj) { +  // Symbols referenced from the indirect symbol table must not be removed. +  for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols) +    if (ISE.Symbol) +      (*ISE.Symbol)->Referenced = true; +} + +static void updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { +  for (SymbolEntry &Sym : Obj.SymTable) { +    auto I = Config.SymbolsToRename.find(Sym.Name); +    if (I != Config.SymbolsToRename.end()) +      Sym.Name = I->getValue(); +  } + +  auto RemovePred = [Config](const std::unique_ptr<SymbolEntry> &N) { +    if (N->Referenced) +      return false; +    return Config.StripAll; +  }; + +  Obj.SymTable.removeSymbols(RemovePred); +} + +static LoadCommand buildRPathLoadCommand(StringRef Path) { +  LoadCommand LC; +  MachO::rpath_command RPathLC; +  RPathLC.cmd = MachO::LC_RPATH; +  RPathLC.path = sizeof(MachO::rpath_command); +  RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size(), 8); +  LC.MachOLoadCommand.rpath_command_data = RPathLC; +  LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0); +  std::copy(Path.begin(), Path.end(), LC.Payload.begin()); +  return LC; +} + +static Error dumpSectionToFile(StringRef SecName, StringRef Filename, +                               Object &Obj) { +  for (LoadCommand &LC : Obj.LoadCommands) +    for (Section &Sec : LC.Sections) { +      if (Sec.CanonicalName == SecName) { +        Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = +            FileOutputBuffer::create(Filename, Sec.Content.size()); +        if (!BufferOrErr) +          return BufferOrErr.takeError(); +        std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); +        llvm::copy(Sec.Content, Buf->getBufferStart()); + +        if (Error E = Buf->commit()) +          return E; +        return Error::success(); +      } +    } + +  return createStringError(object_error::parse_failed, "section '%s' not found", +                           SecName.str().c_str()); +} + +static Error addSection(StringRef SecName, StringRef Filename, Object &Obj) { +  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = +      MemoryBuffer::getFile(Filename); +  if (!BufOrErr) +    return createFileError(Filename, errorCodeToError(BufOrErr.getError())); +  std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr); + +  std::pair<StringRef, StringRef> Pair = SecName.split(','); +  StringRef TargetSegName = Pair.first; +  Section Sec(TargetSegName, Pair.second); +  Sec.Content = Obj.NewSectionsContents.save(Buf->getBuffer()); + +  // Add the a section into an existing segment. +  for (LoadCommand &LC : Obj.LoadCommands) { +    Optional<StringRef> SegName = LC.getSegmentName(); +    if (SegName && SegName == TargetSegName) { +      LC.Sections.push_back(Sec); +      return Error::success(); +    } +  } + +  // There's no segment named TargetSegName. Create a new load command and +  // Insert a new section into it. +  LoadCommand &NewSegment = Obj.addSegment(TargetSegName); +  NewSegment.Sections.push_back(Sec); +  return Error::success(); +} + +// isValidMachOCannonicalName returns success if Name is a MachO cannonical name +// ("<segment>,<section>") and lengths of both segment and section names are +// valid. +Error isValidMachOCannonicalName(StringRef Name) { +  if (Name.count(',') != 1) +    return createStringError(errc::invalid_argument, +                             "invalid section name '%s' (should be formatted " +                             "as '<segment name>,<section name>')", +                             Name.str().c_str()); + +  std::pair<StringRef, StringRef> Pair = Name.split(','); +  if (Pair.first.size() > 16) +    return createStringError(errc::invalid_argument, +                             "too long segment name: '%s'", +                             Pair.first.str().c_str()); +  if (Pair.second.size() > 16) +    return createStringError(errc::invalid_argument, +                             "too long section name: '%s'", +                             Pair.second.str().c_str()); +  return Error::success(); +}  static Error handleArgs(const CopyConfig &Config, Object &Obj) {    if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||        Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||        !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() || -      !Config.AllocSectionsPrefix.empty() || !Config.AddSection.empty() || -      !Config.DumpSection.empty() || !Config.KeepSection.empty() || -      !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() || +      !Config.AllocSectionsPrefix.empty() || !Config.KeepSection.empty() || +      Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() ||        !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||        !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || -      !Config.SectionsToRename.empty() || !Config.SymbolsToRename.empty() || +      !Config.SectionsToRename.empty() ||        !Config.UnneededSymbolsToRemove.empty() || -      !Config.SetSectionFlags.empty() || !Config.ToRemove.empty() || +      !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() ||        Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden || -      Config.PreserveDates || Config.StripDWO || Config.StripNonAlloc || -      Config.StripSections || Config.Weaken || Config.DecompressDebugSections || -      Config.StripDebug || Config.StripNonAlloc || Config.StripSections || -      Config.StripUnneeded || Config.DiscardMode != DiscardType::None || -      !Config.SymbolsToAdd.empty() || Config.EntryExpr) { +      Config.PreserveDates || Config.StripAllGNU || Config.StripDWO || +      Config.StripNonAlloc || Config.StripSections || Config.Weaken || +      Config.DecompressDebugSections || Config.StripNonAlloc || +      Config.StripSections || Config.StripUnneeded || +      Config.DiscardMode != DiscardType::None || !Config.SymbolsToAdd.empty() || +      Config.EntryExpr) {      return createStringError(llvm::errc::invalid_argument,                               "option not supported by llvm-objcopy for MachO");    } +  removeSections(Config, Obj); + +  // Mark symbols to determine which symbols are still needed. +  if (Config.StripAll) +    markSymbols(Config, Obj); + +  updateAndRemoveSymbols(Config, Obj); + +  if (Config.StripAll) +    for (LoadCommand &LC : Obj.LoadCommands) +      for (Section &Sec : LC.Sections) +        Sec.Relocations.clear(); + +  for (const StringRef &Flag : Config.DumpSection) { +    std::pair<StringRef, StringRef> SecPair = Flag.split("="); +    StringRef SecName = SecPair.first; +    StringRef File = SecPair.second; +    if (Error E = dumpSectionToFile(SecName, File, Obj)) +      return E; +  } + +  for (const auto &Flag : Config.AddSection) { +    std::pair<StringRef, StringRef> SecPair = Flag.split("="); +    StringRef SecName = SecPair.first; +    StringRef File = SecPair.second; +    if (Error E = isValidMachOCannonicalName(SecName)) +      return E; +    if (Error E = addSection(SecName, File, Obj)) +      return E; +  } +  for (StringRef RPath : Config.RPathToAdd) { +    for (LoadCommand &LC : Obj.LoadCommands) { +      if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH && +          RPath == StringRef(reinterpret_cast<char *>(LC.Payload.data()), +                             LC.Payload.size()) +                       .trim(0)) { +        return createStringError(errc::invalid_argument, +                                 "rpath " + RPath + +                                     " would create a duplicate load command"); +      } +    } +    Obj.addLoadCommand(buildRPathLoadCommand(RPath)); +  }    return Error::success();  } @@ -57,7 +237,11 @@ Error executeObjcopyOnBinary(const CopyConfig &Config,    if (Error E = handleArgs(Config, *O))      return createFileError(Config.InputFilename, std::move(E)); -  MachOWriter Writer(*O, In.is64Bit(), In.isLittleEndian(), Out); +  // TODO: Support 16KB pages which are employed in iOS arm64 binaries: +  //       https://github.com/llvm/llvm-project/commit/1bebb2832ee312d3b0316dacff457a7a29435edb +  const uint64_t PageSize = 4096; + +  MachOWriter Writer(*O, In.is64Bit(), In.isLittleEndian(), PageSize, Out);    if (auto E = Writer.finalize())      return E;    return Writer.write(); diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp index d31293034608..46bb11727322 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -29,12 +29,9 @@ void MachOReader::readHeader(Object &O) const {  template <typename SectionType>  Section constructSectionCommon(SectionType Sec) { -  Section S; -  S.Sectname = -      StringRef(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname))) -          .str(); -  S.Segname = -      StringRef(Sec.segname, strnlen(Sec.segname, sizeof(Sec.sectname))).str(); +  StringRef SegName(Sec.segname, strnlen(Sec.segname, sizeof(Sec.segname))); +  StringRef SectName(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname))); +  Section S(SegName, SectName);    S.Addr = Sec.addr;    S.Size = Sec.size;    S.Offset = Sec.offset; @@ -129,10 +126,19 @@ void MachOReader::readLoadCommands(Object &O) const {      case MachO::LC_SYMTAB:        O.SymTabCommandIndex = O.LoadCommands.size();        break; +    case MachO::LC_DYSYMTAB: +      O.DySymTabCommandIndex = O.LoadCommands.size(); +      break;      case MachO::LC_DYLD_INFO:      case MachO::LC_DYLD_INFO_ONLY:        O.DyLdInfoCommandIndex = O.LoadCommands.size();        break; +    case MachO::LC_DATA_IN_CODE: +      O.DataInCodeCommandIndex = O.LoadCommands.size(); +      break; +    case MachO::LC_FUNCTION_STARTS: +      O.FunctionStartsCommandIndex = O.LoadCommands.size(); +      break;      }  #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct)                         \    case MachO::LCName:                                                          \ @@ -140,10 +146,11 @@ void MachOReader::readLoadCommands(Object &O) const {             sizeof(MachO::LCStruct));                                           \      if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)                  \        MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data);                  \ -    LC.Payload = ArrayRef<uint8_t>(                                            \ -        reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +         \ -            sizeof(MachO::LCStruct),                                           \ -        LoadCmd.C.cmdsize - sizeof(MachO::LCStruct));                          \ +    if (LoadCmd.C.cmdsize > sizeof(MachO::LCStruct))                           \ +      LC.Payload = ArrayRef<uint8_t>(                                          \ +          reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +       \ +              sizeof(MachO::LCStruct),                                         \ +          LoadCmd.C.cmdsize - sizeof(MachO::LCStruct));                        \      break;      switch (LoadCmd.C.cmd) { @@ -152,10 +159,11 @@ void MachOReader::readLoadCommands(Object &O) const {               sizeof(MachO::load_command));        if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)          MachO::swapStruct(LC.MachOLoadCommand.load_command_data); -      LC.Payload = ArrayRef<uint8_t>( -          reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + -              sizeof(MachO::load_command), -          LoadCmd.C.cmdsize - sizeof(MachO::load_command)); +      if (LoadCmd.C.cmdsize > sizeof(MachO::load_command)) +        LC.Payload = ArrayRef<uint8_t>( +            reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + +                sizeof(MachO::load_command), +            LoadCmd.C.cmdsize - sizeof(MachO::load_command));        break;  #include "llvm/BinaryFormat/MachO.def"      } @@ -188,7 +196,7 @@ void MachOReader::readSymbolTable(Object &O) const {                     StrTable,                     MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl()))); -    O.SymTable.Symbols.push_back(llvm::make_unique<SymbolEntry>(SE)); +    O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE));    }  } @@ -222,8 +230,44 @@ void MachOReader::readExportInfo(Object &O) const {    O.Exports.Trie = MachOObj.getDyldInfoExportsTrie();  } +void MachOReader::readDataInCodeData(Object &O) const { +  if (!O.DataInCodeCommandIndex) +    return; +  const MachO::linkedit_data_command &LDC = +      O.LoadCommands[*O.DataInCodeCommandIndex] +          .MachOLoadCommand.linkedit_data_command_data; + +  O.DataInCode.Data = arrayRefFromStringRef( +      MachOObj.getData().substr(LDC.dataoff, LDC.datasize)); +} + +void MachOReader::readFunctionStartsData(Object &O) const { +  if (!O.FunctionStartsCommandIndex) +    return; +  const MachO::linkedit_data_command &LDC = +      O.LoadCommands[*O.FunctionStartsCommandIndex] +          .MachOLoadCommand.linkedit_data_command_data; + +  O.FunctionStarts.Data = arrayRefFromStringRef( +      MachOObj.getData().substr(LDC.dataoff, LDC.datasize)); +} + +void MachOReader::readIndirectSymbolTable(Object &O) const { +  MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand(); +  constexpr uint32_t AbsOrLocalMask = +      MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS; +  for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) { +    uint32_t Index = MachOObj.getIndirectSymbolTableEntry(DySymTab, i); +    if ((Index & AbsOrLocalMask) != 0) +      O.IndirectSymTable.Symbols.emplace_back(Index, None); +    else +      O.IndirectSymTable.Symbols.emplace_back( +          Index, O.SymTable.getSymbolByIndex(Index)); +  } +} +  std::unique_ptr<Object> MachOReader::create() const { -  auto Obj = llvm::make_unique<Object>(); +  auto Obj = std::make_unique<Object>();    readHeader(*Obj);    readLoadCommands(*Obj);    readSymbolTable(*Obj); @@ -233,6 +277,9 @@ std::unique_ptr<Object> MachOReader::create() const {    readWeakBindInfo(*Obj);    readLazyBindInfo(*Obj);    readExportInfo(*Obj); +  readDataInCodeData(*Obj); +  readFunctionStartsData(*Obj); +  readIndirectSymbolTable(*Obj);    return Obj;  } diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.h b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.h index 795e5cc2363d..00c8f0d55f61 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.h +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.h @@ -36,6 +36,9 @@ class MachOReader : public Reader {    void readWeakBindInfo(Object &O) const;    void readLazyBindInfo(Object &O) const;    void readExportInfo(Object &O) const; +  void readDataInCodeData(Object &O) const; +  void readFunctionStartsData(Object &O) const; +  void readIndirectSymbolTable(Object &O) const;  public:    explicit MachOReader(const object::MachOObjectFile &Obj) : MachOObj(Obj) {} diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp index 74200c5aa62a..0d9590612eca 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp @@ -7,6 +7,7 @@  //===----------------------------------------------------------------------===//  #include "MachOWriter.h" +#include "MachOLayoutBuilder.h"  #include "Object.h"  #include "llvm/ADT/STLExtras.h"  #include "llvm/BinaryFormat/MachO.h" @@ -40,16 +41,10 @@ size_t MachOWriter::totalSize() const {      const MachO::symtab_command &SymTabCommand =          O.LoadCommands[*O.SymTabCommandIndex]              .MachOLoadCommand.symtab_command_data; -    if (SymTabCommand.symoff) { -      assert((SymTabCommand.nsyms == O.SymTable.Symbols.size()) && -             "Incorrect number of symbols"); +    if (SymTabCommand.symoff)        Ends.push_back(SymTabCommand.symoff + symTableSize()); -    } -    if (SymTabCommand.stroff) { -      assert((SymTabCommand.strsize == StrTableBuilder.getSize()) && -             "Incorrect string table size"); +    if (SymTabCommand.stroff)        Ends.push_back(SymTabCommand.stroff + SymTabCommand.strsize); -    }    }    if (O.DyLdInfoCommandIndex) {      const MachO::dyld_info_command &DyLdInfoCommand = @@ -84,6 +79,36 @@ size_t MachOWriter::totalSize() const {      }    } +  if (O.DySymTabCommandIndex) { +    const MachO::dysymtab_command &DySymTabCommand = +        O.LoadCommands[*O.DySymTabCommandIndex] +            .MachOLoadCommand.dysymtab_command_data; + +    if (DySymTabCommand.indirectsymoff) +      Ends.push_back(DySymTabCommand.indirectsymoff + +                     sizeof(uint32_t) * O.IndirectSymTable.Symbols.size()); +  } + +  if (O.DataInCodeCommandIndex) { +    const MachO::linkedit_data_command &LinkEditDataCommand = +        O.LoadCommands[*O.DataInCodeCommandIndex] +            .MachOLoadCommand.linkedit_data_command_data; + +    if (LinkEditDataCommand.dataoff) +      Ends.push_back(LinkEditDataCommand.dataoff + +                     LinkEditDataCommand.datasize); +  } + +  if (O.FunctionStartsCommandIndex) { +    const MachO::linkedit_data_command &LinkEditDataCommand = +        O.LoadCommands[*O.FunctionStartsCommandIndex] +            .MachOLoadCommand.linkedit_data_command_data; + +    if (LinkEditDataCommand.dataoff) +      Ends.push_back(LinkEditDataCommand.dataoff + +                     LinkEditDataCommand.datasize); +  } +    // Otherwise, use the last section / reloction.    for (const auto &LC : O.LoadCommands)      for (const auto &S : LC.Sections) { @@ -120,14 +145,6 @@ void MachOWriter::writeHeader() {    memcpy(B.getBufferStart(), &Header, HeaderSize);  } -void MachOWriter::updateSymbolIndexes() { -  uint32_t Index = 0; -  for (auto &Symbol : O.SymTable.Symbols) { -    Symbol->Index = Index; -    Index++; -  } -} -  void MachOWriter::writeLoadCommands() {    uint8_t *Begin = B.getBufferStart() + headerSize();    for (const auto &LC : O.LoadCommands) { @@ -163,7 +180,8 @@ void MachOWriter::writeLoadCommands() {        MachO::swapStruct(MLC.LCStruct##_data);                                  \      memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct));              \      Begin += sizeof(MachO::LCStruct);                                          \ -    memcpy(Begin, LC.Payload.data(), LC.Payload.size());                       \ +    if (!LC.Payload.empty())                                                   \ +      memcpy(Begin, LC.Payload.data(), LC.Payload.size());                     \      Begin += LC.Payload.size();                                                \      break; @@ -176,7 +194,8 @@ void MachOWriter::writeLoadCommands() {          MachO::swapStruct(MLC.load_command_data);        memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command));        Begin += sizeof(MachO::load_command); -      memcpy(Begin, LC.Payload.data(), LC.Payload.size()); +      if (!LC.Payload.empty()) +        memcpy(Begin, LC.Payload.data(), LC.Payload.size());        Begin += LC.Payload.size();        break;  #include "llvm/BinaryFormat/MachO.def" @@ -253,7 +272,7 @@ void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out,    Out += sizeof(NListType);  } -void MachOWriter::writeSymbolTable() { +void MachOWriter::writeStringTable() {    if (!O.SymTabCommandIndex)      return;    const MachO::symtab_command &SymTabCommand = @@ -261,10 +280,10 @@ void MachOWriter::writeSymbolTable() {            .MachOLoadCommand.symtab_command_data;    uint8_t *StrTable = (uint8_t *)B.getBufferStart() + SymTabCommand.stroff; -  StrTableBuilder.write(StrTable); +  LayoutBuilder.getStringTableBuilder().write(StrTable);  } -void MachOWriter::writeStringTable() { +void MachOWriter::writeSymbolTable() {    if (!O.SymTabCommandIndex)      return;    const MachO::symtab_command &SymTabCommand = @@ -275,7 +294,7 @@ void MachOWriter::writeStringTable() {    for (auto Iter = O.SymTable.Symbols.begin(), End = O.SymTable.Symbols.end();         Iter != End; Iter++) {      SymbolEntry *Sym = Iter->get(); -    auto Nstrx = StrTableBuilder.getOffset(Sym->Name); +    uint32_t Nstrx = LayoutBuilder.getStringTableBuilder().getOffset(Sym->Name);      if (Is64Bit)        writeNListEntry<MachO::nlist_64>(*Sym, IsLittleEndian, SymTable, Nstrx); @@ -344,6 +363,48 @@ void MachOWriter::writeExportInfo() {    memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size());  } +void MachOWriter::writeIndirectSymbolTable() { +  if (!O.DySymTabCommandIndex) +    return; + +  const MachO::dysymtab_command &DySymTabCommand = +      O.LoadCommands[*O.DySymTabCommandIndex] +          .MachOLoadCommand.dysymtab_command_data; + +  uint32_t *Out = +      (uint32_t *)(B.getBufferStart() + DySymTabCommand.indirectsymoff); +  for (const IndirectSymbolEntry &Sym : O.IndirectSymTable.Symbols) { +    uint32_t Entry = (Sym.Symbol) ? (*Sym.Symbol)->Index : Sym.OriginalIndex; +    if (IsLittleEndian != sys::IsLittleEndianHost) +      sys::swapByteOrder(Entry); +    *Out++ = Entry; +  } +} + +void MachOWriter::writeDataInCodeData() { +  if (!O.DataInCodeCommandIndex) +    return; +  const MachO::linkedit_data_command &LinkEditDataCommand = +      O.LoadCommands[*O.DataInCodeCommandIndex] +          .MachOLoadCommand.linkedit_data_command_data; +  char *Out = (char *)B.getBufferStart() + LinkEditDataCommand.dataoff; +  assert((LinkEditDataCommand.datasize == O.DataInCode.Data.size()) && +         "Incorrect data in code data size"); +  memcpy(Out, O.DataInCode.Data.data(), O.DataInCode.Data.size()); +} + +void MachOWriter::writeFunctionStartsData() { +  if (!O.FunctionStartsCommandIndex) +    return; +  const MachO::linkedit_data_command &LinkEditDataCommand = +      O.LoadCommands[*O.FunctionStartsCommandIndex] +          .MachOLoadCommand.linkedit_data_command_data; +  char *Out = (char *)B.getBufferStart() + LinkEditDataCommand.dataoff; +  assert((LinkEditDataCommand.datasize == O.FunctionStarts.Data.size()) && +         "Incorrect function starts data size"); +  memcpy(Out, O.FunctionStarts.Data.data(), O.FunctionStarts.Data.size()); +} +  void MachOWriter::writeTail() {    typedef void (MachOWriter::*WriteHandlerType)(void);    typedef std::pair<uint64_t, WriteHandlerType> WriteOperation; @@ -379,206 +440,51 @@ void MachOWriter::writeTail() {            {DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo});    } -  llvm::sort(Queue, [](const WriteOperation &LHS, const WriteOperation &RHS) { -    return LHS.first < RHS.first; -  }); - -  for (auto WriteOp : Queue) -    (this->*WriteOp.second)(); -} - -void MachOWriter::updateSizeOfCmds() { -  auto Size = 0; -  for (const auto &LC : O.LoadCommands) { -    auto &MLC = LC.MachOLoadCommand; -    auto cmd = MLC.load_command_data.cmd; - -    switch (cmd) { -    case MachO::LC_SEGMENT: -      Size += sizeof(MachO::segment_command) + -              sizeof(MachO::section) * LC.Sections.size(); -      continue; -    case MachO::LC_SEGMENT_64: -      Size += sizeof(MachO::segment_command_64) + -              sizeof(MachO::section_64) * LC.Sections.size(); -      continue; -    } - -    switch (cmd) { -#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct)                         \ -  case MachO::LCName:                                                          \ -    Size += sizeof(MachO::LCStruct);                                           \ -    break; -#include "llvm/BinaryFormat/MachO.def" -#undef HANDLE_LOAD_COMMAND -    } -  } - -  O.Header.SizeOfCmds = Size; -} - -// Updates the index and the number of local/external/undefined symbols. Here we -// assume that MLC is a LC_DYSYMTAB and the nlist entries in the symbol table -// are already sorted by the those types. -void MachOWriter::updateDySymTab(MachO::macho_load_command &MLC) { -  uint32_t NumLocalSymbols = 0; -  auto Iter = O.SymTable.Symbols.begin(); -  auto End = O.SymTable.Symbols.end(); -  for (; Iter != End; Iter++) { -    if ((*Iter)->n_type & (MachO::N_EXT | MachO::N_PEXT)) -      break; +  if (O.DySymTabCommandIndex) { +    const MachO::dysymtab_command &DySymTabCommand = +        O.LoadCommands[*O.DySymTabCommandIndex] +            .MachOLoadCommand.dysymtab_command_data; -    NumLocalSymbols++; +    if (DySymTabCommand.indirectsymoff) +      Queue.emplace_back(DySymTabCommand.indirectsymoff, +                         &MachOWriter::writeIndirectSymbolTable);    } -  uint32_t NumExtDefSymbols = 0; -  for (; Iter != End; Iter++) { -    if (((*Iter)->n_type & MachO::N_TYPE) == MachO::N_UNDF) -      break; - -    NumExtDefSymbols++; -  } - -  MLC.dysymtab_command_data.ilocalsym = 0; -  MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols; -  MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols; -  MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols; -  MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols; -  MLC.dysymtab_command_data.nundefsym = -      O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols); -} - -// Recomputes and updates offset and size fields in load commands and sections -// since they could be modified. -Error MachOWriter::layout() { -  auto SizeOfCmds = loadCommandsSize(); -  auto Offset = headerSize() + SizeOfCmds; -  O.Header.NCmds = O.LoadCommands.size(); -  O.Header.SizeOfCmds = SizeOfCmds; - -  // Lay out sections. -  for (auto &LC : O.LoadCommands) { -    uint64_t FileOff = Offset; -    uint64_t VMSize = 0; -    uint64_t FileOffsetInSegment = 0; -    for (auto &Sec : LC.Sections) { -      if (!Sec.isVirtualSection()) { -        auto FilePaddingSize = -            OffsetToAlignment(FileOffsetInSegment, 1ull << Sec.Align); -        Sec.Offset = Offset + FileOffsetInSegment + FilePaddingSize; -        Sec.Size = Sec.Content.size(); -        FileOffsetInSegment += FilePaddingSize + Sec.Size; -      } - -      VMSize = std::max(VMSize, Sec.Addr + Sec.Size); -    } - -    // TODO: Handle the __PAGEZERO segment. -    auto &MLC = LC.MachOLoadCommand; -    switch (MLC.load_command_data.cmd) { -    case MachO::LC_SEGMENT: -      MLC.segment_command_data.cmdsize = -          sizeof(MachO::segment_command) + -          sizeof(MachO::section) * LC.Sections.size(); -      MLC.segment_command_data.nsects = LC.Sections.size(); -      MLC.segment_command_data.fileoff = FileOff; -      MLC.segment_command_data.vmsize = VMSize; -      MLC.segment_command_data.filesize = FileOffsetInSegment; -      break; -    case MachO::LC_SEGMENT_64: -      MLC.segment_command_64_data.cmdsize = -          sizeof(MachO::segment_command_64) + -          sizeof(MachO::section_64) * LC.Sections.size(); -      MLC.segment_command_64_data.nsects = LC.Sections.size(); -      MLC.segment_command_64_data.fileoff = FileOff; -      MLC.segment_command_64_data.vmsize = VMSize; -      MLC.segment_command_64_data.filesize = FileOffsetInSegment; -      break; -    } +  if (O.DataInCodeCommandIndex) { +    const MachO::linkedit_data_command &LinkEditDataCommand = +        O.LoadCommands[*O.DataInCodeCommandIndex] +            .MachOLoadCommand.linkedit_data_command_data; -    Offset += FileOffsetInSegment; +    if (LinkEditDataCommand.dataoff) +      Queue.emplace_back(LinkEditDataCommand.dataoff, +                         &MachOWriter::writeDataInCodeData);    } -  // Lay out relocations. -  for (auto &LC : O.LoadCommands) -    for (auto &Sec : LC.Sections) { -      Sec.RelOff = Sec.Relocations.empty() ? 0 : Offset; -      Sec.NReloc = Sec.Relocations.size(); -      Offset += sizeof(MachO::any_relocation_info) * Sec.NReloc; -    } +  if (O.FunctionStartsCommandIndex) { +    const MachO::linkedit_data_command &LinkEditDataCommand = +        O.LoadCommands[*O.FunctionStartsCommandIndex] +            .MachOLoadCommand.linkedit_data_command_data; -  // Lay out tail stuff. -  auto NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); -  for (auto &LC : O.LoadCommands) { -    auto &MLC = LC.MachOLoadCommand; -    auto cmd = MLC.load_command_data.cmd; -    switch (cmd) { -    case MachO::LC_SYMTAB: -      MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size(); -      MLC.symtab_command_data.strsize = StrTableBuilder.getSize(); -      MLC.symtab_command_data.symoff = Offset; -      Offset += NListSize * MLC.symtab_command_data.nsyms; -      MLC.symtab_command_data.stroff = Offset; -      Offset += MLC.symtab_command_data.strsize; -      break; -    case MachO::LC_DYSYMTAB: { -      if (MLC.dysymtab_command_data.ntoc != 0 || -          MLC.dysymtab_command_data.nmodtab != 0 || -          MLC.dysymtab_command_data.nextrefsyms != 0 || -          MLC.dysymtab_command_data.nlocrel != 0 || -          MLC.dysymtab_command_data.nextrel != 0) -        return createStringError(llvm::errc::not_supported, -                                 "shared library is not yet supported"); - -      if (MLC.dysymtab_command_data.nindirectsyms != 0) -        return createStringError(llvm::errc::not_supported, -                                 "indirect symbol table is not yet supported"); - -      updateDySymTab(MLC); -      break; -    } -    case MachO::LC_SEGMENT: -    case MachO::LC_SEGMENT_64: -    case MachO::LC_VERSION_MIN_MACOSX: -    case MachO::LC_BUILD_VERSION: -    case MachO::LC_ID_DYLIB: -    case MachO::LC_LOAD_DYLIB: -    case MachO::LC_UUID: -    case MachO::LC_SOURCE_VERSION: -      // Nothing to update. -      break; -    default: -      // Abort if it's unsupported in order to prevent corrupting the object. -      return createStringError(llvm::errc::not_supported, -                               "unsupported load command (cmd=0x%x)", cmd); -    } +    if (LinkEditDataCommand.dataoff) +      Queue.emplace_back(LinkEditDataCommand.dataoff, +                         &MachOWriter::writeFunctionStartsData);    } -  return Error::success(); -} +  llvm::sort(Queue, [](const WriteOperation &LHS, const WriteOperation &RHS) { +    return LHS.first < RHS.first; +  }); -void MachOWriter::constructStringTable() { -  for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols) -    StrTableBuilder.add(Sym->Name); -  StrTableBuilder.finalize(); +  for (auto WriteOp : Queue) +    (this->*WriteOp.second)();  } -Error MachOWriter::finalize() { -  updateSizeOfCmds(); -  constructStringTable(); - -  if (auto E = layout()) -    return E; - -  return Error::success(); -} +Error MachOWriter::finalize() { return LayoutBuilder.layout(); }  Error MachOWriter::write() {    if (Error E = B.allocate(totalSize()))      return E;    memset(B.getBufferStart(), 0, totalSize());    writeHeader(); -  updateSymbolIndexes();    writeLoadCommands();    writeSections();    writeTail(); diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.h b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.h index ecf12d62de2c..22abbad56f41 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.h +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.h @@ -7,6 +7,7 @@  //===----------------------------------------------------------------------===//  #include "../Buffer.h" +#include "MachOLayoutBuilder.h"  #include "MachOObjcopy.h"  #include "Object.h"  #include "llvm/BinaryFormat/MachO.h" @@ -22,20 +23,15 @@ class MachOWriter {    Object &O;    bool Is64Bit;    bool IsLittleEndian; +  uint64_t PageSize;    Buffer &B; -  StringTableBuilder StrTableBuilder{StringTableBuilder::MachO}; +  MachOLayoutBuilder LayoutBuilder;    size_t headerSize() const;    size_t loadCommandsSize() const;    size_t symTableSize() const;    size_t strTableSize() const; -  void updateDySymTab(MachO::macho_load_command &MLC); -  void updateSizeOfCmds(); -  void updateSymbolIndexes(); -  void constructStringTable(); -  Error layout(); -    void writeHeader();    void writeLoadCommands();    template <typename StructType> @@ -48,11 +44,16 @@ class MachOWriter {    void writeWeakBindInfo();    void writeLazyBindInfo();    void writeExportInfo(); +  void writeIndirectSymbolTable(); +  void writeDataInCodeData(); +  void writeFunctionStartsData();    void writeTail();  public: -  MachOWriter(Object &O, bool Is64Bit, bool IsLittleEndian, Buffer &B) -      : O(O), Is64Bit(Is64Bit), IsLittleEndian(IsLittleEndian), B(B) {} +  MachOWriter(Object &O, bool Is64Bit, bool IsLittleEndian, uint64_t PageSize, +              Buffer &B) +      : O(O), Is64Bit(Is64Bit), IsLittleEndian(IsLittleEndian), +        PageSize(PageSize), B(B), LayoutBuilder(O, Is64Bit, PageSize) {}    size_t totalSize() const;    Error finalize(); diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.cpp b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.cpp index 264f39c28ed2..d3b4fdc2f633 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.cpp @@ -10,6 +10,70 @@ const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const {    return Symbols[Index].get();  } +SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) { +  return const_cast<SymbolEntry *>( +      static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index)); +} + +void SymbolTable::removeSymbols( +    function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) { +  Symbols.erase( +      std::remove_if(std::begin(Symbols), std::end(Symbols), ToRemove), +      std::end(Symbols)); +} + +void Object::removeSections(function_ref<bool(const Section &)> ToRemove) { +  for (LoadCommand &LC : LoadCommands) +    LC.Sections.erase(std::remove_if(std::begin(LC.Sections), +                                     std::end(LC.Sections), ToRemove), +                      std::end(LC.Sections)); +} + +void Object::addLoadCommand(LoadCommand LC) { +  LoadCommands.push_back(std::move(LC)); +} + +template <typename SegmentType> +static void constructSegment(SegmentType &Seg, +                             llvm::MachO::LoadCommandType CmdType, +                             StringRef SegName) { +  assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name"); +  memset(&Seg, 0, sizeof(SegmentType)); +  Seg.cmd = CmdType; +  strncpy(Seg.segname, SegName.data(), SegName.size()); +} + +LoadCommand &Object::addSegment(StringRef SegName) { +  LoadCommand LC; +  if (is64Bit()) +    constructSegment(LC.MachOLoadCommand.segment_command_64_data, +                     MachO::LC_SEGMENT_64, SegName); +  else +    constructSegment(LC.MachOLoadCommand.segment_command_data, +                     MachO::LC_SEGMENT, SegName); + +  LoadCommands.push_back(LC); +  return LoadCommands.back(); +} + +/// Extracts a segment name from a string which is possibly non-null-terminated. +static StringRef extractSegmentName(const char *SegName) { +  return StringRef(SegName, +                   strnlen(SegName, sizeof(MachO::segment_command::segname))); +} + +Optional<StringRef> LoadCommand::getSegmentName() const { +  const MachO::macho_load_command &MLC = MachOLoadCommand; +  switch (MLC.load_command_data.cmd) { +  case MachO::LC_SEGMENT: +    return extractSegmentName(MLC.segment_command_data.segname); +  case MachO::LC_SEGMENT_64: +    return extractSegmentName(MLC.segment_command_64_data.segname); +  default: +    return None; +  } +} +  } // end namespace macho  } // end namespace objcopy  } // end namespace llvm diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.h b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.h index ed85fcbc47f7..dc2606eefa4a 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.h +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.h @@ -14,6 +14,7 @@  #include "llvm/BinaryFormat/MachO.h"  #include "llvm/MC/StringTableBuilder.h"  #include "llvm/ObjectYAML/DWARFYAML.h" +#include "llvm/Support/StringSaver.h"  #include "llvm/Support/YAMLTraits.h"  #include <cstdint>  #include <string> @@ -36,22 +37,32 @@ struct MachHeader {  struct RelocationInfo;  struct Section { -  std::string Sectname;    std::string Segname; -  uint64_t Addr; -  uint64_t Size; -  uint32_t Offset; -  uint32_t Align; -  uint32_t RelOff; -  uint32_t NReloc; -  uint32_t Flags; -  uint32_t Reserved1; -  uint32_t Reserved2; -  uint32_t Reserved3; - +  std::string Sectname; +  // CanonicalName is a string formatted as “<Segname>,<Sectname>". +  std::string CanonicalName; +  uint64_t Addr = 0; +  uint64_t Size = 0; +  uint32_t Offset = 0; +  uint32_t Align = 0; +  uint32_t RelOff = 0; +  uint32_t NReloc = 0; +  uint32_t Flags = 0; +  uint32_t Reserved1 = 0; +  uint32_t Reserved2 = 0; +  uint32_t Reserved3 = 0;    StringRef Content;    std::vector<RelocationInfo> Relocations; +  Section(StringRef SegName, StringRef SectName) +      : Segname(SegName), Sectname(SectName), +        CanonicalName((Twine(SegName) + Twine(',') + SectName).str()) {} + +  Section(StringRef SegName, StringRef SectName, StringRef Content) +      : Segname(SegName), Sectname(SectName), +        CanonicalName((Twine(SegName) + Twine(',') + SectName).str()), +        Content(Content) {} +    MachO::SectionType getType() const {      return static_cast<MachO::SectionType>(Flags & MachO::SECTION_TYPE);    } @@ -72,24 +83,38 @@ struct LoadCommand {    // The raw content of the payload of the load command (located right after the    // corresponding struct). In some cases it is either empty or can be    // copied-over without digging into its structure. -  ArrayRef<uint8_t> Payload; +  std::vector<uint8_t> Payload;     // Some load commands can contain (inside the payload) an array of sections,    // though the contents of the sections are stored separately. The struct    // Section describes only sections' metadata and where to find the    // corresponding content inside the binary.    std::vector<Section> Sections; + +  // Returns the segment name if the load command is a segment command. +  Optional<StringRef> getSegmentName() const;  };  // A symbol information. Fields which starts with "n_" are same as them in the  // nlist.  struct SymbolEntry {    std::string Name; +  bool Referenced = false;    uint32_t Index;    uint8_t n_type;    uint8_t n_sect;    uint16_t n_desc;    uint64_t n_value; + +  bool isExternalSymbol() const { +    return n_type & ((MachO::N_EXT | MachO::N_PEXT)); +  } + +  bool isLocalSymbol() const { return !isExternalSymbol(); } + +  bool isUndefinedSymbol() const { +    return (n_type & MachO::N_TYPE) == MachO::N_UNDF; +  }  };  /// The location of the symbol table inside the binary is described by LC_SYMTAB @@ -97,7 +122,32 @@ struct SymbolEntry {  struct SymbolTable {    std::vector<std::unique_ptr<SymbolEntry>> Symbols; +  using iterator = pointee_iterator< +      std::vector<std::unique_ptr<SymbolEntry>>::const_iterator>; + +  iterator begin() const { return iterator(Symbols.begin()); } +  iterator end() const { return iterator(Symbols.end()); } +    const SymbolEntry *getSymbolByIndex(uint32_t Index) const; +  SymbolEntry *getSymbolByIndex(uint32_t Index); +  void removeSymbols( +      function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove); +}; + +struct IndirectSymbolEntry { +  // The original value in an indirect symbol table. Higher bits encode extra +  // information (INDIRECT_SYMBOL_LOCAL and INDIRECT_SYMBOL_ABS). +  uint32_t OriginalIndex; +  /// The Symbol referenced by this entry. It's None if the index is +  /// INDIRECT_SYMBOL_LOCAL or INDIRECT_SYMBOL_ABS. +  Optional<SymbolEntry *> Symbol; + +  IndirectSymbolEntry(uint32_t OriginalIndex, Optional<SymbolEntry *> Symbol) +      : OriginalIndex(OriginalIndex), Symbol(Symbol) {} +}; + +struct IndirectSymbolTable { +  std::vector<IndirectSymbolEntry> Symbols;  };  /// The location of the string table inside the binary is described by LC_SYMTAB @@ -206,6 +256,10 @@ struct ExportInfo {    ArrayRef<uint8_t> Trie;  }; +struct LinkData { +  ArrayRef<uint8_t> Data; +}; +  struct Object {    MachHeader Header;    std::vector<LoadCommand> LoadCommands; @@ -218,11 +272,38 @@ struct Object {    WeakBindInfo WeakBinds;    LazyBindInfo LazyBinds;    ExportInfo Exports; +  IndirectSymbolTable IndirectSymTable; +  LinkData DataInCode; +  LinkData FunctionStarts;    /// The index of LC_SYMTAB load command if present.    Optional<size_t> SymTabCommandIndex;    /// The index of LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command if present.    Optional<size_t> DyLdInfoCommandIndex; +  /// The index LC_DYSYMTAB load comamnd if present. +  Optional<size_t> DySymTabCommandIndex; +  /// The index LC_DATA_IN_CODE load comamnd if present. +  Optional<size_t> DataInCodeCommandIndex; +  /// The index LC_FUNCTION_STARTS load comamnd if present. +  Optional<size_t> FunctionStartsCommandIndex; + +  BumpPtrAllocator Alloc; +  StringSaver NewSectionsContents; + +  Object() : NewSectionsContents(Alloc) {} + +  void removeSections(function_ref<bool(const Section &)> ToRemove); +  void addLoadCommand(LoadCommand LC); + +  /// Creates a new segment load command in the object and returns a reference +  /// to the newly created load command. The caller should verify that SegName +  /// is not too long (SegName.size() should be less than or equal to 16). +  LoadCommand &addSegment(StringRef SegName); + +  bool is64Bit() const { +    return Header.Magic == MachO::MH_MAGIC_64 || +           Header.Magic == MachO::MH_CIGAM_64; +  }  };  } // end namespace macho diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td index 757d7e97958d..9e6b6f0005cd 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td @@ -1,37 +1,33 @@ -include "llvm/Option/OptParser.td" - -multiclass Eq<string name, string help> { -  def NAME : Separate<["--"], name>; -  def NAME #_eq : Joined<["--"], name #"=">, -                  Alias<!cast<Separate>(NAME)>, -                  HelpText<help>; -} - -def help : Flag<["--"], "help">; -def h : Flag<["-"], "h">, Alias<help>; - -def allow_broken_links -    : Flag<["--"], "allow-broken-links">, -      HelpText<"Allow llvm-objcopy to remove sections even if it would leave " -               "invalid section references. The appropriate sh_link fields " -               "will be set to zero.">; +include "CommonOpts.td"  defm binary_architecture -    : Eq<"binary-architecture", "Used when transforming an architecture-less " -                                "format (such as binary) to another format">; -def B : JoinedOrSeparate<["-"], "B">, Alias<binary_architecture>; +    : Eq<"binary-architecture", "Ignored for compatibility">; +def B : JoinedOrSeparate<["-"], "B">, +        Alias<binary_architecture>, +        HelpText<"Alias for --binary-architecture">;  defm target : Eq<"target", "Format of the input and output file">,                Values<"binary">; -def F : JoinedOrSeparate<["-"], "F">, Alias<target>; +def F : JoinedOrSeparate<["-"], "F">, +        Alias<target>, +        HelpText<"Alias for --target">;  defm input_target : Eq<"input-target", "Format of the input file">,                      Values<"binary">; -def I : JoinedOrSeparate<["-"], "I">, Alias<input_target>; +def I : JoinedOrSeparate<["-"], "I">, +        Alias<input_target>, +        HelpText<"Alias for --input-target">;  defm output_target : Eq<"output-target", "Format of the output file">,                       Values<"binary">; -def O : JoinedOrSeparate<["-"], "O">, Alias<output_target>; +def O : JoinedOrSeparate<["-"], "O">, +        Alias<output_target>, +        HelpText<"Alias for --output-target">; + +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'.">;  def compress_debug_sections : Flag<["--"], "compress-debug-sections">;  def compress_debug_sections_eq @@ -46,34 +42,10 @@ defm split_dwo                        "<dwo-file>, then strip-dwo on the input file">,        MetaVarName<"dwo-file">; -def enable_deterministic_archives -    : Flag<["--"], "enable-deterministic-archives">, -      HelpText<"Enable deterministic mode when copying archives (use zero for " -               "UIDs, GIDs, and timestamps).">; -def D : Flag<["-"], "D">, -        Alias<enable_deterministic_archives>, -        HelpText<"Alias for --enable-deterministic-archives">; - -def disable_deterministic_archives -    : Flag<["--"], "disable-deterministic-archives">, -      HelpText<"Disable deterministic mode when copying archives (use real " -               "values for UIDs, GIDs, and timestamps).">; -def U : Flag<["-"], "U">, -        Alias<disable_deterministic_archives>, -        HelpText<"Alias for --disable-deterministic-archives">; - -def preserve_dates : Flag<["--"], "preserve-dates">, -                     HelpText<"Preserve access and modification timestamps">; -def p : Flag<["-"], "p">, Alias<preserve_dates>; -  defm add_gnu_debuglink      : Eq<"add-gnu-debuglink", "Add a .gnu_debuglink for <debug-file>">,        MetaVarName<"debug-file">; -defm remove_section : Eq<"remove-section", "Remove <section>">, -                      MetaVarName<"section">; -def R : JoinedOrSeparate<["-"], "R">, Alias<remove_section>; -  defm rename_section      : Eq<"rename-section",           "Renames a section from old to new, optionally with specified flags. " @@ -93,16 +65,20 @@ defm redefine_symbols           "symbols from many files.">,                 MetaVarName<"filename">; -defm keep_section : Eq<"keep-section", "Keep <section>">, -                    MetaVarName<"section">;  defm only_section : Eq<"only-section", "Remove all but <section>">,                      MetaVarName<"section">; -def j : JoinedOrSeparate<["-"], "j">, Alias<only_section>; +def j : JoinedOrSeparate<["-"], "j">, +        Alias<only_section>, +        HelpText<"Alias for --only-section">;  defm add_section      : Eq<"add-section",           "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.">, +      MetaVarName<"section=align">; +  defm set_section_flags      : Eq<"set-section-flags",           "Set section flags for a given section. Flags supported for GNU " @@ -110,27 +86,14 @@ defm set_section_flags           "rom, share, contents, merge, strings.">,        MetaVarName<"section=flag1[,flag2,...]">; -def strip_all : Flag<["--"], "strip-all">, -                HelpText<"Remove non-allocated sections outside segments. " -                         ".gnu.warning* and .ARM.attribute sections are not " -                         "removed">; -def S : Flag<["-"], "S">, Alias<strip_all>; -def strip_all_gnu : Flag<["--"], "strip-all-gnu">, -                    HelpText<"Compatible with GNU objcopy's --strip-all">; -def strip_debug : Flag<["--"], "strip-debug">, -                  HelpText<"Remove all debug information">; -def g : Flag<["-"], "g">, Alias<strip_debug>, -        HelpText<"Alias for --strip-debug">; +def S : Flag<["-"], "S">, +        Alias<strip_all>, +        HelpText<"Alias for --strip-all">;  def strip_dwo : Flag<["--"], "strip-dwo">,                  HelpText<"Remove all DWARF .dwo sections from file">; -def strip_sections -    : Flag<["--"], "strip-sections">, -      HelpText<"Remove all section headers and all sections not in segments">;  def strip_non_alloc      : Flag<["--"], "strip-non-alloc">,        HelpText<"Remove all non-allocated sections outside segments">; -def strip_unneeded : Flag<["--"], "strip-unneeded">, -                     HelpText<"Remove all symbols not needed by relocations">;  defm strip_unneeded_symbol      : Eq<"strip-unneeded-symbol",           "Remove symbol <symbol> if it is not needed by relocations">, @@ -164,7 +127,9 @@ defm localize_symbols           "Reads a list of symbols from <filename> and marks them local.">,        MetaVarName<"filename">; -def L : JoinedOrSeparate<["-"], "L">, Alias<localize_symbol>; +def L : JoinedOrSeparate<["-"], "L">, +        Alias<localize_symbol>, +        HelpText<"Alias for --localize-symbol">;  defm globalize_symbol : Eq<"globalize-symbol", "Mark <symbol> as global">,                          MetaVarName<"symbol">; @@ -179,7 +144,9 @@ defm keep_global_symbol           "Convert all symbols except <symbol> to local. May be repeated to "           "convert all except a set of symbols to local.">,        MetaVarName<"symbol">; -def G : JoinedOrSeparate<["-"], "G">, Alias<keep_global_symbol>; +def G : JoinedOrSeparate<["-"], "G">, +        Alias<keep_global_symbol>, +        HelpText<"Alias for --keep-global-symbol">;  defm keep_global_symbols      : Eq<"keep-global-symbols", @@ -197,31 +164,17 @@ defm weaken_symbols           "Reads a list of symbols from <filename> and marks them weak.">,        MetaVarName<"filename">; -def W : JoinedOrSeparate<["-"], "W">, Alias<weaken_symbol>; +def W : JoinedOrSeparate<["-"], "W">, +        Alias<weaken_symbol>, +        HelpText<"Alias for --weaken-symbol">;  def weaken : Flag<["--"], "weaken">,               HelpText<"Mark all global symbols as weak">; -def discard_locals : Flag<["--"], "discard-locals">, -                     HelpText<"Remove compiler-generated local symbols, (e.g. " -                              "symbols starting with .L)">; -def X : Flag<["-"], "X">, Alias<discard_locals>; - -def discard_all -    : Flag<["--"], "discard-all">, -      HelpText<"Remove all local symbols except file and section symbols">; -def x : Flag<["-"], "x">, Alias<discard_all>; -defm strip_symbol : Eq<"strip-symbol", "Remove symbol <symbol>">, -                    MetaVarName<"symbol">;  defm strip_symbols      : Eq<"strip-symbols",           "Reads a list of symbols from <filename> and removes them.">,        MetaVarName<"filename">; -def N : JoinedOrSeparate<["-"], "N">, Alias<strip_symbol>; -defm keep_symbol : Eq<"keep-symbol", "Do not remove symbol <symbol>">, -                   MetaVarName<"symbol">; -def K : JoinedOrSeparate<["-"], "K">, Alias<keep_symbol>; -  defm keep_symbols      : Eq<"keep-symbols",           "Reads a list of symbols from <filename> and runs as if " @@ -231,13 +184,6 @@ defm keep_symbols           "be repeated to read symbols from many files.">,        MetaVarName<"filename">; -def only_keep_debug -    : Flag<["--"], "only-keep-debug">, -      HelpText<"Clear sections that would not be stripped by --strip-debug. " -               "Currently only implemented for COFF.">; - -def keep_file_symbols : Flag<["--"], "keep-file-symbols">, -                        HelpText<"Do not remove file symbols">;  defm dump_section      : Eq<"dump-section",           "Dump contents of section named <section> into file <file>">, @@ -250,9 +196,6 @@ defm prefix_alloc_sections      : Eq<"prefix-alloc-sections", "Add <prefix> to the start of every allocated section name">,        MetaVarName<"prefix">; -def version : Flag<["--"], "version">, -              HelpText<"Print the version and exit.">; -def V : Flag<["-"], "V">, Alias<version>;  defm build_id_link_dir      : Eq<"build-id-link-dir", "Set directory for --build-id-link-input and "                                "--build-id-link-output to <dir>">, @@ -266,10 +209,6 @@ defm build_id_link_output                                   "name derived from hex build ID">,        MetaVarName<"suffix">; -def regex -    : Flag<["--"], "regex">, -      HelpText<"Permit regular expressions in name comparison">; -  defm set_start : Eq<"set-start", "Set the start address to <addr>. Overrides "                      "any previous --change-start or --adjust-start values.">,                   MetaVarName<"addr">; @@ -278,11 +217,12 @@ defm change_start : Eq<"change-start", "Add <incr> to the start address. Can be                         "cumulatively.">,                      MetaVarName<"incr">;  def adjust_start : JoinedOrSeparate<["--"], "adjust-start">, -                   Alias<change_start>; +                   Alias<change_start>, +                   HelpText<"Alias for --change-start">;  defm add_symbol      : Eq<"add-symbol", "Add new symbol <name> to .symtab. Accepted flags: " -         "global, local, weak, default, hidden, file, section, object, " +         "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.">, diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/StripOpts.td b/contrib/llvm-project/llvm/tools/llvm-objcopy/StripOpts.td index a80a91e744a9..cd02cffae673 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/StripOpts.td +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/StripOpts.td @@ -1,97 +1,17 @@ -include "llvm/Option/OptParser.td" +include "CommonOpts.td" -multiclass Eq<string name, string help> { -  def NAME : Separate<["--"], name>; -  def NAME #_eq : Joined<["--"], name #"=">, -                  Alias<!cast<Separate>(NAME)>, -                  HelpText<help>; -} +def output : JoinedOrSeparate<["-"], "o">, HelpText<"Write output to <file>">, +             MetaVarName<"<file>">; -def help : Flag<["--"], "help">; -def h : Flag<["-"], "h">, Alias<help>; - -def allow_broken_links -    : Flag<["--"], "allow-broken-links">, -      HelpText<"Allow llvm-strip to remove sections even if it would leave " -               "invalid section references. The appropriate sh_link fields " -               "will be set to zero.">; - -def enable_deterministic_archives -    : Flag<["--"], "enable-deterministic-archives">, -      HelpText<"Enable deterministic mode when stripping archives (use zero " -               "for UIDs, GIDs, and timestamps).">; -def D : Flag<["-"], "D">, -        Alias<enable_deterministic_archives>, -        HelpText<"Alias for --enable-deterministic-archives">; - -def disable_deterministic_archives -    : Flag<["--"], "disable-deterministic-archives">, -      HelpText<"Disable deterministic mode when stripping archives (use real " -               "values for UIDs, GIDs, and timestamps).">; -def U : Flag<["-"], "U">, -        Alias<disable_deterministic_archives>, -        HelpText<"Alias for --disable-deterministic-archives">; - -def output : JoinedOrSeparate<["-"], "o">, HelpText<"Write output to <file>">; - -def preserve_dates : Flag<["--"], "preserve-dates">, -                     HelpText<"Preserve access and modification timestamps">; -def p : Flag<["-"], "p">, Alias<preserve_dates>; - -def strip_all : Flag<["--"], "strip-all">, -                HelpText<"Remove non-allocated sections outside segments. " -                          ".gnu.warning* and .ARM.attribute sections are not " -                          "removed">; -def s : Flag<["-"], "s">, Alias<strip_all>; +def s : Flag<["-"], "s">, +        Alias<strip_all>, +        HelpText<"Alias for --strip-all">;  def no_strip_all : Flag<["--"], "no-strip-all">,                     HelpText<"Disable --strip-all">; -def strip_all_gnu : Flag<["--"], "strip-all-gnu">, -                    HelpText<"Compatible with GNU strip's --strip-all">; -def strip_debug : Flag<["--"], "strip-debug">, -                  HelpText<"Remove debugging symbols only">; -def d : Flag<["-"], "d">, Alias<strip_debug>; -def g : Flag<["-"], "g">, Alias<strip_debug>; -def S : Flag<["-"], "S">, Alias<strip_debug>; -def strip_unneeded : Flag<["--"], "strip-unneeded">, -                     HelpText<"Remove all symbols not needed by relocations">; - -defm remove_section : Eq<"remove-section", "Remove <section>">, -                      MetaVarName<"section">; -def R : JoinedOrSeparate<["-"], "R">, Alias<remove_section>; - -defm strip_symbol : Eq<"strip-symbol", "Strip <symbol>">, -                    MetaVarName<"symbol">; -def N : JoinedOrSeparate<["-"], "N">, Alias<strip_symbol>; - -defm keep_section : Eq<"keep-section", "Keep <section>">, -                    MetaVarName<"section">; -defm keep_symbol : Eq<"keep-symbol", "Do not remove symbol <symbol>">, -                   MetaVarName<"symbol">; -def keep_file_symbols : Flag<["--"], "keep-file-symbols">, -                        HelpText<"Do not remove file symbols">; - -def K : JoinedOrSeparate<["-"], "K">, Alias<keep_symbol>; - -def only_keep_debug -    : Flag<["--"], "only-keep-debug">, -      HelpText<"Clear sections that would not be stripped by --strip-debug. " -               "Currently only implemented for COFF.">; - -def discard_locals : Flag<["--"], "discard-locals">, -                     HelpText<"Remove compiler-generated local symbols, (e.g. " -                              "symbols starting with .L)">; -def X : Flag<["-"], "X">, Alias<discard_locals>; - -def discard_all -    : Flag<["--"], "discard-all">, -      HelpText<"Remove all local symbols except file and section symbols">; -def x : Flag<["-"], "x">, Alias<discard_all>; - -def regex -    : Flag<["--"], "regex">, -      HelpText<"Permit regular expressions in name comparison">; - -def version : Flag<["--"], "version">, -              HelpText<"Print the version and exit.">; -def V : Flag<["-"], "V">, Alias<version>; +def d : Flag<["-"], "d">, +        Alias<strip_debug>, +        HelpText<"Alias for --strip-debug">; +def S : Flag<["-"], "S">, +        Alias<strip_debug>, +        HelpText<"Alias for --strip-debug">; 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 e9372176e43b..e662f35f4b08 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -29,6 +29,7 @@  #include "llvm/Option/ArgList.h"  #include "llvm/Option/Option.h"  #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h"  #include "llvm/Support/Error.h"  #include "llvm/Support/ErrorHandling.h"  #include "llvm/Support/ErrorOr.h" @@ -36,6 +37,7 @@  #include "llvm/Support/Memory.h"  #include "llvm/Support/Path.h"  #include "llvm/Support/Process.h" +#include "llvm/Support/StringSaver.h"  #include "llvm/Support/WithColor.h"  #include "llvm/Support/raw_ostream.h"  #include <algorithm> @@ -84,7 +86,7 @@ LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {  ErrorSuccess reportWarning(Error E) {    assert(E); -  WithColor::warning(errs(), ToolName) << toString(std::move(E)); +  WithColor::warning(errs(), ToolName) << toString(std::move(E)) << '\n';    return Error::success();  } @@ -130,16 +132,18 @@ static Error deepWriteArchive(StringRef ArcName,  /// The function executeObjcopyOnIHex does the dispatch based on the format  /// of the output specified by the command line options. -static Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, +static Error executeObjcopyOnIHex(CopyConfig &Config, MemoryBuffer &In,                                    Buffer &Out) {    // TODO: support output formats other than ELF. +  if (Error E = Config.parseELFConfig()) +    return E;    return elf::executeObjcopyOnIHex(Config, In, Out);  }  /// The function executeObjcopyOnRawBinary does the dispatch based on the format  /// of the output specified by the command line options. -static Error executeObjcopyOnRawBinary(const CopyConfig &Config, -                                       MemoryBuffer &In, Buffer &Out) { +static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In, +                                       Buffer &Out) {    switch (Config.OutputFormat) {    case FileFormat::ELF:    // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the @@ -148,6 +152,8 @@ static Error executeObjcopyOnRawBinary(const CopyConfig &Config,    case FileFormat::Binary:    case FileFormat::IHex:    case FileFormat::Unspecified: +    if (Error E = Config.parseELFConfig()) +      return E;      return elf::executeObjcopyOnRawBinary(Config, In, Out);    } @@ -156,11 +162,13 @@ static Error executeObjcopyOnRawBinary(const CopyConfig &Config,  /// The function executeObjcopyOnBinary does the dispatch based on the format  /// of the input binary (ELF, MachO or COFF). -static Error executeObjcopyOnBinary(const CopyConfig &Config, -                                    object::Binary &In, Buffer &Out) { -  if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) +static Error executeObjcopyOnBinary(CopyConfig &Config, object::Binary &In, +                                    Buffer &Out) { +  if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) { +    if (Error E = Config.parseELFConfig()) +      return E;      return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out); -  else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In)) +  } else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In))      return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out);    else if (auto *MachOBinary = dyn_cast<object::MachOObjectFile>(&In))      return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out); @@ -169,8 +177,7 @@ static Error executeObjcopyOnBinary(const CopyConfig &Config,                               "unsupported object file format");  } -static Error executeObjcopyOnArchive(const CopyConfig &Config, -                                     const Archive &Ar) { +static Error executeObjcopyOnArchive(CopyConfig &Config, const Archive &Ar) {    std::vector<NewArchiveMember> NewArchiveMembers;    Error Err = Error::success();    for (const Archive::Child &Child : Ar.children(Err)) { @@ -246,7 +253,7 @@ static Error restoreStatOnFile(StringRef Filename,  /// The function executeObjcopy does the higher level dispatch based on the type  /// of input (raw binary, archive or single object file) and takes care of the  /// format-agnostic modifications, i.e. preserving dates. -static Error executeObjcopy(const CopyConfig &Config) { +static Error executeObjcopy(CopyConfig &Config) {    sys::fs::file_status Stat;    if (Config.InputFilename != "-") {      if (auto EC = sys::fs::status(Config.InputFilename, Stat)) @@ -255,7 +262,7 @@ static Error executeObjcopy(const CopyConfig &Config) {      Stat.permissions(static_cast<sys::fs::perms>(0777));    } -  typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &); +  using ProcessRawFn = Error (*)(CopyConfig &, MemoryBuffer &, Buffer &);    ProcessRawFn ProcessRaw;    switch (Config.InputFormat) {    case FileFormat::Binary: @@ -306,19 +313,45 @@ static Error executeObjcopy(const CopyConfig &Config) {    return Error::success();  } +namespace { + +enum class ToolType { Objcopy, Strip, InstallNameTool }; + +} // anonymous namespace +  int main(int argc, char **argv) {    InitLLVM X(argc, argv);    ToolName = argv[0]; -  bool IsStrip = sys::path::stem(ToolName).contains("strip"); +  ToolType Tool = StringSwitch<ToolType>(sys::path::stem(ToolName)) +                      .EndsWith("strip", ToolType::Strip) +                      .EndsWith("install-name-tool", ToolType::InstallNameTool) +                      .EndsWith("install_name_tool", ToolType::InstallNameTool) +                      .Default(ToolType::Objcopy); +  // Expand response files. +  // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp, +  // into a separate function in the CommandLine library and call that function +  // here. This is duplicated code. +  SmallVector<const char *, 20> NewArgv(argv, argv + argc); +  BumpPtrAllocator A; +  StringSaver Saver(A); +  cl::ExpandResponseFiles(Saver, +                          Triple(sys::getProcessTriple()).isOSWindows() +                              ? cl::TokenizeWindowsCommandLine +                              : cl::TokenizeGNUCommandLine, +                          NewArgv); + +  auto Args = makeArrayRef(NewArgv).drop_front();    Expected<DriverConfig> DriverConfig = -      IsStrip ? parseStripOptions(makeArrayRef(argv + 1, argc), reportWarning) -              : parseObjcopyOptions(makeArrayRef(argv + 1, argc)); +      (Tool == ToolType::Strip) ? parseStripOptions(Args, reportWarning) +                                : ((Tool == ToolType::InstallNameTool) +                                       ? parseInstallNameToolOptions(Args) +                                       : parseObjcopyOptions(Args, reportWarning));    if (!DriverConfig) {      logAllUnhandledErrors(DriverConfig.takeError(),                            WithColor::error(errs(), ToolName));      return 1;    } -  for (const CopyConfig &CopyConfig : DriverConfig->CopyConfigs) { +  for (CopyConfig &CopyConfig : DriverConfig->CopyConfigs) {      if (Error E = executeObjcopy(CopyConfig)) {        logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName));        return 1; diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp index 1ba0a68902c9..60b0f5a3cbd1 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp @@ -234,15 +234,14 @@ printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {    if (Count == 0)      return; -  const pe32_header *PE32Header; -  error(Obj->getPE32Header(PE32Header)); -  uint32_t ImageBase = PE32Header->ImageBase;    uintptr_t IntPtr = 0; -  error(Obj->getVaPtr(TableVA, IntPtr)); +  if (std::error_code EC = Obj->getVaPtr(TableVA, IntPtr)) +    reportError(errorCodeToError(EC), Obj->getFileName()); +    const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;    outs() << "SEH Table:";    for (int I = 0; I < Count; ++I) -    outs() << format(" 0x%x", P[I] + ImageBase); +    outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase);    outs() << "\n\n";  } @@ -268,22 +267,24 @@ static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {  }  static void printTLSDirectory(const COFFObjectFile *Obj) { -  const pe32_header *PE32Header; -  error(Obj->getPE32Header(PE32Header)); - -  const pe32plus_header *PE32PlusHeader; -  error(Obj->getPE32PlusHeader(PE32PlusHeader)); +  const pe32_header *PE32Header = Obj->getPE32Header(); +  const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();    // Skip if it's not executable.    if (!PE32Header && !PE32PlusHeader)      return;    const data_directory *DataDir; -  error(Obj->getDataDirectory(COFF::TLS_TABLE, DataDir)); -  uintptr_t IntPtr = 0; +  if (std::error_code EC = Obj->getDataDirectory(COFF::TLS_TABLE, DataDir)) +    reportError(errorCodeToError(EC), Obj->getFileName()); +    if (DataDir->RelativeVirtualAddress == 0)      return; -  error(Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr)); + +  uintptr_t IntPtr = 0; +  if (std::error_code EC = +          Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr)) +    reportError(errorCodeToError(EC), Obj->getFileName());    if (PE32Header) {      auto *TLSDir = reinterpret_cast<const coff_tls_directory32 *>(IntPtr); @@ -298,9 +299,7 @@ static void printTLSDirectory(const COFFObjectFile *Obj) {  static void printLoadConfiguration(const COFFObjectFile *Obj) {    // Skip if it's not executable. -  const pe32_header *PE32Header; -  error(Obj->getPE32Header(PE32Header)); -  if (!PE32Header) +  if (!Obj->getPE32Header())      return;    // Currently only x86 is supported @@ -308,11 +307,18 @@ static void printLoadConfiguration(const COFFObjectFile *Obj) {      return;    const data_directory *DataDir; -  error(Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir)); + +  if (std::error_code EC = +          Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir)) +    reportError(errorCodeToError(EC), Obj->getFileName()); +    uintptr_t IntPtr = 0;    if (DataDir->RelativeVirtualAddress == 0)      return; -  error(Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr)); + +  if (std::error_code EC = +          Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr)) +    reportError(errorCodeToError(EC), Obj->getFileName());    auto *LoadConf = reinterpret_cast<const coff_load_configuration32 *>(IntPtr);    outs() << "Load configuration:" @@ -442,8 +448,7 @@ static bool getPDataSection(const COFFObjectFile *Obj,                              std::vector<RelocationRef> &Rels,                              const RuntimeFunction *&RFStart, int &NumRFs) {    for (const SectionRef &Section : Obj->sections()) { -    StringRef Name; -    error(Section.getName(Name)); +    StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());      if (Name != ".pdata")        continue; @@ -455,7 +460,9 @@ static bool getPDataSection(const COFFObjectFile *Obj,      llvm::sort(Rels, isRelocAddressLess);      ArrayRef<uint8_t> Contents; -    error(Obj->getSectionContents(Pdata, Contents)); +    if (Error E = Obj->getSectionContents(Pdata, Contents)) +      reportError(std::move(E), Obj->getFileName()); +      if (Contents.empty())        continue; @@ -571,10 +578,12 @@ static void printRuntimeFunctionRels(const COFFObjectFile *Obj,    ArrayRef<uint8_t> XContents;    uint64_t UnwindInfoOffset = 0; -  error(getSectionContents( -          Obj, Rels, SectionOffset + -                         /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, -          XContents, UnwindInfoOffset)); +  if (Error E = getSectionContents( +          Obj, Rels, +          SectionOffset + +              /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, +          XContents, UnwindInfoOffset)) +    reportError(std::move(E), Obj->getFileName());    if (XContents.empty())      return; @@ -650,9 +659,12 @@ void printCOFFSymbolTable(const object::COFFImportFile *i) {  void printCOFFSymbolTable(const COFFObjectFile *coff) {    for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) {      Expected<COFFSymbolRef> Symbol = coff->getSymbol(SI); +    if (!Symbol) +      reportError(Symbol.takeError(), coff->getFileName()); +      StringRef Name; -    error(Symbol.takeError()); -    error(coff->getSymbolName(*Symbol, Name)); +    if (std::error_code EC = coff->getSymbolName(*Symbol, Name)) +      reportError(errorCodeToError(EC), coff->getFileName());      outs() << "[" << format("%2d", SI) << "]"             << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")" @@ -682,7 +694,9 @@ void printCOFFSymbolTable(const COFFObjectFile *coff) {      for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {        if (Symbol->isSectionDefinition()) {          const coff_aux_section_definition *asd; -        error(coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd)); +        if (std::error_code EC = +                coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd)) +          reportError(errorCodeToError(EC), coff->getFileName());          int32_t AuxNumber = asd->getNumber(Symbol->isBigObj()); @@ -697,7 +711,8 @@ void printCOFFSymbolTable(const COFFObjectFile *coff) {                           , unsigned(asd->Selection));        } else if (Symbol->isFileRecord()) {          const char *FileName; -        error(coff->getAuxSymbol<char>(SI + 1, FileName)); +        if (std::error_code EC = coff->getAuxSymbol<char>(SI + 1, FileName)) +          reportError(errorCodeToError(EC), coff->getFileName());          StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *                                       coff->getSymbolTableEntrySize()); @@ -707,7 +722,9 @@ void printCOFFSymbolTable(const COFFObjectFile *coff) {          break;        } else if (Symbol->isWeakExternal()) {          const coff_aux_weak_external *awe; -        error(coff->getAuxSymbol<coff_aux_weak_external>(SI + 1, awe)); +        if (std::error_code EC = +                coff->getAuxSymbol<coff_aux_weak_external>(SI + 1, awe)) +          reportError(errorCodeToError(EC), coff->getFileName());          outs() << "AUX " << format("indx %d srch %d\n",                                     static_cast<uint32_t>(awe->TagIndex), diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp index 9c4d67d0f1bd..abfe08346bbd 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp @@ -105,9 +105,12 @@ static Error getRelocationValueString(const ELFObjectFile<ELFT> *Obj,    } else {      Fmt << "*ABS*";    } - -  if (Addend != 0) -    Fmt << (Addend < 0 ? "" : "+") << Addend; +  if (Addend != 0) { +      Fmt << (Addend < 0 +          ? "-" +          : "+") << format("0x%" PRIx64, +                          (Addend < 0 ? -(uint64_t)Addend : (uint64_t)Addend)); +  }    Fmt.flush();    Result.append(FmtBuf.begin(), FmtBuf.end());    return Error::success(); @@ -178,7 +181,7 @@ void printDynamicSection(const ELFFile<ELFT> *Elf, StringRef Filename) {          outs() << (Data + Dyn.d_un.d_val) << "\n";          continue;        } -      warn(toString(StrTabOrErr.takeError())); +      reportWarning(toString(StrTabOrErr.takeError()), Filename);        consumeError(StrTabOrErr.takeError());      }      outs() << format(Fmt, (uint64_t)Dyn.d_un.d_val); @@ -201,6 +204,9 @@ template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) {      case ELF::PT_GNU_RELRO:        outs() << "   RELRO ";        break; +    case ELF::PT_GNU_PROPERTY: +      outs() << "   PROPERTY "; +      break;      case ELF::PT_GNU_STACK:        outs() << "   STACK ";        break; diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp index 58ff7be4543c..87c7a92933f1 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp @@ -29,6 +29,7 @@  #include "llvm/MC/MCInstrInfo.h"  #include "llvm/MC/MCRegisterInfo.h"  #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h"  #include "llvm/Object/MachO.h"  #include "llvm/Object/MachOUniversal.h"  #include "llvm/Support/Casting.h" @@ -236,11 +237,11 @@ struct SymbolSorter {    bool operator()(const SymbolRef &A, const SymbolRef &B) {      Expected<SymbolRef::Type> ATypeOrErr = A.getType();      if (!ATypeOrErr) -      report_error(ATypeOrErr.takeError(), A.getObject()->getFileName()); +      reportError(ATypeOrErr.takeError(), A.getObject()->getFileName());      SymbolRef::Type AType = *ATypeOrErr;      Expected<SymbolRef::Type> BTypeOrErr = B.getType();      if (!BTypeOrErr) -      report_error(BTypeOrErr.takeError(), B.getObject()->getFileName()); +      reportError(BTypeOrErr.takeError(), B.getObject()->getFileName());      SymbolRef::Type BType = *BTypeOrErr;      uint64_t AAddr = (AType != SymbolRef::ST_Function) ? 0 : A.getValue();      uint64_t BAddr = (BType != SymbolRef::ST_Function) ? 0 : B.getValue(); @@ -371,11 +372,8 @@ static void getSectionsAndSymbols(MachOObjectFile *MachOObj,        Symbols.push_back(Symbol);    } -  for (const SectionRef &Section : MachOObj->sections()) { -    StringRef SectName; -    Section.getName(SectName); +  for (const SectionRef &Section : MachOObj->sections())      Sections.push_back(Section); -  }    bool BaseSegmentAddressSet = false;    for (const auto &Command : MachOObj->load_commands()) { @@ -393,10 +391,40 @@ static void getSectionsAndSymbols(MachOObjectFile *MachOObj,          BaseSegmentAddressSet = true;          BaseSegmentAddress = SLC.vmaddr;        } +    } else if (Command.C.cmd == MachO::LC_SEGMENT_64) { +      MachO::segment_command_64 SLC = MachOObj->getSegment64LoadCommand(Command); +      StringRef SegName = SLC.segname; +      if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") { +        BaseSegmentAddressSet = true; +        BaseSegmentAddress = SLC.vmaddr; +      }      }    }  } +static bool DumpAndSkipDataInCode(uint64_t PC, const uint8_t *bytes, +                                 DiceTable &Dices, uint64_t &InstSize) { +  // Check the data in code table here to see if this is data not an +  // instruction to be disassembled. +  DiceTable Dice; +  Dice.push_back(std::make_pair(PC, DiceRef())); +  dice_table_iterator DTI = +      std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(), +                  compareDiceTableEntries); +  if (DTI != Dices.end()) { +    uint16_t Length; +    DTI->second.getLength(Length); +    uint16_t Kind; +    DTI->second.getKind(Kind); +    InstSize = DumpDataInCode(bytes, Length, Kind); +    if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) && +        (PC == (DTI->first + Length - 1)) && (Length & 1)) +      InstSize++; +    return true; +  } +  return false; +} +  static void printRelocationTargetName(const MachOObjectFile *O,                                        const MachO::any_relocation_info &RE,                                        raw_string_ostream &Fmt) { @@ -419,13 +447,11 @@ static void printRelocationTargetName(const MachOObjectFile *O,      // If we couldn't find a symbol that this relocation refers to, try      // to find a section beginning instead.      for (const SectionRef &Section : ToolSectionFilter(*O)) { -      StringRef Name;        uint64_t Addr = Section.getAddress();        if (Addr != Val)          continue; -      if (std::error_code EC = Section.getName(Name)) -        report_error(errorCodeToError(EC), O->getFileName()); -      Fmt << Name; +      StringRef NameOrErr = unwrapOrError(Section.getName(), O->getFileName()); +      Fmt << NameOrErr;        return;      } @@ -458,10 +484,14 @@ static void printRelocationTargetName(const MachOObjectFile *O,        --I;        advance(SI, 1);      } -    if (SI == O->section_end()) +    if (SI == O->section_end()) {        Fmt << Val << " (?,?)"; -    else -      SI->getName(S); +    } else { +      if (Expected<StringRef> NameOrErr = SI->getName()) +        S = *NameOrErr; +      else +        consumeError(NameOrErr.takeError()); +    }    }    Fmt << S; @@ -504,8 +534,8 @@ Error getMachORelocationValueString(const MachOObjectFile *Obj,        // NOTE: Scattered relocations don't exist on x86_64.        unsigned RType = Obj->getAnyRelocationType(RENext);        if (RType != MachO::X86_64_RELOC_UNSIGNED) -        report_error(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after " -                                         "X86_64_RELOC_SUBTRACTOR."); +        reportError(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after " +                                        "X86_64_RELOC_SUBTRACTOR.");        // The X86_64_RELOC_UNSIGNED contains the minuend symbol;        // X86_64_RELOC_SUBTRACTOR contains the subtrahend. @@ -553,8 +583,8 @@ Error getMachORelocationValueString(const MachOObjectFile *Obj,        unsigned RType = Obj->getAnyRelocationType(RENext);        if (RType != MachO::GENERIC_RELOC_PAIR) -        report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after " -                                         "GENERIC_RELOC_SECTDIFF."); +        reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after " +                                        "GENERIC_RELOC_SECTDIFF.");        printRelocationTargetName(Obj, RE, Fmt);        Fmt << "-"; @@ -574,8 +604,8 @@ Error getMachORelocationValueString(const MachOObjectFile *Obj,          // GENERIC_RELOC_PAIR.          unsigned RType = Obj->getAnyRelocationType(RENext);          if (RType != MachO::GENERIC_RELOC_PAIR) -          report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after " -                                           "GENERIC_RELOC_LOCAL_SECTDIFF."); +          reportError(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after " +                                          "GENERIC_RELOC_LOCAL_SECTDIFF.");          printRelocationTargetName(Obj, RE, Fmt);          Fmt << "-"; @@ -614,8 +644,8 @@ Error getMachORelocationValueString(const MachOObjectFile *Obj,          // ARM_RELOC_PAIR.          unsigned RType = Obj->getAnyRelocationType(RENext);          if (RType != MachO::ARM_RELOC_PAIR) -          report_error(Obj->getFileName(), "Expected ARM_RELOC_PAIR after " -                                           "ARM_RELOC_HALF"); +          reportError(Obj->getFileName(), "Expected ARM_RELOC_PAIR after " +                                          "ARM_RELOC_HALF");          // NOTE: The half of the target virtual address is stashed in the          // address field of the secondary relocation, but we can't reverse @@ -1501,7 +1531,12 @@ static void DumpLiteralPointerSection(MachOObjectFile *O,      uint64_t SectSize = Sect->getSize();      StringRef SectName; -    Sect->getName(SectName); +    Expected<StringRef> SectNameOrErr = Sect->getName(); +    if (SectNameOrErr) +      SectName = *SectNameOrErr; +    else +      consumeError(SectNameOrErr.takeError()); +      DataRefImpl Ref = Sect->getRawDataRefImpl();      StringRef SegmentName = O->getSectionFinalSegmentName(Ref);      outs() << SegmentName << ":" << SectName << ":"; @@ -1713,7 +1748,12 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,      }      for (const SectionRef &Section : O->sections()) {        StringRef SectName; -      Section.getName(SectName); +      Expected<StringRef> SecNameOrErr = Section.getName(); +      if (SecNameOrErr) +        SectName = *SecNameOrErr; +      else +        consumeError(SecNameOrErr.takeError()); +        DataRefImpl Ref = Section.getRawDataRefImpl();        StringRef SegName = O->getSectionFinalSegmentName(Ref);        if ((DumpSegName.empty() || SegName == DumpSegName) && @@ -1809,7 +1849,12 @@ static void DumpInfoPlistSectionContents(StringRef Filename,                                           MachOObjectFile *O) {    for (const SectionRef &Section : O->sections()) {      StringRef SectName; -    Section.getName(SectName); +    Expected<StringRef> SecNameOrErr = Section.getName(); +    if (SecNameOrErr) +      SectName = *SecNameOrErr; +    else +      consumeError(SecNameOrErr.takeError()); +      DataRefImpl Ref = Section.getRawDataRefImpl();      StringRef SegName = O->getSectionFinalSegmentName(Ref);      if (SegName == "__TEXT" && SectName == "__info_plist") { @@ -1901,12 +1946,16 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,    // the error message.    if (Disassemble || IndirectSymbols || !FilterSections.empty() || UnwindInfo)      if (Error Err = MachOOF->checkSymbolTable()) -      report_error(std::move(Err), ArchiveName, FileName, ArchitectureName); +      reportError(std::move(Err), FileName, ArchiveName, ArchitectureName);    if (DisassembleAll) {      for (const SectionRef &Section : MachOOF->sections()) {        StringRef SectName; -      Section.getName(SectName); +      if (Expected<StringRef> NameOrErr = Section.getName()) +        SectName = *NameOrErr; +      else +        consumeError(NameOrErr.takeError()); +        if (SectName.equals("__text")) {          DataRefImpl Ref = Section.getRawDataRefImpl();          StringRef SegName = MachOOF->getSectionFinalSegmentName(Ref); @@ -2151,7 +2200,7 @@ static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,      outs() << "    offset " << OFA.getOffset();      if (OFA.getOffset() > size)        outs() << " (past end of file)"; -    if (OFA.getOffset() % (1 << OFA.getAlign()) != 0) +    if (OFA.getOffset() % (1ull << OFA.getAlign()) != 0)        outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")";      outs() << "\n";      outs() << "    size " << OFA.getSize(); @@ -2165,12 +2214,14 @@ static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,  }  static void printArchiveChild(StringRef Filename, const Archive::Child &C, -                              bool verbose, bool print_offset, +                              size_t ChildIndex, bool verbose, +                              bool print_offset,                                StringRef ArchitectureName = StringRef()) {    if (print_offset)      outs() << C.getChildOffset() << "\t";    sys::fs::perms Mode = -      unwrapOrError(C.getAccessMode(), Filename, C, ArchitectureName); +      unwrapOrError(C.getAccessMode(), getFileNameForError(C, ChildIndex), +                    Filename, ArchitectureName);    if (verbose) {      // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.      // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG. @@ -2188,11 +2239,14 @@ static void printArchiveChild(StringRef Filename, const Archive::Child &C,      outs() << format("0%o ", Mode);    } -  outs() << format( -      "%3d/%-3d %5" PRId64 " ", -      unwrapOrError(C.getUID(), Filename, C, ArchitectureName), -      unwrapOrError(C.getGID(), Filename, C, ArchitectureName), -      unwrapOrError(C.getRawSize(), Filename, C, ArchitectureName)); +  outs() << format("%3d/%-3d %5" PRId64 " ", +                   unwrapOrError(C.getUID(), getFileNameForError(C, ChildIndex), +                                 Filename, ArchitectureName), +                   unwrapOrError(C.getGID(), getFileNameForError(C, ChildIndex), +                                 Filename, ArchitectureName), +                   unwrapOrError(C.getRawSize(), +                                 getFileNameForError(C, ChildIndex), Filename, +                                 ArchitectureName));    StringRef RawLastModified = C.getRawLastModified();    if (verbose) { @@ -2215,14 +2269,17 @@ static void printArchiveChild(StringRef Filename, const Archive::Child &C,      Expected<StringRef> NameOrErr = C.getName();      if (!NameOrErr) {        consumeError(NameOrErr.takeError()); -      outs() << unwrapOrError(C.getRawName(), Filename, C, ArchitectureName) +      outs() << unwrapOrError(C.getRawName(), +                              getFileNameForError(C, ChildIndex), Filename, +                              ArchitectureName)               << "\n";      } else {        StringRef Name = NameOrErr.get();        outs() << Name << "\n";      }    } else { -    outs() << unwrapOrError(C.getRawName(), Filename, C, ArchitectureName) +    outs() << unwrapOrError(C.getRawName(), getFileNameForError(C, ChildIndex), +                            Filename, ArchitectureName)             << "\n";    }  } @@ -2231,11 +2288,13 @@ static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,                                  bool print_offset,                                  StringRef ArchitectureName = StringRef()) {    Error Err = Error::success(); +  size_t I = 0;    for (const auto &C : A->children(Err, false)) -    printArchiveChild(Filename, C, verbose, print_offset, ArchitectureName); +    printArchiveChild(Filename, C, I++, verbose, print_offset, +                      ArchitectureName);    if (Err) -    report_error(std::move(Err), StringRef(), Filename, ArchitectureName); +    reportError(std::move(Err), Filename, "", ArchitectureName);  }  static bool ValidateArchFlags() { @@ -2267,7 +2326,7 @@ void parseInputMachO(StringRef Filename) {    Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);    if (!BinaryOrErr) {      if (Error E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError())) -      report_error(std::move(E), Filename); +      reportError(std::move(E), Filename);      else        outs() << Filename << ": is not an object file\n";      return; @@ -2280,11 +2339,13 @@ void parseInputMachO(StringRef Filename) {        printArchiveHeaders(Filename, A, !NonVerbose, ArchiveMemberOffsets);      Error Err = Error::success(); +    unsigned I = -1;      for (auto &C : A->children(Err)) { +      ++I;        Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();        if (!ChildOrErr) {          if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) -          report_error(std::move(E), Filename, C); +          reportError(std::move(E), getFileNameForError(C, I), Filename);          continue;        }        if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) { @@ -2294,7 +2355,7 @@ void parseInputMachO(StringRef Filename) {        }      }      if (Err) -      report_error(std::move(Err), Filename); +      reportError(std::move(Err), Filename);      return;    }    if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) { @@ -2346,7 +2407,7 @@ void parseInputMachO(MachOUniversalBinary *UB) {                ProcessMachO(Filename, MachOOF, "", ArchitectureName);            } else if (Error E = isNotObjectErrorInvalidFileType(                           ObjOrErr.takeError())) { -            report_error(std::move(E), Filename, StringRef(), ArchitectureName); +            reportError(std::move(E), "", Filename, ArchitectureName);              continue;            } else if (Expected<std::unique_ptr<Archive>> AOrErr =                           I->getAsArchive()) { @@ -2359,11 +2420,15 @@ void parseInputMachO(MachOUniversalBinary *UB) {                printArchiveHeaders(Filename, A.get(), !NonVerbose,                                    ArchiveMemberOffsets, ArchitectureName);              Error Err = Error::success(); +            unsigned I = -1;              for (auto &C : A->children(Err)) { +              ++I;                Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();                if (!ChildOrErr) { -                if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) -                  report_error(std::move(E), Filename, C, ArchitectureName); +                if (Error E = +                        isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) +                  reportError(std::move(E), getFileNameForError(C, I), Filename, +                              ArchitectureName);                  continue;                }                if (MachOObjectFile *O = @@ -2371,12 +2436,13 @@ void parseInputMachO(MachOUniversalBinary *UB) {                  ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);              }              if (Err) -              report_error(std::move(Err), Filename); +              reportError(std::move(Err), Filename);            } else {              consumeError(AOrErr.takeError()); -            error("Mach-O universal file: " + Filename + " for " + -                  "architecture " + StringRef(I->getArchFlagName()) + -                  " is not a Mach-O file or an archive file"); +            reportError(Filename, +                        "Mach-O universal file for architecture " + +                            StringRef(I->getArchFlagName()) + +                            " is not a Mach-O file or an archive file");            }          }        } @@ -2406,7 +2472,7 @@ void parseInputMachO(MachOUniversalBinary *UB) {              ProcessMachO(Filename, MachOOF);          } else if (Error E =                         isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { -          report_error(std::move(E), Filename); +          reportError(std::move(E), Filename);          } else if (Expected<std::unique_ptr<Archive>> AOrErr =                         I->getAsArchive()) {            std::unique_ptr<Archive> &A = *AOrErr; @@ -2415,12 +2481,14 @@ void parseInputMachO(MachOUniversalBinary *UB) {              printArchiveHeaders(Filename, A.get(), !NonVerbose,                                  ArchiveMemberOffsets);            Error Err = Error::success(); +          unsigned I = -1;            for (auto &C : A->children(Err)) { +            ++I;              Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();              if (!ChildOrErr) {                if (Error E =                        isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) -                report_error(std::move(E), Filename, C); +                reportError(std::move(E), getFileNameForError(C, I), Filename);                continue;              }              if (MachOObjectFile *O = @@ -2428,12 +2496,12 @@ void parseInputMachO(MachOUniversalBinary *UB) {                ProcessMachO(Filename, O, O->getFileName());            }            if (Err) -            report_error(std::move(Err), Filename); +            reportError(std::move(Err), Filename);          } else {            consumeError(AOrErr.takeError()); -          error("Mach-O universal file: " + Filename + " for architecture " + -                StringRef(I->getArchFlagName()) + -                " is not a Mach-O file or an archive file"); +          reportError(Filename, "Mach-O universal file for architecture " + +                                    StringRef(I->getArchFlagName()) + +                                    " is not a Mach-O file or an archive file");          }          return;        } @@ -2455,7 +2523,7 @@ void parseInputMachO(MachOUniversalBinary *UB) {          ProcessMachO(Filename, MachOOF, "", ArchitectureName);      } else if (Error E =                     isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { -      report_error(std::move(E), StringRef(), Filename, ArchitectureName); +      reportError(std::move(E), Filename, "", ArchitectureName);      } else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {        std::unique_ptr<Archive> &A = *AOrErr;        outs() << "Archive : " << Filename; @@ -2466,11 +2534,14 @@ void parseInputMachO(MachOUniversalBinary *UB) {          printArchiveHeaders(Filename, A.get(), !NonVerbose,                              ArchiveMemberOffsets, ArchitectureName);        Error Err = Error::success(); +      unsigned I = -1;        for (auto &C : A->children(Err)) { +        ++I;          Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();          if (!ChildOrErr) {            if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) -            report_error(std::move(E), Filename, C, ArchitectureName); +            reportError(std::move(E), getFileNameForError(C, I), Filename, +                        ArchitectureName);            continue;          }          if (MachOObjectFile *O = @@ -2481,12 +2552,12 @@ void parseInputMachO(MachOUniversalBinary *UB) {          }        }        if (Err) -        report_error(std::move(Err), Filename); +        reportError(std::move(Err), Filename);      } else {        consumeError(AOrErr.takeError()); -      error("Mach-O universal file: " + Filename + " for architecture " + -            StringRef(I->getArchFlagName()) + -            " is not a Mach-O file or an archive file"); +      reportError(Filename, "Mach-O universal file for architecture " + +                                StringRef(I->getArchFlagName()) + +                                " is not a Mach-O file or an archive file");      }    }  } @@ -3083,7 +3154,7 @@ static void method_reference(struct DisassembleInfo *info,      if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {        if (info->selector_name != nullptr) {          if (info->class_name != nullptr) { -          info->method = llvm::make_unique<char[]>( +          info->method = std::make_unique<char[]>(                5 + strlen(info->class_name) + strlen(info->selector_name));            char *method = info->method.get();            if (method != nullptr) { @@ -3097,7 +3168,7 @@ static void method_reference(struct DisassembleInfo *info,            }          } else {            info->method = -              llvm::make_unique<char[]>(9 + strlen(info->selector_name)); +              std::make_unique<char[]>(9 + strlen(info->selector_name));            char *method = info->method.get();            if (method != nullptr) {              if (Arch == Triple::x86_64) @@ -3117,7 +3188,7 @@ static void method_reference(struct DisassembleInfo *info,      } else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {        if (info->selector_name != nullptr) {          info->method = -            llvm::make_unique<char[]>(17 + strlen(info->selector_name)); +            std::make_unique<char[]>(17 + strlen(info->selector_name));          char *method = info->method.get();          if (method != nullptr) {            if (Arch == Triple::x86_64) @@ -3217,7 +3288,13 @@ static const char *get_pointer_64(uint64_t Address, uint32_t &offset,        continue;      if (objc_only) {        StringRef SectName; -      ((*(info->Sections))[SectIdx]).getName(SectName); +      Expected<StringRef> SecNameOrErr = +          ((*(info->Sections))[SectIdx]).getName(); +      if (SecNameOrErr) +        SectName = *SecNameOrErr; +      else +        consumeError(SecNameOrErr.takeError()); +        DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();        StringRef SegName = info->O->getSectionFinalSegmentName(Ref);        if (SegName != "__OBJC" && SectName != "__cstring") @@ -4009,7 +4086,12 @@ static const SectionRef get_section(MachOObjectFile *O, const char *segname,                                      const char *sectname) {    for (const SectionRef &Section : O->sections()) {      StringRef SectName; -    Section.getName(SectName); +    Expected<StringRef> SecNameOrErr = Section.getName(); +    if (SecNameOrErr) +      SectName = *SecNameOrErr; +    else +      consumeError(SecNameOrErr.takeError()); +      DataRefImpl Ref = Section.getRawDataRefImpl();      StringRef SegName = O->getSectionFinalSegmentName(Ref);      if (SegName == segname && SectName == sectname) @@ -4026,7 +4108,12 @@ walk_pointer_list_64(const char *listname, const SectionRef S,      return;    StringRef SectName; -  S.getName(SectName); +  Expected<StringRef> SecNameOrErr = S.getName(); +  if (SecNameOrErr) +    SectName = *SecNameOrErr; +  else +    consumeError(SecNameOrErr.takeError()); +    DataRefImpl Ref = S.getRawDataRefImpl();    StringRef SegName = O->getSectionFinalSegmentName(Ref);    outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; @@ -4075,8 +4162,7 @@ walk_pointer_list_32(const char *listname, const SectionRef S,    if (S == SectionRef())      return; -  StringRef SectName; -  S.getName(SectName); +  StringRef SectName = unwrapOrError(S.getName(), O->getFileName());    DataRefImpl Ref = S.getRawDataRefImpl();    StringRef SegName = O->getSectionFinalSegmentName(Ref);    outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; @@ -5750,7 +5836,12 @@ static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {      return;    StringRef SectName; -  S.getName(SectName); +  Expected<StringRef> SecNameOrErr = S.getName(); +  if (SecNameOrErr) +    SectName = *SecNameOrErr; +  else +    consumeError(SecNameOrErr.takeError()); +    DataRefImpl Ref = S.getRawDataRefImpl();    StringRef SegName = info->O->getSectionFinalSegmentName(Ref);    outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; @@ -5813,7 +5904,12 @@ static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {      return;    StringRef SectName; -  S.getName(SectName); +  Expected<StringRef> SecNameOrErr = S.getName(); +  if (SecNameOrErr) +    SectName = *SecNameOrErr; +  else +    consumeError(SecNameOrErr.takeError()); +    DataRefImpl Ref = S.getRawDataRefImpl();    StringRef SegName = info->O->getSectionFinalSegmentName(Ref);    outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; @@ -5859,7 +5955,12 @@ static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {      return;    StringRef SectName; -  S.getName(SectName); +  Expected<StringRef> SecNameOrErr = S.getName(); +  if (SecNameOrErr) +    SectName = *SecNameOrErr; +  else +    consumeError(SecNameOrErr.takeError()); +    DataRefImpl Ref = S.getRawDataRefImpl();    StringRef SegName = info->O->getSectionFinalSegmentName(Ref);    outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; @@ -5916,7 +6017,12 @@ static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {      return;    StringRef SectName; -  S.getName(SectName); +  Expected<StringRef> SecNameOrErr = S.getName(); +  if (SecNameOrErr) +    SectName = *SecNameOrErr; +  else +    consumeError(SecNameOrErr.takeError()); +    DataRefImpl Ref = S.getRawDataRefImpl();    StringRef SegName = info->O->getSectionFinalSegmentName(Ref);    outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; @@ -5966,7 +6072,12 @@ static void print_image_info(SectionRef S, struct DisassembleInfo *info) {    const char *r;    StringRef SectName; -  S.getName(SectName); +  Expected<StringRef> SecNameOrErr = S.getName(); +  if (SecNameOrErr) +    SectName = *SecNameOrErr; +  else +    consumeError(SecNameOrErr.takeError()); +    DataRefImpl Ref = S.getRawDataRefImpl();    StringRef SegName = info->O->getSectionFinalSegmentName(Ref);    outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; @@ -6001,11 +6112,8 @@ static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {      CreateSymbolAddressMap(O, &AddrMap);    std::vector<SectionRef> Sections; -  for (const SectionRef &Section : O->sections()) { -    StringRef SectName; -    Section.getName(SectName); +  for (const SectionRef &Section : O->sections())      Sections.push_back(Section); -  }    struct DisassembleInfo info(O, &AddrMap, &Sections, verbose); @@ -6086,11 +6194,8 @@ static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {      CreateSymbolAddressMap(O, &AddrMap);    std::vector<SectionRef> Sections; -  for (const SectionRef &Section : O->sections()) { -    StringRef SectName; -    Section.getName(SectName); +  for (const SectionRef &Section : O->sections())      Sections.push_back(Section); -  }    struct DisassembleInfo info(O, &AddrMap, &Sections, verbose); @@ -6184,11 +6289,8 @@ static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {      CreateSymbolAddressMap(O, &AddrMap);    std::vector<SectionRef> Sections; -  for (const SectionRef &Section : O->sections()) { -    StringRef SectName; -    Section.getName(SectName); +  for (const SectionRef &Section : O->sections())      Sections.push_back(Section); -  }    struct DisassembleInfo info(O, &AddrMap, &Sections, verbose); @@ -6345,11 +6447,8 @@ static void DumpProtocolSection(MachOObjectFile *O, const char *sect,    CreateSymbolAddressMap(O, &AddrMap);    std::vector<SectionRef> Sections; -  for (const SectionRef &Section : O->sections()) { -    StringRef SectName; -    Section.getName(SectName); +  for (const SectionRef &Section : O->sections())      Sections.push_back(Section); -  }    struct DisassembleInfo info(O, &AddrMap, &Sections, true); @@ -7110,11 +7209,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,      FeaturesStr = Features.getString();    } +  MCTargetOptions MCOptions;    // Set up disassembler.    std::unique_ptr<const MCRegisterInfo> MRI(        TheTarget->createMCRegInfo(TripleName));    std::unique_ptr<const MCAsmInfo> AsmInfo( -      TheTarget->createMCAsmInfo(*MRI, TripleName)); +      TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));    std::unique_ptr<const MCSubtargetInfo> STI(        TheTarget->createMCSubtargetInfo(TripleName, MachOMCPU, FeaturesStr));    MCContext Ctx(AsmInfo.get(), MRI.get(), nullptr); @@ -7164,7 +7264,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,    if (ThumbTarget) {      ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName));      ThumbAsmInfo.reset( -        ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName)); +        ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName, MCOptions));      ThumbSTI.reset(          ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MachOMCPU,                                             FeaturesStr)); @@ -7203,7 +7303,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,    std::vector<SectionRef> Sections;    std::vector<SymbolRef> Symbols;    SmallVector<uint64_t, 8> FoundFns; -  uint64_t BaseSegmentAddress; +  uint64_t BaseSegmentAddress = 0;    getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns,                          BaseSegmentAddress); @@ -7226,12 +7326,6 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,    }    array_pod_sort(Dices.begin(), Dices.end()); -#ifndef NDEBUG -  raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); -#else -  raw_ostream &DebugOut = nulls(); -#endif -    // Try to find debug info and set up the DIContext for it.    std::unique_ptr<DIContext> diContext;    std::unique_ptr<Binary> DSYMBinary; @@ -7242,10 +7336,24 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,      // A separate DSym file path was specified, parse it as a macho file,      // get the sections and supply it to the section name parsing machinery.      if (!DSYMFile.empty()) { +      std::string DSYMPath(DSYMFile); + +      // If DSYMPath is a .dSYM directory, append the Mach-O file. +      if (llvm::sys::fs::is_directory(DSYMPath) && +          llvm::sys::path::extension(DSYMPath) == ".dSYM") { +        SmallString<128> ShortName(llvm::sys::path::filename(DSYMPath)); +        llvm::sys::path::replace_extension(ShortName, ""); +        SmallString<1024> FullPath(DSYMPath); +        llvm::sys::path::append(FullPath, "Contents", "Resources", "DWARF", +                                ShortName); +        DSYMPath = FullPath.str(); +      } + +      // Load the file.        ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = -          MemoryBuffer::getFileOrSTDIN(DSYMFile); +          MemoryBuffer::getFileOrSTDIN(DSYMPath);        if (std::error_code EC = BufOrErr.getError()) { -        report_error(errorCodeToError(EC), DSYMFile); +        reportError(errorCodeToError(EC), DSYMPath);          return;        } @@ -7255,13 +7363,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,        Expected<std::unique_ptr<Binary>> BinaryOrErr =        createBinary(DSYMBuf.get()->getMemBufferRef());        if (!BinaryOrErr) { -        report_error(BinaryOrErr.takeError(), DSYMFile); +        reportError(BinaryOrErr.takeError(), DSYMPath);          return;        } -      // We need to keep the Binary elive with the buffer +      // We need to keep the Binary alive with the buffer        DSYMBinary = std::move(BinaryOrErr.get()); -            if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {          // this is a Mach-O object file, use it          if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) { @@ -7269,7 +7376,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,          }          else {            WithColor::error(errs(), "llvm-objdump") -            << DSYMFile << " is not a Mach-O file type.\n"; +            << DSYMPath << " is not a Mach-O file type.\n";            return;          }        } @@ -7289,19 +7396,19 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,          Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,                                                    &ArchFlag);          Expected<std::unique_ptr<MachOObjectFile>> MachDSYM = -            UB->getObjectForArch(ArchFlag); +            UB->getMachOObjectForArch(ArchFlag);          if (!MachDSYM) { -          report_error(MachDSYM.takeError(), DSYMFile); +          reportError(MachDSYM.takeError(), DSYMPath);            return;          } -     -        // We need to keep the Binary elive with the buffer + +        // We need to keep the Binary alive with the buffer          DbgObj = &*MachDSYM.get();          DSYMBinary = std::move(*MachDSYM);        }        else {          WithColor::error(errs(), "llvm-objdump") -          << DSYMFile << " is not a Mach-O or Universal file type.\n"; +          << DSYMPath << " is not a Mach-O or Universal file type.\n";          return;        }      } @@ -7314,8 +7421,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,      outs() << "(" << DisSegName << "," << DisSectName << ") section\n";    for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { -    StringRef SectName; -    if (Sections[SectIdx].getName(SectName) || SectName != DisSectName) +    Expected<StringRef> SecNameOrErr = Sections[SectIdx].getName(); +    if (!SecNameOrErr) { +      consumeError(SecNameOrErr.takeError()); +      continue; +    } +    if (*SecNameOrErr != DisSectName)        continue;      DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl(); @@ -7496,24 +7607,8 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,          if (!NoShowRawInsn || Arch == Triple::arm)            outs() << "\t"; -        // Check the data in code table here to see if this is data not an -        // instruction to be disassembled. -        DiceTable Dice; -        Dice.push_back(std::make_pair(PC, DiceRef())); -        dice_table_iterator DTI = -            std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(), -                        compareDiceTableEntries); -        if (DTI != Dices.end()) { -          uint16_t Length; -          DTI->second.getLength(Length); -          uint16_t Kind; -          DTI->second.getKind(Kind); -          Size = DumpDataInCode(Bytes.data() + Index, Length, Kind); -          if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) && -              (PC == (DTI->first + Length - 1)) && (Length & 1)) -            Size++; +        if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, Size))            continue; -        }          SmallVector<char, 64> AnnotationsBytes;          raw_svector_ostream Annotations(AnnotationsBytes); @@ -7521,10 +7616,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,          bool gotInst;          if (UseThumbTarget)            gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index), -                                                PC, DebugOut, Annotations); +                                                PC, Annotations);          else            gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC, -                                           DebugOut, Annotations); +                                           Annotations);          if (gotInst) {            if (!NoShowRawInsn || Arch == Triple::arm) {              dumpBytes(makeArrayRef(Bytes.data() + Index, Size), outs()); @@ -7532,9 +7627,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,            formatted_raw_ostream FormattedOS(outs());            StringRef AnnotationsStr = Annotations.str();            if (UseThumbTarget) -            ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr, *ThumbSTI); +            ThumbIP->printInst(&Inst, PC, AnnotationsStr, *ThumbSTI, +                               FormattedOS);            else -            IP->printInst(&Inst, FormattedOS, AnnotationsStr, *STI); +            IP->printInst(&Inst, PC, AnnotationsStr, *STI, FormattedOS);            emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);            // Print debug info. @@ -7548,8 +7644,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,            }            outs() << "\n";          } else { -          unsigned int Arch = MachOOF->getArch(); -          if (Arch == Triple::x86_64 || Arch == Triple::x86) { +          if (MachOOF->getArchTriple().isX86()) {              outs() << format("\t.byte 0x%02x #bad opcode\n",                               *(Bytes.data() + Index) & 0xff);              Size = 1; // skip exactly one illegible byte and move on. @@ -7588,10 +7683,14 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,          MCInst Inst;          uint64_t PC = SectAddress + Index; + +        if (DumpAndSkipDataInCode(PC, Bytes.data() + Index, Dices, InstSize)) +          continue; +          SmallVector<char, 64> AnnotationsBytes;          raw_svector_ostream Annotations(AnnotationsBytes);          if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC, -                                   DebugOut, Annotations)) { +                                   Annotations)) {            if (!NoLeadingAddr) {              if (FullLeadingAddr) {                if (MachOOF->is64Bit()) @@ -7607,11 +7706,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,              dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs());            }            StringRef AnnotationsStr = Annotations.str(); -          IP->printInst(&Inst, outs(), AnnotationsStr, *STI); +          IP->printInst(&Inst, PC, AnnotationsStr, *STI, outs());            outs() << "\n";          } else { -          unsigned int Arch = MachOOF->getArch(); -          if (Arch == Triple::x86_64 || Arch == Triple::x86) { +          if (MachOOF->getArchTriple().isX86()) {              outs() << format("\t.byte 0x%02x #bad opcode\n",                               *(Bytes.data() + Index) & 0xff);              InstSize = 1; // skip exactly one illegible byte and move on. @@ -7625,7 +7723,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,        }      }      // The TripleName's need to be reset if we are called again for a different -    // archtecture. +    // architecture.      TripleName = "";      ThumbTripleName = ""; @@ -7725,7 +7823,11 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,    if (Sym == Symbols.begin()) {      // The first symbol in the object is after this reference, the best we can      // do is section-relative notation. -    RelocSection.getName(Name); +    if (Expected<StringRef> NameOrErr = RelocSection.getName()) +      Name = *NameOrErr; +    else +      consumeError(NameOrErr.takeError()); +      Addend = Addr - SectionAddr;      return;    } @@ -7744,7 +7846,11 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,    // There is a symbol before this reference, but it's in a different    // section. Probably not helpful to mention it, so use the section name. -  RelocSection.getName(Name); +  if (Expected<StringRef> NameOrErr = RelocSection.getName()) +    Name = *NameOrErr; +  else +    consumeError(NameOrErr.takeError()); +    Addend = Addr - SectionAddr;  } @@ -8109,7 +8215,11 @@ void printMachOUnwindInfo(const MachOObjectFile *Obj) {    for (const SectionRef &Section : Obj->sections()) {      StringRef SectName; -    Section.getName(SectName); +    if (Expected<StringRef> NameOrErr = Section.getName()) +      SectName = *NameOrErr; +    else +      consumeError(NameOrErr.takeError()); +      if (SectName == "__compact_unwind")        printMachOCompactUnwindSection(Obj, Symbols, Section);      else if (SectName == "__unwind_info") @@ -10191,7 +10301,7 @@ void printMachOExportsTrie(const object::MachOObjectFile *Obj) {      outs() << "\n";    }    if (Err) -    report_error(std::move(Err), Obj->getFileName()); +    reportError(std::move(Err), Obj->getFileName());  }  //===----------------------------------------------------------------------===// @@ -10212,7 +10322,7 @@ void printMachORebaseTable(object::MachOObjectFile *Obj) {                       Address, Entry.typeName().str().c_str());    }    if (Err) -    report_error(std::move(Err), Obj->getFileName()); +    reportError(std::move(Err), Obj->getFileName());  }  static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) { @@ -10264,7 +10374,7 @@ void printMachOBindTable(object::MachOObjectFile *Obj) {             << Entry.symbolName() << Attr << "\n";    }    if (Err) -    report_error(std::move(Err), Obj->getFileName()); +    reportError(std::move(Err), Obj->getFileName());  }  //===----------------------------------------------------------------------===// @@ -10289,7 +10399,7 @@ void printMachOLazyBindTable(object::MachOObjectFile *Obj) {             << Entry.symbolName() << "\n";    }    if (Err) -    report_error(std::move(Err), Obj->getFileName()); +    reportError(std::move(Err), Obj->getFileName());  }  //===----------------------------------------------------------------------===// @@ -10321,7 +10431,7 @@ void printMachOWeakBindTable(object::MachOObjectFile *Obj) {             << "\n";    }    if (Err) -    report_error(std::move(Err), Obj->getFileName()); +    reportError(std::move(Err), Obj->getFileName());  }  // get_dyld_bind_info_symbolname() is used for disassembly and passed an @@ -10331,7 +10441,7 @@ void printMachOWeakBindTable(object::MachOObjectFile *Obj) {  static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,                                                   struct DisassembleInfo *info) {    if (info->bindtable == nullptr) { -    info->bindtable = llvm::make_unique<SymbolAddressMap>(); +    info->bindtable = std::make_unique<SymbolAddressMap>();      Error Err = Error::success();      for (const object::MachOBindEntry &Entry : info->O->bindTable(Err)) {        uint64_t Address = Entry.address(); @@ -10340,7 +10450,7 @@ static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,          (*info->bindtable)[Address] = name;      }      if (Err) -      report_error(std::move(Err), info->O->getFileName()); +      reportError(std::move(Err), info->O->getFileName());    }    auto name = info->bindtable->lookup(ReferenceValue);    return !name.empty() ? name.data() : nullptr; 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 58981203c59e..6bd37a1fb86c 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -37,6 +37,7 @@  #include "llvm/MC/MCObjectFileInfo.h"  #include "llvm/MC/MCRegisterInfo.h"  #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h"  #include "llvm/Object/Archive.h"  #include "llvm/Object/COFF.h"  #include "llvm/Object/COFFImportFile.h" @@ -51,6 +52,7 @@  #include "llvm/Support/Errc.h"  #include "llvm/Support/FileSystem.h"  #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" @@ -341,78 +343,84 @@ static StringRef ToolName;  typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy; -static bool shouldKeep(object::SectionRef S) { +namespace { +struct FilterResult { +  // True if the section should not be skipped. +  bool Keep; + +  // True if the index counter should be incremented, even if the section should +  // be skipped. For example, sections may be skipped if they are not included +  // in the --section flag, but we still want those to count toward the section +  // count. +  bool IncrementIndex; +}; +} // namespace + +static FilterResult checkSectionFilter(object::SectionRef S) {    if (FilterSections.empty()) -    return true; -  StringRef SecName; -  std::error_code error = S.getName(SecName); -  if (error) -    return false; +    return {/*Keep=*/true, /*IncrementIndex=*/true}; + +  Expected<StringRef> SecNameOrErr = S.getName(); +  if (!SecNameOrErr) { +    consumeError(SecNameOrErr.takeError()); +    return {/*Keep=*/false, /*IncrementIndex=*/false}; +  } +  StringRef SecName = *SecNameOrErr; +    // StringSet does not allow empty key so avoid adding sections with    // no name (such as the section with index 0) here.    if (!SecName.empty())      FoundSectionSet.insert(SecName); -  return is_contained(FilterSections, SecName); -} -SectionFilter ToolSectionFilter(object::ObjectFile const &O) { -  return SectionFilter([](object::SectionRef S) { return shouldKeep(S); }, O); -} - -void error(std::error_code EC) { -  if (!EC) -    return; -  WithColor::error(errs(), ToolName) -      << "reading file: " << EC.message() << ".\n"; -  errs().flush(); -  exit(1); -} - -void error(Error E) { -  if (!E) -    return; -  WithColor::error(errs(), ToolName) << toString(std::move(E)); -  exit(1); +  // Only show the section if it's in the FilterSections list, but always +  // increment so the indexing is stable. +  return {/*Keep=*/is_contained(FilterSections, SecName), +          /*IncrementIndex=*/true};  } -LLVM_ATTRIBUTE_NORETURN void error(Twine Message) { -  WithColor::error(errs(), ToolName) << Message << ".\n"; -  errs().flush(); -  exit(1); +SectionFilter ToolSectionFilter(object::ObjectFile const &O, uint64_t *Idx) { +  // Start at UINT64_MAX so that the first index returned after an increment is +  // zero (after the unsigned wrap). +  if (Idx) +    *Idx = UINT64_MAX; +  return SectionFilter( +      [Idx](object::SectionRef S) { +        FilterResult Result = checkSectionFilter(S); +        if (Idx != nullptr && Result.IncrementIndex) +          *Idx += 1; +        return Result.Keep; +      }, +      O);  } -void warn(StringRef Message) { -  WithColor::warning(errs(), ToolName) << Message << ".\n"; -  errs().flush(); +std::string getFileNameForError(const object::Archive::Child &C, +                                unsigned Index) { +  Expected<StringRef> NameOrErr = C.getName(); +  if (NameOrErr) +    return NameOrErr.get(); +  // If we have an error getting the name then we print the index of the archive +  // member. Since we are already in an error state, we just ignore this error. +  consumeError(NameOrErr.takeError()); +  return "<file index: " + std::to_string(Index) + ">";  } -static void warn(Twine Message) { +void reportWarning(Twine Message, StringRef File) {    // Output order between errs() and outs() matters especially for archive    // files where the output is per member object.    outs().flush(); -  WithColor::warning(errs(), ToolName) << Message << "\n"; +  WithColor::warning(errs(), ToolName) +      << "'" << File << "': " << Message << "\n";    errs().flush();  } -LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, Twine Message) { -  WithColor::error(errs(), ToolName) -      << "'" << File << "': " << Message << ".\n"; +LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Twine Message) { +  WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n";    exit(1);  } -LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef File) { -  assert(E); -  std::string Buf; -  raw_string_ostream OS(Buf); -  logAllUnhandledErrors(std::move(E), OS); -  OS.flush(); -  WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf; -  exit(1); -} - -LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef ArchiveName, -                                          StringRef FileName, -                                          StringRef ArchitectureName) { +LLVM_ATTRIBUTE_NORETURN void reportError(Error E, StringRef FileName, +                                         StringRef ArchiveName, +                                         StringRef ArchitectureName) {    assert(E);    WithColor::error(errs(), ToolName);    if (ArchiveName != "") @@ -429,18 +437,13 @@ LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef ArchiveName,    exit(1);  } -LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef ArchiveName, -                                          const object::Archive::Child &C, -                                          StringRef ArchitectureName) { -  Expected<StringRef> NameOrErr = C.getName(); -  // TODO: if we have a error getting the name then it would be nice to print -  // the index of which archive member this is and or its offset in the -  // archive instead of "???" as the name. -  if (!NameOrErr) { -    consumeError(NameOrErr.takeError()); -    report_error(std::move(E), ArchiveName, "???", ArchitectureName); -  } else -    report_error(std::move(E), ArchiveName, NameOrErr.get(), ArchitectureName); +static void reportCmdLineWarning(Twine Message) { +  WithColor::warning(errs(), ToolName) << Message << "\n"; +} + +LLVM_ATTRIBUTE_NORETURN static void reportCmdLineError(Twine Message) { +  WithColor::error(errs(), ToolName) << Message << "\n"; +  exit(1);  }  static void warnOnNoMatchForSections() { @@ -455,37 +458,29 @@ static void warnOnNoMatchForSections() {    // Warn only if no section in FilterSections is matched.    for (StringRef S : MissingSections) -    warn("section '" + S + "' mentioned in a -j/--section option, but not " -         "found in any input file"); +    reportCmdLineWarning("section '" + S + +                         "' mentioned in a -j/--section option, but not " +                         "found in any input file");  } -static const Target *getTarget(const ObjectFile *Obj = nullptr) { +static const Target *getTarget(const ObjectFile *Obj) {    // Figure out the target triple.    Triple TheTriple("unknown-unknown-unknown");    if (TripleName.empty()) { -    if (Obj) -      TheTriple = Obj->makeTriple(); +    TheTriple = Obj->makeTriple();    } else {      TheTriple.setTriple(Triple::normalize(TripleName)); - -    // Use the triple, but also try to combine with ARM build attributes. -    if (Obj) { -      auto Arch = Obj->getArch(); -      if (Arch == Triple::arm || Arch == Triple::armeb) -        Obj->setARMSubArch(TheTriple); -    } +    auto Arch = Obj->getArch(); +    if (Arch == Triple::arm || Arch == Triple::armeb) +      Obj->setARMSubArch(TheTriple);    }    // Get the target specific parser.    std::string Error;    const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,                                                           Error); -  if (!TheTarget) { -    if (Obj) -      report_error(Obj->getFileName(), "can't find target: " + Error); -    else -      error("can't find target: " + Error); -  } +  if (!TheTarget) +    reportError(Obj->getFileName(), "can't find target: " + Error);    // Update the triple name and return the found target.    TripleName = TheTriple.getTriple(); @@ -548,17 +543,22 @@ protected:    DILineInfo OldLineInfo;    const ObjectFile *Obj = nullptr;    std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer; -  // File name to file contents of source +  // File name to file contents of source.    std::unordered_map<std::string, std::unique_ptr<MemoryBuffer>> SourceCache; -  // Mark the line endings of the cached source +  // Mark the line endings of the cached source.    std::unordered_map<std::string, std::vector<StringRef>> LineCache; +  // Keep track of missing sources. +  StringSet<> MissingSources; +  // Only emit 'no debug info' warning once. +  bool WarnedNoDebugInfo;  private:    bool cacheSource(const DILineInfo& LineInfoFile);  public:    SourcePrinter() = default; -  SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch) : Obj(Obj) { +  SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch) +      : Obj(Obj), WarnedNoDebugInfo(false) {      symbolize::LLVMSymbolizer::Options SymbolizerOpts;      SymbolizerOpts.PrintFunctions = DILineInfoSpecifier::FunctionNameKind::None;      SymbolizerOpts.Demangle = false; @@ -568,6 +568,7 @@ public:    virtual ~SourcePrinter() = default;    virtual void printSourceLine(raw_ostream &OS,                                 object::SectionedAddress Address, +                               StringRef ObjectFilename,                                 StringRef Delimiter = "; ");  }; @@ -577,8 +578,12 @@ bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {      Buffer = MemoryBuffer::getMemBuffer(*LineInfo.Source);    } else {      auto BufferOrError = MemoryBuffer::getFile(LineInfo.FileName); -    if (!BufferOrError) +    if (!BufferOrError) { +      if (MissingSources.insert(LineInfo.FileName).second) +        reportWarning("failed to find source " + LineInfo.FileName, +                      Obj->getFileName());        return false; +    }      Buffer = std::move(*BufferOrError);    }    // Chomp the file to get lines @@ -599,20 +604,33 @@ bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {  void SourcePrinter::printSourceLine(raw_ostream &OS,                                      object::SectionedAddress Address, +                                    StringRef ObjectFilename,                                      StringRef Delimiter) {    if (!Symbolizer)      return;    DILineInfo LineInfo = DILineInfo();    auto ExpectedLineInfo = Symbolizer->symbolizeCode(*Obj, Address); +  std::string ErrorMessage;    if (!ExpectedLineInfo) -    consumeError(ExpectedLineInfo.takeError()); +    ErrorMessage = toString(ExpectedLineInfo.takeError());    else      LineInfo = *ExpectedLineInfo; -  if ((LineInfo.FileName == "<invalid>") || LineInfo.Line == 0 || -      ((OldLineInfo.Line == LineInfo.Line) && -       (OldLineInfo.FileName == LineInfo.FileName))) +  if (LineInfo.FileName == DILineInfo::BadString) { +    if (!WarnedNoDebugInfo) { +      std::string Warning = +          "failed to parse debug information for " + ObjectFilename.str(); +      if (!ErrorMessage.empty()) +        Warning += ": " + ErrorMessage; +      reportWarning(Warning, ObjectFilename); +      WarnedNoDebugInfo = true; +    } +    return; +  } + +  if (LineInfo.Line == 0 || ((OldLineInfo.Line == LineInfo.Line) && +                             (OldLineInfo.FileName == LineInfo.FileName)))      return;    if (PrintLines) @@ -623,8 +641,14 @@ void SourcePrinter::printSourceLine(raw_ostream &OS,          return;      auto LineBuffer = LineCache.find(LineInfo.FileName);      if (LineBuffer != LineCache.end()) { -      if (LineInfo.Line > LineBuffer->second.size()) +      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] << '\n';      } @@ -646,13 +670,14 @@ static bool hasMappingSymbols(const ObjectFile *Obj) {    return isArmElf(Obj) || isAArch64Elf(Obj);  } -static void printRelocation(const RelocationRef &Rel, uint64_t Address, -                            bool Is64Bits) { +static void printRelocation(StringRef FileName, const RelocationRef &Rel, +                            uint64_t Address, bool Is64Bits) {    StringRef Fmt = Is64Bits ? "\t\t%016" PRIx64 ":  " : "\t\t\t%08" PRIx64 ":  ";    SmallString<16> Name;    SmallString<32> Val;    Rel.getTypeName(Name); -  error(getRelocationValueString(Rel, Val)); +  if (Error E = getRelocationValueString(Rel, Val)) +    reportError(std::move(E), FileName);    outs() << format(Fmt.data(), Address) << Name << "\t" << Val << "\n";  } @@ -663,31 +688,27 @@ public:                           ArrayRef<uint8_t> Bytes,                           object::SectionedAddress Address, raw_ostream &OS,                           StringRef Annot, MCSubtargetInfo const &STI, -                         SourcePrinter *SP, +                         SourcePrinter *SP, StringRef ObjectFilename,                           std::vector<RelocationRef> *Rels = nullptr) {      if (SP && (PrintSource || PrintLines)) -      SP->printSourceLine(OS, Address); +      SP->printSourceLine(OS, Address, ObjectFilename); -    { -      formatted_raw_ostream FOS(OS); -      if (!NoLeadingAddr) -        FOS << format("%8" PRIx64 ":", Address.Address); -      if (!NoShowRawInsn) { -        FOS << ' '; -        dumpBytes(Bytes, FOS); -      } -      FOS.flush(); -      // 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 = NoShowRawInsn ? 16 : 40; -      unsigned Column = FOS.getColumn(); -      FOS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); - -      // The dtor calls flush() to ensure the indent comes before printInst(). +    size_t Start = OS.tell(); +    if (!NoLeadingAddr) +      OS << format("%8" PRIx64 ":", Address.Address); +    if (!NoShowRawInsn) { +      OS << ' '; +      dumpBytes(Bytes, 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 = NoShowRawInsn ? 16 : 40; +    unsigned Column = OS.tell() - Start; +    OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); +      if (MI) -      IP.printInst(MI, OS, "", STI); +      IP.printInst(MI, Address.Address, "", STI, OS);      else        OS << "\t<unknown>";    } @@ -711,9 +732,10 @@ public:    void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,                   object::SectionedAddress Address, raw_ostream &OS,                   StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, +                 StringRef ObjectFilename,                   std::vector<RelocationRef> *Rels) override {      if (SP && (PrintSource || PrintLines)) -      SP->printSourceLine(OS, Address, ""); +      SP->printSourceLine(OS, Address, ObjectFilename, "");      if (!MI) {        printLead(Bytes, Address.Address, OS);        OS << " <unknown>"; @@ -722,7 +744,7 @@ public:      std::string Buffer;      {        raw_string_ostream TempStream(Buffer); -      IP.printInst(MI, TempStream, "", STI); +      IP.printInst(MI, Address.Address, "", STI, TempStream);      }      StringRef Contents(Buffer);      // Split off bundle attributes @@ -739,7 +761,7 @@ public:      auto PrintReloc = [&]() -> void {        while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) {          if (RelCur->getOffset() == Address.Address) { -          printRelocation(*RelCur, Address.Address, false); +          printRelocation(ObjectFilename, *RelCur, Address.Address, false);            return;          }          ++RelCur; @@ -750,7 +772,7 @@ public:        OS << Separator;        Separator = "\n";        if (SP && (PrintSource || PrintLines)) -        SP->printSourceLine(OS, Address, ""); +        SP->printSourceLine(OS, Address, ObjectFilename, "");        printLead(Bytes, Address.Address, OS);        OS << Preamble;        Preamble = "   "; @@ -780,15 +802,16 @@ public:    void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,                   object::SectionedAddress Address, raw_ostream &OS,                   StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, +                 StringRef ObjectFilename,                   std::vector<RelocationRef> *Rels) override {      if (SP && (PrintSource || PrintLines)) -      SP->printSourceLine(OS, Address); +      SP->printSourceLine(OS, Address, ObjectFilename);      if (MI) {        SmallString<40> InstStr;        raw_svector_ostream IS(InstStr); -      IP.printInst(MI, IS, "", STI); +      IP.printInst(MI, Address.Address, "", STI, IS);        OS << left_justify(IS.str(), 60);      } else { @@ -831,9 +854,10 @@ public:    void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,                   object::SectionedAddress Address, raw_ostream &OS,                   StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, +                 StringRef ObjectFilename,                   std::vector<RelocationRef> *Rels) override {      if (SP && (PrintSource || PrintLines)) -      SP->printSourceLine(OS, Address); +      SP->printSourceLine(OS, Address, ObjectFilename);      if (!NoLeadingAddr)        OS << format("%8" PRId64 ":", Address.Address / 8);      if (!NoShowRawInsn) { @@ -841,7 +865,7 @@ public:        dumpBytes(Bytes, OS);      }      if (MI) -      IP.printInst(MI, OS, "", STI); +      IP.printInst(MI, Address.Address, "", STI, OS);      else        OS << "\t<unknown>";    } @@ -924,10 +948,12 @@ static void addPltEntries(const ObjectFile *Obj,                            StringSaver &Saver) {    Optional<SectionRef> Plt = None;    for (const SectionRef &Section : Obj->sections()) { -    StringRef Name; -    if (Section.getName(Name)) +    Expected<StringRef> SecNameOrErr = Section.getName(); +    if (!SecNameOrErr) { +      consumeError(SecNameOrErr.takeError());        continue; -    if (Name == ".plt") +    } +    if (*SecNameOrErr == ".plt")        Plt = Section;    }    if (!Plt) @@ -968,9 +994,18 @@ static size_t countSkippableZeroBytes(ArrayRef<uint8_t> Buf) {  static std::map<SectionRef, std::vector<RelocationRef>>  getRelocsMap(object::ObjectFile const &Obj) {    std::map<SectionRef, std::vector<RelocationRef>> Ret; +  uint64_t I = (uint64_t)-1;    for (SectionRef Sec : Obj.sections()) { -    section_iterator Relocated = Sec.getRelocatedSection(); -    if (Relocated == Obj.section_end() || !shouldKeep(*Relocated)) +    ++I; +    Expected<section_iterator> RelocatedOrErr = Sec.getRelocatedSection(); +    if (!RelocatedOrErr) +      reportError(Obj.getFileName(), +                  "section (" + Twine(I) + +                      "): failed to get a relocated section: " + +                      toString(RelocatedOrErr.takeError())); + +    section_iterator Relocated = *RelocatedOrErr; +    if (Relocated == Obj.section_end() || !checkSectionFilter(*Relocated).Keep)        continue;      std::vector<RelocationRef> &V = Ret[*Relocated];      for (const RelocationRef &R : Sec.relocations()) @@ -1099,6 +1134,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,    std::map<SectionRef, SectionSymbolsTy> AllSymbols;    SectionSymbolsTy AbsoluteSymbols;    const StringRef FileName = Obj->getFileName(); +  const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj);    for (const SymbolRef &Symbol : Obj->symbols()) {      uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName); @@ -1113,6 +1149,18 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,          continue;      } +    // Don't ask a Mach-O STAB symbol for its section unless you know that  +    // STAB symbol's section field refers to a valid section index. Otherwise +    // the symbol may error trying to load a section that does not exist. +    if (MachO) { +      DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); +      uint8_t NType = (MachO->is64Bit() ? +                       MachO->getSymbol64TableEntry(SymDRI).n_type: +                       MachO->getSymbolTableEntry(SymDRI).n_type); +      if (NType & MachO::N_STAB) +        continue; +    } +      section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);      if (SecI != Obj->section_end())        AllSymbols[*SecI].emplace_back(Address, Name, SymbolType); @@ -1137,11 +1185,14 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,    if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) {      for (const auto &ExportEntry : COFFObj->export_directories()) {        StringRef Name; -      error(ExportEntry.getSymbolName(Name)); +      if (std::error_code EC = ExportEntry.getSymbolName(Name)) +        reportError(errorCodeToError(EC), Obj->getFileName());        if (Name.empty())          continue; +        uint32_t RVA; -      error(ExportEntry.getExportRVA(RVA)); +      if (std::error_code EC = ExportEntry.getExportRVA(RVA)) +        reportError(errorCodeToError(EC), Obj->getFileName());        uint64_t VA = COFFObj->getImageBase() + RVA;        auto Sec = partition_point( @@ -1206,13 +1257,12 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,      }      StringRef SegmentName = ""; -    if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj)) { +    if (MachO) {        DataRefImpl DR = Section.getRawDataRefImpl();        SegmentName = MachO->getSectionFinalSegmentName(DR);      } -    StringRef SectionName; -    error(Section.getName(SectionName)); +    StringRef SectionName = unwrapOrError(Section.getName(), Obj->getFileName());      // If the section has no symbol at the start, just insert a dummy one.      if (Symbols.empty() || std::get<0>(Symbols[0]) != 0) {        Symbols.insert( @@ -1303,16 +1353,10 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,          continue;        } -#ifndef NDEBUG -      raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); -#else -      raw_ostream &DebugOut = nulls(); -#endif -        // Some targets (like WebAssembly) have a special prelude at the start        // of each symbol.        DisAsm->onSymbolStart(SymbolName, Size, Bytes.slice(Start, End - Start), -                            SectionAddr + Start, DebugOut, CommentStream); +                            SectionAddr + Start, CommentStream);        Start += Size;        Index = Start; @@ -1376,15 +1420,14 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,          // provided          MCInst Inst;          bool Disassembled = DisAsm->getInstruction( -            Inst, Size, Bytes.slice(Index), SectionAddr + Index, DebugOut, -            CommentStream); +            Inst, Size, Bytes.slice(Index), SectionAddr + Index, CommentStream);          if (Size == 0)            Size = 1; -        PIP.printInst( -            *IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size), -            {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, outs(), -            "", *STI, &SP, &Rels); +        PIP.printInst(*IP, Disassembled ? &Inst : nullptr, +                      Bytes.slice(Index, Size), +                      {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, +                      outs(), "", *STI, &SP, Obj->getFileName(), &Rels);          outs() << CommentStream.str();          Comments.clear(); @@ -1470,7 +1513,8 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,                  Offset += AdjustVMA;              } -            printRelocation(*RelCur, SectionAddr + Offset, Is64Bits); +            printRelocation(Obj->getFileName(), *RelCur, SectionAddr + Offset, +                            Is64Bits);              ++RelCur;            }          } @@ -1482,7 +1526,8 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,    StringSet<> MissingDisasmFuncsSet =        set_difference(DisasmFuncsSet, FoundDisasmFuncsSet);    for (StringRef MissingDisasmFunc : MissingDisasmFuncsSet.keys()) -    warn("failed to disassemble missing function " + MissingDisasmFunc); +    reportWarning("failed to disassemble missing function " + MissingDisasmFunc, +                  FileName);  }  static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) { @@ -1497,24 +1542,25 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {    std::unique_ptr<const MCRegisterInfo> MRI(        TheTarget->createMCRegInfo(TripleName));    if (!MRI) -    report_error(Obj->getFileName(), -                 "no register info for target " + TripleName); +    reportError(Obj->getFileName(), +                "no register info for target " + TripleName);    // Set up disassembler. +  MCTargetOptions MCOptions;    std::unique_ptr<const MCAsmInfo> AsmInfo( -      TheTarget->createMCAsmInfo(*MRI, TripleName)); +      TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));    if (!AsmInfo) -    report_error(Obj->getFileName(), -                 "no assembly info for target " + TripleName); +    reportError(Obj->getFileName(), +                "no assembly info for target " + TripleName);    std::unique_ptr<const MCSubtargetInfo> STI(        TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));    if (!STI) -    report_error(Obj->getFileName(), -                 "no subtarget info for target " + TripleName); +    reportError(Obj->getFileName(), +                "no subtarget info for target " + TripleName);    std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());    if (!MII) -    report_error(Obj->getFileName(), -                 "no instruction info for target " + TripleName); +    reportError(Obj->getFileName(), +                "no instruction info for target " + TripleName);    MCObjectFileInfo MOFI;    MCContext Ctx(AsmInfo.get(), MRI.get(), &MOFI);    // FIXME: for now initialize MCObjectFileInfo with default values @@ -1523,8 +1569,7 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {    std::unique_ptr<MCDisassembler> DisAsm(        TheTarget->createMCDisassembler(*STI, Ctx));    if (!DisAsm) -    report_error(Obj->getFileName(), -                 "no disassembler for target " + TripleName); +    reportError(Obj->getFileName(), "no disassembler for target " + TripleName);    // If we have an ARM object file, we need a second disassembler, because    // ARM CPUs have two different instruction sets: ARM mode, and Thumb mode. @@ -1549,8 +1594,8 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {    std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(        Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));    if (!IP) -    report_error(Obj->getFileName(), -                 "no instruction printer for target " + TripleName); +    reportError(Obj->getFileName(), +                "no instruction printer for target " + TripleName);    IP->setPrintImmHex(PrintImmHex);    PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName)); @@ -1558,7 +1603,8 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {    for (StringRef Opt : DisassemblerOptions)      if (!IP->applyTargetSpecificCLOption(Opt)) -      error("Unrecognized disassembler option: " + Opt); +      reportError(Obj->getFileName(), +                  "Unrecognized disassembler option: " + Opt);    disassembleObject(TheTarget, Obj, Ctx, DisAsm.get(), SecondaryDisAsm.get(),                      MIA.get(), IP.get(), STI.get(), SecondarySTI.get(), PIP, @@ -1577,16 +1623,21 @@ void printRelocations(const ObjectFile *Obj) {    // sections. Usually, there is an only one relocation section for    // each relocated section.    MapVector<SectionRef, std::vector<SectionRef>> SecToRelSec; -  for (const SectionRef &Section : ToolSectionFilter(*Obj)) { +  uint64_t Ndx; +  for (const SectionRef &Section : ToolSectionFilter(*Obj, &Ndx)) {      if (Section.relocation_begin() == Section.relocation_end())        continue; -    const SectionRef TargetSec = *Section.getRelocatedSection(); -    SecToRelSec[TargetSec].push_back(Section); +    Expected<section_iterator> SecOrErr = Section.getRelocatedSection(); +    if (!SecOrErr) +      reportError(Obj->getFileName(), +                  "section (" + Twine(Ndx) + +                      "): unable to get a relocation target: " + +                      toString(SecOrErr.takeError())); +    SecToRelSec[**SecOrErr].push_back(Section);    }    for (std::pair<SectionRef, std::vector<SectionRef>> &P : SecToRelSec) { -    StringRef SecName; -    error(P.first.getName(SecName)); +    StringRef SecName = unwrapOrError(P.first.getName(), Obj->getFileName());      outs() << "RELOCATION RECORDS FOR [" << SecName << "]:\n";      for (SectionRef Section : P.second) { @@ -1597,7 +1648,9 @@ void printRelocations(const ObjectFile *Obj) {          if (Address < StartAddress || Address > StopAddress || getHidden(Reloc))            continue;          Reloc.getTypeName(RelocName); -        error(getRelocationValueString(Reloc, ValueStr)); +        if (Error E = getRelocationValueString(Reloc, ValueStr)) +          reportError(std::move(E), Obj->getFileName()); +          outs() << format(Fmt.data(), Address) << " " << RelocName << " "                 << ValueStr << "\n";        } @@ -1613,7 +1666,7 @@ void printDynamicRelocations(const ObjectFile *Obj) {    const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj);    if (!Elf || Elf->getEType() != ELF::ET_DYN) { -    error("not a dynamic object"); +    reportError(Obj->getFileName(), "not a dynamic object");      return;    } @@ -1629,7 +1682,8 @@ void printDynamicRelocations(const ObjectFile *Obj) {        SmallString<32> RelocName;        SmallString<32> ValueStr;        Reloc.getTypeName(RelocName); -      error(getRelocationValueString(Reloc, ValueStr)); +      if (Error E = getRelocationValueString(Reloc, ValueStr)) +        reportError(std::move(E), Obj->getFileName());        outs() << format(Fmt.data(), Address) << " " << RelocName << " "               << ValueStr << "\n";      } @@ -1647,47 +1701,64 @@ static bool shouldDisplayLMA(const ObjectFile *Obj) {    return ShowLMA;  } +static size_t getMaxSectionNameWidth(const ObjectFile *Obj) { +  // Default column width for names is 13 even if no names are that long. +  size_t MaxWidth = 13; +  for (const SectionRef &Section : ToolSectionFilter(*Obj)) { +    StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName()); +    MaxWidth = std::max(MaxWidth, Name.size()); +  } +  return MaxWidth; +} +  void printSectionHeaders(const ObjectFile *Obj) { +  size_t NameWidth = getMaxSectionNameWidth(Obj); +  size_t AddressWidth = 2 * Obj->getBytesInAddress();    bool HasLMAColumn = shouldDisplayLMA(Obj);    if (HasLMAColumn)      outs() << "Sections:\n" -              "Idx Name          Size     VMA              LMA              " -              "Type\n"; +              "Idx " +           << left_justify("Name", NameWidth) << " Size     " +           << left_justify("VMA", AddressWidth) << " " +           << left_justify("LMA", AddressWidth) << " Type\n";    else      outs() << "Sections:\n" -              "Idx Name          Size     VMA          Type\n"; +              "Idx " +           << left_justify("Name", NameWidth) << " Size     " +           << left_justify("VMA", AddressWidth) << " Type\n"; -  for (const SectionRef &Section : ToolSectionFilter(*Obj)) { -    StringRef Name; -    error(Section.getName(Name)); +  uint64_t Idx; +  for (const SectionRef &Section : ToolSectionFilter(*Obj, &Idx)) { +    StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());      uint64_t VMA = Section.getAddress();      if (shouldAdjustVA(Section))        VMA += AdjustVMA;      uint64_t Size = Section.getSize(); -    bool Text = Section.isText(); -    bool Data = Section.isData(); -    bool BSS = Section.isBSS(); -    std::string Type = (std::string(Text ? "TEXT " : "") + -                        (Data ? "DATA " : "") + (BSS ? "BSS" : "")); + +    std::string Type = Section.isText() ? "TEXT" : ""; +    if (Section.isData()) +      Type += Type.empty() ? "DATA" : " DATA"; +    if (Section.isBSS()) +      Type += Type.empty() ? "BSS" : " BSS";      if (HasLMAColumn) -      outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %016" PRIx64 -                       " %s\n", -                       (unsigned)Section.getIndex(), Name.str().c_str(), Size, -                       VMA, getELFSectionLMA(Section), Type.c_str()); +      outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth, +                       Name.str().c_str(), Size) +             << format_hex_no_prefix(VMA, AddressWidth) << " " +             << format_hex_no_prefix(getELFSectionLMA(Section), AddressWidth) +             << " " << Type << "\n";      else -      outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n", -                       (unsigned)Section.getIndex(), Name.str().c_str(), Size, -                       VMA, Type.c_str()); +      outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth, +                       Name.str().c_str(), Size) +             << format_hex_no_prefix(VMA, AddressWidth) << " " << Type << "\n";    }    outs() << "\n";  }  void printSectionContents(const ObjectFile *Obj) {    for (const SectionRef &Section : ToolSectionFilter(*Obj)) { -    StringRef Name; -    error(Section.getName(Name)); +    StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());      uint64_t BaseAddr = Section.getAddress();      uint64_t Size = Section.getSize();      if (!Size) @@ -1739,23 +1810,44 @@ void printSymbolTable(const ObjectFile *O, StringRef ArchiveName,    }    const StringRef FileName = O->getFileName(); +  const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(O);    for (auto I = O->symbol_begin(), E = O->symbol_end(); I != E; ++I) {      const SymbolRef &Symbol = *I; -    uint64_t Address = unwrapOrError(Symbol.getAddress(), ArchiveName, FileName, +    uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName, ArchiveName,                                       ArchitectureName);      if ((Address < StartAddress) || (Address > StopAddress))        continue; -    SymbolRef::Type Type = unwrapOrError(Symbol.getType(), ArchiveName, -                                         FileName, ArchitectureName); +    SymbolRef::Type Type = unwrapOrError(Symbol.getType(), FileName, +                                         ArchiveName, ArchitectureName);      uint32_t Flags = Symbol.getFlags(); -    section_iterator Section = unwrapOrError(Symbol.getSection(), ArchiveName, -                                             FileName, ArchitectureName); + +    // Don't ask a Mach-O STAB symbol for its section unless you know that  +    // STAB symbol's section field refers to a valid section index. Otherwise +    // the symbol may error trying to load a section that does not exist. +    bool isSTAB = false; +    if (MachO) { +      DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); +      uint8_t NType = (MachO->is64Bit() ? +                       MachO->getSymbol64TableEntry(SymDRI).n_type: +                       MachO->getSymbolTableEntry(SymDRI).n_type); +      if (NType & MachO::N_STAB) +        isSTAB = true; +    } +    section_iterator Section = isSTAB ? O->section_end() : +                               unwrapOrError(Symbol.getSection(), FileName, +                                             ArchiveName, ArchitectureName); +      StringRef Name; -    if (Type == SymbolRef::ST_Debug && Section != O->section_end()) -      Section->getName(Name); -    else -      Name = unwrapOrError(Symbol.getName(), ArchiveName, FileName, +    if (Type == SymbolRef::ST_Debug && Section != O->section_end()) { +      if (Expected<StringRef> NameOrErr = Section->getName()) +        Name = *NameOrErr; +      else +        consumeError(NameOrErr.takeError()); + +    } else { +      Name = unwrapOrError(Symbol.getName(), FileName, ArchiveName,                             ArchitectureName); +    }      bool Global = Flags & SymbolRef::SF_Global;      bool Weak = Flags & SymbolRef::SF_Weak; @@ -1801,8 +1893,8 @@ void printSymbolTable(const ObjectFile *O, StringRef ArchiveName,          StringRef SegmentName = MachO->getSectionFinalSegmentName(DR);          outs() << SegmentName << ",";        } -      StringRef SectionName; -      error(Section->getName(SectionName)); +      StringRef SectionName = +          unwrapOrError(Section->getName(), O->getFileName());        outs() << SectionName;      } @@ -1875,7 +1967,11 @@ void printRawClangAST(const ObjectFile *Obj) {    Optional<object::SectionRef> ClangASTSection;    for (auto Sec : ToolSectionFilter(*Obj)) {      StringRef Name; -    Sec.getName(Name); +    if (Expected<StringRef> NameOrErr = Sec.getName()) +      Name = *NameOrErr; +    else +      consumeError(NameOrErr.takeError()); +      if (Name == ClangASTSectionName) {        ClangASTSection = Sec;        break; @@ -1907,7 +2003,11 @@ static void printFaultMaps(const ObjectFile *Obj) {    for (auto Sec : ToolSectionFilter(*Obj)) {      StringRef Name; -    Sec.getName(Name); +    if (Expected<StringRef> NameOrErr = Sec.getName()) +      Name = *NameOrErr; +    else +      consumeError(NameOrErr.takeError()); +      if (Name == FaultMapSectionName) {        FaultMapSection = Sec;        break; @@ -1946,12 +2046,12 @@ static void printPrivateFileHeaders(const ObjectFile *O, bool OnlyFirst) {        printMachOLoadCommands(O);      return;    } -  report_error(O->getFileName(), "Invalid/Unsupported object file format"); +  reportError(O->getFileName(), "Invalid/Unsupported object file format");  }  static void printFileHeaders(const ObjectFile *O) {    if (!O->isELF() && !O->isCOFF()) -    report_error(O->getFileName(), "Invalid/Unsupported object file format"); +    reportError(O->getFileName(), "Invalid/Unsupported object file format");    Triple::ArchType AT = O->getArch();    outs() << "architecture: " << Triple::getArchTypeName(AT) << "\n"; @@ -2010,6 +2110,43 @@ static void printArchiveChild(StringRef Filename, const Archive::Child &C) {    outs() << Name << "\n";  } +// For ELF only now. +static bool shouldWarnForInvalidStartStopAddress(ObjectFile *Obj) { +  if (const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj)) { +    if (Elf->getEType() != ELF::ET_REL) +      return true; +  } +  return false; +} + +static void checkForInvalidStartStopAddress(ObjectFile *Obj, +                                            uint64_t Start, uint64_t Stop) { +  if (!shouldWarnForInvalidStartStopAddress(Obj)) +    return; + +  for (const SectionRef &Section : Obj->sections()) +    if (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC) { +      uint64_t BaseAddr = Section.getAddress(); +      uint64_t Size = Section.getSize(); +      if ((Start < BaseAddr + Size) && Stop > BaseAddr) +        return; +    } + +  if (StartAddress.getNumOccurrences() == 0) +    reportWarning("no section has address less than 0x" + +                      Twine::utohexstr(Stop) + " specified by --stop-address", +                  Obj->getFileName()); +  else if (StopAddress.getNumOccurrences() == 0) +    reportWarning("no section has address greater than or equal to 0x" + +                      Twine::utohexstr(Start) + " specified by --start-address", +                  Obj->getFileName()); +  else +    reportWarning("no section overlaps the range [0x" + +                      Twine::utohexstr(Start) + ",0x" + Twine::utohexstr(Stop) + +                      ") specified by --start-address/--stop-address", +                  Obj->getFileName()); +} +  static void dumpObject(ObjectFile *O, const Archive *A = nullptr,                         const Archive::Child *C = nullptr) {    // Avoid other output when using a raw option. @@ -2022,27 +2159,40 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr,      outs() << ":\tfile format " << O->getFileFormatName() << "\n\n";    } +  if (StartAddress.getNumOccurrences() || StopAddress.getNumOccurrences()) +    checkForInvalidStartStopAddress(O, StartAddress, StopAddress); + +  // Note: the order here matches GNU objdump for compatability.    StringRef ArchiveName = A ? A->getFileName() : ""; -  if (FileHeaders) -    printFileHeaders(O);    if (ArchiveHeaders && !MachOOpt && C)      printArchiveChild(ArchiveName, *C); -  if (Disassemble) -    disassembleObject(O, Relocations); +  if (FileHeaders) +    printFileHeaders(O); +  if (PrivateHeaders || FirstPrivateHeader) +    printPrivateFileHeaders(O, FirstPrivateHeader); +  if (SectionHeaders) +    printSectionHeaders(O); +  if (SymbolTable) +    printSymbolTable(O, ArchiveName); +  if (DwarfDumpType != DIDT_Null) { +    std::unique_ptr<DIContext> DICtx = DWARFContext::create(*O); +    // Dump the complete DWARF structure. +    DIDumpOptions DumpOpts; +    DumpOpts.DumpType = DwarfDumpType; +    DICtx->dump(outs(), DumpOpts); +  }    if (Relocations && !Disassemble)      printRelocations(O);    if (DynamicRelocations)      printDynamicRelocations(O); -  if (SectionHeaders) -    printSectionHeaders(O);    if (SectionContents)      printSectionContents(O); -  if (SymbolTable) -    printSymbolTable(O, ArchiveName); +  if (Disassemble) +    disassembleObject(O, Relocations);    if (UnwindInfo)      printUnwindInfo(O); -  if (PrivateHeaders || FirstPrivateHeader) -    printPrivateFileHeaders(O, FirstPrivateHeader); + +  // Mach-O specific options:    if (ExportsTrie)      printExportsTrie(O);    if (Rebase) @@ -2053,17 +2203,12 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr,      printLazyBindTable(O);    if (WeakBind)      printWeakBindTable(O); + +  // Other special sections:    if (RawClangAST)      printRawClangAST(O);    if (FaultMapSection)      printFaultMaps(O); -  if (DwarfDumpType != DIDT_Null) { -    std::unique_ptr<DIContext> DICtx = DWARFContext::create(*O); -    // Dump the complete DWARF structure. -    DIDumpOptions DumpOpts; -    DumpOpts.DumpType = DwarfDumpType; -    DICtx->dump(outs(), DumpOpts); -  }  }  static void dumpObject(const COFFImportFile *I, const Archive *A, @@ -2086,11 +2231,13 @@ static void dumpObject(const COFFImportFile *I, const Archive *A,  /// Dump each object file in \a a;  static void dumpArchive(const Archive *A) {    Error Err = Error::success(); +  unsigned I = -1;    for (auto &C : A->children(Err)) { +    ++I;      Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();      if (!ChildOrErr) {        if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) -        report_error(std::move(E), A->getFileName(), C); +        reportError(std::move(E), getFileNameForError(C, I), A->getFileName());        continue;      }      if (ObjectFile *O = dyn_cast<ObjectFile>(&*ChildOrErr.get())) @@ -2098,11 +2245,11 @@ static void dumpArchive(const Archive *A) {      else if (COFFImportFile *I = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))        dumpObject(I, A, &C);      else -      report_error(errorCodeToError(object_error::invalid_file_type), -                   A->getFileName()); +      reportError(errorCodeToError(object_error::invalid_file_type), +                  A->getFileName());    }    if (Err) -    report_error(std::move(Err), A->getFileName()); +    reportError(std::move(Err), A->getFileName());  }  /// Open file and figure out how to dump it. @@ -2126,7 +2273,7 @@ static void dumpInput(StringRef file) {    else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Binary))      parseInputMachO(UB);    else -    report_error(errorCodeToError(object_error::invalid_file_type), file); +    reportError(errorCodeToError(object_error::invalid_file_type), file);  }  } // namespace llvm @@ -2147,7 +2294,7 @@ int main(int argc, char **argv) {    cl::ParseCommandLineOptions(argc, argv, "llvm object file dumper\n");    if (StartAddress >= StopAddress) -    error("start address should be less than stop address"); +    reportCmdLineError("start address should be less than stop address");    ToolName = argv[0]; 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 e58d4a05c2e6..43ce02ae0bc2 100644 --- a/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h @@ -31,6 +31,8 @@ extern cl::opt<bool> Demangle;  typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate; +/// A filtered iterator for SectionRefs that skips sections based on some given +/// predicate.  class SectionFilterIterator {  public:    SectionFilterIterator(FilterPredicate P, @@ -60,6 +62,8 @@ private:    llvm::object::section_iterator End;  }; +/// Creates an iterator range of SectionFilterIterators for a given Object and +/// predicate.  class SectionFilter {  public:    SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O) @@ -79,7 +83,15 @@ private:  };  // Various helper functions. -SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O); + +/// Creates a SectionFilter with a standard predicate that conditionally skips +/// sections when the --section objdump flag is provided. +/// +/// 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);  Error getELFRelocationValueString(const object::ELFObjectFileBase *Obj,                                    const object::RelocationRef &Rel, @@ -96,8 +108,6 @@ Error getMachORelocationValueString(const object::MachOObjectFile *Obj,  uint64_t getELFSectionLMA(const object::ELFSectionRef& Sec); -void error(std::error_code ec); -void error(Error E);  bool isRelocAddressLess(object::RelocationRef A, object::RelocationRef B);  void parseInputMachO(StringRef Filename);  void parseInputMachO(object::MachOUniversalBinary *UB); @@ -129,24 +139,22 @@ void printSectionHeaders(const object::ObjectFile *O);  void printSectionContents(const object::ObjectFile *O);  void printSymbolTable(const object::ObjectFile *O, StringRef ArchiveName,                        StringRef ArchitectureName = StringRef()); -void warn(StringRef Message); -LLVM_ATTRIBUTE_NORETURN void error(Twine Message); -LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, Twine Message); -LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef File); -LLVM_ATTRIBUTE_NORETURN void -report_error(Error E, StringRef FileName, StringRef ArchiveName, -             StringRef ArchitectureName = StringRef()); -LLVM_ATTRIBUTE_NORETURN void -report_error(Error E, StringRef ArchiveName, const object::Archive::Child &C, -             StringRef ArchitectureName = StringRef()); +LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Twine Message); +LLVM_ATTRIBUTE_NORETURN void reportError(Error E, StringRef FileName, +                                         StringRef ArchiveName = "", +                                         StringRef ArchitectureName = ""); +void reportWarning(Twine Message, StringRef File);  template <typename T, typename... Ts>  T unwrapOrError(Expected<T> EO, Ts &&... Args) {    if (EO)      return std::move(*EO); -  report_error(EO.takeError(), std::forward<Ts>(Args)...); +  reportError(EO.takeError(), std::forward<Ts>(Args)...);  } +std::string getFileNameForError(const object::Archive::Child &C, +                                unsigned Index); +  } // end namespace llvm  #endif diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp index 162d12c120b4..ffc907e09f11 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp @@ -457,7 +457,7 @@ BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {    uint32_t Count = Tpi->getNumTypeRecords();    auto Offsets = Tpi->getTypeIndexOffsets();    TypeCollection = -      llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets); +      std::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);    return *TypeCollection;  } diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp index 962d4cf88a8a..bf725ad8d606 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -1369,9 +1369,10 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() {    LazyRandomTypeCollection Types(100);    for (const auto &S : getObj().sections()) { -    StringRef SectionName; -    if (auto EC = S.getName(SectionName)) -      return errorCodeToError(EC); +    Expected<StringRef> NameOrErr = S.getName(); +    if (!NameOrErr) +      return NameOrErr.takeError(); +    StringRef SectionName = *NameOrErr;      // .debug$T is a standard CodeView type section, while .debug$P is the same      // format but used for MSVC precompiled header object files. @@ -1406,7 +1407,7 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() {        P.formatLine("Local / Global hashes:");        TypeIndex TI(TypeIndex::FirstNonSimpleIndex); -      for (const auto &H : zip(LocalHashes, GlobalHashes)) { +      for (auto H : zip(LocalHashes, GlobalHashes)) {          AutoIndent Indent2(P);          LocallyHashedType &L = std::get<0>(H);          GloballyHashedType &G = std::get<1>(H); @@ -1551,7 +1552,7 @@ Error DumpOutputStyle::dumpModuleSymsForObj() {          Dumper.setSymbolGroup(&Strings);          for (auto Symbol : Symbols) {            if (auto EC = Visitor.visitSymbolRecord(Symbol)) { -            SymbolError = llvm::make_unique<Error>(std::move(EC)); +            SymbolError = std::make_unique<Error>(std::move(EC));              return;            }          } diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp index 94faa0463981..3d2490509c03 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp @@ -64,7 +64,7 @@ Error ExplainOutputStyle::explainPdbFile() {  Error ExplainOutputStyle::explainBinaryFile() {    std::unique_ptr<BinaryByteStream> Stream = -      llvm::make_unique<BinaryByteStream>(File.unknown().getBuffer(), +      std::make_unique<BinaryByteStream>(File.unknown().getBuffer(),                                            llvm::support::little);    switch (opts::explain::InputType) {    case opts::explain::InputFileType::DBIStream: { diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.cpp index bd23bfdbe31a..b316882de64d 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.cpp @@ -66,12 +66,13 @@ getModuleDebugStream(PDBFile &File, StringRef &ModuleName, uint32_t Index) {  static inline bool isCodeViewDebugSubsection(object::SectionRef Section,                                               StringRef Name,                                               BinaryStreamReader &Reader) { -  StringRef SectionName; -  if (Section.getName(SectionName)) -    return false; - -  if (SectionName != Name) +  if (Expected<StringRef> NameOrErr = Section.getName()) { +    if (*NameOrErr != Name) +      return false; +  } else { +    consumeError(NameOrErr.takeError());      return false; +  }    Expected<StringRef> ContentsOrErr = Section.getContents();    if (!ContentsOrErr) { @@ -384,7 +385,7 @@ InputFile::getOrCreateTypeCollection(TypeCollectionKind Kind) {      uint32_t Count = Stream.getNumTypeRecords();      auto Offsets = Stream.getTypeIndexOffsets();      Collection = -        llvm::make_unique<LazyRandomTypeCollection>(Array, Count, Offsets); +        std::make_unique<LazyRandomTypeCollection>(Array, Count, Offsets);      return *Collection;    } @@ -397,11 +398,11 @@ InputFile::getOrCreateTypeCollection(TypeCollectionKind Kind) {      if (!isDebugTSection(Section, Records))        continue; -    Types = llvm::make_unique<LazyRandomTypeCollection>(Records, 100); +    Types = std::make_unique<LazyRandomTypeCollection>(Records, 100);      return *Types;    } -  Types = llvm::make_unique<LazyRandomTypeCollection>(100); +  Types = std::make_unique<LazyRandomTypeCollection>(100);    return *Types;  } diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.h b/contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.h index f25390c971d0..a5d2897f5600 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.h +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.h @@ -43,7 +43,7 @@ class InputFile {    std::unique_ptr<NativeSession> PdbSession;    object::OwningBinary<object::Binary> CoffObject;    std::unique_ptr<MemoryBuffer> UnknownFile; -  PointerUnion3<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj; +  PointerUnion<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj;    using TypeCollectionPtr = std::unique_ptr<codeview::LazyRandomTypeCollection>; diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp index e5ae47050678..ebfa50625e76 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp @@ -569,8 +569,9 @@ Error MinimalSymbolDumper::visitKnownRecord(  Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,                                              DefRangeFramePointerRelSym &Def) {    AutoIndent Indent(P, 7); -  P.formatLine("offset = {0}, range = {1}", Def.Offset, formatRange(Def.Range)); -  P.formatLine("gaps = {2}", Def.Offset, +  P.formatLine("offset = {0}, range = {1}", Def.Hdr.Offset, +               formatRange(Def.Range)); +  P.formatLine("gaps = {2}", Def.Hdr.Offset,                 formatGaps(P.getIndentLevel() + 9, Def.Gaps));    return Error::success();  } diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp index e8f8e5aa62c9..2f7a39803ca5 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp @@ -117,7 +117,7 @@ filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,        continue;      } -    auto Layout = llvm::make_unique<ClassLayout>(std::move(Class)); +    auto Layout = std::make_unique<ClassLayout>(std::move(Class));      if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {        ++Discarded;        continue; @@ -259,7 +259,7 @@ void TypeDumper::start(const PDBSymbolExe &Exe) {              continue;            } -          auto Layout = llvm::make_unique<ClassLayout>(std::move(Class)); +          auto Layout = std::make_unique<ClassLayout>(std::move(Class));            if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)              continue; diff --git a/contrib/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/contrib/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp index 785a98086791..9307300861d4 100644 --- a/contrib/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -863,8 +863,8 @@ static void pdb2Yaml(StringRef Path) {    std::unique_ptr<IPDBSession> Session;    auto &File = loadPDB(Path, Session); -  auto O = llvm::make_unique<YAMLOutputStyle>(File); -  O = llvm::make_unique<YAMLOutputStyle>(File); +  auto O = std::make_unique<YAMLOutputStyle>(File); +  O = std::make_unique<YAMLOutputStyle>(File);    ExitOnErr(O->dump());  } @@ -872,7 +872,7 @@ static void pdb2Yaml(StringRef Path) {  static void dumpRaw(StringRef Path) {    InputFile IF = ExitOnErr(InputFile::open(Path)); -  auto O = llvm::make_unique<DumpOutputStyle>(IF); +  auto O = std::make_unique<DumpOutputStyle>(IF);    ExitOnErr(O->dump());  } @@ -880,7 +880,7 @@ static void dumpBytes(StringRef Path) {    std::unique_ptr<IPDBSession> Session;    auto &File = loadPDB(Path, Session); -  auto O = llvm::make_unique<BytesOutputStyle>(File); +  auto O = std::make_unique<BytesOutputStyle>(File);    ExitOnErr(O->dump());  } @@ -1347,7 +1347,7 @@ static void explain() {        ExitOnErr(InputFile::open(opts::explain::InputFilename.front(), true));    for (uint64_t Off : opts::explain::Offsets) { -    auto O = llvm::make_unique<ExplainOutputStyle>(IF, Off); +    auto O = std::make_unique<ExplainOutputStyle>(IF, Off);      ExitOnErr(O->dump());    } 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 16d3ebe3fcbc..41e9abb82b1f 100644 --- a/contrib/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -26,6 +26,7 @@  #include "llvm/Support/InitLLVM.h"  #include "llvm/Support/MemoryBuffer.h"  #include "llvm/Support/Path.h" +#include "llvm/Support/Threading.h"  #include "llvm/Support/ThreadPool.h"  #include "llvm/Support/WithColor.h"  #include "llvm/Support/raw_ostream.h" @@ -37,6 +38,7 @@ enum ProfileFormat {    PF_None = 0,    PF_Text,    PF_Compact_Binary, +  PF_Ext_Binary,    PF_GCC,    PF_Binary  }; @@ -84,6 +86,15 @@ static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") {  namespace {  enum ProfileKinds { instr, sample }; +enum FailureMode { failIfAnyAreInvalid, failIfAllAreInvalid }; +} + +static void warnOrExitGivenError(FailureMode FailMode, std::error_code EC, +                                 StringRef Whence = "") { +  if (FailMode == failIfAnyAreInvalid) +    exitWithErrorCode(EC, Whence); +  else +    warn(EC.message(), Whence);  }  static void handleMergeWriterError(Error E, StringRef WhenceFile = "", @@ -136,7 +147,7 @@ public:      if (!BufOrError)        exitWithErrorCode(BufOrError.getError(), InputFile); -    auto Remapper = llvm::make_unique<SymbolRemapper>(); +    auto Remapper = std::make_unique<SymbolRemapper>();      Remapper->File = std::move(BufOrError.get());      for (line_iterator LineIt(*Remapper->File, /*SkipBlanks=*/true, '#'); @@ -173,33 +184,16 @@ typedef SmallVector<WeightedFile, 5> WeightedFileVector;  struct WriterContext {    std::mutex Lock;    InstrProfWriter Writer; -  Error Err; -  std::string ErrWhence; +  std::vector<std::pair<Error, std::string>> Errors;    std::mutex &ErrLock;    SmallSet<instrprof_error, 4> &WriterErrorCodes;    WriterContext(bool IsSparse, std::mutex &ErrLock,                  SmallSet<instrprof_error, 4> &WriterErrorCodes) -      : Lock(), Writer(IsSparse), Err(Error::success()), ErrWhence(""), -        ErrLock(ErrLock), WriterErrorCodes(WriterErrorCodes) {} +      : Lock(), Writer(IsSparse), Errors(), ErrLock(ErrLock), +        WriterErrorCodes(WriterErrorCodes) {}  }; -/// Determine whether an error is fatal for profile merging. -static bool isFatalError(instrprof_error IPE) { -  switch (IPE) { -  default: -    return true; -  case instrprof_error::success: -  case instrprof_error::eof: -  case instrprof_error::unknown_function: -  case instrprof_error::hash_mismatch: -  case instrprof_error::count_mismatch: -  case instrprof_error::counter_overflow: -  case instrprof_error::value_site_count_mismatch: -    return false; -  } -} -  /// Computer the overlap b/w profile BaseFilename and TestFileName,  /// and store the program level result to Overlap.  static void overlapInput(const std::string &BaseFilename, @@ -212,7 +206,7 @@ static void overlapInput(const std::string &BaseFilename,      // Skip the empty profiles by returning sliently.      instrprof_error IPE = InstrProfError::take(std::move(E));      if (IPE != instrprof_error::empty_raw_profile) -      WC->Err = make_error<InstrProfError>(IPE); +      WC->Errors.emplace_back(make_error<InstrProfError>(IPE), TestFilename);      return;    } @@ -231,21 +225,17 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,                        WriterContext *WC) {    std::unique_lock<std::mutex> CtxGuard{WC->Lock}; -  // If there's a pending hard error, don't do more work. -  if (WC->Err) -    return; -    // Copy the filename, because llvm::ThreadPool copied the input "const    // WeightedFile &" by value, making a reference to the filename within it    // invalid outside of this packaged task. -  WC->ErrWhence = Input.Filename; +  std::string Filename = Input.Filename;    auto ReaderOrErr = InstrProfReader::create(Input.Filename);    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->Err = make_error<InstrProfError>(IPE); +      WC->Errors.emplace_back(make_error<InstrProfError>(IPE), Filename);      return;    } @@ -253,9 +243,11 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,    bool IsIRProfile = Reader->isIRLevelProfile();    bool HasCSIRProfile = Reader->hasCSIRLevelProfile();    if (WC->Writer.setIsIRLevelProfile(IsIRProfile, HasCSIRProfile)) { -    WC->Err = make_error<StringError>( -        "Merge IR generated profile with Clang generated profile.", -        std::error_code()); +    WC->Errors.emplace_back( +        make_error<StringError>( +            "Merge IR generated profile with Clang generated profile.", +            std::error_code()), +        Filename);      return;    } @@ -278,30 +270,23 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,                               FuncName, firstTime);      });    } -  if (Reader->hasError()) { -    if (Error E = Reader->getError()) { -      instrprof_error IPE = InstrProfError::take(std::move(E)); -      if (isFatalError(IPE)) -        WC->Err = make_error<InstrProfError>(IPE); -    } -  } +  if (Reader->hasError()) +    if (Error E = Reader->getError()) +      WC->Errors.emplace_back(std::move(E), Filename);  }  /// Merge the \p Src writer context into \p Dst.  static void mergeWriterContexts(WriterContext *Dst, WriterContext *Src) { -  // If we've already seen a hard error, continuing with the merge would -  // clobber it. -  if (Dst->Err || Src->Err) -    return; +  for (auto &ErrorPair : Src->Errors) +    Dst->Errors.push_back(std::move(ErrorPair)); +  Src->Errors.clear(); -  bool Reported = false;    Dst->Writer.mergeRecordsFromWriter(std::move(Src->Writer), [&](Error E) { -    if (Reported) { -      consumeError(std::move(E)); -      return; -    } -    Reported = true; -    Dst->Err = std::move(E); +    instrprof_error IPE = InstrProfError::take(std::move(E)); +    std::unique_lock<std::mutex> ErrGuard{Dst->ErrLock}; +    bool firstTime = Dst->WriterErrorCodes.insert(IPE).second; +    if (firstTime) +      warn(toString(make_error<InstrProfError>(IPE)));    });  } @@ -309,12 +294,12 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,                                SymbolRemapper *Remapper,                                StringRef OutputFilename,                                ProfileFormat OutputFormat, bool OutputSparse, -                              unsigned NumThreads) { +                              unsigned NumThreads, FailureMode FailMode) {    if (OutputFilename.compare("-") == 0)      exitWithError("Cannot write indexed profdata format to stdout.");    if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary && -      OutputFormat != PF_Text) +      OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text)      exitWithError("Unknown format is specified.");    std::mutex ErrorLock; @@ -328,7 +313,7 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,    // Initialize the writer contexts.    SmallVector<std::unique_ptr<WriterContext>, 4> Contexts;    for (unsigned I = 0; I < NumThreads; ++I) -    Contexts.emplace_back(llvm::make_unique<WriterContext>( +    Contexts.emplace_back(std::make_unique<WriterContext>(          OutputSparse, ErrorLock, WriterErrorCodes));    if (NumThreads == 1) { @@ -364,23 +349,21 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,      } while (Mid > 0);    } -  // Handle deferred hard errors encountered during merging. +  // Handle deferred errors encountered during merging. If the number of errors +  // is equal to the number of inputs the merge failed. +  unsigned NumErrors = 0;    for (std::unique_ptr<WriterContext> &WC : Contexts) { -    if (!WC->Err) -      continue; -    if (!WC->Err.isA<InstrProfError>()) -      exitWithError(std::move(WC->Err), WC->ErrWhence); - -    instrprof_error IPE = InstrProfError::take(std::move(WC->Err)); -    if (isFatalError(IPE)) -      exitWithError(make_error<InstrProfError>(IPE), WC->ErrWhence); -    else -      warn(toString(make_error<InstrProfError>(IPE)), -           WC->ErrWhence); +    for (auto &ErrorPair : WC->Errors) { +      ++NumErrors; +      warn(toString(std::move(ErrorPair.first)), ErrorPair.second); +    }    } +  if (NumErrors == Inputs.size() || +      (NumErrors > 0 && FailMode == failIfAnyAreInvalid)) +    exitWithError("No profiles could be merged.");    std::error_code EC; -  raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None); +  raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::OF_None);    if (EC)      exitWithErrorCode(EC, OutputFilename); @@ -425,21 +408,78 @@ remapSamples(const sampleprof::FunctionSamples &Samples,  }  static sampleprof::SampleProfileFormat FormatMap[] = { -    sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Compact_Binary, -    sampleprof::SPF_GCC, sampleprof::SPF_Binary}; +    sampleprof::SPF_None, +    sampleprof::SPF_Text, +    sampleprof::SPF_Compact_Binary, +    sampleprof::SPF_Ext_Binary, +    sampleprof::SPF_GCC, +    sampleprof::SPF_Binary}; + +static std::unique_ptr<MemoryBuffer> +getInputFileBuf(const StringRef &InputFile) { +  if (InputFile == "") +    return {}; + +  auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFile); +  if (!BufOrError) +    exitWithErrorCode(BufOrError.getError(), InputFile); + +  return std::move(*BufOrError); +} + +static void populateProfileSymbolList(MemoryBuffer *Buffer, +                                      sampleprof::ProfileSymbolList &PSL) { +  if (!Buffer) +    return; + +  SmallVector<StringRef, 32> SymbolVec; +  StringRef Data = Buffer->getBuffer(); +  Data.split(SymbolVec, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false); + +  for (StringRef symbol : SymbolVec) +    PSL.add(symbol); +} + +static void handleExtBinaryWriter(sampleprof::SampleProfileWriter &Writer, +                                  ProfileFormat OutputFormat, +                                  MemoryBuffer *Buffer, +                                  sampleprof::ProfileSymbolList &WriterList, +                                  bool CompressAllSections) { +  populateProfileSymbolList(Buffer, WriterList); +  if (WriterList.size() > 0 && OutputFormat != PF_Ext_Binary) +    warn("Profile Symbol list is not empty but the output format is not " +         "ExtBinary format. The list will be lost in the output. "); + +  Writer.setProfileSymbolList(&WriterList); + +  if (CompressAllSections) { +    if (OutputFormat != PF_Ext_Binary) { +      warn("-compress-all-section is ignored. Specify -extbinary to enable it"); +    } else { +      auto ExtBinaryWriter = +          static_cast<sampleprof::SampleProfileWriterExtBinary *>(&Writer); +      ExtBinaryWriter->setToCompressAllSections(); +    } +  } +}  static void mergeSampleProfile(const WeightedFileVector &Inputs,                                 SymbolRemapper *Remapper,                                 StringRef OutputFilename, -                               ProfileFormat OutputFormat) { +                               ProfileFormat OutputFormat, +                               StringRef ProfileSymbolListFile, +                               bool CompressAllSections, FailureMode FailMode) {    using namespace sampleprof;    StringMap<FunctionSamples> ProfileMap;    SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers;    LLVMContext Context; +  sampleprof::ProfileSymbolList WriterList;    for (const auto &Input : Inputs) {      auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context); -    if (std::error_code EC = ReaderOrErr.getError()) -      exitWithErrorCode(EC, Input.Filename); +    if (std::error_code EC = ReaderOrErr.getError()) { +      warnOrExitGivenError(FailMode, EC, Input.Filename); +      continue; +    }      // We need to keep the readers around until after all the files are      // read so that we do not lose the function names stored in each @@ -447,8 +487,11 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs,      // merged profile map.      Readers.push_back(std::move(ReaderOrErr.get()));      const auto Reader = Readers.back().get(); -    if (std::error_code EC = Reader->read()) -      exitWithErrorCode(EC, Input.Filename); +    if (std::error_code EC = Reader->read()) { +      warnOrExitGivenError(FailMode, EC, Input.Filename); +      Readers.pop_back(); +      continue; +    }      StringMap<FunctionSamples> &Profiles = Reader->getProfiles();      for (StringMap<FunctionSamples>::iterator I = Profiles.begin(), @@ -466,6 +509,11 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs,          handleMergeWriterError(errorCodeToError(EC), Input.Filename, FName);        }      } + +    std::unique_ptr<sampleprof::ProfileSymbolList> ReaderList = +        Reader->getProfileSymbolList(); +    if (ReaderList) +      WriterList.merge(*ReaderList);    }    auto WriterOrErr =        SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]); @@ -473,6 +521,11 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs,      exitWithErrorCode(EC, OutputFilename);    auto Writer = std::move(WriterOrErr.get()); +  // WriterList will have StringRef refering to string in Buffer. +  // Make sure Buffer lives as long as WriterList. +  auto Buffer = getInputFileBuf(ProfileSymbolListFile); +  handleExtBinaryWriter(*Writer, OutputFormat, Buffer.get(), WriterList, +                        CompressAllSections);    Writer->write(ProfileMap);  } @@ -487,18 +540,6 @@ static WeightedFile parseWeightedFile(const StringRef &WeightedFilename) {    return {FileName, Weight};  } -static std::unique_ptr<MemoryBuffer> -getInputFilenamesFileBuf(const StringRef &InputFilenamesFile) { -  if (InputFilenamesFile == "") -    return {}; - -  auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFilenamesFile); -  if (!BufOrError) -    exitWithErrorCode(BufOrError.getError(), InputFilenamesFile); - -  return std::move(*BufOrError); -} -  static void addWeightedInput(WeightedFileVector &WNI, const WeightedFile &WF) {    StringRef Filename = WF.Filename;    uint64_t Weight = WF.Weight; @@ -583,12 +624,20 @@ static int merge_main(int argc, const char *argv[]) {                   clEnumVal(sample, "Sample profile")));    cl::opt<ProfileFormat> OutputFormat(        cl::desc("Format of output profile"), cl::init(PF_Binary), -      cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"), -                 clEnumValN(PF_Compact_Binary, "compbinary", -                            "Compact binary encoding"), -                 clEnumValN(PF_Text, "text", "Text encoding"), -                 clEnumValN(PF_GCC, "gcc", -                            "GCC encoding (only meaningful for -sample)"))); +      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_Text, "text", "Text encoding"), +          clEnumValN(PF_GCC, "gcc", +                     "GCC encoding (only meaningful for -sample)"))); +  cl::opt<FailureMode> FailureMode( +      "failure-mode", cl::init(failIfAnyAreInvalid), cl::desc("Failure mode:"), +      cl::values(clEnumValN(failIfAnyAreInvalid, "any", +                            "Fail if any profile is invalid."), +                 clEnumValN(failIfAllAreInvalid, "all", +                            "Fail only if all profiles are invalid.")));    cl::opt<bool> OutputSparse("sparse", cl::init(false),        cl::desc("Generate a sparse profile (only meaningful for -instr)"));    cl::opt<unsigned> NumThreads( @@ -596,6 +645,14 @@ static int merge_main(int argc, const char *argv[]) {        cl::desc("Number of merge threads to use (default: autodetect)"));    cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),                          cl::aliasopt(NumThreads)); +  cl::opt<std::string> ProfileSymbolListFile( +      "prof-sym-list", cl::init(""), +      cl::desc("Path to file containing the list of function symbols " +               "used to populate profile symbol list")); +  cl::opt<bool> CompressAllSections( +      "compress-all-sections", cl::init(false), cl::Hidden, +      cl::desc("Compress all sections when writing the profile (only " +               "meaningful for -extbinary)"));    cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); @@ -607,7 +664,7 @@ static int merge_main(int argc, const char *argv[]) {    // Make sure that the file buffer stays alive for the duration of the    // weighted input vector's lifetime. -  auto Buffer = getInputFilenamesFileBuf(InputFilenamesFile); +  auto Buffer = getInputFileBuf(InputFilenamesFile);    parseInputFilenamesFile(Buffer.get(), WeightedInputs);    if (WeightedInputs.empty()) @@ -626,10 +683,11 @@ static int merge_main(int argc, const char *argv[]) {    if (ProfileKind == instr)      mergeInstrProfile(WeightedInputs, Remapper.get(), OutputFilename, -                      OutputFormat, OutputSparse, NumThreads); +                      OutputFormat, OutputSparse, NumThreads, FailureMode);    else      mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename, -                       OutputFormat); +                       OutputFormat, ProfileSymbolListFile, CompressAllSections, +                       FailureMode);    return 0;  } @@ -644,7 +702,7 @@ static void overlapInstrProfile(const std::string &BaseFilename,    WriterContext Context(false, ErrorLock, WriterErrorCodes);    WeightedFile WeightedInput{BaseFilename, 1};    OverlapStats Overlap; -  Error E = Overlap.accumuateCounts(BaseFilename, TestFilename, IsCS); +  Error E = Overlap.accumulateCounts(BaseFilename, TestFilename, IsCS);    if (E)      exitWithError(std::move(E), "Error in getting profile count sums");    if (Overlap.Base.CountSum < 1.0f) { @@ -682,7 +740,7 @@ static int overlap_main(int argc, const char *argv[]) {    cl::ParseCommandLineOptions(argc, argv, "LLVM profile data overlap tool\n");    std::error_code EC; -  raw_fd_ostream OS(Output.data(), EC, sys::fs::F_Text); +  raw_fd_ostream OS(Output.data(), EC, sys::fs::OF_Text);    if (EC)      exitWithErrorCode(EC, Output); @@ -944,10 +1002,21 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,    return 0;  } +static void showSectionInfo(sampleprof::SampleProfileReader *Reader, +                            raw_fd_ostream &OS) { +  if (!Reader->dumpSectionInfo(OS)) { +    WithColor::warning() << "-show-sec-info-only is only supported for " +                         << "sample profile in extbinary format and is " +                         << "ignored for other formats.\n"; +    return; +  } +} +  static int showSampleProfile(const std::string &Filename, bool ShowCounts,                               bool ShowAllFunctions,                               const std::string &ShowFunction, -                             raw_fd_ostream &OS) { +                             bool ShowProfileSymbolList, +                             bool ShowSectionInfoOnly, raw_fd_ostream &OS) {    using namespace sampleprof;    LLVMContext Context;    auto ReaderOrErr = SampleProfileReader::create(Filename, Context); @@ -955,6 +1024,12 @@ static int showSampleProfile(const std::string &Filename, bool ShowCounts,      exitWithErrorCode(EC, Filename);    auto Reader = std::move(ReaderOrErr.get()); + +  if (ShowSectionInfoOnly) { +    showSectionInfo(Reader.get(), OS); +    return 0; +  } +    if (std::error_code EC = Reader->read())      exitWithErrorCode(EC, Filename); @@ -963,6 +1038,12 @@ static int showSampleProfile(const std::string &Filename, bool ShowCounts,    else      Reader->dumpFunctionProfile(ShowFunction, OS); +  if (ShowProfileSymbolList) { +    std::unique_ptr<sampleprof::ProfileSymbolList> ReaderList = +        Reader->getProfileSymbolList(); +    ReaderList->dump(OS); +  } +    return 0;  } @@ -1015,6 +1096,15 @@ static int show_main(int argc, const char *argv[]) {        "list-below-cutoff", cl::init(false),        cl::desc("Only output names of functions whose max count values are "                 "below the cutoff value")); +  cl::opt<bool> ShowProfileSymbolList( +      "show-prof-sym-list", cl::init(false), +      cl::desc("Show profile symbol list if it exists in the profile. ")); +  cl::opt<bool> ShowSectionInfoOnly( +      "show-sec-info-only", cl::init(false), +      cl::desc("Show the information of each section in the sample profile. " +               "The flag is only usable when the sample profile is in " +               "extbinary format")); +    cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");    if (OutputFilename.empty()) @@ -1027,7 +1117,7 @@ static int show_main(int argc, const char *argv[]) {    }    std::error_code EC; -  raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text); +  raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_Text);    if (EC)      exitWithErrorCode(EC, OutputFilename); @@ -1042,7 +1132,8 @@ static int show_main(int argc, const char *argv[]) {                              OnlyListBelow, ShowFunction, TextFormat, OS);    else      return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, -                             ShowFunction, OS); +                             ShowFunction, ShowProfileSymbolList, +                             ShowSectionInfoOnly, OS);  }  int main(int argc, const char *argv[]) { diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/contrib/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h index 11f9d6166a59..2c0912038c31 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h @@ -329,6 +329,7 @@ class PrinterContext {    ScopedPrinter &SW;    const object::ELFFile<ET> *ELF; +  StringRef FileName;    const Elf_Shdr *Symtab;    ArrayRef<Elf_Word> ShndxTable; @@ -352,8 +353,8 @@ class PrinterContext {  public:    PrinterContext(ScopedPrinter &SW, const object::ELFFile<ET> *ELF, -                 const Elf_Shdr *Symtab) -      : SW(SW), ELF(ELF), Symtab(Symtab) {} +                 StringRef FileName, const Elf_Shdr *Symtab) +      : SW(SW), ELF(ELF), FileName(FileName), Symtab(Symtab) {}    void PrintUnwindInformation() const;  }; @@ -369,10 +370,10 @@ PrinterContext<ET>::FunctionAtAddress(unsigned Section,      return readobj_error::unknown_symbol;    auto StrTableOrErr = ELF->getStringTableForSymtab(*Symtab);    if (!StrTableOrErr) -    error(StrTableOrErr.takeError()); +    reportError(StrTableOrErr.takeError(), FileName);    StringRef StrTable = *StrTableOrErr; -  for (const Elf_Sym &Sym : unwrapOrError(ELF->symbols(Symtab))) +  for (const Elf_Sym &Sym : unwrapOrError(FileName, ELF->symbols(Symtab)))      if (Sym.st_shndx == Section && Sym.st_value == Address &&          Sym.getType() == ELF::STT_FUNC) {        auto NameOrErr = Sym.getName(StrTable); @@ -398,16 +399,16 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex,    /// handling table.  Use this symbol to recover the actual exception handling    /// table. -  for (const Elf_Shdr &Sec : unwrapOrError(ELF->sections())) { +  for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF->sections())) {      if (Sec.sh_type != ELF::SHT_REL || Sec.sh_info != IndexSectionIndex)        continue;      auto SymTabOrErr = ELF->getSection(Sec.sh_link);      if (!SymTabOrErr) -      error(SymTabOrErr.takeError()); +      reportError(SymTabOrErr.takeError(), FileName);      const Elf_Shdr *SymTab = *SymTabOrErr; -    for (const Elf_Rel &R : unwrapOrError(ELF->rels(&Sec))) { +    for (const Elf_Rel &R : unwrapOrError(FileName, ELF->rels(&Sec))) {        if (R.r_offset != static_cast<unsigned>(IndexTableOffset))          continue; @@ -417,7 +418,7 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex,        RelA.r_addend = 0;        const Elf_Sym *Symbol = -          unwrapOrError(ELF->getRelocationSymbol(&RelA, SymTab)); +          unwrapOrError(FileName, ELF->getRelocationSymbol(&RelA, SymTab));        auto Ret = ELF->getSection(Symbol, SymTab, ShndxTable);        if (!Ret) @@ -570,7 +571,7 @@ void PrinterContext<ET>::PrintUnwindInformation() const {    DictScope UI(SW, "UnwindInformation");    int SectionIndex = 0; -  for (const Elf_Shdr &Sec : unwrapOrError(ELF->sections())) { +  for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF->sections())) {      if (Sec.sh_type == ELF::SHT_ARM_EXIDX) {        DictScope UIT(SW, "UnwindIndexTable"); diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp index 4de14e2e78d5..8f365c5ad082 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -842,8 +842,10 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,    if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XData) -                  (XData.E() ? 0 : XData.EpilogueCount() * 4) - -                (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) +                (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) { +    SW.flush();      report_fatal_error("Malformed unwind data"); +  }    if (XData.E()) {      ArrayRef<uint8_t> UC = XData.UnwindByteCode(); @@ -882,7 +884,7 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,    }    if (XData.X()) { -    const uint32_t Address = XData.ExceptionHandlerRVA(); +    const uint64_t Address = COFF.getImageBase() + XData.ExceptionHandlerRVA();      const uint32_t Parameter = XData.ExceptionHandlerParameter();      const size_t HandlerOffset = HeaderWords(XData)                                 + (XData.E() ? 0 : XData.EpilogueCount()) @@ -894,7 +896,8 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,        Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true);      if (!Symbol) {        ListScope EHS(SW, "ExceptionHandler"); -      SW.printString("Routine", "(null)"); +      SW.printHex("Routine", Address); +      SW.printHex("Parameter", Parameter);        return true;      } @@ -923,7 +926,8 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF,    ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset);    if (!Function) -    Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); +    Function = getSymbol(COFF, COFF.getImageBase() + RF.BeginAddress, +                         /*FunctionOnly=*/true);    ErrorOr<SymbolRef> XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4);    if (!XDataRecord) @@ -1039,10 +1043,7 @@ bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF,      }      FunctionAddress = *FunctionAddressOrErr;    } else { -    const pe32_header *PEHeader; -    if (COFF.getPE32Header(PEHeader)) -      return false; -    FunctionAddress = PEHeader->ImageBase + RF.BeginAddress; +    FunctionAddress = COFF.getPE32Header()->ImageBase + RF.BeginAddress;    }    SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp index 4c2e39dfa3cc..9b2c6adb9d93 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -60,6 +60,10 @@ using namespace llvm::codeview;  using namespace llvm::support;  using namespace llvm::Win64EH; +static inline Error createError(const Twine &Err) { +  return make_error<StringError>(Err, object_error::parse_failed); +} +  namespace {  struct LoadConfigTables { @@ -167,9 +171,6 @@ private:    void printDelayImportedSymbols(        const DelayImportDirectoryEntryRef &I,        iterator_range<imported_symbol_iterator> Range); -  ErrorOr<const coff_resource_dir_entry &> -  getResourceDirectoryTableEntry(const coff_resource_dir_table &Table, -                                 uint32_t Index);    typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy; @@ -627,14 +628,10 @@ void COFFDumper::printFileHeaders() {    // Print PE header. This header does not exist if this is an object file and    // not an executable. -  const pe32_header *PEHeader = nullptr; -  error(Obj->getPE32Header(PEHeader)); -  if (PEHeader) +  if (const pe32_header *PEHeader = Obj->getPE32Header())      printPEHeader<pe32_header>(PEHeader); -  const pe32plus_header *PEPlusHeader = nullptr; -  error(Obj->getPE32PlusHeader(PEPlusHeader)); -  if (PEPlusHeader) +  if (const pe32plus_header *PEPlusHeader = Obj->getPE32PlusHeader())      printPEHeader<pe32plus_header>(PEPlusHeader);    if (const dos_header *DH = Obj->getDOSHeader()) @@ -728,7 +725,9 @@ void COFFDumper::printCOFFDebugDirectory() {      if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW) {        const codeview::DebugInfo *DebugInfo;        StringRef PDBFileName; -      error(Obj->getDebugPDBInfo(&D, DebugInfo, PDBFileName)); +      if (std::error_code EC = Obj->getDebugPDBInfo(&D, DebugInfo, PDBFileName)) +        reportError(errorCodeToError(EC), Obj->getFileName()); +        DictScope PDBScope(W, "PDBInfo");        W.printHex("PDBSignature", DebugInfo->Signature.CVSignature);        if (DebugInfo->Signature.CVSignature == OMF::Signature::PDB70) { @@ -740,8 +739,9 @@ void COFFDumper::printCOFFDebugDirectory() {        // FIXME: Type values of 12 and 13 are commonly observed but are not in        // the documented type enum.  Figure out what they mean.        ArrayRef<uint8_t> RawData; -      error( -          Obj->getRvaAndSizeAsBytes(D.AddressOfRawData, D.SizeOfData, RawData)); +      if (std::error_code EC = Obj->getRvaAndSizeAsBytes(D.AddressOfRawData, +                                                         D.SizeOfData, RawData)) +        reportError(errorCodeToError(EC), Obj->getFileName());        W.printBinaryBlock("RawData", RawData);      }    } @@ -750,8 +750,11 @@ void COFFDumper::printCOFFDebugDirectory() {  void COFFDumper::printRVATable(uint64_t TableVA, uint64_t Count,                                 uint64_t EntrySize, PrintExtraCB PrintExtra) {    uintptr_t TableStart, TableEnd; -  error(Obj->getVaPtr(TableVA, TableStart)); -  error(Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd)); +  if (std::error_code EC = Obj->getVaPtr(TableVA, TableStart)) +    reportError(errorCodeToError(EC), Obj->getFileName()); +  if (std::error_code EC = +          Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd)) +    reportError(errorCodeToError(EC), Obj->getFileName());    TableEnd++;    for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) {      uint32_t RVA = *reinterpret_cast<const ulittle32_t *>(I); @@ -887,16 +890,14 @@ void COFFDumper::printBaseOfDataField(const pe32plus_header *) {}  void COFFDumper::printCodeViewDebugInfo() {    // Print types first to build CVUDTNames, then print symbols.    for (const SectionRef &S : Obj->sections()) { -    StringRef SectionName; -    error(S.getName(SectionName)); +    StringRef SectionName = unwrapOrError(Obj->getFileName(), S.getName());      // .debug$T is a standard CodeView type section, while .debug$P is the same      // format but used for MSVC precompiled header object files.      if (SectionName == ".debug$T" || SectionName == ".debug$P")        printCodeViewTypeSection(SectionName, S);    }    for (const SectionRef &S : Obj->sections()) { -    StringRef SectionName; -    error(S.getName(SectionName)); +    StringRef SectionName = unwrapOrError(Obj->getFileName(), S.getName());      if (SectionName == ".debug$S")        printCodeViewSymbolSection(SectionName, S);    } @@ -908,32 +909,40 @@ void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) {      // The section consists of a number of subsection in the following format:      // |SubSectionType|SubSectionSize|Contents...|      uint32_t SubType, SubSectionSize; -    error(Reader.readInteger(SubType)); -    error(Reader.readInteger(SubSectionSize)); + +    if (Error E = Reader.readInteger(SubType)) +      reportError(std::move(E), Obj->getFileName()); +    if (Error E = Reader.readInteger(SubSectionSize)) +      reportError(std::move(E), Obj->getFileName());      StringRef Contents; -    error(Reader.readFixedString(Contents, SubSectionSize)); +    if (Error E = Reader.readFixedString(Contents, SubSectionSize)) +      reportError(std::move(E), Obj->getFileName());      BinaryStreamRef ST(Contents, support::little);      switch (DebugSubsectionKind(SubType)) {      case DebugSubsectionKind::FileChecksums: -      error(CVFileChecksumTable.initialize(ST)); +      if (Error E = CVFileChecksumTable.initialize(ST)) +        reportError(std::move(E), Obj->getFileName());        break;      case DebugSubsectionKind::StringTable: -      error(CVStringTable.initialize(ST)); +      if (Error E = CVStringTable.initialize(ST)) +        reportError(std::move(E), Obj->getFileName());        break;      default:        break;      }      uint32_t PaddedSize = alignTo(SubSectionSize, 4); -    error(Reader.skip(PaddedSize - SubSectionSize)); +    if (Error E = Reader.skip(PaddedSize - SubSectionSize)) +      reportError(std::move(E), Obj->getFileName());    }  }  void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,                                              const SectionRef &Section) { -  StringRef SectionContents = unwrapOrError(Section.getContents()); +  StringRef SectionContents = +      unwrapOrError(Obj->getFileName(), Section.getContents());    StringRef Data = SectionContents;    SmallVector<StringRef, 10> FunctionNames; @@ -944,10 +953,13 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,    W.printNumber("Section", SectionName, Obj->getSectionID(Section));    uint32_t Magic; -  error(consume(Data, Magic)); +  if (Error E = consume(Data, Magic)) +    reportError(std::move(E), Obj->getFileName()); +    W.printHex("Magic", Magic);    if (Magic != COFF::DEBUG_SECTION_MAGIC) -    return error(object_error::parse_failed); +    reportError(errorCodeToError(object_error::parse_failed), +                Obj->getFileName());    BinaryStreamReader FSReader(Data, support::little);    initializeFileAndStringTables(FSReader); @@ -957,8 +969,10 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,      // The section consists of a number of subsection in the following format:      // |SubSectionType|SubSectionSize|Contents...|      uint32_t SubType, SubSectionSize; -    error(consume(Data, SubType)); -    error(consume(Data, SubSectionSize)); +    if (Error E = consume(Data, SubType)) +      reportError(std::move(E), Obj->getFileName()); +    if (Error E = consume(Data, SubSectionSize)) +      reportError(std::move(E), Obj->getFileName());      ListScope S(W, "Subsection");      // Dump the subsection as normal even if the ignore bit is set. @@ -971,7 +985,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,      // Get the contents of the subsection.      if (SubSectionSize > Data.size()) -      return error(object_error::parse_failed); +      return reportError(errorCodeToError(object_error::parse_failed), +                         Obj->getFileName());      StringRef Contents = Data.substr(0, SubSectionSize);      // Add SubSectionSize to the current offset and align that offset to find @@ -980,7 +995,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,      size_t NextOffset = SectionOffset + SubSectionSize;      NextOffset = alignTo(NextOffset, 4);      if (NextOffset > SectionContents.size()) -      return error(object_error::parse_failed); +      return reportError(errorCodeToError(object_error::parse_failed), +                         Obj->getFileName());      Data = SectionContents.drop_front(NextOffset);      // Optionally print the subsection bytes in case our parsing gets confused @@ -1010,17 +1026,21 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,        if (SubSectionSize < 12) {          // There should be at least three words to store two function          // relocations and size of the code. -        error(object_error::parse_failed); +        reportError(errorCodeToError(object_error::parse_failed), +                    Obj->getFileName());          return;        }        StringRef LinkageName; -      error(resolveSymbolName(Obj->getCOFFSection(Section), SectionOffset, -                              LinkageName)); +      if (std::error_code EC = resolveSymbolName(Obj->getCOFFSection(Section), +                                                 SectionOffset, LinkageName)) +        reportError(errorCodeToError(EC), Obj->getFileName()); +        W.printString("LinkageName", LinkageName);        if (FunctionLineTables.count(LinkageName) != 0) {          // Saw debug info for this function already? -        error(object_error::parse_failed); +        reportError(errorCodeToError(object_error::parse_failed), +                    Obj->getFileName());          return;        } @@ -1033,17 +1053,21 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,        BinaryStreamReader SR(Contents, llvm::support::little);        DebugFrameDataSubsectionRef FrameData; -      error(FrameData.initialize(SR)); +      if (Error E = FrameData.initialize(SR)) +        reportError(std::move(E), Obj->getFileName());        StringRef LinkageName; -      error(resolveSymbolName(Obj->getCOFFSection(Section), SectionContents, -                              FrameData.getRelocPtr(), LinkageName)); +      if (std::error_code EC = +              resolveSymbolName(Obj->getCOFFSection(Section), SectionContents, +                                FrameData.getRelocPtr(), LinkageName)) +        reportError(errorCodeToError(EC), Obj->getFileName());        W.printString("LinkageName", LinkageName);        // To find the active frame description, search this array for the        // smallest PC range that includes the current PC.        for (const auto &FD : FrameData) { -        StringRef FrameFunc = error(CVStringTable.getString(FD.FrameFunc)); +        StringRef FrameFunc = unwrapOrError( +            Obj->getFileName(), CVStringTable.getString(FD.FrameFunc));          DictScope S(W, "FrameData");          W.printHex("RvaStart", FD.RvaStart); @@ -1094,7 +1118,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,      BinaryStreamReader Reader(FunctionLineTables[Name], support::little);      DebugLinesSubsectionRef LineInfo; -    error(LineInfo.initialize(Reader)); +    if (Error E = LineInfo.initialize(Reader)) +      reportError(std::move(E), Obj->getFileName());      W.printHex("Flags", LineInfo.header()->Flags);      W.printHex("CodeSize", LineInfo.header()->CodeSize); @@ -1105,7 +1130,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,        uint32_t ColumnIndex = 0;        for (const auto &Line : Entry.LineNumbers) {          if (Line.Offset >= LineInfo.header()->CodeSize) { -          error(object_error::parse_failed); +          reportError(errorCodeToError(object_error::parse_failed), +                      Obj->getFileName());            return;          } @@ -1136,21 +1162,20 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,                                                  StringRef SectionContents) {    ArrayRef<uint8_t> BinaryData(Subsection.bytes_begin(),                                 Subsection.bytes_end()); -  auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj, +  auto CODD = std::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,                                                          SectionContents);    CVSymbolDumper CVSD(W, Types, CodeViewContainer::ObjectFile, std::move(CODD),                        CompilationCPUType, opts::CodeViewSubsectionBytes);    CVSymbolArray Symbols;    BinaryStreamReader Reader(BinaryData, llvm::support::little); -  if (auto EC = Reader.readArray(Symbols, Reader.getLength())) { -    consumeError(std::move(EC)); +  if (Error E = Reader.readArray(Symbols, Reader.getLength())) {      W.flush(); -    error(object_error::parse_failed); +    reportError(std::move(E), Obj->getFileName());    } -  if (auto EC = CVSD.dump(Symbols)) { +  if (Error E = CVSD.dump(Symbols)) {      W.flush(); -    error(std::move(EC)); +    reportError(std::move(E), Obj->getFileName());    }    CompilationCPUType = CVSD.getCompilationCPUType();    W.flush(); @@ -1159,12 +1184,14 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,  void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) {    BinaryStreamRef Stream(Subsection, llvm::support::little);    DebugChecksumsSubsectionRef Checksums; -  error(Checksums.initialize(Stream)); +  if (Error E = Checksums.initialize(Stream)) +    reportError(std::move(E), Obj->getFileName());    for (auto &FC : Checksums) {      DictScope S(W, "FileChecksum"); -    StringRef Filename = error(CVStringTable.getString(FC.FileNameOffset)); +    StringRef Filename = unwrapOrError( +        Obj->getFileName(), CVStringTable.getString(FC.FileNameOffset));      W.printHex("Filename", Filename, FC.FileNameOffset);      W.printHex("ChecksumSize", FC.Checksum.size());      W.printEnum("ChecksumKind", uint8_t(FC.Kind), @@ -1177,7 +1204,8 @@ void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) {  void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {    BinaryStreamReader SR(Subsection, llvm::support::little);    DebugInlineeLinesSubsectionRef Lines; -  error(Lines.initialize(SR)); +  if (Error E = Lines.initialize(SR)) +    reportError(std::move(E), Obj->getFileName());    for (auto &Line : Lines) {      DictScope S(W, "InlineeSourceLine"); @@ -1198,15 +1226,18 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {  StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) {    // The file checksum subsection should precede all references to it.    if (!CVFileChecksumTable.valid() || !CVStringTable.valid()) -    error(object_error::parse_failed); +    reportError(errorCodeToError(object_error::parse_failed), +                Obj->getFileName());    auto Iter = CVFileChecksumTable.getArray().at(FileOffset);    // Check if the file checksum table offset is valid.    if (Iter == CVFileChecksumTable.end()) -    error(object_error::parse_failed); +    reportError(errorCodeToError(object_error::parse_failed), +                Obj->getFileName()); -  return error(CVStringTable.getString(Iter->FileNameOffset)); +  return unwrapOrError(Obj->getFileName(), +                       CVStringTable.getString(Iter->FileNameOffset));  }  void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) { @@ -1219,35 +1250,38 @@ void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder &CVIDs,                                      GlobalTypeTableBuilder &GlobalCVTypes,                                      bool GHash) {    for (const SectionRef &S : Obj->sections()) { -    StringRef SectionName; -    error(S.getName(SectionName)); +    StringRef SectionName = unwrapOrError(Obj->getFileName(), S.getName());      if (SectionName == ".debug$T") { -      StringRef Data = unwrapOrError(S.getContents()); +      StringRef Data = unwrapOrError(Obj->getFileName(), S.getContents());        uint32_t Magic; -      error(consume(Data, Magic)); +      if (Error E = consume(Data, Magic)) +        reportError(std::move(E), Obj->getFileName()); +        if (Magic != 4) -        error(object_error::parse_failed); +        reportError(errorCodeToError(object_error::parse_failed), +                    Obj->getFileName());        CVTypeArray Types;        BinaryStreamReader Reader(Data, llvm::support::little);        if (auto EC = Reader.readArray(Types, Reader.getLength())) {          consumeError(std::move(EC));          W.flush(); -        error(object_error::parse_failed); +        reportError(errorCodeToError(object_error::parse_failed), +                    Obj->getFileName());        }        SmallVector<TypeIndex, 128> SourceToDest;        Optional<uint32_t> PCHSignature;        if (GHash) {          std::vector<GloballyHashedType> Hashes =              GloballyHashedType::hashTypes(Types); -        if (auto EC = +        if (Error E =                  mergeTypeAndIdRecords(GlobalCVIDs, GlobalCVTypes, SourceToDest,                                        Types, Hashes, PCHSignature)) -          return error(std::move(EC)); +          return reportError(std::move(E), Obj->getFileName());        } else { -        if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types, +        if (Error E = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types,                                              PCHSignature)) -          return error(std::move(EC)); +          return reportError(std::move(E), Obj->getFileName());        }      }    } @@ -1258,20 +1292,25 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName,    ListScope D(W, "CodeViewTypes");    W.printNumber("Section", SectionName, Obj->getSectionID(Section)); -  StringRef Data = unwrapOrError(Section.getContents()); +  StringRef Data = unwrapOrError(Obj->getFileName(), Section.getContents());    if (opts::CodeViewSubsectionBytes)      W.printBinaryBlock("Data", Data);    uint32_t Magic; -  error(consume(Data, Magic)); +  if (Error E = consume(Data, Magic)) +    reportError(std::move(E), Obj->getFileName()); +    W.printHex("Magic", Magic);    if (Magic != COFF::DEBUG_SECTION_MAGIC) -    return error(object_error::parse_failed); +    reportError(errorCodeToError(object_error::parse_failed), +                Obj->getFileName());    Types.reset(Data, 100);    TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes); -  error(codeview::visitTypeStream(Types, TDV)); +  if (Error E = codeview::visitTypeStream(Types, TDV)) +    reportError(std::move(E), Obj->getFileName()); +    W.flush();  } @@ -1282,8 +1321,7 @@ void COFFDumper::printSectionHeaders() {      ++SectionNumber;      const coff_section *Section = Obj->getCOFFSection(Sec); -    StringRef Name; -    error(Sec.getName(Name)); +    StringRef Name = unwrapOrError(Obj->getFileName(), Sec.getName());      DictScope D(W, "Section");      W.printNumber("Number", SectionNumber); @@ -1318,7 +1356,7 @@ void COFFDumper::printSectionHeaders() {      if (opts::SectionData &&          !(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) { -      StringRef Data = unwrapOrError(Sec.getContents()); +      StringRef Data = unwrapOrError(Obj->getFileName(), Sec.getContents());        W.printBinaryBlock("SectionData", Data);      }    } @@ -1330,8 +1368,7 @@ void COFFDumper::printRelocations() {    int SectionNumber = 0;    for (const SectionRef &Section : Obj->sections()) {      ++SectionNumber; -    StringRef Name; -    error(Section.getName(Name)); +    StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName());      bool PrintedGroup = false;      for (const RelocationRef &Reloc : Section.relocations()) { @@ -1362,7 +1399,9 @@ void COFFDumper::printRelocation(const SectionRef &Section,    int64_t SymbolIndex = -1;    if (Symbol != Obj->symbol_end()) {      Expected<StringRef> SymbolNameOrErr = Symbol->getName(); -    error(errorToErrorCode(SymbolNameOrErr.takeError())); +    if (!SymbolNameOrErr) +      reportError(SymbolNameOrErr.takeError(), Obj->getFileName()); +      SymbolName = *SymbolNameOrErr;      SymbolIndex = Obj->getSymbolIndex(Obj->getCOFFSymbol(*Symbol));    } @@ -1439,7 +1478,8 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {    for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) {      if (Symbol.isFunctionDefinition()) {        const coff_aux_function_definition *Aux; -      error(getSymbolAuxData(Obj, Symbol, I, Aux)); +      if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) +        reportError(errorCodeToError(EC), Obj->getFileName());        DictScope AS(W, "AuxFunctionDef");        W.printNumber("TagIndex", Aux->TagIndex); @@ -1449,15 +1489,16 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {      } else if (Symbol.isAnyUndefined()) {        const coff_aux_weak_external *Aux; -      error(getSymbolAuxData(Obj, Symbol, I, Aux)); +      if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) +        reportError(errorCodeToError(EC), Obj->getFileName());        Expected<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex); +      if (!Linked) +        reportError(Linked.takeError(), Obj->getFileName()); +        StringRef LinkedName; -      std::error_code EC = errorToErrorCode(Linked.takeError()); -      if (EC || (EC = Obj->getSymbolName(*Linked, LinkedName))) { -        LinkedName = ""; -        error(EC); -      } +      if (std::error_code EC = Obj->getSymbolName(*Linked, LinkedName)) +        reportError(errorCodeToError(EC), Obj->getFileName());        DictScope AS(W, "AuxWeakExternal");        W.printNumber("Linked", LinkedName, Aux->TagIndex); @@ -1466,8 +1507,8 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {      } else if (Symbol.isFileRecord()) {        const char *FileName; -      error(getSymbolAuxData(Obj, Symbol, I, FileName)); - +      if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, FileName)) +        reportError(errorCodeToError(EC), Obj->getFileName());        DictScope AS(W, "AuxFileRecord");        StringRef Name(FileName, Symbol.getNumberOfAuxSymbols() * @@ -1476,7 +1517,8 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {        break;      } else if (Symbol.isSectionDefinition()) {        const coff_aux_section_definition *Aux; -      error(getSymbolAuxData(Obj, Symbol, I, Aux)); +      if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) +        reportError(errorCodeToError(EC), Obj->getFileName());        int32_t AuxNumber = Aux->getNumber(Symbol.isBigObj()); @@ -1493,26 +1535,27 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {          const coff_section *Assoc;          StringRef AssocName = "";          if (std::error_code EC = Obj->getSection(AuxNumber, Assoc)) -          error(EC); +          reportError(errorCodeToError(EC), Obj->getFileName());          Expected<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc);          if (!Res) -          error(Res.takeError()); +          reportError(Res.takeError(), Obj->getFileName());          AssocName = *Res;          W.printNumber("AssocSection", AssocName, AuxNumber);        }      } else if (Symbol.isCLRToken()) {        const coff_aux_clr_token *Aux; -      error(getSymbolAuxData(Obj, Symbol, I, Aux)); +      if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) +        reportError(errorCodeToError(EC), Obj->getFileName());        Expected<COFFSymbolRef> ReferredSym =            Obj->getSymbol(Aux->SymbolTableIndex); +      if (!ReferredSym) +        reportError(ReferredSym.takeError(), Obj->getFileName()); +        StringRef ReferredName; -      std::error_code EC = errorToErrorCode(ReferredSym.takeError()); -      if (EC || (EC = Obj->getSymbolName(*ReferredSym, ReferredName))) { -        ReferredName = ""; -        error(EC); -      } +      if (std::error_code EC = Obj->getSymbolName(*ReferredSym, ReferredName)) +        reportError(errorCodeToError(EC), Obj->getFileName());        DictScope AS(W, "AuxCLRToken");        W.printNumber("AuxType", Aux->AuxType); @@ -1578,9 +1621,11 @@ void COFFDumper::printImportedSymbols(      iterator_range<imported_symbol_iterator> Range) {    for (const ImportedSymbolRef &I : Range) {      StringRef Sym; -    error(I.getSymbolName(Sym)); +    if (std::error_code EC = I.getSymbolName(Sym)) +      reportError(errorCodeToError(EC), Obj->getFileName());      uint16_t Ordinal; -    error(I.getOrdinal(Ordinal)); +    if (std::error_code EC = I.getOrdinal(Ordinal)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printNumber("Symbol", Sym, Ordinal);    }  } @@ -1592,12 +1637,17 @@ void COFFDumper::printDelayImportedSymbols(    for (const ImportedSymbolRef &S : Range) {      DictScope Import(W, "Import");      StringRef Sym; -    error(S.getSymbolName(Sym)); +    if (std::error_code EC = S.getSymbolName(Sym)) +      reportError(errorCodeToError(EC), Obj->getFileName()); +      uint16_t Ordinal; -    error(S.getOrdinal(Ordinal)); +    if (std::error_code EC = S.getOrdinal(Ordinal)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printNumber("Symbol", Sym, Ordinal); +      uint64_t Addr; -    error(I.getImportAddress(Index++, Addr)); +    if (std::error_code EC = I.getImportAddress(Index++, Addr)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printHex("Address", Addr);    }  } @@ -1607,13 +1657,16 @@ void COFFDumper::printCOFFImports() {    for (const ImportDirectoryEntryRef &I : Obj->import_directories()) {      DictScope Import(W, "Import");      StringRef Name; -    error(I.getName(Name)); +    if (std::error_code EC = I.getName(Name)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printString("Name", Name);      uint32_t ILTAddr; -    error(I.getImportLookupTableRVA(ILTAddr)); +    if (std::error_code EC = I.getImportLookupTableRVA(ILTAddr)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printHex("ImportLookupTableRVA", ILTAddr);      uint32_t IATAddr; -    error(I.getImportAddressTableRVA(IATAddr)); +    if (std::error_code EC = I.getImportAddressTableRVA(IATAddr)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printHex("ImportAddressTableRVA", IATAddr);      // The import lookup table can be missing with certain older linkers, so      // fall back to the import address table in that case. @@ -1627,10 +1680,12 @@ void COFFDumper::printCOFFImports() {    for (const DelayImportDirectoryEntryRef &I : Obj->delay_import_directories()) {      DictScope Import(W, "DelayImport");      StringRef Name; -    error(I.getName(Name)); +    if (std::error_code EC = I.getName(Name)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printString("Name", Name);      const delay_import_directory_table_entry *Table; -    error(I.getDelayImportTable(Table)); +    if (std::error_code EC = I.getDelayImportTable(Table)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printHex("Attributes", Table->Attributes);      W.printHex("ModuleHandle", Table->ModuleHandle);      W.printHex("ImportAddressTable", Table->DelayImportAddressTable); @@ -1648,9 +1703,12 @@ void COFFDumper::printCOFFExports() {      StringRef Name;      uint32_t Ordinal, RVA; -    error(E.getSymbolName(Name)); -    error(E.getOrdinal(Ordinal)); -    error(E.getExportRVA(RVA)); +    if (std::error_code EC = E.getSymbolName(Name)) +      reportError(errorCodeToError(EC), Obj->getFileName()); +    if (std::error_code EC = E.getOrdinal(Ordinal)) +      reportError(errorCodeToError(EC), Obj->getFileName()); +    if (std::error_code EC = E.getExportRVA(RVA)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printNumber("Ordinal", Ordinal);      W.printString("Name", Name); @@ -1660,13 +1718,12 @@ void COFFDumper::printCOFFExports() {  void COFFDumper::printCOFFDirectives() {    for (const SectionRef &Section : Obj->sections()) { -    StringRef Name; - -    error(Section.getName(Name)); +    StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName());      if (Name != ".drectve")        continue; -    StringRef Contents = unwrapOrError(Section.getContents()); +    StringRef Contents = +        unwrapOrError(Obj->getFileName(), Section.getContents());      W.printString("Directive(s)", Contents);    }  } @@ -1689,8 +1746,10 @@ void COFFDumper::printCOFFBaseReloc() {    for (const BaseRelocRef &I : Obj->base_relocs()) {      uint8_t Type;      uint32_t RVA; -    error(I.getRVA(RVA)); -    error(I.getType(Type)); +    if (std::error_code EC = I.getRVA(RVA)) +      reportError(errorCodeToError(EC), Obj->getFileName()); +    if (std::error_code EC = I.getType(Type)) +      reportError(errorCodeToError(EC), Obj->getFileName());      DictScope Import(W, "Entry");      W.printString("Type", getBaseRelocTypeName(Type));      W.printHex("Address", RVA); @@ -1700,16 +1759,18 @@ void COFFDumper::printCOFFBaseReloc() {  void COFFDumper::printCOFFResources() {    ListScope ResourcesD(W, "Resources");    for (const SectionRef &S : Obj->sections()) { -    StringRef Name; -    error(S.getName(Name)); +    StringRef Name = unwrapOrError(Obj->getFileName(), S.getName());      if (!Name.startswith(".rsrc"))        continue; -    StringRef Ref = unwrapOrError(S.getContents()); +    StringRef Ref = unwrapOrError(Obj->getFileName(), S.getContents());      if ((Name == ".rsrc") || (Name == ".rsrc$01")) { -      ResourceSectionRef RSF(Ref); -      auto &BaseTable = unwrapOrError(RSF.getBaseTable()); +      ResourceSectionRef RSF; +      Error E = RSF.load(Obj, S); +      if (E) +        reportError(std::move(E), Obj->getFileName()); +      auto &BaseTable = unwrapOrError(Obj->getFileName(), RSF.getBaseTable());        W.printNumber("Total Number of Resources",                      countTotalTableEntries(RSF, BaseTable, "Type"));        W.printHex("Base Table Address", @@ -1729,14 +1790,15 @@ COFFDumper::countTotalTableEntries(ResourceSectionRef RSF,    uint32_t TotalEntries = 0;    for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;         i++) { -    auto Entry = unwrapOrError(getResourceDirectoryTableEntry(Table, i)); +    auto Entry = unwrapOrError(Obj->getFileName(), RSF.getTableEntry(Table, i));      if (Entry.Offset.isSubDir()) {        StringRef NextLevel;        if (Level == "Name")          NextLevel = "Language";        else          NextLevel = "Name"; -      auto &NextTable = unwrapOrError(RSF.getEntrySubDir(Entry)); +      auto &NextTable = +          unwrapOrError(Obj->getFileName(), RSF.getEntrySubDir(Entry));        TotalEntries += countTotalTableEntries(RSF, NextTable, NextLevel);      } else {        TotalEntries += 1; @@ -1755,13 +1817,13 @@ void COFFDumper::printResourceDirectoryTable(    // Iterate through level in resource directory tree.    for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;         i++) { -    auto Entry = unwrapOrError(getResourceDirectoryTableEntry(Table, i)); +    auto Entry = unwrapOrError(Obj->getFileName(), RSF.getTableEntry(Table, i));      StringRef Name;      SmallString<20> IDStr;      raw_svector_ostream OS(IDStr);      if (i < Table.NumberOfNameEntries) {        ArrayRef<UTF16> RawEntryNameString = -          unwrapOrError(RSF.getEntryNameString(Entry)); +          unwrapOrError(Obj->getFileName(), RSF.getEntryNameString(Entry));        std::vector<UTF16> EndianCorrectedNameString;        if (llvm::sys::IsBigEndianHost) {          EndianCorrectedNameString.resize(RawEntryNameString.size() + 1); @@ -1772,14 +1834,14 @@ void COFFDumper::printResourceDirectoryTable(        }        std::string EntryNameString;        if (!llvm::convertUTF16ToUTF8String(RawEntryNameString, EntryNameString)) -        error(object_error::parse_failed); +        reportError(errorCodeToError(object_error::parse_failed), +                    Obj->getFileName());        OS << ": ";        OS << EntryNameString;      } else {        if (Level == "Type") {          OS << ": ";          printResourceTypeName(Entry.Identifier.ID, OS); -        IDStr = IDStr.slice(0, IDStr.find_first_of(")", 0) + 1);        } else {          OS << ": (ID " << Entry.Identifier.ID << ")";        } @@ -1793,7 +1855,8 @@ void COFFDumper::printResourceDirectoryTable(          NextLevel = "Language";        else          NextLevel = "Name"; -      auto &NextTable = unwrapOrError(RSF.getEntrySubDir(Entry)); +      auto &NextTable = +          unwrapOrError(Obj->getFileName(), RSF.getEntrySubDir(Entry));        printResourceDirectoryTable(RSF, NextTable, NextLevel);      } else {        W.printHex("Entry Offset", Entry.Offset.value()); @@ -1804,24 +1867,29 @@ void COFFDumper::printResourceDirectoryTable(        W.printNumber("Major Version", Table.MajorVersion);        W.printNumber("Minor Version", Table.MinorVersion);        W.printNumber("Characteristics", Table.Characteristics); +      ListScope DataScope(W, "Data"); +      auto &DataEntry = +          unwrapOrError(Obj->getFileName(), RSF.getEntryData(Entry)); +      W.printHex("DataRVA", DataEntry.DataRVA); +      W.printNumber("DataSize", DataEntry.DataSize); +      W.printNumber("Codepage", DataEntry.Codepage); +      W.printNumber("Reserved", DataEntry.Reserved); +      StringRef Contents = +          unwrapOrError(Obj->getFileName(), RSF.getContents(DataEntry)); +      W.printBinaryBlock("Data", Contents);      }    }  } -ErrorOr<const coff_resource_dir_entry &> -COFFDumper::getResourceDirectoryTableEntry(const coff_resource_dir_table &Table, -                                           uint32_t Index) { -  if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries)) -    return object_error::parse_failed; -  auto TablePtr = reinterpret_cast<const coff_resource_dir_entry *>(&Table + 1); -  return TablePtr[Index]; -} -  void COFFDumper::printStackMap() const {    object::SectionRef StackMapSection;    for (auto Sec : Obj->sections()) {      StringRef Name; -    Sec.getName(Name); +    if (Expected<StringRef> NameOrErr = Sec.getName()) +      Name = *NameOrErr; +    else +      consumeError(NameOrErr.takeError()); +      if (Name == ".llvm_stackmaps") {        StackMapSection = Sec;        break; @@ -1831,7 +1899,8 @@ void COFFDumper::printStackMap() const {    if (StackMapSection == object::SectionRef())      return; -  StringRef StackMapContents = unwrapOrError(StackMapSection.getContents()); +  StringRef StackMapContents = +      unwrapOrError(Obj->getFileName(), StackMapSection.getContents());    ArrayRef<uint8_t> StackMapContentsArray =        arrayRefFromStringRef(StackMapContents); @@ -1847,7 +1916,11 @@ void COFFDumper::printAddrsig() {    object::SectionRef AddrsigSection;    for (auto Sec : Obj->sections()) {      StringRef Name; -    Sec.getName(Name); +    if (Expected<StringRef> NameOrErr = Sec.getName()) +      Name = *NameOrErr; +    else +      consumeError(NameOrErr.takeError()); +      if (Name == ".llvm_addrsig") {        AddrsigSection = Sec;        break; @@ -1857,7 +1930,8 @@ void COFFDumper::printAddrsig() {    if (AddrsigSection == object::SectionRef())      return; -  StringRef AddrsigContents = unwrapOrError(AddrsigSection.getContents()); +  StringRef AddrsigContents = +      unwrapOrError(Obj->getFileName(), AddrsigSection.getContents());    ArrayRef<uint8_t> AddrsigContentsArray(AddrsigContents.bytes_begin(),                                           AddrsigContents.size()); @@ -1869,15 +1943,15 @@ void COFFDumper::printAddrsig() {      const char *Err;      uint64_t SymIndex = decodeULEB128(Cur, &Size, End, &Err);      if (Err) -      reportError(Err); +      reportError(createError(Err), Obj->getFileName());      Expected<COFFSymbolRef> Sym = Obj->getSymbol(SymIndex); +    if (!Sym) +      reportError(Sym.takeError(), Obj->getFileName()); +      StringRef SymName; -    std::error_code EC = errorToErrorCode(Sym.takeError()); -    if (EC || (EC = Obj->getSymbolName(*Sym, SymName))) { -      SymName = ""; -      error(EC); -    } +    if (std::error_code EC = Obj->getSymbolName(*Sym, SymName)) +      reportError(errorCodeToError(EC), Obj->getFileName());      W.printNumber("Sym", SymName, SymIndex);      Cur += Size; @@ -1891,7 +1965,8 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,    {      ListScope S(Writer, "MergedTypeStream");      TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes); -    error(codeview::visitTypeStream(TpiTypes, TDV)); +    if (Error Err = codeview::visitTypeStream(TpiTypes, TDV)) +      reportError(std::move(Err), "<?>");      Writer.flush();    } @@ -1902,7 +1977,8 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,      ListScope S(Writer, "MergedIDStream");      TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);      TDV.setIpiTypes(IpiTypes); -    error(codeview::visitTypeStream(IpiTypes, TDV)); +    if (Error Err = codeview::visitTypeStream(IpiTypes, TDV)) +      reportError(std::move(Err), "<?>");      Writer.flush();    }  } diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h b/contrib/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h index 7055510ef2f2..0a365d4fe72a 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h @@ -44,12 +44,12 @@ public:    void printUnwindInformation() const;  }; -template <class ELFO> -static const typename ELFO::Elf_Shdr *findSectionByAddress(const ELFO *Obj, -                                                           uint64_t Addr) { -  auto Sections = Obj->sections(); +template <class ELFT> +static const typename object::ELFObjectFile<ELFT>::Elf_Shdr * +findSectionByAddress(const object::ELFObjectFile<ELFT> *ObjF, uint64_t Addr) { +  auto Sections = ObjF->getELFFile()->sections();    if (Error E = Sections.takeError()) -    reportError(toString(std::move(E))); +    reportError(std::move(E), ObjF->getFileName());    for (const auto &Shdr : *Sections)      if (Shdr.sh_addr == Addr) @@ -64,13 +64,15 @@ void PrinterContext<ELFT>::printUnwindInformation() const {    auto PHs = Obj->program_headers();    if (Error E = PHs.takeError()) -    reportError(toString(std::move(E))); +    reportError(std::move(E), ObjF->getFileName());    for (const auto &Phdr : *PHs) {      if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {        EHFramePhdr = &Phdr;        if (Phdr.p_memsz != Phdr.p_filesz) -        reportError("p_memsz does not match p_filesz for GNU_EH_FRAME"); +        reportError(object::createError( +                        "p_memsz does not match p_filesz for GNU_EH_FRAME"), +                    ObjF->getFileName());        break;      }    } @@ -81,12 +83,12 @@ void PrinterContext<ELFT>::printUnwindInformation() const {    auto Sections = Obj->sections();    if (Error E = Sections.takeError()) -    reportError(toString(std::move(E))); +    reportError(std::move(E), ObjF->getFileName());    for (const auto &Shdr : *Sections) {      auto SectionName = Obj->getSectionName(&Shdr);      if (Error E = SectionName.takeError()) -      reportError(toString(std::move(E))); +      reportError(std::move(E), ObjF->getFileName());      if (*SectionName == ".eh_frame")        printEHFrame(&Shdr); @@ -97,49 +99,52 @@ template <typename ELFT>  void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset,                                             uint64_t EHFrameHdrAddress,                                             uint64_t EHFrameHdrSize) const { -  ListScope L(W, "EH_FRAME Header"); +  DictScope L(W, "EHFrameHeader");    W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);    W.startLine() << format("Offset: 0x%" PRIx64 "\n", EHFrameHdrOffset);    W.startLine() << format("Size: 0x%" PRIx64 "\n", EHFrameHdrSize);    const object::ELFFile<ELFT> *Obj = ObjF->getELFFile(); -  const auto *EHFrameHdrShdr = findSectionByAddress(Obj, EHFrameHdrAddress); +  const auto *EHFrameHdrShdr = findSectionByAddress(ObjF, EHFrameHdrAddress);    if (EHFrameHdrShdr) {      auto SectionName = Obj->getSectionName(EHFrameHdrShdr);      if (Error E = SectionName.takeError()) -      reportError(toString(std::move(E))); +      reportError(std::move(E), ObjF->getFileName());      W.printString("Corresponding Section", *SectionName);    } -  DataExtractor DE( -      StringRef(reinterpret_cast<const char *>(Obj->base()) + EHFrameHdrOffset, -                EHFrameHdrSize), -      ELFT::TargetEndianness == support::endianness::little, -      ELFT::Is64Bits ? 8 : 4); +  DataExtractor DE(makeArrayRef(Obj->base() + EHFrameHdrOffset, EHFrameHdrSize), +                   ELFT::TargetEndianness == support::endianness::little, +                   ELFT::Is64Bits ? 8 : 4);    DictScope D(W, "Header"); -  uint32_t Offset = 0; +  uint64_t Offset = 0;    auto Version = DE.getU8(&Offset);    W.printNumber("version", Version);    if (Version != 1) -    reportError("only version 1 of .eh_frame_hdr is supported"); +    reportError( +        object::createError("only version 1 of .eh_frame_hdr is supported"), +        ObjF->getFileName());    uint64_t EHFramePtrEnc = DE.getU8(&Offset);    W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc);    if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4)) -    reportError("unexpected encoding eh_frame_ptr_enc"); +    reportError(object::createError("unexpected encoding eh_frame_ptr_enc"), +                ObjF->getFileName());    uint64_t FDECountEnc = DE.getU8(&Offset);    W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc);    if (FDECountEnc != dwarf::DW_EH_PE_udata4) -    reportError("unexpected encoding fde_count_enc"); +    reportError(object::createError("unexpected encoding fde_count_enc"), +                ObjF->getFileName());    uint64_t TableEnc = DE.getU8(&Offset);    W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);    if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4)) -    reportError("unexpected encoding table_enc"); +    reportError(object::createError("unexpected encoding table_enc"), +                ObjF->getFileName());    auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;    W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr); @@ -158,7 +163,8 @@ void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset,      W.startLine() << format("address: 0x%" PRIx64 "\n", Address);      if (InitialPC < PrevPC) -      reportError("initial_location is out of order"); +      reportError(object::createError("initial_location is out of order"), +                  ObjF->getFileName());      PrevPC = InitialPC;      ++NumEntries; @@ -178,7 +184,7 @@ void PrinterContext<ELFT>::printEHFrame(    const object::ELFFile<ELFT> *Obj = ObjF->getELFFile();    auto Result = Obj->getSectionContents(EHFrameShdr);    if (Error E = Result.takeError()) -    reportError(toString(std::move(E))); +    reportError(std::move(E), ObjF->getFileName());    auto Contents = Result.get();    DWARFDataExtractor DE( diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp index 4e1cb7d544e7..8ffb68283405 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -20,6 +20,7 @@  #include "llvm/ADT/ArrayRef.h"  #include "llvm/ADT/DenseMap.h"  #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/MapVector.h"  #include "llvm/ADT/Optional.h"  #include "llvm/ADT/PointerIntPair.h"  #include "llvm/ADT/STLExtras.h" @@ -36,6 +37,7 @@  #include "llvm/Object/ELFTypes.h"  #include "llvm/Object/Error.h"  #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/RelocationResolver.h"  #include "llvm/Object/StackMapParser.h"  #include "llvm/Support/AMDGPUMetadata.h"  #include "llvm/Support/ARMAttributeParser.h" @@ -61,6 +63,7 @@  #include <memory>  #include <string>  #include <system_error> +#include <unordered_set>  #include <vector>  using namespace llvm; @@ -119,9 +122,9 @@ template <class ELFT> class DumpStyle;  /// the size, entity size and virtual address are different entries in arbitrary  /// order (DT_REL, DT_RELSZ, DT_RELENT for example).  struct DynRegionInfo { -  DynRegionInfo() = default; -  DynRegionInfo(const void *A, uint64_t S, uint64_t ES) -      : Addr(A), Size(S), EntSize(ES) {} +  DynRegionInfo(StringRef ObjName) : FileName(ObjName) {} +  DynRegionInfo(const void *A, uint64_t S, uint64_t ES, StringRef ObjName) +      : Addr(A), Size(S), EntSize(ES), FileName(ObjName) {}    /// Address in current address space.    const void *Addr = nullptr; @@ -130,20 +133,59 @@ struct DynRegionInfo {    /// Size of each entity in the region.    uint64_t EntSize = 0; +  /// Name of the file. Used for error reporting. +  StringRef FileName; +    template <typename Type> ArrayRef<Type> getAsArrayRef() const {      const Type *Start = reinterpret_cast<const Type *>(Addr);      if (!Start)        return {Start, Start};      if (EntSize != sizeof(Type) || Size % EntSize) {        // TODO: Add a section index to this warning. -      reportWarning("invalid section size (" + Twine(Size) + -                    ") or entity size (" + Twine(EntSize) + ")"); +      reportWarning(createError("invalid section size (" + Twine(Size) + +                                ") or entity size (" + Twine(EntSize) + ")"), +                    FileName);        return {Start, Start};      }      return {Start, Start + (Size / EntSize)};    }  }; +namespace { +struct VerdAux { +  unsigned Offset; +  std::string Name; +}; + +struct VerDef { +  unsigned Offset; +  unsigned Version; +  unsigned Flags; +  unsigned Ndx; +  unsigned Cnt; +  unsigned Hash; +  std::string Name; +  std::vector<VerdAux> AuxV; +}; + +struct VernAux { +  unsigned Hash; +  unsigned Flags; +  unsigned Other; +  unsigned Offset; +  std::string Name; +}; + +struct VerNeed { +  unsigned Version; +  unsigned Cnt; +  unsigned Offset; +  std::string File; +  std::vector<VernAux> AuxV; +}; + +} // namespace +  template <typename ELFT> class ELFDumper : public ObjDumper {  public:    ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ScopedPrinter &Writer); @@ -151,6 +193,7 @@ public:    void printFileHeaders() override;    void printSectionHeaders() override;    void printRelocations() override; +  void printDependentLibs() override;    void printDynamicRelocations() override;    void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override;    void printHashSymbols() override; @@ -166,11 +209,7 @@ public:    void printVersionInfo() override;    void printGroupSections() override; -  void printAttributes() override; -  void printMipsPLTGOT() override; -  void printMipsABIFlags() override; -  void printMipsReginfo() override; -  void printMipsOptions() override; +  void printArchSpecificInfo() override;    void printStackMap() const override; @@ -182,6 +221,7 @@ public:    void printNotes() override;    void printELFLinkerOptions() override; +  void printStackSizes() override;    const object::ELFObjectFile<ELFT> *getElfObject() const { return ObjF; }; @@ -195,28 +235,33 @@ private:      if (DRI.Addr < Obj->base() ||          reinterpret_cast<const uint8_t *>(DRI.Addr) + DRI.Size >              Obj->base() + Obj->getBufSize()) -      error(llvm::object::object_error::parse_failed); +      reportError(errorCodeToError(llvm::object::object_error::parse_failed), +                  ObjF->getFileName());      return DRI;    }    DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) { -    return checkDRI( -        {ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, EntSize}); +    return checkDRI({ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, +                     EntSize, ObjF->getFileName()});    }    DynRegionInfo createDRIFrom(const Elf_Shdr *S) { -    return checkDRI( -        {ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize}); +    return checkDRI({ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, +                     S->sh_entsize, ObjF->getFileName()});    } +  void printAttributes(); +  void printMipsReginfo(); +  void printMipsOptions(); + +  std::pair<const Elf_Phdr *, const Elf_Shdr *> +  findDynamic(const ELFFile<ELFT> *Obj);    void loadDynamicTable(const ELFFile<ELFT> *Obj); -  void parseDynamicTable(); +  void parseDynamicTable(const ELFFile<ELFT> *Obj); -  StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, -                             bool &IsDefault) const; -  void LoadVersionMap() const; -  void LoadVersionNeeds(const Elf_Shdr *ec) const; -  void LoadVersionDefs(const Elf_Shdr *sec) const; +  Expected<StringRef> getSymbolVersion(const Elf_Sym *symb, +                                       bool &IsDefault) const; +  Error LoadVersionMap() const;    const object::ELFObjectFile<ELFT> *ObjF;    DynRegionInfo DynRelRegion; @@ -226,7 +271,7 @@ private:    DynRegionInfo DynSymRegion;    DynRegionInfo DynamicTable;    StringRef DynamicStringTable; -  StringRef SOName = "<Not found>"; +  std::string SOName = "<Not found>";    const Elf_Hash *HashTable = nullptr;    const Elf_GnuHash *GnuHashTable = nullptr;    const Elf_Shdr *DotSymtabSec = nullptr; @@ -239,29 +284,11 @@ private:    const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r    const Elf_Shdr *SymbolVersionDefSection = nullptr; // .gnu.version_d -  // Records for each version index the corresponding Verdef or Vernaux entry. -  // This is filled the first time LoadVersionMap() is called. -  class VersionMapEntry : public PointerIntPair<const void *, 1> { -  public: -    // If the integer is 0, this is an Elf_Verdef*. -    // If the integer is 1, this is an Elf_Vernaux*. -    VersionMapEntry() : PointerIntPair<const void *, 1>(nullptr, 0) {} -    VersionMapEntry(const Elf_Verdef *verdef) -        : PointerIntPair<const void *, 1>(verdef, 0) {} -    VersionMapEntry(const Elf_Vernaux *vernaux) -        : PointerIntPair<const void *, 1>(vernaux, 1) {} - -    bool isNull() const { return getPointer() == nullptr; } -    bool isVerdef() const { return !isNull() && getInt() == 0; } -    bool isVernaux() const { return !isNull() && getInt() == 1; } -    const Elf_Verdef *getVerdef() const { -      return isVerdef() ? (const Elf_Verdef *)getPointer() : nullptr; -    } -    const Elf_Vernaux *getVernaux() const { -      return isVernaux() ? (const Elf_Vernaux *)getPointer() : nullptr; -    } +  struct VersionEntry { +    std::string Name; +    bool IsVerDef;    }; -  mutable SmallVector<VersionMapEntry, 16> VersionMap; +  mutable SmallVector<Optional<VersionEntry>, 16> VersionMap;  public:    Elf_Dyn_Range dynamic_table() const { @@ -288,13 +315,14 @@ public:    Elf_Relr_Range dyn_relrs() const;    std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,                                  bool IsDynamic) const; -  void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym, -                           StringRef &SectionName, -                           unsigned &SectionIndex) const; -  std::string getStaticSymbolName(uint32_t Index) const; -  StringRef getSymbolVersionByIndex(StringRef StrTab, -                                    uint32_t VersionSymbolIndex, -                                    bool &IsDefault) const; +  Expected<unsigned> getSymbolSectionIndex(const Elf_Sym *Symbol, +                                           const Elf_Sym *FirstSym) const; +  Expected<StringRef> getSymbolSectionName(const Elf_Sym *Symbol, +                                           unsigned SectionIndex) const; +  Expected<std::string> getStaticSymbolName(uint32_t Index) const; +  std::string getDynamicString(uint64_t Value) const; +  Expected<StringRef> getSymbolVersionByIndex(uint32_t VersionSymbolIndex, +                                              bool &IsDefault) const;    void printSymbolsHelper(bool IsDynamic) const;    void printDynamicEntry(raw_ostream &OS, uint64_t Type, uint64_t Value) const; @@ -311,9 +339,307 @@ public:    const DynRegionInfo &getDynamicTableRegion() const { return DynamicTable; }    const Elf_Hash *getHashTable() const { return HashTable; }    const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; } + +  Expected<ArrayRef<Elf_Versym>> getVersionTable(const Elf_Shdr *Sec, +                                                 ArrayRef<Elf_Sym> *SymTab, +                                                 StringRef *StrTab) const; +  Expected<std::vector<VerDef>> +  getVersionDefinitions(const Elf_Shdr *Sec) const; +  Expected<std::vector<VerNeed>> +  getVersionDependencies(const Elf_Shdr *Sec) const;  };  template <class ELFT> +static Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> *Obj, +                                           const typename ELFT::Shdr *Sec, +                                           unsigned SecNdx) { +  Expected<const typename ELFT::Shdr *> StrTabSecOrErr = +      Obj->getSection(Sec->sh_link); +  if (!StrTabSecOrErr) +    return createError("invalid section linked to " + +                       object::getELFSectionTypeName( +                           Obj->getHeader()->e_machine, Sec->sh_type) + +                       " section with index " + Twine(SecNdx) + ": " + +                       toString(StrTabSecOrErr.takeError())); + +  Expected<StringRef> StrTabOrErr = Obj->getStringTable(*StrTabSecOrErr); +  if (!StrTabOrErr) +    return createError("invalid string table linked to " + +                       object::getELFSectionTypeName( +                           Obj->getHeader()->e_machine, Sec->sh_type) + +                       " section with index " + Twine(SecNdx) + ": " + +                       toString(StrTabOrErr.takeError())); +  return *StrTabOrErr; +} + +// Returns the linked symbol table and associated string table for a given section. +template <class ELFT> +static Expected<std::pair<typename ELFT::SymRange, StringRef>> +getLinkAsSymtab(const ELFFile<ELFT> *Obj, const typename ELFT::Shdr *Sec, +                   unsigned SecNdx, unsigned ExpectedType) { +  Expected<const typename ELFT::Shdr *> SymtabOrErr = +      Obj->getSection(Sec->sh_link); +  if (!SymtabOrErr) +    return createError("invalid section linked to " + +                       object::getELFSectionTypeName( +                           Obj->getHeader()->e_machine, Sec->sh_type) + +                       " section with index " + Twine(SecNdx) + ": " + +                       toString(SymtabOrErr.takeError())); + +  if ((*SymtabOrErr)->sh_type != ExpectedType) +    return createError( +        "invalid section linked to " + +        object::getELFSectionTypeName(Obj->getHeader()->e_machine, +                                      Sec->sh_type) + +        " section with index " + Twine(SecNdx) + ": expected " + +        object::getELFSectionTypeName(Obj->getHeader()->e_machine, +                                      ExpectedType) + +        ", but got " + +        object::getELFSectionTypeName(Obj->getHeader()->e_machine, +                                      (*SymtabOrErr)->sh_type)); + +  Expected<StringRef> StrTabOrErr = +      getLinkAsStrtab(Obj, *SymtabOrErr, Sec->sh_link); +  if (!StrTabOrErr) +    return createError( +        "can't get a string table for the symbol table linked to " + +        object::getELFSectionTypeName(Obj->getHeader()->e_machine, +                                      Sec->sh_type) + +        " section with index " + Twine(SecNdx) + ": " + +        toString(StrTabOrErr.takeError())); + +  Expected<typename ELFT::SymRange> SymsOrErr = Obj->symbols(*SymtabOrErr); +  if (!SymsOrErr) +    return createError( +        "unable to read symbols from the symbol table with index " + +        Twine(Sec->sh_link) + ": " + toString(SymsOrErr.takeError())); + +  return std::make_pair(*SymsOrErr, *StrTabOrErr); +} + +template <class ELFT> +Expected<ArrayRef<typename ELFT::Versym>> +ELFDumper<ELFT>::getVersionTable(const Elf_Shdr *Sec, ArrayRef<Elf_Sym> *SymTab, +                                 StringRef *StrTab) const { +  assert((!SymTab && !StrTab) || (SymTab && StrTab)); +  const ELFFile<ELFT> *Obj = ObjF->getELFFile(); +  unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); + +  if (uintptr_t(Obj->base() + Sec->sh_offset) % sizeof(uint16_t) != 0) +    return createError("the SHT_GNU_versym section with index " + +                       Twine(SecNdx) + " is misaligned"); + +  Expected<ArrayRef<Elf_Versym>> VersionsOrErr = +      Obj->template getSectionContentsAsArray<Elf_Versym>(Sec); +  if (!VersionsOrErr) +    return createError( +        "cannot read content of SHT_GNU_versym section with index " + +        Twine(SecNdx) + ": " + toString(VersionsOrErr.takeError())); + +  Expected<std::pair<ArrayRef<Elf_Sym>, StringRef>> SymTabOrErr = +      getLinkAsSymtab(Obj, Sec, SecNdx, SHT_DYNSYM); +  if (!SymTabOrErr) { +    ELFDumperStyle->reportUniqueWarning(SymTabOrErr.takeError()); +    return *VersionsOrErr; +  } + +  if (SymTabOrErr->first.size() != VersionsOrErr->size()) +    ELFDumperStyle->reportUniqueWarning( +        createError("SHT_GNU_versym section with index " + Twine(SecNdx) + +                    ": the number of entries (" + Twine(VersionsOrErr->size()) + +                    ") does not match the number of symbols (" + +                    Twine(SymTabOrErr->first.size()) + +                    ") in the symbol table with index " + Twine(Sec->sh_link))); + +  if (SymTab) +    std::tie(*SymTab, *StrTab) = *SymTabOrErr; +  return *VersionsOrErr; +} + +template <class ELFT> +Expected<std::vector<VerDef>> +ELFDumper<ELFT>::getVersionDefinitions(const Elf_Shdr *Sec) const { +  const ELFFile<ELFT> *Obj = ObjF->getELFFile(); +  unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); + +  Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx); +  if (!StrTabOrErr) +    return StrTabOrErr.takeError(); + +  Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(Sec); +  if (!ContentsOrErr) +    return createError( +        "cannot read content of SHT_GNU_verdef section with index " + +        Twine(SecNdx) + ": " + toString(ContentsOrErr.takeError())); + +  const uint8_t *Start = ContentsOrErr->data(); +  const uint8_t *End = Start + ContentsOrErr->size(); + +  auto ExtractNextAux = [&](const uint8_t *&VerdauxBuf, +                            unsigned VerDefNdx) -> Expected<VerdAux> { +    if (VerdauxBuf + sizeof(Elf_Verdaux) > End) +      return createError("invalid SHT_GNU_verdef section with index " + +                         Twine(SecNdx) + ": version definition " + +                         Twine(VerDefNdx) + +                         " refers to an auxiliary entry that goes past the end " +                         "of the section"); + +    auto *Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); +    VerdauxBuf += Verdaux->vda_next; + +    VerdAux Aux; +    Aux.Offset = VerdauxBuf - Start; +    if (Verdaux->vda_name <= StrTabOrErr->size()) +      Aux.Name = StrTabOrErr->drop_front(Verdaux->vda_name); +    else +      Aux.Name = "<invalid vda_name: " + to_string(Verdaux->vda_name) + ">"; +    return Aux; +  }; + +  std::vector<VerDef> Ret; +  const uint8_t *VerdefBuf = Start; +  for (unsigned I = 1; I <= /*VerDefsNum=*/Sec->sh_info; ++I) { +    if (VerdefBuf + sizeof(Elf_Verdef) > End) +      return createError("invalid SHT_GNU_verdef section with index " + +                         Twine(SecNdx) + ": version definition " + Twine(I) + +                         " goes past the end of the section"); + +    if (uintptr_t(VerdefBuf) % sizeof(uint32_t) != 0) +      return createError( +          "invalid SHT_GNU_verdef section with index " + Twine(SecNdx) + +          ": found a misaligned version definition entry at offset 0x" + +          Twine::utohexstr(VerdefBuf - Start)); + +    unsigned Version = *reinterpret_cast<const Elf_Half *>(VerdefBuf); +    if (Version != 1) +      return createError("unable to dump SHT_GNU_verdef section with index " + +                         Twine(SecNdx) + ": version " + Twine(Version) + +                         " is not yet supported"); + +    const Elf_Verdef *D = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); +    VerDef &VD = *Ret.emplace(Ret.end()); +    VD.Offset = VerdefBuf - Start; +    VD.Version = D->vd_version; +    VD.Flags = D->vd_flags; +    VD.Ndx = D->vd_ndx; +    VD.Cnt = D->vd_cnt; +    VD.Hash = D->vd_hash; + +    const uint8_t *VerdauxBuf = VerdefBuf + D->vd_aux; +    for (unsigned J = 0; J < D->vd_cnt; ++J) { +      if (uintptr_t(VerdauxBuf) % sizeof(uint32_t) != 0) +        return createError("invalid SHT_GNU_verdef section with index " + +                           Twine(SecNdx) + +                           ": found a misaligned auxiliary entry at offset 0x" + +                           Twine::utohexstr(VerdauxBuf - Start)); + +      Expected<VerdAux> AuxOrErr = ExtractNextAux(VerdauxBuf, I); +      if (!AuxOrErr) +        return AuxOrErr.takeError(); + +      if (J == 0) +        VD.Name = AuxOrErr->Name; +      else +        VD.AuxV.push_back(*AuxOrErr); +    } + +    VerdefBuf += D->vd_next; +  } + +  return Ret; +} + +template <class ELFT> +Expected<std::vector<VerNeed>> +ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const { +  const ELFFile<ELFT> *Obj = ObjF->getELFFile(); +  unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); + +  StringRef StrTab; +  Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx); +  if (!StrTabOrErr) +    ELFDumperStyle->reportUniqueWarning(StrTabOrErr.takeError()); +  else +    StrTab = *StrTabOrErr; + +  Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(Sec); +  if (!ContentsOrErr) +    return createError( +        "cannot read content of SHT_GNU_verneed section with index " + +        Twine(SecNdx) + ": " + toString(ContentsOrErr.takeError())); + +  const uint8_t *Start = ContentsOrErr->data(); +  const uint8_t *End = Start + ContentsOrErr->size(); +  const uint8_t *VerneedBuf = Start; + +  std::vector<VerNeed> Ret; +  for (unsigned I = 1; I <= /*VerneedNum=*/Sec->sh_info; ++I) { +    if (VerneedBuf + sizeof(Elf_Verdef) > End) +      return createError("invalid SHT_GNU_verneed section with index " + +                         Twine(SecNdx) + ": version dependency " + Twine(I) + +                         " goes past the end of the section"); + +    if (uintptr_t(VerneedBuf) % sizeof(uint32_t) != 0) +      return createError( +          "invalid SHT_GNU_verneed section with index " + Twine(SecNdx) + +          ": found a misaligned version dependency entry at offset 0x" + +          Twine::utohexstr(VerneedBuf - Start)); + +    unsigned Version = *reinterpret_cast<const Elf_Half *>(VerneedBuf); +    if (Version != 1) +      return createError("unable to dump SHT_GNU_verneed section with index " + +                         Twine(SecNdx) + ": version " + Twine(Version) + +                         " is not yet supported"); + +    const Elf_Verneed *Verneed = +        reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + +    VerNeed &VN = *Ret.emplace(Ret.end()); +    VN.Version = Verneed->vn_version; +    VN.Cnt = Verneed->vn_cnt; +    VN.Offset = VerneedBuf - Start; + +    if (Verneed->vn_file < StrTab.size()) +      VN.File = StrTab.drop_front(Verneed->vn_file); +    else +      VN.File = "<corrupt vn_file: " + to_string(Verneed->vn_file) + ">"; + +    const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; +    for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { +      if (uintptr_t(VernauxBuf) % sizeof(uint32_t) != 0) +        return createError("invalid SHT_GNU_verneed section with index " + +                           Twine(SecNdx) + +                           ": found a misaligned auxiliary entry at offset 0x" + +                           Twine::utohexstr(VernauxBuf - Start)); + +      if (VernauxBuf + sizeof(Elf_Vernaux) > End) +        return createError( +            "invalid SHT_GNU_verneed section with index " + Twine(SecNdx) + +            ": version dependency " + Twine(I) + +            " refers to an auxiliary entry that goes past the end " +            "of the section"); + +      const Elf_Vernaux *Vernaux = +          reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); + +      VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end()); +      Aux.Hash = Vernaux->vna_hash; +      Aux.Flags = Vernaux->vna_flags; +      Aux.Other = Vernaux->vna_other; +      Aux.Offset = VernauxBuf - Start; +      if (StrTab.size() <= Vernaux->vna_name) +        Aux.Name = "<corrupt>"; +      else +        Aux.Name = StrTab.drop_front(Vernaux->vna_name); + +      VernauxBuf += Vernaux->vna_next; +    } +    VerneedBuf += Verneed->vn_next; +  } +  return Ret; +} + +template <class ELFT>  void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {    StringRef StrTable, SymtabName;    size_t Entries = 0; @@ -328,16 +654,27 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {    } else {      if (!DotSymtabSec)        return; -    StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec)); -    Syms = unwrapOrError(Obj->symbols(DotSymtabSec)); -    SymtabName = unwrapOrError(Obj->getSectionName(DotSymtabSec)); +    StrTable = unwrapOrError(ObjF->getFileName(), +                             Obj->getStringTableForSymtab(*DotSymtabSec)); +    Syms = unwrapOrError(ObjF->getFileName(), Obj->symbols(DotSymtabSec)); +    SymtabName = +        unwrapOrError(ObjF->getFileName(), Obj->getSectionName(DotSymtabSec));      Entries = DotSymtabSec->getEntityCount();    }    if (Syms.begin() == Syms.end())      return; -  ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries); + +  // The st_other field has 2 logical parts. The first two bits hold the symbol +  // visibility (STV_*) and the remainder hold other platform-specific values. +  bool NonVisibilityBitsUsed = llvm::find_if(Syms, [](const Elf_Sym &S) { +                                 return S.st_other & ~0x3; +                               }) != Syms.end(); + +  ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries, +                                     NonVisibilityBitsUsed);    for (const auto &Sym : Syms) -    ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic); +    ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic, +                                NonVisibilityBitsUsed);  }  template <class ELFT> class MipsGOTParser; @@ -346,8 +683,20 @@ template <typename ELFT> class DumpStyle {  public:    using Elf_Shdr = typename ELFT::Shdr;    using Elf_Sym = typename ELFT::Sym; +  using Elf_Addr = typename ELFT::Addr; + +  DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) { +    FileName = this->Dumper->getElfObject()->getFileName(); + +    // Dumper reports all non-critical errors as warnings. +    // It does not print the same warning more than once. +    WarningHandler = [this](const Twine &Msg) { +      if (Warnings.insert(Msg.str()).second) +        reportWarning(createError(Msg), FileName); +      return Error::success(); +    }; +  } -  DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {}    virtual ~DumpStyle() = default;    virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0; @@ -357,13 +706,14 @@ public:    virtual void printSymbols(const ELFFile<ELFT> *Obj, bool PrintSymbols,                              bool PrintDynamicSymbols) = 0;    virtual void printHashSymbols(const ELFFile<ELFT> *Obj) {} +  virtual void printDependentLibs(const ELFFile<ELFT> *Obj) = 0;    virtual void printDynamic(const ELFFile<ELFT> *Obj) {}    virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0;    virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name, -                                  size_t Offset) {} +                                  size_t Offset, bool NonVisibilityBitsUsed) {}    virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,                             const Elf_Sym *FirstSym, StringRef StrTable, -                           bool IsDynamic) = 0; +                           bool IsDynamic, bool NonVisibilityBitsUsed) = 0;    virtual void printProgramHeaders(const ELFFile<ELFT> *Obj,                                     bool PrintProgramHeaders,                                     cl::boolOrDefault PrintSectionMapping) = 0; @@ -378,11 +728,33 @@ public:    virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0;    virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;    virtual void printELFLinkerOptions(const ELFFile<ELFT> *Obj) = 0; +  virtual void printStackSizes(const ELFObjectFile<ELFT> *Obj) = 0; +  void printNonRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj, +                                     std::function<void()> PrintHeader); +  void printRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj, +                                  std::function<void()> PrintHeader); +  void printFunctionStackSize(const ELFObjectFile<ELFT> *Obj, uint64_t SymValue, +                              SectionRef FunctionSec, +                              const StringRef SectionName, DataExtractor Data, +                              uint64_t *Offset); +  void printStackSize(const ELFObjectFile<ELFT> *Obj, RelocationRef Rel, +                      SectionRef FunctionSec, +                      const StringRef &StackSizeSectionName, +                      const RelocationResolver &Resolver, DataExtractor Data); +  virtual void printStackSizeEntry(uint64_t Size, StringRef FuncName) = 0;    virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;    virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; +  virtual void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) = 0;    const ELFDumper<ELFT> *dumper() const { return Dumper; } +  void reportUniqueWarning(Error Err) const; + +protected: +  std::function<Error(const Twine &Msg)> WarningHandler; +  StringRef FileName; +  private: +  std::unordered_set<std::string> Warnings;    const ELFDumper<ELFT> *Dumper;  }; @@ -405,10 +777,11 @@ public:    void printSymbols(const ELFO *Obj, bool PrintSymbols,                      bool PrintDynamicSymbols) override;    void printHashSymbols(const ELFO *Obj) override; +  void printDependentLibs(const ELFFile<ELFT> *Obj) override;    void printDynamic(const ELFFile<ELFT> *Obj) override;    void printDynamicRelocations(const ELFO *Obj) override; -  void printSymtabMessage(const ELFO *Obj, StringRef Name, -                          size_t Offset) override; +  void printSymtabMessage(const ELFO *Obj, StringRef Name, size_t Offset, +                          bool NonVisibilityBitsUsed) override;    void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders,                             cl::boolOrDefault PrintSectionMapping) override;    void printVersionSymbolSection(const ELFFile<ELFT> *Obj, @@ -422,8 +795,11 @@ public:    void printAddrsig(const ELFFile<ELFT> *Obj) override;    void printNotes(const ELFFile<ELFT> *Obj) override;    void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override; +  void printStackSizes(const ELFObjectFile<ELFT> *Obj) override; +  void printStackSizeEntry(uint64_t Size, StringRef FuncName) override;    void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;    void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; +  void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override;  private:    struct Field { @@ -484,7 +860,8 @@ private:    void printRelocation(const ELFO *Obj, const Elf_Sym *Sym,                         StringRef SymbolName, const Elf_Rela &R, bool IsRela);    void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, -                   StringRef StrTable, bool IsDynamic) override; +                   StringRef StrTable, bool IsDynamic, +                   bool NonVisibilityBitsUsed) override;    std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,                                    const Elf_Sym *FirstSym);    void printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela); @@ -494,8 +871,19 @@ private:    bool checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);    void printProgramHeaders(const ELFO *Obj);    void printSectionMapping(const ELFO *Obj); +  void printGNUVersionSectionProlog(const ELFFile<ELFT> *Obj, +                                    const typename ELFT::Shdr *Sec, +                                    const Twine &Label, unsigned EntriesNum);  }; +template <class ELFT> +void DumpStyle<ELFT>::reportUniqueWarning(Error Err) const { +  handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { +    cantFail(WarningHandler(EI.message()), +             "WarningHandler should always return ErrorSuccess"); +  }); +} +  template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {  public:    TYPEDEF_ELF_TYPES(ELFT) @@ -510,6 +898,7 @@ public:    void printSectionHeaders(const ELFO *Obj) override;    void printSymbols(const ELFO *Obj, bool PrintSymbols,                      bool PrintDynamicSymbols) override; +  void printDependentLibs(const ELFFile<ELFT> *Obj) override;    void printDynamic(const ELFFile<ELFT> *Obj) override;    void printDynamicRelocations(const ELFO *Obj) override;    void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, @@ -525,16 +914,21 @@ public:    void printAddrsig(const ELFFile<ELFT> *Obj) override;    void printNotes(const ELFFile<ELFT> *Obj) override;    void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override; +  void printStackSizes(const ELFObjectFile<ELFT> *Obj) override; +  void printStackSizeEntry(uint64_t Size, StringRef FuncName) override;    void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;    void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; +  void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override;  private:    void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);    void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel);    void printSymbols(const ELFO *Obj);    void printDynamicSymbols(const ELFO *Obj); +  void printSymbolSection(const Elf_Sym *Symbol, const Elf_Sym *First);    void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, -                   StringRef StrTable, bool IsDynamic) override; +                   StringRef StrTable, bool IsDynamic, +                   bool /*NonVisibilityBitsUsed*/) override;    void printProgramHeaders(const ELFO *Obj);    void printSectionMapping(const ELFO *Obj) {} @@ -577,96 +971,51 @@ std::error_code createELFDumper(const object::ObjectFile *Obj,  } // end namespace llvm -// Iterate through the versions needed section, and place each Elf_Vernaux -// in the VersionMap according to its index. -template <class ELFT> -void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *Sec) const { -  unsigned VerneedSize = Sec->sh_size;    // Size of section in bytes -  unsigned VerneedEntries = Sec->sh_info; // Number of Verneed entries -  const uint8_t *VerneedStart = reinterpret_cast<const uint8_t *>( -      ObjF->getELFFile()->base() + Sec->sh_offset); -  const uint8_t *VerneedEnd = VerneedStart + VerneedSize; -  // The first Verneed entry is at the start of the section. -  const uint8_t *VerneedBuf = VerneedStart; -  for (unsigned VerneedIndex = 0; VerneedIndex < VerneedEntries; -       ++VerneedIndex) { -    if (VerneedBuf + sizeof(Elf_Verneed) > VerneedEnd) -      report_fatal_error("Section ended unexpectedly while scanning " -                         "version needed records."); -    const Elf_Verneed *Verneed = -        reinterpret_cast<const Elf_Verneed *>(VerneedBuf); -    if (Verneed->vn_version != ELF::VER_NEED_CURRENT) -      report_fatal_error("Unexpected verneed version"); -    // Iterate through the Vernaux entries -    const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; -    for (unsigned VernauxIndex = 0; VernauxIndex < Verneed->vn_cnt; -         ++VernauxIndex) { -      if (VernauxBuf + sizeof(Elf_Vernaux) > VerneedEnd) -        report_fatal_error("Section ended unexpected while scanning auxiliary " -                           "version needed records."); -      const Elf_Vernaux *Vernaux = -          reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); -      size_t Index = Vernaux->vna_other & ELF::VERSYM_VERSION; -      if (Index >= VersionMap.size()) -        VersionMap.resize(Index + 1); -      VersionMap[Index] = VersionMapEntry(Vernaux); -      VernauxBuf += Vernaux->vna_next; -    } -    VerneedBuf += Verneed->vn_next; -  } -} - -// Iterate through the version definitions, and place each Elf_Verdef -// in the VersionMap according to its index. -template <class ELFT> -void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *Sec) const { -  unsigned VerdefSize = Sec->sh_size;    // Size of section in bytes -  unsigned VerdefEntries = Sec->sh_info; // Number of Verdef entries -  const uint8_t *VerdefStart = reinterpret_cast<const uint8_t *>( -      ObjF->getELFFile()->base() + Sec->sh_offset); -  const uint8_t *VerdefEnd = VerdefStart + VerdefSize; -  // The first Verdef entry is at the start of the section. -  const uint8_t *VerdefBuf = VerdefStart; -  for (unsigned VerdefIndex = 0; VerdefIndex < VerdefEntries; ++VerdefIndex) { -    if (VerdefBuf + sizeof(Elf_Verdef) > VerdefEnd) -      report_fatal_error("Section ended unexpectedly while scanning " -                         "version definitions."); -    const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); -    if (Verdef->vd_version != ELF::VER_DEF_CURRENT) -      report_fatal_error("Unexpected verdef version"); -    size_t Index = Verdef->vd_ndx & ELF::VERSYM_VERSION; -    if (Index >= VersionMap.size()) -      VersionMap.resize(Index + 1); -    VersionMap[Index] = VersionMapEntry(Verdef); -    VerdefBuf += Verdef->vd_next; -  } -} - -template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() const { +template <class ELFT> Error ELFDumper<ELFT>::LoadVersionMap() const {    // If there is no dynamic symtab or version table, there is nothing to do.    if (!DynSymRegion.Addr || !SymbolVersionSection) -    return; +    return Error::success();    // Has the VersionMap already been loaded?    if (!VersionMap.empty()) -    return; +    return Error::success();    // The first two version indexes are reserved.    // Index 0 is LOCAL, index 1 is GLOBAL. -  VersionMap.push_back(VersionMapEntry()); -  VersionMap.push_back(VersionMapEntry()); +  VersionMap.push_back(VersionEntry()); +  VersionMap.push_back(VersionEntry()); + +  auto InsertEntry = [this](unsigned N, StringRef Version, bool IsVerdef) { +    if (N >= VersionMap.size()) +      VersionMap.resize(N + 1); +    VersionMap[N] = {Version, IsVerdef}; +  }; + +  if (SymbolVersionDefSection) { +    Expected<std::vector<VerDef>> Defs = +        this->getVersionDefinitions(SymbolVersionDefSection); +    if (!Defs) +      return Defs.takeError(); +    for (const VerDef &Def : *Defs) +      InsertEntry(Def.Ndx & ELF::VERSYM_VERSION, Def.Name, true); +  } -  if (SymbolVersionDefSection) -    LoadVersionDefs(SymbolVersionDefSection); +  if (SymbolVersionNeedSection) { +    Expected<std::vector<VerNeed>> Deps = +        this->getVersionDependencies(SymbolVersionNeedSection); +    if (!Deps) +      return Deps.takeError(); +    for (const VerNeed &Dep : *Deps) +      for (const VernAux &Aux : Dep.AuxV) +        InsertEntry(Aux.Other & ELF::VERSYM_VERSION, Aux.Name, false); +  } -  if (SymbolVersionNeedSection) -    LoadVersionNeeds(SymbolVersionNeedSection); +  return Error::success();  }  template <typename ELFT> -StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, -                                            const Elf_Sym *Sym, -                                            bool &IsDefault) const { +Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym *Sym, +                                                      bool &IsDefault) const {    // This is a dynamic symbol. Look in the GNU symbol version table.    if (!SymbolVersionSection) {      // No version table. @@ -680,10 +1029,10 @@ StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab,                         sizeof(Elf_Sym);    // Get the corresponding version index entry. -  const Elf_Versym *Versym = -      unwrapOrError(ObjF->getELFFile()->template getEntry<Elf_Versym>( -          SymbolVersionSection, EntryIndex)); -  return this->getSymbolVersionByIndex(StrTab, Versym->vs_index, IsDefault); +  const Elf_Versym *Versym = unwrapOrError( +      ObjF->getFileName(), ObjF->getELFFile()->template getEntry<Elf_Versym>( +                               SymbolVersionSection, EntryIndex)); +  return this->getSymbolVersionByIndex(Versym->vs_index, IsDefault);  }  static std::string maybeDemangle(StringRef Name) { @@ -691,21 +1040,28 @@ static std::string maybeDemangle(StringRef Name) {  }  template <typename ELFT> -std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { +Expected<std::string> +ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {    const ELFFile<ELFT> *Obj = ObjF->getELFFile(); -  StringRef StrTable = -      unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec)); -  Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec)); -  if (Index >= Syms.size()) -    reportError("Invalid symbol index"); -  const Elf_Sym *Sym = &Syms[Index]; -  return maybeDemangle(unwrapOrError(Sym->getName(StrTable))); +  Expected<const typename ELFT::Sym *> SymOrErr = +      Obj->getSymbol(DotSymtabSec, Index); +  if (!SymOrErr) +    return SymOrErr.takeError(); + +  Expected<StringRef> StrTabOrErr = Obj->getStringTableForSymtab(*DotSymtabSec); +  if (!StrTabOrErr) +    return StrTabOrErr.takeError(); + +  Expected<StringRef> NameOrErr = (*SymOrErr)->getName(*StrTabOrErr); +  if (!NameOrErr) +    return NameOrErr.takeError(); +  return maybeDemangle(*NameOrErr);  }  template <typename ELFT> -StringRef ELFDumper<ELFT>::getSymbolVersionByIndex(StringRef StrTab, -                                                   uint32_t SymbolVersionIndex, -                                                   bool &IsDefault) const { +Expected<StringRef> +ELFDumper<ELFT>::getSymbolVersionByIndex(uint32_t SymbolVersionIndex, +                                         bool &IsDefault) const {    size_t VersionIndex = SymbolVersionIndex & VERSYM_VERSION;    // Special markers for unversioned symbols. @@ -715,99 +1071,117 @@ StringRef ELFDumper<ELFT>::getSymbolVersionByIndex(StringRef StrTab,    }    // Lookup this symbol in the version table. -  LoadVersionMap(); -  if (VersionIndex >= VersionMap.size() || VersionMap[VersionIndex].isNull()) -    reportError("Invalid version entry"); -  const VersionMapEntry &Entry = VersionMap[VersionIndex]; - -  // Get the version name string. -  size_t NameOffset; -  if (Entry.isVerdef()) { -    // The first Verdaux entry holds the name. -    NameOffset = Entry.getVerdef()->getAux()->vda_name; +  if (Error E = LoadVersionMap()) +    return std::move(E); +  if (VersionIndex >= VersionMap.size() || !VersionMap[VersionIndex]) +    return createError("SHT_GNU_versym section refers to a version index " + +                       Twine(VersionIndex) + " which is missing"); + +  const VersionEntry &Entry = *VersionMap[VersionIndex]; +  if (Entry.IsVerDef)      IsDefault = !(SymbolVersionIndex & VERSYM_HIDDEN); -  } else { -    NameOffset = Entry.getVernaux()->vna_name; +  else      IsDefault = false; -  } -  if (NameOffset >= StrTab.size()) -    reportError("Invalid string offset"); -  return StrTab.data() + NameOffset; +  return Entry.Name.c_str();  }  template <typename ELFT>  std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,                                                 StringRef StrTable,                                                 bool IsDynamic) const { -  std::string SymbolName = -      maybeDemangle(unwrapOrError(Symbol->getName(StrTable))); +  std::string SymbolName = maybeDemangle( +      unwrapOrError(ObjF->getFileName(), Symbol->getName(StrTable)));    if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) { -    unsigned SectionIndex; -    StringRef SectionName; -    Elf_Sym_Range Syms = -        unwrapOrError(ObjF->getELFFile()->symbols(DotSymtabSec)); -    getSectionNameIndex(Symbol, Syms.begin(), SectionName, SectionIndex); -    return SectionName; +    Elf_Sym_Range Syms = unwrapOrError( +        ObjF->getFileName(), ObjF->getELFFile()->symbols(DotSymtabSec)); +    Expected<unsigned> SectionIndex = +        getSymbolSectionIndex(Symbol, Syms.begin()); +    if (!SectionIndex) { +      ELFDumperStyle->reportUniqueWarning(SectionIndex.takeError()); +      return "<?>"; +    } +    Expected<StringRef> NameOrErr = getSymbolSectionName(Symbol, *SectionIndex); +    if (!NameOrErr) { +      ELFDumperStyle->reportUniqueWarning(NameOrErr.takeError()); +      return ("<section " + Twine(*SectionIndex) + ">").str(); +    } +    return *NameOrErr;    }    if (!IsDynamic)      return SymbolName;    bool IsDefault; -  StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault); -  if (!Version.empty()) { +  Expected<StringRef> VersionOrErr = getSymbolVersion(&*Symbol, IsDefault); +  if (!VersionOrErr) { +    ELFDumperStyle->reportUniqueWarning(VersionOrErr.takeError()); +    return SymbolName + "@<corrupt>"; +  } + +  if (!VersionOrErr->empty()) {      SymbolName += (IsDefault ? "@@" : "@"); -    SymbolName += Version; +    SymbolName += *VersionOrErr;    }    return SymbolName;  }  template <typename ELFT> -void ELFDumper<ELFT>::getSectionNameIndex(const Elf_Sym *Symbol, -                                          const Elf_Sym *FirstSym, -                                          StringRef &SectionName, -                                          unsigned &SectionIndex) const { -  SectionIndex = Symbol->st_shndx; +Expected<unsigned> +ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym *Symbol, +                                       const Elf_Sym *FirstSym) const { +  return Symbol->st_shndx == SHN_XINDEX +             ? object::getExtendedSymbolTableIndex<ELFT>(Symbol, FirstSym, +                                                         ShndxTable) +             : Symbol->st_shndx; +} + +// If the Symbol has a reserved st_shndx other than SHN_XINDEX, return a +// descriptive interpretation of the st_shndx value. Otherwise, return the name +// of the section with index SectionIndex. This function assumes that if the +// Symbol has st_shndx == SHN_XINDEX the SectionIndex will be the value derived +// from the SHT_SYMTAB_SHNDX section. +template <typename ELFT> +Expected<StringRef> +ELFDumper<ELFT>::getSymbolSectionName(const Elf_Sym *Symbol, +                                      unsigned SectionIndex) const {    if (Symbol->isUndefined()) -    SectionName = "Undefined"; -  else if (Symbol->isProcessorSpecific()) -    SectionName = "Processor Specific"; -  else if (Symbol->isOSSpecific()) -    SectionName = "Operating System Specific"; -  else if (Symbol->isAbsolute()) -    SectionName = "Absolute"; -  else if (Symbol->isCommon()) -    SectionName = "Common"; -  else if (Symbol->isReserved() && SectionIndex != SHN_XINDEX) -    SectionName = "Reserved"; -  else { -    if (SectionIndex == SHN_XINDEX) -      SectionIndex = unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>( -          Symbol, FirstSym, ShndxTable)); -    const ELFFile<ELFT> *Obj = ObjF->getELFFile(); -    const typename ELFT::Shdr *Sec = -        unwrapOrError(Obj->getSection(SectionIndex)); -    SectionName = unwrapOrError(Obj->getSectionName(Sec)); -  } +    return "Undefined"; +  if (Symbol->isProcessorSpecific()) +    return "Processor Specific"; +  if (Symbol->isOSSpecific()) +    return "Operating System Specific"; +  if (Symbol->isAbsolute()) +    return "Absolute"; +  if (Symbol->isCommon()) +    return "Common"; +  if (Symbol->isReserved() && Symbol->st_shndx != SHN_XINDEX) +    return "Reserved"; + +  const ELFFile<ELFT> *Obj = ObjF->getELFFile(); +  Expected<const Elf_Shdr *> SecOrErr = +      Obj->getSection(SectionIndex); +  if (!SecOrErr) +    return SecOrErr.takeError(); +  return Obj->getSectionName(*SecOrErr);  }  template <class ELFO>  static const typename ELFO::Elf_Shdr * -findNotEmptySectionByAddress(const ELFO *Obj, uint64_t Addr) { -  for (const auto &Shdr : unwrapOrError(Obj->sections())) +findNotEmptySectionByAddress(const ELFO *Obj, StringRef FileName, +                             uint64_t Addr) { +  for (const auto &Shdr : unwrapOrError(FileName, Obj->sections()))      if (Shdr.sh_addr == Addr && Shdr.sh_size > 0)        return &Shdr;    return nullptr;  }  template <class ELFO> -static const typename ELFO::Elf_Shdr *findSectionByName(const ELFO &Obj, -                                                        StringRef Name) { -  for (const auto &Shdr : unwrapOrError(Obj.sections())) { -    if (Name == unwrapOrError(Obj.getSectionName(&Shdr))) +static const typename ELFO::Elf_Shdr * +findSectionByName(const ELFO &Obj, StringRef FileName, StringRef Name) { +  for (const auto &Shdr : unwrapOrError(FileName, Obj.sections())) +    if (Name == unwrapOrError(FileName, Obj.getSectionName(&Shdr)))        return &Shdr; -  }    return nullptr;  } @@ -1060,76 +1434,126 @@ static const char *getGroupType(uint32_t Flag) {  static const EnumEntry<unsigned> ElfSectionFlags[] = {    ENUM_ENT(SHF_WRITE,            "W"),    ENUM_ENT(SHF_ALLOC,            "A"), -  ENUM_ENT(SHF_EXCLUDE,          "E"),    ENUM_ENT(SHF_EXECINSTR,        "X"),    ENUM_ENT(SHF_MERGE,            "M"),    ENUM_ENT(SHF_STRINGS,          "S"),    ENUM_ENT(SHF_INFO_LINK,        "I"),    ENUM_ENT(SHF_LINK_ORDER,       "L"), -  ENUM_ENT(SHF_OS_NONCONFORMING, "o"), +  ENUM_ENT(SHF_OS_NONCONFORMING, "O"),    ENUM_ENT(SHF_GROUP,            "G"),    ENUM_ENT(SHF_TLS,              "T"), -  ENUM_ENT(SHF_MASKOS,           "o"), -  ENUM_ENT(SHF_MASKPROC,         "p"), -  ENUM_ENT_1(SHF_COMPRESSED), +  ENUM_ENT(SHF_COMPRESSED,       "C"), +  ENUM_ENT(SHF_EXCLUDE,          "E"),  };  static const EnumEntry<unsigned> ElfXCoreSectionFlags[] = { -  LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION), -  LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION) +  ENUM_ENT(XCORE_SHF_CP_SECTION, ""), +  ENUM_ENT(XCORE_SHF_DP_SECTION, "")  };  static const EnumEntry<unsigned> ElfARMSectionFlags[] = { -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_ARM_PURECODE) +  ENUM_ENT(SHF_ARM_PURECODE, "y")  };  static const EnumEntry<unsigned> ElfHexagonSectionFlags[] = { -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_HEX_GPREL) +  ENUM_ENT(SHF_HEX_GPREL, "")  };  static const EnumEntry<unsigned> ElfMipsSectionFlags[] = { -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NODUPES), -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NAMES  ), -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_LOCAL  ), -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP), -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_GPREL  ), -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_MERGE  ), -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_ADDR   ), -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_STRING ) +  ENUM_ENT(SHF_MIPS_NODUPES, ""), +  ENUM_ENT(SHF_MIPS_NAMES,   ""), +  ENUM_ENT(SHF_MIPS_LOCAL,   ""), +  ENUM_ENT(SHF_MIPS_NOSTRIP, ""), +  ENUM_ENT(SHF_MIPS_GPREL,   ""), +  ENUM_ENT(SHF_MIPS_MERGE,   ""), +  ENUM_ENT(SHF_MIPS_ADDR,    ""), +  ENUM_ENT(SHF_MIPS_STRING,  "")  };  static const EnumEntry<unsigned> ElfX86_64SectionFlags[] = { -  LLVM_READOBJ_ENUM_ENT(ELF, SHF_X86_64_LARGE) +  ENUM_ENT(SHF_X86_64_LARGE, "l")  }; -static std::string getGNUFlags(uint64_t Flags) { +static std::vector<EnumEntry<unsigned>> +getSectionFlagsForTarget(unsigned EMachine) { +  std::vector<EnumEntry<unsigned>> Ret(std::begin(ElfSectionFlags), +                                       std::end(ElfSectionFlags)); +  switch (EMachine) { +  case EM_ARM: +    Ret.insert(Ret.end(), std::begin(ElfARMSectionFlags), +               std::end(ElfARMSectionFlags)); +    break; +  case EM_HEXAGON: +    Ret.insert(Ret.end(), std::begin(ElfHexagonSectionFlags), +               std::end(ElfHexagonSectionFlags)); +    break; +  case EM_MIPS: +    Ret.insert(Ret.end(), std::begin(ElfMipsSectionFlags), +               std::end(ElfMipsSectionFlags)); +    break; +  case EM_X86_64: +    Ret.insert(Ret.end(), std::begin(ElfX86_64SectionFlags), +               std::end(ElfX86_64SectionFlags)); +    break; +  case EM_XCORE: +    Ret.insert(Ret.end(), std::begin(ElfXCoreSectionFlags), +               std::end(ElfXCoreSectionFlags)); +    break; +  default: +    break; +  } +  return Ret; +} + +static std::string getGNUFlags(unsigned EMachine, uint64_t Flags) { +  // Here we are trying to build the flags string in the same way as GNU does. +  // It is not that straightforward. Imagine we have sh_flags == 0x90000000. +  // SHF_EXCLUDE ("E") has a value of 0x80000000 and SHF_MASKPROC is 0xf0000000. +  // GNU readelf will not print "E" or "Ep" in this case, but will print just +  // "p". It only will print "E" when no other processor flag is set.    std::string Str; -  for (auto Entry : ElfSectionFlags) { -    uint64_t Flag = Entry.Value & Flags; -    Flags &= ~Entry.Value; -    switch (Flag) { -    case ELF::SHF_WRITE: -    case ELF::SHF_ALLOC: -    case ELF::SHF_EXECINSTR: -    case ELF::SHF_MERGE: -    case ELF::SHF_STRINGS: -    case ELF::SHF_INFO_LINK: -    case ELF::SHF_LINK_ORDER: -    case ELF::SHF_OS_NONCONFORMING: -    case ELF::SHF_GROUP: -    case ELF::SHF_TLS: -    case ELF::SHF_EXCLUDE: -      Str += Entry.AltName; -      break; -    default: -      if (Flag & ELF::SHF_MASKOS) -        Str += "o"; -      else if (Flag & ELF::SHF_MASKPROC) -        Str += "p"; -      else if (Flag) -        Str += "x"; +  bool HasUnknownFlag = false; +  bool HasOSFlag = false; +  bool HasProcFlag = false; +  std::vector<EnumEntry<unsigned>> FlagsList = +      getSectionFlagsForTarget(EMachine); +  while (Flags) { +    // Take the least significant bit as a flag. +    uint64_t Flag = Flags & -Flags; +    Flags -= Flag; + +    // Find the flag in the known flags list. +    auto I = llvm::find_if(FlagsList, [=](const EnumEntry<unsigned> &E) { +      // Flags with empty names are not printed in GNU style output. +      return E.Value == Flag && !E.AltName.empty(); +    }); +    if (I != FlagsList.end()) { +      Str += I->AltName; +      continue; +    } + +    // If we did not find a matching regular flag, then we deal with an OS +    // specific flag, processor specific flag or an unknown flag. +    if (Flag & ELF::SHF_MASKOS) { +      HasOSFlag = true; +      Flags &= ~ELF::SHF_MASKOS; +    } else if (Flag & ELF::SHF_MASKPROC) { +      HasProcFlag = true; +      // Mask off all the processor-specific bits. This removes the SHF_EXCLUDE +      // bit if set so that it doesn't also get printed. +      Flags &= ~ELF::SHF_MASKPROC; +    } else { +      HasUnknownFlag = true;      }    } + +  // "o", "p" and "x" are printed last. +  if (HasOSFlag) +    Str += "o"; +  if (HasProcFlag) +    Str += "p"; +  if (HasUnknownFlag) +    Str += "x";    return Str;  } @@ -1166,6 +1590,7 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) {      LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK);      LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO); +    LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_PROPERTY);      LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE);      LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED); @@ -1190,6 +1615,7 @@ static std::string getElfPtType(unsigned Arch, unsigned Type) {      LLVM_READOBJ_PHDR_ENUM(ELF, PT_SUNW_UNWIND)      LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_STACK)      LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_RELRO) +    LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_PROPERTY)    default:      // All machine specific PT_* types      switch (Arch) { @@ -1356,10 +1782,12 @@ static const char *getElfMipsOptionsOdkType(unsigned Odk) {  }  template <typename ELFT> -void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { +std::pair<const typename ELFT::Phdr *, const typename ELFT::Shdr *> +ELFDumper<ELFT>::findDynamic(const ELFFile<ELFT> *Obj) {    // Try to locate the PT_DYNAMIC header.    const Elf_Phdr *DynamicPhdr = nullptr; -  for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { +  for (const Elf_Phdr &Phdr : +       unwrapOrError(ObjF->getFileName(), Obj->program_headers())) {      if (Phdr.p_type != ELF::PT_DYNAMIC)        continue;      DynamicPhdr = &Phdr; @@ -1368,61 +1796,132 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {    // Try to locate the .dynamic section in the sections header table.    const Elf_Shdr *DynamicSec = nullptr; -  for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { +  for (const Elf_Shdr &Sec : +       unwrapOrError(ObjF->getFileName(), Obj->sections())) {      if (Sec.sh_type != ELF::SHT_DYNAMIC)        continue;      DynamicSec = &Sec;      break;    } -  // Information in the section header has priority over the information -  // in a PT_DYNAMIC header. +  if (DynamicPhdr && DynamicPhdr->p_offset + DynamicPhdr->p_filesz > +                         ObjF->getMemoryBufferRef().getBufferSize()) { +    reportWarning( +        createError( +            "PT_DYNAMIC segment offset + size exceeds the size of the file"), +        ObjF->getFileName()); +    // Don't use the broken dynamic header. +    DynamicPhdr = nullptr; +  } + +  if (DynamicPhdr && DynamicSec) { +    StringRef Name = +        unwrapOrError(ObjF->getFileName(), Obj->getSectionName(DynamicSec)); +    if (DynamicSec->sh_addr + DynamicSec->sh_size > +            DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz || +        DynamicSec->sh_addr < DynamicPhdr->p_vaddr) +      reportWarning(createError("The SHT_DYNAMIC section '" + Name + +                                "' is not contained within the " +                                "PT_DYNAMIC segment"), +                    ObjF->getFileName()); + +    if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr) +      reportWarning(createError("The SHT_DYNAMIC section '" + Name + +                                "' is not at the start of " +                                "PT_DYNAMIC segment"), +                    ObjF->getFileName()); +  } + +  return std::make_pair(DynamicPhdr, DynamicSec); +} + +template <typename ELFT> +void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { +  const Elf_Phdr *DynamicPhdr; +  const Elf_Shdr *DynamicSec; +  std::tie(DynamicPhdr, DynamicSec) = findDynamic(Obj); +  if (!DynamicPhdr && !DynamicSec) +    return; + +  DynRegionInfo FromPhdr(ObjF->getFileName()); +  bool IsPhdrTableValid = false; +  if (DynamicPhdr) { +    FromPhdr = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn)); +    IsPhdrTableValid = !FromPhdr.getAsArrayRef<Elf_Dyn>().empty(); +  } + +  // Locate the dynamic table described in a section header.    // Ignore sh_entsize and use the expected value for entry size explicitly. -  // This allows us to dump the dynamic sections with a broken sh_entsize +  // This allows us to dump dynamic sections with a broken sh_entsize    // field. +  DynRegionInfo FromSec(ObjF->getFileName()); +  bool IsSecTableValid = false;    if (DynamicSec) { -    DynamicTable = checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset, -                             DynamicSec->sh_size, sizeof(Elf_Dyn)}); -    parseDynamicTable(); +    FromSec = +        checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset, +                  DynamicSec->sh_size, sizeof(Elf_Dyn), ObjF->getFileName()}); +    IsSecTableValid = !FromSec.getAsArrayRef<Elf_Dyn>().empty();    } -  // If we have a PT_DYNAMIC header, we will either check the found dynamic -  // section or take the dynamic table data directly from the header. -  if (!DynamicPhdr) +  // When we only have information from one of the SHT_DYNAMIC section header or +  // PT_DYNAMIC program header, just use that. +  if (!DynamicPhdr || !DynamicSec) { +    if ((DynamicPhdr && IsPhdrTableValid) || (DynamicSec && IsSecTableValid)) { +      DynamicTable = DynamicPhdr ? FromPhdr : FromSec; +      parseDynamicTable(Obj); +    } else { +      reportWarning(createError("no valid dynamic table was found"), +                    ObjF->getFileName()); +    }      return; +  } -  if (DynamicPhdr->p_offset + DynamicPhdr->p_filesz > -      ObjF->getMemoryBufferRef().getBufferSize()) -    reportError( -        "PT_DYNAMIC segment offset + size exceeds the size of the file"); +  // At this point we have tables found from the section header and from the +  // dynamic segment. Usually they match, but we have to do sanity checks to +  // verify that. -  if (!DynamicSec) { -    DynamicTable = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn)); -    parseDynamicTable(); +  if (FromPhdr.Addr != FromSec.Addr) +    reportWarning(createError("SHT_DYNAMIC section header and PT_DYNAMIC " +                              "program header disagree about " +                              "the location of the dynamic table"), +                  ObjF->getFileName()); + +  if (!IsPhdrTableValid && !IsSecTableValid) { +    reportWarning(createError("no valid dynamic table was found"), +                  ObjF->getFileName());      return;    } -  StringRef Name = unwrapOrError(Obj->getSectionName(DynamicSec)); -  if (DynamicSec->sh_addr + DynamicSec->sh_size > -          DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz || -      DynamicSec->sh_addr < DynamicPhdr->p_vaddr) -    reportWarning("The SHT_DYNAMIC section '" + Name + -                  "' is not contained within the " -                  "PT_DYNAMIC segment"); +  // Information in the PT_DYNAMIC program header has priority over the information +  // in a section header. +  if (IsPhdrTableValid) { +    if (!IsSecTableValid) +      reportWarning( +          createError( +              "SHT_DYNAMIC dynamic table is invalid: PT_DYNAMIC will be used"), +          ObjF->getFileName()); +    DynamicTable = FromPhdr; +  } else { +    reportWarning( +        createError( +            "PT_DYNAMIC dynamic table is invalid: SHT_DYNAMIC will be used"), +        ObjF->getFileName()); +    DynamicTable = FromSec; +  } -  if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr) -    reportWarning("The SHT_DYNAMIC section '" + Name + -                  "' is not at the start of " -                  "PT_DYNAMIC segment"); +  parseDynamicTable(Obj);  }  template <typename ELFT>  ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, -    ScopedPrinter &Writer) -    : ObjDumper(Writer), ObjF(ObjF) { +                           ScopedPrinter &Writer) +    : ObjDumper(Writer), ObjF(ObjF), DynRelRegion(ObjF->getFileName()), +      DynRelaRegion(ObjF->getFileName()), DynRelrRegion(ObjF->getFileName()), +      DynPLTRelRegion(ObjF->getFileName()), DynSymRegion(ObjF->getFileName()), +      DynamicTable(ObjF->getFileName()) {    const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - -  for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { +  for (const Elf_Shdr &Sec : +       unwrapOrError(ObjF->getFileName(), Obj->sections())) {      switch (Sec.sh_type) {      case ELF::SHT_SYMTAB:        if (!DotSymtabSec) @@ -1433,16 +1932,17 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,          DynSymRegion = createDRIFrom(&Sec);          // This is only used (if Elf_Shdr present)for naming section in GNU          // style -        DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec)); +        DynSymtabName = +            unwrapOrError(ObjF->getFileName(), Obj->getSectionName(&Sec));          if (Expected<StringRef> E = Obj->getStringTableForSymtab(Sec))            DynamicStringTable = *E;          else -          warn(E.takeError()); +          reportWarning(E.takeError(), ObjF->getFileName());        }        break;      case ELF::SHT_SYMTAB_SHNDX: -      ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec)); +      ShndxTable = unwrapOrError(ObjF->getFileName(), Obj->getSHNDXTable(Sec));        break;      case ELF::SHT_GNU_versym:        if (!SymbolVersionSection) @@ -1475,82 +1975,16 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,      ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));  } -static const char *getTypeString(unsigned Arch, uint64_t Type) { -#define DYNAMIC_TAG(n, v) -  switch (Arch) { - -  case EM_AARCH64: -    switch (Type) { -#define AARCH64_DYNAMIC_TAG(name, value)                                       \ -    case DT_##name:                                                            \ -      return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef AARCH64_DYNAMIC_TAG -    } -    break; - -  case EM_HEXAGON: -    switch (Type) { -#define HEXAGON_DYNAMIC_TAG(name, value)                                       \ -  case DT_##name:                                                              \ -    return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef HEXAGON_DYNAMIC_TAG -    } -    break; - -  case EM_MIPS: -    switch (Type) { -#define MIPS_DYNAMIC_TAG(name, value)                                          \ -  case DT_##name:                                                              \ -    return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef MIPS_DYNAMIC_TAG -    } -    break; - -  case EM_PPC64: -    switch (Type) { -#define PPC64_DYNAMIC_TAG(name, value)                                         \ -  case DT_##name:                                                              \ -    return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef PPC64_DYNAMIC_TAG -    } -    break; -  } -#undef DYNAMIC_TAG -  switch (Type) { -// Now handle all dynamic tags except the architecture specific ones -#define AARCH64_DYNAMIC_TAG(name, value) -#define MIPS_DYNAMIC_TAG(name, value) -#define HEXAGON_DYNAMIC_TAG(name, value) -#define PPC64_DYNAMIC_TAG(name, value) -// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc. -#define DYNAMIC_TAG_MARKER(name, value) -#define DYNAMIC_TAG(name, value)                                               \ -  case DT_##name:                                                              \ -    return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef DYNAMIC_TAG -#undef AARCH64_DYNAMIC_TAG -#undef MIPS_DYNAMIC_TAG -#undef HEXAGON_DYNAMIC_TAG -#undef PPC64_DYNAMIC_TAG -#undef DYNAMIC_TAG_MARKER -  default: -    return "unknown"; -  } -} - -template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { +template <typename ELFT> +void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {    auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * {      auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr);      if (!MappedAddrOrError) { -      reportWarning("Unable to parse DT_" + -                    Twine(getTypeString( -                        ObjF->getELFFile()->getHeader()->e_machine, Tag)) + -                    ": " + llvm::toString(MappedAddrOrError.takeError())); +      Error Err = +          createError("Unable to parse DT_" + Obj->getDynamicTagAsString(Tag) + +                      ": " + llvm::toString(MappedAddrOrError.takeError())); + +      reportWarning(std::move(Err), ObjF->getFileName());        return nullptr;      }      return MappedAddrOrError.get(); @@ -1576,10 +2010,29 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {      case ELF::DT_STRSZ:        StringTableSize = Dyn.getVal();        break; -    case ELF::DT_SYMTAB: -      DynSymRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); -      DynSymRegion.EntSize = sizeof(Elf_Sym); +    case ELF::DT_SYMTAB: { +      // Often we find the information about the dynamic symbol table +      // location in the SHT_DYNSYM section header. However, the value in +      // DT_SYMTAB has priority, because it is used by dynamic loaders to +      // locate .dynsym at runtime. The location we find in the section header +      // and the location we find here should match. If we can't map the +      // DT_SYMTAB value to an address (e.g. when there are no program headers), we +      // ignore its value. +      if (const uint8_t *VA = toMappedAddr(Dyn.getTag(), Dyn.getPtr())) { +        // EntSize is non-zero if the dynamic symbol table has been found via a +        // section header. +        if (DynSymRegion.EntSize && VA != DynSymRegion.Addr) +          reportWarning( +              createError( +                  "SHT_DYNSYM section header and DT_SYMTAB disagree about " +                  "the location of the dynamic symbol table"), +              ObjF->getFileName()); + +        DynSymRegion.Addr = VA; +        DynSymRegion.EntSize = sizeof(Elf_Sym); +      }        break; +    }      case ELF::DT_RELA:        DynRelaRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());        break; @@ -1619,8 +2072,9 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {        else if (Dyn.getVal() == DT_RELA)          DynPLTRelRegion.EntSize = sizeof(Elf_Rela);        else -        reportError(Twine("unknown DT_PLTREL value of ") + -                    Twine((uint64_t)Dyn.getVal())); +        reportError(createError(Twine("unknown DT_PLTREL value of ") + +                                Twine((uint64_t)Dyn.getVal())), +                    ObjF->getFileName());        break;      case ELF::DT_JMPREL:        DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); @@ -1632,8 +2086,7 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {    }    if (StringTableBegin)      DynamicStringTable = StringRef(StringTableBegin, StringTableSize); -  if (SONameOffset && SONameOffset < DynamicStringTable.size()) -    SOName = DynamicStringTable.data() + SONameOffset; +  SOName = getDynamicString(SONameOffset);  }  template <typename ELFT> @@ -1684,6 +2137,10 @@ template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() {                                                  SymbolVersionNeedSection);  } +template <class ELFT> void ELFDumper<ELFT>::printDependentLibs() { +  ELFDumperStyle->printDependentLibs(ObjF->getELFFile()); +} +  template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() {    ELFDumperStyle->printDynamicRelocations(ObjF->getELFFile());  } @@ -1715,6 +2172,10 @@ template <class ELFT> void ELFDumper<ELFT>::printELFLinkerOptions() {    ELFDumperStyle->printELFLinkerOptions(ObjF->getELFFile());  } +template <class ELFT> void ELFDumper<ELFT>::printStackSizes() { +  ELFDumperStyle->printStackSizes(ObjF); +} +  #define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum)                                 \    { #enum, prefix##_##enum } @@ -1953,13 +2414,7 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,        {DT_RPATH,     "Library rpath"},        {DT_RUNPATH,   "Library runpath"},      }; -    OS << TagNames.at(Type) << ": "; -    if (DynamicStringTable.empty()) -      OS << "<String table is empty or was not found> "; -    else if (Value < DynamicStringTable.size()) -      OS << "[" << StringRef(DynamicStringTable.data() + Value) << "]"; -    else -      OS << "<Invalid offset 0x" << utohexstr(Value) << ">"; +    OS << TagNames.at(Type) << ": [" << getDynamicString(Value) << "]";      break;    }    case DT_FLAGS: @@ -1974,6 +2429,15 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,    }  } +template <class ELFT> +std::string ELFDumper<ELFT>::getDynamicString(uint64_t Value) const { +  if (DynamicStringTable.empty()) +    return "<String table is empty or was not found>"; +  if (Value < DynamicStringTable.size()) +    return DynamicStringTable.data() + Value; +  return Twine("<Invalid offset 0x" + utohexstr(Value) + ">").str(); +} +  template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() {    DwarfCFIEH::PrinterContext<ELFT> Ctx(W, ObjF);    Ctx.printUnwindInformation(); @@ -1985,7 +2449,8 @@ template <> void ELFDumper<ELF32LE>::printUnwindInfo() {    const ELFFile<ELF32LE> *Obj = ObjF->getELFFile();    const unsigned Machine = Obj->getHeader()->e_machine;    if (Machine == EM_ARM) { -    ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, DotSymtabSec); +    ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, ObjF->getFileName(), +                                            DotSymtabSec);      Ctx.PrintUnwindInformation();    }    DwarfCFIEH::PrinterContext<ELF32LE> Ctx(W, ObjF); @@ -2001,17 +2466,10 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicTable() {  template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() {    ListScope D(W, "NeededLibraries"); -  using LibsTy = std::vector<StringRef>; -  LibsTy Libs; - +  std::vector<std::string> Libs;    for (const auto &Entry : dynamic_table()) -    if (Entry.d_tag == ELF::DT_NEEDED) { -      uint64_t Value = Entry.d_un.d_val; -      if (Value < DynamicStringTable.size()) -        Libs.push_back(StringRef(DynamicStringTable.data() + Value)); -      else -        Libs.push_back("<Library name index out of range>"); -    } +    if (Entry.d_tag == ELF::DT_NEEDED) +      Libs.push_back(getDynamicString(Entry.d_un.d_val));    llvm::stable_sort(Libs); @@ -2042,7 +2500,7 @@ template <typename ELFT> void ELFDumper<ELFT>::printGnuHashTable() {    Elf_Sym_Range Syms = dynamic_symbols();    unsigned NumSyms = std::distance(Syms.begin(), Syms.end());    if (!NumSyms) -    reportError("No dynamic symbol section"); +    reportError(createError("No dynamic symbol section"), ObjF->getFileName());    W.printHexList("Values", GnuHashTable->values(NumSyms));  } @@ -2050,6 +2508,30 @@ template <typename ELFT> void ELFDumper<ELFT>::printLoadName() {    W.printString("LoadName", SOName);  } +template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() { +  const ELFFile<ELFT> *Obj = ObjF->getELFFile(); +  switch (Obj->getHeader()->e_machine) { +  case EM_ARM: +    printAttributes(); +    break; +  case EM_MIPS: { +    ELFDumperStyle->printMipsABIFlags(ObjF); +    printMipsOptions(); +    printMipsReginfo(); + +    MipsGOTParser<ELFT> Parser(Obj, ObjF->getFileName(), dynamic_table(), +                               dynamic_symbols()); +    if (Parser.hasGot()) +      ELFDumperStyle->printMipsGOT(Parser); +    if (Parser.hasPlt()) +      ELFDumperStyle->printMipsPLT(Parser); +    break; +  } +  default: +    break; +  } +} +  template <class ELFT> void ELFDumper<ELFT>::printAttributes() {    W.startLine() << "Attributes not implemented.\n";  } @@ -2064,11 +2546,13 @@ template <> void ELFDumper<ELF32LE>::printAttributes() {    }    DictScope BA(W, "BuildAttributes"); -  for (const ELFO::Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { +  for (const ELFO::Elf_Shdr &Sec : +       unwrapOrError(ObjF->getFileName(), Obj->sections())) {      if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES)        continue; -    ArrayRef<uint8_t> Contents = unwrapOrError(Obj->getSectionContents(&Sec)); +    ArrayRef<uint8_t> Contents = +        unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(&Sec));      if (Contents[0] != ARMBuildAttrs::Format_Version) {        errs() << "unrecognised FormatVersion: 0x"               << Twine::utohexstr(Contents[0]) << '\n'; @@ -2092,7 +2576,8 @@ public:    const bool IsStatic;    const ELFO * const Obj; -  MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, Elf_Sym_Range DynSyms); +  MipsGOTParser(const ELFO *Obj, StringRef FileName, Elf_Dyn_Range DynTable, +                Elf_Sym_Range DynSyms);    bool hasGot() const { return !GotEntries.empty(); }    bool hasPlt() const { return !PltEntries.empty(); } @@ -2126,6 +2611,8 @@ private:    const Elf_Shdr *PltSec;    const Elf_Shdr *PltRelSec;    const Elf_Shdr *PltSymTable; +  StringRef FileName; +    Elf_Sym_Range GotDynSyms;    StringRef PltStrTable; @@ -2136,21 +2623,24 @@ private:  } // end anonymous namespace  template <class ELFT> -MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, +MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName, +                                   Elf_Dyn_Range DynTable,                                     Elf_Sym_Range DynSyms)      : IsStatic(DynTable.empty()), Obj(Obj), GotSec(nullptr), LocalNum(0), -      GlobalNum(0), PltSec(nullptr), PltRelSec(nullptr), PltSymTable(nullptr) { +      GlobalNum(0), PltSec(nullptr), PltRelSec(nullptr), PltSymTable(nullptr), +      FileName(FileName) {    // See "Global Offset Table" in Chapter 5 in the following document    // for detailed GOT description.    // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf    // Find static GOT secton.    if (IsStatic) { -    GotSec = findSectionByName(*Obj, ".got"); +    GotSec = findSectionByName(*Obj, FileName, ".got");      if (!GotSec) -      reportError("Cannot find .got section"); +      return; -    ArrayRef<uint8_t> Content = unwrapOrError(Obj->getSectionContents(GotSec)); +    ArrayRef<uint8_t> Content = +        unwrapOrError(FileName, Obj->getSectionContents(GotSec));      GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),                           Content.size() / sizeof(Entry));      LocalNum = GotEntries.size(); @@ -2194,17 +2684,21 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable,      size_t DynSymTotal = DynSyms.size();      if (*DtGotSym > DynSymTotal) -      reportError("MIPS_GOTSYM exceeds a number of dynamic symbols"); +      reportError( +          createError("MIPS_GOTSYM exceeds a number of dynamic symbols"), +          FileName); -    GotSec = findNotEmptySectionByAddress(Obj, *DtPltGot); +    GotSec = findNotEmptySectionByAddress(Obj, FileName, *DtPltGot);      if (!GotSec) -      reportError("There is no not empty GOT section at 0x" + -                  Twine::utohexstr(*DtPltGot)); +      reportError(createError("There is no not empty GOT section at 0x" + +                              Twine::utohexstr(*DtPltGot)), +                  FileName);      LocalNum = *DtLocalGotNum;      GlobalNum = DynSymTotal - *DtGotSym; -    ArrayRef<uint8_t> Content = unwrapOrError(Obj->getSectionContents(GotSec)); +    ArrayRef<uint8_t> Content = +        unwrapOrError(FileName, Obj->getSectionContents(GotSec));      GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),                           Content.size() / sizeof(Entry));      GotDynSyms = DynSyms.drop_front(*DtGotSym); @@ -2217,23 +2711,24 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable,      if (!DtJmpRel)        report_fatal_error("Cannot find JMPREL dynamic table tag."); -    PltSec = findNotEmptySectionByAddress(Obj, *DtMipsPltGot); +    PltSec = findNotEmptySectionByAddress(Obj, FileName, * DtMipsPltGot);      if (!PltSec)        report_fatal_error("There is no not empty PLTGOT section at 0x " +                           Twine::utohexstr(*DtMipsPltGot)); -    PltRelSec = findNotEmptySectionByAddress(Obj, *DtJmpRel); +    PltRelSec = findNotEmptySectionByAddress(Obj, FileName, * DtJmpRel);      if (!PltRelSec)        report_fatal_error("There is no not empty RELPLT section at 0x" +                           Twine::utohexstr(*DtJmpRel));      ArrayRef<uint8_t> PltContent = -        unwrapOrError(Obj->getSectionContents(PltSec)); +        unwrapOrError(FileName, Obj->getSectionContents(PltSec));      PltEntries = Entries(reinterpret_cast<const Entry *>(PltContent.data()),                           PltContent.size() / sizeof(Entry)); -    PltSymTable = unwrapOrError(Obj->getSection(PltRelSec->sh_link)); -    PltStrTable = unwrapOrError(Obj->getStringTableForSymtab(*PltSymTable)); +    PltSymTable = unwrapOrError(FileName, Obj->getSection(PltRelSec->sh_link)); +    PltStrTable = +        unwrapOrError(FileName, Obj->getStringTableForSymtab(*PltSymTable));    }  } @@ -2334,26 +2829,16 @@ const typename MipsGOTParser<ELFT>::Elf_Sym *  MipsGOTParser<ELFT>::getPltSym(const Entry *E) const {    int64_t Offset = std::distance(getPltEntries().data(), E);    if (PltRelSec->sh_type == ELF::SHT_REL) { -    Elf_Rel_Range Rels = unwrapOrError(Obj->rels(PltRelSec)); -    return unwrapOrError(Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); +    Elf_Rel_Range Rels = unwrapOrError(FileName, Obj->rels(PltRelSec)); +    return unwrapOrError(FileName, +                         Obj->getRelocationSymbol(&Rels[Offset], PltSymTable));    } else { -    Elf_Rela_Range Rels = unwrapOrError(Obj->relas(PltRelSec)); -    return unwrapOrError(Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); +    Elf_Rela_Range Rels = unwrapOrError(FileName, Obj->relas(PltRelSec)); +    return unwrapOrError(FileName, +                         Obj->getRelocationSymbol(&Rels[Offset], PltSymTable));    }  } -template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { -  const ELFFile<ELFT> *Obj = ObjF->getELFFile(); -  if (Obj->getHeader()->e_machine != EM_MIPS) -    reportError("MIPS PLT GOT is available for MIPS targets only"); - -  MipsGOTParser<ELFT> Parser(Obj, dynamic_table(), dynamic_symbols()); -  if (Parser.hasGot()) -    ELFDumperStyle->printMipsGOT(Parser); -  if (Parser.hasPlt()) -    ELFDumperStyle->printMipsPLT(Parser); -} -  static const EnumEntry<unsigned> ElfMipsISAExtType[] = {    {"None",                    Mips::AFL_EXT_NONE},    {"Broadcom SB-1",           Mips::AFL_EXT_SB1}, @@ -2427,41 +2912,6 @@ static int getMipsRegisterSize(uint8_t Flag) {    }  } -template <class ELFT> void ELFDumper<ELFT>::printMipsABIFlags() { -  const ELFFile<ELFT> *Obj = ObjF->getELFFile(); -  const Elf_Shdr *Shdr = findSectionByName(*Obj, ".MIPS.abiflags"); -  if (!Shdr) { -    W.startLine() << "There is no .MIPS.abiflags section in the file.\n"; -    return; -  } -  ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr)); -  if (Sec.size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) { -    W.startLine() << "The .MIPS.abiflags section has a wrong size.\n"; -    return; -  } - -  auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec.data()); - -  raw_ostream &OS = W.getOStream(); -  DictScope GS(W, "MIPS ABI Flags"); - -  W.printNumber("Version", Flags->version); -  W.startLine() << "ISA: "; -  if (Flags->isa_rev <= 1) -    OS << format("MIPS%u", Flags->isa_level); -  else -    OS << format("MIPS%ur%u", Flags->isa_level, Flags->isa_rev); -  OS << "\n"; -  W.printEnum("ISA Extension", Flags->isa_ext, makeArrayRef(ElfMipsISAExtType)); -  W.printFlags("ASEs", Flags->ases, makeArrayRef(ElfMipsASEFlags)); -  W.printEnum("FP ABI", Flags->fp_abi, makeArrayRef(ElfMipsFpABIType)); -  W.printNumber("GPR size", getMipsRegisterSize(Flags->gpr_size)); -  W.printNumber("CPR1 size", getMipsRegisterSize(Flags->cpr1_size)); -  W.printNumber("CPR2 size", getMipsRegisterSize(Flags->cpr2_size)); -  W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1)); -  W.printHex("Flags 2", Flags->flags2); -} -  template <class ELFT>  static void printMipsReginfoData(ScopedPrinter &W,                                   const Elf_Mips_RegInfo<ELFT> &Reginfo) { @@ -2475,12 +2925,13 @@ static void printMipsReginfoData(ScopedPrinter &W,  template <class ELFT> void ELFDumper<ELFT>::printMipsReginfo() {    const ELFFile<ELFT> *Obj = ObjF->getELFFile(); -  const Elf_Shdr *Shdr = findSectionByName(*Obj, ".reginfo"); +  const Elf_Shdr *Shdr = findSectionByName(*Obj, ObjF->getFileName(), ".reginfo");    if (!Shdr) {      W.startLine() << "There is no .reginfo section in the file.\n";      return;    } -  ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr)); +  ArrayRef<uint8_t> Sec = +      unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr));    if (Sec.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) {      W.startLine() << "The .reginfo section has a wrong size.\n";      return; @@ -2493,7 +2944,8 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsReginfo() {  template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() {    const ELFFile<ELFT> *Obj = ObjF->getELFFile(); -  const Elf_Shdr *Shdr = findSectionByName(*Obj, ".MIPS.options"); +  const Elf_Shdr *Shdr = +      findSectionByName(*Obj, ObjF->getFileName(), ".MIPS.options");    if (!Shdr) {      W.startLine() << "There is no .MIPS.options section in the file.\n";      return; @@ -2501,7 +2953,8 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() {    DictScope GS(W, "MIPS Options"); -  ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr)); +  ArrayRef<uint8_t> Sec = +      unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr));    while (!Sec.empty()) {      if (Sec.size() < sizeof(Elf_Mips_Options<ELFT>)) {        W.startLine() << "The .MIPS.options section has a wrong size.\n"; @@ -2524,8 +2977,9 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() {  template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {    const ELFFile<ELFT> *Obj = ObjF->getELFFile();    const Elf_Shdr *StackMapSection = nullptr; -  for (const auto &Sec : unwrapOrError(Obj->sections())) { -    StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); +  for (const auto &Sec : unwrapOrError(ObjF->getFileName(), Obj->sections())) { +    StringRef Name = +        unwrapOrError(ObjF->getFileName(), Obj->getSectionName(&Sec));      if (Name == ".llvm_stackmaps") {        StackMapSection = &Sec;        break; @@ -2535,8 +2989,8 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {    if (!StackMapSection)      return; -  ArrayRef<uint8_t> StackMapContentsArray = -      unwrapOrError(Obj->getSectionContents(StackMapSection)); +  ArrayRef<uint8_t> StackMapContentsArray = unwrapOrError( +      ObjF->getFileName(), Obj->getSectionContents(StackMapSection));    prettyPrintStackMap(        W, StackMapParser<ELFT::TargetEndianness>(StackMapContentsArray)); @@ -2560,24 +3014,26 @@ static inline void printFields(formatted_raw_ostream &OS, StringRef Str1,  }  template <class ELFT> -static std::string getSectionHeadersNumString(const ELFFile<ELFT> *Obj) { +static std::string getSectionHeadersNumString(const ELFFile<ELFT> *Obj, +                                              StringRef FileName) {    const typename ELFT::Ehdr *ElfHeader = Obj->getHeader();    if (ElfHeader->e_shnum != 0)      return to_string(ElfHeader->e_shnum); -  ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(Obj->sections()); +  ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(FileName, Obj->sections());    if (Arr.empty())      return "0";    return "0 (" + to_string(Arr[0].sh_size) + ")";  }  template <class ELFT> -static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj) { +static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj, +                                                    StringRef FileName) {    const typename ELFT::Ehdr *ElfHeader = Obj->getHeader();    if (ElfHeader->e_shstrndx != SHN_XINDEX)      return to_string(ElfHeader->e_shstrndx); -  ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(Obj->sections()); +  ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(FileName, Obj->sections());    if (Arr.empty())      return "65535 (corrupt: out of range)";    return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) + @@ -2605,8 +3061,8 @@ template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) {    OS << "\n";    Str = printEnum(e->e_ident[ELF::EI_OSABI], makeArrayRef(ElfOSABI));    printFields(OS, "OS/ABI:", Str); -  Str = "0x" + to_hexString(e->e_ident[ELF::EI_ABIVERSION]); -  printFields(OS, "ABI Version:", Str); +  printFields(OS, +              "ABI Version:", std::to_string(e->e_ident[ELF::EI_ABIVERSION]));    Str = printEnum(e->e_type, makeArrayRef(ElfObjectFileType));    printFields(OS, "Type:", Str);    Str = printEnum(e->e_machine, makeArrayRef(ElfMachineType)); @@ -2639,9 +3095,9 @@ template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) {    printFields(OS, "Number of program headers:", Str);    Str = to_string(e->e_shentsize) + " (bytes)";    printFields(OS, "Size of section headers:", Str); -  Str = getSectionHeadersNumString(Obj); +  Str = getSectionHeadersNumString(Obj, this->FileName);    printFields(OS, "Number of section headers:", Str); -  Str = getSectionHeaderTableIndexString(Obj); +  Str = getSectionHeaderTableIndexString(Obj, this->FileName);    printFields(OS, "Section header string table index:", Str);  } @@ -2663,26 +3119,29 @@ struct GroupSection {  };  template <class ELFT> -std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) { +std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj, +                                    StringRef FileName) {    using Elf_Shdr = typename ELFT::Shdr;    using Elf_Sym = typename ELFT::Sym;    using Elf_Word = typename ELFT::Word;    std::vector<GroupSection> Ret;    uint64_t I = 0; -  for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { +  for (const Elf_Shdr &Sec : unwrapOrError(FileName, Obj->sections())) {      ++I;      if (Sec.sh_type != ELF::SHT_GROUP)        continue; -    const Elf_Shdr *Symtab = unwrapOrError(Obj->getSection(Sec.sh_link)); -    StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); -    const Elf_Sym *Sym = -        unwrapOrError(Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); -    auto Data = -        unwrapOrError(Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); +    const Elf_Shdr *Symtab = +        unwrapOrError(FileName, Obj->getSection(Sec.sh_link)); +    StringRef StrTable = +        unwrapOrError(FileName, Obj->getStringTableForSymtab(*Symtab)); +    const Elf_Sym *Sym = unwrapOrError( +        FileName, Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); +    auto Data = unwrapOrError( +        FileName, Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); -    StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); +    StringRef Name = unwrapOrError(FileName, Obj->getSectionName(&Sec));      StringRef Signature = StrTable.data() + Sym->st_name;      Ret.push_back({Name,                     maybeDemangle(Signature), @@ -2695,8 +3154,8 @@ std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) {      std::vector<GroupMember> &GM = Ret.back().Members;      for (uint32_t Ndx : Data.slice(1)) { -      auto Sec = unwrapOrError(Obj->getSection(Ndx)); -      const StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); +      auto Sec = unwrapOrError(FileName, Obj->getSection(Ndx)); +      const StringRef Name = unwrapOrError(FileName, Obj->getSectionName(Sec));        GM.push_back({Name, Ndx});      }    } @@ -2715,7 +3174,7 @@ mapSectionsToGroups(ArrayRef<GroupSection> Groups) {  } // namespace  template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { -  std::vector<GroupSection> V = getGroups<ELFT>(Obj); +  std::vector<GroupSection> V = getGroups<ELFT>(Obj, this->FileName);    DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V);    for (const GroupSection &G : V) {      OS << "\n" @@ -2745,14 +3204,17 @@ template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) {  template <class ELFT>  void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,                                       const Elf_Rela &R, bool IsRela) { -  const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&R, SymTab)); +  const Elf_Sym *Sym = +      unwrapOrError(this->FileName, Obj->getRelocationSymbol(&R, SymTab));    std::string TargetName;    if (Sym && Sym->getType() == ELF::STT_SECTION) {      const Elf_Shdr *Sec = unwrapOrError( +        this->FileName,          Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable())); -    TargetName = unwrapOrError(Obj->getSectionName(Sec)); +    TargetName = unwrapOrError(this->FileName, Obj->getSectionName(Sec));    } else if (Sym) { -    StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); +    StringRef StrTable = +        unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*SymTab));      TargetName = this->dumper()->getFullSymbolName(          Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);    } @@ -2821,21 +3283,21 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) {  template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {    bool HasRelocSections = false; -  for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { +  for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {      if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA &&          Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_REL &&          Sec.sh_type != ELF::SHT_ANDROID_RELA &&          Sec.sh_type != ELF::SHT_ANDROID_RELR)        continue;      HasRelocSections = true; -    StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); +    StringRef Name = unwrapOrError(this->FileName, Obj->getSectionName(&Sec));      unsigned Entries = Sec.getEntityCount();      std::vector<Elf_Rela> AndroidRelas;      if (Sec.sh_type == ELF::SHT_ANDROID_REL ||          Sec.sh_type == ELF::SHT_ANDROID_RELA) {        // Android's packed relocation section needs to be unpacked first        // to get the actual number of entries. -      AndroidRelas = unwrapOrError(Obj->android_relas(&Sec)); +      AndroidRelas = unwrapOrError(this->FileName, Obj->android_relas(&Sec));        Entries = AndroidRelas.size();      }      std::vector<Elf_Rela> RelrRelas; @@ -2843,8 +3305,8 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {                             Sec.sh_type == ELF::SHT_ANDROID_RELR)) {        // .relr.dyn relative relocation section needs to be unpacked first        // to get the actual number of entries. -      Elf_Relr_Range Relrs = unwrapOrError(Obj->relrs(&Sec)); -      RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); +      Elf_Relr_Range Relrs = unwrapOrError(this->FileName, Obj->relrs(&Sec)); +      RelrRelas = unwrapOrError(this->FileName, Obj->decode_relrs(Relrs));        Entries = RelrRelas.size();      }      uintX_t Offset = Sec.sh_offset; @@ -2852,10 +3314,11 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {         << to_hexString(Offset, false) << " contains " << Entries         << " entries:\n";      printRelocHeader(Sec.sh_type); -    const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec.sh_link)); +    const Elf_Shdr *SymTab = +        unwrapOrError(this->FileName, Obj->getSection(Sec.sh_link));      switch (Sec.sh_type) {      case ELF::SHT_REL: -      for (const auto &R : unwrapOrError(Obj->rels(&Sec))) { +      for (const auto &R : unwrapOrError(this->FileName, Obj->rels(&Sec))) {          Elf_Rela Rela;          Rela.r_offset = R.r_offset;          Rela.r_info = R.r_info; @@ -2864,13 +3327,13 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {        }        break;      case ELF::SHT_RELA: -      for (const auto &R : unwrapOrError(Obj->relas(&Sec))) +      for (const auto &R : unwrapOrError(this->FileName, Obj->relas(&Sec)))          printRelocation(Obj, SymTab, R, true);        break;      case ELF::SHT_RELR:      case ELF::SHT_ANDROID_RELR:        if (opts::RawRelr) -        for (const auto &R : unwrapOrError(Obj->relrs(&Sec))) +        for (const auto &R : unwrapOrError(this->FileName, Obj->relrs(&Sec)))            OS << to_string(format_hex_no_prefix(R, ELFT::Is64Bits ? 16 : 8))               << "\n";        else @@ -2992,6 +3455,12 @@ static std::string getSectionTypeString(unsigned Arch, unsigned Type) {      return "LLVM_ADDRSIG";    case SHT_LLVM_DEPENDENT_LIBRARIES:      return "LLVM_DEPENDENT_LIBRARIES"; +  case SHT_LLVM_SYMPART: +    return "LLVM_SYMPART"; +  case SHT_LLVM_PART_EHDR: +    return "LLVM_PART_EHDR"; +  case SHT_LLVM_PART_PHDR: +    return "LLVM_PART_PHDR";    // FIXME: Parse processor specific GNU attributes    case SHT_GNU_ATTRIBUTES:      return "ATTRIBUTES"; @@ -3009,30 +3478,29 @@ static std::string getSectionTypeString(unsigned Arch, unsigned Type) {    return "";  } -template <class ELFT> -static StringRef getSectionName(const typename ELFT::Shdr &Sec, -                                const ELFObjectFile<ELFT> &ElfObj, -                                ArrayRef<typename ELFT::Shdr> Sections) { -  const ELFFile<ELFT> &Obj = *ElfObj.getELFFile(); -  uint32_t Index = Obj.getHeader()->e_shstrndx; -  if (Index == ELF::SHN_XINDEX) -    Index = Sections[0].sh_link; -  if (!Index) // no section string table. -    return ""; -  // TODO: Test a case when the sh_link of the section with index 0 is broken. -  if (Index >= Sections.size()) -    reportError(ElfObj.getFileName(), -                createError("section header string table index " + -                            Twine(Index) + " does not exist")); -  StringRef Data = toStringRef(unwrapOrError( -      Obj.template getSectionContentsAsArray<uint8_t>(&Sections[Index]))); -  return unwrapOrError(Obj.getSectionName(&Sec, Data)); +static void printSectionDescription(formatted_raw_ostream &OS, +                                    unsigned EMachine) { +  OS << "Key to Flags:\n"; +  OS << "  W (write), A (alloc), X (execute), M (merge), S (strings), I " +        "(info),\n"; +  OS << "  L (link order), O (extra OS processing required), G (group), T " +        "(TLS),\n"; +  OS << "  C (compressed), x (unknown), o (OS specific), E (exclude),\n"; + +  if (EMachine == EM_X86_64) +    OS << "  l (large), "; +  else if (EMachine == EM_ARM) +    OS << "  y (purecode), "; +  else +    OS << "  "; + +  OS << "p (processor specific)\n";  }  template <class ELFT>  void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {    unsigned Bias = ELFT::Is64Bits ? 0 : 8; -  ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections()); +  ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());    OS << "There are " << to_string(Sections.size())       << " section headers, starting at offset "       << "0x" << to_hexString(Obj->getHeader()->e_shoff, false) << ":\n\n"; @@ -3050,7 +3518,8 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {    size_t SectionIndex = 0;    for (const Elf_Shdr &Sec : Sections) {      Fields[0].Str = to_string(SectionIndex); -    Fields[1].Str = getSectionName(Sec, *ElfObj, Sections); +    Fields[1].Str = unwrapOrError<StringRef>( +        ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler));      Fields[2].Str =          getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type);      Fields[3].Str = @@ -3058,7 +3527,7 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {      Fields[4].Str = to_string(format_hex_no_prefix(Sec.sh_offset, 6));      Fields[5].Str = to_string(format_hex_no_prefix(Sec.sh_size, 6));      Fields[6].Str = to_string(format_hex_no_prefix(Sec.sh_entsize, 2)); -    Fields[7].Str = getGNUFlags(Sec.sh_flags); +    Fields[7].Str = getGNUFlags(Obj->getHeader()->e_machine, Sec.sh_flags);      Fields[8].Str = to_string(Sec.sh_link);      Fields[9].Str = to_string(Sec.sh_info);      Fields[10].Str = to_string(Sec.sh_addralign); @@ -3078,18 +3547,13 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {      OS << "\n";      ++SectionIndex;    } -  OS << "Key to Flags:\n" -     << "  W (write), A (alloc), X (execute), M (merge), S (strings), l " -        "(large)\n" -     << "  I (info), L (link order), G (group), T (TLS), E (exclude),\ - x (unknown)\n" -     << "  O (extra OS processing required) o (OS specific),\ - p (processor specific)\n"; +  printSectionDescription(OS, Obj->getHeader()->e_machine);  }  template <class ELFT>  void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name, -                                        size_t Entries) { +                                        size_t Entries, +                                        bool NonVisibilityBitsUsed) {    if (!Name.empty())      OS << "\nSymbol table '" << Name << "' contains " << Entries         << " entries:\n"; @@ -3097,9 +3561,13 @@ void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name,      OS << "\n Symbol table for image:\n";    if (ELFT::Is64Bits) -    OS << "   Num:    Value          Size Type    Bind   Vis      Ndx Name\n"; +    OS << "   Num:    Value          Size Type    Bind   Vis";    else -    OS << "   Num:    Value  Size Type    Bind   Vis      Ndx Name\n"; +    OS << "   Num:    Value  Size Type    Bind   Vis"; + +  if (NonVisibilityBitsUsed) +    OS << "             "; +  OS << "       Ndx Name\n";  }  template <class ELFT> @@ -3114,11 +3582,18 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj,      return "ABS";    case ELF::SHN_COMMON:      return "COM"; -  case ELF::SHN_XINDEX: -    return to_string( -        format_decimal(unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>( -                           Symbol, FirstSym, this->dumper()->getShndxTable())), -                       3)); +  case ELF::SHN_XINDEX: { +    Expected<uint32_t> IndexOrErr = object::getExtendedSymbolTableIndex<ELFT>( +        Symbol, FirstSym, this->dumper()->getShndxTable()); +    if (!IndexOrErr) { +      assert(Symbol->st_shndx == SHN_XINDEX && +             "getSymbolSectionIndex should only fail due to an invalid " +             "SHT_SYMTAB_SHNDX table/reference"); +      this->reportUniqueWarning(IndexOrErr.takeError()); +      return "RSV[0xffff]"; +    } +    return to_string(format_decimal(*IndexOrErr, 3)); +  }    default:      // Find if:      // Processor specific @@ -3142,7 +3617,7 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj,  template <class ELFT>  void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,                                   const Elf_Sym *FirstSym, StringRef StrTable, -                                 bool IsDynamic) { +                                 bool IsDynamic, bool NonVisibilityBitsUsed) {    static int Idx = 0;    static bool Dynamic = true; @@ -3156,7 +3631,7 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,    unsigned Bias = ELFT::Is64Bits ? 8 : 0;    Field Fields[8] = {0,         8,         17 + Bias, 23 + Bias, -                     31 + Bias, 38 + Bias, 47 + Bias, 51 + Bias}; +                     31 + Bias, 38 + Bias, 48 + Bias, 51 + Bias};    Fields[0].Str = to_string(format_decimal(Idx++, 6)) + ":";    Fields[1].Str = to_string(        format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 16 : 8)); @@ -3173,7 +3648,13 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,        printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));    Fields[5].Str =        printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities)); +  if (Symbol->st_other & ~0x3) +    Fields[5].Str += +        " [<other: " + to_string(format_hex(Symbol->st_other, 2)) + ">]"; + +  Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0;    Fields[6].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym); +    Fields[7].Str =        this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);    for (auto &Entry : Fields) @@ -3193,7 +3674,7 @@ void GNUStyle<ELFT>::printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym,    const auto Symbol = FirstSym + Sym;    Fields[2].Str = to_string( -      format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 18 : 8)); +      format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 16 : 8));    Fields[3].Str = to_string(format_decimal(Symbol->st_size, 5));    unsigned char SymbolType = Symbol->getType(); @@ -3246,10 +3727,21 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {      for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) {        if (Buckets[Buc] == ELF::STN_UNDEF)          continue; +      std::vector<bool> Visited(SysVHash->nchain);        for (uint32_t Ch = Buckets[Buc]; Ch < SysVHash->nchain; Ch = Chains[Ch]) {          if (Ch == ELF::STN_UNDEF)            break; + +        if (Visited[Ch]) { +          reportWarning( +              createError(".hash section is invalid: bucket " + Twine(Ch) + +                          ": a cycle was detected in the linked chain"), +              this->FileName); +          break; +        } +          printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc); +        Visited[Ch] = true;        }      }    } @@ -3380,7 +3872,8 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {    unsigned Width = ELFT::Is64Bits ? 18 : 10;    unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7; -  for (const auto &Phdr : unwrapOrError(Obj->program_headers())) { +  for (const auto &Phdr : +       unwrapOrError(this->FileName, Obj->program_headers())) {      Fields[0].Str = getElfPtType(Header->e_machine, Phdr.p_type);      Fields[1].Str = to_string(format_hex(Phdr.p_offset, 8));      Fields[2].Str = to_string(format_hex(Phdr.p_vaddr, Width)); @@ -3404,10 +3897,11 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) {    OS << "\n Section to Segment mapping:\n  Segment Sections...\n";    DenseSet<const Elf_Shdr *> BelongsToSegment;    int Phnum = 0; -  for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { +  for (const Elf_Phdr &Phdr : +       unwrapOrError(this->FileName, Obj->program_headers())) {      std::string Sections;      OS << format("   %2.2d     ", Phnum++); -    for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { +    for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {        // Check if each section is in a segment and then print mapping.        // readelf additionally makes sure it does not print zero sized sections        // at end of segments and for PT_DYNAMIC both start and end of section @@ -3418,7 +3912,9 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) {        if (!TbssInNonTLS && checkTLSSections(Phdr, Sec) &&            checkoffsets(Phdr, Sec) && checkVMA(Phdr, Sec) &&            checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL)) { -        Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + " "; +        Sections += +            unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() + +            " ";          BelongsToSegment.insert(&Sec);        }      } @@ -3428,9 +3924,10 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) {    // Display sections that do not belong to a segment.    std::string Sections; -  for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { +  for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {      if (BelongsToSegment.find(&Sec) == BelongsToSegment.end()) -      Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + ' '; +      Sections += +          unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() + ' ';    }    if (!Sections.empty()) {      OS << "   None  " << Sections << '\n'; @@ -3438,14 +3935,40 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) {    }  } +namespace { +template <class ELFT> struct RelSymbol { +  const typename ELFT::Sym *Sym; +  std::string Name; +}; + +template <class ELFT> +RelSymbol<ELFT> getSymbolForReloc(const ELFFile<ELFT> *Obj, StringRef FileName, +                                  const ELFDumper<ELFT> *Dumper, +                                  const typename ELFT::Rela &Reloc) { +  uint32_t SymIndex = Reloc.getSymbol(Obj->isMips64EL()); +  const typename ELFT::Sym *Sym = Dumper->dynamic_symbols().begin() + SymIndex; +  Expected<StringRef> ErrOrName = Sym->getName(Dumper->getDynamicStringTable()); + +  std::string Name; +  if (ErrOrName) { +    Name = maybeDemangle(*ErrOrName); +  } else { +    reportWarning( +        createError("unable to get name of the dynamic symbol with index " + +                    Twine(SymIndex) + ": " + toString(ErrOrName.takeError())), +        FileName); +    Name = "<corrupt>"; +  } + +  return {Sym, std::move(Name)}; +} +} // namespace +  template <class ELFT>  void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R,                                              bool IsRela) { -  uint32_t SymIndex = R.getSymbol(Obj->isMips64EL()); -  const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; -  std::string SymbolName = maybeDemangle( -      unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()))); -  printRelocation(Obj, Sym, SymbolName, R, IsRela); +  RelSymbol<ELFT> S = getSymbolForReloc(Obj, this->FileName, this->dumper(), R); +  printRelocation(Obj, S.Sym, S.Name, R, IsRela);  }  template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) { @@ -3469,9 +3992,8 @@ template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) {      OS << "  Tag        Type                 Name/Value\n";    for (auto Entry : Table) {      uintX_t Tag = Entry.getTag(); -    std::string TypeString = std::string("(") + -                             getTypeString(Obj->getHeader()->e_machine, Tag) + -                             ")"; +    std::string TypeString = +        std::string("(") + Obj->getDynamicTagAsString(Tag).c_str() + ")";      OS << "  " << format_hex(Tag, Is64 ? 18 : 10)         << format(" %-20s ", TypeString.c_str());      this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal()); @@ -3518,7 +4040,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {         << " contains " << DynRelrRegion.Size << " bytes:\n";      printRelocHeader(ELF::SHT_REL);      Elf_Relr_Range Relrs = this->dumper()->dyn_relrs(); -    std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); +    std::vector<Elf_Rela> RelrRelas = +        unwrapOrError(this->FileName, Obj->decode_relrs(Relrs));      for (const Elf_Rela &Rela : RelrRelas) {        printDynamicRelocation(Obj, Rela, false);      } @@ -3547,17 +4070,29 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {  }  template <class ELFT> -static void printGNUVersionSectionProlog(formatted_raw_ostream &OS, -                                         const Twine &Name, unsigned EntriesNum, -                                         const ELFFile<ELFT> *Obj, -                                         const typename ELFT::Shdr *Sec) { -  StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); -  OS << Name << " section '" << SecName << "' " +void GNUStyle<ELFT>::printGNUVersionSectionProlog( +    const ELFFile<ELFT> *Obj, const typename ELFT::Shdr *Sec, +    const Twine &Label, unsigned EntriesNum) { +  StringRef SecName = unwrapOrError(this->FileName, Obj->getSectionName(Sec)); +  OS << Label << " section '" << SecName << "' "       << "contains " << EntriesNum << " entries:\n"; -  const typename ELFT::Shdr *SymTab = -      unwrapOrError(Obj->getSection(Sec->sh_link)); -  StringRef SymTabName = unwrapOrError(Obj->getSectionName(SymTab)); +  unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); +  StringRef SymTabName = "<corrupt>"; + +  Expected<const typename ELFT::Shdr *> SymTabOrErr = +      Obj->getSection(Sec->sh_link); +  if (SymTabOrErr) +    SymTabName = +        unwrapOrError(this->FileName, Obj->getSectionName(*SymTabOrErr)); +  else +    this->reportUniqueWarning( +        createError("invalid section linked to " + +                    object::getELFSectionTypeName(Obj->getHeader()->e_machine, +                                                  Sec->sh_type) + +                    " section with index " + Twine(SecNdx) + ": " + +                    toString(SymTabOrErr.takeError()))); +    OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16)       << "  Offset: " << format_hex(Sec->sh_offset, 8)       << "  Link: " << Sec->sh_link << " (" << SymTabName << ")\n"; @@ -3569,45 +4104,51 @@ void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,    if (!Sec)      return; -  unsigned Entries = Sec->sh_size / sizeof(Elf_Versym); -  printGNUVersionSectionProlog(OS, "Version symbols", Entries, Obj, Sec); +  printGNUVersionSectionProlog(Obj, Sec, "Version symbols", +                               Sec->sh_size / sizeof(Elf_Versym)); +  Expected<ArrayRef<Elf_Versym>> VerTableOrErr = +      this->dumper()->getVersionTable(Sec, /*SymTab=*/nullptr, +                                      /*StrTab=*/nullptr); +  if (!VerTableOrErr) { +    this->reportUniqueWarning(VerTableOrErr.takeError()); +    return; +  } -  const uint8_t *VersymBuf = -      reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); -  const ELFDumper<ELFT> *Dumper = this->dumper(); -  StringRef StrTable = Dumper->getDynamicStringTable(); +  ArrayRef<Elf_Versym> VerTable = *VerTableOrErr; +  std::vector<StringRef> Versions; +  for (size_t I = 0, E = VerTable.size(); I < E; ++I) { +    unsigned Ndx = VerTable[I].vs_index; +    if (Ndx == VER_NDX_LOCAL || Ndx == VER_NDX_GLOBAL) { +      Versions.emplace_back(Ndx == VER_NDX_LOCAL ? "*local*" : "*global*"); +      continue; +    } + +    bool IsDefault; +    Expected<StringRef> NameOrErr = +        this->dumper()->getSymbolVersionByIndex(Ndx, IsDefault); +    if (!NameOrErr) { +      if (!NameOrErr) { +        unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); +        this->reportUniqueWarning(createError( +            "unable to get a version for entry " + Twine(I) + +            " of SHT_GNU_versym section with index " + Twine(SecNdx) + ": " + +            toString(NameOrErr.takeError()))); +      } +      Versions.emplace_back("<corrupt>"); +      continue; +    } +    Versions.emplace_back(*NameOrErr); +  }    // readelf prints 4 entries per line. +  uint64_t Entries = VerTable.size();    for (uint64_t VersymRow = 0; VersymRow < Entries; VersymRow += 4) {      OS << "  " << format_hex_no_prefix(VersymRow, 3) << ":"; - -    for (uint64_t VersymIndex = 0; -         (VersymIndex < 4) && (VersymIndex + VersymRow) < Entries; -         ++VersymIndex) { -      const Elf_Versym *Versym = -          reinterpret_cast<const Elf_Versym *>(VersymBuf); -      switch (Versym->vs_index) { -      case 0: -        OS << "   0 (*local*)    "; -        break; -      case 1: -        OS << "   1 (*global*)   "; -        break; -      default: -        OS << format("%4x%c", Versym->vs_index & VERSYM_VERSION, -                     Versym->vs_index & VERSYM_HIDDEN ? 'h' : ' '); - -        bool IsDefault = true; -        std::string VersionName = Dumper->getSymbolVersionByIndex( -            StrTable, Versym->vs_index, IsDefault); - -        if (!VersionName.empty()) -          VersionName = "(" + VersionName + ")"; -        else -          VersionName = "(*invalid*)"; -        OS << left_justify(VersionName, 13); -      } -      VersymBuf += sizeof(Elf_Versym); +    for (uint64_t I = 0; (I < 4) && (I + VersymRow) < Entries; ++I) { +      unsigned Ndx = VerTable[VersymRow + I].vs_index; +      OS << format("%4x%c", Ndx & VERSYM_VERSION, +                   Ndx & VERSYM_HIDDEN ? 'h' : ' '); +      OS << left_justify("(" + std::string(Versions[VersymRow + I]) + ")", 13);      }      OS << '\n';    } @@ -3641,39 +4182,25 @@ void GNUStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj,    if (!Sec)      return; -  unsigned VerDefsNum = Sec->sh_info; -  printGNUVersionSectionProlog(OS, "Version definition", VerDefsNum, Obj, Sec); - -  const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link)); -  StringRef StringTable( -      reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset), -      (size_t)StrTabSec->sh_size); - -  const uint8_t *VerdefBuf = unwrapOrError(Obj->getSectionContents(Sec)).data(); -  const uint8_t *Begin = VerdefBuf; - -  while (VerDefsNum--) { -    const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); -    OS << format("  0x%04x: Rev: %u  Flags: %s  Index: %u  Cnt: %u", -                 VerdefBuf - Begin, (unsigned)Verdef->vd_version, -                 versionFlagToString(Verdef->vd_flags).c_str(), -                 (unsigned)Verdef->vd_ndx, (unsigned)Verdef->vd_cnt); - -    const uint8_t *VerdauxBuf = VerdefBuf + Verdef->vd_aux; -    const Elf_Verdaux *Verdaux = -        reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); -    OS << format("  Name: %s\n", -                 StringTable.drop_front(Verdaux->vda_name).data()); - -    for (unsigned I = 1; I < Verdef->vd_cnt; ++I) { -      VerdauxBuf += Verdaux->vda_next; -      Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); -      OS << format("  0x%04x: Parent %u: %s\n", VerdauxBuf - Begin, I, -                   StringTable.drop_front(Verdaux->vda_name).data()); -    } +  printGNUVersionSectionProlog(Obj, Sec, "Version definition", Sec->sh_info); -    VerdefBuf += Verdef->vd_next; +  Expected<std::vector<VerDef>> V = this->dumper()->getVersionDefinitions(Sec); +  if (!V) { +    this->reportUniqueWarning(V.takeError()); +    return;    } + +  for (const VerDef &Def : *V) { +    OS << format("  0x%04x: Rev: %u  Flags: %s  Index: %u  Cnt: %u  Name: %s\n", +                 Def.Offset, Def.Version, +                 versionFlagToString(Def.Flags).c_str(), Def.Ndx, Def.Cnt, +                 Def.Name.data()); +    unsigned I = 0; +    for (const VerdAux &Aux : Def.AuxV) +      OS << format("  0x%04x: Parent %u: %s\n", Aux.Offset, ++I, +                   Aux.Name.data()); +  } +    OS << '\n';  } @@ -3684,39 +4211,22 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,      return;    unsigned VerneedNum = Sec->sh_info; -  printGNUVersionSectionProlog(OS, "Version needs", VerneedNum, Obj, Sec); +  printGNUVersionSectionProlog(Obj, Sec, "Version needs", VerneedNum); -  ArrayRef<uint8_t> SecData = unwrapOrError(Obj->getSectionContents(Sec)); - -  const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link)); -  StringRef StringTable = { -      reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset), -      (size_t)StrTabSec->sh_size}; - -  const uint8_t *VerneedBuf = SecData.data(); -  for (unsigned I = 0; I < VerneedNum; ++I) { -    const Elf_Verneed *Verneed = -        reinterpret_cast<const Elf_Verneed *>(VerneedBuf); - -    OS << format("  0x%04x: Version: %u  File: %s  Cnt: %u\n", -                 reinterpret_cast<const uint8_t *>(Verneed) - SecData.begin(), -                 (unsigned)Verneed->vn_version, -                 StringTable.drop_front(Verneed->vn_file).data(), -                 (unsigned)Verneed->vn_cnt); - -    const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; -    for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { -      const Elf_Vernaux *Vernaux = -          reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); +  Expected<std::vector<VerNeed>> V = +      this->dumper()->getVersionDependencies(Sec); +  if (!V) { +    this->reportUniqueWarning(V.takeError()); +    return; +  } -      OS << format("  0x%04x:   Name: %s  Flags: %s  Version: %u\n", -                   reinterpret_cast<const uint8_t *>(Vernaux) - SecData.begin(), -                   StringTable.drop_front(Vernaux->vna_name).data(), -                   versionFlagToString(Vernaux->vna_flags).c_str(), -                   (unsigned)Vernaux->vna_other); -      VernauxBuf += Vernaux->vna_next; -    } -    VerneedBuf += Verneed->vn_next; +  for (const VerNeed &VN : *V) { +    OS << format("  0x%04x: Version: %u  File: %s  Cnt: %u\n", VN.Offset, +                 VN.Version, VN.File.data(), VN.Cnt); +    for (const VernAux &Aux : VN.AuxV) +      OS << format("  0x%04x:   Name: %s  Flags: %s  Version: %u\n", Aux.Offset, +                   Aux.Name.data(), versionFlagToString(Aux.Flags).c_str(), +                   Aux.Other);    }    OS << '\n';  } @@ -3745,9 +4255,21 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {      // Go over all buckets and and note chain lengths of each bucket (total      // unique chain lengths).      for (size_t B = 0; B < NBucket; B++) { -      for (size_t C = Buckets[B]; C > 0 && C < NChain; C = Chains[C]) +      std::vector<bool> Visited(NChain); +      for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) { +        if (C == ELF::STN_UNDEF) +          break; +        if (Visited[C]) { +          reportWarning( +              createError(".hash section is invalid: bucket " + Twine(C) + +                          ": a cycle was detected in the linked chain"), +              this->FileName); +          break; +        } +        Visited[C] = true;          if (MaxChain <= ++ChainLen[B])            MaxChain++; +      }        TotalSyms += ChainLen[B];      } @@ -3829,7 +4351,7 @@ void GNUStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) {  template <class ELFT>  void GNUStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) { -    OS << "GNUStyle::printAddrsig not implemented\n"; +  reportError(createError("--addrsig: not implemented"), this->FileName);  }  static StringRef getGenericNoteTypeName(const uint32_t NT) { @@ -3850,6 +4372,86 @@ static StringRef getGenericNoteTypeName(const uint32_t NT) {    return "";  } +static StringRef getCoreNoteTypeName(const uint32_t NT) { +  static const struct { +    uint32_t ID; +    const char *Name; +  } Notes[] = { +      {ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"}, +      {ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"}, +      {ELF::NT_PRPSINFO, "NT_PRPSINFO (prpsinfo structure)"}, +      {ELF::NT_TASKSTRUCT, "NT_TASKSTRUCT (task structure)"}, +      {ELF::NT_AUXV, "NT_AUXV (auxiliary vector)"}, +      {ELF::NT_PSTATUS, "NT_PSTATUS (pstatus structure)"}, +      {ELF::NT_FPREGS, "NT_FPREGS (floating point registers)"}, +      {ELF::NT_PSINFO, "NT_PSINFO (psinfo structure)"}, +      {ELF::NT_LWPSTATUS, "NT_LWPSTATUS (lwpstatus_t structure)"}, +      {ELF::NT_LWPSINFO, "NT_LWPSINFO (lwpsinfo_t structure)"}, +      {ELF::NT_WIN32PSTATUS, "NT_WIN32PSTATUS (win32_pstatus structure)"}, + +      {ELF::NT_PPC_VMX, "NT_PPC_VMX (ppc Altivec registers)"}, +      {ELF::NT_PPC_VSX, "NT_PPC_VSX (ppc VSX registers)"}, +      {ELF::NT_PPC_TAR, "NT_PPC_TAR (ppc TAR register)"}, +      {ELF::NT_PPC_PPR, "NT_PPC_PPR (ppc PPR register)"}, +      {ELF::NT_PPC_DSCR, "NT_PPC_DSCR (ppc DSCR register)"}, +      {ELF::NT_PPC_EBB, "NT_PPC_EBB (ppc EBB registers)"}, +      {ELF::NT_PPC_PMU, "NT_PPC_PMU (ppc PMU registers)"}, +      {ELF::NT_PPC_TM_CGPR, "NT_PPC_TM_CGPR (ppc checkpointed GPR registers)"}, +      {ELF::NT_PPC_TM_CFPR, +       "NT_PPC_TM_CFPR (ppc checkpointed floating point registers)"}, +      {ELF::NT_PPC_TM_CVMX, +       "NT_PPC_TM_CVMX (ppc checkpointed Altivec registers)"}, +      {ELF::NT_PPC_TM_CVSX, "NT_PPC_TM_CVSX (ppc checkpointed VSX registers)"}, +      {ELF::NT_PPC_TM_SPR, "NT_PPC_TM_SPR (ppc TM special purpose registers)"}, +      {ELF::NT_PPC_TM_CTAR, "NT_PPC_TM_CTAR (ppc checkpointed TAR register)"}, +      {ELF::NT_PPC_TM_CPPR, "NT_PPC_TM_CPPR (ppc checkpointed PPR register)"}, +      {ELF::NT_PPC_TM_CDSCR, +       "NT_PPC_TM_CDSCR (ppc checkpointed DSCR register)"}, + +      {ELF::NT_386_TLS, "NT_386_TLS (x86 TLS information)"}, +      {ELF::NT_386_IOPERM, "NT_386_IOPERM (x86 I/O permissions)"}, +      {ELF::NT_X86_XSTATE, "NT_X86_XSTATE (x86 XSAVE extended state)"}, + +      {ELF::NT_S390_HIGH_GPRS, +       "NT_S390_HIGH_GPRS (s390 upper register halves)"}, +      {ELF::NT_S390_TIMER, "NT_S390_TIMER (s390 timer register)"}, +      {ELF::NT_S390_TODCMP, "NT_S390_TODCMP (s390 TOD comparator register)"}, +      {ELF::NT_S390_TODPREG, +       "NT_S390_TODPREG (s390 TOD programmable register)"}, +      {ELF::NT_S390_CTRS, "NT_S390_CTRS (s390 control registers)"}, +      {ELF::NT_S390_PREFIX, "NT_S390_PREFIX (s390 prefix register)"}, +      {ELF::NT_S390_LAST_BREAK, +       "NT_S390_LAST_BREAK (s390 last breaking event address)"}, +      {ELF::NT_S390_SYSTEM_CALL, +       "NT_S390_SYSTEM_CALL (s390 system call restart data)"}, +      {ELF::NT_S390_TDB, "NT_S390_TDB (s390 transaction diagnostic block)"}, +      {ELF::NT_S390_VXRS_LOW, +       "NT_S390_VXRS_LOW (s390 vector registers 0-15 upper half)"}, +      {ELF::NT_S390_VXRS_HIGH, +       "NT_S390_VXRS_HIGH (s390 vector registers 16-31)"}, +      {ELF::NT_S390_GS_CB, "NT_S390_GS_CB (s390 guarded-storage registers)"}, +      {ELF::NT_S390_GS_BC, +       "NT_S390_GS_BC (s390 guarded-storage broadcast control)"}, + +      {ELF::NT_ARM_VFP, "NT_ARM_VFP (arm VFP registers)"}, +      {ELF::NT_ARM_TLS, "NT_ARM_TLS (AArch TLS registers)"}, +      {ELF::NT_ARM_HW_BREAK, +       "NT_ARM_HW_BREAK (AArch hardware breakpoint registers)"}, +      {ELF::NT_ARM_HW_WATCH, +       "NT_ARM_HW_WATCH (AArch hardware watchpoint registers)"}, + +      {ELF::NT_FILE, "NT_FILE (mapped files)"}, +      {ELF::NT_PRXFPREG, "NT_PRXFPREG (user_xfpregs structure)"}, +      {ELF::NT_SIGINFO, "NT_SIGINFO (siginfo_t data)"}, +  }; + +  for (const auto &Note : Notes) +    if (Note.ID == NT) +      return Note.Name; + +  return ""; +} +  static std::string getGNUNoteTypeName(const uint32_t NT) {    static const struct {      uint32_t ID; @@ -4207,13 +4809,85 @@ static AMDGPUNote getAMDGPUNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) {    }  } +struct CoreFileMapping { +  uint64_t Start, End, Offset; +  StringRef Filename; +}; + +struct CoreNote { +  uint64_t PageSize; +  std::vector<CoreFileMapping> Mappings; +}; + +static Expected<CoreNote> readCoreNote(DataExtractor Desc) { +  // Expected format of the NT_FILE note description: +  // 1. # of file mappings (call it N) +  // 2. Page size +  // 3. N (start, end, offset) triples +  // 4. N packed filenames (null delimited) +  // Each field is an Elf_Addr, except for filenames which are char* strings. + +  CoreNote Ret; +  const int Bytes = Desc.getAddressSize(); + +  if (!Desc.isValidOffsetForAddress(2)) +    return createStringError(object_error::parse_failed, +                             "malformed note: header too short"); +  if (Desc.getData().back() != 0) +    return createStringError(object_error::parse_failed, +                             "malformed note: not NUL terminated"); + +  uint64_t DescOffset = 0; +  uint64_t FileCount = Desc.getAddress(&DescOffset); +  Ret.PageSize = Desc.getAddress(&DescOffset); + +  if (!Desc.isValidOffsetForAddress(3 * FileCount * Bytes)) +    return createStringError(object_error::parse_failed, +                             "malformed note: too short for number of files"); + +  uint64_t FilenamesOffset = 0; +  DataExtractor Filenames( +      Desc.getData().drop_front(DescOffset + 3 * FileCount * Bytes), +      Desc.isLittleEndian(), Desc.getAddressSize()); + +  Ret.Mappings.resize(FileCount); +  for (CoreFileMapping &Mapping : Ret.Mappings) { +    if (!Filenames.isValidOffsetForDataOfSize(FilenamesOffset, 1)) +      return createStringError(object_error::parse_failed, +                               "malformed note: too few filenames"); +    Mapping.Start = Desc.getAddress(&DescOffset); +    Mapping.End = Desc.getAddress(&DescOffset); +    Mapping.Offset = Desc.getAddress(&DescOffset); +    Mapping.Filename = Filenames.getCStrRef(&FilenamesOffset); +  } + +  return Ret; +} + +template <typename ELFT> +static void printCoreNote(raw_ostream &OS, const CoreNote &Note) { +  // Length of "0x<address>" string. +  const int FieldWidth = ELFT::Is64Bits ? 18 : 10; + +  OS << "    Page size: " << format_decimal(Note.PageSize, 0) << '\n'; +  OS << "    " << right_justify("Start", FieldWidth) << "  " +     << right_justify("End", FieldWidth) << "  " +     << right_justify("Page Offset", FieldWidth) << '\n'; +  for (const CoreFileMapping &Mapping : Note.Mappings) { +    OS << "    " << format_hex(Mapping.Start, FieldWidth) << "  " +       << format_hex(Mapping.End, FieldWidth) << "  " +       << format_hex(Mapping.Offset, FieldWidth) << "\n        " +       << Mapping.Filename << '\n'; +  } +} +  template <class ELFT>  void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {    auto PrintHeader = [&](const typename ELFT::Off Offset,                           const typename ELFT::Addr Size) {      OS << "Displaying notes found at file offset " << format_hex(Offset, 10)         << " with length " << format_hex(Size, 10) << ":\n" -       << "  Owner                 Data size\tDescription\n"; +       << "  Owner                Data size \tDescription\n";    };    auto ProcessNote = [&](const Elf_Note &Note) { @@ -4221,55 +4895,81 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {      ArrayRef<uint8_t> Descriptor = Note.getDesc();      Elf_Word Type = Note.getType(); -    OS << "  " << Name << std::string(22 - Name.size(), ' ') +    // Print the note owner/type. +    OS << "  " << left_justify(Name, 20) << ' '         << format_hex(Descriptor.size(), 10) << '\t'; -      if (Name == "GNU") {        OS << getGNUNoteTypeName(Type) << '\n'; -      printGNUNote<ELFT>(OS, Type, Descriptor);      } else if (Name == "FreeBSD") {        OS << getFreeBSDNoteTypeName(Type) << '\n';      } else if (Name == "AMD") {        OS << getAMDNoteTypeName(Type) << '\n'; +    } else if (Name == "AMDGPU") { +      OS << getAMDGPUNoteTypeName(Type) << '\n'; +    } else { +      StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE +                               ? getCoreNoteTypeName(Type) +                               : getGenericNoteTypeName(Type); +      if (!NoteType.empty()) +        OS << NoteType << '\n'; +      else +        OS << "Unknown note type: (" << format_hex(Type, 10) << ")\n"; +    } + +    // Print the description, or fallback to printing raw bytes for unknown +    // owners. +    if (Name == "GNU") { +      printGNUNote<ELFT>(OS, Type, Descriptor); +    } else if (Name == "AMD") {        const AMDNote N = getAMDNote<ELFT>(Type, Descriptor);        if (!N.Type.empty())          OS << "    " << N.Type << ":\n        " << N.Value << '\n';      } else if (Name == "AMDGPU") { -      OS << getAMDGPUNoteTypeName(Type) << '\n';        const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor);        if (!N.Type.empty())          OS << "    " << N.Type << ":\n        " << N.Value << '\n'; -    } else { -      StringRef NoteType = getGenericNoteTypeName(Type); -      if (!NoteType.empty()) -        OS << NoteType; -      else -        OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; +    } else if (Name == "CORE") { +      if (Type == ELF::NT_FILE) { +        DataExtractor DescExtractor(Descriptor, +                                    ELFT::TargetEndianness == support::little, +                                    sizeof(Elf_Addr)); +        Expected<CoreNote> Note = readCoreNote(DescExtractor); +        if (Note) +          printCoreNote<ELFT>(OS, *Note); +        else +          reportWarning(Note.takeError(), this->FileName); +      } +    } else if (!Descriptor.empty()) { +      OS << "   description data:"; +      for (uint8_t B : Descriptor) +        OS << " " << format("%02x", B); +      OS << '\n';      } -    OS << '\n';    }; -  if (Obj->getHeader()->e_type == ELF::ET_CORE) { -    for (const auto &P : unwrapOrError(Obj->program_headers())) { -      if (P.p_type != PT_NOTE) +  ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections()); +  if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) { +    for (const auto &S : Sections) { +      if (S.sh_type != SHT_NOTE)          continue; -      PrintHeader(P.p_offset, P.p_filesz); +      PrintHeader(S.sh_offset, S.sh_size);        Error Err = Error::success(); -      for (const auto &Note : Obj->notes(P, Err)) +      for (auto Note : Obj->notes(S, Err))          ProcessNote(Note);        if (Err) -        error(std::move(Err)); +        reportError(std::move(Err), this->FileName);      }    } else { -    for (const auto &S : unwrapOrError(Obj->sections())) { -      if (S.sh_type != SHT_NOTE) +    for (const auto &P : +         unwrapOrError(this->FileName, Obj->program_headers())) { +      if (P.p_type != PT_NOTE)          continue; -      PrintHeader(S.sh_offset, S.sh_size); +      PrintHeader(P.p_offset, P.p_filesz);        Error Err = Error::success(); -      for (const auto &Note : Obj->notes(S, Err)) +      for (auto Note : Obj->notes(P, Err))          ProcessNote(Note);        if (Err) -        error(std::move(Err)); +        reportError(std::move(Err), this->FileName);      }    }  } @@ -4280,6 +4980,299 @@ void GNUStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {  }  template <class ELFT> +void GNUStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) { +  OS << "printDependentLibs not implemented!\n"; +} + +// Used for printing section names in places where possible errors can be +// ignored. +static StringRef getSectionName(const SectionRef &Sec) { +  Expected<StringRef> NameOrErr = Sec.getName(); +  if (NameOrErr) +    return *NameOrErr; +  consumeError(NameOrErr.takeError()); +  return "<?>"; +} + +// Used for printing symbol names in places where possible errors can be +// ignored. +static std::string getSymbolName(const ELFSymbolRef &Sym) { +  Expected<StringRef> NameOrErr = Sym.getName(); +  if (NameOrErr) +    return maybeDemangle(*NameOrErr); +  consumeError(NameOrErr.takeError()); +  return "<?>"; +} + +template <class ELFT> +void DumpStyle<ELFT>::printFunctionStackSize( +    const ELFObjectFile<ELFT> *Obj, uint64_t SymValue, SectionRef FunctionSec, +    const StringRef SectionName, DataExtractor Data, uint64_t *Offset) { +  // This function ignores potentially erroneous input, unless it is directly +  // related to stack size reporting. +  SymbolRef FuncSym; +  for (const ELFSymbolRef &Symbol : Obj->symbols()) { +    Expected<uint64_t> SymAddrOrErr = Symbol.getAddress(); +    if (!SymAddrOrErr) { +      consumeError(SymAddrOrErr.takeError()); +      continue; +    } +    if (Symbol.getELFType() == ELF::STT_FUNC && *SymAddrOrErr == SymValue) { +      // Check if the symbol is in the right section. +      if (FunctionSec.containsSymbol(Symbol)) { +        FuncSym = Symbol; +        break; +      } +    } +  } + +  std::string FuncName = "?"; +  // A valid SymbolRef has a non-null object file pointer. +  if (FuncSym.BasicSymbolRef::getObject()) +    FuncName = getSymbolName(FuncSym); +  else +    reportWarning( +        createError("could not identify function symbol for stack size entry"), +        Obj->getFileName()); + +  // Extract the size. The expectation is that Offset is pointing to the right +  // place, i.e. past the function address. +  uint64_t PrevOffset = *Offset; +  uint64_t StackSize = Data.getULEB128(Offset); +  // getULEB128() does not advance Offset if it is not able to extract a valid +  // integer. +  if (*Offset == PrevOffset) +    reportError( +        createStringError(object_error::parse_failed, +                          "could not extract a valid stack size in section %s", +                          SectionName.data()), +        Obj->getFileName()); + +  printStackSizeEntry(StackSize, FuncName); +} + +template <class ELFT> +void GNUStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) { +  OS.PadToColumn(2); +  OS << format_decimal(Size, 11); +  OS.PadToColumn(18); +  OS << FuncName << "\n"; +} + +template <class ELFT> +void DumpStyle<ELFT>::printStackSize(const ELFObjectFile<ELFT> *Obj, +                                     RelocationRef Reloc, +                                     SectionRef FunctionSec, +                                     const StringRef &StackSizeSectionName, +                                     const RelocationResolver &Resolver, +                                     DataExtractor Data) { +  // This function ignores potentially erroneous input, unless it is directly +  // related to stack size reporting. +  object::symbol_iterator RelocSym = Reloc.getSymbol(); +  uint64_t RelocSymValue = 0; +  StringRef FileStr = Obj->getFileName(); +  if (RelocSym != Obj->symbol_end()) { +    // Ensure that the relocation symbol is in the function section, i.e. the +    // section where the functions whose stack sizes we are reporting are +    // located. +    auto SectionOrErr = RelocSym->getSection(); +    if (!SectionOrErr) { +      reportWarning( +          createError("cannot identify the section for relocation symbol '" + +                      getSymbolName(*RelocSym) + "'"), +          FileStr); +      consumeError(SectionOrErr.takeError()); +    } else if (*SectionOrErr != FunctionSec) { +      reportWarning(createError("relocation symbol '" + +                                getSymbolName(*RelocSym) + +                                "' is not in the expected section"), +                    FileStr); +      // Pretend that the symbol is in the correct section and report its +      // stack size anyway. +      FunctionSec = **SectionOrErr; +    } + +    Expected<uint64_t> RelocSymValueOrErr = RelocSym->getValue(); +    if (RelocSymValueOrErr) +      RelocSymValue = *RelocSymValueOrErr; +    else +      consumeError(RelocSymValueOrErr.takeError()); +  } + +  uint64_t Offset = Reloc.getOffset(); +  if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1)) +    reportError( +        createStringError(object_error::parse_failed, +                          "found invalid relocation offset into section %s " +                          "while trying to extract a stack size entry", +                          StackSizeSectionName.data()), +        FileStr); + +  uint64_t Addend = Data.getAddress(&Offset); +  uint64_t SymValue = Resolver(Reloc, RelocSymValue, Addend); +  this->printFunctionStackSize(Obj, SymValue, FunctionSec, StackSizeSectionName, +                               Data, &Offset); +} + +template <class ELFT> +void DumpStyle<ELFT>::printNonRelocatableStackSizes( +    const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) { +  // This function ignores potentially erroneous input, unless it is directly +  // related to stack size reporting. +  const ELFFile<ELFT> *EF = Obj->getELFFile(); +  StringRef FileStr = Obj->getFileName(); +  for (const SectionRef &Sec : Obj->sections()) { +    StringRef SectionName = getSectionName(Sec); +    if (SectionName != ".stack_sizes") +      continue; +    PrintHeader(); +    const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl()); +    ArrayRef<uint8_t> Contents = +        unwrapOrError(this->FileName, EF->getSectionContents(ElfSec)); +    DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr)); +    // A .stack_sizes section header's sh_link field is supposed to point +    // to the section that contains the functions whose stack sizes are +    // described in it. +    const Elf_Shdr *FunctionELFSec = +        unwrapOrError(this->FileName, EF->getSection(ElfSec->sh_link)); +    uint64_t Offset = 0; +    while (Offset < Contents.size()) { +      // The function address is followed by a ULEB representing the stack +      // size. Check for an extra byte before we try to process the entry. +      if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1)) { +        reportError( +            createStringError( +                object_error::parse_failed, +                "section %s ended while trying to extract a stack size entry", +                SectionName.data()), +            FileStr); +      } +      uint64_t SymValue = Data.getAddress(&Offset); +      printFunctionStackSize(Obj, SymValue, Obj->toSectionRef(FunctionELFSec), +                             SectionName, Data, &Offset); +    } +  } +} + +template <class ELFT> +void DumpStyle<ELFT>::printRelocatableStackSizes( +    const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) { +  const ELFFile<ELFT> *EF = Obj->getELFFile(); + +  // Build a map between stack size sections and their corresponding relocation +  // sections. +  llvm::MapVector<SectionRef, SectionRef> StackSizeRelocMap; +  const SectionRef NullSection{}; + +  for (const SectionRef &Sec : Obj->sections()) { +    StringRef SectionName; +    if (Expected<StringRef> NameOrErr = Sec.getName()) +      SectionName = *NameOrErr; +    else +      consumeError(NameOrErr.takeError()); + +    // A stack size section that we haven't encountered yet is mapped to the +    // null section until we find its corresponding relocation section. +    if (SectionName == ".stack_sizes") +      if (StackSizeRelocMap.count(Sec) == 0) { +        StackSizeRelocMap[Sec] = NullSection; +        continue; +      } + +    // Check relocation sections if they are relocating contents of a +    // stack sizes section. +    const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl()); +    uint32_t SectionType = ElfSec->sh_type; +    if (SectionType != ELF::SHT_RELA && SectionType != ELF::SHT_REL) +      continue; + +    Expected<section_iterator> RelSecOrErr = Sec.getRelocatedSection(); +    if (!RelSecOrErr) +      reportError(createStringError(object_error::parse_failed, +                                    "%s: failed to get a relocated section: %s", +                                    SectionName.data(), +                                    toString(RelSecOrErr.takeError()).c_str()), +                  Obj->getFileName()); + +    const Elf_Shdr *ContentsSec = +        Obj->getSection((*RelSecOrErr)->getRawDataRefImpl()); +    Expected<StringRef> ContentsSectionNameOrErr = +        EF->getSectionName(ContentsSec); +    if (!ContentsSectionNameOrErr) { +      consumeError(ContentsSectionNameOrErr.takeError()); +      continue; +    } +    if (*ContentsSectionNameOrErr != ".stack_sizes") +      continue; +    // Insert a mapping from the stack sizes section to its relocation section. +    StackSizeRelocMap[Obj->toSectionRef(ContentsSec)] = Sec; +  } + +  for (const auto &StackSizeMapEntry : StackSizeRelocMap) { +    PrintHeader(); +    const SectionRef &StackSizesSec = StackSizeMapEntry.first; +    const SectionRef &RelocSec = StackSizeMapEntry.second; + +    // Warn about stack size sections without a relocation section. +    StringRef StackSizeSectionName = getSectionName(StackSizesSec); +    if (RelocSec == NullSection) { +      reportWarning(createError("section " + StackSizeSectionName + +                                " does not have a corresponding " +                                "relocation section"), +                    Obj->getFileName()); +      continue; +    } + +    // A .stack_sizes section header's sh_link field is supposed to point +    // to the section that contains the functions whose stack sizes are +    // described in it. +    const Elf_Shdr *StackSizesELFSec = +        Obj->getSection(StackSizesSec.getRawDataRefImpl()); +    const SectionRef FunctionSec = Obj->toSectionRef(unwrapOrError( +        this->FileName, EF->getSection(StackSizesELFSec->sh_link))); + +    bool (*IsSupportedFn)(uint64_t); +    RelocationResolver Resolver; +    std::tie(IsSupportedFn, Resolver) = getRelocationResolver(*Obj); +    auto Contents = unwrapOrError(this->FileName, StackSizesSec.getContents()); +    DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr)); +    for (const RelocationRef &Reloc : RelocSec.relocations()) { +      if (!IsSupportedFn || !IsSupportedFn(Reloc.getType())) +        reportError(createStringError( +                        object_error::parse_failed, +                        "unsupported relocation type in section %s: %s", +                        getSectionName(RelocSec).data(), +                        EF->getRelocationTypeName(Reloc.getType()).data()), +                    Obj->getFileName()); +      this->printStackSize(Obj, Reloc, FunctionSec, StackSizeSectionName, +                           Resolver, Data); +    } +  } +} + +template <class ELFT> +void GNUStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) { +  bool HeaderHasBeenPrinted = false; +  auto PrintHeader = [&]() { +    if (HeaderHasBeenPrinted) +      return; +    OS << "\nStack Sizes:\n"; +    OS.PadToColumn(9); +    OS << "Size"; +    OS.PadToColumn(18); +    OS << "Function\n"; +    HeaderHasBeenPrinted = true; +  }; + +  // For non-relocatable objects, look directly for sections whose name starts +  // with .stack_sizes and process the contents. +  if (Obj->isRelocatableObject()) +    this->printRelocatableStackSizes(Obj, PrintHeader); +  else +    this->printNonRelocatableStackSizes(Obj, PrintHeader); +} + +template <class ELFT>  void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {    size_t Bias = ELFT::Is64Bits ? 8 : 0;    auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) { @@ -4402,6 +5395,45 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {    }  } +template <class ELFT> +void GNUStyle<ELFT>::printMipsABIFlags(const ELFObjectFile<ELFT> *ObjF) { +  const ELFFile<ELFT> *Obj = ObjF->getELFFile(); +  const Elf_Shdr *Shdr = +      findSectionByName(*Obj, ObjF->getFileName(), ".MIPS.abiflags"); +  if (!Shdr) +    return; + +  ArrayRef<uint8_t> Sec = +      unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); +  if (Sec.size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) +    reportError(createError(".MIPS.abiflags section has a wrong size"), +                ObjF->getFileName()); + +  auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec.data()); + +  OS << "MIPS ABI Flags Version: " << Flags->version << "\n\n"; +  OS << "ISA: MIPS" << int(Flags->isa_level); +  if (Flags->isa_rev > 1) +    OS << "r" << int(Flags->isa_rev); +  OS << "\n"; +  OS << "GPR size: " << getMipsRegisterSize(Flags->gpr_size) << "\n"; +  OS << "CPR1 size: " << getMipsRegisterSize(Flags->cpr1_size) << "\n"; +  OS << "CPR2 size: " << getMipsRegisterSize(Flags->cpr2_size) << "\n"; +  OS << "FP ABI: " << printEnum(Flags->fp_abi, makeArrayRef(ElfMipsFpABIType)) +     << "\n"; +  OS << "ISA Extension: " +     << printEnum(Flags->isa_ext, makeArrayRef(ElfMipsISAExtType)) << "\n"; +  if (Flags->ases == 0) +    OS << "ASEs: None\n"; +  else +    // FIXME: Print each flag on a separate line. +    OS << "ASEs: " << printFlags(Flags->ases, makeArrayRef(ElfMipsASEFlags)) +       << "\n"; +  OS << "FLAGS 1: " << format_hex_no_prefix(Flags->flags1, 8, false) << "\n"; +  OS << "FLAGS 2: " << format_hex_no_prefix(Flags->flags2, 8, false) << "\n"; +  OS << "\n"; +} +  template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) {    const Elf_Ehdr *E = Obj->getHeader();    { @@ -4455,16 +5487,17 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) {      W.printNumber("ProgramHeaderEntrySize", E->e_phentsize);      W.printNumber("ProgramHeaderCount", E->e_phnum);      W.printNumber("SectionHeaderEntrySize", E->e_shentsize); -    W.printString("SectionHeaderCount", getSectionHeadersNumString(Obj)); +    W.printString("SectionHeaderCount", +                  getSectionHeadersNumString(Obj, this->FileName));      W.printString("StringTableSectionIndex", -                  getSectionHeaderTableIndexString(Obj)); +                  getSectionHeaderTableIndexString(Obj, this->FileName));    }  }  template <class ELFT>  void LLVMStyle<ELFT>::printGroupSections(const ELFO *Obj) {    DictScope Lists(W, "Groups"); -  std::vector<GroupSection> V = getGroups<ELFT>(Obj); +  std::vector<GroupSection> V = getGroups<ELFT>(Obj, this->FileName);    DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V);    for (const GroupSection &G : V) {      DictScope D(W, "Group"); @@ -4499,7 +5532,7 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) {    ListScope D(W, "Relocations");    int SectionNumber = -1; -  for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { +  for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {      ++SectionNumber;      if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && @@ -4508,7 +5541,7 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) {          Sec.sh_type != ELF::SHT_ANDROID_RELR)        continue; -    StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); +    StringRef Name = unwrapOrError(this->FileName, Obj->getSectionName(&Sec));      W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";      W.indent(); @@ -4522,11 +5555,12 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) {  template <class ELFT>  void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { -  const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec->sh_link)); +  const Elf_Shdr *SymTab = +      unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link));    switch (Sec->sh_type) {    case ELF::SHT_REL: -    for (const Elf_Rel &R : unwrapOrError(Obj->rels(Sec))) { +    for (const Elf_Rel &R : unwrapOrError(this->FileName, Obj->rels(Sec))) {        Elf_Rela Rela;        Rela.r_offset = R.r_offset;        Rela.r_info = R.r_info; @@ -4535,17 +5569,18 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {      }      break;    case ELF::SHT_RELA: -    for (const Elf_Rela &R : unwrapOrError(Obj->relas(Sec))) +    for (const Elf_Rela &R : unwrapOrError(this->FileName, Obj->relas(Sec)))        printRelocation(Obj, R, SymTab);      break;    case ELF::SHT_RELR:    case ELF::SHT_ANDROID_RELR: { -    Elf_Relr_Range Relrs = unwrapOrError(Obj->relrs(Sec)); +    Elf_Relr_Range Relrs = unwrapOrError(this->FileName, Obj->relrs(Sec));      if (opts::RawRelr) {        for (const Elf_Relr &R : Relrs)          W.startLine() << W.hex(R) << "\n";      } else { -      std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); +      std::vector<Elf_Rela> RelrRelas = +          unwrapOrError(this->FileName, Obj->decode_relrs(Relrs));        for (const Elf_Rela &R : RelrRelas)          printRelocation(Obj, R, SymTab);      } @@ -4553,7 +5588,8 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {    }    case ELF::SHT_ANDROID_REL:    case ELF::SHT_ANDROID_RELA: -    for (const Elf_Rela &R : unwrapOrError(Obj->android_relas(Sec))) +    for (const Elf_Rela &R : +         unwrapOrError(this->FileName, Obj->android_relas(Sec)))        printRelocation(Obj, R, SymTab);      break;    } @@ -4565,13 +5601,16 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,    SmallString<32> RelocName;    Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);    std::string TargetName; -  const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTab)); +  const Elf_Sym *Sym = +      unwrapOrError(this->FileName, Obj->getRelocationSymbol(&Rel, SymTab));    if (Sym && Sym->getType() == ELF::STT_SECTION) {      const Elf_Shdr *Sec = unwrapOrError( +        this->FileName,          Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable())); -    TargetName = unwrapOrError(Obj->getSectionName(Sec)); +    TargetName = unwrapOrError(this->FileName, Obj->getSectionName(Sec));    } else if (Sym) { -    StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); +    StringRef StrTable = +        unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*SymTab));      TargetName = this->dumper()->getFullSymbolName(          Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);    } @@ -4596,10 +5635,13 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {    ListScope SectionsD(W, "Sections");    int SectionIndex = -1; -  ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections()); +  ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());    const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject(); +  std::vector<EnumEntry<unsigned>> FlagsList = +      getSectionFlagsForTarget(Obj->getHeader()->e_machine);    for (const Elf_Shdr &Sec : Sections) { -    StringRef Name = getSectionName(Sec, *ElfObj, Sections); +    StringRef Name = unwrapOrError( +        ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler));      DictScope SectionD(W, "Section");      W.printNumber("Index", ++SectionIndex);      W.printNumber("Name", Name, Sec.sh_name); @@ -4607,35 +5649,7 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {          "Type",          object::getELFSectionTypeName(Obj->getHeader()->e_machine, Sec.sh_type),          Sec.sh_type); -    std::vector<EnumEntry<unsigned>> SectionFlags(std::begin(ElfSectionFlags), -                                                  std::end(ElfSectionFlags)); -    switch (Obj->getHeader()->e_machine) { -    case EM_ARM: -      SectionFlags.insert(SectionFlags.end(), std::begin(ElfARMSectionFlags), -                          std::end(ElfARMSectionFlags)); -      break; -    case EM_HEXAGON: -      SectionFlags.insert(SectionFlags.end(), -                          std::begin(ElfHexagonSectionFlags), -                          std::end(ElfHexagonSectionFlags)); -      break; -    case EM_MIPS: -      SectionFlags.insert(SectionFlags.end(), std::begin(ElfMipsSectionFlags), -                          std::end(ElfMipsSectionFlags)); -      break; -    case EM_X86_64: -      SectionFlags.insert(SectionFlags.end(), std::begin(ElfX86_64SectionFlags), -                          std::end(ElfX86_64SectionFlags)); -      break; -    case EM_XCORE: -      SectionFlags.insert(SectionFlags.end(), std::begin(ElfXCoreSectionFlags), -                          std::end(ElfXCoreSectionFlags)); -      break; -    default: -      // Nothing to do. -      break; -    } -    W.printFlags("Flags", Sec.sh_flags, makeArrayRef(SectionFlags)); +    W.printFlags("Flags", Sec.sh_flags, makeArrayRef(FlagsList));      W.printHex("Address", Sec.sh_addr);      W.printHex("Offset", Sec.sh_offset);      W.printNumber("Size", Sec.sh_size); @@ -4652,19 +5666,25 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {      if (opts::SectionSymbols) {        ListScope D(W, "Symbols");        const Elf_Shdr *Symtab = this->dumper()->getDotSymtabSec(); -      StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); +      StringRef StrTable = +          unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*Symtab)); -      for (const Elf_Sym &Sym : unwrapOrError(Obj->symbols(Symtab))) { +      for (const Elf_Sym &Sym : +           unwrapOrError(this->FileName, Obj->symbols(Symtab))) {          const Elf_Shdr *SymSec = unwrapOrError( +            this->FileName,              Obj->getSection(&Sym, Symtab, this->dumper()->getShndxTable()));          if (SymSec == &Sec) -          printSymbol(Obj, &Sym, unwrapOrError(Obj->symbols(Symtab)).begin(), -                      StrTable, false); +          printSymbol( +              Obj, &Sym, +              unwrapOrError(this->FileName, Obj->symbols(Symtab)).begin(), +              StrTable, false, false);        }      }      if (opts::SectionData && Sec.sh_type != ELF::SHT_NOBITS) { -      ArrayRef<uint8_t> Data = unwrapOrError(Obj->getSectionContents(&Sec)); +      ArrayRef<uint8_t> Data = +          unwrapOrError(this->FileName, Obj->getSectionContents(&Sec));        W.printBinaryBlock(            "SectionData",            StringRef(reinterpret_cast<const char *>(Data.data()), Data.size())); @@ -4673,12 +5693,34 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {  }  template <class ELFT> +void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol, +                                         const Elf_Sym *First) { +  Expected<unsigned> SectionIndex = +      this->dumper()->getSymbolSectionIndex(Symbol, First); +  if (!SectionIndex) { +    assert(Symbol->st_shndx == SHN_XINDEX && +           "getSymbolSectionIndex should only fail due to an invalid " +           "SHT_SYMTAB_SHNDX table/reference"); +    this->reportUniqueWarning(SectionIndex.takeError()); +    W.printHex("Section", "Reserved", SHN_XINDEX); +    return; +  } + +  Expected<StringRef> SectionName = +      this->dumper()->getSymbolSectionName(Symbol, *SectionIndex); +  if (!SectionName) { +    this->reportUniqueWarning(SectionName.takeError()); +    W.printHex("Section", "<?>", *SectionIndex); +  } else { +    W.printHex("Section", *SectionName, *SectionIndex); +  } +} + +template <class ELFT>  void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,                                    const Elf_Sym *First, StringRef StrTable, -                                  bool IsDynamic) { -  unsigned SectionIndex = 0; -  StringRef SectionName; -  this->dumper()->getSectionNameIndex(Symbol, First, SectionName, SectionIndex); +                                  bool IsDynamic, +                                  bool /*NonVisibilityBitsUsed*/) {    std::string FullSymbolName =        this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);    unsigned char SymbolType = Symbol->getType(); @@ -4715,7 +5757,7 @@ void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,      }      W.printFlags("Other", Symbol->st_other, makeArrayRef(SymOtherFlags), 0x3u);    } -  W.printHex("Section", SectionName, SectionIndex); +  printSymbolSection(Symbol, First);  }  template <class ELFT> @@ -4754,12 +5796,10 @@ template <class ELFT> void LLVMStyle<ELFT>::printDynamic(const ELFFile<ELFT> *Ob    for (auto Entry : Table) {      uintX_t Tag = Entry.getTag();      W.startLine() << "  " << format_hex(Tag, Is64 ? 18 : 10, true) << " " -                  << format("%-21s", -                            getTypeString(Obj->getHeader()->e_machine, Tag)); +                  << format("%-21s", Obj->getDynamicTagAsString(Tag).c_str());      this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal());      OS << "\n";    } -    W.startLine() << "]\n";  } @@ -4786,7 +5826,8 @@ void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {      }    if (DynRelrRegion.Size > 0) {      Elf_Relr_Range Relrs = this->dumper()->dyn_relrs(); -    std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); +    std::vector<Elf_Rela> RelrRelas = +        unwrapOrError(this->FileName, Obj->decode_relrs(Relrs));      for (const Elf_Rela &Rela : RelrRelas)        printDynamicRelocation(Obj, Rela);    } @@ -4809,11 +5850,9 @@ template <class ELFT>  void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) {    SmallString<32> RelocName;    Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); -  std::string SymbolName; -  uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); -  const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; -  SymbolName = maybeDemangle( -      unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()))); +  std::string SymbolName = +      getSymbolForReloc(Obj, this->FileName, this->dumper(), Rel).Name; +    if (opts::ExpandRelocs) {      DictScope Group(W, "Relocation");      W.printHex("Offset", Rel.r_offset); @@ -4842,7 +5881,8 @@ template <class ELFT>  void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {    ListScope L(W, "ProgramHeaders"); -  for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { +  for (const Elf_Phdr &Phdr : +       unwrapOrError(this->FileName, Obj->program_headers())) {      DictScope P(W, "ProgramHeader");      W.printHex("Type",                 getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type), @@ -4860,119 +5900,84 @@ void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {  template <class ELFT>  void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,                                                  const Elf_Shdr *Sec) { -  DictScope SS(W, "Version symbols"); +  ListScope SS(W, "VersionSymbols");    if (!Sec)      return; -  StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); -  W.printNumber("Section Name", SecName, Sec->sh_name); -  W.printHex("Address", Sec->sh_addr); -  W.printHex("Offset", Sec->sh_offset); -  W.printNumber("Link", Sec->sh_link); +  StringRef StrTable; +  ArrayRef<Elf_Sym> Syms; +  Expected<ArrayRef<Elf_Versym>> VerTableOrErr = +      this->dumper()->getVersionTable(Sec, &Syms, &StrTable); +  if (!VerTableOrErr) { +    this->reportUniqueWarning(VerTableOrErr.takeError()); +    return; +  } -  const uint8_t *VersymBuf = -      reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); -  const ELFDumper<ELFT> *Dumper = this->dumper(); -  StringRef StrTable = Dumper->getDynamicStringTable(); +  if (StrTable.empty() || Syms.empty() || Syms.size() != VerTableOrErr->size()) +    return; -  // Same number of entries in the dynamic symbol table (DT_SYMTAB). -  ListScope Syms(W, "Symbols"); -  for (const Elf_Sym &Sym : Dumper->dynamic_symbols()) { +  for (size_t I = 0, E = Syms.size(); I < E; ++I) {      DictScope S(W, "Symbol"); -    const Elf_Versym *Versym = reinterpret_cast<const Elf_Versym *>(VersymBuf); -    std::string FullSymbolName = -        Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */); -    W.printNumber("Version", Versym->vs_index & VERSYM_VERSION); -    W.printString("Name", FullSymbolName); -    VersymBuf += sizeof(Elf_Versym); +    W.printNumber("Version", (*VerTableOrErr)[I].vs_index & VERSYM_VERSION); +    W.printString("Name", this->dumper()->getFullSymbolName( +                              &Syms[I], StrTable, /*IsDynamic=*/true));    }  }  template <class ELFT>  void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj,                                                      const Elf_Shdr *Sec) { -  DictScope SD(W, "SHT_GNU_verdef"); +  ListScope SD(W, "VersionDefinitions");    if (!Sec)      return; -  const uint8_t *SecStartAddress = -      reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); -  const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size; -  const uint8_t *VerdefBuf = SecStartAddress; -  const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link)); - -  unsigned VerDefsNum = Sec->sh_info; -  while (VerDefsNum--) { -    if (VerdefBuf + sizeof(Elf_Verdef) > SecEndAddress) -      // FIXME: report_fatal_error is not a good way to report error. We should -      // emit a parsing error here and below. -      report_fatal_error("invalid offset in the section"); +  Expected<std::vector<VerDef>> V = this->dumper()->getVersionDefinitions(Sec); +  if (!V) { +    this->reportUniqueWarning(V.takeError()); +    return; +  } -    const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); +  for (const VerDef &D : *V) {      DictScope Def(W, "Definition"); -    W.printNumber("Version", Verdef->vd_version); -    W.printEnum("Flags", Verdef->vd_flags, makeArrayRef(SymVersionFlags)); -    W.printNumber("Index", Verdef->vd_ndx); -    W.printNumber("Hash", Verdef->vd_hash); -    W.printString("Name", StringRef(reinterpret_cast<const char *>( -                              Obj->base() + StrTab->sh_offset + -                              Verdef->getAux()->vda_name))); -    if (!Verdef->vd_cnt) -      report_fatal_error("at least one definition string must exist"); -    if (Verdef->vd_cnt > 2) -      report_fatal_error("more than one predecessor is not expected"); - -    if (Verdef->vd_cnt == 2) { -      const uint8_t *VerdauxBuf = -          VerdefBuf + Verdef->vd_aux + Verdef->getAux()->vda_next; -      const Elf_Verdaux *Verdaux = -          reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); -      W.printString("Predecessor", -                    StringRef(reinterpret_cast<const char *>( -                        Obj->base() + StrTab->sh_offset + Verdaux->vda_name))); -    } -    VerdefBuf += Verdef->vd_next; +    W.printNumber("Version", D.Version); +    W.printFlags("Flags", D.Flags, makeArrayRef(SymVersionFlags)); +    W.printNumber("Index", D.Ndx); +    W.printNumber("Hash", D.Hash); +    W.printString("Name", D.Name.c_str()); +    W.printList( +        "Predecessors", D.AuxV, +        [](raw_ostream &OS, const VerdAux &Aux) { OS << Aux.Name.c_str(); });    }  }  template <class ELFT>  void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,                                                      const Elf_Shdr *Sec) { -  DictScope SD(W, "SHT_GNU_verneed"); +  ListScope SD(W, "VersionRequirements");    if (!Sec)      return; -  const uint8_t *SecData = -      reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); -  const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link)); +  Expected<std::vector<VerNeed>> V = +      this->dumper()->getVersionDependencies(Sec); +  if (!V) { +    this->reportUniqueWarning(V.takeError()); +    return; +  } -  const uint8_t *VerneedBuf = SecData; -  unsigned VerneedNum = Sec->sh_info; -  for (unsigned I = 0; I < VerneedNum; ++I) { -    const Elf_Verneed *Verneed = -        reinterpret_cast<const Elf_Verneed *>(VerneedBuf); +  for (const VerNeed &VN : *V) {      DictScope Entry(W, "Dependency"); -    W.printNumber("Version", Verneed->vn_version); -    W.printNumber("Count", Verneed->vn_cnt); -    W.printString("FileName", -                  StringRef(reinterpret_cast<const char *>( -                      Obj->base() + StrTab->sh_offset + Verneed->vn_file))); +    W.printNumber("Version", VN.Version); +    W.printNumber("Count", VN.Cnt); +    W.printString("FileName", VN.File.c_str()); -    const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;      ListScope L(W, "Entries"); -    for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { -      const Elf_Vernaux *Vernaux = -          reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); +    for (const VernAux &Aux : VN.AuxV) {        DictScope Entry(W, "Entry"); -      W.printNumber("Hash", Vernaux->vna_hash); -      W.printEnum("Flags", Vernaux->vna_flags, makeArrayRef(SymVersionFlags)); -      W.printNumber("Index", Vernaux->vna_other); -      W.printString("Name", -                    StringRef(reinterpret_cast<const char *>( -                        Obj->base() + StrTab->sh_offset + Vernaux->vna_name))); -      VernauxBuf += Vernaux->vna_next; +      W.printNumber("Hash", Aux.Hash); +      W.printFlags("Flags", Aux.Flags, makeArrayRef(SymVersionFlags)); +      W.printNumber("Index", Aux.Other); +      W.printString("Name", Aux.Name.c_str());      } -    VerneedBuf += Verneed->vn_next;    }  } @@ -4986,37 +5991,62 @@ void LLVMStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) {    ListScope L(W, "CGProfile");    if (!this->dumper()->getDotCGProfileSec())      return; -  auto CGProfile = -      unwrapOrError(Obj->template getSectionContentsAsArray<Elf_CGProfile>( -          this->dumper()->getDotCGProfileSec())); +  auto CGProfile = unwrapOrError( +      this->FileName, Obj->template getSectionContentsAsArray<Elf_CGProfile>( +                          this->dumper()->getDotCGProfileSec()));    for (const Elf_CGProfile &CGPE : CGProfile) {      DictScope D(W, "CGProfileEntry"); -    W.printNumber("From", this->dumper()->getStaticSymbolName(CGPE.cgp_from), -                  CGPE.cgp_from); -    W.printNumber("To", this->dumper()->getStaticSymbolName(CGPE.cgp_to), -                  CGPE.cgp_to); +    W.printNumber( +        "From", +        unwrapOrError(this->FileName, +                      this->dumper()->getStaticSymbolName(CGPE.cgp_from)), +        CGPE.cgp_from); +    W.printNumber( +        "To", +        unwrapOrError(this->FileName, +                      this->dumper()->getStaticSymbolName(CGPE.cgp_to)), +        CGPE.cgp_to);      W.printNumber("Weight", CGPE.cgp_weight);    }  } +static Expected<std::vector<uint64_t>> toULEB128Array(ArrayRef<uint8_t> Data) { +  std::vector<uint64_t> Ret; +  const uint8_t *Cur = Data.begin(); +  const uint8_t *End = Data.end(); +  while (Cur != End) { +    unsigned Size; +    const char *Err; +    Ret.push_back(decodeULEB128(Cur, &Size, End, &Err)); +    if (Err) +      return createError(Err); +    Cur += Size; +  } +  return Ret; +} +  template <class ELFT>  void LLVMStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) {    ListScope L(W, "Addrsig");    if (!this->dumper()->getDotAddrsigSec())      return;    ArrayRef<uint8_t> Contents = unwrapOrError( +      this->FileName,        Obj->getSectionContents(this->dumper()->getDotAddrsigSec())); -  const uint8_t *Cur = Contents.begin(); -  const uint8_t *End = Contents.end(); -  while (Cur != End) { -    unsigned Size; -    const char *Err; -    uint64_t SymIndex = decodeULEB128(Cur, &Size, End, &Err); -    if (Err) -      reportError(Err); -    W.printNumber("Sym", this->dumper()->getStaticSymbolName(SymIndex), -                  SymIndex); -    Cur += Size; +  Expected<std::vector<uint64_t>> V = toULEB128Array(Contents); +  if (!V) { +    reportWarning(V.takeError(), this->FileName); +    return; +  } + +  for (uint64_t Sym : *V) { +    Expected<std::string> NameOrErr = this->dumper()->getStaticSymbolName(Sym); +    if (NameOrErr) { +      W.printNumber("Sym", *NameOrErr, Sym); +      continue; +    } +    reportWarning(NameOrErr.takeError(), this->FileName); +    W.printNumber("Sym", "<?>", Sym);    }  } @@ -5051,6 +6081,17 @@ static void printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,    }  } +static void printCoreNoteLLVMStyle(const CoreNote &Note, ScopedPrinter &W) { +  W.printNumber("Page Size", Note.PageSize); +  for (const CoreFileMapping &Mapping : Note.Mappings) { +    ListScope D(W, "Mapping"); +    W.printHex("Start", Mapping.Start); +    W.printHex("End", Mapping.End); +    W.printHex("Offset", Mapping.Offset); +    W.printString("Filename", Mapping.Filename); +  } +} +  template <class ELFT>  void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {    ListScope L(W, "Notes"); @@ -5067,56 +6108,81 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {      ArrayRef<uint8_t> Descriptor = Note.getDesc();      Elf_Word Type = Note.getType(); +    // Print the note owner/type.      W.printString("Owner", Name);      W.printHex("Data size", Descriptor.size());      if (Name == "GNU") {        W.printString("Type", getGNUNoteTypeName(Type)); -      printGNUNoteLLVMStyle<ELFT>(Type, Descriptor, W);      } else if (Name == "FreeBSD") {        W.printString("Type", getFreeBSDNoteTypeName(Type));      } else if (Name == "AMD") {        W.printString("Type", getAMDNoteTypeName(Type)); -      const AMDNote N = getAMDNote<ELFT>(Type, Descriptor); -      if (!N.Type.empty()) -        W.printString(N.Type, N.Value);      } else if (Name == "AMDGPU") {        W.printString("Type", getAMDGPUNoteTypeName(Type)); -      const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor); -      if (!N.Type.empty()) -        W.printString(N.Type, N.Value);      } else { -      StringRef NoteType = getGenericNoteTypeName(Type); +      StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE +                               ? getCoreNoteTypeName(Type) +                               : getGenericNoteTypeName(Type);        if (!NoteType.empty())          W.printString("Type", NoteType);        else          W.printString("Type",                        "Unknown (" + to_string(format_hex(Type, 10)) + ")");      } + +    // Print the description, or fallback to printing raw bytes for unknown +    // owners. +    if (Name == "GNU") { +      printGNUNoteLLVMStyle<ELFT>(Type, Descriptor, W); +    } else if (Name == "AMD") { +      const AMDNote N = getAMDNote<ELFT>(Type, Descriptor); +      if (!N.Type.empty()) +        W.printString(N.Type, N.Value); +    } else if (Name == "AMDGPU") { +      const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor); +      if (!N.Type.empty()) +        W.printString(N.Type, N.Value); +    } else if (Name == "CORE") { +      if (Type == ELF::NT_FILE) { +        DataExtractor DescExtractor(Descriptor, +                                    ELFT::TargetEndianness == support::little, +                                    sizeof(Elf_Addr)); +        Expected<CoreNote> Note = readCoreNote(DescExtractor); +        if (Note) +          printCoreNoteLLVMStyle(*Note, W); +        else +          reportWarning(Note.takeError(), this->FileName); +      } +    } else if (!Descriptor.empty()) { +      W.printBinaryBlock("Description data", Descriptor); +    }    }; -  if (Obj->getHeader()->e_type == ELF::ET_CORE) { -    for (const auto &P : unwrapOrError(Obj->program_headers())) { -      if (P.p_type != PT_NOTE) +  ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections()); +  if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) { +    for (const auto &S : Sections) { +      if (S.sh_type != SHT_NOTE)          continue;        DictScope D(W, "NoteSection"); -      PrintHeader(P.p_offset, P.p_filesz); +      PrintHeader(S.sh_offset, S.sh_size);        Error Err = Error::success(); -      for (const auto &Note : Obj->notes(P, Err)) +      for (auto Note : Obj->notes(S, Err))          ProcessNote(Note);        if (Err) -        error(std::move(Err)); +        reportError(std::move(Err), this->FileName);      }    } else { -    for (const auto &S : unwrapOrError(Obj->sections())) { -      if (S.sh_type != SHT_NOTE) +    for (const auto &P : +         unwrapOrError(this->FileName, Obj->program_headers())) { +      if (P.p_type != PT_NOTE)          continue;        DictScope D(W, "NoteSection"); -      PrintHeader(S.sh_offset, S.sh_size); +      PrintHeader(P.p_offset, P.p_filesz);        Error Err = Error::success(); -      for (const auto &Note : Obj->notes(S, Err)) +      for (auto Note : Obj->notes(P, Err))          ProcessNote(Note);        if (Err) -        error(std::move(Err)); +        reportError(std::move(Err), this->FileName);      }    }  } @@ -5125,24 +6191,97 @@ template <class ELFT>  void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {    ListScope L(W, "LinkerOptions"); -  for (const Elf_Shdr &Shdr : unwrapOrError(Obj->sections())) { +  unsigned I = -1; +  for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) { +    ++I;      if (Shdr.sh_type != ELF::SHT_LLVM_LINKER_OPTIONS)        continue; -    ArrayRef<uint8_t> Contents = unwrapOrError(Obj->getSectionContents(&Shdr)); -    for (const uint8_t *P = Contents.begin(), *E = Contents.end(); P < E; ) { -      StringRef Key = StringRef(reinterpret_cast<const char *>(P)); -      StringRef Value = -          StringRef(reinterpret_cast<const char *>(P) + Key.size() + 1); +    ArrayRef<uint8_t> Contents = +        unwrapOrError(this->FileName, Obj->getSectionContents(&Shdr)); +    if (Contents.empty()) +      continue; + +    if (Contents.back() != 0) { +      reportWarning(createError("SHT_LLVM_LINKER_OPTIONS section at index " + +                                Twine(I) + +                                " is broken: the " +                                "content is not null-terminated"), +                    this->FileName); +      continue; +    } + +    SmallVector<StringRef, 16> Strings; +    toStringRef(Contents.drop_back()).split(Strings, '\0'); +    if (Strings.size() % 2 != 0) { +      reportWarning( +          createError( +              "SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) + +              " is broken: an incomplete " +              "key-value pair was found. The last possible key was: \"" + +              Strings.back() + "\""), +          this->FileName); +      continue; +    } + +    for (size_t I = 0; I < Strings.size(); I += 2) +      W.printString(Strings[I], Strings[I + 1]); +  } +} + +template <class ELFT> +void LLVMStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) { +  ListScope L(W, "DependentLibs"); + +  auto Warn = [this](unsigned SecNdx, StringRef Msg) { +    this->reportUniqueWarning( +        createError("SHT_LLVM_DEPENDENT_LIBRARIES section at index " + +                    Twine(SecNdx) + " is broken: " + Msg)); +  }; -      W.printString(Key, Value); +  unsigned I = -1; +  for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) { +    ++I; +    if (Shdr.sh_type != ELF::SHT_LLVM_DEPENDENT_LIBRARIES) +      continue; -      P = P + Key.size() + Value.size() + 2; +    Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr); +    if (!ContentsOrErr) { +      Warn(I, toString(ContentsOrErr.takeError())); +      continue; +    } + +    ArrayRef<uint8_t> Contents = *ContentsOrErr; +    if (!Contents.empty() && Contents.back() != 0) { +      Warn(I, "the content is not null-terminated"); +      continue; +    } + +    for (const uint8_t *I = Contents.begin(), *E = Contents.end(); I < E;) { +      StringRef Lib((const char *)I); +      W.printString(Lib); +      I += Lib.size() + 1;      }    }  }  template <class ELFT> +void LLVMStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) { +  ListScope L(W, "StackSizes"); +  if (Obj->isRelocatableObject()) +    this->printRelocatableStackSizes(Obj, []() {}); +  else +    this->printNonRelocatableStackSizes(Obj, []() {}); +} + +template <class ELFT> +void LLVMStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) { +  DictScope D(W, "Entry"); +  W.printString("Function", FuncName); +  W.printHex("Size", Size); +} + +template <class ELFT>  void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {    auto PrintEntry = [&](const Elf_Addr *E) {      W.printHex("Address", Parser.getGotAddress(E)); @@ -5188,13 +6327,7 @@ void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {        const Elf_Sym *Sym = Parser.getGotSym(&E);        W.printHex("Value", Sym->st_value);        W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); - -      unsigned SectionIndex = 0; -      StringRef SectionName; -      this->dumper()->getSectionNameIndex( -          Sym, this->dumper()->dynamic_symbols().begin(), SectionName, -          SectionIndex); -      W.printHex("Section", SectionName, SectionIndex); +      printSymbolSection(Sym, this->dumper()->dynamic_symbols().begin());        std::string SymName = this->dumper()->getFullSymbolName(            Sym, this->dumper()->getDynamicStringTable(), true); @@ -5238,13 +6371,7 @@ void LLVMStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {        const Elf_Sym *Sym = Parser.getPltSym(&E);        W.printHex("Value", Sym->st_value);        W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); - -      unsigned SectionIndex = 0; -      StringRef SectionName; -      this->dumper()->getSectionNameIndex( -          Sym, this->dumper()->dynamic_symbols().begin(), SectionName, -          SectionIndex); -      W.printHex("Section", SectionName, SectionIndex); +      printSymbolSection(Sym, this->dumper()->dynamic_symbols().begin());        std::string SymName =            this->dumper()->getFullSymbolName(Sym, Parser.getPltStrTable(), true); @@ -5252,3 +6379,41 @@ void LLVMStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {      }    }  } + +template <class ELFT> +void LLVMStyle<ELFT>::printMipsABIFlags(const ELFObjectFile<ELFT> *ObjF) { +  const ELFFile<ELFT> *Obj = ObjF->getELFFile(); +  const Elf_Shdr *Shdr = +      findSectionByName(*Obj, ObjF->getFileName(), ".MIPS.abiflags"); +  if (!Shdr) { +    W.startLine() << "There is no .MIPS.abiflags section in the file.\n"; +    return; +  } +  ArrayRef<uint8_t> Sec = +      unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); +  if (Sec.size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) { +    W.startLine() << "The .MIPS.abiflags section has a wrong size.\n"; +    return; +  } + +  auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec.data()); + +  raw_ostream &OS = W.getOStream(); +  DictScope GS(W, "MIPS ABI Flags"); + +  W.printNumber("Version", Flags->version); +  W.startLine() << "ISA: "; +  if (Flags->isa_rev <= 1) +    OS << format("MIPS%u", Flags->isa_level); +  else +    OS << format("MIPS%ur%u", Flags->isa_level, Flags->isa_rev); +  OS << "\n"; +  W.printEnum("ISA Extension", Flags->isa_ext, makeArrayRef(ElfMipsISAExtType)); +  W.printFlags("ASEs", Flags->ases, makeArrayRef(ElfMipsASEFlags)); +  W.printEnum("FP ABI", Flags->fp_abi, makeArrayRef(ElfMipsFpABIType)); +  W.printNumber("GPR size", getMipsRegisterSize(Flags->gpr_size)); +  W.printNumber("CPR1 size", getMipsRegisterSize(Flags->cpr1_size)); +  W.printNumber("CPR2 size", getMipsRegisterSize(Flags->cpr2_size)); +  W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1)); +  W.printHex("Flags 2", Flags->flags2); +} diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp index 32a3866eb2f2..20a60b3df699 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp @@ -214,6 +214,31 @@ static const EnumEntry<uint32_t> MachOHeaderFlags[] = {    LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE),  }; +static const EnumEntry<unsigned> MachOSectionTypes[] = { +  { "Regular"                        , MachO::S_REGULAR }, +  { "ZeroFill"                       , MachO::S_ZEROFILL }, +  { "CStringLiterals"                , MachO::S_CSTRING_LITERALS }, +  { "4ByteLiterals"                  , MachO::S_4BYTE_LITERALS }, +  { "8ByteLiterals"                  , MachO::S_8BYTE_LITERALS }, +  { "LiteralPointers"                , MachO::S_LITERAL_POINTERS }, +  { "NonLazySymbolPointers"          , MachO::S_NON_LAZY_SYMBOL_POINTERS }, +  { "LazySymbolPointers"             , MachO::S_LAZY_SYMBOL_POINTERS }, +  { "SymbolStubs"                    , MachO::S_SYMBOL_STUBS }, +  { "ModInitFuncPointers"            , MachO::S_MOD_INIT_FUNC_POINTERS }, +  { "ModTermFuncPointers"            , MachO::S_MOD_TERM_FUNC_POINTERS }, +  { "Coalesced"                      , MachO::S_COALESCED }, +  { "GBZeroFill"                     , MachO::S_GB_ZEROFILL }, +  { "Interposing"                    , MachO::S_INTERPOSING }, +  { "16ByteLiterals"                 , MachO::S_16BYTE_LITERALS }, +  { "DTraceDOF"                      , MachO::S_DTRACE_DOF }, +  { "LazyDylibSymbolPointers"        , MachO::S_LAZY_DYLIB_SYMBOL_POINTERS }, +  { "ThreadLocalRegular"             , MachO::S_THREAD_LOCAL_REGULAR }, +  { "ThreadLocalZerofill"            , MachO::S_THREAD_LOCAL_ZEROFILL }, +  { "ThreadLocalVariables"           , MachO::S_THREAD_LOCAL_VARIABLES }, +  { "ThreadLocalVariablePointers"    , MachO::S_THREAD_LOCAL_VARIABLE_POINTERS }, +  { "ThreadLocalInitFunctionPointers", MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS } +}; +  static const EnumEntry<unsigned> MachOSectionAttributes[] = {    { "LocReloc"         , 1 <<  0 /*S_ATTR_LOC_RELOC          */ },    { "ExtReloc"         , 1 <<  1 /*S_ATTR_EXT_RELOC          */ }, @@ -440,10 +465,7 @@ void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) {      MachOSection MOSection;      getSection(Obj, Section.getRawDataRefImpl(), MOSection);      DataRefImpl DR = Section.getRawDataRefImpl(); - -    StringRef Name; -    error(Section.getName(Name)); - +    StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName());      ArrayRef<char> RawName = Obj->getSectionRawName(DR);      StringRef SegmentName = Obj->getSectionFinalSegmentName(DR);      ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR); @@ -459,7 +481,7 @@ void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) {      W.printHex("RelocationOffset", MOSection.RelocationTableOffset);      W.printNumber("RelocationCount", MOSection.NumRelocationTableEntries);      W.printEnum("Type", MOSection.Flags & 0xFF, -                makeArrayRef(MachOSectionAttributes)); +                makeArrayRef(MachOSectionTypes));      W.printFlags("Attributes", MOSection.Flags >> 8,                   makeArrayRef(MachOSectionAttributes));      W.printHex("Reserved1", MOSection.Reserved1); @@ -484,7 +506,8 @@ void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) {      }      if (opts::SectionData && !Section.isBSS()) -      W.printBinaryBlock("SectionData", unwrapOrError(Section.getContents())); +      W.printBinaryBlock("SectionData", unwrapOrError(Obj->getFileName(), +                                                      Section.getContents()));    }  } @@ -493,9 +516,7 @@ void MachODumper::printRelocations() {    std::error_code EC;    for (const SectionRef &Section : Obj->sections()) { -    StringRef Name; -    error(Section.getName(Name)); - +    StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName());      bool PrintedGroup = false;      for (const RelocationRef &Reloc : Section.relocations()) {        if (!PrintedGroup) { @@ -535,14 +556,13 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj,      if (Symbol != Obj->symbol_end()) {        Expected<StringRef> TargetNameOrErr = Symbol->getName();        if (!TargetNameOrErr) -        error(errorToErrorCode(TargetNameOrErr.takeError())); +        reportError(TargetNameOrErr.takeError(), Obj->getFileName());        TargetName = *TargetNameOrErr;      }    } else if (!IsScattered) {      section_iterator SecI = Obj->getRelocationSection(DR); -    if (SecI != Obj->section_end()) { -      error(SecI->getName(TargetName)); -    } +    if (SecI != Obj->section_end()) +      TargetName = unwrapOrError(Obj->getFileName(), SecI->getName());    }    if (TargetName.empty())      TargetName = "-"; @@ -610,10 +630,12 @@ void MachODumper::printSymbol(const SymbolRef &Symbol) {    StringRef SectionName = "";    Expected<section_iterator> SecIOrErr = Symbol.getSection(); -  error(errorToErrorCode(SecIOrErr.takeError())); +  if (!SecIOrErr) +    reportError(SecIOrErr.takeError(), Obj->getFileName()); +    section_iterator SecI = *SecIOrErr;    if (SecI != Obj->section_end()) -    error(SecI->getName(SectionName)); +    SectionName = unwrapOrError(Obj->getFileName(), SecI->getName());    DictScope D(W, "Symbol");    W.printNumber("Name", SymbolName, MOSymbol.StringIndex); @@ -643,7 +665,11 @@ void MachODumper::printStackMap() const {    object::SectionRef StackMapSection;    for (auto Sec : Obj->sections()) {      StringRef Name; -    Sec.getName(Name); +    if (Expected<StringRef> NameOrErr = Sec.getName()) +      Name = *NameOrErr; +    else +      consumeError(NameOrErr.takeError()); +      if (Name == "__llvm_stackmaps") {        StackMapSection = Sec;        break; @@ -653,7 +679,8 @@ void MachODumper::printStackMap() const {    if (StackMapSection == object::SectionRef())      return; -  StringRef StackMapContents = unwrapOrError(StackMapSection.getContents()); +  StringRef StackMapContents = +      unwrapOrError(Obj->getFileName(), StackMapSection.getContents());    ArrayRef<uint8_t> StackMapContentsArray =        arrayRefFromStringRef(StackMapContents); diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp index 0a9e22c8a71c..6229b52693d8 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp @@ -23,6 +23,10 @@  namespace llvm { +static inline Error createError(const Twine &Msg) { +  return createStringError(object::object_error::parse_failed, Msg); +} +  ObjDumper::ObjDumper(ScopedPrinter &Writer) : W(Writer) {}  ObjDumper::~ObjDumper() { @@ -49,8 +53,7 @@ getSectionRefsByNameOrIndex(const object::ObjectFile *Obj,    SecIndex = Obj->isELF() ? 0 : 1;    for (object::SectionRef SecRef : Obj->sections()) { -    StringRef SecName; -    error(SecRef.getName(SecName)); +    StringRef SecName = unwrapOrError(Obj->getFileName(), SecRef.getName());      auto NameIt = SecNames.find(SecName);      if (NameIt != SecNames.end())        NameIt->second = true; @@ -62,12 +65,17 @@ getSectionRefsByNameOrIndex(const object::ObjectFile *Obj,      SecIndex++;    } -  for (const std::pair<std::string, bool> &S : SecNames) +  for (const std::pair<const std::string, bool> &S : SecNames)      if (!S.second) -      reportWarning(formatv("could not find section '{0}'", S.first).str()); +      reportWarning( +          createError(formatv("could not find section '{0}'", S.first).str()), +          Obj->getFileName()); +    for (std::pair<unsigned, bool> S : SecIndices)      if (!S.second) -      reportWarning(formatv("could not find section {0}", S.first).str()); +      reportWarning( +          createError(formatv("could not find section {0}", S.first).str()), +          Obj->getFileName());    return Ret;  } @@ -77,14 +85,16 @@ void ObjDumper::printSectionsAsString(const object::ObjectFile *Obj,    bool First = true;    for (object::SectionRef Section :         getSectionRefsByNameOrIndex(Obj, Sections)) { -    StringRef SectionName; -    error(Section.getName(SectionName)); +    StringRef SectionName = +        unwrapOrError(Obj->getFileName(), Section.getName()); +      if (!First)        W.startLine() << '\n';      First = false;      W.startLine() << "String dump of section '" << SectionName << "':\n"; -    StringRef SectionContent = unwrapOrError(Section.getContents()); +    StringRef SectionContent = +        unwrapOrError(Obj->getFileName(), Section.getContents());      const uint8_t *SecContent = SectionContent.bytes_begin();      const uint8_t *CurrentWord = SecContent; @@ -110,14 +120,16 @@ void ObjDumper::printSectionsAsHex(const object::ObjectFile *Obj,    bool First = true;    for (object::SectionRef Section :         getSectionRefsByNameOrIndex(Obj, Sections)) { -    StringRef SectionName; -    error(Section.getName(SectionName)); +    StringRef SectionName = +        unwrapOrError(Obj->getFileName(), Section.getName()); +      if (!First)        W.startLine() << '\n';      First = false;      W.startLine() << "Hex dump of section '" << SectionName << "':\n"; -    StringRef SectionContent = unwrapOrError(Section.getContents()); +    StringRef SectionContent = +        unwrapOrError(Obj->getFileName(), Section.getContents());      const uint8_t *SecContent = SectionContent.bytes_begin();      const uint8_t *SecEnd = SecContent + SectionContent.size(); diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h index aaabfa2ca2e8..3fc8d3e79ac1 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h @@ -53,6 +53,7 @@ public:    virtual void printUnwindInfo() = 0;    // Only implemented for ELF at this time. +  virtual void printDependentLibs() {}    virtual void printDynamicRelocations() { }    virtual void printDynamicTable() { }    virtual void printNeededLibraries() { } @@ -68,15 +69,8 @@ public:    virtual void printAddrsig() {}    virtual void printNotes() {}    virtual void printELFLinkerOptions() {} - -  // Only implemented for ARM ELF at this time. -  virtual void printAttributes() { } - -  // Only implemented for MIPS ELF at this time. -  virtual void printMipsPLTGOT() { } -  virtual void printMipsABIFlags() { } -  virtual void printMipsReginfo() { } -  virtual void printMipsOptions() { } +  virtual void printStackSizes() {} +  virtual void printArchSpecificInfo() { }    // Only implemented for PE/COFF.    virtual void printCOFFImports() { } diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp index 041a9a15bdb6..dfab9f40d71b 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp @@ -51,6 +51,7 @@ static const EnumEntry<unsigned> WasmSymbolFlags[] = {    ENUM_ENTRY(UNDEFINED),    ENUM_ENTRY(EXPORTED),    ENUM_ENTRY(EXPLICIT_NAME), +  ENUM_ENTRY(NO_STRIP),  #undef ENUM_ENTRY  }; @@ -90,7 +91,7 @@ void WasmDumper::printRelocation(const SectionRef &Section,    StringRef SymName;    symbol_iterator SI = Reloc.getSymbol();    if (SI != Obj->symbol_end()) -    SymName = error(SI->getName()); +    SymName = unwrapOrError(Obj->getFileName(), SI->getName());    bool HasAddend = false;    switch (RelocType) { @@ -133,8 +134,8 @@ void WasmDumper::printRelocations() {    int SectionNumber = 0;    for (const SectionRef &Section : Obj->sections()) {      bool PrintedGroup = false; -    StringRef Name; -    error(Section.getName(Name)); +    StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); +      ++SectionNumber;      for (const RelocationRef &Reloc : Section.relocations()) { diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp index e64b8f157180..380baae2eeb4 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp @@ -7,6 +7,7 @@  //===----------------------------------------------------------------------===//  #include "Win64EHDumper.h" +#include "Error.h"  #include "llvm-readobj.h"  #include "llvm/Object/COFF.h"  #include "llvm/Support/ErrorHandling.h" @@ -111,6 +112,20 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {    }  } +static std::error_code getSymbol(const COFFObjectFile &COFF, uint64_t VA, +                                 object::SymbolRef &Sym) { +  for (const auto &Symbol : COFF.symbols()) { +    Expected<uint64_t> Address = Symbol.getAddress(); +    if (!Address) +      return errorToErrorCode(Address.takeError()); +    if (*Address == VA) { +      Sym = Symbol; +      return readobj_error::success; +    } +  } +  return readobj_error::unknown_symbol; +} +  static std::string formatSymbol(const Dumper::Context &Ctx,                                  const coff_section *Section, uint64_t Offset,                                  uint32_t Displacement) { @@ -131,9 +146,22 @@ static std::string formatSymbol(const Dumper::Context &Ctx,        // TODO: Actually report errors helpfully.        consumeError(Name.takeError());      } +  } else if (!getSymbol(Ctx.COFF, Ctx.COFF.getImageBase() + Displacement, +                        Symbol)) { +    Expected<StringRef> Name = Symbol.getName(); +    if (Name) { +      OS << *Name; +      OS << format(" (0x%" PRIX64 ")", Ctx.COFF.getImageBase() + Displacement); +      return OS.str(); +    } else { +      consumeError(Name.takeError()); +    }    } -  OS << format(" (0x%" PRIX64 ")", Offset); +  if (Displacement > 0) +    OS << format("(0x%" PRIX64 ")", Ctx.COFF.getImageBase() + Displacement); +  else +    OS << format("(0x%" PRIX64 ")", Offset);    return OS.str();  } @@ -159,6 +187,18 @@ static std::error_code resolveRelocation(const Dumper::Context &Ctx,    return std::error_code();  } +static const object::coff_section * +getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { +  for (const auto &Section : COFF.sections()) { +    uint64_t Address = Section.getAddress(); +    uint64_t Size = Section.getSize(); + +    if (VA >= Address && (VA - Address) <= Size) +      return COFF.getCOFFSection(Section); +  } +  return nullptr; +} +  namespace llvm {  namespace Win64EH {  void Dumper::printRuntimeFunctionEntry(const Context &Ctx, @@ -284,16 +324,26 @@ void Dumper::printRuntimeFunction(const Context &Ctx,    DictScope RFS(SW, "RuntimeFunction");    printRuntimeFunctionEntry(Ctx, Section, SectionOffset, RF); -  const coff_section *XData; +  const coff_section *XData = nullptr;    uint64_t Offset;    resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset); +  Offset = Offset + RF.UnwindInfoOffset; + +  if (!XData) { +    uint64_t Address = Ctx.COFF.getImageBase() + RF.UnwindInfoOffset; +    XData = getSectionContaining(Ctx.COFF, Address); +    if (!XData) +      return; +    Offset = RF.UnwindInfoOffset - XData->VirtualAddress; +  }    ArrayRef<uint8_t> Contents; -  error(Ctx.COFF.getSectionContents(XData, Contents)); +  if (Error E = Ctx.COFF.getSectionContents(XData, Contents)) +    reportError(std::move(E), Ctx.COFF.getFileName()); +    if (Contents.empty())      return; -  Offset = Offset + RF.UnwindInfoOffset;    if (Offset > Contents.size())      return; @@ -304,14 +354,19 @@ void Dumper::printRuntimeFunction(const Context &Ctx,  void Dumper::printData(const Context &Ctx) {    for (const auto &Section : Ctx.COFF.sections()) {      StringRef Name; -    Section.getName(Name); +    if (Expected<StringRef> NameOrErr = Section.getName()) +      Name = *NameOrErr; +    else +      consumeError(NameOrErr.takeError());      if (Name != ".pdata" && !Name.startswith(".pdata$"))        continue;      const coff_section *PData = Ctx.COFF.getCOFFSection(Section);      ArrayRef<uint8_t> Contents; -    error(Ctx.COFF.getSectionContents(PData, Contents)); + +    if (Error E = Ctx.COFF.getSectionContents(PData, Contents)) +      reportError(std::move(E), Ctx.COFF.getFileName());      if (Contents.empty())        continue; diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp index 13989f696d9d..a2fb6aac3f93 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp @@ -56,8 +56,12 @@ void Dumper::printEntry(const ResourceEntryRef &Ref) {    if (Ref.checkTypeString()) {      auto NarrowStr = stripUTF16(Ref.getTypeString());      SW.printString("Resource type (string)", NarrowStr); -  } else -    SW.printNumber("Resource type (int)", Ref.getTypeID()); +  } else { +    SmallString<20> IDStr; +    raw_svector_ostream OS(IDStr); +    printResourceTypeName(Ref.getTypeID(), OS); +    SW.printString("Resource type (int)", IDStr); +  }    if (Ref.checkNameString()) {      auto NarrowStr = stripUTF16(Ref.getNameString()); diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp index 6f260f91537f..1f9403665594 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -22,6 +22,12 @@ using namespace object;  namespace {  class XCOFFDumper : public ObjDumper { +  enum { +    SymbolTypeMask = 0x07, +    SymbolAlignmentMask = 0xF8, +    SymbolAlignmentBitOffset = 3 +  }; +  public:    XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)        : ObjDumper(Writer), Obj(Obj) {} @@ -37,11 +43,14 @@ public:  private:    template <typename T> void printSectionHeaders(ArrayRef<T> Sections); - +  template <typename T> void printGenericSectionHeader(T &Sec) const; +  template <typename T> void printOverflowSectionHeader(T &Sec) const; +  void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr); +  void printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr); +  void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); +  void printSymbol(const SymbolRef &); +  void printRelocations(ArrayRef<XCOFFSectionHeader32> Sections);    const XCOFFObjectFile &Obj; - -  // Least significant 3 bits are reserved. -  static constexpr unsigned SectionFlagsReservedMask = 0x7;  };  } // anonymous namespace @@ -100,11 +109,315 @@ void XCOFFDumper::printSectionHeaders() {  }  void XCOFFDumper::printRelocations() { -  llvm_unreachable("Unimplemented functionality for XCOFFDumper"); +  if (Obj.is64Bit()) +    llvm_unreachable("64-bit relocation output not implemented!"); +  else +    printRelocations(Obj.sections32()); +} + +static const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = { +#define ECase(X)                                                               \ +  { #X, XCOFF::X } +    ECase(R_POS),    ECase(R_RL),     ECase(R_RLA),    ECase(R_NEG), +    ECase(R_REL),    ECase(R_TOC),    ECase(R_TRL),    ECase(R_TRLA), +    ECase(R_GL),     ECase(R_TCL),    ECase(R_REF),    ECase(R_BA), +    ECase(R_BR),     ECase(R_RBA),    ECase(R_RBR),    ECase(R_TLS), +    ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM), +    ECase(R_TLSML),  ECase(R_TOCU),   ECase(R_TOCL) +#undef ECase +}; + +void XCOFFDumper::printRelocations(ArrayRef<XCOFFSectionHeader32> Sections) { +  if (!opts::ExpandRelocs) +    report_fatal_error("Unexpanded relocation output not implemented."); + +  ListScope LS(W, "Relocations"); +  uint16_t Index = 0; +  for (const auto &Sec : Sections) { +    ++Index; +    // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation. +    if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA && +        Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF) +      continue; +    auto Relocations = unwrapOrError(Obj.getFileName(), Obj.relocations(Sec)); +    if (Relocations.empty()) +      continue; + +    W.startLine() << "Section (index: " << Index << ") " << Sec.getName() +                  << " {\n"; +    for (auto Reloc : Relocations) { +      StringRef SymbolName = unwrapOrError( +          Obj.getFileName(), Obj.getSymbolNameByIndex(Reloc.SymbolIndex)); + +      DictScope RelocScope(W, "Relocation"); +      W.printHex("Virtual Address", Reloc.VirtualAddress); +      W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex); +      W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No"); +      W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0); +      W.printNumber("Length", Reloc.getRelocatedLength()); +      W.printEnum("Type", (uint8_t)Reloc.Type, +                  makeArrayRef(RelocationTypeNameclass)); +    } +    W.unindent(); +    W.startLine() << "}\n"; +  } +} + +static const EnumEntry<XCOFF::CFileStringType> FileStringType[] = { +#define ECase(X)                                                               \ +  { #X, XCOFF::X } +    ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD) +#undef ECase +}; + +void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) { +  if (Obj.is64Bit()) +    report_fatal_error( +        "Printing for File Auxiliary Entry in 64-bit is unimplemented."); +  StringRef FileName = +      unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr)); +  DictScope SymDs(W, "File Auxiliary Entry"); +  W.printNumber("Index", +                Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); +  W.printString("Name", FileName); +  W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type), +              makeArrayRef(FileStringType)); +} + +static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] = +    { +#define ECase(X)                                                               \ +  { #X, XCOFF::X } +        ECase(XMC_PR),   ECase(XMC_RO),     ECase(XMC_DB), +        ECase(XMC_GL),   ECase(XMC_XO),     ECase(XMC_SV), +        ECase(XMC_SV64), ECase(XMC_SV3264), ECase(XMC_TI), +        ECase(XMC_TB),   ECase(XMC_RW),     ECase(XMC_TC0), +        ECase(XMC_TC),   ECase(XMC_TD),     ECase(XMC_DS), +        ECase(XMC_UA),   ECase(XMC_BS),     ECase(XMC_UC), +        ECase(XMC_TL),   ECase(XMC_TE) +#undef ECase +}; + +static const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = { +#define ECase(X)                                                               \ +  { #X, XCOFF::X } +    ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM) +#undef ECase +}; + +void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr) { +  assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); + +  DictScope SymDs(W, "CSECT Auxiliary Entry"); +  W.printNumber("Index", +                Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); +  if ((AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask) == XCOFF::XTY_LD) +    W.printNumber("ContainingCsectSymbolIndex", AuxEntPtr->SectionOrLength); +  else +    W.printNumber("SectionLen", AuxEntPtr->SectionOrLength); +  W.printHex("ParameterHashIndex", AuxEntPtr->ParameterHashIndex); +  W.printHex("TypeChkSectNum", AuxEntPtr->TypeChkSectNum); +  // Print out symbol alignment and type. +  W.printNumber("SymbolAlignmentLog2", +                (AuxEntPtr->SymbolAlignmentAndType & SymbolAlignmentMask) >> +                    SymbolAlignmentBitOffset); +  W.printEnum("SymbolType", AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask, +              makeArrayRef(CsectSymbolTypeClass)); +  W.printEnum("StorageMappingClass", +              static_cast<uint8_t>(AuxEntPtr->StorageMappingClass), +              makeArrayRef(CsectStorageMappingClass)); +  W.printHex("StabInfoIndex", AuxEntPtr->StabInfoIndex); +  W.printHex("StabSectNum", AuxEntPtr->StabSectNum); +} + +void XCOFFDumper::printSectAuxEntForStat( +    const XCOFFSectAuxEntForStat *AuxEntPtr) { +  assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); + +  DictScope SymDs(W, "Sect Auxiliary Entry For Stat"); +  W.printNumber("Index", +                Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); +  W.printNumber("SectionLength", AuxEntPtr->SectionLength); + +  // Unlike the corresponding fields in the section header, NumberOfRelocEnt +  // and NumberOfLineNum do not handle values greater than 65535. +  W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt); +  W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum); +} + +static const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = { +#define ECase(X)                                                               \ +  { #X, XCOFF::X } +    ECase(C_NULL),  ECase(C_AUTO),    ECase(C_EXT),     ECase(C_STAT), +    ECase(C_REG),   ECase(C_EXTDEF),  ECase(C_LABEL),   ECase(C_ULABEL), +    ECase(C_MOS),   ECase(C_ARG),     ECase(C_STRTAG),  ECase(C_MOU), +    ECase(C_UNTAG), ECase(C_TPDEF),   ECase(C_USTATIC), ECase(C_ENTAG), +    ECase(C_MOE),   ECase(C_REGPARM), ECase(C_FIELD),   ECase(C_BLOCK), +    ECase(C_FCN),   ECase(C_EOS),     ECase(C_FILE),    ECase(C_LINE), +    ECase(C_ALIAS), ECase(C_HIDDEN),  ECase(C_HIDEXT),  ECase(C_BINCL), +    ECase(C_EINCL), ECase(C_INFO),    ECase(C_WEAKEXT), ECase(C_DWARF), +    ECase(C_GSYM),  ECase(C_LSYM),    ECase(C_PSYM),    ECase(C_RSYM), +    ECase(C_RPSYM), ECase(C_STSYM),   ECase(C_TCSYM),   ECase(C_BCOMM), +    ECase(C_ECOML), ECase(C_ECOMM),   ECase(C_DECL),    ECase(C_ENTRY), +    ECase(C_FUN),   ECase(C_BSTAT),   ECase(C_ESTAT),   ECase(C_GTLS), +    ECase(C_STTLS), ECase(C_EFCN) +#undef ECase +}; + +static StringRef GetSymbolValueName(XCOFF::StorageClass SC) { +  switch (SC) { +  case XCOFF::C_EXT: +  case XCOFF::C_WEAKEXT: +  case XCOFF::C_HIDEXT: +  case XCOFF::C_STAT: +    return "Value (RelocatableAddress)"; +  case XCOFF::C_FILE: +    return "Value (SymbolTableIndex)"; +  case XCOFF::C_FCN: +  case XCOFF::C_BLOCK: +  case XCOFF::C_FUN: +  case XCOFF::C_STSYM: +  case XCOFF::C_BINCL: +  case XCOFF::C_EINCL: +  case XCOFF::C_INFO: +  case XCOFF::C_BSTAT: +  case XCOFF::C_LSYM: +  case XCOFF::C_PSYM: +  case XCOFF::C_RPSYM: +  case XCOFF::C_RSYM: +  case XCOFF::C_ECOML: +  case XCOFF::C_DWARF: +    assert(false && "This StorageClass for the symbol is not yet implemented."); +    return ""; +  default: +    return "Value"; +  } +} + +static const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = { +#define ECase(X)                                                               \ +  { #X, XCOFF::X } +    ECase(TB_C), ECase(TB_CPLUSPLUS) +#undef ECase +}; + +static const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = { +#define ECase(X)                                                               \ +  { #X, XCOFF::X } +    ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970) +#undef ECase +}; + +void XCOFFDumper::printSymbol(const SymbolRef &S) { +  if (Obj.is64Bit()) +    report_fatal_error("64-bit support is unimplemented."); + +  DataRefImpl SymbolDRI = S.getRawDataRefImpl(); +  const XCOFFSymbolEntry *SymbolEntPtr = Obj.toSymbolEntry(SymbolDRI); + +  XCOFFSymbolRef XCOFFSymRef(SymbolDRI, &Obj); +  uint8_t NumberOfAuxEntries = XCOFFSymRef.getNumberOfAuxEntries(); + +  DictScope SymDs(W, "Symbol"); + +  StringRef SymbolName = +      unwrapOrError(Obj.getFileName(), Obj.getSymbolName(SymbolDRI)); + +  W.printNumber("Index", +                Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(SymbolEntPtr))); +  W.printString("Name", SymbolName); +  W.printHex(GetSymbolValueName(SymbolEntPtr->StorageClass), +             SymbolEntPtr->Value); + +  StringRef SectionName = +      unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntPtr)); + +  W.printString("Section", SectionName); +  if (XCOFFSymRef.getStorageClass() == XCOFF::C_FILE) { +    W.printEnum("Source Language ID", +                SymbolEntPtr->CFileLanguageIdAndTypeId.LanguageId, +                makeArrayRef(CFileLangIdClass)); +    W.printEnum("CPU Version ID", +                SymbolEntPtr->CFileLanguageIdAndTypeId.CpuTypeId, +                makeArrayRef(CFileCpuIdClass)); +  } else +    W.printHex("Type", SymbolEntPtr->SymbolType); + +  W.printEnum("StorageClass", static_cast<uint8_t>(SymbolEntPtr->StorageClass), +              makeArrayRef(SymStorageClass)); +  W.printNumber("NumberOfAuxEntries", SymbolEntPtr->NumberOfAuxEntries); + +  if (NumberOfAuxEntries == 0) +    return; + +  switch (XCOFFSymRef.getStorageClass()) { +  case XCOFF::C_FILE: +    // If the symbol is C_FILE and has auxiliary entries... +    for (int i = 1; i <= NumberOfAuxEntries; i++) { +      const XCOFFFileAuxEnt *FileAuxEntPtr = +          reinterpret_cast<const XCOFFFileAuxEnt *>(SymbolEntPtr + i); +#ifndef NDEBUG +      Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr)); +#endif +      printFileAuxEnt(FileAuxEntPtr); +    } +    break; +  case XCOFF::C_EXT: +  case XCOFF::C_WEAKEXT: +  case XCOFF::C_HIDEXT: +    // If the symbol is for a function, and it has more than 1 auxiliary entry, +    // then one of them must be function auxiliary entry which we do not +    // support yet. +    if (XCOFFSymRef.isFunction() && NumberOfAuxEntries >= 2) +      report_fatal_error("Function auxiliary entry printing is unimplemented."); + +    // If there is more than 1 auxiliary entry, instead of printing out +    // error information, print out the raw Auxiliary entry from 1st till +    // the last - 1. The last one must be a CSECT Auxiliary Entry. +    for (int i = 1; i < NumberOfAuxEntries; i++) { +      W.startLine() << "!Unexpected raw auxiliary entry data:\n"; +      W.startLine() << format_bytes( +          ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i), +                            XCOFF::SymbolTableEntrySize)); +    } + +    // The symbol's last auxiliary entry is a CSECT Auxiliary Entry. +    printCsectAuxEnt32(XCOFFSymRef.getXCOFFCsectAuxEnt32()); +    break; +  case XCOFF::C_STAT: +    if (NumberOfAuxEntries > 1) +      report_fatal_error( +          "C_STAT symbol should not have more than 1 auxiliary entry."); + +    const XCOFFSectAuxEntForStat *StatAuxEntPtr; +    StatAuxEntPtr = +        reinterpret_cast<const XCOFFSectAuxEntForStat *>(SymbolEntPtr + 1); +#ifndef NDEBUG +    Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr)); +#endif +    printSectAuxEntForStat(StatAuxEntPtr); +    break; +  case XCOFF::C_DWARF: +  case XCOFF::C_BLOCK: +  case XCOFF::C_FCN: +    report_fatal_error("Symbol table entry printing for this storage class " +                       "type is unimplemented."); +    break; +  default: +    for (int i = 1; i <= NumberOfAuxEntries; i++) { +      W.startLine() << "!Unexpected raw auxiliary entry data:\n"; +      W.startLine() << format_bytes( +          ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i), +                            XCOFF::SymbolTableEntrySize)); +    } +    break; +  }  }  void XCOFFDumper::printSymbols() { -  llvm_unreachable("Unimplemented functionality for XCOFFDumper"); +  ListScope Group(W, "Symbols"); +  for (const SymbolRef &S : Obj.symbols()) +    printSymbol(S);  }  void XCOFFDumper::printDynamicSymbols() { @@ -135,6 +448,39 @@ static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {  };  template <typename T> +void XCOFFDumper::printOverflowSectionHeader(T &Sec) const { +  if (Obj.is64Bit()) { +    reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not " +                                          "contain an overflow section header.", +                                          object_error::parse_failed), +                  Obj.getFileName()); +  } + +  W.printString("Name", Sec.getName()); +  W.printNumber("NumberOfRelocations", Sec.PhysicalAddress); +  W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress); +  W.printHex("Size", Sec.SectionSize); +  W.printHex("RawDataOffset", Sec.FileOffsetToRawData); +  W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); +  W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); +  W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations); +  W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers); +} + +template <typename T> +void XCOFFDumper::printGenericSectionHeader(T &Sec) const { +  W.printString("Name", Sec.getName()); +  W.printHex("PhysicalAddress", Sec.PhysicalAddress); +  W.printHex("VirtualAddress", Sec.VirtualAddress); +  W.printHex("Size", Sec.SectionSize); +  W.printHex("RawDataOffset", Sec.FileOffsetToRawData); +  W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); +  W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); +  W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); +  W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); +} + +template <typename T>  void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {    ListScope Group(W, "Sections"); @@ -143,27 +489,26 @@ void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {      DictScope SecDS(W, "Section");      W.printNumber("Index", Index++); -    W.printString("Name", Sec.getName()); - -    W.printHex("PhysicalAddress", Sec.PhysicalAddress); -    W.printHex("VirtualAddress", Sec.VirtualAddress); -    W.printHex("Size", Sec.SectionSize); -    W.printHex("RawDataOffset", Sec.FileOffsetToRawData); -    W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); -    W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); - -    // TODO Need to add overflow handling when NumberOfX == _OVERFLOW_MARKER -    // in 32-bit object files. -    W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); -    W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); - -    // The most significant 16-bits represent the DWARF section subtype. For -    // now we just dump the section type flags. -    uint16_t Flags = Sec.Flags & 0xffffu; -    if (Flags & SectionFlagsReservedMask) -      W.printHex("Flags", "Reserved", Flags); +    uint16_t SectionType = Sec.getSectionType(); +    switch (SectionType) { +    case XCOFF::STYP_OVRFLO: +      printOverflowSectionHeader(Sec); +      break; +    case XCOFF::STYP_LOADER: +    case XCOFF::STYP_EXCEPT: +    case XCOFF::STYP_TYPCHK: +      // TODO The interpretation of loader, exception and type check section +      // headers are different from that of generic section headers. We will +      // implement them later. We interpret them as generic section headers for +      // now. +    default: +      printGenericSectionHeader(Sec); +      break; +    } +    if (Sec.isReservedSectionType()) +      W.printHex("Flags", "Reserved", SectionType);      else -      W.printEnum("Type", Flags, makeArrayRef(SectionTypeFlagsNames)); +      W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames));    }    if (opts::SectionRelocations) 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 1bd5bb74bf29..fadeec1072d6 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -58,6 +58,11 @@ namespace opts {                     "--section-groups and --elf-hash-histogram."));    cl::alias AllShort("a", cl::desc("Alias for --all"), cl::aliasopt(All)); +  // --dependent-libraries +  cl::opt<bool> +      DependentLibraries("dependent-libraries", +                         cl::desc("Display the dependent libraries section")); +    // --headers -e    cl::opt<bool>        Headers("headers", @@ -231,26 +236,11 @@ namespace opts {        "codeview-subsection-bytes",        cl::desc("Dump raw contents of codeview debug sections and records")); -  // --arm-attributes -  cl::opt<bool> ARMAttributes("arm-attributes", -                              cl::desc("Display the ARM attributes section")); - -  // --mips-plt-got -  cl::opt<bool> -  MipsPLTGOT("mips-plt-got", -             cl::desc("Display the MIPS GOT and PLT GOT sections")); - -  // --mips-abi-flags -  cl::opt<bool> MipsABIFlags("mips-abi-flags", -                             cl::desc("Display the MIPS.abiflags section")); - -  // --mips-reginfo -  cl::opt<bool> MipsReginfo("mips-reginfo", -                            cl::desc("Display the MIPS .reginfo section")); - -  // --mips-options -  cl::opt<bool> MipsOptions("mips-options", -                            cl::desc("Display the MIPS .MIPS.options section")); +  // --arch-specific +  cl::opt<bool> ArchSpecificInfo("arch-specific", +                              cl::desc("Displays architecture-specific information, if there is any.")); +  cl::alias ArchSpecifcInfoShort("A", cl::desc("Alias for --arch-specific"), +                                 cl::aliasopt(ArchSpecificInfo), cl::NotHidden);    // --coff-imports    cl::opt<bool> @@ -324,6 +314,11 @@ namespace opts {    PrintStackMap("stackmap",                  cl::desc("Display contents of stackmap section")); +  // --stack-sizes +  cl::opt<bool> +      PrintStackSizes("stack-sizes", +                      cl::desc("Display contents of all stack sizes sections")); +    // --version-info, -V    cl::opt<bool>        VersionInfo("version-info", @@ -368,63 +363,43 @@ namespace opts {        HelpResponse("\nPass @FILE as argument to read options from FILE.\n");  } // namespace opts +static StringRef ToolName; +  namespace llvm { -LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) { +LLVM_ATTRIBUTE_NORETURN static void error(Twine Msg) { +  // Flush the standard output to print the error at a +  // proper place.    fouts().flush(); -  errs() << "\n"; -  WithColor::error(errs()) << Msg << "\n"; +  WithColor::error(errs(), ToolName) << Msg << "\n";    exit(1);  } -void reportError(StringRef Input, Error Err) { +LLVM_ATTRIBUTE_NORETURN void reportError(Error Err, StringRef Input) { +  assert(Err);    if (Input == "-")      Input = "<stdin>"; -  error(createFileError(Input, std::move(Err))); -} - -void reportWarning(Twine Msg) { -  fouts().flush(); -  errs() << "\n"; -  WithColor::warning(errs()) << Msg << "\n"; -} - -void warn(Error Err) { -  handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { -    reportWarning(EI.message()); -  }); +  handleAllErrors(createFileError(Input, std::move(Err)), +                  [&](const ErrorInfoBase &EI) { error(EI.message()); }); +  llvm_unreachable("error() call should never return");  } -void error(Error EC) { -  if (!EC) -    return; -  handleAllErrors(std::move(EC), -                  [&](const ErrorInfoBase &EI) { reportError(EI.message()); }); -} +void reportWarning(Error Err, StringRef Input) { +  assert(Err); +  if (Input == "-") +    Input = "<stdin>"; -void error(std::error_code EC) { -  if (!EC) -    return; -  reportError(EC.message()); +  // Flush the standard output to print the warning at a +  // proper place. +  fouts().flush(); +  handleAllErrors( +      createFileError(Input, std::move(Err)), [&](const ErrorInfoBase &EI) { +        WithColor::warning(errs(), ToolName) << EI.message() << "\n"; +      });  }  } // namespace llvm -static void reportError(StringRef Input, std::error_code EC) { -  reportError(Input, errorCodeToError(EC)); -} - -static bool isMipsArch(unsigned Arch) { -  switch (Arch) { -  case llvm::Triple::mips: -  case llvm::Triple::mipsel: -  case llvm::Triple::mips64: -  case llvm::Triple::mips64el: -    return true; -  default: -    return false; -  } -}  namespace {  struct ReadObjTypeTableBuilder {    ReadObjTypeTableBuilder() @@ -471,19 +446,19 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,    std::unique_ptr<ObjDumper> Dumper;    if (std::error_code EC = createDumper(Obj, Writer, Dumper)) -    reportError(FileStr, EC); +    reportError(errorCodeToError(EC), FileStr); -  Writer.startLine() << "\n"; -  if (opts::Output == opts::LLVM) { +  if (opts::Output == opts::LLVM || opts::InputFilenames.size() > 1 || A) { +    Writer.startLine() << "\n";      Writer.printString("File", FileStr); +  } +  if (opts::Output == opts::LLVM) {      Writer.printString("Format", Obj->getFileFormatName());      Writer.printString("Arch", Triple::getArchTypeName(                                     (llvm::Triple::ArchType)Obj->getArch()));      Writer.printString("AddressSize",                         formatv("{0}bit", 8 * Obj->getBytesInAddress()));      Dumper->printLoadName(); -  } else if (opts::Output == opts::GNU && A) { -    Writer.printString("File", FileStr);    }    if (opts::FileHeaders) @@ -517,21 +492,12 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,    if (opts::VersionInfo)      Dumper->printVersionInfo();    if (Obj->isELF()) { +    if (opts::DependentLibraries) +      Dumper->printDependentLibs();      if (opts::ELFLinkerOptions)        Dumper->printELFLinkerOptions(); -    if (Obj->getArch() == llvm::Triple::arm) -      if (opts::ARMAttributes) -        Dumper->printAttributes(); -    if (isMipsArch(Obj->getArch())) { -      if (opts::MipsPLTGOT) -        Dumper->printMipsPLTGOT(); -      if (opts::MipsABIFlags) -        Dumper->printMipsABIFlags(); -      if (opts::MipsReginfo) -        Dumper->printMipsReginfo(); -      if (opts::MipsOptions) -        Dumper->printMipsOptions(); -    } +    if (opts::ArchSpecificInfo) +      Dumper->printArchSpecificInfo();      if (opts::SectionGroups)        Dumper->printGroupSections();      if (opts::HashHistogram) @@ -583,6 +549,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,    }    if (opts::PrintStackMap)      Dumper->printStackMap(); +  if (opts::PrintStackSizes) +    Dumper->printStackSizes();  }  /// Dumps each object file in \a Arc; @@ -591,9 +559,8 @@ static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {    for (auto &Child : Arc->children(Err)) {      Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();      if (!ChildOrErr) { -      if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) { -        reportError(Arc->getFileName(), std::move(E)); -      } +      if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) +        reportError(std::move(E), Arc->getFileName());        continue;      }      if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get())) @@ -601,10 +568,11 @@ static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {      else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))        dumpCOFFImportFile(Imp, Writer);      else -      reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); +      reportError(errorCodeToError(readobj_error::unrecognized_file_format), +                  Arc->getFileName());    }    if (Err) -    reportError(Arc->getFileName(), std::move(Err)); +    reportError(std::move(Err), Arc->getFileName());  }  /// Dumps each object file in \a MachO Universal Binary; @@ -614,9 +582,8 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary,      Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();      if (ObjOrErr)        dumpObject(&*ObjOrErr.get(), Writer); -    else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { -      reportError(UBinary->getFileName(), ObjOrErr.takeError()); -    } +    else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) +      reportError(ObjOrErr.takeError(), UBinary->getFileName());      else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())        dumpArchive(&*AOrErr.get(), Writer);    } @@ -627,7 +594,7 @@ static void dumpWindowsResourceFile(WindowsResource *WinRes,                                      ScopedPrinter &Printer) {    WindowsRes::Dumper Dumper(WinRes, Printer);    if (auto Err = Dumper.printData()) -    reportError(WinRes->getFileName(), std::move(Err)); +    reportError(std::move(Err), WinRes->getFileName());  } @@ -636,7 +603,7 @@ static void dumpInput(StringRef File, ScopedPrinter &Writer) {    // Attempt to open the binary.    Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);    if (!BinaryOrErr) -    reportError(File, BinaryOrErr.takeError()); +    reportError(BinaryOrErr.takeError(), File);    Binary &Binary = *BinaryOrErr.get().getBinary();    if (Archive *Arc = dyn_cast<Archive>(&Binary)) @@ -651,7 +618,8 @@ static void dumpInput(StringRef File, ScopedPrinter &Writer) {    else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary))      dumpWindowsResourceFile(WinRes, Writer);    else -    reportError(File, readobj_error::unrecognized_file_format); +    reportError(errorCodeToError(readobj_error::unrecognized_file_format), +                File);    CVTypes.Binaries.push_back(std::move(*BinaryOrErr));  } @@ -702,6 +670,7 @@ static void registerReadelfAliases() {  int main(int argc, const char *argv[]) {    InitLLVM X(argc, argv); +  ToolName = argv[0];    // Register the target printer for --version.    cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); @@ -727,6 +696,10 @@ int main(int argc, const char *argv[]) {      opts::UnwindInfo = true;      opts::SectionGroups = true;      opts::HashHistogram = true; +    if (opts::Output == opts::LLVM) { +      opts::Addrsig = true; +      opts::PrintStackSizes = true; +    }    }    if (opts::Headers) { diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h index 0e02da4cb847..d9813f5dea62 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h @@ -21,30 +21,13 @@ namespace llvm {    }    // Various helper functions. -  LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg); -  void reportError(StringRef Input, Error Err);  -  void reportWarning(Twine Msg); -  void warn(llvm::Error Err); -  void error(std::error_code EC); -  void error(llvm::Error EC); -  template <typename T> T error(llvm::Expected<T> &&E) { -    error(E.takeError()); -    return std::move(*E); -  } +  LLVM_ATTRIBUTE_NORETURN void reportError(Error Err, StringRef Input);  +  void reportWarning(Error Err, StringRef Input); -  template <class T> T unwrapOrError(ErrorOr<T> EO) { -    if (EO) -      return *EO; -    reportError(EO.getError().message()); -  } -  template <class T> T unwrapOrError(Expected<T> EO) { +  template <class T> T unwrapOrError(StringRef Input, Expected<T> EO) {      if (EO)        return *EO; -    std::string Buf; -    raw_string_ostream OS(Buf); -    logAllUnhandledErrors(EO.takeError(), OS); -    OS.flush(); -    reportError(Buf); +    reportError(EO.takeError(), Input);    }  } // namespace llvm diff --git a/contrib/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/contrib/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp index a7cc1deb8cf6..9b84c46d3901 100644 --- a/contrib/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -23,16 +23,18 @@  #include "llvm/MC/MCInstrInfo.h"  #include "llvm/MC/MCRegisterInfo.h"  #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h"  #include "llvm/Object/SymbolSize.h"  #include "llvm/Support/CommandLine.h"  #include "llvm/Support/DynamicLibrary.h"  #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MSVCErrorWorkarounds.h"  #include "llvm/Support/Memory.h"  #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/MSVCErrorWorkarounds.h"  #include "llvm/Support/Path.h"  #include "llvm/Support/TargetRegistry.h"  #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/Timer.h"  #include "llvm/Support/raw_ostream.h"  #include <future> @@ -138,8 +140,21 @@ PrintAllocationRequests("print-alloc-requests",                                   "manager by RuntimeDyld"),                          cl::Hidden); +static cl::opt<bool> ShowTimes("show-times", +                               cl::desc("Show times for llvm-rtdyld phases"), +                               cl::init(false)); +  ExitOnError ExitOnErr; +struct RTDyldTimers { +  TimerGroup RTDyldTG{"llvm-rtdyld timers", "timers for llvm-rtdyld phases"}; +  Timer LoadObjectsTimer{"load", "time to load/add object files", RTDyldTG}; +  Timer LinkTimer{"link", "time to link object files", RTDyldTG}; +  Timer RunTimer{"run", "time to execute jitlink'd code", RTDyldTG}; +}; + +std::unique_ptr<RTDyldTimers> Timers; +  /* *** */  using SectionIDMap = StringMap<unsigned>; @@ -441,8 +456,6 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {              continue;            }            object::section_iterator Sec = *SecOrErr; -          StringRef SecName; -          Sec->getName(SecName);            Address.SectionIndex = Sec->getIndex();            uint64_t SectionLoadAddress =              LoadedObjInfo->getSectionLoadAddress(*Sec); @@ -491,35 +504,41 @@ static int executeInput() {    // If we don't have any input files, read from stdin.    if (!InputFileList.size())      InputFileList.push_back("-"); -  for (auto &File : InputFileList) { -    // Load the input memory buffer. -    ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = -        MemoryBuffer::getFileOrSTDIN(File); -    if (std::error_code EC = InputBuffer.getError()) -      ErrorAndExit("unable to read input: '" + EC.message() + "'"); -    Expected<std::unique_ptr<ObjectFile>> MaybeObj( -      ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); - -    if (!MaybeObj) { -      std::string Buf; -      raw_string_ostream OS(Buf); -      logAllUnhandledErrors(MaybeObj.takeError(), OS); -      OS.flush(); -      ErrorAndExit("unable to create object file: '" + Buf + "'"); -    } +  { +    TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr); +    for (auto &File : InputFileList) { +      // Load the input memory buffer. +      ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = +          MemoryBuffer::getFileOrSTDIN(File); +      if (std::error_code EC = InputBuffer.getError()) +        ErrorAndExit("unable to read input: '" + EC.message() + "'"); +      Expected<std::unique_ptr<ObjectFile>> MaybeObj( +          ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); + +      if (!MaybeObj) { +        std::string Buf; +        raw_string_ostream OS(Buf); +        logAllUnhandledErrors(MaybeObj.takeError(), OS); +        OS.flush(); +        ErrorAndExit("unable to create object file: '" + Buf + "'"); +      } -    ObjectFile &Obj = **MaybeObj; +      ObjectFile &Obj = **MaybeObj; -    // Load the object file -    Dyld.loadObject(Obj); -    if (Dyld.hasError()) { -      ErrorAndExit(Dyld.getErrorString()); +      // Load the object file +      Dyld.loadObject(Obj); +      if (Dyld.hasError()) { +        ErrorAndExit(Dyld.getErrorString()); +      }      }    } -  // Resove all the relocations we can. -  // FIXME: Error out if there are unresolved relocations. -  Dyld.resolveRelocations(); +  { +    TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr); +    // Resove all the relocations we can. +    // FIXME: Error out if there are unresolved relocations. +    Dyld.resolveRelocations(); +  }    // Get the address of the entry point (_main by default).    void *MainAddress = Dyld.getSymbolLocalAddress(EntryPoint); @@ -551,7 +570,13 @@ static int executeInput() {    for (auto &Arg : InputArgv)      Argv.push_back(Arg.data());    Argv.push_back(nullptr); -  return Main(Argv.size() - 1, Argv.data()); +  int Result = 0; +  { +    TimeRegion TR(Timers ? &Timers->RunTimer : nullptr); +    Result = Main(Argv.size() - 1, Argv.data()); +  } + +  return Result;  }  static int checkAllExpressions(RuntimeDyldChecker &Checker) { @@ -725,7 +750,9 @@ static int linkAndVerify() {    if (!MRI)      ErrorAndExit("Unable to create target register info!"); -  std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); +  MCTargetOptions MCOptions; +  std::unique_ptr<MCAsmInfo> MAI( +      TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));    if (!MAI)      ErrorAndExit("Unable to create target asm info!"); @@ -891,7 +918,7 @@ static int linkAndVerify() {      ObjectFile &Obj = **MaybeObj;      if (!Checker) -      Checker = llvm::make_unique<RuntimeDyldChecker>( +      Checker = std::make_unique<RuntimeDyldChecker>(            IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo,            GetStubInfo, Obj.isLittleEndian() ? support::little : support::big,            Disassembler.get(), InstPrinter.get(), dbgs()); @@ -937,16 +964,28 @@ int main(int argc, char **argv) {    ExitOnErr.setBanner(std::string(argv[0]) + ": "); +  Timers = ShowTimes ? std::make_unique<RTDyldTimers>() : nullptr; + +  int Result;    switch (Action) {    case AC_Execute: -    return executeInput(); +    Result = executeInput(); +    break;    case AC_PrintDebugLineInfo: -    return printLineInfoForInput(/* LoadObjects */ true,/* UseDebugObj */ true); +    Result = +        printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ true); +    break;    case AC_PrintLineInfo: -    return printLineInfoForInput(/* LoadObjects */ true,/* UseDebugObj */false); +    Result = +        printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ false); +    break;    case AC_PrintObjectLineInfo: -    return printLineInfoForInput(/* LoadObjects */false,/* UseDebugObj */false); +    Result = +        printLineInfoForInput(/* LoadObjects */ false, /* UseDebugObj */ false); +    break;    case AC_Verify: -    return linkAndVerify(); +    Result = linkAndVerify(); +    break;    } +  return Result;  } 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 a455bf13fe7b..5f36a785332b 100644 --- a/contrib/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp @@ -735,7 +735,7 @@ int main(int argc, char **argv) {    cl::ParseCommandLineOptions(argc, argv, "llvm codegen stress-tester\n");    llvm_shutdown_obj Y; -  auto M = llvm::make_unique<Module>("/tmp/autogen.bc", Context); +  auto M = std::make_unique<Module>("/tmp/autogen.bc", Context);    Function *F = GenEmptyFunction(M.get());    // Pick an initial seed value @@ -752,7 +752,7 @@ int main(int argc, char **argv) {      OutputFilename = "-";    std::error_code EC; -  Out.reset(new ToolOutputFile(OutputFilename, EC, sys::fs::F_None)); +  Out.reset(new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None));    if (EC) {      errs() << EC.message() << '\n';      return 1; 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 ea94cf9b69a1..96b2b72d8ba1 100644 --- a/contrib/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -24,6 +24,7 @@  #include "llvm/Support/InitLLVM.h"  #include "llvm/Support/Path.h"  #include "llvm/Support/raw_ostream.h" +#include <algorithm>  #include <cstdio>  #include <cstring>  #include <string> @@ -55,6 +56,10 @@ static cl::opt<bool>                           cl::desc("Interpret addresses as relative addresses"),                           cl::ReallyHidden); +static cl::opt<bool> ClUntagAddresses( +    "untag-addresses", cl::init(true), +    cl::desc("Remove memory tags from addresses before symbolization")); +  static cl::opt<bool>      ClPrintInlining("inlining", cl::init(true),                      cl::desc("Print all inlined frames for a given address")); @@ -146,6 +151,12 @@ static cl::opt<std::string>      ClFallbackDebugPath("fallback-debug-path", cl::init(""),                          cl::desc("Fallback path for debug binaries.")); +static cl::list<std::string> +    ClDebugFileDirectory("debug-file-directory", cl::ZeroOrMore, +                         cl::value_desc("dir"), +                         cl::desc("Path to directory where to look for debug " +                                  "files.")); +  static cl::opt<DIPrinter::OutputStyle>      ClOutputStyle("output-style", cl::init(DIPrinter::OutputStyle::LLVM),                    cl::desc("Specify print style"), @@ -218,7 +229,7 @@ static void symbolizeInput(StringRef InputString, LLVMSymbolizer &Symbolizer,    std::string ModuleName;    uint64_t Offset = 0;    if (!parseCommand(StringRef(InputString), Cmd, ModuleName, Offset)) { -    outs() << InputString; +    outs() << InputString << "\n";      return;    } @@ -274,12 +285,15 @@ int main(int argc, char **argv) {      ClDemangle.setInitialValue(false);      ClPrintFunctions.setInitialValue(FunctionNameKind::None);      ClPrintInlining.setInitialValue(false); +    ClUntagAddresses.setInitialValue(false);      ClOutputStyle.setInitialValue(DIPrinter::OutputStyle::GNU);    }    llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); -  cl::ParseCommandLineOptions(argc, argv, IsAddr2Line ? "llvm-addr2line\n" -                                                      : "llvm-symbolizer\n"); +  cl::ParseCommandLineOptions( +      argc, argv, IsAddr2Line ? "llvm-addr2line\n" : "llvm-symbolizer\n", +      /*Errs=*/nullptr, +      IsAddr2Line ? "LLVM_ADDR2LINE_OPTS" : "LLVM_SYMBOLIZER_OPTS");    // If both --demangle and --no-demangle are specified then pick the last one.    if (ClNoDemangle.getPosition() > ClDemangle.getPosition()) @@ -290,9 +304,11 @@ int main(int argc, char **argv) {    Opts.UseSymbolTable = ClUseSymbolTable;    Opts.Demangle = ClDemangle;    Opts.RelativeAddresses = ClUseRelativeAddress; +  Opts.UntagAddresses = ClUntagAddresses;    Opts.DefaultArch = ClDefaultArch;    Opts.FallbackDebugPath = ClFallbackDebugPath;    Opts.DWPName = ClDwpName; +  Opts.DebugFileDirectory = ClDebugFileDirectory;    for (const auto &hint : ClDsymHint) {      if (sys::path::extension(hint) == ".dSYM") { @@ -313,7 +329,13 @@ int main(int argc, char **argv) {      char InputString[kMaxInputStringLength];      while (fgets(InputString, sizeof(InputString), stdin)) { -      symbolizeInput(InputString, Symbolizer, Printer); +      // Strip newline characters. +      std::string StrippedInputString(InputString); +      StrippedInputString.erase( +          std::remove_if(StrippedInputString.begin(), StrippedInputString.end(), +                         [](char c) { return c == '\r' || c == '\n'; }), +          StrippedInputString.end()); +      symbolizeInput(StrippedInputString, Symbolizer, Printer);        outs().flush();      }    } else { diff --git a/contrib/llvm-project/llvm/tools/llvm-xray/func-id-helper.cpp b/contrib/llvm-project/llvm/tools/llvm-xray/func-id-helper.cpp index dc821a420c67..afc912a6398e 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/func-id-helper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/func-id-helper.cpp @@ -36,7 +36,7 @@ std::string FuncIdConversionHelper::SymbolOrNumber(int32_t FuncId) const {    ModuleAddress.SectionIndex = object::SectionedAddress::UndefSection;    if (auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, ModuleAddress)) {      auto &DI = *ResOrErr; -    if (DI.FunctionName == "<invalid>") +    if (DI.FunctionName == DILineInfo::BadString)        F << "@(" << std::hex << It->second << ")";      else        F << DI.FunctionName; 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 2b49a311d7e3..fcac33b23d4d 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/xray-account.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/xray-account.cpp @@ -34,23 +34,20 @@ static cl::opt<bool>      AccountKeepGoing("keep-going", cl::desc("Keep going on errors encountered"),                       cl::sub(Account), cl::init(false));  static cl::alias AccountKeepGoing2("k", cl::aliasopt(AccountKeepGoing), -                                   cl::desc("Alias for -keep_going"), -                                   cl::sub(Account)); +                                   cl::desc("Alias for -keep_going"));  static cl::opt<bool> AccountDeduceSiblingCalls(      "deduce-sibling-calls",      cl::desc("Deduce sibling calls when unrolling function call stacks"),      cl::sub(Account), cl::init(false));  static cl::alias      AccountDeduceSiblingCalls2("d", cl::aliasopt(AccountDeduceSiblingCalls), -                               cl::desc("Alias for -deduce_sibling_calls"), -                               cl::sub(Account)); +                               cl::desc("Alias for -deduce_sibling_calls"));  static cl::opt<std::string>      AccountOutput("output", cl::value_desc("output file"), cl::init("-"),                    cl::desc("output file; use '-' for stdout"),                    cl::sub(Account));  static cl::alias AccountOutput2("o", cl::aliasopt(AccountOutput), -                                cl::desc("Alias for -output"), -                                cl::sub(Account)); +                                cl::desc("Alias for -output"));  enum class AccountOutputFormats { TEXT, CSV };  static cl::opt<AccountOutputFormats>      AccountOutputFormat("format", cl::desc("output format"), @@ -60,8 +57,7 @@ static cl::opt<AccountOutputFormats>                                                "report stats in csv")),                          cl::sub(Account));  static cl::alias AccountOutputFormat2("f", cl::desc("Alias of -format"), -                                      cl::aliasopt(AccountOutputFormat), -                                      cl::sub(Account)); +                                      cl::aliasopt(AccountOutputFormat));  enum class SortField {    FUNCID, @@ -88,8 +84,7 @@ static cl::opt<SortField> AccountSortOutput(                 clEnumValN(SortField::SUM, "sum", "sum of call durations"),                 clEnumValN(SortField::FUNC, "func", "function names")));  static cl::alias AccountSortOutput2("s", cl::aliasopt(AccountSortOutput), -                                    cl::desc("Alias for -sort"), -                                    cl::sub(Account)); +                                    cl::desc("Alias for -sort"));  enum class SortDirection {    ASCENDING, @@ -101,14 +96,13 @@ static cl::opt<SortDirection> AccountSortOrder(                 clEnumValN(SortDirection::DESCENDING, "dsc", "descending")),      cl::sub(Account));  static cl::alias AccountSortOrder2("r", cl::aliasopt(AccountSortOrder), -                                   cl::desc("Alias for -sortorder"), -                                   cl::sub(Account)); +                                   cl::desc("Alias for -sortorder"));  static cl::opt<int> AccountTop("top", cl::desc("only show the top N results"),                                 cl::value_desc("N"), cl::sub(Account),                                 cl::init(-1));  static cl::alias AccountTop2("p", cl::desc("Alias for -top"), -                             cl::aliasopt(AccountTop), cl::sub(Account)); +                             cl::aliasopt(AccountTop));  static cl::opt<std::string>      AccountInstrMap("instr_map", @@ -117,8 +111,7 @@ static cl::opt<std::string>                      cl::value_desc("binary with xray_instr_map"),                      cl::sub(Account), cl::init(""));  static cl::alias AccountInstrMap2("m", cl::aliasopt(AccountInstrMap), -                                  cl::desc("Alias for -instr_map"), -                                  cl::sub(Account)); +                                  cl::desc("Alias for -instr_map"));  namespace { @@ -421,7 +414,7 @@ static CommandRegistration Unused(&Account, []() -> Error {    }    std::error_code EC; -  raw_fd_ostream OS(AccountOutput, EC, sys::fs::OpenFlags::F_Text); +  raw_fd_ostream OS(AccountOutput, EC, sys::fs::OpenFlags::OF_Text);    if (EC)      return make_error<StringError>(          Twine("Cannot open file '") + AccountOutput + "' for writing.", EC); diff --git a/contrib/llvm-project/llvm/tools/llvm-xray/xray-converter.cpp b/contrib/llvm-project/llvm/tools/llvm-xray/xray-converter.cpp index dfc757e0f276..c1a623f0f858 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/xray-converter.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/xray-converter.cpp @@ -43,23 +43,20 @@ static cl::opt<ConvertFormats> ConvertOutputFormat(                            "May be visualized with the Catapult trace viewer.")),      cl::sub(Convert));  static cl::alias ConvertOutputFormat2("f", cl::aliasopt(ConvertOutputFormat), -                                      cl::desc("Alias for -output-format"), -                                      cl::sub(Convert)); +                                      cl::desc("Alias for -output-format"));  static cl::opt<std::string>      ConvertOutput("output", cl::value_desc("output file"), cl::init("-"),                    cl::desc("output file; use '-' for stdout"),                    cl::sub(Convert));  static cl::alias ConvertOutput2("o", cl::aliasopt(ConvertOutput), -                                cl::desc("Alias for -output"), -                                cl::sub(Convert)); +                                cl::desc("Alias for -output"));  static cl::opt<bool>      ConvertSymbolize("symbolize",                       cl::desc("symbolize function ids from the input log"),                       cl::init(false), cl::sub(Convert));  static cl::alias ConvertSymbolize2("y", cl::aliasopt(ConvertSymbolize), -                                   cl::desc("Alias for -symbolize"), -                                   cl::sub(Convert)); +                                   cl::desc("Alias for -symbolize"));  static cl::opt<std::string>      ConvertInstrMap("instr_map", @@ -68,15 +65,13 @@ static cl::opt<std::string>                      cl::value_desc("binary with xray_instr_map"),                      cl::sub(Convert), cl::init(""));  static cl::alias ConvertInstrMap2("m", cl::aliasopt(ConvertInstrMap), -                                  cl::desc("Alias for -instr_map"), -                                  cl::sub(Convert)); +                                  cl::desc("Alias for -instr_map"));  static cl::opt<bool> ConvertSortInput(      "sort",      cl::desc("determines whether to sort input log records by timestamp"),      cl::sub(Convert), cl::init(true));  static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput), -                                   cl::desc("Alias for -sort"), -                                   cl::sub(Convert)); +                                   cl::desc("Alias for -sort"));  using llvm::yaml::Output; @@ -387,8 +382,8 @@ static CommandRegistration Unused(&Convert, []() -> Error {    std::error_code EC;    raw_fd_ostream OS(ConvertOutput, EC,                      ConvertOutputFormat == ConvertFormats::BINARY -                        ? sys::fs::OpenFlags::F_None -                        : sys::fs::OpenFlags::F_Text); +                        ? sys::fs::OpenFlags::OF_None +                        : sys::fs::OpenFlags::OF_Text);    if (EC)      return make_error<StringError>(          Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC); diff --git a/contrib/llvm-project/llvm/tools/llvm-xray/xray-extract.cpp b/contrib/llvm-project/llvm/tools/llvm-xray/xray-extract.cpp index 7c7d26b5a389..af9255af21c3 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/xray-extract.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/xray-extract.cpp @@ -38,15 +38,13 @@ static cl::opt<std::string>                    cl::desc("output file; use '-' for stdout"),                    cl::sub(Extract));  static cl::alias ExtractOutput2("o", cl::aliasopt(ExtractOutput), -                                cl::desc("Alias for -output"), -                                cl::sub(Extract)); +                                cl::desc("Alias for -output"));  static cl::opt<bool> ExtractSymbolize("symbolize", cl::value_desc("symbolize"),                                        cl::init(false),                                        cl::desc("symbolize functions"),                                        cl::sub(Extract));  static cl::alias ExtractSymbolize2("s", cl::aliasopt(ExtractSymbolize), -                                   cl::desc("alias for -symbolize"), -                                   cl::sub(Extract)); +                                   cl::desc("alias for -symbolize"));  namespace { @@ -80,7 +78,7 @@ static CommandRegistration Unused(&Extract, []() -> Error {                        InstrumentationMapOrError.takeError());    std::error_code EC; -  raw_fd_ostream OS(ExtractOutput, EC, sys::fs::OpenFlags::F_Text); +  raw_fd_ostream OS(ExtractOutput, EC, sys::fs::OpenFlags::OF_Text);    if (EC)      return make_error<StringError>(          Twine("Cannot open file '") + ExtractOutput + "' for writing.", EC); diff --git a/contrib/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp b/contrib/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp index 81a93cac57c4..295f7a78765f 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp @@ -51,7 +51,7 @@ static CommandRegistration Unused(&Dump, []() -> Error {    sys::fs::closeFile(*FDOrErr);    DataExtractor DE(StringRef(MappedFile.data(), MappedFile.size()), true, 8); -  uint32_t OffsetPtr = 0; +  uint64_t OffsetPtr = 0;    auto FileHeaderOrError = readBinaryFormatHeader(DE, OffsetPtr);    if (!FileHeaderOrError) diff --git a/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.cpp b/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.cpp index a514be97f40b..a1bca326930e 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.cpp @@ -41,22 +41,19 @@ static cl::opt<bool>                         cl::desc("Keep going on errors encountered"),                         cl::sub(GraphDiff), cl::init(false));  static cl::alias GraphDiffKeepGoingA("k", cl::aliasopt(GraphDiffKeepGoing), -                                     cl::desc("Alias for -keep-going"), -                                     cl::sub(GraphDiff)); +                                     cl::desc("Alias for -keep-going"));  static cl::opt<bool>      GraphDiffKeepGoing1("keep-going-1",                          cl::desc("Keep going on errors encountered in trace 1"),                          cl::sub(GraphDiff), cl::init(false));  static cl::alias GraphDiffKeepGoing1A("k1", cl::aliasopt(GraphDiffKeepGoing1), -                                      cl::desc("Alias for -keep-going-1"), -                                      cl::sub(GraphDiff)); +                                      cl::desc("Alias for -keep-going-1"));  static cl::opt<bool>      GraphDiffKeepGoing2("keep-going-2",                          cl::desc("Keep going on errors encountered in trace 2"),                          cl::sub(GraphDiff), cl::init(false));  static cl::alias GraphDiffKeepGoing2A("k2", cl::aliasopt(GraphDiffKeepGoing2), -                                      cl::desc("Alias for -keep-going-2"), -                                      cl::sub(GraphDiff)); +                                      cl::desc("Alias for -keep-going-2"));  static cl::opt<std::string>      GraphDiffInstrMap("instr-map", @@ -65,8 +62,7 @@ static cl::opt<std::string>                        cl::value_desc("binary with xray_instr_map or yaml"),                        cl::sub(GraphDiff), cl::init(""));  static cl::alias GraphDiffInstrMapA("m", cl::aliasopt(GraphDiffInstrMap), -                                    cl::desc("Alias for -instr-map"), -                                    cl::sub(GraphDiff)); +                                    cl::desc("Alias for -instr-map"));  static cl::opt<std::string>      GraphDiffInstrMap1("instr-map-1",                         cl::desc("binary with the instrumentation map, or " @@ -74,8 +70,7 @@ static cl::opt<std::string>                         cl::value_desc("binary with xray_instr_map or yaml"),                         cl::sub(GraphDiff), cl::init(""));  static cl::alias GraphDiffInstrMap1A("m1", cl::aliasopt(GraphDiffInstrMap1), -                                     cl::desc("Alias for -instr-map-1"), -                                     cl::sub(GraphDiff)); +                                     cl::desc("Alias for -instr-map-1"));  static cl::opt<std::string>      GraphDiffInstrMap2("instr-map-2",                         cl::desc("binary with the instrumentation map, or " @@ -83,8 +78,7 @@ static cl::opt<std::string>                         cl::value_desc("binary with xray_instr_map or yaml"),                         cl::sub(GraphDiff), cl::init(""));  static cl::alias GraphDiffInstrMap2A("m2", cl::aliasopt(GraphDiffInstrMap2), -                                     cl::desc("Alias for -instr-map-2"), -                                     cl::sub(GraphDiff)); +                                     cl::desc("Alias for -instr-map-2"));  static cl::opt<bool> GraphDiffDeduceSiblingCalls(      "deduce-sibling-calls", @@ -92,22 +86,21 @@ static cl::opt<bool> GraphDiffDeduceSiblingCalls(      cl::sub(GraphDiff), cl::init(false));  static cl::alias      GraphDiffDeduceSiblingCallsA("d", cl::aliasopt(GraphDiffDeduceSiblingCalls), -                                 cl::desc("Alias for -deduce-sibling-calls"), -                                 cl::sub(GraphDiff)); +                                 cl::desc("Alias for -deduce-sibling-calls"));  static cl::opt<bool> GraphDiffDeduceSiblingCalls1(      "deduce-sibling-calls-1",      cl::desc("Deduce sibling calls when unrolling function call stacks"),      cl::sub(GraphDiff), cl::init(false));  static cl::alias GraphDiffDeduceSiblingCalls1A(      "d1", cl::aliasopt(GraphDiffDeduceSiblingCalls1), -    cl::desc("Alias for -deduce-sibling-calls-1"), cl::sub(GraphDiff)); +    cl::desc("Alias for -deduce-sibling-calls-1"));  static cl::opt<bool> GraphDiffDeduceSiblingCalls2(      "deduce-sibling-calls-2",      cl::desc("Deduce sibling calls when unrolling function call stacks"),      cl::sub(GraphDiff), cl::init(false));  static cl::alias GraphDiffDeduceSiblingCalls2A(      "d2", cl::aliasopt(GraphDiffDeduceSiblingCalls2), -    cl::desc("Alias for -deduce-sibling-calls-2"), cl::sub(GraphDiff)); +    cl::desc("Alias for -deduce-sibling-calls-2"));  static cl::opt<GraphRenderer::StatType> GraphDiffEdgeLabel(      "edge-label", cl::desc("Output graphs with edges labeled with this field"), @@ -130,8 +123,7 @@ static cl::opt<GraphRenderer::StatType> GraphDiffEdgeLabel(                 clEnumValN(GraphRenderer::StatType::SUM, "sum",                            "sum of call durations")));  static cl::alias GraphDiffEdgeLabelA("e", cl::aliasopt(GraphDiffEdgeLabel), -                                     cl::desc("Alias for -edge-label"), -                                     cl::sub(GraphDiff)); +                                     cl::desc("Alias for -edge-label"));  static cl::opt<GraphRenderer::StatType> GraphDiffEdgeColor(      "edge-color", cl::desc("Output graphs with edges colored by this field"), @@ -154,8 +146,7 @@ static cl::opt<GraphRenderer::StatType> GraphDiffEdgeColor(                 clEnumValN(GraphRenderer::StatType::SUM, "sum",                            "sum of call durations")));  static cl::alias GraphDiffEdgeColorA("c", cl::aliasopt(GraphDiffEdgeColor), -                                     cl::desc("Alias for -edge-color"), -                                     cl::sub(GraphDiff)); +                                     cl::desc("Alias for -edge-color"));  static cl::opt<GraphRenderer::StatType> GraphDiffVertexLabel(      "vertex-label", @@ -179,8 +170,7 @@ static cl::opt<GraphRenderer::StatType> GraphDiffVertexLabel(                 clEnumValN(GraphRenderer::StatType::SUM, "sum",                            "sum of call durations")));  static cl::alias GraphDiffVertexLabelA("v", cl::aliasopt(GraphDiffVertexLabel), -                                       cl::desc("Alias for -vertex-label"), -                                       cl::sub(GraphDiff)); +                                       cl::desc("Alias for -vertex-label"));  static cl::opt<GraphRenderer::StatType> GraphDiffVertexColor(      "vertex-color", @@ -204,24 +194,21 @@ static cl::opt<GraphRenderer::StatType> GraphDiffVertexColor(                 clEnumValN(GraphRenderer::StatType::SUM, "sum",                            "sum of call durations")));  static cl::alias GraphDiffVertexColorA("b", cl::aliasopt(GraphDiffVertexColor), -                                       cl::desc("Alias for -vertex-color"), -                                       cl::sub(GraphDiff)); +                                       cl::desc("Alias for -vertex-color"));  static cl::opt<int> GraphDiffVertexLabelTrunc(      "vertex-label-trun", cl::desc("What length to truncate vertex labels to "),      cl::sub(GraphDiff), cl::init(40));  static cl::alias      GraphDiffVertexLabelTrunc1("t", cl::aliasopt(GraphDiffVertexLabelTrunc), -                               cl::desc("Alias for -vertex-label-trun"), -                               cl::sub(GraphDiff)); +                               cl::desc("Alias for -vertex-label-trun"));  static cl::opt<std::string>      GraphDiffOutput("output", cl::value_desc("Output file"), cl::init("-"),                      cl::desc("output file; use '-' for stdout"),                      cl::sub(GraphDiff));  static cl::alias GraphDiffOutputA("o", cl::aliasopt(GraphDiffOutput), -                                  cl::desc("Alias for -output"), -                                  cl::sub(GraphDiff)); +                                  cl::desc("Alias for -output"));  Expected<GraphDiffRenderer> GraphDiffRenderer::Factory::getGraphDiffRenderer() {    GraphDiffRenderer R; @@ -470,7 +457,7 @@ static CommandRegistration Unused(&GraphDiff, []() -> Error {    auto &GDR = *GDROrErr;    std::error_code EC; -  raw_fd_ostream OS(GraphDiffOutput, EC, sys::fs::OpenFlags::F_Text); +  raw_fd_ostream OS(GraphDiffOutput, EC, sys::fs::OpenFlags::OF_Text);    if (EC)      return make_error<StringError>(          Twine("Cannot open file '") + GraphDiffOutput + "' for writing.", EC); 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 c09357fcb502..f836f9ba54fc 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp @@ -30,14 +30,13 @@ static cl::opt<bool>      GraphKeepGoing("keep-going", cl::desc("Keep going on errors encountered"),                     cl::sub(GraphC), cl::init(false));  static cl::alias GraphKeepGoing2("k", cl::aliasopt(GraphKeepGoing), -                                 cl::desc("Alias for -keep-going"), -                                 cl::sub(GraphC)); +                                 cl::desc("Alias for -keep-going"));  static cl::opt<std::string>      GraphOutput("output", cl::value_desc("Output file"), cl::init("-"),                  cl::desc("output file; use '-' for stdout"), cl::sub(GraphC));  static cl::alias GraphOutput2("o", cl::aliasopt(GraphOutput), -                              cl::desc("Alias for -output"), cl::sub(GraphC)); +                              cl::desc("Alias for -output"));  static cl::opt<std::string>      GraphInstrMap("instr_map", @@ -46,8 +45,7 @@ static cl::opt<std::string>                    cl::value_desc("binary with xray_instr_map"), cl::sub(GraphC),                    cl::init(""));  static cl::alias GraphInstrMap2("m", cl::aliasopt(GraphInstrMap), -                                cl::desc("alias for -instr_map"), -                                cl::sub(GraphC)); +                                cl::desc("alias for -instr_map"));  static cl::opt<bool> GraphDeduceSiblingCalls(      "deduce-sibling-calls", @@ -55,8 +53,7 @@ static cl::opt<bool> GraphDeduceSiblingCalls(      cl::sub(GraphC), cl::init(false));  static cl::alias      GraphDeduceSiblingCalls2("d", cl::aliasopt(GraphDeduceSiblingCalls), -                             cl::desc("Alias for -deduce-sibling-calls"), -                             cl::sub(GraphC)); +                             cl::desc("Alias for -deduce-sibling-calls"));  static cl::opt<GraphRenderer::StatType>      GraphEdgeLabel("edge-label", @@ -80,8 +77,7 @@ static cl::opt<GraphRenderer::StatType>                                clEnumValN(GraphRenderer::StatType::SUM, "sum",                                           "sum of call durations")));  static cl::alias GraphEdgeLabel2("e", cl::aliasopt(GraphEdgeLabel), -                                 cl::desc("Alias for -edge-label"), -                                 cl::sub(GraphC)); +                                 cl::desc("Alias for -edge-label"));  static cl::opt<GraphRenderer::StatType> GraphVertexLabel(      "vertex-label", @@ -105,8 +101,7 @@ static cl::opt<GraphRenderer::StatType> GraphVertexLabel(                 clEnumValN(GraphRenderer::StatType::SUM, "sum",                            "sum of call durations")));  static cl::alias GraphVertexLabel2("v", cl::aliasopt(GraphVertexLabel), -                                   cl::desc("Alias for -edge-label"), -                                   cl::sub(GraphC)); +                                   cl::desc("Alias for -edge-label"));  static cl::opt<GraphRenderer::StatType> GraphEdgeColorType(      "color-edges", @@ -130,8 +125,7 @@ static cl::opt<GraphRenderer::StatType> GraphEdgeColorType(                 clEnumValN(GraphRenderer::StatType::SUM, "sum",                            "sum of call durations")));  static cl::alias GraphEdgeColorType2("c", cl::aliasopt(GraphEdgeColorType), -                                     cl::desc("Alias for -color-edges"), -                                     cl::sub(GraphC)); +                                     cl::desc("Alias for -color-edges"));  static cl::opt<GraphRenderer::StatType> GraphVertexColorType(      "color-vertices", @@ -155,8 +149,7 @@ static cl::opt<GraphRenderer::StatType> GraphVertexColorType(                 clEnumValN(GraphRenderer::StatType::SUM, "sum",                            "sum of call durations")));  static cl::alias GraphVertexColorType2("b", cl::aliasopt(GraphVertexColorType), -                                       cl::desc("Alias for -edge-label"), -                                       cl::sub(GraphC)); +                                       cl::desc("Alias for -edge-label"));  template <class T> T diff(T L, T R) { return std::max(L, R) - std::min(L, R); } @@ -506,7 +499,7 @@ static CommandRegistration Unused(&GraphC, []() -> Error {    auto &GR = *GROrError;    std::error_code EC; -  raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::F_Text); +  raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::OF_Text);    if (EC)      return make_error<StringError>(          Twine("Cannot open file '") + GraphOutput + "' for writing.", EC); diff --git a/contrib/llvm-project/llvm/tools/llvm-xray/xray-stacks.cpp b/contrib/llvm-project/llvm/tools/llvm-xray/xray-stacks.cpp index bcfc5cb1f1be..cf292887b6b8 100644 --- a/contrib/llvm-project/llvm/tools/llvm-xray/xray-stacks.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-xray/xray-stacks.cpp @@ -42,8 +42,7 @@ static cl::opt<bool>      StackKeepGoing("keep-going", cl::desc("Keep going on errors encountered"),                     cl::sub(Stack), cl::init(false));  static cl::alias StackKeepGoing2("k", cl::aliasopt(StackKeepGoing), -                                 cl::desc("Alias for -keep-going"), -                                 cl::sub(Stack)); +                                 cl::desc("Alias for -keep-going"));  // TODO: Does there need to be an option to deduce tail or sibling calls? @@ -53,8 +52,7 @@ static cl::opt<std::string> StacksInstrMap(               "Currently supports elf file instrumentation maps."),      cl::sub(Stack), cl::init(""));  static cl::alias StacksInstrMap2("m", cl::aliasopt(StacksInstrMap), -                                 cl::desc("Alias for -instr_map"), -                                 cl::sub(Stack)); +                                 cl::desc("Alias for -instr_map"));  static cl::opt<bool>      SeparateThreadStacks("per-thread-stacks", @@ -72,8 +70,7 @@ static cl::opt<bool>                             "By default separates stacks per-thread."),                    cl::sub(Stack), cl::init(false));  static cl::alias DumpAllStacksShort("all", cl::aliasopt(DumpAllStacks), -                                    cl::desc("Alias for -all-stacks"), -                                    cl::sub(Stack)); +                                    cl::desc("Alias for -all-stacks"));  // TODO(kpw): Add other interesting formats. Perhaps chrome trace viewer format  // possibly with aggregations or just a linear trace of timings. diff --git a/contrib/llvm-project/llvm/tools/opt/Debugify.cpp b/contrib/llvm-project/llvm/tools/opt/Debugify.cpp deleted file mode 100644 index 222cc702bc1f..000000000000 --- a/contrib/llvm-project/llvm/tools/opt/Debugify.cpp +++ /dev/null @@ -1,463 +0,0 @@ -//===- Debugify.cpp - Attach synthetic debug info to everything -----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file This pass attaches synthetic debug info to everything. It can be used -/// to create targeted tests for debug info preservation. -/// -//===----------------------------------------------------------------------===// - -#include "Debugify.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DIBuilder.h" -#include "llvm/IR/DebugInfo.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/Pass.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/IPO.h" - -using namespace llvm; - -namespace { - -cl::opt<bool> Quiet("debugify-quiet", -                    cl::desc("Suppress verbose debugify output")); - -raw_ostream &dbg() { return Quiet ? nulls() : errs(); } - -uint64_t getAllocSizeInBits(Module &M, Type *Ty) { -  return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0; -} - -bool isFunctionSkipped(Function &F) { -  return F.isDeclaration() || !F.hasExactDefinition(); -} - -/// Find the basic block's terminating instruction. -/// -/// Special care is needed to handle musttail and deopt calls, as these behave -/// like (but are in fact not) terminators. -Instruction *findTerminatingInstruction(BasicBlock &BB) { -  if (auto *I = BB.getTerminatingMustTailCall()) -    return I; -  if (auto *I = BB.getTerminatingDeoptimizeCall()) -    return I; -  return BB.getTerminator(); -} - -bool applyDebugifyMetadata(Module &M, -                           iterator_range<Module::iterator> Functions, -                           StringRef Banner) { -  // Skip modules with debug info. -  if (M.getNamedMetadata("llvm.dbg.cu")) { -    dbg() << Banner << "Skipping module with debug info\n"; -    return false; -  } - -  DIBuilder DIB(M); -  LLVMContext &Ctx = M.getContext(); - -  // Get a DIType which corresponds to Ty. -  DenseMap<uint64_t, DIType *> TypeCache; -  auto getCachedDIType = [&](Type *Ty) -> DIType * { -    uint64_t Size = getAllocSizeInBits(M, Ty); -    DIType *&DTy = TypeCache[Size]; -    if (!DTy) { -      std::string Name = "ty" + utostr(Size); -      DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned); -    } -    return DTy; -  }; - -  unsigned NextLine = 1; -  unsigned NextVar = 1; -  auto File = DIB.createFile(M.getName(), "/"); -  auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "debugify", -                                  /*isOptimized=*/true, "", 0); - -  // Visit each instruction. -  for (Function &F : Functions) { -    if (isFunctionSkipped(F)) -      continue; - -    auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); -    DISubprogram::DISPFlags SPFlags = -        DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized; -    if (F.hasPrivateLinkage() || F.hasInternalLinkage()) -      SPFlags |= DISubprogram::SPFlagLocalToUnit; -    auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine, -                                 SPType, NextLine, DINode::FlagZero, SPFlags); -    F.setSubprogram(SP); -    for (BasicBlock &BB : F) { -      // Attach debug locations. -      for (Instruction &I : BB) -        I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); - -      // Inserting debug values into EH pads can break IR invariants. -      if (BB.isEHPad()) -        continue; - -      // Find the terminating instruction, after which no debug values are -      // attached. -      Instruction *LastInst = findTerminatingInstruction(BB); -      assert(LastInst && "Expected basic block with a terminator"); - -      // Maintain an insertion point which can't be invalidated when updates -      // are made. -      BasicBlock::iterator InsertPt = BB.getFirstInsertionPt(); -      assert(InsertPt != BB.end() && "Expected to find an insertion point"); -      Instruction *InsertBefore = &*InsertPt; - -      // Attach debug values. -      for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) { -        // Skip void-valued instructions. -        if (I->getType()->isVoidTy()) -          continue; - -        // Phis and EH pads must be grouped at the beginning of the block. -        // Only advance the insertion point when we finish visiting these. -        if (!isa<PHINode>(I) && !I->isEHPad()) -          InsertBefore = I->getNextNode(); - -        std::string Name = utostr(NextVar++); -        const DILocation *Loc = I->getDebugLoc().get(); -        auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(), -                                               getCachedDIType(I->getType()), -                                               /*AlwaysPreserve=*/true); -        DIB.insertDbgValueIntrinsic(I, LocalVar, DIB.createExpression(), Loc, -                                    InsertBefore); -      } -    } -    DIB.finalizeSubprogram(SP); -  } -  DIB.finalize(); - -  // Track the number of distinct lines and variables. -  NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify"); -  auto *IntTy = Type::getInt32Ty(Ctx); -  auto addDebugifyOperand = [&](unsigned N) { -    NMD->addOperand(MDNode::get( -        Ctx, ValueAsMetadata::getConstant(ConstantInt::get(IntTy, N)))); -  }; -  addDebugifyOperand(NextLine - 1); // Original number of lines. -  addDebugifyOperand(NextVar - 1);  // Original number of variables. -  assert(NMD->getNumOperands() == 2 && -         "llvm.debugify should have exactly 2 operands!"); - -  // Claim that this synthetic debug info is valid. -  StringRef DIVersionKey = "Debug Info Version"; -  if (!M.getModuleFlag(DIVersionKey)) -    M.addModuleFlag(Module::Warning, DIVersionKey, DEBUG_METADATA_VERSION); - -  return true; -} - -/// Return true if a mis-sized diagnostic is issued for \p DVI. -bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { -  // The size of a dbg.value's value operand should match the size of the -  // variable it corresponds to. -  // -  // TODO: This, along with a check for non-null value operands, should be -  // promoted to verifier failures. -  Value *V = DVI->getValue(); -  if (!V) -    return false; - -  // For now, don't try to interpret anything more complicated than an empty -  // DIExpression. Eventually we should try to handle OP_deref and fragments. -  if (DVI->getExpression()->getNumElements()) -    return false; - -  Type *Ty = V->getType(); -  uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty); -  Optional<uint64_t> DbgVarSize = DVI->getFragmentSizeInBits(); -  if (!ValueOperandSize || !DbgVarSize) -    return false; - -  bool HasBadSize = false; -  if (Ty->isIntegerTy()) { -    auto Signedness = DVI->getVariable()->getSignedness(); -    if (Signedness && *Signedness == DIBasicType::Signedness::Signed) -      HasBadSize = ValueOperandSize < *DbgVarSize; -  } else { -    HasBadSize = ValueOperandSize != *DbgVarSize; -  } - -  if (HasBadSize) { -    dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize -          << ", but its variable has size " << *DbgVarSize << ": "; -    DVI->print(dbg()); -    dbg() << "\n"; -  } -  return HasBadSize; -} - -bool checkDebugifyMetadata(Module &M, -                           iterator_range<Module::iterator> Functions, -                           StringRef NameOfWrappedPass, StringRef Banner, -                           bool Strip, DebugifyStatsMap *StatsMap) { -  // Skip modules without debugify metadata. -  NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify"); -  if (!NMD) { -    dbg() << Banner << "Skipping module without debugify metadata\n"; -    return false; -  } - -  auto getDebugifyOperand = [&](unsigned Idx) -> unsigned { -    return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0)) -        ->getZExtValue(); -  }; -  assert(NMD->getNumOperands() == 2 && -         "llvm.debugify should have exactly 2 operands!"); -  unsigned OriginalNumLines = getDebugifyOperand(0); -  unsigned OriginalNumVars = getDebugifyOperand(1); -  bool HasErrors = false; - -  // Track debug info loss statistics if able. -  DebugifyStatistics *Stats = nullptr; -  if (StatsMap && !NameOfWrappedPass.empty()) -    Stats = &StatsMap->operator[](NameOfWrappedPass); - -  BitVector MissingLines{OriginalNumLines, true}; -  BitVector MissingVars{OriginalNumVars, true}; -  for (Function &F : Functions) { -    if (isFunctionSkipped(F)) -      continue; - -    // Find missing lines. -    for (Instruction &I : instructions(F)) { -      if (isa<DbgValueInst>(&I)) -        continue; - -      auto DL = I.getDebugLoc(); -      if (DL && DL.getLine() != 0) { -        MissingLines.reset(DL.getLine() - 1); -        continue; -      } - -      if (!DL) { -        dbg() << "ERROR: Instruction with empty DebugLoc in function "; -        dbg() << F.getName() << " --"; -        I.print(dbg()); -        dbg() << "\n"; -        HasErrors = true; -      } -    } - -    // Find missing variables and mis-sized debug values. -    for (Instruction &I : instructions(F)) { -      auto *DVI = dyn_cast<DbgValueInst>(&I); -      if (!DVI) -        continue; - -      unsigned Var = ~0U; -      (void)to_integer(DVI->getVariable()->getName(), Var, 10); -      assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable"); -      bool HasBadSize = diagnoseMisSizedDbgValue(M, DVI); -      if (!HasBadSize) -        MissingVars.reset(Var - 1); -      HasErrors |= HasBadSize; -    } -  } - -  // Print the results. -  for (unsigned Idx : MissingLines.set_bits()) -    dbg() << "WARNING: Missing line " << Idx + 1 << "\n"; - -  for (unsigned Idx : MissingVars.set_bits()) -    dbg() << "WARNING: Missing variable " << Idx + 1 << "\n"; - -  // Update DI loss statistics. -  if (Stats) { -    Stats->NumDbgLocsExpected += OriginalNumLines; -    Stats->NumDbgLocsMissing += MissingLines.count(); -    Stats->NumDbgValuesExpected += OriginalNumVars; -    Stats->NumDbgValuesMissing += MissingVars.count(); -  } - -  dbg() << Banner; -  if (!NameOfWrappedPass.empty()) -    dbg() << " [" << NameOfWrappedPass << "]"; -  dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n'; - -  // Strip the Debugify Metadata if required. -  if (Strip) { -    StripDebugInfo(M); -    M.eraseNamedMetadata(NMD); -    return true; -  } - -  return false; -} - -/// ModulePass for attaching synthetic debug info to everything, used with the -/// legacy module pass manager. -struct DebugifyModulePass : public ModulePass { -  bool runOnModule(Module &M) override { -    return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); -  } - -  DebugifyModulePass() : ModulePass(ID) {} - -  void getAnalysisUsage(AnalysisUsage &AU) const override { -    AU.setPreservesAll(); -  } - -  static char ID; // Pass identification. -}; - -/// FunctionPass for attaching synthetic debug info to instructions within a -/// single function, used with the legacy module pass manager. -struct DebugifyFunctionPass : public FunctionPass { -  bool runOnFunction(Function &F) override { -    Module &M = *F.getParent(); -    auto FuncIt = F.getIterator(); -    return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), -                                 "FunctionDebugify: "); -  } - -  DebugifyFunctionPass() : FunctionPass(ID) {} - -  void getAnalysisUsage(AnalysisUsage &AU) const override { -    AU.setPreservesAll(); -  } - -  static char ID; // Pass identification. -}; - -/// ModulePass for checking debug info inserted by -debugify, used with the -/// legacy module pass manager. -struct CheckDebugifyModulePass : public ModulePass { -  bool runOnModule(Module &M) override { -    return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass, -                                 "CheckModuleDebugify", Strip, StatsMap); -  } - -  CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "", -                          DebugifyStatsMap *StatsMap = nullptr) -      : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), -        StatsMap(StatsMap) {} - -  void getAnalysisUsage(AnalysisUsage &AU) const override { -    AU.setPreservesAll(); -  } - -  static char ID; // Pass identification. - -private: -  bool Strip; -  StringRef NameOfWrappedPass; -  DebugifyStatsMap *StatsMap; -}; - -/// FunctionPass for checking debug info inserted by -debugify-function, used -/// with the legacy module pass manager. -struct CheckDebugifyFunctionPass : public FunctionPass { -  bool runOnFunction(Function &F) override { -    Module &M = *F.getParent(); -    auto FuncIt = F.getIterator(); -    return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), -                                 NameOfWrappedPass, "CheckFunctionDebugify", -                                 Strip, StatsMap); -  } - -  CheckDebugifyFunctionPass(bool Strip = false, -                            StringRef NameOfWrappedPass = "", -                            DebugifyStatsMap *StatsMap = nullptr) -      : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), -        StatsMap(StatsMap) {} - -  void getAnalysisUsage(AnalysisUsage &AU) const override { -    AU.setPreservesAll(); -  } - -  static char ID; // Pass identification. - -private: -  bool Strip; -  StringRef NameOfWrappedPass; -  DebugifyStatsMap *StatsMap; -}; - -} // end anonymous namespace - -void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map) { -  std::error_code EC; -  raw_fd_ostream OS{Path, EC}; -  if (EC) { -    errs() << "Could not open file: " << EC.message() << ", " << Path << '\n'; -    return; -  } - -  OS << "Pass Name" << ',' << "# of missing debug values" << ',' -     << "# of missing locations" << ',' << "Missing/Expected value ratio" << ',' -     << "Missing/Expected location ratio" << '\n'; -  for (const auto &Entry : Map) { -    StringRef Pass = Entry.first; -    DebugifyStatistics Stats = Entry.second; - -    OS << Pass << ',' << Stats.NumDbgValuesMissing << ',' -       << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ',' -       << Stats.getEmptyLocationRatio() << '\n'; -  } -} - -ModulePass *createDebugifyModulePass() { return new DebugifyModulePass(); } - -FunctionPass *createDebugifyFunctionPass() { -  return new DebugifyFunctionPass(); -} - -PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { -  applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); -  return PreservedAnalyses::all(); -} - -ModulePass *createCheckDebugifyModulePass(bool Strip, -                                          StringRef NameOfWrappedPass, -                                          DebugifyStatsMap *StatsMap) { -  return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap); -} - -FunctionPass *createCheckDebugifyFunctionPass(bool Strip, -                                              StringRef NameOfWrappedPass, -                                              DebugifyStatsMap *StatsMap) { -  return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap); -} - -PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M, -                                              ModuleAnalysisManager &) { -  checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false, -                        nullptr); -  return PreservedAnalyses::all(); -} - -char DebugifyModulePass::ID = 0; -static RegisterPass<DebugifyModulePass> DM("debugify", -                                           "Attach debug info to everything"); - -char CheckDebugifyModulePass::ID = 0; -static RegisterPass<CheckDebugifyModulePass> -    CDM("check-debugify", "Check debug info from -debugify"); - -char DebugifyFunctionPass::ID = 0; -static RegisterPass<DebugifyFunctionPass> DF("debugify-function", -                                             "Attach debug info to a function"); - -char CheckDebugifyFunctionPass::ID = 0; -static RegisterPass<CheckDebugifyFunctionPass> -    CDF("check-debugify-function", "Check debug info from -debugify-function"); diff --git a/contrib/llvm-project/llvm/tools/opt/Debugify.h b/contrib/llvm-project/llvm/tools/opt/Debugify.h deleted file mode 100644 index 266f577951ae..000000000000 --- a/contrib/llvm-project/llvm/tools/opt/Debugify.h +++ /dev/null @@ -1,74 +0,0 @@ -//===- Debugify.h - Attach synthetic debug info to everything -------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file Interface to the `debugify` synthetic debug info testing utility. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_OPT_DEBUGIFY_H -#define LLVM_TOOLS_OPT_DEBUGIFY_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/IR/PassManager.h" -#include "llvm/Support/raw_ostream.h" - -llvm::ModulePass *createDebugifyModulePass(); -llvm::FunctionPass *createDebugifyFunctionPass(); - -struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> { -  llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); -}; - -/// Track how much `debugify` information has been lost. -struct DebugifyStatistics { -  /// Number of missing dbg.values. -  unsigned NumDbgValuesMissing = 0; - -  /// Number of dbg.values expected. -  unsigned NumDbgValuesExpected = 0; - -  /// Number of instructions with empty debug locations. -  unsigned NumDbgLocsMissing = 0; - -  /// Number of instructions expected to have debug locations. -  unsigned NumDbgLocsExpected = 0; - -  /// Get the ratio of missing/expected dbg.values. -  float getMissingValueRatio() const { -    return float(NumDbgValuesMissing) / float(NumDbgLocsExpected); -  } - -  /// Get the ratio of missing/expected instructions with locations. -  float getEmptyLocationRatio() const { -    return float(NumDbgLocsMissing) / float(NumDbgLocsExpected); -  } -}; - -/// Map pass names to a per-pass DebugifyStatistics instance. -using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>; - -/// Export per-pass debugify statistics to the file specified by \p Path. -void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map); - -llvm::ModulePass * -createCheckDebugifyModulePass(bool Strip = false, -                              llvm::StringRef NameOfWrappedPass = "", -                              DebugifyStatsMap *StatsMap = nullptr); - -llvm::FunctionPass * -createCheckDebugifyFunctionPass(bool Strip = false, -                                llvm::StringRef NameOfWrappedPass = "", -                                DebugifyStatsMap *StatsMap = nullptr); - -struct NewPMCheckDebugifyPass -    : public llvm::PassInfoMixin<NewPMCheckDebugifyPass> { -  llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); -}; - -#endif // LLVM_TOOLS_OPT_DEBUGIFY_H diff --git a/contrib/llvm-project/llvm/tools/opt/NewPMDriver.cpp b/contrib/llvm-project/llvm/tools/opt/NewPMDriver.cpp index efe0bec35d72..ac04a32d93fd 100644 --- a/contrib/llvm-project/llvm/tools/opt/NewPMDriver.cpp +++ b/contrib/llvm-project/llvm/tools/opt/NewPMDriver.cpp @@ -13,7 +13,6 @@  //===----------------------------------------------------------------------===//  #include "NewPMDriver.h" -#include "Debugify.h"  #include "PassPrinters.h"  #include "llvm/ADT/StringRef.h"  #include "llvm/Analysis/AliasAnalysis.h" @@ -35,6 +34,7 @@  #include "llvm/Target/TargetMachine.h"  #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"  #include "llvm/Transforms/Scalar/LoopPassManager.h" +#include "llvm/Transforms/Utils/Debugify.h"  using namespace llvm;  using namespace opt_tool; @@ -202,11 +202,9 @@ static void registerEPCallbacks(PassBuilder &PB, bool VerifyEachPass,          });  } -#ifdef LINK_POLLY_INTO_TOOLS -namespace polly { -void RegisterPollyPasses(PassBuilder &); -} -#endif +#define HANDLE_EXTENSION(Ext)                                                  \ +  llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); +#include "llvm/Support/Extension.def"  bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM,                             ToolOutputFile *Out, ToolOutputFile *ThinLTOLinkOut, @@ -290,9 +288,9 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM,          return false;        }); -#ifdef LINK_POLLY_INTO_TOOLS -  polly::RegisterPollyPasses(PB); -#endif +#define HANDLE_EXTENSION(Ext)                                                  \ +  get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB); +#include "llvm/Support/Extension.def"    // Specially handle the alias analysis manager so that we can register    // a custom pipeline of AA passes with it. diff --git a/contrib/llvm-project/llvm/tools/opt/PassPrinters.cpp b/contrib/llvm-project/llvm/tools/opt/PassPrinters.cpp index 70da6a43f8d9..a877d9dc90f4 100644 --- a/contrib/llvm-project/llvm/tools/opt/PassPrinters.cpp +++ b/contrib/llvm-project/llvm/tools/opt/PassPrinters.cpp @@ -198,40 +198,6 @@ struct RegionPassPrinter : public RegionPass {  char RegionPassPrinter::ID = 0; -struct BasicBlockPassPrinter : public BasicBlockPass { -  const PassInfo *PassToPrint; -  raw_ostream &Out; -  static char ID; -  std::string PassName; -  bool QuietPass; - -  BasicBlockPassPrinter(const PassInfo *PI, raw_ostream &out, bool Quiet) -      : BasicBlockPass(ID), PassToPrint(PI), Out(out), QuietPass(Quiet) { -    std::string PassToPrintName = PassToPrint->getPassName(); -    PassName = "BasicBlockPass Printer: " + PassToPrintName; -  } - -  bool runOnBasicBlock(BasicBlock &BB) override { -    if (!QuietPass) -      Out << "Printing Analysis info for BasicBlock '" << BB.getName() -          << "': Pass " << PassToPrint->getPassName() << ":\n"; - -    // Get and print pass... -    getAnalysisID<Pass>(PassToPrint->getTypeInfo()) -        .print(Out, BB.getParent()->getParent()); -    return false; -  } - -  StringRef getPassName() const override { return PassName; } - -  void getAnalysisUsage(AnalysisUsage &AU) const override { -    AU.addRequiredID(PassToPrint->getTypeInfo()); -    AU.setPreservesAll(); -  } -}; - -char BasicBlockPassPrinter::ID = 0; -  } // end anonymous namespace  FunctionPass *llvm::createFunctionPassPrinter(const PassInfo *PI, @@ -260,7 +226,3 @@ RegionPass *llvm::createRegionPassPrinter(const PassInfo *PI, raw_ostream &OS,    return new RegionPassPrinter(PI, OS, Quiet);  } -BasicBlockPass *llvm::createBasicBlockPassPrinter(const PassInfo *PI, -                                                  raw_ostream &OS, bool Quiet) { -  return new BasicBlockPassPrinter(PI, OS, Quiet); -} diff --git a/contrib/llvm-project/llvm/tools/opt/PassPrinters.h b/contrib/llvm-project/llvm/tools/opt/PassPrinters.h index d4e7a4a97f31..692befbdae75 100644 --- a/contrib/llvm-project/llvm/tools/opt/PassPrinters.h +++ b/contrib/llvm-project/llvm/tools/opt/PassPrinters.h @@ -18,7 +18,6 @@  namespace llvm { -class BasicBlockPass;  class CallGraphSCCPass;  class FunctionPass;  class ModulePass; @@ -43,9 +42,6 @@ LoopPass *createLoopPassPrinter(const PassInfo *PI, raw_ostream &out,  RegionPass *createRegionPassPrinter(const PassInfo *PI, raw_ostream &out,                                      bool Quiet); -BasicBlockPass *createBasicBlockPassPrinter(const PassInfo *PI, -                                            raw_ostream &out, bool Quiet); -  } // end namespace llvm  #endif // LLVM_TOOLS_OPT_PASSPRINTERS_H diff --git a/contrib/llvm-project/llvm/tools/opt/opt.cpp b/contrib/llvm-project/llvm/tools/opt/opt.cpp index 2ee028e774f4..75a6cdc3892b 100644 --- a/contrib/llvm-project/llvm/tools/opt/opt.cpp +++ b/contrib/llvm-project/llvm/tools/opt/opt.cpp @@ -12,7 +12,6 @@  //===----------------------------------------------------------------------===//  #include "BreakpointPrinter.h" -#include "Debugify.h"  #include "NewPMDriver.h"  #include "PassPrinters.h"  #include "llvm/ADT/Triple.h" @@ -56,6 +55,7 @@  #include "llvm/Transforms/IPO/AlwaysInliner.h"  #include "llvm/Transforms/IPO/PassManagerBuilder.h"  #include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/Debugify.h"  #include <algorithm>  #include <memory>  using namespace llvm; @@ -193,6 +193,12 @@ static cl::opt<bool>  DisableSimplifyLibCalls("disable-simplify-libcalls",                          cl::desc("Disable simplify-libcalls")); +static cl::list<std::string> +DisableBuiltins("disable-builtin", +                cl::desc("Disable specific target library builtin function"), +                cl::ZeroOrMore); + +  static cl::opt<bool>  Quiet("q", cl::desc("Obsolete option"), cl::Hidden); @@ -328,7 +334,7 @@ public:      PassKind Kind = P->getPassKind();      StringRef Name = P->getPassName(); -    // TODO: Implement Debugify for BasicBlockPass, LoopPass. +    // TODO: Implement Debugify for LoopPass.      switch (Kind) {        case PT_Function:          super::add(createDebugifyFunctionPass()); @@ -476,12 +482,32 @@ static TargetMachine* GetTargetMachine(Triple TheTriple, StringRef CPUStr,                                          getCodeModel(), GetCodeGenOptLevel());  } -#ifdef LINK_POLLY_INTO_TOOLS -namespace polly { -void initializePollyPasses(llvm::PassRegistry &Registry); -} +#ifdef BUILD_EXAMPLES +void initializeExampleIRTransforms(llvm::PassRegistry &Registry);  #endif + +void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map) { +  std::error_code EC; +  raw_fd_ostream OS{Path, EC}; +  if (EC) { +    errs() << "Could not open file: " << EC.message() << ", " << Path << '\n'; +    return; +  } + +  OS << "Pass Name" << ',' << "# of missing debug values" << ',' +     << "# of missing locations" << ',' << "Missing/Expected value ratio" << ',' +     << "Missing/Expected location ratio" << '\n'; +  for (const auto &Entry : Map) { +    StringRef Pass = Entry.first; +    DebugifyStatistics Stats = Entry.second; + +    OS << Pass << ',' << Stats.NumDbgValuesMissing << ',' +       << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ',' +       << Stats.getEmptyLocationRatio() << '\n'; +  } +} +  //===----------------------------------------------------------------------===//  // main for opt  // @@ -535,9 +561,10 @@ int main(int argc, char **argv) {    initializeWasmEHPreparePass(Registry);    initializeWriteBitcodePassPass(Registry);    initializeHardwareLoopsPass(Registry); +  initializeTypePromotionPass(Registry); -#ifdef LINK_POLLY_INTO_TOOLS -  polly::initializePollyPasses(Registry); +#ifdef BUILD_EXAMPLES +  initializeExampleIRTransforms(Registry);  #endif    cl::ParseCommandLineOptions(argc, argv, @@ -611,7 +638,9 @@ int main(int argc, char **argv) {        OutputFilename = "-";      std::error_code EC; -    Out.reset(new ToolOutputFile(OutputFilename, EC, sys::fs::F_None)); +    sys::fs::OpenFlags Flags = OutputAssembly ? sys::fs::OF_Text +                                              : sys::fs::OF_None; +    Out.reset(new ToolOutputFile(OutputFilename, EC, Flags));      if (EC) {        errs() << EC.message() << '\n';        return 1; @@ -619,7 +648,7 @@ int main(int argc, char **argv) {      if (!ThinLinkBitcodeFile.empty()) {        ThinLinkOut.reset( -          new ToolOutputFile(ThinLinkBitcodeFile, EC, sys::fs::F_None)); +          new ToolOutputFile(ThinLinkBitcodeFile, EC, sys::fs::OF_None));        if (EC) {          errs() << EC.message() << '\n';          return 1; @@ -695,6 +724,19 @@ int main(int argc, char **argv) {    // The -disable-simplify-libcalls flag actually disables all builtin optzns.    if (DisableSimplifyLibCalls)      TLII.disableAllFunctions(); +  else { +    // Disable individual builtin functions in TargetLibraryInfo. +    LibFunc F; +    for (auto &FuncName : DisableBuiltins) +      if (TLII.getLibFunc(FuncName, F)) +        TLII.setUnavailable(F); +      else { +        errs() << argv[0] << ": cannot disable nonexistent builtin function " +               << FuncName << '\n'; +        return 1; +      } +  } +    Passes.add(new TargetLibraryInfoWrapperPass(TLII));    // Add internal analysis passes from the target machine. @@ -719,8 +761,8 @@ int main(int argc, char **argv) {          OutputFilename = "-";        std::error_code EC; -      Out = llvm::make_unique<ToolOutputFile>(OutputFilename, EC, -                                              sys::fs::F_None); +      Out = std::make_unique<ToolOutputFile>(OutputFilename, EC, +                                              sys::fs::OF_None);        if (EC) {          errs() << EC.message() << '\n';          return 1; @@ -788,9 +830,6 @@ int main(int argc, char **argv) {        if (AnalyzeOnly) {          switch (Kind) { -        case PT_BasicBlock: -          Passes.add(createBasicBlockPassPrinter(PassInf, Out->os(), Quiet)); -          break;          case PT_Region:            Passes.add(createRegionPassPrinter(PassInf, Out->os(), Quiet));            break; @@ -861,12 +900,14 @@ int main(int argc, char **argv) {    std::unique_ptr<raw_svector_ostream> BOS;    raw_ostream *OS = nullptr; +  const bool ShouldEmitOutput = !NoOutput && !AnalyzeOnly; +    // Write bitcode or assembly to the output as the last step... -  if (!NoOutput && !AnalyzeOnly) { +  if (ShouldEmitOutput || RunTwice) {      assert(Out);      OS = &Out->os();      if (RunTwice) { -      BOS = make_unique<raw_svector_ostream>(Buffer); +      BOS = std::make_unique<raw_svector_ostream>(Buffer);        OS = BOS.get();      }      if (OutputAssembly) { @@ -910,13 +951,16 @@ int main(int argc, char **argv) {               "Writing the result of the second run to the specified output.\n"               "To generate the one-run comparison binary, just run without\n"               "the compile-twice option\n"; -      Out->os() << BOS->str(); -      Out->keep(); +      if (ShouldEmitOutput) { +        Out->os() << BOS->str(); +        Out->keep(); +      }        if (RemarksFile)          RemarksFile->keep();        return 1;      } -    Out->os() << BOS->str(); +    if (ShouldEmitOutput) +      Out->os() << BOS->str();    }    if (DebugifyEach && !DebugifyExport.empty())  | 
