summaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/tools
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/tools')
-rw-r--r--contrib/llvm-project/llvm/tools/bugpoint/BugDriver.h7
-rw-r--r--contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp163
-rw-r--r--contrib/llvm-project/llvm/tools/bugpoint/ExtractFunction.cpp3
-rw-r--r--contrib/llvm-project/llvm/tools/bugpoint/OptimizerDriver.cpp12
-rw-r--r--contrib/llvm-project/llvm/tools/bugpoint/ToolRunner.cpp16
-rw-r--r--contrib/llvm-project/llvm/tools/bugpoint/bugpoint.cpp65
-rw-r--r--contrib/llvm-project/llvm/tools/llc/llc.cpp55
-rw-r--r--contrib/llvm-project/llvm/tools/lli/RemoteJITUtils.h2
-rw-r--r--contrib/llvm-project/llvm/tools/lli/lli.cpp107
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp276
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-as/llvm-as.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp5
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-cov/CodeCoverage.cpp29
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-cov/CoverageExporterJson.cpp16
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp8
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp10
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp6
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp32
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-diff/DifferenceEngine.cpp9
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-dis/llvm-dis.cpp102
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp320
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp4
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-extract/llvm-extract.cpp16
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-link/llvm-link.cpp6
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp20
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-lto2/llvm-lto2.cpp14
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.cpp22
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mc/Disassembler.h13
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp30
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.cpp6
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp42
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h8
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp3
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp33
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/InstructionInfoView.h13
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/SummaryView.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp54
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/Views/TimelineView.h1
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-mca/llvm-mca.cpp117
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-modextract/llvm-modextract.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp64
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp87
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Object.h6
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Reader.cpp22
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/COFF/Writer.cpp26
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/CommonOpts.td125
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.cpp459
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/CopyConfig.h122
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFConfig.cpp133
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFConfig.h44
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp184
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.cpp451
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h140
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/InstallNameToolOpts.td22
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp355
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.h50
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp206
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp79
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.h3
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp314
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOWriter.h19
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.cpp64
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/Object.h107
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOpts.td142
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/StripOpts.td104
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp65
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp77
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp14
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objdump/MachODump.cpp408
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp597
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.h36
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp11
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.cpp17
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-pdbutil/InputFile.h2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp5
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp4
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp10
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-profdata/llvm-profdata.cpp287
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/ARMEHABIPrinter.h19
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp17
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/COFFDumper.cpp362
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h54
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/ELFDumper.cpp2947
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/MachODumper.cpp61
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp34
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.h12
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/WasmDumper.cpp7
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp67
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp8
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp397
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp155
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.h25
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp109
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-stress/llvm-stress.cpp4
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp30
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-xray/func-id-helper.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-xray/xray-account.cpp25
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-xray/xray-converter.cpp19
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-xray/xray-extract.cpp8
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp2
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-xray/xray-graph-diff.cpp45
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-xray/xray-graph.cpp25
-rw-r--r--contrib/llvm-project/llvm/tools/llvm-xray/xray-stacks.cpp9
-rw-r--r--contrib/llvm-project/llvm/tools/opt/Debugify.cpp463
-rw-r--r--contrib/llvm-project/llvm/tools/opt/Debugify.h74
-rw-r--r--contrib/llvm-project/llvm/tools/opt/NewPMDriver.cpp16
-rw-r--r--contrib/llvm-project/llvm/tools/opt/PassPrinters.cpp38
-rw-r--r--contrib/llvm-project/llvm/tools/opt/PassPrinters.h4
-rw-r--r--contrib/llvm-project/llvm/tools/opt/opt.cpp84
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(&sectionIsAlloc)>>
+ 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())