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