summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
commit71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch)
tree5343938942df402b49ec7300a1c25a2d4ccd5821 /tools
parent31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff)
Notes
Diffstat (limited to 'tools')
-rw-r--r--tools/bugpoint/CrashDebugger.cpp8
-rw-r--r--tools/bugpoint/ExtractFunction.cpp1
-rw-r--r--tools/bugpoint/FindBugs.cpp6
-rw-r--r--tools/bugpoint/ListReducer.h5
-rw-r--r--tools/bugpoint/Miscompilation.cpp25
-rw-r--r--tools/bugpoint/ToolRunner.cpp67
-rw-r--r--tools/bugpoint/bugpoint.cpp3
-rw-r--r--tools/dsymutil/DwarfLinker.cpp115
-rw-r--r--tools/dsymutil/MachOUtils.cpp4
-rw-r--r--tools/gold/gold-plugin.cpp99
-rw-r--r--tools/llc/CMakeLists.txt1
-rw-r--r--tools/llc/LLVMBuild.txt2
-rw-r--r--tools/llc/llc.cpp49
-rw-r--r--tools/lli/OrcLazyJIT.h4
-rw-r--r--tools/lli/lli.cpp3
-rw-r--r--tools/llvm-ar/llvm-ar.cpp25
-rw-r--r--tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp5
-rw-r--r--tools/llvm-c-test/echo.cpp2
-rw-r--r--tools/llvm-cat/llvm-cat.cpp4
-rw-r--r--tools/llvm-cov/CodeCoverage.cpp42
-rw-r--r--tools/llvm-cov/CoverageReport.cpp69
-rw-r--r--tools/llvm-cov/CoverageReport.h6
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.h13
-rw-r--r--tools/llvm-cov/TestingSupport.cpp7
-rw-r--r--tools/llvm-cov/gcov.cpp2
-rw-r--r--tools/llvm-cxxfilt/llvm-cxxfilt.cpp78
-rw-r--r--tools/llvm-diff/DiffConsumer.cpp7
-rw-r--r--tools/llvm-diff/DifferenceEngine.cpp16
-rw-r--r--tools/llvm-dwp/llvm-dwp.cpp55
-rw-r--r--tools/llvm-extract/llvm-extract.cpp35
-rw-r--r--tools/llvm-link/llvm-link.cpp23
-rw-r--r--tools/llvm-lto/llvm-lto.cpp6
-rw-r--r--tools/llvm-lto2/llvm-lto2.cpp124
-rw-r--r--tools/llvm-mc-assemble-fuzzer/CMakeLists.txt19
-rw-r--r--tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp313
-rw-r--r--tools/llvm-mc-disassemble-fuzzer/CMakeLists.txt (renamed from tools/llvm-mc-fuzzer/CMakeLists.txt)9
-rw-r--r--tools/llvm-mc-disassemble-fuzzer/llvm-mc-disassemble-fuzzer.cpp (renamed from tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp)24
-rw-r--r--tools/llvm-mc/llvm-mc.cpp2
-rw-r--r--tools/llvm-nm/llvm-nm.cpp33
-rw-r--r--tools/llvm-objdump/MachODump.cpp532
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp104
-rw-r--r--tools/llvm-objdump/llvm-objdump.h17
-rw-r--r--tools/llvm-pdbdump/Analyze.cpp164
-rw-r--r--tools/llvm-pdbdump/Analyze.h30
-rw-r--r--tools/llvm-pdbdump/CMakeLists.txt6
-rw-r--r--tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp57
-rw-r--r--tools/llvm-pdbdump/CompactTypeDumpVisitor.h47
-rw-r--r--tools/llvm-pdbdump/Diff.cpp523
-rw-r--r--tools/llvm-pdbdump/Diff.h45
-rw-r--r--tools/llvm-pdbdump/LLVMOutputStyle.cpp337
-rw-r--r--tools/llvm-pdbdump/LLVMOutputStyle.h9
-rw-r--r--tools/llvm-pdbdump/LinePrinter.cpp36
-rw-r--r--tools/llvm-pdbdump/LinePrinter.h12
-rw-r--r--tools/llvm-pdbdump/PdbYaml.cpp117
-rw-r--r--tools/llvm-pdbdump/PdbYaml.h55
-rw-r--r--tools/llvm-pdbdump/PrettyBuiltinDumper.cpp4
-rw-r--r--tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp229
-rw-r--r--tools/llvm-pdbdump/PrettyClassDefinitionDumper.h38
-rw-r--r--tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp151
-rw-r--r--tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h47
-rw-r--r--tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp119
-rw-r--r--tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h44
-rw-r--r--tools/llvm-pdbdump/PrettyFunctionDumper.cpp10
-rw-r--r--tools/llvm-pdbdump/PrettyTypeDumper.cpp199
-rw-r--r--tools/llvm-pdbdump/PrettyTypeDumper.h4
-rw-r--r--tools/llvm-pdbdump/PrettyTypedefDumper.cpp7
-rw-r--r--tools/llvm-pdbdump/PrettyVariableDumper.cpp163
-rw-r--r--tools/llvm-pdbdump/PrettyVariableDumper.h9
-rw-r--r--tools/llvm-pdbdump/StreamUtil.cpp136
-rw-r--r--tools/llvm-pdbdump/StreamUtil.h25
-rw-r--r--tools/llvm-pdbdump/YAMLOutputStyle.cpp44
-rw-r--r--tools/llvm-pdbdump/YAMLOutputStyle.h1
-rw-r--r--tools/llvm-pdbdump/YamlSymbolDumper.cpp1
-rw-r--r--tools/llvm-pdbdump/YamlTypeDumper.cpp23
-rw-r--r--tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp11
-rw-r--r--tools/llvm-pdbdump/llvm-pdbdump.cpp327
-rw-r--r--tools/llvm-pdbdump/llvm-pdbdump.h21
-rw-r--r--tools/llvm-profdata/llvm-profdata.cpp122
-rw-r--r--tools/llvm-readobj/ARMAttributeParser.cpp682
-rw-r--r--tools/llvm-readobj/ARMAttributeParser.h126
-rw-r--r--tools/llvm-readobj/CMakeLists.txt3
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp95
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp60
-rw-r--r--tools/llvm-readobj/LLVMBuild.txt2
-rw-r--r--tools/llvm-readobj/MachODumper.cpp20
-rw-r--r--tools/llvm-readobj/ObjDumper.h12
-rw-r--r--tools/llvm-readobj/WasmDumper.cpp177
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp23
-rw-r--r--tools/llvm-shlib/CMakeLists.txt2
-rw-r--r--tools/llvm-stress/llvm-stress.cpp13
-rw-r--r--tools/llvm-strings/llvm-strings.cpp34
-rw-r--r--tools/llvm-symbolizer/llvm-symbolizer.cpp5
-rw-r--r--tools/llvm-xray/CMakeLists.txt2
-rw-r--r--tools/llvm-xray/llvm-xray.cc10
-rw-r--r--tools/llvm-xray/xray-account.cc96
-rw-r--r--tools/llvm-xray/xray-color-helper.cc198
-rw-r--r--tools/llvm-xray/xray-color-helper.h81
-rw-r--r--tools/llvm-xray/xray-converter.cc69
-rw-r--r--tools/llvm-xray/xray-extract.cc244
-rw-r--r--tools/llvm-xray/xray-extract.h58
-rw-r--r--tools/llvm-xray/xray-graph.cc529
-rw-r--r--tools/llvm-xray/xray-graph.h164
-rw-r--r--tools/llvm-xray/xray-sleds.h32
-rw-r--r--tools/lto/lto.cpp14
-rw-r--r--tools/msbuild/CMakeLists.txt2
-rw-r--r--tools/obj2yaml/CMakeLists.txt1
-rw-r--r--tools/obj2yaml/dwarf2yaml.cpp37
-rw-r--r--tools/obj2yaml/elf2yaml.cpp16
-rw-r--r--tools/obj2yaml/macho2yaml.cpp17
-rw-r--r--tools/obj2yaml/obj2yaml.cpp2
-rw-r--r--tools/obj2yaml/obj2yaml.h3
-rw-r--r--tools/obj2yaml/wasm2yaml.cpp219
-rw-r--r--tools/opt/GraphPrinters.cpp2
-rw-r--r--tools/opt/opt.cpp48
-rwxr-xr-xtools/sancov/coverage-report-server.py4
-rw-r--r--tools/sancov/sancov.cc40
-rw-r--r--tools/yaml2obj/CMakeLists.txt2
-rw-r--r--tools/yaml2obj/yaml2dwarf.cpp330
-rw-r--r--tools/yaml2obj/yaml2macho.cpp32
-rw-r--r--tools/yaml2obj/yaml2obj.cpp28
-rw-r--r--tools/yaml2obj/yaml2obj.h16
-rw-r--r--tools/yaml2obj/yaml2wasm.cpp377
122 files changed, 6124 insertions, 2940 deletions
diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp
index 0cae0669477f2..2fd8699c5fc8f 100644
--- a/tools/bugpoint/CrashDebugger.cpp
+++ b/tools/bugpoint/CrashDebugger.cpp
@@ -731,7 +731,8 @@ bool ReduceCrashingInstructions::TestInsts(
for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) {
Instruction *Inst = &*I++;
if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst) &&
- !Inst->isEHPad() && !Inst->getType()->isTokenTy()) {
+ !Inst->isEHPad() && !Inst->getType()->isTokenTy() &&
+ !Inst->isSwiftError()) {
if (!Inst->getType()->isVoidTy())
Inst->replaceAllUsesWith(UndefValue::get(Inst->getType()));
Inst->eraseFromParent();
@@ -1015,7 +1016,8 @@ static Error ReduceInsts(BugDriver &BD,
// TODO: Should this be some kind of interrupted error?
return Error::success();
- if (I->isEHPad() || I->getType()->isTokenTy())
+ if (I->isEHPad() || I->getType()->isTokenTy() ||
+ I->isSwiftError())
continue;
outs() << "Checking instruction: " << *I;
@@ -1111,7 +1113,7 @@ static Error DebugACrash(BugDriver &BD,
BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks");
}
- if (!DisableSimplifyCFG & !BugpointIsInterrupted) {
+ if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
std::vector<const BasicBlock *> Blocks;
for (Function &F : *BD.getProgram())
for (BasicBlock &BB : F)
diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp
index d57613ec5e376..82c61b6e1be7a 100644
--- a/tools/bugpoint/ExtractFunction.cpp
+++ b/tools/bugpoint/ExtractFunction.cpp
@@ -209,6 +209,7 @@ static void eliminateAliases(GlobalValue *GV) {
void llvm::DeleteGlobalInitializer(GlobalVariable *GV) {
eliminateAliases(GV);
GV->setInitializer(nullptr);
+ GV->setComdat(nullptr);
}
// DeleteFunctionBody - "Remove" the function by deleting all of its basic
diff --git a/tools/bugpoint/FindBugs.cpp b/tools/bugpoint/FindBugs.cpp
index 156f4d0d78fe1..3093169ba8b00 100644
--- a/tools/bugpoint/FindBugs.cpp
+++ b/tools/bugpoint/FindBugs.cpp
@@ -21,6 +21,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <ctime>
+#include <random>
using namespace llvm;
Error
@@ -39,14 +40,13 @@ BugDriver::runManyPasses(const std::vector<std::string> &AllPasses) {
return E;
}
- srand(time(nullptr));
-
+ std::mt19937 randomness(std::random_device{}());
unsigned num = 1;
while (1) {
//
// Step 1: Randomize the order of the optimizer passes.
//
- std::random_shuffle(PassesToRun.begin(), PassesToRun.end());
+ std::shuffle(PassesToRun.begin(), PassesToRun.end(), randomness);
//
// Step 2: Run optimizer passes on the program and check for success.
diff --git a/tools/bugpoint/ListReducer.h b/tools/bugpoint/ListReducer.h
index dcfa11d06927f..0f9db022d555e 100644
--- a/tools/bugpoint/ListReducer.h
+++ b/tools/bugpoint/ListReducer.h
@@ -19,6 +19,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdlib>
+#include <random>
#include <vector>
namespace llvm {
@@ -46,7 +47,7 @@ template <typename ElTy> struct ListReducer {
/// that bugpoint does.
Expected<bool> reduceList(std::vector<ElTy> &TheList) {
std::vector<ElTy> empty;
- std::srand(0x6e5ea738); // Seed the random number generator
+ std::mt19937 randomness(0x6e5ea738); // Seed the random number generator
Expected<TestResult> Result = doTest(TheList, empty);
if (Error E = Result.takeError())
return std::move(E);
@@ -92,7 +93,7 @@ template <typename ElTy> struct ListReducer {
// distribution (improving the speed of convergence).
if (ShufflingEnabled && NumOfIterationsWithoutProgress > MaxIterations) {
std::vector<ElTy> ShuffledList(TheList);
- std::random_shuffle(ShuffledList.begin(), ShuffledList.end());
+ std::shuffle(ShuffledList.begin(), ShuffledList.end(), randomness);
errs() << "\n\n*** Testing shuffled set...\n\n";
// Check that random shuffle doesn't lose the bug
Expected<TestResult> Result = doTest(ShuffledList, empty);
diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp
index 792fab07bf11e..80f4cea234815 100644
--- a/tools/bugpoint/Miscompilation.cpp
+++ b/tools/bugpoint/Miscompilation.cpp
@@ -225,19 +225,22 @@ public:
/// output is different. If the DeleteInputs argument is set to true then this
/// function deletes both input modules before it returns.
///
-static Expected<std::unique_ptr<Module>>
-testMergedProgram(const BugDriver &BD, std::unique_ptr<Module> M1,
- std::unique_ptr<Module> M2, bool &Broken) {
- if (Linker::linkModules(*M1, std::move(M2)))
+static Expected<std::unique_ptr<Module>> testMergedProgram(const BugDriver &BD,
+ const Module &M1,
+ const Module &M2,
+ bool &Broken) {
+ // Resulting merge of M1 and M2.
+ auto Merged = CloneModule(&M1);
+ if (Linker::linkModules(*Merged, CloneModule(&M2)))
// TODO: Shouldn't we thread the error up instead of exiting?
exit(1);
// Execute the program.
- Expected<bool> Diff = BD.diffProgram(M1.get(), "", "", false);
+ Expected<bool> Diff = BD.diffProgram(Merged.get(), "", "", false);
if (Error E = Diff.takeError())
return std::move(E);
Broken = *Diff;
- return std::move(M1);
+ return std::move(Merged);
}
/// TestFuncs - split functions in a Module into two groups: those that are
@@ -335,9 +338,8 @@ ExtractLoops(BugDriver &BD,
// extraction.
AbstractInterpreter *AI = BD.switchToSafeInterpreter();
bool Failure;
- Expected<std::unique_ptr<Module>> New =
- testMergedProgram(BD, std::move(ToOptimizeLoopExtracted),
- std::move(ToNotOptimize), Failure);
+ Expected<std::unique_ptr<Module>> New = testMergedProgram(
+ BD, *ToOptimizeLoopExtracted, *ToNotOptimize, Failure);
if (Error E = New.takeError())
return std::move(E);
if (!*New)
@@ -726,8 +728,7 @@ static Expected<bool> TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test,
outs() << " Checking to see if the merged program executes correctly: ";
bool Broken;
- auto Result =
- testMergedProgram(BD, std::move(Optimized), std::move(Safe), Broken);
+ auto Result = testMergedProgram(BD, *Optimized, *Safe, Broken);
if (Error E = Result.takeError())
return std::move(E);
if (auto New = std::move(*Result)) {
@@ -840,7 +841,7 @@ static void CleanupAndPrepareModules(BugDriver &BD,
// Prototype: void *getPointerToNamedFunction(const char* Name)
Constant *resolverFunc = Safe->getOrInsertFunction(
"getPointerToNamedFunction", Type::getInt8PtrTy(Safe->getContext()),
- Type::getInt8PtrTy(Safe->getContext()), (Type *)nullptr);
+ Type::getInt8PtrTy(Safe->getContext()));
// Use the function we just added to get addresses of functions we need.
for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) {
diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp
index 4633d64373368..10532ef8395b8 100644
--- a/tools/bugpoint/ToolRunner.cpp
+++ b/tools/bugpoint/ToolRunner.cpp
@@ -355,37 +355,62 @@ Expected<int> CustomExecutor::ExecuteProgram(
// Tokenize the CommandLine to the command and the args to allow
// defining a full command line as the command instead of just the
// executed program. We cannot just pass the whole string after the command
-// as a single argument because then program sees only a single
+// as a single argument because then the program sees only a single
// command line argument (with spaces in it: "foo bar" instead
// of "foo" and "bar").
//
-// code borrowed from:
-// http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
+// Spaces are used as a delimiter; however repeated, leading, and trailing
+// whitespace are ignored. Simple escaping is allowed via the '\'
+// character, as seen below:
+//
+// Two consecutive '\' evaluate to a single '\'.
+// A space after a '\' evaluates to a space that is not interpreted as a
+// delimiter.
+// Any other instances of the '\' character are removed.
+//
+// Example:
+// '\\' -> '\'
+// '\ ' -> ' '
+// 'exa\mple' -> 'example'
+//
static void lexCommand(std::string &Message, const std::string &CommandLine,
std::string &CmdPath, std::vector<std::string> &Args) {
- std::string Command = "";
- std::string delimiters = " ";
-
- std::string::size_type lastPos = CommandLine.find_first_not_of(delimiters, 0);
- std::string::size_type pos = CommandLine.find_first_of(delimiters, lastPos);
-
- while (std::string::npos != pos || std::string::npos != lastPos) {
- std::string token = CommandLine.substr(lastPos, pos - lastPos);
- if (Command == "")
- Command = token;
- else
- Args.push_back(token);
- // Skip delimiters. Note the "not_of"
- lastPos = CommandLine.find_first_not_of(delimiters, pos);
- // Find next "non-delimiter"
- pos = CommandLine.find_first_of(delimiters, lastPos);
+ std::string Token;
+ std::string Command;
+ bool FoundPath = false;
+
+ // first argument is the PATH.
+ // Skip repeated whitespace, leading whitespace and trailing whitespace.
+ for (std::size_t Pos = 0u; Pos <= CommandLine.size(); ++Pos) {
+ if ('\\' == CommandLine[Pos]) {
+ if (Pos + 1 < CommandLine.size())
+ Token.push_back(CommandLine[++Pos]);
+
+ continue;
+ }
+ if (' ' == CommandLine[Pos] || CommandLine.size() == Pos) {
+ if (Token.empty())
+ continue;
+
+ if (!FoundPath) {
+ Command = Token;
+ FoundPath = true;
+ Token.clear();
+ continue;
+ }
+
+ Args.push_back(Token);
+ Token.clear();
+ continue;
+ }
+ Token.push_back(CommandLine[Pos]);
}
auto Path = sys::findProgramByName(Command);
if (!Path) {
- Message = std::string("Cannot find '") + Command + "' in PATH: " +
- Path.getError().message() + "\n";
+ Message = std::string("Cannot find '") + Command +
+ "' in PATH: " + Path.getError().message() + "\n";
return;
}
CmdPath = *Path;
diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp
index a5de953b2b75b..85c1ddd8277d9 100644
--- a/tools/bugpoint/bugpoint.cpp
+++ b/tools/bugpoint/bugpoint.cpp
@@ -181,7 +181,8 @@ int main(int argc, char **argv) {
if (OptLevelO1)
Builder.Inliner = createAlwaysInlinerLegacyPass();
else if (OptLevelOs || OptLevelO2)
- Builder.Inliner = createFunctionInliningPass(2, OptLevelOs ? 1 : 0);
+ Builder.Inliner = createFunctionInliningPass(
+ 2, OptLevelOs ? 1 : 0, false);
else
Builder.Inliner = createFunctionInliningPass(275);
Builder.populateFunctionPassManager(PM);
diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp
index f1ec8a6226712..25f1a0f271223 100644
--- a/tools/dsymutil/DwarfLinker.cpp
+++ b/tools/dsymutil/DwarfLinker.cpp
@@ -197,30 +197,34 @@ public:
CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR,
StringRef ClangModuleName)
- : OrigUnit(OrigUnit), ID(ID), NewUnit(OrigUnit.getVersion(),
- OrigUnit.getAddressByteSize(),
- OrigUnit.getUnitDIE().getTag()),
- LowPc(UINT64_MAX), HighPc(0), RangeAlloc(), Ranges(RangeAlloc),
- ClangModuleName(ClangModuleName) {
+ : OrigUnit(OrigUnit), ID(ID), LowPc(UINT64_MAX), HighPc(0), RangeAlloc(),
+ Ranges(RangeAlloc), ClangModuleName(ClangModuleName) {
Info.resize(OrigUnit.getNumDIEs());
auto CUDie = OrigUnit.getUnitDIE(false);
- unsigned Lang =
- CUDie.getAttributeValueAsUnsignedConstant(dwarf::DW_AT_language)
- .getValueOr(0);
- HasODR = CanUseODR && (Lang == dwarf::DW_LANG_C_plus_plus ||
- Lang == dwarf::DW_LANG_C_plus_plus_03 ||
- Lang == dwarf::DW_LANG_C_plus_plus_11 ||
- Lang == dwarf::DW_LANG_C_plus_plus_14 ||
- Lang == dwarf::DW_LANG_ObjC_plus_plus);
+ if (auto Lang = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language)))
+ HasODR = CanUseODR && (*Lang == dwarf::DW_LANG_C_plus_plus ||
+ *Lang == dwarf::DW_LANG_C_plus_plus_03 ||
+ *Lang == dwarf::DW_LANG_C_plus_plus_11 ||
+ *Lang == dwarf::DW_LANG_C_plus_plus_14 ||
+ *Lang == dwarf::DW_LANG_ObjC_plus_plus);
+ else
+ HasODR = false;
}
DWARFUnit &getOrigUnit() const { return OrigUnit; }
unsigned getUniqueID() const { return ID; }
+ void createOutputDIE() {
+ NewUnit.emplace(OrigUnit.getVersion(), OrigUnit.getAddressByteSize(),
+ OrigUnit.getUnitDIE().getTag());
+ }
+
DIE *getOutputUnitDIE() const {
- return &const_cast<DIEUnit &>(NewUnit).getUnitDie();
+ if (NewUnit)
+ return &const_cast<DIEUnit &>(*NewUnit).getUnitDie();
+ return nullptr;
}
bool hasODR() const { return HasODR; }
@@ -329,7 +333,7 @@ private:
DWARFUnit &OrigUnit;
unsigned ID;
std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
- DIEUnit NewUnit;
+ Optional<DIEUnit> NewUnit;
uint64_t StartOffset;
uint64_t NextUnitOffset;
@@ -359,7 +363,7 @@ private:
Optional<PatchLocation> UnitRangeAttribute;
/// @}
- /// \brief Location attributes that need to be transfered from th
+ /// \brief Location attributes that need to be transferred from the
/// original debug_loc section to the liked one. They are stored
/// along with the PC offset that is to be applied to their
/// function's address.
@@ -397,7 +401,8 @@ uint64_t CompileUnit::computeNextUnitOffset() {
// The root DIE might be null, meaning that the Unit had nothing to
// contribute to the linked output. In that case, we will emit the
// unit header without any actual DIE.
- NextUnitOffset += NewUnit.getUnitDie().getSize();
+ if (NewUnit)
+ NextUnitOffset += NewUnit->getUnitDie().getSize();
return NextUnitOffset;
}
@@ -843,8 +848,7 @@ void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
DWARFUnit &OrigUnit = Unit.getOrigUnit();
auto OrigUnitDie = OrigUnit.getUnitDIE(false);
int64_t UnitPcOffset = 0;
- auto OrigLowPc = OrigUnitDie.getAttributeValueAsAddress(dwarf::DW_AT_low_pc);
- if (OrigLowPc)
+ if (auto OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc)))
UnitPcOffset = int64_t(*OrigLowPc) - Unit.getLowPc();
for (const auto &Attr : Attributes) {
@@ -1080,7 +1084,7 @@ void DwarfStreamer::emitCIE(StringRef CIEBytes) {
/// \brief Emit a FDE into the debug_frame section. \p FDEBytes
/// contains the FDE data without the length, CIE offset and address
-/// which will be replaced with the paramter values.
+/// which will be replaced with the parameter values.
void DwarfStreamer::emitFDE(uint32_t CIEOffset, uint32_t AddrSize,
uint32_t Address, StringRef FDEBytes) {
MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
@@ -1558,8 +1562,7 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
// Do not unique anything inside CU local functions.
if ((Context.getTag() == dwarf::DW_TAG_namespace ||
Context.getTag() == dwarf::DW_TAG_compile_unit) &&
- !DIE.getAttributeValueAsUnsignedConstant(dwarf::DW_AT_external)
- .getValueOr(0))
+ !dwarf::toUnsigned(DIE.find(dwarf::DW_AT_external), 0))
return PointerIntPair<DeclContext *, 1>(nullptr);
LLVM_FALLTHROUGH;
case dwarf::DW_TAG_member:
@@ -1573,8 +1576,7 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
// created on demand. For example implicitely defined constructors
// are ambiguous because of the way we identify contexts, and they
// won't be generated everytime everywhere.
- if (DIE.getAttributeValueAsUnsignedConstant(dwarf::DW_AT_artificial)
- .getValueOr(0))
+ if (dwarf::toUnsigned(DIE.find(dwarf::DW_AT_artificial), 0))
return PointerIntPair<DeclContext *, 1>(nullptr);
break;
}
@@ -1614,12 +1616,9 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
// namespaces, use these additional data points to make the process
// safer. This is disabled for clang modules, because forward
// declarations of module-defined types do not have a file and line.
- ByteSize = DIE.getAttributeValueAsUnsignedConstant(dwarf::DW_AT_byte_size)
- .getValueOr(UINT64_MAX);
+ ByteSize = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_byte_size), UINT64_MAX);
if (Tag != dwarf::DW_TAG_namespace || !Name) {
- if (unsigned FileNum =
- DIE.getAttributeValueAsUnsignedConstant(dwarf::DW_AT_decl_file)
- .getValueOr(0)) {
+ if (unsigned FileNum = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_file), 0)) {
if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
&U.getOrigUnit())) {
// FIXME: dsymutil-classic compatibility. I'd rather not
@@ -1632,9 +1631,7 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
// instead of "" would allow more uniquing, but for now, do
// it this way to match dsymutil-classic.
if (LT->hasFileAtIndex(FileNum)) {
- Line =
- DIE.getAttributeValueAsUnsignedConstant(dwarf::DW_AT_decl_line)
- .getValueOr(0);
+ Line = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_line), 0);
// Cache the resolved paths, because calling realpath is expansive.
StringRef ResolvedPath = U.getResolvedPath(FileNum);
if (!ResolvedPath.empty()) {
@@ -1782,8 +1779,7 @@ static bool analyzeContextInfo(const DWARFDie &DIE,
//
// We treat non-C++ modules like namespaces for this reason.
if (DIE.getTag() == dwarf::DW_TAG_module && ParentIdx == 0 &&
- DIE.getAttributeValueAsString(dwarf::DW_AT_name,
- "") != CU.getClangModuleName()) {
+ dwarf::toString(DIE.find(dwarf::DW_AT_name), "") != CU.getClangModuleName()) {
InImportedModule = true;
}
@@ -1811,8 +1807,7 @@ static bool analyzeContextInfo(const DWARFDie &DIE,
// forward declarations.
Info.Prune &=
(DIE.getTag() == dwarf::DW_TAG_module) ||
- DIE.getAttributeValueAsUnsignedConstant(dwarf::DW_AT_declaration)
- .getValueOr(0);
+ dwarf::toUnsigned(DIE.find(dwarf::DW_AT_declaration), 0);
// Don't prune it if there is no definition for the DIE.
Info.Prune &= Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset();
@@ -2129,7 +2124,7 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE(
std::tie(LowPcOffset, LowPcEndOffset) =
getAttributeOffsets(Abbrev, *LowPcIdx, Offset, OrigUnit);
- auto LowPc = DIE.getAttributeValueAsAddress(dwarf::DW_AT_low_pc);
+ auto LowPc = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc));
assert(LowPc.hasValue() && "low_pc attribute is not an address.");
if (!LowPc ||
!RelocMgr.hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo))
@@ -2746,14 +2741,11 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
// file might be start address of another function which got moved
// independantly by the linker). The computation of the actual
// high_pc value is done in cloneAddressAttribute().
- AttrInfo.OrigHighPc =
- InputDIE.getAttributeValueAsAddress(dwarf::DW_AT_high_pc).getValueOr(0);
+ AttrInfo.OrigHighPc = dwarf::toAddress(InputDIE.find(dwarf::DW_AT_high_pc), 0);
// Also store the low_pc. It might get relocated in an
// inline_subprogram that happens at the beginning of its
// inlining function.
- AttrInfo.OrigLowPc =
- InputDIE.getAttributeValueAsAddress(dwarf::DW_AT_low_pc)
- .getValueOr(UINT64_MAX);
+ AttrInfo.OrigLowPc = dwarf::toAddress(InputDIE.find(dwarf::DW_AT_low_pc), UINT64_MAX);
}
// Reset the Offset to 0 as we will be working on the local copy of
@@ -2872,9 +2864,7 @@ void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit,
auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
DWARFUnit &OrigUnit = Unit.getOrigUnit();
auto OrigUnitDie = OrigUnit.getUnitDIE(false);
- uint64_t OrigLowPc =
- OrigUnitDie.getAttributeValueAsAddress(dwarf::DW_AT_low_pc)
- .getValueOr(-1ULL);
+ uint64_t OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc), -1ULL);
// Ranges addresses are based on the unit's low_pc. Compute the
// offset we need to apply to adapt to the new unit's low_pc.
int64_t UnitPcOffset = 0;
@@ -2969,7 +2959,7 @@ static void patchStmtList(DIE &Die, DIEInteger Offset) {
void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
DWARFContext &OrigDwarf) {
DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
- auto StmtList = CUDie.getAttributeValueAsSectionOffset(dwarf::DW_AT_stmt_list);
+ auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list));
if (!StmtList)
return;
@@ -3081,7 +3071,7 @@ void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
if (LineTable.Prologue.Version != 2 ||
LineTable.Prologue.DefaultIsStmt != DWARF2_LINE_DEFAULT_IS_STMT ||
LineTable.Prologue.OpcodeBase > 13)
- reportWarning("line table paramters mismatch. Cannot emit.");
+ reportWarning("line table parameters mismatch. Cannot emit.");
else {
MCDwarfLineTableParams Params;
Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
@@ -3201,10 +3191,8 @@ void DwarfLinker::DIECloner::copyAbbrev(
static uint64_t getDwoId(const DWARFDie &CUDie,
const DWARFUnit &Unit) {
- auto DwoId = CUDie.getAttributeValueAsUnsignedConstant(dwarf::DW_AT_dwo_id);
- if (DwoId)
- return *DwoId;
- DwoId = CUDie.getAttributeValueAsUnsignedConstant(dwarf::DW_AT_GNU_dwo_id);
+ auto DwoId = dwarf::toUnsigned(CUDie.find({dwarf::DW_AT_dwo_id,
+ dwarf::DW_AT_GNU_dwo_id}));
if (DwoId)
return *DwoId;
return 0;
@@ -3214,20 +3202,16 @@ bool DwarfLinker::registerModuleReference(
const DWARFDie &CUDie, const DWARFUnit &Unit,
DebugMap &ModuleMap, unsigned Indent) {
std::string PCMfile =
- CUDie.getAttributeValueAsString(dwarf::DW_AT_dwo_name, "");
- if (PCMfile.empty())
- PCMfile =
- CUDie.getAttributeValueAsString(dwarf::DW_AT_GNU_dwo_name, "");
+ dwarf::toString(CUDie.find({dwarf::DW_AT_dwo_name,
+ dwarf::DW_AT_GNU_dwo_name}), "");
if (PCMfile.empty())
return false;
// Clang module DWARF skeleton CUs abuse this for the path to the module.
- std::string PCMpath =
- CUDie.getAttributeValueAsString(dwarf::DW_AT_comp_dir, "");
+ std::string PCMpath = dwarf::toString(CUDie.find(dwarf::DW_AT_comp_dir), "");
uint64_t DwoId = getDwoId(CUDie, Unit);
- std::string Name =
- CUDie.getAttributeValueAsString(dwarf::DW_AT_name, "");
+ std::string Name = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");
if (Name.empty()) {
reportWarning("Anonymous module skeleton CU for " + PCMfile);
return true;
@@ -3378,12 +3362,13 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(
for (auto &CurrentUnit : CompileUnits) {
auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();
CurrentUnit->setStartOffset(Linker.OutputDebugInfoSize);
- // Clonse the InputDIE into your Unit DIE in our compile unit since it
- // already has a DIE inside of it.
- if (!cloneDIE(InputDIE, *CurrentUnit, 0 /* PC offset */,
- 11 /* Unit Header size */, 0,
- CurrentUnit->getOutputUnitDIE()))
- continue;
+ if (CurrentUnit->getInfo(0).Keep) {
+ // Clone the InputDIE into your Unit DIE in our compile unit since it
+ // already has a DIE inside of it.
+ CurrentUnit->createOutputDIE();
+ cloneDIE(InputDIE, *CurrentUnit, 0 /* PC offset */,
+ 11 /* Unit Header size */, 0, CurrentUnit->getOutputUnitDIE());
+ }
Linker.OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset();
if (Linker.Options.NoOutput)
continue;
diff --git a/tools/dsymutil/MachOUtils.cpp b/tools/dsymutil/MachOUtils.cpp
index 8a730a1d0c8a2..ea6f113e4fae6 100644
--- a/tools/dsymutil/MachOUtils.cpp
+++ b/tools/dsymutil/MachOUtils.cpp
@@ -220,7 +220,7 @@ getSection(const object::MachOObjectFile &Obj,
// The function also tries to find a hole in the address map to fit the __DWARF
// segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the
// highest segment address.
-// When the __LINKEDIT segment is transfered, its offset and size are set resp.
+// When the __LINKEDIT segment is transferred, its offset and size are set resp.
// to \a LinkeditOffset and \a LinkeditSize.
template <typename SegmentTy>
static void transferSegmentAndSections(
@@ -236,6 +236,8 @@ static void transferSegmentAndSections(
if (StringRef("__LINKEDIT") == Segment.segname) {
Segment.fileoff = LinkeditOffset;
Segment.filesize = LinkeditSize;
+ // Resize vmsize by rounding to the page size.
+ Segment.vmsize = alignTo(LinkeditSize, 0x1000);
}
// Check if the end address of the last segment and our current
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index 50e102b045953..9b783d19a2834 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/Statistic.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/CodeGen/CommandFlags.h"
@@ -20,7 +21,9 @@
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/Caching.h"
#include "llvm/LTO/LTO.h"
+#include "llvm/Object/Error.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -105,8 +108,6 @@ static std::list<claimed_file> Modules;
static DenseMap<int, void *> FDToLeaderHandle;
static StringMap<ResolutionInfo> ResInfo;
static std::vector<std::string> Cleanup;
-static llvm::TargetOptions TargetOpts;
-static size_t MaxTasks;
namespace options {
enum OutputType {
@@ -165,6 +166,12 @@ namespace options {
// corresponding bitcode file, will use a path formed by replacing the
// bitcode file's path prefix matching oldprefix with newprefix.
static std::string thinlto_prefix_replace;
+ // Option to control the name of modules encoded in the individual index
+ // files for a distributed backend. This enables the use of minimized
+ // bitcode files for the thin link, assuming the name of the full bitcode
+ // file used in the backend differs just in some part of the file suffix.
+ // If specified, expects a string of the form "oldsuffix:newsuffix".
+ static std::string thinlto_object_suffix_replace;
// Optional path to a directory for caching ThinLTO objects.
static std::string cache_dir;
// Additional options to pass into the code generator.
@@ -207,6 +214,12 @@ namespace options {
thinlto_prefix_replace = opt.substr(strlen("thinlto-prefix-replace="));
if (thinlto_prefix_replace.find(';') == std::string::npos)
message(LDPL_FATAL, "thinlto-prefix-replace expects 'old;new' format");
+ } else if (opt.startswith("thinlto-object-suffix-replace=")) {
+ thinlto_object_suffix_replace =
+ opt.substr(strlen("thinlto-object-suffix-replace="));
+ if (thinlto_object_suffix_replace.find(';') == std::string::npos)
+ message(LDPL_FATAL,
+ "thinlto-object-suffix-replace expects 'old;new' format");
} else if (opt.startswith("cache-dir=")) {
cache_dir = opt.substr(strlen("cache-dir="));
} else if (opt.size() == 2 && opt[0] == 'O') {
@@ -452,7 +465,7 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
EC == object::object_error::bitcode_section_not_found)
*claimed = 0;
else
- message(LDPL_ERROR,
+ message(LDPL_FATAL,
"LLVM gold plugin has failed to create LTO module: %s",
EI.message().c_str());
});
@@ -485,8 +498,6 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
sys::path::filename(Obj->getSourceFileName()).str();
for (auto &Sym : Obj->symbols()) {
- uint32_t Symflags = Sym.getFlags();
-
cf.syms.push_back(ld_plugin_symbol());
ld_plugin_symbol &sym = cf.syms.back();
sym.version = nullptr;
@@ -512,20 +523,20 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
break;
}
- if (Symflags & object::BasicSymbolRef::SF_Undefined) {
+ if (Sym.isUndefined()) {
sym.def = LDPK_UNDEF;
- if (Symflags & object::BasicSymbolRef::SF_Weak)
+ if (Sym.isWeak())
sym.def = LDPK_WEAKUNDEF;
- } else if (Symflags & object::BasicSymbolRef::SF_Common)
+ } else if (Sym.isCommon())
sym.def = LDPK_COMMON;
- else if (Symflags & object::BasicSymbolRef::SF_Weak)
+ else if (Sym.isWeak())
sym.def = LDPK_WEAKDEF;
else
sym.def = LDPK_DEF;
sym.size = 0;
sym.comdat_key = nullptr;
- int CI = check(Sym.getComdatIndex());
+ int CI = Sym.getComdatIndex();
if (CI != -1) {
StringRef C = Obj->getComdatTable()[CI];
sym.comdat_key = strdup(C.str().c_str());
@@ -567,8 +578,35 @@ static const void *getSymbolsAndView(claimed_file &F) {
return View;
}
-static void addModule(LTO &Lto, claimed_file &F, const void *View) {
- MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize), F.name);
+/// Parse the thinlto-object-suffix-replace option into the \p OldSuffix and
+/// \p NewSuffix strings, if it was specified.
+static void getThinLTOOldAndNewSuffix(std::string &OldSuffix,
+ std::string &NewSuffix) {
+ assert(options::thinlto_object_suffix_replace.empty() ||
+ options::thinlto_object_suffix_replace.find(";") != StringRef::npos);
+ StringRef SuffixReplace = options::thinlto_object_suffix_replace;
+ std::pair<StringRef, StringRef> Split = SuffixReplace.split(";");
+ OldSuffix = Split.first.str();
+ NewSuffix = Split.second.str();
+}
+
+/// Given the original \p Path to an output file, replace any filename
+/// suffix matching \p OldSuffix with \p NewSuffix.
+static std::string getThinLTOObjectFileName(const std::string Path,
+ const std::string &OldSuffix,
+ const std::string &NewSuffix) {
+ if (OldSuffix.empty() && NewSuffix.empty())
+ return Path;
+ StringRef NewPath = Path;
+ NewPath.consume_back(OldSuffix);
+ std::string NewNewPath = NewPath.str() + NewSuffix;
+ return NewPath.str() + NewSuffix;
+}
+
+static void addModule(LTO &Lto, claimed_file &F, const void *View,
+ StringRef Filename) {
+ MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize),
+ Filename);
Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(BufferRef);
if (!ObjOrErr)
@@ -637,7 +675,7 @@ static void recordFile(std::string Filename, bool TempOutFile) {
/// indicating whether a temp file should be generated, and an optional task id.
/// The new filename generated is returned in \p NewFilename.
static void getOutputFileName(SmallString<128> InFilename, bool TempOutFile,
- SmallString<128> &NewFilename, int TaskID = -1) {
+ SmallString<128> &NewFilename, int TaskID) {
if (TempOutFile) {
std::error_code EC =
sys::fs::createTemporaryFile("lto-llvm", "o", NewFilename);
@@ -646,7 +684,7 @@ static void getOutputFileName(SmallString<128> InFilename, bool TempOutFile,
EC.message().c_str());
} else {
NewFilename = InFilename;
- if (TaskID >= 0)
+ if (TaskID > 0)
NewFilename += utostr(TaskID);
}
}
@@ -790,19 +828,31 @@ static ld_plugin_status allSymbolsReadHook() {
if (options::thinlto_index_only)
getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
+ std::string OldSuffix, NewSuffix;
+ getThinLTOOldAndNewSuffix(OldSuffix, NewSuffix);
+ // Set for owning string objects used as buffer identifiers.
+ StringSet<> ObjectFilenames;
+
for (claimed_file &F : Modules) {
if (options::thinlto && !HandleToInputFile.count(F.leader_handle))
HandleToInputFile.insert(std::make_pair(
F.leader_handle, llvm::make_unique<PluginInputFile>(F.handle)));
const void *View = getSymbolsAndView(F);
+ // In case we are thin linking with a minimized bitcode file, ensure
+ // the module paths encoded in the index reflect where the backends
+ // will locate the full bitcode files for compiling/importing.
+ std::string Identifier =
+ getThinLTOObjectFileName(F.name, OldSuffix, NewSuffix);
+ auto ObjFilename = ObjectFilenames.insert(Identifier);
+ assert(ObjFilename.second);
if (!View) {
if (options::thinlto_index_only)
// Write empty output files that may be expected by the distributed
// build system.
- writeEmptyDistributedBuildOutputs(F.name, OldPrefix, NewPrefix);
+ writeEmptyDistributedBuildOutputs(Identifier, OldPrefix, NewPrefix);
continue;
}
- addModule(*Lto, F, View);
+ addModule(*Lto, F, View, ObjFilename.first->first());
}
SmallString<128> Filename;
@@ -813,7 +863,7 @@ static ld_plugin_status allSymbolsReadHook() {
Filename = output_name + ".o";
bool SaveTemps = !Filename.empty();
- MaxTasks = Lto->getMaxTasks();
+ size_t MaxTasks = Lto->getMaxTasks();
std::vector<uintptr_t> IsTemporary(MaxTasks);
std::vector<SmallString<128>> Filenames(MaxTasks);
@@ -821,21 +871,26 @@ static ld_plugin_status allSymbolsReadHook() {
[&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> {
IsTemporary[Task] = !SaveTemps;
getOutputFileName(Filename, /*TempOutFile=*/!SaveTemps, Filenames[Task],
- MaxTasks > 1 ? Task : -1);
+ Task);
int FD;
std::error_code EC =
sys::fs::openFileForWrite(Filenames[Task], FD, sys::fs::F_None);
if (EC)
- message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
+ message(LDPL_FATAL, "Could not open file %s: %s", Filenames[Task].c_str(),
+ EC.message().c_str());
return llvm::make_unique<lto::NativeObjectStream>(
llvm::make_unique<llvm::raw_fd_ostream>(FD, true));
};
- auto AddFile = [&](size_t Task, StringRef Path) { Filenames[Task] = Path; };
+ auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ // Note that this requires that the memory buffers provided to AddBuffer are
+ // backed by a file.
+ Filenames[Task] = MB->getBufferIdentifier();
+ };
NativeObjectCache Cache;
if (!options::cache_dir.empty())
- Cache = localCache(options::cache_dir, AddFile);
+ Cache = check(localCache(options::cache_dir, AddBuffer));
check(Lto->run(AddStream, Cache));
@@ -844,6 +899,8 @@ static ld_plugin_status allSymbolsReadHook() {
return LDPS_OK;
if (options::thinlto_index_only) {
+ if (llvm::AreStatisticsEnabled())
+ llvm::PrintStatistics();
cleanup_hook();
exit(0);
}
diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt
index 5a98122a233e7..4f8181a1b6577 100644
--- a/tools/llc/CMakeLists.txt
+++ b/tools/llc/CMakeLists.txt
@@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS
Support
Target
TransformUtils
+ Vectorize
)
# Support plugins.
diff --git a/tools/llc/LLVMBuild.txt b/tools/llc/LLVMBuild.txt
index c1f5cebea859d..014dcac176106 100644
--- a/tools/llc/LLVMBuild.txt
+++ b/tools/llc/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llc
parent = Tools
-required_libraries = AsmParser BitReader IRReader MIRParser TransformUtils all-targets
+required_libraries = AsmParser BitReader IRReader MIRParser TransformUtils Scalar Vectorize all-targets
diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp
index a76d3249674ff..43f97f112f6bc 100644
--- a/tools/llc/llc.cpp
+++ b/tools/llc/llc.cpp
@@ -136,6 +136,16 @@ static cl::opt<std::string> StartAfter("start-after",
static cl::list<std::string> IncludeDirs("I", cl::desc("include search path"));
+static cl::opt<bool> PassRemarksWithHotness(
+ "pass-remarks-with-hotness",
+ cl::desc("With PGO, include profile count in optimization remarks"),
+ cl::Hidden);
+
+static cl::opt<std::string>
+ RemarksFilename("pass-remarks-output",
+ cl::desc("YAML output filename for pass remarks"),
+ cl::value_desc("filename"));
+
namespace {
static ManagedStatic<std::vector<std::string>> RunPassNames;
@@ -233,12 +243,29 @@ static void DiagnosticHandler(const DiagnosticInfo &DI, void *Context) {
if (DI.getSeverity() == DS_Error)
*HasError = true;
+ if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI))
+ if (!Remark->isEnabled())
+ return;
+
DiagnosticPrinterRawOStream DP(errs());
errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
DI.print(DP);
errs() << "\n";
}
+static void InlineAsmDiagHandler(const SMDiagnostic &SMD, void *Context,
+ unsigned LocCookie) {
+ bool *HasError = static_cast<bool *>(Context);
+ if (SMD.getKind() == SourceMgr::DK_Error)
+ *HasError = true;
+
+ SMD.print(nullptr, errs());
+
+ // For testing purposes, we print the LocCookie here.
+ if (LocCookie)
+ errs() << "note: !srcloc = " << LocCookie << "\n";
+}
+
// main - Entry point for the llc compiler.
//
int main(int argc, char **argv) {
@@ -267,6 +294,8 @@ int main(int argc, char **argv) {
initializeCountingFunctionInserterPass(*Registry);
initializeUnreachableBlockElimLegacyPassPass(*Registry);
initializeConstantHoistingLegacyPassPass(*Registry);
+ initializeScalarOpts(*Registry);
+ initializeVectorization(*Registry);
// Register the target printer for --version.
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
@@ -278,12 +307,32 @@ int main(int argc, char **argv) {
// Set a diagnostic handler that doesn't exit on the first error
bool HasError = false;
Context.setDiagnosticHandler(DiagnosticHandler, &HasError);
+ Context.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, &HasError);
+
+ if (PassRemarksWithHotness)
+ Context.setDiagnosticHotnessRequested(true);
+
+ std::unique_ptr<tool_output_file> YamlFile;
+ if (RemarksFilename != "") {
+ std::error_code EC;
+ YamlFile = llvm::make_unique<tool_output_file>(RemarksFilename, EC,
+ sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
+ return 1;
+ }
+ Context.setDiagnosticsOutputFile(
+ llvm::make_unique<yaml::Output>(YamlFile->os()));
+ }
// Compile the module TimeCompilations times to give better compile time
// metrics.
for (unsigned I = TimeCompilations; I; --I)
if (int RetVal = compileModule(argv, Context))
return RetVal;
+
+ if (YamlFile)
+ YamlFile->keep();
return 0;
}
diff --git a/tools/lli/OrcLazyJIT.h b/tools/lli/OrcLazyJIT.h
index 05319c345484f..56e7d36d05fb4 100644
--- a/tools/lli/OrcLazyJIT.h
+++ b/tools/lli/OrcLazyJIT.h
@@ -21,7 +21,7 @@
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
-#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
namespace llvm {
@@ -30,7 +30,7 @@ class OrcLazyJIT {
public:
typedef orc::JITCompileCallbackManager CompileCallbackMgr;
- typedef orc::ObjectLinkingLayer<> ObjLayerT;
+ typedef orc::RTDyldObjectLinkingLayer<> ObjLayerT;
typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT;
typedef std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>
TransformFtor;
diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp
index 0823ff469de6d..f228a36194573 100644
--- a/tools/lli/lli.cpp
+++ b/tools/lli/lli.cpp
@@ -606,8 +606,7 @@ int main(int argc, char **argv, char * const *envp) {
// If the program doesn't explicitly call exit, we will need the Exit
// function later on to make an explicit call, so get the function now.
Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context),
- Type::getInt32Ty(Context),
- nullptr);
+ Type::getInt32Ty(Context));
// Run static constructors.
if (!ForceInterpreter) {
diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp
index b99a396da62ac..1519464521dd0 100644
--- a/tools/llvm-ar/llvm-ar.cpp
+++ b/tools/llvm-ar/llvm-ar.cpp
@@ -52,7 +52,7 @@ static StringRef ToolName;
// Show the error message and exit.
LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) {
- outs() << ToolName << ": " << Error << ".\n";
+ errs() << ToolName << ": " << Error << ".\n";
exit(1);
}
@@ -87,13 +87,14 @@ static cl::opt<bool> MRI("M", cl::desc(""));
static cl::opt<std::string> Plugin("plugin", cl::desc("plugin (ignored for compatibility"));
namespace {
-enum Format { Default, GNU, BSD };
+enum Format { Default, GNU, BSD, DARWIN };
}
static cl::opt<Format>
FormatOpt("format", cl::desc("Archive format to create"),
cl::values(clEnumValN(Default, "default", "default"),
clEnumValN(GNU, "gnu", "gnu"),
+ clEnumValN(DARWIN, "darwin", "darwin"),
clEnumValN(BSD, "bsd", "bsd")));
static std::string Options;
@@ -167,7 +168,7 @@ LLVM_ATTRIBUTE_NORETURN static void
show_help(const std::string &msg) {
errs() << ToolName << ": " << msg << "\n\n";
cl::PrintHelpMessage();
- std::exit(1);
+ exit(1);
}
// Extract the member filename from the command line for the [relpos] argument
@@ -376,7 +377,9 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) {
sys::fs::perms Mode = ModeOrErr.get();
int FD;
- failIfError(sys::fs::openFileForWrite(Name, FD, sys::fs::F_None, Mode), Name);
+ failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD,
+ sys::fs::F_None, Mode),
+ Name);
{
raw_fd_ostream file(FD, false);
@@ -462,7 +465,7 @@ static void performReadOperation(ArchiveOperation Operation,
return;
for (StringRef Name : Members)
errs() << Name << " was not found\n";
- std::exit(1);
+ exit(1);
}
static void addMember(std::vector<NewArchiveMember> &Members,
@@ -623,8 +626,9 @@ computeNewArchiveMembers(ArchiveOperation Operation,
}
static object::Archive::Kind getDefaultForHost() {
- return Triple(sys::getProcessTriple()).isOSDarwin() ? object::Archive::K_BSD
- : object::Archive::K_GNU;
+ return Triple(sys::getProcessTriple()).isOSDarwin()
+ ? object::Archive::K_DARWIN
+ : object::Archive::K_GNU;
}
static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
@@ -633,7 +637,7 @@ static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
if (OptionalObject)
return isa<object::MachOObjectFile>(**OptionalObject)
- ? object::Archive::K_BSD
+ ? object::Archive::K_DARWIN
: object::Archive::K_GNU;
// squelch the error in case we had a non-object file
@@ -672,6 +676,11 @@ performWriteOperation(ArchiveOperation Operation,
fail("Only the gnu format has a thin mode");
Kind = object::Archive::K_BSD;
break;
+ case DARWIN:
+ if (Thin)
+ fail("Only the gnu format has a thin mode");
+ Kind = object::Archive::K_DARWIN;
+ break;
}
std::pair<StringRef, std::error_code> Result =
diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index b84c4a83dee45..abc6fa27a0e05 100644
--- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -171,7 +171,6 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(MODULE_CODE, GLOBALVAR)
STRINGIFY_CODE(MODULE_CODE, FUNCTION)
STRINGIFY_CODE(MODULE_CODE, ALIAS)
- STRINGIFY_CODE(MODULE_CODE, PURGEVALS)
STRINGIFY_CODE(MODULE_CODE, GCNAME)
STRINGIFY_CODE(MODULE_CODE, VSTOFFSET)
STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES_UNUSED)
@@ -312,6 +311,10 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(FS, COMBINED_ORIGINAL_NAME)
STRINGIFY_CODE(FS, VERSION)
STRINGIFY_CODE(FS, TYPE_TESTS)
+ STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_VCALLS)
+ STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_VCALLS)
+ STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_CONST_VCALL)
+ STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL)
}
case bitc::METADATA_ATTACHMENT_ID:
switch(CodeID) {
diff --git a/tools/llvm-c-test/echo.cpp b/tools/llvm-c-test/echo.cpp
index 72ff138c74e32..52ce85c577821 100644
--- a/tools/llvm-c-test/echo.cpp
+++ b/tools/llvm-c-test/echo.cpp
@@ -591,7 +591,7 @@ struct FunCloner {
break;
}
case LLVMPHI: {
- // We need to agressively set things here because of loops.
+ // We need to aggressively set things here because of loops.
VMap[Src] = Dst = LLVMBuildPhi(Builder, CloneType(Src), Name);
SmallVector<LLVMValueRef, 8> Values;
diff --git a/tools/llvm-cat/llvm-cat.cpp b/tools/llvm-cat/llvm-cat.cpp
index d884970309b44..4d62099094bb8 100644
--- a/tools/llvm-cat/llvm-cat.cpp
+++ b/tools/llvm-cat/llvm-cat.cpp
@@ -40,7 +40,7 @@ int main(int argc, char **argv) {
SmallVector<char, 0> Buffer;
BitcodeWriter Writer(Buffer);
if (BinaryCat) {
- for (std::string InputFilename : InputFilenames) {
+ for (const auto &InputFilename : InputFilenames) {
std::unique_ptr<MemoryBuffer> MB = ExitOnErr(
errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFilename)));
std::vector<BitcodeModule> Mods = ExitOnErr(getBitcodeModuleList(*MB));
@@ -49,7 +49,7 @@ int main(int argc, char **argv) {
BitcodeMod.getBuffer().end());
}
} else {
- for (std::string InputFilename : InputFilenames) {
+ for (const auto &InputFilename : InputFilenames) {
SMDiagnostic Err;
std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
if (!M) {
diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp
index 0a9807ab00334..6179c760d5b20 100644
--- a/tools/llvm-cov/CodeCoverage.cpp
+++ b/tools/llvm-cov/CodeCoverage.cpp
@@ -15,6 +15,7 @@
#include "CoverageFilters.h"
#include "CoverageReport.h"
+#include "CoverageSummaryInfo.h"
#include "CoverageViewOptions.h"
#include "RenderingSupport.h"
#include "SourceCoverageView.h"
@@ -98,9 +99,6 @@ private:
/// \brief If a demangler is available, demangle all symbol names.
void demangleSymbols(const CoverageMapping &Coverage);
- /// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym.
- StringRef getSymbolForHumans(StringRef Sym) const;
-
/// \brief Write out a source file view to the filesystem.
void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
CoveragePrinter *Printer, bool ShowFilenames);
@@ -136,10 +134,10 @@ private:
/// The architecture the coverage mapping data targets.
std::string CoverageArch;
- /// A cache for demangled symbol names.
- StringMap<std::string> DemangledNames;
+ /// A cache for demangled symbols.
+ DemangleCache DC;
- /// Errors and warnings which have not been printed.
+ /// A lock which guards printing to stderr.
std::mutex ErrsLock;
/// A container for input source file buffers.
@@ -267,7 +265,7 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
return nullptr;
auto Expansions = FunctionCoverage.getExpansions();
- auto View = SourceCoverageView::create(getSymbolForHumans(Function.Name),
+ auto View = SourceCoverageView::create(DC.demangle(Function.Name),
SourceBuffer.get(), ViewOpts,
std::move(FunctionCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
@@ -293,7 +291,7 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
for (const auto *Function : Coverage.getInstantiations(SourceFile)) {
std::unique_ptr<SourceCoverageView> SubView{nullptr};
- StringRef Funcname = getSymbolForHumans(Function->Name);
+ StringRef Funcname = DC.demangle(Function->Name);
if (Function->ExecutionCount > 0) {
auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
@@ -453,14 +451,9 @@ void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
// Cache the demangled names.
unsigned I = 0;
for (const auto &Function : Coverage.getCoveredFunctions())
- DemangledNames[Function.Name] = Symbols[I++];
-}
-
-StringRef CodeCoverageTool::getSymbolForHumans(StringRef Sym) const {
- const auto DemangledName = DemangledNames.find(Sym);
- if (DemangledName == DemangledNames.end())
- return Sym;
- return DemangledName->getValue();
+ // On Windows, lines in the demangler's output file end with "\r\n".
+ // Splitting by '\n' keeps '\r's, so cut them now.
+ DC.DemangledNames[Function.Name] = Symbols[I++].rtrim();
}
void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
@@ -817,22 +810,28 @@ int CodeCoverageTool::show(int argc, const char **argv,
int CodeCoverageTool::report(int argc, const char **argv,
CommandLineParserType commandLineParser) {
+ cl::opt<bool> ShowFunctionSummaries(
+ "show-functions", cl::Optional, cl::init(false),
+ cl::desc("Show coverage summaries for each function"));
+
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
- if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML)
+ if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
error("HTML output for summary reports is not yet supported.");
+ return 1;
+ }
auto Coverage = load();
if (!Coverage)
return 1;
CoverageReport Report(ViewOpts, *Coverage.get());
- if (SourceFiles.empty())
+ if (!ShowFunctionSummaries)
Report.renderFileReports(llvm::outs());
else
- Report.renderFunctionReports(SourceFiles, llvm::outs());
+ Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
return 0;
}
@@ -843,6 +842,11 @@ int CodeCoverageTool::export_(int argc, const char **argv,
if (Err)
return Err;
+ if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
+ error("Coverage data can only be exported as textual JSON.");
+ return 1;
+ }
+
auto Coverage = load();
if (!Coverage) {
error("Could not load coverage information");
diff --git a/tools/llvm-cov/CoverageReport.cpp b/tools/llvm-cov/CoverageReport.cpp
index e88cb186acd66..c68bb9048df1b 100644
--- a/tools/llvm-cov/CoverageReport.cpp
+++ b/tools/llvm-cov/CoverageReport.cpp
@@ -118,19 +118,51 @@ raw_ostream::Colors determineCoveragePercentageColor(const T &Info) {
: raw_ostream::RED;
}
-/// \brief Determine the length of the longest common prefix of the strings in
-/// \p Strings.
-unsigned getLongestCommonPrefixLen(ArrayRef<std::string> Strings) {
- unsigned LCP = Strings[0].size();
- for (unsigned I = 1, E = Strings.size(); LCP > 0 && I < E; ++I) {
- unsigned Cursor;
- StringRef S = Strings[I];
- for (Cursor = 0; Cursor < LCP && Cursor < S.size(); ++Cursor)
- if (Strings[0][Cursor] != S[Cursor])
+/// \brief Get the number of redundant path components in each path in \p Paths.
+unsigned getNumRedundantPathComponents(ArrayRef<std::string> Paths) {
+ // To start, set the number of redundant path components to the maximum
+ // possible value.
+ SmallVector<StringRef, 8> FirstPathComponents{sys::path::begin(Paths[0]),
+ sys::path::end(Paths[0])};
+ unsigned NumRedundant = FirstPathComponents.size();
+
+ for (unsigned I = 1, E = Paths.size(); NumRedundant > 0 && I < E; ++I) {
+ StringRef Path = Paths[I];
+ for (const auto &Component :
+ enumerate(make_range(sys::path::begin(Path), sys::path::end(Path)))) {
+ // Do not increase the number of redundant components: that would remove
+ // useful parts of already-visited paths.
+ if (Component.index() >= NumRedundant)
break;
- LCP = std::min(LCP, Cursor);
+
+ // Lower the number of redundant components when there's a mismatch
+ // between the first path, and the path under consideration.
+ if (FirstPathComponents[Component.index()] != Component.value()) {
+ NumRedundant = Component.index();
+ break;
+ }
+ }
+ }
+
+ return NumRedundant;
+}
+
+/// \brief Determine the length of the longest redundant prefix of the paths in
+/// \p Paths.
+unsigned getRedundantPrefixLen(ArrayRef<std::string> Paths) {
+ // If there's at most one path, no path components are redundant.
+ if (Paths.size() <= 1)
+ return 0;
+
+ unsigned PrefixLen = 0;
+ unsigned NumRedundant = getNumRedundantPathComponents(Paths);
+ auto Component = sys::path::begin(Paths[0]);
+ for (unsigned I = 0; I < NumRedundant; ++I) {
+ auto LastComponent = Component;
+ ++Component;
+ PrefixLen += Component - LastComponent;
}
- return LCP;
+ return PrefixLen;
}
} // end anonymous namespace
@@ -200,12 +232,14 @@ void CoverageReport::render(const FileCoverageSummary &File,
}
void CoverageReport::render(const FunctionCoverageSummary &Function,
+ const DemangleCache &DC,
raw_ostream &OS) const {
auto FuncCoverageColor =
determineCoveragePercentageColor(Function.RegionCoverage);
auto LineCoverageColor =
determineCoveragePercentageColor(Function.LineCoverage);
- OS << column(Function.Name, FunctionReportColumns[0], Column::RightTrim)
+ OS << column(DC.demangle(Function.Name), FunctionReportColumns[0],
+ Column::RightTrim)
<< format("%*u", FunctionReportColumns[1],
(unsigned)Function.RegionCoverage.NumRegions);
Options.colored_ostream(OS, FuncCoverageColor)
@@ -230,6 +264,7 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
}
void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
+ const DemangleCache &DC,
raw_ostream &OS) {
bool isFirst = true;
for (StringRef Filename : Files) {
@@ -242,7 +277,7 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
std::vector<StringRef> Funcnames;
for (const auto &F : Functions)
- Funcnames.emplace_back(F.Name);
+ Funcnames.emplace_back(DC.demangle(F.Name));
adjustColumnWidths({}, Funcnames);
OS << "File '" << Filename << "':\n";
@@ -262,12 +297,12 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
++Totals.ExecutionCount;
Totals.RegionCoverage += Function.RegionCoverage;
Totals.LineCoverage += Function.LineCoverage;
- render(Function, OS);
+ render(Function, DC, OS);
}
if (Totals.ExecutionCount) {
renderDivider(FunctionReportColumns, OS);
OS << "\n";
- render(Totals, OS);
+ render(Totals, DC, OS);
}
}
}
@@ -277,9 +312,7 @@ CoverageReport::prepareFileReports(const coverage::CoverageMapping &Coverage,
FileCoverageSummary &Totals,
ArrayRef<std::string> Files) {
std::vector<FileCoverageSummary> FileReports;
- unsigned LCP = 0;
- if (Files.size() > 1)
- LCP = getLongestCommonPrefixLen(Files);
+ unsigned LCP = getRedundantPrefixLen(Files);
for (StringRef Filename : Files) {
FileCoverageSummary Summary(Filename.drop_front(LCP));
diff --git a/tools/llvm-cov/CoverageReport.h b/tools/llvm-cov/CoverageReport.h
index 7a416497e258e..071be2e21594c 100644
--- a/tools/llvm-cov/CoverageReport.h
+++ b/tools/llvm-cov/CoverageReport.h
@@ -25,14 +25,16 @@ class CoverageReport {
const coverage::CoverageMapping &Coverage;
void render(const FileCoverageSummary &File, raw_ostream &OS) const;
- void render(const FunctionCoverageSummary &Function, raw_ostream &OS) const;
+ void render(const FunctionCoverageSummary &Function, const DemangleCache &DC,
+ raw_ostream &OS) const;
public:
CoverageReport(const CoverageViewOptions &Options,
const coverage::CoverageMapping &Coverage)
: Options(Options), Coverage(Coverage) {}
- void renderFunctionReports(ArrayRef<std::string> Files, raw_ostream &OS);
+ void renderFunctionReports(ArrayRef<std::string> Files,
+ const DemangleCache &DC, raw_ostream &OS);
/// Prepare file reports for the files specified in \p Files.
static std::vector<FileCoverageSummary>
diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h
index c04a4d42ccd74..680fc3757686f 100644
--- a/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/tools/llvm-cov/CoverageSummaryInfo.h
@@ -160,6 +160,19 @@ struct FileCoverageSummary {
}
};
+/// \brief A cache for demangled symbols.
+struct DemangleCache {
+ StringMap<std::string> DemangledNames;
+
+ /// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym.
+ StringRef demangle(StringRef Sym) const {
+ const auto DemangledName = DemangledNames.find(Sym);
+ if (DemangledName == DemangledNames.end())
+ return Sym;
+ return DemangledName->getValue();
+ }
+};
+
} // namespace llvm
#endif // LLVM_COV_COVERAGESUMMARYINFO_H
diff --git a/tools/llvm-cov/TestingSupport.cpp b/tools/llvm-cov/TestingSupport.cpp
index 72768f4fd583f..4713d75f17dd4 100644
--- a/tools/llvm-cov/TestingSupport.cpp
+++ b/tools/llvm-cov/TestingSupport.cpp
@@ -48,13 +48,16 @@ int convertForTestingMain(int argc, const char *argv[]) {
// Look for the sections that we are interested in.
int FoundSectionCount = 0;
SectionRef ProfileNames, CoverageMapping;
+ auto ObjFormat = OF->getTripleObjectFormat();
for (const auto &Section : OF->sections()) {
StringRef Name;
if (Section.getName(Name))
return 1;
- if (Name == llvm::getInstrProfNameSectionName(false)) {
+ if (Name == llvm::getInstrProfSectionName(IPSK_name, ObjFormat,
+ /*AddSegmentInfo=*/false)) {
ProfileNames = Section;
- } else if (Name == llvm::getInstrProfCoverageSectionName(false)) {
+ } else if (Name == llvm::getInstrProfSectionName(
+ IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false)) {
CoverageMapping = Section;
} else
continue;
diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp
index 4652fed2a384e..4df7f015fd188 100644
--- a/tools/llvm-cov/gcov.cpp
+++ b/tools/llvm-cov/gcov.cpp
@@ -74,7 +74,7 @@ static void reportCoverage(StringRef SourceFile, StringRef ObjectDir,
}
if (DumpGCOV)
- GF.dump();
+ GF.print(errs());
FileInfo FI(Options);
GF.collectLineCounts(FI);
diff --git a/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
index 1e2797ba33343..13024fbeaeaa0 100644
--- a/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
+++ b/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
@@ -8,29 +8,89 @@
//===----------------------------------------------------------------------===//
#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
#include <iostream>
using namespace llvm;
+enum Style {
+ Auto, ///< auto-detect mangling
+ GNU, ///< GNU
+ Lucid, ///< Lucid compiler (lcc)
+ ARM,
+ HP, ///< HP compiler (xCC)
+ EDG, ///< EDG compiler
+ GNUv3, ///< GNU C++ v3 ABI
+ Java, ///< Java (gcj)
+ GNAT ///< ADA copiler (gnat)
+};
+static cl::opt<Style>
+ Format("format", cl::desc("decoration style"),
+ cl::values(clEnumValN(Auto, "auto", "auto-detect style"),
+ clEnumValN(GNU, "gnu", "GNU (itanium) style")),
+ cl::init(Auto));
+static cl::alias FormatShort("s", cl::desc("alias for --format"),
+ cl::aliasopt(Format));
+
+static cl::opt<bool> StripUnderscore("strip-underscore",
+ cl::desc("strip the leading underscore"),
+ cl::init(false));
+static cl::alias StripUnderscoreShort("_",
+ cl::desc("alias for --strip-underscore"),
+ cl::aliasopt(StripUnderscore));
+
+static cl::opt<bool>
+ Types("types",
+ cl::desc("attempt to demangle types as well as function names"),
+ cl::init(false));
+static cl::alias TypesShort("t", cl::desc("alias for --types"),
+ cl::aliasopt(Types));
+
+static cl::list<std::string>
+Decorated(cl::Positional, cl::desc("<mangled>"), cl::ZeroOrMore);
+
static void demangle(llvm::raw_ostream &OS, const std::string &Mangled) {
int Status;
- char *Demangled = nullptr;
- if ((Mangled.size() >= 2 && Mangled.compare(0, 2, "_Z")) ||
- (Mangled.size() >= 4 && Mangled.compare(0, 4, "___Z")))
- Demangled = itaniumDemangle(Mangled.c_str(), nullptr, nullptr, &Status);
- OS << (Demangled ? Demangled : Mangled) << '\n';
- free(Demangled);
+
+ const char *Decorated = Mangled.c_str();
+ if (StripUnderscore)
+ if (Decorated[0] == '_')
+ ++Decorated;
+ size_t DecoratedLength = strlen(Decorated);
+
+ char *Undecorated = nullptr;
+
+ if (Types || ((DecoratedLength >= 2 && strncmp(Decorated, "_Z", 2) == 0) ||
+ (DecoratedLength >= 4 && strncmp(Decorated, "___Z", 4) == 0)))
+ Undecorated = itaniumDemangle(Decorated, nullptr, nullptr, &Status);
+
+ if (!Undecorated &&
+ (DecoratedLength > 6 && strncmp(Decorated, "__imp_", 6) == 0)) {
+ OS << "import thunk for ";
+ Undecorated = itaniumDemangle(Decorated + 6, nullptr, nullptr, &Status);
+ }
+
+ OS << (Undecorated ? Undecorated : Mangled) << '\n';
+
+ free(Undecorated);
}
int main(int argc, char **argv) {
- if (argc == 1)
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
+ PrettyStackTraceProgram X(argc, argv);
+
+ cl::ParseCommandLineOptions(argc, argv, "llvm symbol undecoration tool\n");
+
+ if (Decorated.empty())
for (std::string Mangled; std::getline(std::cin, Mangled);)
demangle(llvm::outs(), Mangled);
else
- for (int I = 1; I < argc; ++I)
- demangle(llvm::outs(), argv[I]);
+ for (const auto &Symbol : Decorated)
+ demangle(llvm::outs(), Symbol);
return EXIT_SUCCESS;
}
diff --git a/tools/llvm-diff/DiffConsumer.cpp b/tools/llvm-diff/DiffConsumer.cpp
index 9078013c1c163..e16775010fef4 100644
--- a/tools/llvm-diff/DiffConsumer.cpp
+++ b/tools/llvm-diff/DiffConsumer.cpp
@@ -15,6 +15,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Debug.h"
using namespace llvm;
@@ -195,17 +196,17 @@ void DiffConsumer::logd(const DiffLogBuilder &Log) {
switch (Log.getLineKind(I)) {
case DC_match:
out << " ";
- Log.getLeft(I)->dump();
+ Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
//printValue(Log.getLeft(I), true);
break;
case DC_left:
out << "< ";
- Log.getLeft(I)->dump();
+ Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
//printValue(Log.getLeft(I), true);
break;
case DC_right:
out << "> ";
- Log.getRight(I)->dump();
+ Log.getRight(I)->print(dbgs()); dbgs() << '\n';
//printValue(Log.getRight(I), false);
break;
}
diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp
index df208a26ab7df..95a63d7f9c835 100644
--- a/tools/llvm-diff/DifferenceEngine.cpp
+++ b/tools/llvm-diff/DifferenceEngine.cpp
@@ -315,17 +315,15 @@ class FunctionDifferenceEngine {
bool Difference = false;
DenseMap<ConstantInt*,BasicBlock*> LCases;
-
- for (SwitchInst::CaseIt I = LI->case_begin(), E = LI->case_end();
- I != E; ++I)
- LCases[I.getCaseValue()] = I.getCaseSuccessor();
-
- for (SwitchInst::CaseIt I = RI->case_begin(), E = RI->case_end();
- I != E; ++I) {
- ConstantInt *CaseValue = I.getCaseValue();
+ for (auto Case : LI->cases())
+ LCases[Case.getCaseValue()] = Case.getCaseSuccessor();
+
+ for (auto Case : RI->cases()) {
+ ConstantInt *CaseValue = Case.getCaseValue();
BasicBlock *LCase = LCases[CaseValue];
if (LCase) {
- if (TryUnify) tryUnify(LCase, I.getCaseSuccessor());
+ if (TryUnify)
+ tryUnify(LCase, Case.getCaseSuccessor());
LCases.erase(CaseValue);
} else if (Complain || !Difference) {
if (Complain)
diff --git a/tools/llvm-dwp/llvm-dwp.cpp b/tools/llvm-dwp/llvm-dwp.cpp
index 7418c77bdeca2..0c4af7576608c 100644
--- a/tools/llvm-dwp/llvm-dwp.cpp
+++ b/tools/llvm-dwp/llvm-dwp.cpp
@@ -27,6 +27,7 @@
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include "llvm/Object/Decompressor.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/DataExtractor.h"
@@ -334,21 +335,6 @@ writeIndex(MCStreamer &Out, MCSection *Section,
writeIndexTable(Out, ContributionOffsets, IndexEntries,
&DWARFUnitIndex::Entry::SectionContribution::Length);
}
-static bool consumeCompressedDebugSectionHeader(StringRef &data,
- uint64_t &OriginalSize) {
- // Consume "ZLIB" prefix.
- if (!data.startswith("ZLIB"))
- return false;
- data = data.substr(4);
- // Consume uncompressed section size (big-endian 8 bytes).
- DataExtractor extractor(data, false, 8);
- uint32_t Offset = 0;
- OriginalSize = extractor.getU64(&Offset);
- if (Offset == 0)
- return false;
- data = data.substr(Offset);
- return true;
-}
std::string buildDWODescription(StringRef Name, StringRef DWPName, StringRef DWOName) {
std::string Text = "\'";
@@ -368,22 +354,29 @@ std::string buildDWODescription(StringRef Name, StringRef DWPName, StringRef DWO
return Text;
}
-static Error handleCompressedSection(
- std::deque<SmallString<32>> &UncompressedSections, StringRef &Name,
- StringRef &Contents) {
- if (!Name.startswith("zdebug_"))
+static Error createError(StringRef Name, Error E) {
+ return make_error<DWPError>(
+ ("failure while decompressing compressed section: '" + Name + "', " +
+ llvm::toString(std::move(E)))
+ .str());
+}
+
+static Error
+handleCompressedSection(std::deque<SmallString<32>> &UncompressedSections,
+ StringRef &Name, StringRef &Contents) {
+ if (!Decompressor::isGnuStyle(Name))
return Error::success();
+
+ Expected<Decompressor> Dec =
+ Decompressor::create(Name, Contents, false /*IsLE*/, false /*Is64Bit*/);
+ if (!Dec)
+ return createError(Name, Dec.takeError());
+
UncompressedSections.emplace_back();
- uint64_t OriginalSize;
- if (!zlib::isAvailable())
- return make_error<DWPError>("zlib not available");
- if (!consumeCompressedDebugSectionHeader(Contents, OriginalSize) ||
- zlib::uncompress(Contents, UncompressedSections.back(), OriginalSize) !=
- zlib::StatusOK)
- return make_error<DWPError>(
- ("failure while decompressing compressed section: '" + Name + "\'")
- .str());
- Name = Name.substr(1);
+ if (Error E = Dec->decompress(UncompressedSections.back()))
+ return createError(Name, std::move(E));
+
+ Name = Name.substr(2); // Drop ".z"
Contents = UncompressedSections.back();
return Error::success();
}
@@ -409,8 +402,6 @@ static Error handleSection(
if (std::error_code Err = Section.getName(Name))
return errorCodeToError(Err);
- Name = Name.substr(Name.find_first_not_of("._"));
-
StringRef Contents;
if (auto Err = Section.getContents(Contents))
return errorCodeToError(Err);
@@ -418,6 +409,8 @@ static Error handleSection(
if (auto Err = handleCompressedSection(UncompressedSections, Name, Contents))
return Err;
+ Name = Name.substr(Name.find_first_not_of("._"));
+
auto SectionPair = KnownSections.find(Name);
if (SectionPair == KnownSections.end())
return Error::success();
diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp
index aa1eda2f094a6..d868db7f78ad1 100644
--- a/tools/llvm-extract/llvm-extract.cpp
+++ b/tools/llvm-extract/llvm-extract.cpp
@@ -17,10 +17,11 @@
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IRPrintingPasses.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
-#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
@@ -50,6 +51,10 @@ Force("f", cl::desc("Enable binary output on terminals"));
static cl::opt<bool>
DeleteFn("delete", cl::desc("Delete specified Globals from Module"));
+static cl::opt<bool>
+ Recursive("recursive",
+ cl::desc("Recursively extract all called functions"));
+
// ExtractFuncs - The functions to extract from the module.
static cl::list<std::string>
ExtractFuncs("func", cl::desc("Specify function to extract"),
@@ -226,6 +231,34 @@ int main(int argc, char **argv) {
// Use *argv instead of argv[0] to work around a wrong GCC warning.
ExitOnError ExitOnErr(std::string(*argv) + ": error reading input: ");
+ if (Recursive) {
+ std::vector<llvm::Function *> Workqueue;
+ for (GlobalValue *GV : GVs) {
+ if (auto *F = dyn_cast<Function>(GV)) {
+ Workqueue.push_back(F);
+ }
+ }
+ while (!Workqueue.empty()) {
+ Function *F = &*Workqueue.back();
+ Workqueue.pop_back();
+ ExitOnErr(F->materialize());
+ for (auto &BB : *F) {
+ for (auto &I : BB) {
+ auto *CI = dyn_cast<CallInst>(&I);
+ if (!CI)
+ continue;
+ Function *CF = CI->getCalledFunction();
+ if (!CF)
+ continue;
+ if (CF->isDeclaration() || GVs.count(CF))
+ continue;
+ GVs.insert(CF);
+ Workqueue.push_back(CF);
+ }
+ }
+ }
+ }
+
auto Materialize = [&](GlobalValue &GV) { ExitOnErr(GV.materialize()); };
// Materialize requisite global values.
diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp
index e89696e7e7c24..a024b6926d5dd 100644
--- a/tools/llvm-link/llvm-link.cpp
+++ b/tools/llvm-link/llvm-link.cpp
@@ -34,6 +34,7 @@
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Transforms/IPO/FunctionImport.h"
+#include "llvm/Transforms/IPO/Internalize.h"
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
#include <memory>
@@ -272,6 +273,8 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
unsigned Flags) {
// Filter out flags that don't apply to the first file we load.
unsigned ApplicableFlags = Flags & Linker::Flags::OverrideFromSrc;
+ // Similar to some flags, internalization doesn't apply to the first file.
+ bool InternalizeLinkedSymbols = false;
for (const auto &File : Files) {
std::unique_ptr<Module> M = loadFile(argv0, File, Context);
if (!M.get()) {
@@ -311,8 +314,24 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
if (Verbose)
errs() << "Linking in '" << File << "'\n";
- if (L.linkInModule(std::move(M), ApplicableFlags))
+ bool Err = false;
+ if (InternalizeLinkedSymbols) {
+ Err = L.linkInModule(
+ std::move(M), ApplicableFlags, [](Module &M, const StringSet<> &GVS) {
+ internalizeModule(M, [&GVS](const GlobalValue &GV) {
+ return !GV.hasName() || (GVS.count(GV.getName()) == 0);
+ });
+ });
+ } else {
+ Err = L.linkInModule(std::move(M), ApplicableFlags);
+ }
+
+ if (Err)
return false;
+
+ // Internalization applies to linking of subsequent files.
+ InternalizeLinkedSymbols = Internalize;
+
// All linker flags apply to linking of subsequent files.
ApplicableFlags = Flags;
}
@@ -340,8 +359,6 @@ int main(int argc, char **argv) {
Linker L(*Composite);
unsigned Flags = Linker::Flags::None;
- if (Internalize)
- Flags |= Linker::Flags::InternalizeLinkedSymbols;
if (OnlyNeeded)
Flags |= Linker::Flags::LinkOnlyNeeded;
diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp
index 475350c8ecf12..2f005412a3b92 100644
--- a/tools/llvm-lto/llvm-lto.cpp
+++ b/tools/llvm-lto/llvm-lto.cpp
@@ -63,6 +63,10 @@ static cl::opt<bool> DisableLTOVectorization(
"disable-lto-vectorization", cl::init(false),
cl::desc("Do not run loop or slp vectorization during LTO"));
+static cl::opt<bool> EnableFreestanding(
+ "lto-freestanding", cl::init(false),
+ cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"));
+
static cl::opt<bool> UseDiagnosticHandler(
"use-diagnostic-handler", cl::init(false),
cl::desc("Use a diagnostic handler to test the handler interface"));
@@ -433,6 +437,7 @@ public:
ThinGenerator.setCodePICModel(getRelocModel());
ThinGenerator.setTargetOptions(Options);
ThinGenerator.setCacheDir(ThinLTOCacheDir);
+ ThinGenerator.setFreestanding(EnableFreestanding);
// Add all the exported symbols to the table of symbols to preserve.
for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
@@ -809,6 +814,7 @@ int main(int argc, char **argv) {
CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
CodeGen.setCodePICModel(getRelocModel());
+ CodeGen.setFreestanding(EnableFreestanding);
CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
CodeGen.setTargetOptions(Options);
diff --git a/tools/llvm-lto2/llvm-lto2.cpp b/tools/llvm-lto2/llvm-lto2.cpp
index c09311a05b90d..3d2643db85bd8 100644
--- a/tools/llvm-lto2/llvm-lto2.cpp
+++ b/tools/llvm-lto2/llvm-lto2.cpp
@@ -21,12 +21,12 @@
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Threading.h"
using namespace llvm;
using namespace lto;
-using namespace object;
static cl::opt<char>
OptLevel("O", cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
@@ -90,11 +90,20 @@ static cl::opt<std::string> DefaultTriple(
cl::desc(
"Replace unspecified target triples in input files with this triple"));
+static cl::opt<std::string>
+ OptRemarksOutput("pass-remarks-output",
+ cl::desc("YAML output file for optimization remarks"));
+
+static cl::opt<bool> OptRemarksWithHotness(
+ "pass-remarks-with-hotness",
+ cl::desc("Whether to include hotness informations in the remarks.\n"
+ "Has effect only if -pass-remarks-output is specified."));
+
static void check(Error E, std::string Msg) {
if (!E)
return;
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
- errs() << "llvm-lto: " << Msg << ": " << EIB.message().c_str() << '\n';
+ errs() << "llvm-lto2: " << Msg << ": " << EIB.message().c_str() << '\n';
});
exit(1);
}
@@ -117,12 +126,12 @@ template <typename T> static T check(ErrorOr<T> E, std::string Msg) {
return T();
}
-int main(int argc, char **argv) {
- InitializeAllTargets();
- InitializeAllTargetMCs();
- InitializeAllAsmPrinters();
- InitializeAllAsmParsers();
+static int usage() {
+ errs() << "Available subcommands: dump-symtab run\n";
+ return 1;
+}
+static int run(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");
// FIXME: Workaround PR30396 which means that a symbol can appear
@@ -148,9 +157,11 @@ int main(int argc, char **argv) {
Res.FinalDefinitionInLinkageUnit = true;
else if (C == 'x')
Res.VisibleToRegularObj = true;
- else
+ else {
llvm::errs() << "invalid character " << C << " in resolution: " << R
<< '\n';
+ return 1;
+ }
}
CommandLineResolutions[{FileName, SymbolName}].push_back(Res);
}
@@ -176,6 +187,10 @@ int main(int argc, char **argv) {
check(Conf.addSaveTemps(OutputFilename + "."),
"Config::addSaveTemps failed");
+ // Optimization remarks.
+ Conf.RemarksFilename = OptRemarksOutput;
+ Conf.RemarksWithHotness = OptRemarksWithHotness;
+
// Run a custom pipeline, if asked for.
Conf.OptPipeline = OptPipeline;
Conf.AAPipeline = AAPipeline;
@@ -199,6 +214,9 @@ int main(int argc, char **argv) {
return 1;
}
+ if (FileType.getNumOccurrences())
+ Conf.CGFileType = FileType;
+
Conf.OverrideTriple = OverrideTriple;
Conf.DefaultTriple = DefaultTriple;
@@ -257,18 +275,92 @@ int main(int argc, char **argv) {
return llvm::make_unique<lto::NativeObjectStream>(std::move(S));
};
- auto AddFile = [&](size_t Task, StringRef Path) {
- auto ReloadedBufferOrErr = MemoryBuffer::getFile(Path);
- if (auto EC = ReloadedBufferOrErr.getError())
- report_fatal_error(Twine("Can't reload cached file '") + Path + "': " +
- EC.message() + "\n");
-
- *AddStream(Task)->OS << (*ReloadedBufferOrErr)->getBuffer();
+ auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ *AddStream(Task)->OS << MB->getBuffer();
};
NativeObjectCache Cache;
if (!CacheDir.empty())
- Cache = localCache(CacheDir, AddFile);
+ Cache = check(localCache(CacheDir, AddBuffer), "failed to create cache");
check(Lto.run(AddStream, Cache), "LTO::run failed");
+ return 0;
+}
+
+static int dumpSymtab(int argc, char **argv) {
+ for (StringRef F : make_range(argv + 1, argv + argc)) {
+ std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);
+ std::unique_ptr<InputFile> Input =
+ check(InputFile::create(MB->getMemBufferRef()), F);
+
+ outs() << "target triple: " << Input->getTargetTriple() << '\n';
+ Triple TT(Input->getTargetTriple());
+
+ outs() << "source filename: " << Input->getSourceFileName() << '\n';
+
+ if (TT.isOSBinFormatCOFF())
+ outs() << "linker opts: " << Input->getCOFFLinkerOpts() << '\n';
+
+ std::vector<StringRef> ComdatTable = Input->getComdatTable();
+ for (const InputFile::Symbol &Sym : Input->symbols()) {
+ switch (Sym.getVisibility()) {
+ case GlobalValue::HiddenVisibility:
+ outs() << 'H';
+ break;
+ case GlobalValue::ProtectedVisibility:
+ outs() << 'P';
+ break;
+ case GlobalValue::DefaultVisibility:
+ outs() << 'D';
+ break;
+ }
+
+ auto PrintBool = [&](char C, bool B) { outs() << (B ? C : '-'); };
+ PrintBool('U', Sym.isUndefined());
+ PrintBool('C', Sym.isCommon());
+ PrintBool('W', Sym.isWeak());
+ PrintBool('I', Sym.isIndirect());
+ PrintBool('O', Sym.canBeOmittedFromSymbolTable());
+ PrintBool('T', Sym.isTLS());
+ PrintBool('X', Sym.isExecutable());
+ outs() << ' ' << Sym.getName() << '\n';
+
+ if (Sym.isCommon())
+ outs() << " size " << Sym.getCommonSize() << " align "
+ << Sym.getCommonAlignment() << '\n';
+
+ int Comdat = Sym.getComdatIndex();
+ if (Comdat != -1)
+ outs() << " comdat " << ComdatTable[Comdat] << '\n';
+
+ if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect())
+ outs() << " fallback " << Sym.getCOFFWeakExternalFallback() << '\n';
+ }
+
+ outs() << '\n';
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+
+ // FIXME: This should use llvm::cl subcommands, but it isn't currently
+ // possible to pass an argument not associated with a subcommand to a
+ // subcommand (e.g. -lto-use-new-pm).
+ if (argc < 2)
+ return usage();
+
+ StringRef Subcommand = argv[1];
+ // Ensure that argv[0] is correct after adjusting argv/argc.
+ argv[1] = argv[0];
+ if (Subcommand == "dump-symtab")
+ return dumpSymtab(argc - 1, argv + 1);
+ if (Subcommand == "run")
+ return run(argc - 1, argv + 1);
+ return usage();
}
diff --git a/tools/llvm-mc-assemble-fuzzer/CMakeLists.txt b/tools/llvm-mc-assemble-fuzzer/CMakeLists.txt
new file mode 100644
index 0000000000000..c5fb62166cfd4
--- /dev/null
+++ b/tools/llvm-mc-assemble-fuzzer/CMakeLists.txt
@@ -0,0 +1,19 @@
+if( LLVM_USE_SANITIZE_COVERAGE )
+ include_directories(BEFORE
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/Fuzzer)
+
+ set(LLVM_LINK_COMPONENTS
+ AllTargetsAsmPrinters
+ AllTargetsAsmParsers
+ AllTargetsDescs
+ AllTargetsInfos
+ MC
+ MCParser
+ Support
+ )
+ add_llvm_tool(llvm-mc-assemble-fuzzer
+ llvm-mc-assemble-fuzzer.cpp)
+ target_link_libraries(llvm-mc-assemble-fuzzer
+ LLVMFuzzer
+ )
+endif()
diff --git a/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp b/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp
new file mode 100644
index 0000000000000..0344d8cd8c9a2
--- /dev/null
+++ b/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp
@@ -0,0 +1,313 @@
+//===--- llvm-mc-fuzzer.cpp - Fuzzer for the MC layer ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerInterface.h"
+#include "llvm-c/Target.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/AsmLexer.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/ToolOutputFile.h"
+
+using namespace llvm;
+
+static cl::opt<std::string>
+ TripleName("triple", cl::desc("Target triple to assemble for, "
+ "see -version for available targets"));
+
+static cl::opt<std::string>
+ MCPU("mcpu",
+ cl::desc("Target a specific cpu type (-mcpu=help for details)"),
+ cl::value_desc("cpu-name"), cl::init(""));
+
+// This is useful for variable-length instruction sets.
+static cl::opt<unsigned> InsnLimit(
+ "insn-limit",
+ cl::desc("Limit the number of instructions to process (0 for no limit)"),
+ cl::value_desc("count"), cl::init(0));
+
+static cl::list<std::string>
+ MAttrs("mattr", cl::CommaSeparated,
+ cl::desc("Target specific attributes (-mattr=help for details)"),
+ cl::value_desc("a1,+a2,-a3,..."));
+// The feature string derived from -mattr's values.
+std::string FeaturesStr;
+
+static cl::list<std::string>
+ FuzzerArgs("fuzzer-args", cl::Positional,
+ cl::desc("Options to pass to the fuzzer"), cl::ZeroOrMore,
+ cl::PositionalEatsArgs);
+static std::vector<char *> ModifiedArgv;
+
+enum OutputFileType {
+ OFT_Null,
+ OFT_AssemblyFile,
+ OFT_ObjectFile
+};
+static cl::opt<OutputFileType>
+FileType("filetype", cl::init(OFT_AssemblyFile),
+ cl::desc("Choose an output file type:"),
+ cl::values(
+ clEnumValN(OFT_AssemblyFile, "asm",
+ "Emit an assembly ('.s') file"),
+ clEnumValN(OFT_Null, "null",
+ "Don't emit anything (for timing purposes)"),
+ clEnumValN(OFT_ObjectFile, "obj",
+ "Emit a native object ('.o') file")));
+
+
+class LLVMFuzzerInputBuffer : public MemoryBuffer
+{
+ public:
+ LLVMFuzzerInputBuffer(const uint8_t *data_, size_t size_)
+ : Data(reinterpret_cast<const char *>(data_)),
+ Size(size_) {
+ init(Data, Data+Size, false);
+ }
+
+
+ virtual BufferKind getBufferKind() const {
+ return MemoryBuffer_Malloc; // it's not disk-backed so I think that's
+ // the intent ... though AFAIK it
+ // probably came from an mmap or sbrk
+ }
+
+ private:
+ const char *Data;
+ size_t Size;
+};
+
+static int AssembleInput(const char *ProgName, const Target *TheTarget,
+ SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,
+ MCAsmInfo &MAI, MCSubtargetInfo &STI,
+ MCInstrInfo &MCII, MCTargetOptions &MCOptions) {
+ static const bool NoInitialTextSection = false;
+
+ std::unique_ptr<MCAsmParser> Parser(
+ createMCAsmParser(SrcMgr, Ctx, Str, MAI));
+
+ std::unique_ptr<MCTargetAsmParser> TAP(
+ TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
+
+ if (!TAP) {
+ errs() << ProgName
+ << ": error: this target '" << TripleName
+ << "', does not support assembly parsing.\n";
+ abort();
+ }
+
+ Parser->setTargetParser(*TAP);
+
+ return Parser->Run(NoInitialTextSection);
+}
+
+
+int AssembleOneInput(const uint8_t *Data, size_t Size) {
+ const bool ShowInst = false;
+ const bool AsmVerbose = false;
+ const bool UseDwarfDirectory = true;
+
+ Triple TheTriple(Triple::normalize(TripleName));
+
+ SourceMgr SrcMgr;
+
+ std::unique_ptr<MemoryBuffer> BufferPtr(new LLVMFuzzerInputBuffer(Data, Size));
+
+ // Tell SrcMgr about this buffer, which is what the parser will pick up.
+ SrcMgr.AddNewSourceBuffer(std::move(BufferPtr), SMLoc());
+
+ static const std::vector<std::string> NoIncludeDirs;
+ SrcMgr.setIncludeDirs(NoIncludeDirs);
+
+ static std::string ArchName;
+ std::string Error;
+ const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
+ Error);
+ if (!TheTarget) {
+ errs() << "error: this target '" << TheTriple.normalize()
+ << "/" << ArchName << "', was not found: '" << Error << "'\n";
+
+ abort();
+ }
+
+ std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
+ if (!MRI) {
+ errs() << "Unable to create target register info!";
+ abort();
+ }
+
+ std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName));
+ if (!MAI) {
+ errs() << "Unable to create target asm info!";
+ abort();
+ }
+
+
+ MCObjectFileInfo MOFI;
+ MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr);
+
+ static const bool UsePIC = false;
+ static const CodeModel::Model CMModel = CodeModel::Default;
+ MOFI.InitMCObjectFileInfo(TheTriple, UsePIC, CMModel, Ctx);
+
+ const unsigned OutputAsmVariant = 0;
+ std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
+ MCInstPrinter *IP = TheTarget->createMCInstPrinter(Triple(TripleName), OutputAsmVariant,
+ *MAI, *MCII, *MRI);
+ if (!IP) {
+ errs()
+ << "error: unable to create instruction printer for target triple '"
+ << TheTriple.normalize() << "' with assembly variant "
+ << OutputAsmVariant << ".\n";
+
+ abort();
+ }
+
+ const char *ProgName = "llvm-mc-fuzzer";
+ std::unique_ptr<MCSubtargetInfo> STI(
+ TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));
+ MCCodeEmitter *CE = nullptr;
+ MCAsmBackend *MAB = nullptr;
+
+ MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
+
+ std::string OutputString;
+ raw_string_ostream Out(OutputString);
+ auto FOut = llvm::make_unique<formatted_raw_ostream>(Out);
+
+ std::unique_ptr<MCStreamer> Str;
+
+ if (FileType == OFT_AssemblyFile) {
+ Str.reset(TheTarget->createAsmStreamer(
+ Ctx, std::move(FOut), AsmVerbose,
+ UseDwarfDirectory, IP, CE, MAB, ShowInst));
+ } else {
+ assert(FileType == OFT_ObjectFile && "Invalid file type!");
+
+ std::error_code EC;
+ const std::string OutputFilename = "-";
+ auto Out = llvm::make_unique<tool_output_file>(OutputFilename, EC,
+ sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
+ abort();
+ }
+
+ // Don't waste memory on names of temp labels.
+ Ctx.setUseNamesOnTempLabels(false);
+
+ std::unique_ptr<buffer_ostream> BOS;
+ raw_pwrite_stream *OS = &Out->os();
+ if (!Out->os().supportsSeeking()) {
+ BOS = make_unique<buffer_ostream>(Out->os());
+ OS = BOS.get();
+ }
+
+ MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
+ MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU,
+ MCOptions);
+ Str.reset(TheTarget->createMCObjectStreamer(
+ TheTriple, Ctx, *MAB, *OS, CE, *STI, MCOptions.MCRelaxAll,
+ MCOptions.MCIncrementalLinkerCompatible,
+ /*DWARFMustBeAtTheEnd*/ false));
+ }
+ const int Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI,
+ *MCII, MCOptions);
+
+ (void) Res;
+
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ return AssembleOneInput(Data, Size);
+}
+
+int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ // The command line is unusual compared to other fuzzers due to the need to
+ // specify the target. Options like -triple, -mcpu, and -mattr work like
+ // their counterparts in llvm-mc, while -fuzzer-args collects options for the
+ // fuzzer itself.
+ //
+ // Examples:
+ //
+ // Fuzz the big-endian MIPS32R6 disassembler using 100,000 inputs of up to
+ // 4-bytes each and use the contents of ./corpus as the test corpus:
+ // llvm-mc-fuzzer -triple mips-linux-gnu -mcpu=mips32r6 -disassemble \
+ // -fuzzer-args -max_len=4 -runs=100000 ./corpus
+ //
+ // Infinitely fuzz the little-endian MIPS64R2 disassembler with the MSA
+ // feature enabled using up to 64-byte inputs:
+ // llvm-mc-fuzzer -triple mipsel-linux-gnu -mcpu=mips64r2 -mattr=msa \
+ // -disassemble -fuzzer-args ./corpus
+ //
+ // If your aim is to find instructions that are not tested, then it is
+ // advisable to constrain the maximum input size to a single instruction
+ // using -max_len as in the first example. This results in a test corpus of
+ // individual instructions that test unique paths. Without this constraint,
+ // there will be considerable redundancy in the corpus.
+
+ char **OriginalArgv = *argv;
+
+ LLVMInitializeAllTargetInfos();
+ LLVMInitializeAllTargetMCs();
+ LLVMInitializeAllAsmParsers();
+
+ cl::ParseCommandLineOptions(*argc, OriginalArgv);
+
+ // Rebuild the argv without the arguments llvm-mc-fuzzer consumed so that
+ // the driver can parse its arguments.
+ //
+ // FuzzerArgs cannot provide the non-const pointer that OriginalArgv needs.
+ // Re-use the strings from OriginalArgv instead of copying FuzzerArg to a
+ // non-const buffer to avoid the need to clean up when the fuzzer terminates.
+ ModifiedArgv.push_back(OriginalArgv[0]);
+ for (const auto &FuzzerArg : FuzzerArgs) {
+ for (int i = 1; i < *argc; ++i) {
+ if (FuzzerArg == OriginalArgv[i])
+ ModifiedArgv.push_back(OriginalArgv[i]);
+ }
+ }
+ *argc = ModifiedArgv.size();
+ *argv = ModifiedArgv.data();
+
+ // Package up features to be passed to target/subtarget
+ // We have to pass it via a global since the callback doesn't
+ // permit any user data.
+ if (MAttrs.size()) {
+ SubtargetFeatures Features;
+ for (unsigned i = 0; i != MAttrs.size(); ++i)
+ Features.AddFeature(MAttrs[i]);
+ FeaturesStr = Features.getString();
+ }
+
+ if (TripleName.empty())
+ TripleName = sys::getDefaultTargetTriple();
+
+ return 0;
+}
diff --git a/tools/llvm-mc-fuzzer/CMakeLists.txt b/tools/llvm-mc-disassemble-fuzzer/CMakeLists.txt
index b42b3eee3c981..c539f823e57f4 100644
--- a/tools/llvm-mc-fuzzer/CMakeLists.txt
+++ b/tools/llvm-mc-disassemble-fuzzer/CMakeLists.txt
@@ -3,16 +3,19 @@ if( LLVM_USE_SANITIZE_COVERAGE )
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/Fuzzer)
set(LLVM_LINK_COMPONENTS
+ AllTargetsAsmPrinters
AllTargetsDescs
AllTargetsDisassemblers
AllTargetsInfos
MC
MCDisassembler
+ MCParser
Support
)
- add_llvm_tool(llvm-mc-fuzzer
- llvm-mc-fuzzer.cpp)
- target_link_libraries(llvm-mc-fuzzer
+ add_llvm_tool(llvm-mc-disassemble-fuzzer
+ llvm-mc-disassemble-fuzzer.cpp)
+
+ target_link_libraries(llvm-mc-disassemble-fuzzer
LLVMFuzzer
)
endif()
diff --git a/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp b/tools/llvm-mc-disassemble-fuzzer/llvm-mc-disassemble-fuzzer.cpp
index e31ea762add53..643afe64073e6 100644
--- a/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp
+++ b/tools/llvm-mc-disassemble-fuzzer/llvm-mc-disassemble-fuzzer.cpp
@@ -20,19 +20,6 @@ using namespace llvm;
const unsigned AssemblyTextBufSize = 80;
-enum ActionType {
- AC_Assemble,
- AC_Disassemble
-};
-
-static cl::opt<ActionType>
-Action(cl::desc("Action to perform:"),
- cl::init(AC_Assemble),
- cl::values(clEnumValN(AC_Assemble, "assemble",
- "Assemble a .s file (default)"),
- clEnumValN(AC_Disassemble, "disassemble",
- "Disassemble strings of hex bytes")));
-
static cl::opt<std::string>
TripleName("triple", cl::desc("Target triple to assemble for, "
"see -version for available targets"));
@@ -88,13 +75,7 @@ int DisassembleOneInput(const uint8_t *Data, size_t Size) {
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
- if (Action == AC_Assemble)
- errs() << "error: -assemble is not implemented\n";
- else if (Action == AC_Disassemble)
- return DisassembleOneInput(Data, Size);
-
- llvm_unreachable("Unknown action");
- return 0;
+ return DisassembleOneInput(Data, Size);
}
int LLVMFuzzerInitialize(int *argc, char ***argv) {
@@ -155,5 +136,8 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) {
FeaturesStr = Features.getString();
}
+ if (TripleName.empty())
+ TripleName = sys::getDefaultTargetTriple();
+
return 0;
}
diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp
index 497fb1987764e..87efac2d33cf7 100644
--- a/tools/llvm-mc/llvm-mc.cpp
+++ b/tools/llvm-mc/llvm-mc.cpp
@@ -516,7 +516,7 @@ int main(int argc, char **argv) {
Ctx.setGenDwarfForAssembly(GenDwarfForAssembly);
// Default to 4 for dwarf version.
unsigned DwarfVersion = MCOptions.DwarfVersion ? MCOptions.DwarfVersion : 4;
- if (DwarfVersion < 2 || DwarfVersion > 4) {
+ if (DwarfVersion < 2 || DwarfVersion > 5) {
errs() << ProgName << ": Dwarf version " << DwarfVersion
<< " is not supported." << '\n';
return 1;
diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp
index aa89f89c31d56..a07fcef35ebe5 100644
--- a/tools/llvm-nm/llvm-nm.cpp
+++ b/tools/llvm-nm/llvm-nm.cpp
@@ -29,6 +29,7 @@
#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/Wasm.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
@@ -129,6 +130,7 @@ cl::opt<bool> PrintSize("print-size",
cl::desc("Show symbol size instead of address"));
cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"),
cl::aliasopt(PrintSize), cl::Grouping);
+bool MachOPrintSizeWarning = false;
cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size"));
@@ -269,6 +271,8 @@ static char isSymbolList64Bit(SymbolicFile &Obj) {
return Triple(IRObj->getTargetTriple()).isArch64Bit();
if (isa<COFFObjectFile>(Obj))
return false;
+ if (isa<WasmObjectFile>(Obj))
+ return false;
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
return MachO->is64Bit();
return cast<ELFObjectFileBase>(Obj).getBytesInAddress() == 8;
@@ -882,6 +886,13 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
return '?';
}
+static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) {
+ uint32_t Flags = I->getFlags();
+ if (Flags & SymbolRef::SF_Executable)
+ return 't';
+ return 'd';
+}
+
static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) {
uint32_t Flags = I->getFlags();
// FIXME: should we print 'b'? At the IR level we cannot be sure if this
@@ -923,6 +934,8 @@ static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) {
Ret = getSymbolNMTypeChar(*COFF, I);
else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
Ret = getSymbolNMTypeChar(*MachO, I);
+ else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj))
+ Ret = getSymbolNMTypeChar(*Wasm, I);
else
Ret = getSymbolNMTypeChar(cast<ELFObjectFileBase>(Obj), I);
@@ -1057,15 +1070,19 @@ static bool checkMachOAndArchFlags(SymbolicFile *O, std::string &Filename) {
MachO::mach_header H;
MachO::mach_header_64 H_64;
Triple T;
+ const char *McpuDefault, *ArchFlag;
if (MachO->is64Bit()) {
H_64 = MachO->MachOObjectFile::getHeader64();
- T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
+ T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
+ &McpuDefault, &ArchFlag);
} else {
H = MachO->MachOObjectFile::getHeader();
- T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
+ T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
+ &McpuDefault, &ArchFlag);
}
+ const std::string ArchFlagName(ArchFlag);
if (none_of(ArchFlags, [&](const std::string &Name) {
- return Name == T.getArchName();
+ return Name == ArchFlagName;
})) {
error("No architecture specified", Filename);
return false;
@@ -1120,6 +1137,11 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
continue;
}
if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
+ if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
+ errs() << ToolName << ": warning sizes with -print-size for Mach-O "
+ "files are always zero.\n";
+ MachOPrintSizeWarning = true;
+ }
if (!checkMachOAndArchFlags(O, Filename))
return;
if (!PrintFileName) {
@@ -1357,6 +1379,11 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
return;
}
if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin)) {
+ if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
+ errs() << ToolName << ": warning sizes with -print-size for Mach-O files "
+ "are always zero.\n";
+ MachOPrintSizeWarning = true;
+ }
if (!checkMachOAndArchFlags(O, Filename))
return;
dumpSymbolNamesFromObject(*O, true);
diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp
index 563084856f6f8..9e02951a4a93f 100644
--- a/tools/llvm-objdump/MachODump.cpp
+++ b/tools/llvm-objdump/MachODump.cpp
@@ -68,9 +68,6 @@ static cl::opt<std::string> DSYMFile("dsym",
static cl::opt<bool> FullLeadingAddr("full-leading-addr",
cl::desc("Print full leading address"));
-static cl::opt<bool> NoLeadingAddr("no-leading-addr",
- cl::desc("Print no leading address"));
-
static cl::opt<bool> NoLeadingHeaders("no-leading-headers",
cl::desc("Print no leading headers"));
@@ -1142,7 +1139,7 @@ static void DumpInfoPlistSectionContents(StringRef Filename,
StringRef BytesStr;
Section.getContents(BytesStr);
const char *sect = reinterpret_cast<const char *>(BytesStr.data());
- outs() << sect;
+ outs() << format("%.*s", BytesStr.size(), sect) << "\n";
return;
}
}
@@ -1566,8 +1563,13 @@ void llvm::ParseInputMachO(StringRef Filename) {
// Attempt to open the binary.
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
- if (!BinaryOrErr)
- report_error(Filename, BinaryOrErr.takeError());
+ if (!BinaryOrErr) {
+ if (auto E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))
+ report_error(Filename, std::move(E));
+ else
+ outs() << Filename << ": is not an object file\n";
+ return;
+ }
Binary &Bin = *BinaryOrErr.get().getBinary();
if (Archive *A = dyn_cast<Archive>(&Bin)) {
@@ -5269,42 +5271,70 @@ static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {
SectionRef CL = get_section(O, "__OBJC2", "__class_list");
if (CL == SectionRef())
CL = get_section(O, "__DATA", "__objc_classlist");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA_CONST", "__objc_classlist");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
info.S = CL;
walk_pointer_list_64("class", CL, O, &info, print_class64_t);
SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
if (CR == SectionRef())
CR = get_section(O, "__DATA", "__objc_classrefs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
info.S = CR;
walk_pointer_list_64("class refs", CR, O, &info, nullptr);
SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
if (SR == SectionRef())
SR = get_section(O, "__DATA", "__objc_superrefs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
info.S = SR;
walk_pointer_list_64("super refs", SR, O, &info, nullptr);
SectionRef CA = get_section(O, "__OBJC2", "__category_list");
if (CA == SectionRef())
CA = get_section(O, "__DATA", "__objc_catlist");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA_CONST", "__objc_catlist");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
info.S = CA;
walk_pointer_list_64("category", CA, O, &info, print_category64_t);
SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
if (PL == SectionRef())
PL = get_section(O, "__DATA", "__objc_protolist");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA_CONST", "__objc_protolist");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
info.S = PL;
walk_pointer_list_64("protocol", PL, O, &info, nullptr);
SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
if (MR == SectionRef())
MR = get_section(O, "__DATA", "__objc_msgrefs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
info.S = MR;
print_message_refs64(MR, &info);
SectionRef II = get_section(O, "__OBJC2", "__image_info");
if (II == SectionRef())
II = get_section(O, "__DATA", "__objc_imageinfo");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
info.S = II;
print_image_info64(II, &info);
}
@@ -5335,75 +5365,75 @@ static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {
info.adrp_addr = 0;
info.adrp_inst = 0;
- const SectionRef CL = get_section(O, "__OBJC2", "__class_list");
- if (CL != SectionRef()) {
- info.S = CL;
- walk_pointer_list_32("class", CL, O, &info, print_class32_t);
- } else {
- const SectionRef CL = get_section(O, "__DATA", "__objc_classlist");
- info.S = CL;
- walk_pointer_list_32("class", CL, O, &info, print_class32_t);
- }
+ SectionRef CL = get_section(O, "__OBJC2", "__class_list");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA", "__objc_classlist");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA_CONST", "__objc_classlist");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
+ info.S = CL;
+ walk_pointer_list_32("class", CL, O, &info, print_class32_t);
- const SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
- if (CR != SectionRef()) {
- info.S = CR;
- walk_pointer_list_32("class refs", CR, O, &info, nullptr);
- } else {
- const SectionRef CR = get_section(O, "__DATA", "__objc_classrefs");
- info.S = CR;
- walk_pointer_list_32("class refs", CR, O, &info, nullptr);
- }
+ SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA", "__objc_classrefs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
+ info.S = CR;
+ walk_pointer_list_32("class refs", CR, O, &info, nullptr);
- const SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
- if (SR != SectionRef()) {
- info.S = SR;
- walk_pointer_list_32("super refs", SR, O, &info, nullptr);
- } else {
- const SectionRef SR = get_section(O, "__DATA", "__objc_superrefs");
- info.S = SR;
- walk_pointer_list_32("super refs", SR, O, &info, nullptr);
- }
+ SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA", "__objc_superrefs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
+ info.S = SR;
+ walk_pointer_list_32("super refs", SR, O, &info, nullptr);
- const SectionRef CA = get_section(O, "__OBJC2", "__category_list");
- if (CA != SectionRef()) {
- info.S = CA;
- walk_pointer_list_32("category", CA, O, &info, print_category32_t);
- } else {
- const SectionRef CA = get_section(O, "__DATA", "__objc_catlist");
- info.S = CA;
- walk_pointer_list_32("category", CA, O, &info, print_category32_t);
- }
+ SectionRef CA = get_section(O, "__OBJC2", "__category_list");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA", "__objc_catlist");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA_CONST", "__objc_catlist");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
+ info.S = CA;
+ walk_pointer_list_32("category", CA, O, &info, print_category32_t);
- const SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
- if (PL != SectionRef()) {
- info.S = PL;
- walk_pointer_list_32("protocol", PL, O, &info, nullptr);
- } else {
- const SectionRef PL = get_section(O, "__DATA", "__objc_protolist");
- info.S = PL;
- walk_pointer_list_32("protocol", PL, O, &info, nullptr);
- }
+ SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA", "__objc_protolist");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA_CONST", "__objc_protolist");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
+ info.S = PL;
+ walk_pointer_list_32("protocol", PL, O, &info, nullptr);
- const SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
- if (MR != SectionRef()) {
- info.S = MR;
- print_message_refs32(MR, &info);
- } else {
- const SectionRef MR = get_section(O, "__DATA", "__objc_msgrefs");
- info.S = MR;
- print_message_refs32(MR, &info);
- }
+ SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA", "__objc_msgrefs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
+ info.S = MR;
+ print_message_refs32(MR, &info);
- const SectionRef II = get_section(O, "__OBJC2", "__image_info");
- if (II != SectionRef()) {
- info.S = II;
- print_image_info32(II, &info);
- } else {
- const SectionRef II = get_section(O, "__DATA", "__objc_imageinfo");
- info.S = II;
- print_image_info32(II, &info);
- }
+ SectionRef II = get_section(O, "__OBJC2", "__image_info");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA", "__objc_imageinfo");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
+ info.S = II;
+ print_image_info32(II, &info);
}
static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {
@@ -6597,6 +6627,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
if (Bytes.size() == 0)
return;
+ // If the section has symbols but no symbol at the start of the section
+ // these are used to make sure the bytes before the first symbol are
+ // disassembled.
+ bool FirstSymbol = true;
+ bool FirstSymbolAtSectionStart = true;
+
// Disassemble symbol by symbol.
for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
Expected<StringRef> SymNameOrErr = Symbols[SymIdx].getName();
@@ -6686,11 +6722,29 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
// (i.e. we're not targeting M-class) and the function is Thumb.
bool UseThumbTarget = IsThumb && ThumbTarget;
- outs() << SymName << ":\n";
+ // If we are not specifying a symbol to start disassembly with and this
+ // is the first symbol in the section but not at the start of the section
+ // then move the disassembly index to the start of the section and
+ // don't print the symbol name just yet. This is so the bytes before the
+ // first symbol are disassembled.
+ uint64_t SymbolStart = Start;
+ if (DisSymName.empty() && FirstSymbol && Start != 0) {
+ FirstSymbolAtSectionStart = false;
+ Start = 0;
+ }
+ else
+ outs() << SymName << ":\n";
+
DILineInfo lastLine;
for (uint64_t Index = Start; Index < End; Index += Size) {
MCInst Inst;
+ // If this is the first symbol in the section and it was not at the
+ // start of the section, see if we are at its Index now and if so print
+ // the symbol name.
+ if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)
+ outs() << SymName << ":\n";
+
uint64_t PC = SectAddress + Index;
if (!NoLeadingAddr) {
if (FullLeadingAddr) {
@@ -6783,6 +6837,9 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
}
}
}
+ // Now that we are done disassembled the first symbol set the bool that
+ // were doing this to false.
+ FirstSymbol = false;
}
if (!symbolTableWorked) {
// Reading the symbol table didn't work, disassemble the whole section.
@@ -6793,8 +6850,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
MCInst Inst;
uint64_t PC = SectAddress + Index;
+ SmallVector<char, 64> AnnotationsBytes;
+ raw_svector_ostream Annotations(AnnotationsBytes);
if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,
- DebugOut, nulls())) {
+ DebugOut, Annotations)) {
if (!NoLeadingAddr) {
if (FullLeadingAddr) {
if (MachOOF->is64Bit())
@@ -6809,7 +6868,8 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
outs() << "\t";
dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs());
}
- IP->printInst(&Inst, outs(), "", *STI);
+ StringRef AnnotationsStr = Annotations.str();
+ IP->printInst(&Inst, outs(), AnnotationsStr, *STI);
outs() << "\n";
} else {
unsigned int Arch = MachOOF->getArch();
@@ -8169,6 +8229,51 @@ static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
outs() << "\n";
}
+static void PrintNoteLoadCommand(MachO::note_command Nt) {
+ outs() << " cmd LC_NOTE\n";
+ outs() << " cmdsize " << Nt.cmdsize;
+ if (Nt.cmdsize != sizeof(struct MachO::note_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ const char *d = Nt.data_owner;
+ outs() << "data_owner " << format("%.16s\n", d);
+ outs() << " offset " << Nt.offset << "\n";
+ outs() << " size " << Nt.size << "\n";
+}
+
+static void PrintBuildToolVersion(MachO::build_tool_version bv) {
+ outs() << " tool " << MachOObjectFile::getBuildTool(bv.tool) << "\n";
+ outs() << " version " << MachOObjectFile::getVersionString(bv.version)
+ << "\n";
+}
+
+static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,
+ MachO::build_version_command bd) {
+ outs() << " cmd LC_BUILD_VERSION\n";
+ outs() << " cmdsize " << bd.cmdsize;
+ if (bd.cmdsize !=
+ sizeof(struct MachO::build_version_command) +
+ bd.ntools * sizeof(struct MachO::build_tool_version))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " platform " << MachOObjectFile::getBuildPlatform(bd.platform)
+ << "\n";
+ if (bd.sdk)
+ outs() << " sdk " << MachOObjectFile::getVersionString(bd.sdk)
+ << "\n";
+ else
+ outs() << " sdk n/a\n";
+ outs() << " minos " << MachOObjectFile::getVersionString(bd.minos)
+ << "\n";
+ outs() << " ntools " << bd.ntools << "\n";
+ for (unsigned i = 0; i < bd.ntools; ++i) {
+ MachO::build_tool_version bv = obj->getBuildToolVersion(i);
+ PrintBuildToolVersion(bv);
+ }
+}
+
static void PrintSourceVersionCommand(MachO::source_version_command sd) {
outs() << " cmd LC_SOURCE_VERSION\n";
outs() << " cmdsize " << sd.cmdsize;
@@ -8374,6 +8479,25 @@ static void PrintRoutinesCommand64(MachO::routines_command_64 r) {
outs() << " reserved6 " << r.reserved6 << "\n";
}
+static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) {
+ outs() << "\t eax " << format("0x%08" PRIx32, cpu32.eax);
+ outs() << " ebx " << format("0x%08" PRIx32, cpu32.ebx);
+ outs() << " ecx " << format("0x%08" PRIx32, cpu32.ecx);
+ outs() << " edx " << format("0x%08" PRIx32, cpu32.edx) << "\n";
+ outs() << "\t edi " << format("0x%08" PRIx32, cpu32.edi);
+ outs() << " esi " << format("0x%08" PRIx32, cpu32.esi);
+ outs() << " ebp " << format("0x%08" PRIx32, cpu32.ebp);
+ outs() << " esp " << format("0x%08" PRIx32, cpu32.esp) << "\n";
+ outs() << "\t ss " << format("0x%08" PRIx32, cpu32.ss);
+ outs() << " eflags " << format("0x%08" PRIx32, cpu32.eflags);
+ outs() << " eip " << format("0x%08" PRIx32, cpu32.eip);
+ outs() << " cs " << format("0x%08" PRIx32, cpu32.cs) << "\n";
+ outs() << "\t ds " << format("0x%08" PRIx32, cpu32.ds);
+ outs() << " es " << format("0x%08" PRIx32, cpu32.es);
+ outs() << " fs " << format("0x%08" PRIx32, cpu32.fs);
+ outs() << " gs " << format("0x%08" PRIx32, cpu32.gs) << "\n";
+}
+
static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {
outs() << " rax " << format("0x%016" PRIx64, cpu64.rax);
outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx);
@@ -8611,7 +8735,85 @@ static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,
const char *begin = Ptr + sizeof(struct MachO::thread_command);
const char *end = Ptr + t.cmdsize;
uint32_t flavor, count, left;
- if (cputype == MachO::CPU_TYPE_X86_64) {
+ if (cputype == MachO::CPU_TYPE_I386) {
+ while (begin < end) {
+ if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
+ memcpy((char *)&flavor, begin, sizeof(uint32_t));
+ begin += sizeof(uint32_t);
+ } else {
+ flavor = 0;
+ begin = end;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ sys::swapByteOrder(flavor);
+ if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
+ memcpy((char *)&count, begin, sizeof(uint32_t));
+ begin += sizeof(uint32_t);
+ } else {
+ count = 0;
+ begin = end;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ sys::swapByteOrder(count);
+ if (flavor == MachO::x86_THREAD_STATE32) {
+ outs() << " flavor i386_THREAD_STATE\n";
+ if (count == MachO::x86_THREAD_STATE32_COUNT)
+ outs() << " count i386_THREAD_STATE_COUNT\n";
+ else
+ outs() << " count " << count
+ << " (not x86_THREAD_STATE32_COUNT)\n";
+ MachO::x86_thread_state32_t cpu32;
+ left = end - begin;
+ if (left >= sizeof(MachO::x86_thread_state32_t)) {
+ memcpy(&cpu32, begin, sizeof(MachO::x86_thread_state32_t));
+ begin += sizeof(MachO::x86_thread_state32_t);
+ } else {
+ memset(&cpu32, '\0', sizeof(MachO::x86_thread_state32_t));
+ memcpy(&cpu32, begin, left);
+ begin += left;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ swapStruct(cpu32);
+ Print_x86_thread_state32_t(cpu32);
+ } else if (flavor == MachO::x86_THREAD_STATE) {
+ outs() << " flavor x86_THREAD_STATE\n";
+ if (count == MachO::x86_THREAD_STATE_COUNT)
+ outs() << " count x86_THREAD_STATE_COUNT\n";
+ else
+ outs() << " count " << count
+ << " (not x86_THREAD_STATE_COUNT)\n";
+ struct MachO::x86_thread_state_t ts;
+ left = end - begin;
+ if (left >= sizeof(MachO::x86_thread_state_t)) {
+ memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
+ begin += sizeof(MachO::x86_thread_state_t);
+ } else {
+ memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
+ memcpy(&ts, begin, left);
+ begin += left;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ swapStruct(ts);
+ if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) {
+ outs() << "\t tsh.flavor x86_THREAD_STATE32 ";
+ if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT)
+ outs() << "tsh.count x86_THREAD_STATE32_COUNT\n";
+ else
+ outs() << "tsh.count " << ts.tsh.count
+ << " (not x86_THREAD_STATE32_COUNT\n";
+ Print_x86_thread_state32_t(ts.uts.ts32);
+ } else {
+ outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
+ << ts.tsh.count << "\n";
+ }
+ } else {
+ outs() << " flavor " << flavor << " (unknown)\n";
+ outs() << " count " << count << "\n";
+ outs() << " state (unknown)\n";
+ begin += count * sizeof(uint32_t);
+ }
+ }
+ } else if (cputype == MachO::CPU_TYPE_X86_64) {
while (begin < end) {
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
memcpy((char *)&flavor, begin, sizeof(uint32_t));
@@ -9014,6 +9216,13 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,
Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);
PrintVersionMinLoadCommand(Vd);
+ } else if (Command.C.cmd == MachO::LC_NOTE) {
+ MachO::note_command Nt = Obj->getNoteLoadCommand(Command);
+ PrintNoteLoadCommand(Nt);
+ } else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {
+ MachO::build_version_command Bv =
+ Obj->getBuildVersionLoadCommand(Command);
+ PrintBuildVersionLoadCommand(Obj, Bv);
} else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);
PrintSourceVersionCommand(Sd);
@@ -9182,117 +9391,21 @@ void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
// rebase table dumping
//===----------------------------------------------------------------------===//
-namespace {
-class SegInfo {
-public:
- SegInfo(const object::MachOObjectFile *Obj);
-
- StringRef segmentName(uint32_t SegIndex);
- StringRef sectionName(uint32_t SegIndex, uint64_t SegOffset);
- uint64_t address(uint32_t SegIndex, uint64_t SegOffset);
- bool isValidSegIndexAndOffset(uint32_t SegIndex, uint64_t SegOffset);
-
-private:
- struct SectionInfo {
- uint64_t Address;
- uint64_t Size;
- StringRef SectionName;
- StringRef SegmentName;
- uint64_t OffsetInSegment;
- uint64_t SegmentStartAddress;
- uint32_t SegmentIndex;
- };
- const SectionInfo &findSection(uint32_t SegIndex, uint64_t SegOffset);
- SmallVector<SectionInfo, 32> Sections;
-};
-}
-
-SegInfo::SegInfo(const object::MachOObjectFile *Obj) {
- // Build table of sections so segIndex/offset pairs can be translated.
- uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0;
- StringRef CurSegName;
- uint64_t CurSegAddress;
- for (const SectionRef &Section : Obj->sections()) {
- SectionInfo Info;
- error(Section.getName(Info.SectionName));
- Info.Address = Section.getAddress();
- Info.Size = Section.getSize();
- Info.SegmentName =
- Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl());
- if (!Info.SegmentName.equals(CurSegName)) {
- ++CurSegIndex;
- CurSegName = Info.SegmentName;
- CurSegAddress = Info.Address;
- }
- Info.SegmentIndex = CurSegIndex - 1;
- Info.OffsetInSegment = Info.Address - CurSegAddress;
- Info.SegmentStartAddress = CurSegAddress;
- Sections.push_back(Info);
- }
-}
-
-StringRef SegInfo::segmentName(uint32_t SegIndex) {
- for (const SectionInfo &SI : Sections) {
- if (SI.SegmentIndex == SegIndex)
- return SI.SegmentName;
- }
- llvm_unreachable("invalid segIndex");
-}
-
-bool SegInfo::isValidSegIndexAndOffset(uint32_t SegIndex,
- uint64_t OffsetInSeg) {
- for (const SectionInfo &SI : Sections) {
- if (SI.SegmentIndex != SegIndex)
- continue;
- if (SI.OffsetInSegment > OffsetInSeg)
- continue;
- if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size))
- continue;
- return true;
- }
- return false;
-}
-
-const SegInfo::SectionInfo &SegInfo::findSection(uint32_t SegIndex,
- uint64_t OffsetInSeg) {
- for (const SectionInfo &SI : Sections) {
- if (SI.SegmentIndex != SegIndex)
- continue;
- if (SI.OffsetInSegment > OffsetInSeg)
- continue;
- if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size))
- continue;
- return SI;
- }
- llvm_unreachable("segIndex and offset not in any section");
-}
-
-StringRef SegInfo::sectionName(uint32_t SegIndex, uint64_t OffsetInSeg) {
- return findSection(SegIndex, OffsetInSeg).SectionName;
-}
-
-uint64_t SegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) {
- const SectionInfo &SI = findSection(SegIndex, OffsetInSeg);
- return SI.SegmentStartAddress + OffsetInSeg;
-}
-
-void llvm::printMachORebaseTable(const object::MachOObjectFile *Obj) {
- // Build table of sections so names can used in final output.
- SegInfo sectionTable(Obj);
-
+void llvm::printMachORebaseTable(object::MachOObjectFile *Obj) {
outs() << "segment section address type\n";
- for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable()) {
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- StringRef SegmentName = sectionTable.segmentName(SegIndex);
- StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ Error Err = Error::success();
+ for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {
+ StringRef SegmentName = Entry.segmentName();
+ StringRef SectionName = Entry.sectionName();
+ uint64_t Address = Entry.address();
// Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer
outs() << format("%-8s %-18s 0x%08" PRIX64 " %s\n",
SegmentName.str().c_str(), SectionName.str().c_str(),
Address, Entry.typeName().str().c_str());
}
+ if (Err)
+ report_error(Obj->getFileName(), std::move(Err));
}
static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
@@ -9320,18 +9433,15 @@ static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
// bind table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOBindTable(const object::MachOObjectFile *Obj) {
+void llvm::printMachOBindTable(object::MachOObjectFile *Obj) {
// Build table of sections so names can used in final output.
- SegInfo sectionTable(Obj);
-
outs() << "segment section address type "
"addend dylib symbol\n";
- for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable()) {
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- StringRef SegmentName = sectionTable.segmentName(SegIndex);
- StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ Error Err = Error::success();
+ for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable(Err)) {
+ StringRef SegmentName = Entry.segmentName();
+ StringRef SectionName = Entry.sectionName();
+ uint64_t Address = Entry.address();
// Table lines look like:
// __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard
@@ -9346,24 +9456,22 @@ void llvm::printMachOBindTable(const object::MachOObjectFile *Obj) {
<< left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
<< Entry.symbolName() << Attr << "\n";
}
+ if (Err)
+ report_error(Obj->getFileName(), std::move(Err));
}
//===----------------------------------------------------------------------===//
// lazy bind table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOLazyBindTable(const object::MachOObjectFile *Obj) {
- // Build table of sections so names can used in final output.
- SegInfo sectionTable(Obj);
-
+void llvm::printMachOLazyBindTable(object::MachOObjectFile *Obj) {
outs() << "segment section address "
"dylib symbol\n";
- for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable()) {
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- StringRef SegmentName = sectionTable.segmentName(SegIndex);
- StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ Error Err = Error::success();
+ for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {
+ StringRef SegmentName = Entry.segmentName();
+ StringRef SectionName = Entry.sectionName();
+ uint64_t Address = Entry.address();
// Table lines look like:
// __DATA __got 0x00012010 libSystem ___stack_chk_guard
@@ -9373,30 +9481,28 @@ void llvm::printMachOLazyBindTable(const object::MachOObjectFile *Obj) {
<< left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
<< Entry.symbolName() << "\n";
}
+ if (Err)
+ report_error(Obj->getFileName(), std::move(Err));
}
//===----------------------------------------------------------------------===//
// weak bind table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) {
- // Build table of sections so names can used in final output.
- SegInfo sectionTable(Obj);
-
+void llvm::printMachOWeakBindTable(object::MachOObjectFile *Obj) {
outs() << "segment section address "
"type addend symbol\n";
- for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable()) {
+ Error Err = Error::success();
+ for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {
// Strong symbols don't have a location to update.
if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
outs() << " strong "
<< Entry.symbolName() << "\n";
continue;
}
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- StringRef SegmentName = sectionTable.segmentName(SegIndex);
- StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ StringRef SegmentName = Entry.segmentName();
+ StringRef SectionName = Entry.sectionName();
+ uint64_t Address = Entry.address();
// Table lines look like:
// __DATA __data 0x00001000 pointer 0 _foo
@@ -9407,6 +9513,8 @@ void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) {
<< format_decimal(Entry.addend(), 8) << " " << Entry.symbolName()
<< "\n";
}
+ if (Err)
+ report_error(Obj->getFileName(), std::move(Err));
}
// get_dyld_bind_info_symbolname() is used for disassembly and passed an
@@ -9417,17 +9525,15 @@ static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
struct DisassembleInfo *info) {
if (info->bindtable == nullptr) {
info->bindtable = llvm::make_unique<SymbolAddressMap>();
- SegInfo sectionTable(info->O);
- for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable()) {
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- if (!sectionTable.isValidSegIndexAndOffset(SegIndex, OffsetInSeg))
- continue;
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ Error Err = Error::success();
+ for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable(Err)) {
+ uint64_t Address = Entry.address();
StringRef name = Entry.symbolName();
if (!name.empty())
(*info->bindtable)[Address] = name;
}
+ if (Err)
+ report_error(info->O->getFileName(), std::move(Err));
}
auto name = info->bindtable->lookup(ReferenceValue);
return !name.empty() ? name.data() : nullptr;
diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp
index 8373f0ce3f1ef..613d0643b4335 100644
--- a/tools/llvm-objdump/llvm-objdump.cpp
+++ b/tools/llvm-objdump/llvm-objdump.cpp
@@ -158,6 +158,8 @@ cl::opt<bool>
llvm::NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling "
"instructions, do not print "
"the instruction bytes."));
+cl::opt<bool>
+llvm::NoLeadingAddr("no-leading-addr", cl::desc("Print no leading address"));
cl::opt<bool>
llvm::UnwindInfo("unwind-info", cl::desc("Display unwind information"));
@@ -213,6 +215,8 @@ cl::opt<unsigned long long>
cl::value_desc("address"), cl::init(UINT64_MAX));
static StringRef ToolName;
+typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy;
+
namespace {
typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate;
@@ -357,7 +361,16 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) {
llvm::Triple TheTriple("unknown-unknown-unknown");
if (TripleName.empty()) {
if (Obj) {
- TheTriple.setArch(Triple::ArchType(Obj->getArch()));
+ auto Arch = Obj->getArch();
+ TheTriple.setArch(Triple::ArchType(Arch));
+
+ // For ARM targets, try to use the build attributes to build determine
+ // the build target. Target features are also added, but later during
+ // disassembly.
+ if (Arch == Triple::arm || Arch == Triple::armeb) {
+ Obj->setARMSubArch(TheTriple);
+ }
+
// TheTriple defaults to ELF, and COFF doesn't have an environment:
// the best we can do here is indicate that it is mach-o.
if (Obj->isMachO())
@@ -369,8 +382,16 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) {
TheTriple.setTriple("thumbv7-windows");
}
}
- } else
+ } else {
TheTriple.setTriple(Triple::normalize(TripleName));
+ // Use the triple, but also try to combine with ARM build attributes.
+ if (Obj) {
+ auto Arch = Obj->getArch();
+ if (Arch == Triple::arm || Arch == Triple::armeb) {
+ Obj->setARMSubArch(TheTriple);
+ }
+ }
+ }
// Get the target specific parser.
std::string Error;
@@ -491,7 +512,8 @@ public:
MCSubtargetInfo const &STI, SourcePrinter *SP) {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
- OS << format("%8" PRIx64 ":", Address);
+ if (!NoLeadingAddr)
+ OS << format("%8" PRIx64 ":", Address);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes, OS);
@@ -509,7 +531,8 @@ public:
raw_ostream &OS) {
uint32_t opcode =
(Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0];
- OS << format("%8" PRIx64 ":", Address);
+ if (!NoLeadingAddr)
+ OS << format("%8" PRIx64 ":", Address);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes.slice(0, 4), OS);
@@ -570,6 +593,9 @@ public:
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
uint64_t Address, raw_ostream &OS, StringRef Annot,
MCSubtargetInfo const &STI, SourcePrinter *SP) override {
+ if (SP && (PrintSource || PrintLines))
+ SP->printSourceLine(OS, Address);
+
if (!MI) {
OS << " <unknown>";
return;
@@ -601,7 +627,8 @@ public:
MCSubtargetInfo const &STI, SourcePrinter *SP) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
- OS << format("%8" PRId64 ":", Address / 8);
+ if (!NoLeadingAddr)
+ OS << format("%8" PRId64 ":", Address / 8);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes, OS);
@@ -1091,6 +1118,52 @@ static uint8_t getElfSymbolType(const ObjectFile *Obj, const SymbolRef &Sym) {
llvm_unreachable("Unsupported binary format");
}
+template <class ELFT> static void
+addDynamicElfSymbols(const ELFObjectFile<ELFT> *Obj,
+ std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
+ for (auto Symbol : Obj->getDynamicSymbolIterators()) {
+ uint8_t SymbolType = Symbol.getELFType();
+ if (SymbolType != ELF::STT_FUNC || Symbol.getSize() == 0)
+ continue;
+
+ Expected<uint64_t> AddressOrErr = Symbol.getAddress();
+ if (!AddressOrErr)
+ report_error(Obj->getFileName(), AddressOrErr.takeError());
+ uint64_t Address = *AddressOrErr;
+
+ Expected<StringRef> Name = Symbol.getName();
+ if (!Name)
+ report_error(Obj->getFileName(), Name.takeError());
+ if (Name->empty())
+ continue;
+
+ Expected<section_iterator> SectionOrErr = Symbol.getSection();
+ if (!SectionOrErr)
+ report_error(Obj->getFileName(), SectionOrErr.takeError());
+ section_iterator SecI = *SectionOrErr;
+ if (SecI == Obj->section_end())
+ continue;
+
+ AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType);
+ }
+}
+
+static void
+addDynamicElfSymbols(const ObjectFile *Obj,
+ std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
+ assert(Obj->isELF());
+ if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj))
+ addDynamicElfSymbols(Elf32LEObj, AllSymbols);
+ else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
+ addDynamicElfSymbols(Elf64LEObj, AllSymbols);
+ else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
+ addDynamicElfSymbols(Elf32BEObj, AllSymbols);
+ else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj))
+ addDynamicElfSymbols(Elf64BEObj, AllSymbols);
+ else
+ llvm_unreachable("Unsupported binary format");
+}
+
static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
if (StartAddress > StopAddress)
error("Start address should be less than stop address");
@@ -1165,7 +1238,6 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
// Create a mapping from virtual address to symbol name. This is used to
// pretty print the symbols while disassembling.
- typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy;
std::map<SectionRef, SectionSymbolsTy> AllSymbols;
for (const SymbolRef &Symbol : Obj->symbols()) {
Expected<uint64_t> AddressOrErr = Symbol.getAddress();
@@ -1193,6 +1265,8 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType);
}
+ if (AllSymbols.empty() && Obj->isELF())
+ addDynamicElfSymbols(Obj, AllSymbols);
// Create a mapping from virtual address to section.
std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses;
@@ -1811,9 +1885,9 @@ void llvm::printExportsTrie(const ObjectFile *o) {
}
}
-void llvm::printRebaseTable(const ObjectFile *o) {
+void llvm::printRebaseTable(ObjectFile *o) {
outs() << "Rebase table:\n";
- if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachORebaseTable(MachO);
else {
errs() << "This operation is only currently supported "
@@ -1822,9 +1896,9 @@ void llvm::printRebaseTable(const ObjectFile *o) {
}
}
-void llvm::printBindTable(const ObjectFile *o) {
+void llvm::printBindTable(ObjectFile *o) {
outs() << "Bind table:\n";
- if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOBindTable(MachO);
else {
errs() << "This operation is only currently supported "
@@ -1833,9 +1907,9 @@ void llvm::printBindTable(const ObjectFile *o) {
}
}
-void llvm::printLazyBindTable(const ObjectFile *o) {
+void llvm::printLazyBindTable(ObjectFile *o) {
outs() << "Lazy bind table:\n";
- if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOLazyBindTable(MachO);
else {
errs() << "This operation is only currently supported "
@@ -1844,9 +1918,9 @@ void llvm::printLazyBindTable(const ObjectFile *o) {
}
}
-void llvm::printWeakBindTable(const ObjectFile *o) {
+void llvm::printWeakBindTable(ObjectFile *o) {
outs() << "Weak bind table:\n";
- if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOWeakBindTable(MachO);
else {
errs() << "This operation is only currently supported "
@@ -1944,7 +2018,7 @@ static void printPrivateFileHeaders(const ObjectFile *o, bool onlyFirst) {
report_error(o->getFileName(), "Invalid/Unsupported object file format");
}
-static void DumpObject(const ObjectFile *o, const Archive *a = nullptr) {
+static void DumpObject(ObjectFile *o, const Archive *a = nullptr) {
StringRef ArchiveName = a != nullptr ? a->getFileName() : "";
// Avoid other output when using a raw option.
if (!RawClangAST) {
diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h
index dace82af3d07d..2fcd506884b18 100644
--- a/tools/llvm-objdump/llvm-objdump.h
+++ b/tools/llvm-objdump/llvm-objdump.h
@@ -35,6 +35,7 @@ extern cl::list<std::string> FilterSections;
extern cl::opt<bool> Disassemble;
extern cl::opt<bool> DisassembleAll;
extern cl::opt<bool> NoShowRawInsn;
+extern cl::opt<bool> NoLeadingAddr;
extern cl::opt<bool> PrivateHeaders;
extern cl::opt<bool> FirstPrivateHeader;
extern cl::opt<bool> ExportsTrie;
@@ -69,10 +70,10 @@ void ParseInputMachO(StringRef Filename);
void printCOFFUnwindInfo(const object::COFFObjectFile* o);
void printMachOUnwindInfo(const object::MachOObjectFile* o);
void printMachOExportsTrie(const object::MachOObjectFile* o);
-void printMachORebaseTable(const object::MachOObjectFile* o);
-void printMachOBindTable(const object::MachOObjectFile* o);
-void printMachOLazyBindTable(const object::MachOObjectFile* o);
-void printMachOWeakBindTable(const object::MachOObjectFile* o);
+void printMachORebaseTable(object::MachOObjectFile* o);
+void printMachOBindTable(object::MachOObjectFile* o);
+void printMachOLazyBindTable(object::MachOObjectFile* o);
+void printMachOWeakBindTable(object::MachOObjectFile* o);
void printELFFileHeader(const object::ObjectFile *o);
void printCOFFFileHeader(const object::ObjectFile *o);
void printCOFFSymbolTable(const object::COFFImportFile *i);
@@ -81,10 +82,10 @@ void printMachOFileHeader(const object::ObjectFile *o);
void printMachOLoadCommands(const object::ObjectFile *o);
void printWasmFileHeader(const object::ObjectFile *o);
void printExportsTrie(const object::ObjectFile *o);
-void printRebaseTable(const object::ObjectFile *o);
-void printBindTable(const object::ObjectFile *o);
-void printLazyBindTable(const object::ObjectFile *o);
-void printWeakBindTable(const object::ObjectFile *o);
+void printRebaseTable(object::ObjectFile *o);
+void printBindTable(object::ObjectFile *o);
+void printLazyBindTable(object::ObjectFile *o);
+void printWeakBindTable(object::ObjectFile *o);
void printRawClangAST(const object::ObjectFile *o);
void PrintRelocations(const object::ObjectFile *o);
void PrintSectionHeaders(const object::ObjectFile *o);
diff --git a/tools/llvm-pdbdump/Analyze.cpp b/tools/llvm-pdbdump/Analyze.cpp
new file mode 100644
index 0000000000000..b65dd40d25ff1
--- /dev/null
+++ b/tools/llvm-pdbdump/Analyze.cpp
@@ -0,0 +1,164 @@
+//===- Analyze.cpp - PDB analysis functions ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Analyze.h"
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <list>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static StringRef getLeafTypeName(TypeLeafKind LT) {
+ switch (LT) {
+#define TYPE_RECORD(ename, value, name) \
+ case ename: \
+ return #name;
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+ default:
+ break;
+ }
+ return "UnknownLeaf";
+}
+
+namespace {
+struct HashLookupVisitor : public TypeVisitorCallbacks {
+ struct Entry {
+ TypeIndex TI;
+ CVType Record;
+ };
+
+ explicit HashLookupVisitor(TpiStream &Tpi) : Tpi(Tpi) {}
+
+ Error visitTypeBegin(CVType &Record) override {
+ uint32_t H = Tpi.getHashValues()[I];
+ Record.Hash = H;
+ TypeIndex TI(I + TypeIndex::FirstNonSimpleIndex);
+ Lookup[H].push_back(Entry{TI, Record});
+ ++I;
+ return Error::success();
+ }
+
+ uint32_t I = 0;
+ DenseMap<uint32_t, std::list<Entry>> Lookup;
+ TpiStream &Tpi;
+};
+}
+
+AnalysisStyle::AnalysisStyle(PDBFile &File) : File(File) {}
+
+Error AnalysisStyle::dump() {
+ auto Tpi = File.getPDBTpiStream();
+ if (!Tpi)
+ return Tpi.takeError();
+
+ TypeDatabase TypeDB;
+ TypeDatabaseVisitor DBV(TypeDB);
+ TypeDeserializer Deserializer;
+ TypeVisitorCallbackPipeline Pipeline;
+ HashLookupVisitor Hasher(*Tpi);
+ // Deserialize the types
+ Pipeline.addCallbackToPipeline(Deserializer);
+ // Add them to the database
+ Pipeline.addCallbackToPipeline(DBV);
+ // Store their hash values
+ Pipeline.addCallbackToPipeline(Hasher);
+
+ CVTypeVisitor Visitor(Pipeline);
+
+ bool Error = false;
+ for (auto Item : Tpi->types(&Error)) {
+ if (auto EC = Visitor.visitTypeRecord(Item))
+ return EC;
+ }
+ if (Error)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI stream contained corrupt record");
+
+ auto &Adjusters = Tpi->getHashAdjusters();
+ DenseSet<uint32_t> AdjusterSet;
+ for (const auto &Adj : Adjusters) {
+ assert(AdjusterSet.find(Adj.second) == AdjusterSet.end());
+ AdjusterSet.insert(Adj.second);
+ }
+
+ uint32_t Count = 0;
+ outs() << "Searching for hash collisions\n";
+ for (const auto &H : Hasher.Lookup) {
+ if (H.second.size() <= 1)
+ continue;
+ ++Count;
+ outs() << formatv("Hash: {0}, Count: {1} records\n", H.first,
+ H.second.size());
+ for (const auto &R : H.second) {
+ auto Iter = AdjusterSet.find(R.TI.getIndex());
+ StringRef Prefix;
+ if (Iter != AdjusterSet.end()) {
+ Prefix = "[HEAD]";
+ AdjusterSet.erase(Iter);
+ }
+ StringRef LeafName = getLeafTypeName(R.Record.Type);
+ uint32_t TI = R.TI.getIndex();
+ StringRef TypeName = TypeDB.getTypeName(R.TI);
+ outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI,
+ TypeName);
+ }
+ }
+
+ outs() << "\n";
+ outs() << "Dumping hash adjustment chains\n";
+ for (const auto &A : Tpi->getHashAdjusters()) {
+ TypeIndex TI(A.second);
+ StringRef TypeName = TypeDB.getTypeName(TI);
+ const CVType &HeadRecord = TypeDB.getTypeRecord(TI);
+ assert(HeadRecord.Hash.hasValue());
+
+ auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash);
+ if (CollisionsIter == Hasher.Lookup.end())
+ continue;
+
+ const auto &Collisions = CollisionsIter->second;
+ outs() << TypeName << "\n";
+ outs() << formatv(" [HEAD] {0:x} {1} {2}\n", A.second,
+ getLeafTypeName(HeadRecord.Type), TypeName);
+ for (const auto &Chain : Collisions) {
+ if (Chain.TI == TI)
+ continue;
+ const CVType &TailRecord = TypeDB.getTypeRecord(Chain.TI);
+ outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(),
+ getLeafTypeName(TailRecord.Type),
+ TypeDB.getTypeName(Chain.TI));
+ }
+ }
+ outs() << formatv("There are {0} orphaned hash adjusters\n",
+ AdjusterSet.size());
+ for (const auto &Adj : AdjusterSet) {
+ outs() << formatv(" {0}\n", Adj);
+ }
+
+ uint32_t DistinctHashValues = Hasher.Lookup.size();
+ outs() << formatv("{0}/{1} hash collisions", Count, DistinctHashValues);
+ return Error::success();
+}
diff --git a/tools/llvm-pdbdump/Analyze.h b/tools/llvm-pdbdump/Analyze.h
new file mode 100644
index 0000000000000..7230ae45b0c8c
--- /dev/null
+++ b/tools/llvm-pdbdump/Analyze.h
@@ -0,0 +1,30 @@
+//===- Analyze.h - PDB analysis functions -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_ANALYSIS_H
+#define LLVM_TOOLS_LLVMPDBDUMP_ANALYSIS_H
+
+#include "OutputStyle.h"
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+class AnalysisStyle : public OutputStyle {
+public:
+ explicit AnalysisStyle(PDBFile &File);
+
+ Error dump() override;
+
+private:
+ PDBFile &File;
+};
+}
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/CMakeLists.txt b/tools/llvm-pdbdump/CMakeLists.txt
index 7c46171941f7d..37c76ab697b46 100644
--- a/tools/llvm-pdbdump/CMakeLists.txt
+++ b/tools/llvm-pdbdump/CMakeLists.txt
@@ -7,6 +7,9 @@ set(LLVM_LINK_COMPONENTS
)
add_llvm_tool(llvm-pdbdump
+ Analyze.cpp
+ Diff.cpp
+ CompactTypeDumpVisitor.cpp
llvm-pdbdump.cpp
YamlSymbolDumper.cpp
YamlTypeDumper.cpp
@@ -15,6 +18,8 @@ add_llvm_tool(llvm-pdbdump
PdbYaml.cpp
PrettyBuiltinDumper.cpp
PrettyClassDefinitionDumper.cpp
+ PrettyClassLayoutTextDumper.cpp
+ PrettyClassLayoutGraphicalDumper.cpp
PrettyCompilandDumper.cpp
PrettyEnumDumper.cpp
PrettyExternalSymbolDumper.cpp
@@ -22,6 +27,7 @@ add_llvm_tool(llvm-pdbdump
PrettyTypeDumper.cpp
PrettyTypedefDumper.cpp
PrettyVariableDumper.cpp
+ StreamUtil.cpp
YAMLOutputStyle.cpp
)
diff --git a/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp b/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp
new file mode 100644
index 0000000000000..1fc8dd5d51f0a
--- /dev/null
+++ b/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp
@@ -0,0 +1,57 @@
+//===-- CompactTypeDumpVisitor.cpp - CodeView type info dumper --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CompactTypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
+#define CV_TYPE(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+};
+
+static StringRef getLeafName(TypeLeafKind K) {
+ for (const auto &E : LeafTypeNames) {
+ if (E.Value == K)
+ return E.Name;
+ }
+ return StringRef();
+}
+
+CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB,
+ ScopedPrinter *W)
+ : W(W), TI(TypeIndex::None()), Offset(0), TypeDB(TypeDB) {}
+
+Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) {
+ if (TI == TypeIndex::None())
+ TI.setIndex(TypeIndex::FirstNonSimpleIndex);
+ else
+ TI.setIndex(TI.getIndex() + 1);
+
+ return Error::success();
+}
+
+Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) {
+ uint32_t I = TI.getIndex();
+ StringRef Leaf = getLeafName(Record.Type);
+ StringRef Name = TypeDB.getTypeName(TI);
+ W->printString(
+ llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I,
+ Record.length(), Offset, Leaf, Name)
+ .str());
+
+ Offset += Record.length();
+
+ return Error::success();
+}
diff --git a/tools/llvm-pdbdump/CompactTypeDumpVisitor.h b/tools/llvm-pdbdump/CompactTypeDumpVisitor.h
new file mode 100644
index 0000000000000..180eea7b8d6a1
--- /dev/null
+++ b/tools/llvm-pdbdump/CompactTypeDumpVisitor.h
@@ -0,0 +1,47 @@
+//===-- CompactTypeDumpVisitor.h - CodeView type info dumper ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H
+#define LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H
+
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+
+namespace llvm {
+class ScopedPrinter;
+namespace codeview {
+class TypeDatabase;
+}
+
+namespace pdb {
+
+/// Dumper for CodeView type streams found in COFF object files and PDB files.
+/// Dumps records on a single line, and ignores member records.
+class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
+public:
+ CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, ScopedPrinter *W);
+
+ /// Paired begin/end actions for all types. Receives all record data,
+ /// including the fixed-length record prefix.
+ Error visitTypeBegin(codeview::CVType &Record) override;
+ Error visitTypeEnd(codeview::CVType &Record) override;
+
+private:
+ ScopedPrinter *W;
+
+ codeview::TypeIndex TI;
+ uint32_t Offset;
+ codeview::TypeDatabase &TypeDB;
+};
+
+} // end namespace pdb
+} // end namespace llvm
+
+#endif
diff --git a/tools/llvm-pdbdump/Diff.cpp b/tools/llvm-pdbdump/Diff.cpp
new file mode 100644
index 0000000000000..8c02d36044d82
--- /dev/null
+++ b/tools/llvm-pdbdump/Diff.cpp
@@ -0,0 +1,523 @@
+//===- Diff.cpp - PDB diff utility ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Diff.h"
+
+#include "StreamUtil.h"
+#include "llvm-pdbdump.h"
+
+#include "llvm/DebugInfo/PDB/Native/Formatters.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/StringTable.h"
+
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace llvm {
+template <> struct format_provider<PdbRaw_FeatureSig> {
+ static void format(const PdbRaw_FeatureSig &Sig, raw_ostream &Stream,
+ StringRef Style) {
+ switch (Sig) {
+ case PdbRaw_FeatureSig::MinimalDebugInfo:
+ Stream << "MinimalDebugInfo";
+ break;
+ case PdbRaw_FeatureSig::NoTypeMerge:
+ Stream << "NoTypeMerge";
+ break;
+ case PdbRaw_FeatureSig::VC110:
+ Stream << "VC110";
+ break;
+ case PdbRaw_FeatureSig::VC140:
+ Stream << "VC140";
+ break;
+ }
+ }
+};
+}
+
+template <typename R> using ValueOfRange = llvm::detail::ValueOfRange<R>;
+
+template <typename Range, typename Comp>
+static void set_differences(Range &&R1, Range &&R2,
+ SmallVectorImpl<ValueOfRange<Range>> *OnlyLeft,
+ SmallVectorImpl<ValueOfRange<Range>> *OnlyRight,
+ SmallVectorImpl<ValueOfRange<Range>> *Intersection,
+ Comp Comparator) {
+
+ std::sort(R1.begin(), R1.end(), Comparator);
+ std::sort(R2.begin(), R2.end(), Comparator);
+
+ if (OnlyLeft) {
+ OnlyLeft->reserve(R1.size());
+ auto End = std::set_difference(R1.begin(), R1.end(), R2.begin(), R2.end(),
+ OnlyLeft->begin(), Comparator);
+ OnlyLeft->set_size(std::distance(OnlyLeft->begin(), End));
+ }
+ if (OnlyRight) {
+ OnlyLeft->reserve(R2.size());
+ auto End = std::set_difference(R2.begin(), R2.end(), R1.begin(), R1.end(),
+ OnlyRight->begin(), Comparator);
+ OnlyRight->set_size(std::distance(OnlyRight->begin(), End));
+ }
+ if (Intersection) {
+ Intersection->reserve(std::min(R1.size(), R2.size()));
+ auto End = std::set_intersection(R1.begin(), R1.end(), R2.begin(), R2.end(),
+ Intersection->begin(), Comparator);
+ Intersection->set_size(std::distance(Intersection->begin(), End));
+ }
+}
+
+template <typename Range>
+static void
+set_differences(Range &&R1, Range &&R2,
+ SmallVectorImpl<ValueOfRange<Range>> *OnlyLeft,
+ SmallVectorImpl<ValueOfRange<Range>> *OnlyRight,
+ SmallVectorImpl<ValueOfRange<Range>> *Intersection = nullptr) {
+ std::less<ValueOfRange<Range>> Comp;
+ set_differences(std::forward<Range>(R1), std::forward<Range>(R2), OnlyLeft,
+ OnlyRight, Intersection, Comp);
+}
+
+DiffStyle::DiffStyle(PDBFile &File1, PDBFile &File2)
+ : File1(File1), File2(File2) {}
+
+Error DiffStyle::dump() {
+ if (auto EC = diffSuperBlock())
+ return EC;
+
+ if (auto EC = diffFreePageMap())
+ return EC;
+
+ if (auto EC = diffStreamDirectory())
+ return EC;
+
+ if (auto EC = diffStringTable())
+ return EC;
+
+ if (auto EC = diffInfoStream())
+ return EC;
+
+ if (auto EC = diffDbiStream())
+ return EC;
+
+ if (auto EC = diffSectionContribs())
+ return EC;
+
+ if (auto EC = diffSectionMap())
+ return EC;
+
+ if (auto EC = diffFpoStream())
+ return EC;
+
+ if (auto EC = diffTpiStream(StreamTPI))
+ return EC;
+
+ if (auto EC = diffTpiStream(StreamIPI))
+ return EC;
+
+ if (auto EC = diffPublics())
+ return EC;
+
+ if (auto EC = diffGlobals())
+ return EC;
+
+ return Error::success();
+}
+
+template <typename T>
+static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, T V1,
+ T V2) {
+ if (V1 == V2) {
+ outs() << formatv(" {0}: No differences detected!\n", Label);
+ return false;
+ }
+
+ outs().indent(2) << Label << "\n";
+ outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(), V1);
+ outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(), V2);
+ return true;
+}
+
+template <typename T>
+static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2,
+ ArrayRef<T> V1, ArrayRef<T> V2) {
+ if (V1 == V2) {
+ outs() << formatv(" {0}: No differences detected!\n", Label);
+ return false;
+ }
+
+ outs().indent(2) << Label << "\n";
+ outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(),
+ make_range(V1.begin(), V1.end()));
+ outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(),
+ make_range(V2.begin(), V2.end()));
+ return true;
+}
+
+template <typename T>
+static bool printSymmetricDifferences(PDBFile &File1, PDBFile &File2,
+ T &&OnlyRange1, T &&OnlyRange2,
+ StringRef Label) {
+ bool HasDiff = false;
+ if (!OnlyRange1.empty()) {
+ HasDiff = true;
+ outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange1.size(), Label,
+ File1.getFilePath());
+ for (const auto &Item : OnlyRange1)
+ outs() << formatv(" {0}\n", Label, Item);
+ }
+ if (!OnlyRange2.empty()) {
+ HasDiff = true;
+ outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange2.size(),
+ File2.getFilePath());
+ for (const auto &Item : OnlyRange2)
+ outs() << formatv(" {0}\n", Item);
+ }
+ return HasDiff;
+}
+
+Error DiffStyle::diffSuperBlock() {
+ outs() << "MSF Super Block: Searching for differences...\n";
+ bool Diffs = false;
+
+ Diffs |= diffAndPrint("Block Size", File1, File2, File1.getBlockSize(),
+ File2.getBlockSize());
+ Diffs |= diffAndPrint("Block Count", File1, File2, File1.getBlockCount(),
+ File2.getBlockCount());
+ Diffs |= diffAndPrint("Unknown 1", File1, File2, File1.getUnknown1(),
+ File2.getUnknown1());
+
+ if (opts::diff::Pedantic) {
+ Diffs |= diffAndPrint("Free Block Map", File1, File2,
+ File1.getFreeBlockMapBlock(),
+ File2.getFreeBlockMapBlock());
+ Diffs |= diffAndPrint("Directory Size", File1, File2,
+ File1.getNumDirectoryBytes(),
+ File2.getNumDirectoryBytes());
+ Diffs |= diffAndPrint("Block Map Addr", File1, File2,
+ File1.getBlockMapOffset(), File2.getBlockMapOffset());
+ }
+ if (!Diffs)
+ outs() << "MSF Super Block: No differences detected...\n";
+ return Error::success();
+}
+
+Error DiffStyle::diffStreamDirectory() {
+ SmallVector<std::string, 32> P;
+ SmallVector<std::string, 32> Q;
+ discoverStreamPurposes(File1, P);
+ discoverStreamPurposes(File2, Q);
+ outs() << "Stream Directory: Searching for differences...\n";
+
+ bool HasDifferences = false;
+ if (opts::diff::Pedantic) {
+ size_t Min = std::min(P.size(), Q.size());
+ for (size_t I = 0; I < Min; ++I) {
+ StringRef Names[] = {P[I], Q[I]};
+ uint32_t Sizes[] = {File1.getStreamByteSize(I),
+ File2.getStreamByteSize(I)};
+ bool NamesDiffer = Names[0] != Names[1];
+ bool SizesDiffer = Sizes[0] != Sizes[1];
+ if (NamesDiffer) {
+ HasDifferences = true;
+ outs().indent(2) << formatv("Stream {0} - {1}: {2}, {3}: {4}\n", I,
+ File1.getFilePath(), Names[0],
+ File2.getFilePath(), Names[1]);
+ continue;
+ }
+ if (SizesDiffer) {
+ HasDifferences = true;
+ outs().indent(2) << formatv(
+ "Stream {0} ({1}): {2}: {3} bytes, {4}: {5} bytes\n", I, Names[0],
+ File1.getFilePath(), Sizes[0], File2.getFilePath(), Sizes[1]);
+ continue;
+ }
+ }
+
+ ArrayRef<std::string> MaxNames = (P.size() > Q.size() ? P : Q);
+ size_t Max = std::max(P.size(), Q.size());
+ PDBFile &MaxFile = (P.size() > Q.size() ? File1 : File2);
+ StringRef MinFileName =
+ (P.size() < Q.size() ? File1.getFilePath() : File2.getFilePath());
+ for (size_t I = Min; I < Max; ++I) {
+ HasDifferences = true;
+ StringRef StreamName = MaxNames[I];
+
+ outs().indent(2) << formatv(
+ "Stream {0} - {1}: <not present>, {2}: Index {3}, {4} bytes\n",
+ StreamName, MinFileName, MaxFile.getFilePath(), I,
+ MaxFile.getStreamByteSize(I));
+ }
+ if (!HasDifferences)
+ outs() << "Stream Directory: No differences detected...\n";
+ } else {
+ auto PI = to_vector<32>(enumerate(P));
+ auto QI = to_vector<32>(enumerate(Q));
+
+ typedef decltype(PI) ContainerType;
+ typedef typename ContainerType::value_type value_type;
+
+ auto Comparator = [](const value_type &I1, const value_type &I2) {
+ return I1.value() < I2.value();
+ };
+
+ decltype(PI) OnlyP;
+ decltype(QI) OnlyQ;
+ decltype(PI) Common;
+
+ set_differences(PI, QI, &OnlyP, &OnlyQ, &Common, Comparator);
+
+ if (!OnlyP.empty()) {
+ HasDifferences = true;
+ outs().indent(2) << formatv("{0} Stream(s) only in ({1})\n", OnlyP.size(),
+ File1.getFilePath());
+ for (auto &Item : OnlyP) {
+ outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(),
+ Item.value());
+ }
+ }
+
+ if (!OnlyQ.empty()) {
+ HasDifferences = true;
+ outs().indent(2) << formatv("{0} Streams(s) only in ({1})\n",
+ OnlyQ.size(), File2.getFilePath());
+ for (auto &Item : OnlyQ) {
+ outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(),
+ Item.value());
+ }
+ }
+ if (!Common.empty()) {
+ outs().indent(2) << formatv("Found {0} common streams. Searching for "
+ "intra-stream differences.\n",
+ Common.size());
+ bool HasCommonDifferences = false;
+ for (const auto &Left : Common) {
+ // Left was copied from the first range so its index refers to a stream
+ // index in the first file. Find the corresponding stream index in the
+ // second file.
+ auto Range =
+ std::equal_range(QI.begin(), QI.end(), Left,
+ [](const value_type &L, const value_type &R) {
+ return L.value() < R.value();
+ });
+ const auto &Right = *Range.first;
+ assert(Left.value() == Right.value());
+ uint32_t LeftSize = File1.getStreamByteSize(Left.index());
+ uint32_t RightSize = File2.getStreamByteSize(Right.index());
+ if (LeftSize != RightSize) {
+ HasDifferences = true;
+ HasCommonDifferences = true;
+ outs().indent(4) << formatv("{0} ({1}: {2} bytes, {3}: {4} bytes)\n",
+ Left.value(), File1.getFilePath(),
+ LeftSize, File2.getFilePath(), RightSize);
+ }
+ }
+ if (!HasCommonDifferences)
+ outs().indent(2) << "Common Streams: No differences detected!\n";
+ }
+ if (!HasDifferences)
+ outs() << "Stream Directory: No differences detected!\n";
+ }
+
+ return Error::success();
+}
+
+Error DiffStyle::diffStringTable() {
+ auto ExpectedST1 = File1.getStringTable();
+ auto ExpectedST2 = File2.getStringTable();
+ outs() << "String Table: Searching for differences...\n";
+ bool Has1 = !!ExpectedST1;
+ bool Has2 = !!ExpectedST2;
+ if (!(Has1 && Has2)) {
+ // If one has a string table and the other doesn't, we can print less
+ // output.
+ if (Has1 != Has2) {
+ if (Has1) {
+ outs() << formatv(" {0}: ({1} strings)\n", File1.getFilePath(),
+ ExpectedST1->getNameCount());
+ outs() << formatv(" {0}: (string table not present)\n",
+ File2.getFilePath());
+ } else {
+ outs() << formatv(" {0}: (string table not present)\n",
+ File1.getFilePath());
+ outs() << formatv(" {0}: ({1})\n", File2.getFilePath(),
+ ExpectedST2->getNameCount());
+ }
+ }
+ consumeError(ExpectedST1.takeError());
+ consumeError(ExpectedST2.takeError());
+ return Error::success();
+ }
+
+ bool HasDiff = false;
+ auto &ST1 = *ExpectedST1;
+ auto &ST2 = *ExpectedST2;
+
+ if (ST1.getByteSize() != ST2.getByteSize()) {
+ outs() << " Stream Size\n";
+ outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(),
+ ST1.getByteSize());
+ outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(),
+ ST2.getByteSize());
+ outs() << formatv(" Difference: {0} bytes\n",
+ AbsoluteDifference(ST1.getByteSize(), ST2.getByteSize()));
+ HasDiff = true;
+ }
+ HasDiff |= diffAndPrint("Hash Version", File1, File2, ST1.getHashVersion(),
+ ST1.getHashVersion());
+ HasDiff |= diffAndPrint("Signature", File1, File2, ST1.getSignature(),
+ ST1.getSignature());
+
+ // Both have a valid string table, dive in and compare individual strings.
+
+ auto IdList1 = ST1.name_ids();
+ auto IdList2 = ST2.name_ids();
+ if (opts::diff::Pedantic) {
+ // In pedantic mode, we compare index by index (i.e. the strings are in the
+ // same order
+ // in both tables.
+ uint32_t Max = std::max(IdList1.size(), IdList2.size());
+ for (uint32_t I = 0; I < Max; ++I) {
+ Optional<uint32_t> Id1, Id2;
+ StringRef S1, S2;
+ if (I < IdList1.size()) {
+ Id1 = IdList1[I];
+ S1 = ST1.getStringForID(*Id1);
+ }
+ if (I < IdList2.size()) {
+ Id2 = IdList2[I];
+ S2 = ST2.getStringForID(*Id2);
+ }
+ if (Id1 == Id2 && S1 == S2)
+ continue;
+
+ std::string OutId1 =
+ Id1 ? formatv("{0}", *Id1).str() : "(index not present)";
+ std::string OutId2 =
+ Id2 ? formatv("{0}", *Id2).str() : "(index not present)";
+ outs() << formatv(" String {0}\n", I);
+ outs() << formatv(" {0}: Hash - {1}, Value - {2}\n",
+ File1.getFilePath(), OutId1, S1);
+ outs() << formatv(" {0}: Hash - {1}, Value - {2}\n",
+ File2.getFilePath(), OutId2, S2);
+ HasDiff = true;
+ }
+ } else {
+ std::vector<StringRef> Strings1, Strings2;
+ Strings1.reserve(IdList1.size());
+ Strings2.reserve(IdList2.size());
+ for (auto ID : IdList1)
+ Strings1.push_back(ST1.getStringForID(ID));
+ for (auto ID : IdList2)
+ Strings2.push_back(ST2.getStringForID(ID));
+
+ SmallVector<StringRef, 64> OnlyP;
+ SmallVector<StringRef, 64> OnlyQ;
+ auto End1 = std::remove(Strings1.begin(), Strings1.end(), "");
+ auto End2 = std::remove(Strings2.begin(), Strings2.end(), "");
+ uint32_t Empty1 = std::distance(End1, Strings1.end());
+ uint32_t Empty2 = std::distance(End2, Strings2.end());
+ Strings1.erase(End1, Strings1.end());
+ Strings2.erase(End2, Strings2.end());
+ set_differences(Strings1, Strings2, &OnlyP, &OnlyQ);
+ printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "String");
+
+ if (Empty1 != Empty2) {
+ PDBFile &MoreF = (Empty1 > Empty2) ? File1 : File2;
+ PDBFile &LessF = (Empty1 < Empty2) ? File1 : File2;
+ uint32_t Difference = AbsoluteDifference(Empty1, Empty2);
+ outs() << formatv(" {0} had {1} more empty strings than {2}\n",
+ MoreF.getFilePath(), Difference, LessF.getFilePath());
+ }
+ }
+ if (!HasDiff)
+ outs() << "String Table: No differences detected!\n";
+ return Error::success();
+}
+
+Error DiffStyle::diffFreePageMap() { return Error::success(); }
+
+Error DiffStyle::diffInfoStream() {
+ auto ExpectedInfo1 = File1.getPDBInfoStream();
+ auto ExpectedInfo2 = File2.getPDBInfoStream();
+
+ outs() << "PDB Stream: Searching for differences...\n";
+ bool Has1 = !!ExpectedInfo1;
+ bool Has2 = !!ExpectedInfo2;
+ if (!(Has1 && Has2)) {
+ if (Has1 != Has2)
+ outs() << formatv("{0} does not have a PDB Stream!\n",
+ Has1 ? File1.getFilePath() : File2.getFilePath());
+ consumeError(ExpectedInfo2.takeError());
+ consumeError(ExpectedInfo2.takeError());
+ return Error::success();
+ }
+
+ bool HasDiff = false;
+ auto &IS1 = *ExpectedInfo1;
+ auto &IS2 = *ExpectedInfo2;
+ if (IS1.getStreamSize() != IS2.getStreamSize()) {
+ outs() << " Stream Size\n";
+ outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(),
+ IS1.getStreamSize());
+ outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(),
+ IS2.getStreamSize());
+ outs() << formatv(
+ " Difference: {0} bytes\n",
+ AbsoluteDifference(IS1.getStreamSize(), IS2.getStreamSize()));
+ HasDiff = true;
+ }
+ HasDiff |= diffAndPrint("Age", File1, File2, IS1.getAge(), IS2.getAge());
+ HasDiff |= diffAndPrint("Guid", File1, File2, IS1.getGuid(), IS2.getGuid());
+ HasDiff |= diffAndPrint("Signature", File1, File2, IS1.getSignature(),
+ IS2.getSignature());
+ HasDiff |=
+ diffAndPrint("Version", File1, File2, IS1.getVersion(), IS2.getVersion());
+ HasDiff |= diffAndPrint("Features", File1, File2, IS1.getFeatureSignatures(),
+ IS2.getFeatureSignatures());
+ HasDiff |= diffAndPrint("Named Stream Byte Size", File1, File2,
+ IS1.getNamedStreamMapByteSize(),
+ IS2.getNamedStreamMapByteSize());
+ SmallVector<StringRef, 4> NS1;
+ SmallVector<StringRef, 4> NS2;
+ for (const auto &X : IS1.getNamedStreams().entries())
+ NS1.push_back(X.getKey());
+ for (const auto &X : IS2.getNamedStreams().entries())
+ NS2.push_back(X.getKey());
+ SmallVector<StringRef, 4> OnlyP;
+ SmallVector<StringRef, 4> OnlyQ;
+ set_differences(NS1, NS2, &OnlyP, &OnlyQ);
+ printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "Named Streams");
+ if (!HasDiff)
+ outs() << "PDB Stream: No differences detected!\n";
+
+ return Error::success();
+}
+
+Error DiffStyle::diffDbiStream() { return Error::success(); }
+
+Error DiffStyle::diffSectionContribs() { return Error::success(); }
+
+Error DiffStyle::diffSectionMap() { return Error::success(); }
+
+Error DiffStyle::diffFpoStream() { return Error::success(); }
+
+Error DiffStyle::diffTpiStream(int Index) { return Error::success(); }
+
+Error DiffStyle::diffModuleInfoStream(int Index) { return Error::success(); }
+
+Error DiffStyle::diffPublics() { return Error::success(); }
+
+Error DiffStyle::diffGlobals() { return Error::success(); }
diff --git a/tools/llvm-pdbdump/Diff.h b/tools/llvm-pdbdump/Diff.h
new file mode 100644
index 0000000000000..6037576e21bb6
--- /dev/null
+++ b/tools/llvm-pdbdump/Diff.h
@@ -0,0 +1,45 @@
+//===- Diff.h - PDB diff utility --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_DIFF_H
+#define LLVM_TOOLS_LLVMPDBDUMP_DIFF_H
+
+#include "OutputStyle.h"
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+class DiffStyle : public OutputStyle {
+public:
+ explicit DiffStyle(PDBFile &File1, PDBFile &File2);
+
+ Error dump() override;
+
+private:
+ Error diffSuperBlock();
+ Error diffStreamDirectory();
+ Error diffStringTable();
+ Error diffFreePageMap();
+ Error diffInfoStream();
+ Error diffDbiStream();
+ Error diffSectionContribs();
+ Error diffSectionMap();
+ Error diffFpoStream();
+ Error diffTpiStream(int Index);
+ Error diffModuleInfoStream(int Index);
+ Error diffPublics();
+ Error diffGlobals();
+
+ PDBFile &File1;
+ PDBFile &File2;
+};
+}
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/tools/llvm-pdbdump/LLVMOutputStyle.cpp
index 629ba40b113c5..8348751703f14 100644
--- a/tools/llvm-pdbdump/LLVMOutputStyle.cpp
+++ b/tools/llvm-pdbdump/LLVMOutputStyle.cpp
@@ -9,7 +9,10 @@
#include "LLVMOutputStyle.h"
+#include "CompactTypeDumpVisitor.h"
+#include "StreamUtil.h"
#include "llvm-pdbdump.h"
+
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/EnumTables.h"
@@ -20,20 +23,21 @@
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-#include "llvm/DebugInfo/MSF/StreamReader.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/EnumTables.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModInfo.h"
+#include "llvm/DebugInfo/PDB/Native/ModStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/EnumTables.h"
-#include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h"
-#include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
-#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
-#include "llvm/DebugInfo/PDB/Raw/ModStream.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
-#include "llvm/DebugInfo/PDB/Raw/RawError.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/FormatVariadic.h"
#include <unordered_map>
@@ -110,6 +114,9 @@ Error LLVMOutputStyle::dump() {
if (auto EC = dumpStreamBytes())
return EC;
+ if (auto EC = dumpStringTable())
+ return EC;
+
if (auto EC = dumpInfoStream())
return EC;
@@ -166,124 +173,12 @@ Error LLVMOutputStyle::dumpFileHeaders() {
return Error::success();
}
-void LLVMOutputStyle::discoverStreamPurposes() {
- if (!StreamPurposes.empty())
- return;
-
- // It's OK if we fail to load some of these streams, we still attempt to print
- // what we can.
- auto Dbi = File.getPDBDbiStream();
- auto Tpi = File.getPDBTpiStream();
- auto Ipi = File.getPDBIpiStream();
- auto Info = File.getPDBInfoStream();
-
- uint32_t StreamCount = File.getNumStreams();
- std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams;
- std::unordered_map<uint16_t, std::string> NamedStreams;
-
- if (Dbi) {
- for (auto &ModI : Dbi->modules()) {
- uint16_t SN = ModI.Info.getModuleStreamIndex();
- ModStreams[SN] = &ModI;
- }
- }
- if (Info) {
- for (auto &NSE : Info->named_streams()) {
- NamedStreams[NSE.second] = NSE.first();
- }
- }
-
- StreamPurposes.resize(StreamCount);
- for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
- std::string Value;
- if (StreamIdx == OldMSFDirectory)
- Value = "Old MSF Directory";
- else if (StreamIdx == StreamPDB)
- Value = "PDB Stream";
- else if (StreamIdx == StreamDBI)
- Value = "DBI Stream";
- else if (StreamIdx == StreamTPI)
- Value = "TPI Stream";
- else if (StreamIdx == StreamIPI)
- Value = "IPI Stream";
- else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
- Value = "Global Symbol Hash";
- else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
- Value = "Public Symbol Hash";
- else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
- Value = "Public Symbol Records";
- else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
- Value = "TPI Hash";
- else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
- Value = "TPI Aux Hash";
- else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
- Value = "IPI Hash";
- else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
- Value = "IPI Aux Hash";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
- Value = "Exception Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
- Value = "Fixup Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
- Value = "FPO Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
- Value = "New FPO Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
- Value = "Omap From Source Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
- Value = "Omap To Source Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
- Value = "Pdata";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
- Value = "Section Header Data";
- else if (Dbi &&
- StreamIdx ==
- Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
- Value = "Section Header Original Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
- Value = "Token Rid Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
- Value = "Xdata";
- else {
- auto ModIter = ModStreams.find(StreamIdx);
- auto NSIter = NamedStreams.find(StreamIdx);
- if (ModIter != ModStreams.end()) {
- Value = "Module \"";
- Value += ModIter->second->Info.getModuleName().str();
- Value += "\"";
- } else if (NSIter != NamedStreams.end()) {
- Value = "Named Stream \"";
- Value += NSIter->second;
- Value += "\"";
- } else {
- Value = "???";
- }
- }
- StreamPurposes[StreamIdx] = Value;
- }
-
- // Consume errors from missing streams.
- if (!Dbi)
- consumeError(Dbi.takeError());
- if (!Tpi)
- consumeError(Tpi.takeError());
- if (!Ipi)
- consumeError(Ipi.takeError());
- if (!Info)
- consumeError(Info.takeError());
-}
-
Error LLVMOutputStyle::dumpStreamSummary() {
if (!opts::raw::DumpStreamSummary)
return Error::success();
- discoverStreamPurposes();
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
uint32_t StreamCount = File.getNumStreams();
@@ -425,7 +320,8 @@ Error LLVMOutputStyle::dumpStreamBytes() {
if (opts::raw::DumpStreamData.empty())
return Error::success();
- discoverStreamPurposes();
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
DictScope D(P, "Stream Data");
for (uint32_t SI : opts::raw::DumpStreamData) {
@@ -444,7 +340,7 @@ Error LLVMOutputStyle::dumpStreamBytes() {
auto Blocks = File.getMsfLayout().StreamMap[SI];
P.printList("Blocks", Blocks);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
ArrayRef<uint8_t> StreamData;
if (auto EC = R.readBytes(StreamData, S->getLength()))
return EC;
@@ -453,6 +349,28 @@ Error LLVMOutputStyle::dumpStreamBytes() {
return Error::success();
}
+Error LLVMOutputStyle::dumpStringTable() {
+ if (!opts::raw::DumpStringTable)
+ return Error::success();
+
+ auto IS = File.getStringTable();
+ if (!IS)
+ return IS.takeError();
+
+ DictScope D(P, "String Table");
+ for (uint32_t I : IS->name_ids()) {
+ StringRef S = IS->getStringForID(I);
+ if (!S.empty()) {
+ llvm::SmallString<32> Str;
+ Str.append("'");
+ Str.append(S);
+ Str.append("'");
+ P.printString(Str);
+ }
+ }
+ return Error::success();
+}
+
Error LLVMOutputStyle::dumpInfoStream() {
if (!opts::raw::DumpHeaders)
return Error::success();
@@ -469,25 +387,28 @@ Error LLVMOutputStyle::dumpInfoStream() {
P.printHex("Signature", IS->getSignature());
P.printNumber("Age", IS->getAge());
P.printObject("Guid", IS->getGuid());
+ P.printHex("Features", IS->getFeatures());
+ {
+ DictScope DD(P, "Named Streams");
+ for (const auto &S : IS->getNamedStreams().entries())
+ P.printObject(S.getKey(), S.getValue());
+ }
return Error::success();
}
-static void printTypeIndexOffset(raw_ostream &OS,
- const TypeIndexOffset &TIOff) {
- OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}";
-}
+namespace {
+class RecordBytesVisitor : public TypeVisitorCallbacks {
+public:
+ explicit RecordBytesVisitor(ScopedPrinter &P) : P(P) {}
-static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) {
- if (!opts::raw::DumpTpiHash)
- return;
- DictScope DD(P, "Hash");
- P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets());
- P.printNumber("Hash Key Size", Tpi.getHashKeySize());
- P.printList("Values", Tpi.getHashValues());
- P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(),
- printTypeIndexOffset);
- P.printList("Hash Adjustments", Tpi.getHashAdjustments(),
- printTypeIndexOffset);
+ Error visitTypeEnd(CVType &Record) override {
+ P.printBinaryBlock("Bytes", Record.content());
+ return Error::success();
+ }
+
+private:
+ ScopedPrinter &P;
+};
}
Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
@@ -495,6 +416,7 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
bool DumpRecordBytes = false;
bool DumpRecords = false;
+ bool DumpTpiHash = false;
StringRef Label;
StringRef VerLabel;
if (StreamIdx == StreamTPI) {
@@ -504,6 +426,7 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
}
DumpRecordBytes = opts::raw::DumpTpiRecordBytes;
DumpRecords = opts::raw::DumpTpiRecords;
+ DumpTpiHash = opts::raw::DumpTpiHash;
Label = "Type Info Stream (TPI)";
VerLabel = "TPI Version";
} else if (StreamIdx == StreamIPI) {
@@ -516,64 +439,102 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
Label = "Type Info Stream (IPI)";
VerLabel = "IPI Version";
}
- if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms)
+ if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash &&
+ !opts::raw::DumpModuleSyms)
return Error::success();
+ bool IsSilentDatabaseBuild = !DumpRecordBytes && !DumpRecords && !DumpTpiHash;
+
auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
: File.getPDBIpiStream();
if (!Tpi)
return Tpi.takeError();
- CVTypeDumper Dumper(TypeDB);
- if (DumpRecords || DumpRecordBytes) {
- DictScope D(P, Label);
+ std::unique_ptr<DictScope> StreamScope;
+ std::unique_ptr<ListScope> RecordScope;
+ if (!IsSilentDatabaseBuild) {
+ StreamScope = llvm::make_unique<DictScope>(P, Label);
P.printNumber(VerLabel, Tpi->getTpiVersion());
P.printNumber("Record count", Tpi->NumTypeRecords());
+ }
- ListScope L(P, "Records");
+ TypeDatabase &StreamDB = (StreamIdx == StreamTPI) ? TypeDB : ItemDB;
+
+ TypeDatabaseVisitor DBV(StreamDB);
+ CompactTypeDumpVisitor CTDV(StreamDB, &P);
+ TypeDumpVisitor TDV(TypeDB, &P, false);
+ if (StreamIdx == StreamIPI)
+ TDV.setItemDB(ItemDB);
+ RecordBytesVisitor RBV(P);
+ TypeDeserializer Deserializer;
+
+ // We always need to deserialize and add it to the type database. This is
+ // true if even if we're not dumping anything, because we could need the
+ // type database for the purposes of dumping symbols.
+ TypeVisitorCallbackPipeline Pipeline;
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(DBV);
+
+ // If we're in dump mode, add a dumper with the appropriate detail level.
+ if (DumpRecords) {
+ if (opts::raw::CompactRecords)
+ Pipeline.addCallbackToPipeline(CTDV);
+ else
+ Pipeline.addCallbackToPipeline(TDV);
+ }
+ if (DumpRecordBytes)
+ Pipeline.addCallbackToPipeline(RBV);
- bool HadError = false;
- for (auto &Type : Tpi->types(&HadError)) {
- DictScope DD(P, "");
+ CVTypeVisitor Visitor(Pipeline);
- if (DumpRecords) {
- TypeDumpVisitor TDV(TypeDB, &P, false);
- if (auto EC = Dumper.dump(Type, TDV))
- return EC;
- }
+ if (DumpRecords || DumpRecordBytes)
+ RecordScope = llvm::make_unique<ListScope>(P, "Records");
- if (DumpRecordBytes)
- P.printBinaryBlock("Bytes", Type.content());
- }
- dumpTpiHash(P, *Tpi);
- if (HadError)
- return make_error<RawError>(raw_error_code::corrupt_file,
- "TPI stream contained corrupt record");
- } else if (opts::raw::DumpModuleSyms) {
- // Even if the user doesn't want to dump type records, we still need to
- // iterate them in order to build the type database. So when they want to
- // dump symbols but not types, don't stick a dumper on the end, just build
- // the type database.
- TypeDatabaseVisitor DBV(TypeDB);
- TypeDeserializer Deserializer;
- TypeVisitorCallbackPipeline Pipeline;
- Pipeline.addCallbackToPipeline(Deserializer);
- Pipeline.addCallbackToPipeline(DBV);
-
- CVTypeVisitor Visitor(Pipeline);
-
- bool HadError = false;
- for (auto Type : Tpi->types(&HadError)) {
- if (auto EC = Visitor.visitTypeRecord(Type))
- return EC;
+ bool HadError = false;
+
+ TypeIndex T(TypeIndex::FirstNonSimpleIndex);
+ for (auto Type : Tpi->types(&HadError)) {
+ std::unique_ptr<DictScope> OneRecordScope;
+
+ if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords)
+ OneRecordScope = llvm::make_unique<DictScope>(P, "");
+
+ if (auto EC = Visitor.visitTypeRecord(Type))
+ return EC;
+ }
+ if (HadError)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI stream contained corrupt record");
+
+ if (DumpTpiHash) {
+ DictScope DD(P, "Hash");
+ P.printNumber("Number of Hash Buckets", Tpi->NumHashBuckets());
+ P.printNumber("Hash Key Size", Tpi->getHashKeySize());
+ P.printList("Values", Tpi->getHashValues());
+
+ ListScope LHA(P, "Adjusters");
+ auto ExpectedST = File.getStringTable();
+ if (!ExpectedST)
+ return ExpectedST.takeError();
+ const auto &ST = *ExpectedST;
+ for (const auto &E : Tpi->getHashAdjusters()) {
+ DictScope DHA(P);
+ StringRef Name = ST.getStringForID(E.first);
+ P.printString("Type", Name);
+ P.printHex("TI", E.second);
}
+ }
- dumpTpiHash(P, *Tpi);
- if (HadError)
- return make_error<RawError>(raw_error_code::corrupt_file,
- "TPI stream contained corrupt record");
+ if (!IsSilentDatabaseBuild) {
+ ListScope L(P, "TypeIndexOffsets");
+ for (const auto &IO : Tpi->getTypeIndexOffsets()) {
+ P.printString(formatv("Index: {0:x}, Offset: {1:N}", IO.Type.getIndex(),
+ (uint32_t)IO.Offset)
+ .str());
+ }
}
+
P.flush();
return Error::success();
}
@@ -679,10 +640,10 @@ Error LLVMOutputStyle::dumpDbiStream() {
public:
RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {}
Error visitUnknown(ModuleSubstreamKind Kind,
- ReadableStreamRef Stream) override {
+ BinaryStreamRef Stream) override {
DictScope DD(P, "Unknown");
ArrayRef<uint8_t> Data;
- StreamReader R(Stream);
+ BinaryStreamReader R(Stream);
if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
return make_error<RawError>(
raw_error_code::corrupt_file,
@@ -692,7 +653,7 @@ Error LLVMOutputStyle::dumpDbiStream() {
return Error::success();
}
Error
- visitFileChecksums(ReadableStreamRef Data,
+ visitFileChecksums(BinaryStreamRef Data,
const FileChecksumArray &Checksums) override {
DictScope DD(P, "FileChecksums");
for (const auto &C : Checksums) {
@@ -708,7 +669,7 @@ Error LLVMOutputStyle::dumpDbiStream() {
return Error::success();
}
- Error visitLines(ReadableStreamRef Data,
+ Error visitLines(BinaryStreamRef Data,
const LineSubstreamHeader *Header,
const LineInfoArray &Lines) override {
DictScope DD(P, "Lines");
diff --git a/tools/llvm-pdbdump/LLVMOutputStyle.h b/tools/llvm-pdbdump/LLVMOutputStyle.h
index 816d591f08f83..bfff3b8308db9 100644
--- a/tools/llvm-pdbdump/LLVMOutputStyle.h
+++ b/tools/llvm-pdbdump/LLVMOutputStyle.h
@@ -12,9 +12,12 @@
#include "OutputStyle.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/Support/ScopedPrinter.h"
+#include <string>
+
namespace llvm {
class BitVector;
namespace pdb {
@@ -25,8 +28,6 @@ public:
Error dump() override;
private:
- void discoverStreamPurposes();
-
Error dumpFileHeaders();
Error dumpStreamSummary();
Error dumpFreePageMap();
@@ -34,6 +35,7 @@ private:
Error dumpGlobalsStream();
Error dumpStreamBytes();
Error dumpStreamBlocks();
+ Error dumpStringTable();
Error dumpInfoStream();
Error dumpTpiStream(uint32_t StreamIdx);
Error dumpDbiStream();
@@ -50,7 +52,8 @@ private:
PDBFile &File;
ScopedPrinter P;
codeview::TypeDatabase TypeDB;
- std::vector<std::string> StreamPurposes;
+ codeview::TypeDatabase ItemDB;
+ SmallVector<std::string, 32> StreamPurposes;
};
}
}
diff --git a/tools/llvm-pdbdump/LinePrinter.cpp b/tools/llvm-pdbdump/LinePrinter.cpp
index 47c7d3e3c0e74..d4a5a8d859e5c 100644
--- a/tools/llvm-pdbdump/LinePrinter.cpp
+++ b/tools/llvm-pdbdump/LinePrinter.cpp
@@ -12,6 +12,7 @@
#include "llvm-pdbdump.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
#include "llvm/Support/Regex.h"
#include <algorithm>
@@ -42,8 +43,8 @@ bool IsItemExcluded(llvm::StringRef Item,
using namespace llvm;
-LinePrinter::LinePrinter(int Indent, llvm::raw_ostream &Stream)
- : OS(Stream), IndentSpaces(Indent), CurrentIndent(0) {
+LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream)
+ : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) {
SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(),
opts::pretty::ExcludeTypes.end());
SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(),
@@ -70,8 +71,20 @@ void LinePrinter::NewLine() {
OS.indent(CurrentIndent);
}
-bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName) {
- return IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters);
+bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
+ if (IsTypeExcluded(Class.getUDTName(), Class.getClassSize()))
+ return true;
+ if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
+ return true;
+ return false;
+}
+
+bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
+ if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
+ return true;
+ if (Size < opts::pretty::SizeThreshold)
+ return true;
+ return false;
}
bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
@@ -83,17 +96,25 @@ bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
ExcludeCompilandFilters);
}
-WithColor::WithColor(LinePrinter &P, PDB_ColorItem C) : OS(P.OS) {
- applyColor(C);
+WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)
+ : OS(P.OS), UseColor(P.hasColor()) {
+ if (UseColor)
+ applyColor(C);
}
-WithColor::~WithColor() { OS.resetColor(); }
+WithColor::~WithColor() {
+ if (UseColor)
+ OS.resetColor();
+}
void WithColor::applyColor(PDB_ColorItem C) {
switch (C) {
case PDB_ColorItem::None:
OS.resetColor();
return;
+ case PDB_ColorItem::Comment:
+ OS.changeColor(raw_ostream::GREEN, false);
+ return;
case PDB_ColorItem::Address:
OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
return;
@@ -113,6 +134,7 @@ void WithColor::applyColor(PDB_ColorItem C) {
case PDB_ColorItem::Path:
OS.changeColor(raw_ostream::CYAN, false);
return;
+ case PDB_ColorItem::Padding:
case PDB_ColorItem::SectionHeader:
OS.changeColor(raw_ostream::RED, true);
return;
diff --git a/tools/llvm-pdbdump/LinePrinter.h b/tools/llvm-pdbdump/LinePrinter.h
index a4401f8af9552..1a922feb1e622 100644
--- a/tools/llvm-pdbdump/LinePrinter.h
+++ b/tools/llvm-pdbdump/LinePrinter.h
@@ -20,20 +20,24 @@
namespace llvm {
namespace pdb {
+class ClassLayout;
+
class LinePrinter {
friend class WithColor;
public:
- LinePrinter(int Indent, raw_ostream &Stream);
+ LinePrinter(int Indent, bool UseColor, raw_ostream &Stream);
void Indent();
void Unindent();
void NewLine();
+ bool hasColor() const { return UseColor; }
raw_ostream &getStream() { return OS; }
int getIndentLevel() const { return CurrentIndent; }
- bool IsTypeExcluded(llvm::StringRef TypeName);
+ bool IsClassExcluded(const ClassLayout &Class);
+ bool IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size);
bool IsSymbolExcluded(llvm::StringRef SymbolName);
bool IsCompilandExcluded(llvm::StringRef CompilandName);
@@ -48,6 +52,7 @@ private:
raw_ostream &OS;
int IndentSpaces;
int CurrentIndent;
+ bool UseColor;
std::list<Regex> ExcludeCompilandFilters;
std::list<Regex> ExcludeTypeFilters;
@@ -68,6 +73,8 @@ enum class PDB_ColorItem {
None,
Address,
Type,
+ Comment,
+ Padding,
Keyword,
Offset,
Identifier,
@@ -87,6 +94,7 @@ public:
private:
void applyColor(PDB_ColorItem C);
raw_ostream &OS;
+ bool UseColor;
};
}
}
diff --git a/tools/llvm-pdbdump/PdbYaml.cpp b/tools/llvm-pdbdump/PdbYaml.cpp
index 34e0611e14643..e2c4ee967ed36 100644
--- a/tools/llvm-pdbdump/PdbYaml.cpp
+++ b/tools/llvm-pdbdump/PdbYaml.cpp
@@ -16,14 +16,15 @@
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
#include "llvm/DebugInfo/PDB/PDBTypes.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h"
using namespace llvm;
using namespace llvm::pdb;
@@ -37,6 +38,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSymbolRecord)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiRecord)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::pdb::PdbRaw_FeatureSig)
namespace llvm {
namespace yaml {
@@ -133,25 +135,45 @@ template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_TpiVer> {
io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80);
}
};
+
+template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_FeatureSig> {
+ static void enumeration(IO &io, PdbRaw_FeatureSig &Features) {
+ io.enumCase(Features, "MinimalDebugInfo",
+ PdbRaw_FeatureSig::MinimalDebugInfo);
+ io.enumCase(Features, "NoTypeMerge", PdbRaw_FeatureSig::NoTypeMerge);
+ io.enumCase(Features, "VC110", PdbRaw_FeatureSig::VC110);
+ io.enumCase(Features, "VC140", PdbRaw_FeatureSig::VC140);
+ }
+};
}
}
void MappingTraits<PdbObject>::mapping(IO &IO, PdbObject &Obj) {
+ // Create a single serialization context that will be passed through the
+ // entire process of serializing / deserializing a Tpi Stream. This is
+ // especially important when we are going from Pdb -> Yaml because we need
+ // to maintain state in a TypeTableBuilder across mappings, and at the end of
+ // the entire process, we need to have one TypeTableBuilder that has every
+ // record.
+ pdb::yaml::SerializationContext Context(IO, Obj.Allocator);
+
+
IO.mapOptional("MSF", Obj.Headers);
IO.mapOptional("StreamSizes", Obj.StreamSizes);
IO.mapOptional("StreamMap", Obj.StreamMap);
+ IO.mapOptional("StringTable", Obj.StringTable);
IO.mapOptional("PdbStream", Obj.PdbStream);
- IO.mapOptional("DbiStream", Obj.DbiStream);
- IO.mapOptionalWithContext("TpiStream", Obj.TpiStream, Obj.Allocator);
- IO.mapOptionalWithContext("IpiStream", Obj.IpiStream, Obj.Allocator);
+ IO.mapOptionalWithContext("DbiStream", Obj.DbiStream, Context);
+ IO.mapOptionalWithContext("TpiStream", Obj.TpiStream, Context);
+ IO.mapOptionalWithContext("IpiStream", Obj.IpiStream, Context);
}
void MappingTraits<MSFHeaders>::mapping(IO &IO, MSFHeaders &Obj) {
- IO.mapRequired("SuperBlock", Obj.SuperBlock);
- IO.mapRequired("NumDirectoryBlocks", Obj.NumDirectoryBlocks);
- IO.mapRequired("DirectoryBlocks", Obj.DirectoryBlocks);
- IO.mapRequired("NumStreams", Obj.NumStreams);
- IO.mapRequired("FileSize", Obj.FileSize);
+ IO.mapOptional("SuperBlock", Obj.SuperBlock);
+ IO.mapOptional("NumDirectoryBlocks", Obj.NumDirectoryBlocks);
+ IO.mapOptional("DirectoryBlocks", Obj.DirectoryBlocks);
+ IO.mapOptional("NumStreams", Obj.NumStreams);
+ IO.mapOptional("FileSize", Obj.FileSize);
}
void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) {
@@ -159,12 +181,13 @@ void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) {
::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
}
- IO.mapRequired("BlockSize", SB.BlockSize);
- IO.mapRequired("FreeBlockMap", SB.FreeBlockMapBlock);
- IO.mapRequired("NumBlocks", SB.NumBlocks);
- IO.mapRequired("NumDirectoryBytes", SB.NumDirectoryBytes);
- IO.mapRequired("Unknown1", SB.Unknown1);
- IO.mapRequired("BlockMapAddr", SB.BlockMapAddr);
+ using u32 = support::ulittle32_t;
+ IO.mapOptional("BlockSize", SB.BlockSize, u32(4096U));
+ IO.mapOptional("FreeBlockMap", SB.FreeBlockMapBlock, u32(0U));
+ IO.mapOptional("NumBlocks", SB.NumBlocks, u32(0U));
+ IO.mapOptional("NumDirectoryBytes", SB.NumDirectoryBytes, u32(0U));
+ IO.mapOptional("Unknown1", SB.Unknown1, u32(0U));
+ IO.mapOptional("BlockMapAddr", SB.BlockMapAddr, u32(0U));
}
void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) {
@@ -172,35 +195,27 @@ void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) {
}
void MappingTraits<PdbInfoStream>::mapping(IO &IO, PdbInfoStream &Obj) {
- IO.mapRequired("Age", Obj.Age);
- IO.mapRequired("Guid", Obj.Guid);
- IO.mapRequired("Signature", Obj.Signature);
- IO.mapRequired("Version", Obj.Version);
- IO.mapRequired("NamedStreams", Obj.NamedStreams);
+ IO.mapOptional("Age", Obj.Age, 1U);
+ IO.mapOptional("Guid", Obj.Guid);
+ IO.mapOptional("Signature", Obj.Signature, 0U);
+ IO.mapOptional("Features", Obj.Features);
+ IO.mapOptional("Version", Obj.Version, PdbImplVC70);
}
-void MappingTraits<PdbDbiStream>::mapping(IO &IO, PdbDbiStream &Obj) {
- IO.mapRequired("VerHeader", Obj.VerHeader);
- IO.mapRequired("Age", Obj.Age);
- IO.mapRequired("BuildNumber", Obj.BuildNumber);
- IO.mapRequired("PdbDllVersion", Obj.PdbDllVersion);
- IO.mapRequired("PdbDllRbld", Obj.PdbDllRbld);
- IO.mapRequired("Flags", Obj.Flags);
- IO.mapRequired("MachineType", Obj.MachineType);
- IO.mapOptional("Modules", Obj.ModInfos);
+void MappingContextTraits<PdbDbiStream, pdb::yaml::SerializationContext>::mapping(IO &IO, PdbDbiStream &Obj, pdb::yaml::SerializationContext &Context) {
+ IO.mapOptional("VerHeader", Obj.VerHeader, PdbDbiV70);
+ IO.mapOptional("Age", Obj.Age, 1U);
+ IO.mapOptional("BuildNumber", Obj.BuildNumber, uint16_t(0U));
+ IO.mapOptional("PdbDllVersion", Obj.PdbDllVersion, 0U);
+ IO.mapOptional("PdbDllRbld", Obj.PdbDllRbld, uint16_t(0U));
+ IO.mapOptional("Flags", Obj.Flags, uint16_t(1U));
+ IO.mapOptional("MachineType", Obj.MachineType, PDB_Machine::x86);
+ IO.mapOptionalWithContext("Modules", Obj.ModInfos, Context);
}
-void MappingContextTraits<PdbTpiStream, BumpPtrAllocator>::mapping(
- IO &IO, pdb::yaml::PdbTpiStream &Obj, BumpPtrAllocator &Allocator) {
- // Create a single serialization context that will be passed through the
- // entire process of serializing / deserializing a Tpi Stream. This is
- // especially important when we are going from Pdb -> Yaml because we need
- // to maintain state in a TypeTableBuilder across mappings, and at the end of
- // the entire process, we need to have one TypeTableBuilder that has every
- // record.
- pdb::yaml::SerializationContext Context(IO, Allocator);
-
- IO.mapRequired("Version", Obj.Version);
+void MappingContextTraits<PdbTpiStream, pdb::yaml::SerializationContext>::mapping(
+ IO &IO, pdb::yaml::PdbTpiStream &Obj, pdb::yaml::SerializationContext &Context) {
+ IO.mapOptional("Version", Obj.Version, PdbTpiV80);
IO.mapRequired("Records", Obj.Records, Context);
}
@@ -210,8 +225,9 @@ void MappingTraits<NamedStreamMapping>::mapping(IO &IO,
IO.mapRequired("StreamNum", Obj.StreamNumber);
}
-void MappingTraits<PdbSymbolRecord>::mapping(IO &IO, PdbSymbolRecord &Obj) {
+void MappingContextTraits<PdbSymbolRecord, pdb::yaml::SerializationContext>::mapping(IO &IO, PdbSymbolRecord &Obj, pdb::yaml::SerializationContext &Context) {
codeview::SymbolVisitorCallbackPipeline Pipeline;
+ codeview::SymbolSerializer Serializer(Context.Allocator);
codeview::SymbolDeserializer Deserializer(nullptr);
codeview::yaml::YamlSymbolDumper Dumper(IO);
@@ -220,23 +236,26 @@ void MappingTraits<PdbSymbolRecord>::mapping(IO &IO, PdbSymbolRecord &Obj) {
Pipeline.addCallbackToPipeline(Deserializer);
Pipeline.addCallbackToPipeline(Dumper);
} else {
- return;
+ // For the other way around, dump it into a concrete structure, and then
+ // serialize it into the CVRecord.
+ Pipeline.addCallbackToPipeline(Dumper);
+ Pipeline.addCallbackToPipeline(Serializer);
}
codeview::CVSymbolVisitor Visitor(Pipeline);
consumeError(Visitor.visitSymbolRecord(Obj.Record));
}
-void MappingTraits<PdbModiStream>::mapping(IO &IO, PdbModiStream &Obj) {
- IO.mapRequired("Signature", Obj.Signature);
- IO.mapRequired("Records", Obj.Symbols);
+void MappingContextTraits<PdbModiStream, pdb::yaml::SerializationContext>::mapping(IO &IO, PdbModiStream &Obj, pdb::yaml::SerializationContext &Context) {
+ IO.mapOptional("Signature", Obj.Signature, 4U);
+ IO.mapRequired("Records", Obj.Symbols, Context);
}
-void MappingTraits<PdbDbiModuleInfo>::mapping(IO &IO, PdbDbiModuleInfo &Obj) {
+void MappingContextTraits<PdbDbiModuleInfo, pdb::yaml::SerializationContext>::mapping(IO &IO, PdbDbiModuleInfo &Obj, pdb::yaml::SerializationContext &Context) {
IO.mapRequired("Module", Obj.Mod);
- IO.mapRequired("ObjFile", Obj.Obj);
+ IO.mapOptional("ObjFile", Obj.Obj, Obj.Mod);
IO.mapOptional("SourceFiles", Obj.SourceFiles);
- IO.mapOptional("Modi", Obj.Modi);
+ IO.mapOptionalWithContext("Modi", Obj.Modi, Context);
}
void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>::
diff --git a/tools/llvm-pdbdump/PdbYaml.h b/tools/llvm-pdbdump/PdbYaml.h
index 398186f16d723..2c4cd237f8d7f 100644
--- a/tools/llvm-pdbdump/PdbYaml.h
+++ b/tools/llvm-pdbdump/PdbYaml.h
@@ -16,9 +16,9 @@
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/PDBTypes.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/YAMLTraits.h"
@@ -32,10 +32,10 @@ struct SerializationContext;
struct MSFHeaders {
msf::SuperBlock SuperBlock;
- uint32_t NumDirectoryBlocks;
+ uint32_t NumDirectoryBlocks = 0;
std::vector<uint32_t> DirectoryBlocks;
- uint32_t NumStreams;
- uint32_t FileSize;
+ uint32_t NumStreams = 0;
+ uint32_t FileSize = 0;
};
struct StreamBlockList {
@@ -48,10 +48,11 @@ struct NamedStreamMapping {
};
struct PdbInfoStream {
- PdbRaw_ImplVer Version;
- uint32_t Signature;
- uint32_t Age;
+ PdbRaw_ImplVer Version = PdbImplVC70;
+ uint32_t Signature = 0;
+ uint32_t Age = 1;
PDB_UniqueId Guid;
+ std::vector<PdbRaw_FeatureSig> Features;
std::vector<NamedStreamMapping> NamedStreams;
};
@@ -72,13 +73,13 @@ struct PdbDbiModuleInfo {
};
struct PdbDbiStream {
- PdbRaw_DbiVer VerHeader;
- uint32_t Age;
- uint16_t BuildNumber;
- uint32_t PdbDllVersion;
- uint16_t PdbDllRbld;
- uint16_t Flags;
- PDB_Machine MachineType;
+ PdbRaw_DbiVer VerHeader = PdbDbiV70;
+ uint32_t Age = 1;
+ uint16_t BuildNumber = 0;
+ uint32_t PdbDllVersion = 0;
+ uint16_t PdbDllRbld = 0;
+ uint16_t Flags = 1;
+ PDB_Machine MachineType = PDB_Machine::x86;
std::vector<PdbDbiModuleInfo> ModInfos;
};
@@ -92,7 +93,7 @@ struct PdbTpiFieldListRecord {
};
struct PdbTpiStream {
- PdbRaw_TpiVer Version;
+ PdbRaw_TpiVer Version = PdbTpiV80;
std::vector<PdbTpiRecord> Records;
};
@@ -107,6 +108,8 @@ struct PdbObject {
Optional<PdbTpiStream> TpiStream;
Optional<PdbTpiStream> IpiStream;
+ Optional<std::vector<StringRef>> StringTable;
+
BumpPtrAllocator &Allocator;
};
}
@@ -136,30 +139,30 @@ template <> struct MappingTraits<pdb::yaml::PdbInfoStream> {
static void mapping(IO &IO, pdb::yaml::PdbInfoStream &Obj);
};
-template <> struct MappingTraits<pdb::yaml::PdbDbiStream> {
- static void mapping(IO &IO, pdb::yaml::PdbDbiStream &Obj);
+template <> struct MappingContextTraits<pdb::yaml::PdbDbiStream, pdb::yaml::SerializationContext> {
+ static void mapping(IO &IO, pdb::yaml::PdbDbiStream &Obj, pdb::yaml::SerializationContext &Context);
};
template <>
-struct MappingContextTraits<pdb::yaml::PdbTpiStream, llvm::BumpPtrAllocator> {
+struct MappingContextTraits<pdb::yaml::PdbTpiStream, pdb::yaml::SerializationContext> {
static void mapping(IO &IO, pdb::yaml::PdbTpiStream &Obj,
- llvm::BumpPtrAllocator &Allocator);
+ pdb::yaml::SerializationContext &Context);
};
template <> struct MappingTraits<pdb::yaml::NamedStreamMapping> {
static void mapping(IO &IO, pdb::yaml::NamedStreamMapping &Obj);
};
-template <> struct MappingTraits<pdb::yaml::PdbSymbolRecord> {
- static void mapping(IO &IO, pdb::yaml::PdbSymbolRecord &Obj);
+template <> struct MappingContextTraits<pdb::yaml::PdbSymbolRecord, pdb::yaml::SerializationContext> {
+ static void mapping(IO &IO, pdb::yaml::PdbSymbolRecord &Obj, pdb::yaml::SerializationContext &Context);
};
-template <> struct MappingTraits<pdb::yaml::PdbModiStream> {
- static void mapping(IO &IO, pdb::yaml::PdbModiStream &Obj);
+template <> struct MappingContextTraits<pdb::yaml::PdbModiStream, pdb::yaml::SerializationContext> {
+ static void mapping(IO &IO, pdb::yaml::PdbModiStream &Obj, pdb::yaml::SerializationContext &Context);
};
-template <> struct MappingTraits<pdb::yaml::PdbDbiModuleInfo> {
- static void mapping(IO &IO, pdb::yaml::PdbDbiModuleInfo &Obj);
+template <> struct MappingContextTraits<pdb::yaml::PdbDbiModuleInfo, pdb::yaml::SerializationContext> {
+ static void mapping(IO &IO, pdb::yaml::PdbDbiModuleInfo &Obj, pdb::yaml::SerializationContext &Context);
};
template <>
diff --git a/tools/llvm-pdbdump/PrettyBuiltinDumper.cpp b/tools/llvm-pdbdump/PrettyBuiltinDumper.cpp
index f866132aa8866..591d5e70cfd6e 100644
--- a/tools/llvm-pdbdump/PrettyBuiltinDumper.cpp
+++ b/tools/llvm-pdbdump/PrettyBuiltinDumper.cpp
@@ -20,6 +20,10 @@ BuiltinDumper::BuiltinDumper(LinePrinter &P)
: PDBSymDumper(false), Printer(P) {}
void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) {
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
WithColor(Printer, PDB_ColorItem::Type).get() << getTypeName(Symbol);
}
diff --git a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
index b0c534f7c5b17..9f213a4b4d960 100644
--- a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
+++ b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
@@ -10,22 +10,16 @@
#include "PrettyClassDefinitionDumper.h"
#include "LinePrinter.h"
-#include "PrettyEnumDumper.h"
-#include "PrettyFunctionDumper.h"
-#include "PrettyTypedefDumper.h"
-#include "PrettyVariableDumper.h"
+#include "PrettyClassLayoutGraphicalDumper.h"
+#include "PrettyClassLayoutTextDumper.h"
#include "llvm-pdbdump.h"
-#include "llvm/DebugInfo/PDB/IPDBSession.h"
-#include "llvm/DebugInfo/PDB/PDBExtras.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+
#include "llvm/Support/Format.h"
using namespace llvm;
@@ -35,158 +29,97 @@ ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
: PDBSymDumper(true), Printer(P) {}
void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
- std::string Name = Class.getName();
- WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
- WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
-
- auto Bases = Class.findAllChildren<PDBSymbolTypeBaseClass>();
- if (Bases->getChildCount() > 0) {
- Printer.Indent();
- Printer.NewLine();
- Printer << ":";
- uint32_t BaseIndex = 0;
- while (auto Base = Bases->getNext()) {
- Printer << " ";
- WithColor(Printer, PDB_ColorItem::Keyword).get() << Base->getAccess();
- if (Base->isVirtualBaseClass())
- WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
- WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base->getName();
- if (++BaseIndex < Bases->getChildCount()) {
- Printer.NewLine();
- Printer << ",";
- }
- }
- Printer.Unindent();
- }
-
- Printer << " {";
- auto Children = Class.findAllChildren();
- if (Children->getChildCount() == 0) {
- Printer << "}";
- return;
- }
+ assert(opts::pretty::ClassFormat !=
+ opts::pretty::ClassDefinitionFormat::None);
- // Try to dump symbols organized by member access level. Public members
- // first, then protected, then private. This might be slow, so it's worth
- // reconsidering the value of this if performance of large PDBs is a problem.
- // NOTE: Access level of nested types is not recorded in the PDB, so we have
- // a special case for them.
- SymbolGroupByAccess Groups;
- Groups.insert(std::make_pair(0, SymbolGroup()));
- Groups.insert(std::make_pair((int)PDB_MemberAccess::Private, SymbolGroup()));
- Groups.insert(
- std::make_pair((int)PDB_MemberAccess::Protected, SymbolGroup()));
- Groups.insert(std::make_pair((int)PDB_MemberAccess::Public, SymbolGroup()));
-
- while (auto Child = Children->getNext()) {
- PDB_MemberAccess Access = Child->getRawSymbol().getAccess();
- if (isa<PDBSymbolTypeBaseClass>(*Child))
- continue;
-
- auto &AccessGroup = Groups.find((int)Access)->second;
-
- if (auto Func = dyn_cast<PDBSymbolFunc>(Child.get())) {
- if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
- continue;
- if (Func->getLength() == 0 && !Func->isPureVirtual() &&
- !Func->isIntroVirtualFunction())
- continue;
- Child.release();
- AccessGroup.Functions.push_back(std::unique_ptr<PDBSymbolFunc>(Func));
- } else if (auto Data = dyn_cast<PDBSymbolData>(Child.get())) {
- Child.release();
- AccessGroup.Data.push_back(std::unique_ptr<PDBSymbolData>(Data));
- } else {
- AccessGroup.Unknown.push_back(std::move(Child));
- }
- }
-
- int Count = 0;
- Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0]);
- Count += dumpAccessGroup(PDB_MemberAccess::Public,
- Groups[(int)PDB_MemberAccess::Public]);
- Count += dumpAccessGroup(PDB_MemberAccess::Protected,
- Groups[(int)PDB_MemberAccess::Protected]);
- Count += dumpAccessGroup(PDB_MemberAccess::Private,
- Groups[(int)PDB_MemberAccess::Private]);
- if (Count > 0)
- Printer.NewLine();
- Printer << "}";
+ ClassLayout Layout(Class);
+ start(Layout);
}
-int ClassDefinitionDumper::dumpAccessGroup(PDB_MemberAccess Access,
- const SymbolGroup &Group) {
- if (Group.Functions.empty() && Group.Data.empty() && Group.Unknown.empty())
- return 0;
+void ClassDefinitionDumper::start(const ClassLayout &Layout) {
+ prettyPrintClassIntro(Layout);
- int Count = 0;
- if (Access == PDB_MemberAccess::Private) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "private";
- Printer << ":";
- } else if (Access == PDB_MemberAccess::Protected) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "protected";
- Printer << ":";
- } else if (Access == PDB_MemberAccess::Public) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "public";
- Printer << ":";
+ switch (opts::pretty::ClassFormat) {
+ case opts::pretty::ClassDefinitionFormat::Graphical: {
+ PrettyClassLayoutGraphicalDumper Dumper(Printer, 0);
+ DumpedAnything = Dumper.start(Layout);
+ break;
}
- Printer.Indent();
- for (auto iter = Group.Functions.begin(), end = Group.Functions.end();
- iter != end; ++iter) {
- ++Count;
- (*iter)->dump(*this);
- }
- for (auto iter = Group.Data.begin(), end = Group.Data.end(); iter != end;
- ++iter) {
- ++Count;
- (*iter)->dump(*this);
+ case opts::pretty::ClassDefinitionFormat::Standard:
+ case opts::pretty::ClassDefinitionFormat::Layout: {
+ PrettyClassLayoutTextDumper Dumper(Printer);
+ DumpedAnything |= Dumper.start(Layout);
+ break;
}
- for (auto iter = Group.Unknown.begin(), end = Group.Unknown.end();
- iter != end; ++iter) {
- ++Count;
- (*iter)->dump(*this);
+ default:
+ llvm_unreachable("Unreachable!");
}
- Printer.Unindent();
- return Count;
-}
-
-void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
-void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
- VariableDumper Dumper(Printer);
- Dumper.start(Symbol);
+ prettyPrintClassOutro(Layout);
}
-void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) {
- if (Printer.IsSymbolExcluded(Symbol.getName()))
- return;
+static void printBase(LinePrinter &Printer, const PDBSymbolTypeBaseClass &Base,
+ uint32_t &CurIndex, uint32_t TotalBaseCount,
+ bool IsVirtual) {
+ Printer << " ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess();
+ if (IsVirtual)
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
+ WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName();
+ if (++CurIndex < TotalBaseCount) {
+ Printer.NewLine();
+ Printer << ",";
+ }
+}
+void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) {
+ DumpedAnything = false;
Printer.NewLine();
- FunctionDumper Dumper(Printer);
- Dumper.start(Symbol, FunctionDumper::PointerType::None);
-}
-void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {}
+ uint32_t Size = Layout.getClassSize();
+ const PDBSymbolTypeUDT &Class = Layout.getClass();
-void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
+ WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size
+ << "]";
+ uint32_t BaseCount = Layout.bases().size();
+ uint32_t VBaseCount = Layout.vbases().size();
+ uint32_t TotalBaseCount = BaseCount + VBaseCount;
+ if (TotalBaseCount > 0) {
+ Printer.Indent();
+ Printer.NewLine();
+ Printer << ":";
+ uint32_t BaseIndex = 0;
+ for (auto BC : Layout.bases()) {
+ const auto &Base = BC->getBase();
+ printBase(Printer, Base, BaseIndex, TotalBaseCount, false);
+ }
+ for (auto &BC : Layout.vbases()) {
+ printBase(Printer, *BC, BaseIndex, TotalBaseCount, true);
+ }
- Printer.NewLine();
- EnumDumper Dumper(Printer);
- Dumper.start(Symbol);
-}
+ Printer.Unindent();
+ }
-void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
+ Printer << " {";
+ Printer.Indent();
+}
+void ClassDefinitionDumper::prettyPrintClassOutro(const ClassLayout &Layout) {
+ Printer.Unindent();
+ if (DumpedAnything)
+ Printer.NewLine();
+ Printer << "}";
Printer.NewLine();
- TypedefDumper Dumper(Printer);
- Dumper.start(Symbol);
+ if (Layout.deepPaddingSize() > 0) {
+ APFloat Pct(100.0 * (double)Layout.deepPaddingSize() /
+ (double)Layout.getClassSize());
+ SmallString<8> PctStr;
+ Pct.toString(PctStr, 4);
+ WithColor(Printer, PDB_ColorItem::Padding).get()
+ << "Total padding " << Layout.deepPaddingSize() << " bytes (" << PctStr
+ << "% of class size)";
+ Printer.NewLine();
+ }
}
-
-void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
diff --git a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h
index 0831f47557ed6..0e27733b3ccb9 100644
--- a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h
+++ b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h
@@ -10,6 +10,8 @@
#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H
#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H
+#include "llvm/ADT/BitVector.h"
+
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
@@ -19,44 +21,26 @@
#include <unordered_map>
namespace llvm {
+class BitVector;
+
namespace pdb {
+class ClassLayout;
class LinePrinter;
class ClassDefinitionDumper : public PDBSymDumper {
public:
ClassDefinitionDumper(LinePrinter &P);
- void start(const PDBSymbolTypeUDT &Exe);
-
- void dump(const PDBSymbolTypeBaseClass &Symbol) override;
- void dump(const PDBSymbolData &Symbol) override;
- void dump(const PDBSymbolTypeEnum &Symbol) override;
- void dump(const PDBSymbolFunc &Symbol) override;
- void dump(const PDBSymbolTypeTypedef &Symbol) override;
- void dump(const PDBSymbolTypeUDT &Symbol) override;
- void dump(const PDBSymbolTypeVTable &Symbol) override;
+ void start(const PDBSymbolTypeUDT &Class);
+ void start(const ClassLayout &Class);
private:
- LinePrinter &Printer;
+ void prettyPrintClassIntro(const ClassLayout &Class);
+ void prettyPrintClassOutro(const ClassLayout &Class);
- struct SymbolGroup {
- SymbolGroup() {}
- SymbolGroup(SymbolGroup &&Other) {
- Functions = std::move(Other.Functions);
- Data = std::move(Other.Data);
- Unknown = std::move(Other.Unknown);
- }
-
- std::list<std::unique_ptr<PDBSymbolFunc>> Functions;
- std::list<std::unique_ptr<PDBSymbolData>> Data;
- std::list<std::unique_ptr<PDBSymbol>> Unknown;
- SymbolGroup(const SymbolGroup &other) = delete;
- SymbolGroup &operator=(const SymbolGroup &other) = delete;
- };
- typedef std::unordered_map<int, SymbolGroup> SymbolGroupByAccess;
-
- int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group);
+ bool DumpedAnything = false;
+ LinePrinter &Printer;
};
}
}
diff --git a/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp
new file mode 100644
index 0000000000000..d146ca9d47121
--- /dev/null
+++ b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp
@@ -0,0 +1,151 @@
+//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyClassLayoutGraphicalDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyClassDefinitionDumper.h"
+#include "PrettyVariableDumper.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
+ LinePrinter &P, uint32_t InitialOffset)
+ : PDBSymDumper(true), Printer(P), ClassOffsetZero(InitialOffset),
+ CurrentAbsoluteOffset(InitialOffset) {}
+
+bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) {
+ const BitVector &UseMap = Layout.usedBytes();
+ int NextPaddingByte = UseMap.find_first_unset();
+
+ for (auto &Item : Layout.layout_items()) {
+ // Calculate the absolute offset of the first byte of the next field.
+ uint32_t RelativeOffset = Item->getOffsetInParent();
+ CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset;
+
+ // Since there is storage there, it should be set! However, this might
+ // be an empty base, in which case it could extend outside the bounds of
+ // the parent class.
+ if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) {
+ assert(UseMap.test(RelativeOffset));
+
+ // If there is any remaining padding in this class, and the offset of the
+ // new item is after the padding, then we must have just jumped over some
+ // padding. Print a padding row and then look for where the next block
+ // of padding begins.
+ if ((NextPaddingByte >= 0) &&
+ (RelativeOffset > uint32_t(NextPaddingByte))) {
+ printPaddingRow(RelativeOffset - NextPaddingByte);
+ NextPaddingByte = UseMap.find_next_unset(RelativeOffset);
+ }
+ }
+
+ CurrentItem = Item.get();
+ Item->getSymbol().dump(*this);
+ }
+
+ if (NextPaddingByte >= 0 && Layout.getClassSize() > 1) {
+ uint32_t Amount = Layout.getClassSize() - NextPaddingByte;
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
+ << " bytes)";
+ DumpedAnything = true;
+ }
+
+ return DumpedAnything;
+}
+
+void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) {
+ if (Amount == 0)
+ return;
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
+ << " bytes)";
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(
+ const PDBSymbolTypeBaseClass &Symbol) {
+ assert(CurrentItem != nullptr);
+
+ Printer.NewLine();
+ BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem);
+
+ std::string Label = Layout.isVirtualBase() ? "vbase" : "base";
+ Printer << Label << " ";
+
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(CurrentAbsoluteOffset, 4)
+ << " [sizeof=" << Layout.getSize() << "] ";
+
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName();
+
+ Printer.Indent();
+ uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
+ PrettyClassLayoutGraphicalDumper BaseDumper(Printer, ChildOffsetZero);
+ BaseDumper.start(Layout);
+ Printer.Unindent();
+
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {
+ assert(CurrentItem != nullptr);
+
+ DataMemberLayoutItem &Layout =
+ static_cast<DataMemberLayoutItem &>(*CurrentItem);
+
+ VariableDumper VarDumper(Printer);
+ VarDumper.start(Symbol, ClassOffsetZero);
+
+ if (Layout.hasUDTLayout()) {
+ Printer.Indent();
+ PrettyClassLayoutGraphicalDumper TypeDumper(Printer, ClassOffsetZero);
+ TypeDumper.start(Layout.getUDTLayout());
+ Printer.Unindent();
+ }
+
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
+ assert(CurrentItem != nullptr);
+
+ VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
+
+ VariableDumper VarDumper(Printer);
+ VarDumper.start(Symbol, ClassOffsetZero);
+
+ Printer.Indent();
+ uint32_t Index = 0;
+ for (auto &Func : Layout.funcs()) {
+ Printer.NewLine();
+ std::string Name = Func->getName();
+ auto ParentClass =
+ unique_dyn_cast<PDBSymbolTypeUDT>(Func->getClassParent());
+ assert(ParentClass);
+ WithColor(Printer, PDB_ColorItem::Address).get() << " [" << Index << "] ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << "&" << ParentClass->getName();
+ Printer << "::";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
+ ++Index;
+ }
+ Printer.Unindent();
+
+ DumpedAnything = true;
+}
diff --git a/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h
new file mode 100644
index 0000000000000..7dfb74c4e14b4
--- /dev/null
+++ b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h
@@ -0,0 +1,47 @@
+//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
+
+#include "llvm/ADT/BitVector.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+namespace pdb {
+
+class UDTLayoutBase;
+class StorageItemBase;
+class LinePrinter;
+
+class PrettyClassLayoutGraphicalDumper : public PDBSymDumper {
+public:
+ PrettyClassLayoutGraphicalDumper(LinePrinter &P, uint32_t InitialOffset);
+
+ bool start(const UDTLayoutBase &Layout);
+
+ void dump(const PDBSymbolTypeBaseClass &Symbol) override;
+ void dump(const PDBSymbolData &Symbol) override;
+ void dump(const PDBSymbolTypeVTable &Symbol) override;
+
+private:
+ void printPaddingRow(uint32_t Amount);
+
+ LinePrinter &Printer;
+
+ StorageItemBase *CurrentItem = nullptr;
+ uint32_t ClassOffsetZero = 0;
+ uint32_t CurrentAbsoluteOffset = 0;
+ bool DumpedAnything = false;
+};
+}
+}
+#endif
diff --git a/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp b/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp
new file mode 100644
index 0000000000000..02f31108b0dfe
--- /dev/null
+++ b/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp
@@ -0,0 +1,119 @@
+//===- PrettyClassLayoutTextDumper.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyClassLayoutTextDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyEnumDumper.h"
+#include "PrettyFunctionDumper.h"
+#include "PrettyTypedefDumper.h"
+#include "PrettyVariableDumper.h"
+#include "llvm-pdbdump.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+PrettyClassLayoutTextDumper::PrettyClassLayoutTextDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+bool PrettyClassLayoutTextDumper::start(const ClassLayout &Layout) {
+ if (opts::pretty::ClassFormat ==
+ opts::pretty::ClassDefinitionFormat::Standard) {
+ for (auto &Other : Layout.other_items())
+ Other->dump(*this);
+ for (auto &Func : Layout.funcs())
+ Func->dump(*this);
+ }
+
+ const BitVector &UseMap = Layout.usedBytes();
+ int NextUnusedByte = Layout.usedBytes().find_first_unset();
+ // Next dump items which affect class layout.
+ for (auto &LayoutItem : Layout.layout_items()) {
+ if (NextUnusedByte >= 0) {
+ // If there are padding bytes remaining, see if this field is the first to
+ // cross a padding boundary, and print a padding field indicator if so.
+ int Off = LayoutItem->getOffsetInParent();
+ if (Off > NextUnusedByte) {
+ uint32_t Amount = Off - NextUnusedByte;
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> ("
+ << Amount << " bytes)";
+ assert(UseMap.find_next(NextUnusedByte) == Off);
+ NextUnusedByte = UseMap.find_next_unset(Off);
+ }
+ }
+ LayoutItem->getSymbol().dump(*this);
+ }
+
+ if (NextUnusedByte >= 0 && Layout.getClassSize() > 1) {
+ uint32_t Amount = Layout.getClassSize() - NextUnusedByte;
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
+ << " bytes)";
+ DumpedAnything = true;
+ }
+
+ return DumpedAnything;
+}
+
+void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
+
+void PrettyClassLayoutTextDumper::dump(const PDBSymbolData &Symbol) {
+ VariableDumper Dumper(Printer);
+ Dumper.start(Symbol);
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutTextDumper::dump(const PDBSymbolFunc &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+ if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
+ return;
+ if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
+ !Symbol.isIntroVirtualFunction())
+ return;
+
+ DumpedAnything = true;
+ Printer.NewLine();
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, FunctionDumper::PointerType::None);
+}
+
+void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeVTable &Symbol) {
+ VariableDumper Dumper(Printer);
+ Dumper.start(Symbol);
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ DumpedAnything = true;
+ Printer.NewLine();
+ EnumDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ DumpedAnything = true;
+ Printer.NewLine();
+ TypedefDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
diff --git a/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h b/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h
new file mode 100644
index 0000000000000..56c20f0e84336
--- /dev/null
+++ b/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h
@@ -0,0 +1,44 @@
+//===- PrettyClassLayoutTextDumper.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTTEXTDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTTEXTDUMPER_H
+
+#include "llvm/ADT/BitVector.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+namespace pdb {
+
+class ClassLayout;
+class LinePrinter;
+
+class PrettyClassLayoutTextDumper : public PDBSymDumper {
+public:
+ PrettyClassLayoutTextDumper(LinePrinter &P);
+
+ bool start(const ClassLayout &Layout);
+
+ void dump(const PDBSymbolTypeBaseClass &Symbol) override;
+ void dump(const PDBSymbolData &Symbol) override;
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolFunc &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+ void dump(const PDBSymbolTypeVTable &Symbol) override;
+
+private:
+ bool DumpedAnything = false;
+ LinePrinter &Printer;
+};
+}
+}
+#endif
diff --git a/tools/llvm-pdbdump/PrettyFunctionDumper.cpp b/tools/llvm-pdbdump/PrettyFunctionDumper.cpp
index 2f6ca894fadf3..b0be33c157ce6 100644
--- a/tools/llvm-pdbdump/PrettyFunctionDumper.cpp
+++ b/tools/llvm-pdbdump/PrettyFunctionDumper.cpp
@@ -195,10 +195,7 @@ void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) {
}
void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) {
- uint32_t ElementTypeId = Symbol.getTypeId();
- auto ElementType = Symbol.getSession().getSymbolById(ElementTypeId);
- if (!ElementType)
- return;
+ auto ElementType = Symbol.getElementType();
ElementType->dump(*this);
Printer << "[";
@@ -232,12 +229,11 @@ void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
}
void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) {
- uint32_t PointeeId = Symbol.getTypeId();
- auto PointeeType = Symbol.getSession().getSymbolById(PointeeId);
+ auto PointeeType = Symbol.getPointeeType();
if (!PointeeType)
return;
- if (auto FuncSig = dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
FunctionDumper NestedDumper(Printer);
PointerType Pointer =
Symbol.isReference() ? PointerType::Reference : PointerType::Pointer;
diff --git a/tools/llvm-pdbdump/PrettyTypeDumper.cpp b/tools/llvm-pdbdump/PrettyTypeDumper.cpp
index 4f70c8047337a..ffeef72150d26 100644
--- a/tools/llvm-pdbdump/PrettyTypeDumper.cpp
+++ b/tools/llvm-pdbdump/PrettyTypeDumper.cpp
@@ -22,45 +22,166 @@
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/FormatVariadic.h"
using namespace llvm;
using namespace llvm::pdb;
+using LayoutPtr = std::unique_ptr<ClassLayout>;
+
+typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
+
+static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->getUDTName() < S2->getUDTName();
+}
+
+static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->getClassSize() < S2->getClassSize();
+}
+
+static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->deepPaddingSize() < S2->deepPaddingSize();
+}
+
+static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
+ switch (Mode) {
+ case opts::pretty::ClassSortMode::Name:
+ return CompareNames;
+ case opts::pretty::ClassSortMode::Size:
+ return CompareSizes;
+ case opts::pretty::ClassSortMode::Padding:
+ return ComparePadding;
+ default:
+ return nullptr;
+ }
+}
+
+template <typename Enumerator>
+static std::vector<std::unique_ptr<ClassLayout>>
+filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
+ uint32_t UnfilteredCount) {
+ std::vector<std::unique_ptr<ClassLayout>> Filtered;
+
+ Filtered.reserve(UnfilteredCount);
+ CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
+
+ uint32_t Examined = 0;
+ uint32_t Discarded = 0;
+ while (auto Class = E.getNext()) {
+ ++Examined;
+ if (Examined % 10000 == 0) {
+ outs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
+ Examined, UnfilteredCount, Discarded);
+ outs().flush();
+ }
+
+ if (Class->getUnmodifiedTypeId() != 0) {
+ ++Discarded;
+ continue;
+ }
+
+ if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
+ ++Discarded;
+ continue;
+ }
+
+ auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
+ if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
+ ++Discarded;
+ continue;
+ }
+
+ Filtered.push_back(std::move(Layout));
+ }
+
+ if (Comp)
+ std::sort(Filtered.begin(), Filtered.end(), Comp);
+ return Filtered;
+}
+
TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
void TypeDumper::start(const PDBSymbolExe &Exe) {
- auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>();
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
- Printer << ": (" << Enums->getChildCount() << " items)";
- Printer.Indent();
- while (auto Enum = Enums->getNext())
- Enum->dump(*this);
- Printer.Unindent();
-
- auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>();
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
- Printer << ": (" << Typedefs->getChildCount() << " items)";
- Printer.Indent();
- while (auto Typedef = Typedefs->getNext())
- Typedef->dump(*this);
- Printer.Unindent();
-
- auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>();
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
- Printer << ": (" << Classes->getChildCount() << " items)";
- Printer.Indent();
- while (auto Class = Classes->getNext())
- Class->dump(*this);
- Printer.Unindent();
+ if (opts::pretty::Enums) {
+ auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>();
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
+ Printer << ": (" << Enums->getChildCount() << " items)";
+ Printer.Indent();
+ while (auto Enum = Enums->getNext())
+ Enum->dump(*this);
+ Printer.Unindent();
+ }
+
+ if (opts::pretty::Typedefs) {
+ auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>();
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
+ Printer << ": (" << Typedefs->getChildCount() << " items)";
+ Printer.Indent();
+ while (auto Typedef = Typedefs->getNext())
+ Typedef->dump(*this);
+ Printer.Unindent();
+ }
+
+ if (opts::pretty::Classes) {
+ auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>();
+ uint32_t All = Classes->getChildCount();
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
+
+ bool Precompute = false;
+ Precompute =
+ (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
+
+ // If we're using no sort mode, then we can start getting immediate output
+ // from the tool by just filtering as we go, rather than processing
+ // everything up front so that we can sort it. This makes the tool more
+ // responsive. So only precompute the filtered/sorted set of classes if
+ // necessary due to the specified options.
+ std::vector<LayoutPtr> Filtered;
+ uint32_t Shown = All;
+ if (Precompute) {
+ Filtered = filterAndSortClassDefs(Printer, *Classes, All);
+
+ Shown = Filtered.size();
+ }
+
+ Printer << ": (Showing " << Shown << " items";
+ if (Shown < All)
+ Printer << ", " << (All - Shown) << " filtered";
+ Printer << ")";
+ Printer.Indent();
+
+ // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
+ // the DIA enumerator and filter on the fly.
+ if (Precompute) {
+ for (auto &Class : Filtered)
+ dumpClassLayout(*Class);
+ } else {
+ while (auto Class = Classes->getNext()) {
+ if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
+ continue;
+
+ auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
+ if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
+ continue;
+
+ dumpClassLayout(*Layout);
+ }
+ }
+
+ Printer.Unindent();
+ }
}
void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
- if (Symbol.getUnmodifiedTypeId() != 0)
- return;
- if (Printer.IsTypeExcluded(Symbol.getName()))
+ assert(opts::pretty::Enums);
+
+ if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
return;
// Dump member enums when dumping their class definition.
if (nullptr != Symbol.getClassParent())
@@ -72,7 +193,9 @@ void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
}
void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
- if (Printer.IsTypeExcluded(Symbol.getName()))
+ assert(opts::pretty::Typedefs);
+
+ if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
return;
Printer.NewLine();
@@ -80,19 +203,15 @@ void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
Dumper.start(Symbol);
}
-void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
- if (Symbol.getUnmodifiedTypeId() != 0)
- return;
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
-
- Printer.NewLine();
+void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
+ assert(opts::pretty::Classes);
- if (opts::pretty::NoClassDefs) {
+ if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
+ Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
- WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getUDTName();
} else {
ClassDefinitionDumper Dumper(Printer);
- Dumper.start(Symbol);
+ Dumper.start(Class);
}
}
diff --git a/tools/llvm-pdbdump/PrettyTypeDumper.h b/tools/llvm-pdbdump/PrettyTypeDumper.h
index f9d8304c3208e..68a2f0246ebae 100644
--- a/tools/llvm-pdbdump/PrettyTypeDumper.h
+++ b/tools/llvm-pdbdump/PrettyTypeDumper.h
@@ -15,6 +15,7 @@
namespace llvm {
namespace pdb {
class LinePrinter;
+class ClassLayout;
class TypeDumper : public PDBSymDumper {
public:
@@ -24,7 +25,8 @@ public:
void dump(const PDBSymbolTypeEnum &Symbol) override;
void dump(const PDBSymbolTypeTypedef &Symbol) override;
- void dump(const PDBSymbolTypeUDT &Symbol) override;
+
+ void dumpClassLayout(const ClassLayout &Class);
private:
LinePrinter &Printer;
diff --git a/tools/llvm-pdbdump/PrettyTypedefDumper.cpp b/tools/llvm-pdbdump/PrettyTypedefDumper.cpp
index c458755cb7806..2d8e915d76043 100644
--- a/tools/llvm-pdbdump/PrettyTypedefDumper.cpp
+++ b/tools/llvm-pdbdump/PrettyTypedefDumper.cpp
@@ -53,11 +53,8 @@ void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) {
WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
if (Symbol.isVolatileType())
WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
- uint32_t PointeeId = Symbol.getTypeId();
- auto PointeeType = Symbol.getSession().getSymbolById(PointeeId);
- if (!PointeeType)
- return;
- if (auto FuncSig = dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
+ auto PointeeType = Symbol.getPointeeType();
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer;
if (Symbol.isReference())
Pointer = FunctionDumper::PointerType::Reference;
diff --git a/tools/llvm-pdbdump/PrettyVariableDumper.cpp b/tools/llvm-pdbdump/PrettyVariableDumper.cpp
index e1469186ad8b5..76a0d23bf87a4 100644
--- a/tools/llvm-pdbdump/PrettyVariableDumper.cpp
+++ b/tools/llvm-pdbdump/PrettyVariableDumper.cpp
@@ -14,6 +14,7 @@
#include "PrettyFunctionDumper.h"
#include "llvm-pdbdump.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
@@ -23,16 +24,18 @@
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
#include "llvm/Support/Format.h"
using namespace llvm;
+using namespace llvm::codeview;
using namespace llvm::pdb;
VariableDumper::VariableDumper(LinePrinter &P)
: PDBSymDumper(true), Printer(P) {}
-void VariableDumper::start(const PDBSymbolData &Var) {
+void VariableDumper::start(const PDBSymbolData &Var, uint32_t Offset) {
if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
return;
if (Printer.IsSymbolExcluded(Var.getName()))
@@ -40,13 +43,15 @@ void VariableDumper::start(const PDBSymbolData &Var) {
auto VarType = Var.getType();
+ uint64_t Length = VarType->getRawSymbol().getLength();
+
switch (auto LocType = Var.getLocationType()) {
case PDB_LocType::Static:
Printer.NewLine();
Printer << "data [";
WithColor(Printer, PDB_ColorItem::Address).get()
<< format_hex(Var.getVirtualAddress(), 10);
- Printer << "] ";
+ Printer << ", sizeof=" << Length << "] ";
WithColor(Printer, PDB_ColorItem::Keyword).get() << "static ";
dumpSymbolTypeAndName(*VarType, Var.getName());
break;
@@ -54,8 +59,7 @@ void VariableDumper::start(const PDBSymbolData &Var) {
if (isa<PDBSymbolTypeEnum>(*VarType))
break;
Printer.NewLine();
- Printer << "data ";
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ Printer << "data [sizeof=" << Length << "] ";
dumpSymbolTypeAndName(*VarType, Var.getName());
Printer << " = ";
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue();
@@ -64,27 +68,57 @@ void VariableDumper::start(const PDBSymbolData &Var) {
Printer.NewLine();
Printer << "data ";
WithColor(Printer, PDB_ColorItem::Offset).get()
- << "+" << format_hex(Var.getOffset(), 4) << " ";
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << Length << "] ";
dumpSymbolTypeAndName(*VarType, Var.getName());
break;
case PDB_LocType::BitField:
Printer.NewLine();
Printer << "data ";
WithColor(Printer, PDB_ColorItem::Offset).get()
- << "+" << format_hex(Var.getOffset(), 4) << " ";
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << Length << "] ";
dumpSymbolTypeAndName(*VarType, Var.getName());
Printer << " : ";
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength();
break;
default:
Printer.NewLine();
- Printer << "data ";
+ Printer << "data [sizeof=" << Length << "] ";
Printer << "unknown(" << LocType << ") ";
WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName();
break;
}
}
+void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) {
+ Printer.NewLine();
+ Printer << "vfptr ";
+ auto VTableType = cast<PDBSymbolTypePointer>(Var.getType());
+ uint32_t PointerSize = VTableType->getLength();
+
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << PointerSize << "] ";
+}
+
+void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) {
+ auto ElementType = Symbol.getElementType();
+ assert(ElementType);
+ if (!ElementType)
+ return;
+ ElementType->dump(*this);
+}
+
+void VariableDumper::dumpRight(const PDBSymbolTypeArray &Symbol) {
+ auto ElementType = Symbol.getElementType();
+ assert(ElementType);
+ if (!ElementType)
+ return;
+ Printer << '[' << Symbol.getCount() << ']';
+ ElementType->dumpRight(*this);
+}
+
void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
BuiltinDumper Dumper(Printer);
Dumper.start(Symbol);
@@ -94,27 +128,71 @@ void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) {
WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
}
-void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {}
+void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
+ auto ReturnType = Symbol.getReturnType();
+ ReturnType->dump(*this);
+ Printer << " ";
+
+ uint32_t ClassParentId = Symbol.getClassParentId();
+ auto ClassParent =
+ Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>(
+ ClassParentId);
+
+ if (ClassParent) {
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << ClassParent->getName();
+ Printer << "::";
+ }
+}
+
+void VariableDumper::dumpRight(const PDBSymbolTypeFunctionSig &Symbol) {
+ Printer << "(";
+ if (auto Arguments = Symbol.getArguments()) {
+ uint32_t Index = 0;
+ while (auto Arg = Arguments->getNext()) {
+ Arg->dump(*this);
+ if (++Index < Arguments->getChildCount())
+ Printer << ", ";
+ }
+ }
+ Printer << ")";
+
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
+}
void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) {
auto PointeeType = Symbol.getPointeeType();
if (!PointeeType)
return;
+ PointeeType->dump(*this);
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
+ // A hack to get the calling convention in the right spot.
+ Printer << " (";
+ PDB_CallingConv CC = FuncSig->getCallingConvention();
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
+ } else if (isa<PDBSymbolTypeArray>(PointeeType)) {
+ Printer << " (";
+ }
+ Printer << (Symbol.isReference() ? "&" : "*");
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile ";
+}
- if (auto Func = dyn_cast<PDBSymbolFunc>(PointeeType.get())) {
- FunctionDumper NestedDumper(Printer);
- FunctionDumper::PointerType Pointer =
- Symbol.isReference() ? FunctionDumper::PointerType::Reference
- : FunctionDumper::PointerType::Pointer;
- NestedDumper.start(*Func, Pointer);
- } else {
- if (Symbol.isConstType())
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
- if (Symbol.isVolatileType())
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
- PointeeType->dump(*this);
- Printer << (Symbol.isReference() ? "&" : "*");
+void VariableDumper::dumpRight(const PDBSymbolTypePointer &Symbol) {
+ auto PointeeType = Symbol.getPointeeType();
+ assert(PointeeType);
+ if (!PointeeType)
+ return;
+ if (isa<PDBSymbolTypeFunctionSig>(PointeeType) ||
+ isa<PDBSymbolTypeArray>(PointeeType)) {
+ Printer << ")";
}
+ PointeeType->dumpRight(*this);
}
void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
@@ -128,44 +206,7 @@ void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) {
void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type,
StringRef Name) {
- if (auto *ArrayType = dyn_cast<PDBSymbolTypeArray>(&Type)) {
- std::string IndexSpec;
- raw_string_ostream IndexStream(IndexSpec);
- std::unique_ptr<PDBSymbol> ElementType = ArrayType->getElementType();
- while (auto NestedArray = dyn_cast<PDBSymbolTypeArray>(ElementType.get())) {
- IndexStream << "[";
- IndexStream << NestedArray->getCount();
- IndexStream << "]";
- ElementType = NestedArray->getElementType();
- }
- IndexStream << "[" << ArrayType->getCount() << "]";
- ElementType->dump(*this);
- WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
- Printer << IndexStream.str();
- } else {
- if (!tryDumpFunctionPointer(Type, Name)) {
- Type.dump(*this);
- WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
- }
- }
-}
-
-bool VariableDumper::tryDumpFunctionPointer(const PDBSymbol &Type,
- StringRef Name) {
- // Function pointers come across as pointers to function signatures. But the
- // signature carries no name, so we have to handle this case separately.
- if (auto *PointerType = dyn_cast<PDBSymbolTypePointer>(&Type)) {
- auto PointeeType = PointerType->getPointeeType();
- if (auto *FunctionSig =
- dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
- FunctionDumper Dumper(Printer);
- FunctionDumper::PointerType PT = FunctionDumper::PointerType::Pointer;
- if (PointerType->isReference())
- PT = FunctionDumper::PointerType::Reference;
- std::string NameStr(Name.begin(), Name.end());
- Dumper.start(*FunctionSig, NameStr.c_str(), PT);
- return true;
- }
- }
- return false;
+ Type.dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
+ Type.dumpRight(*this);
}
diff --git a/tools/llvm-pdbdump/PrettyVariableDumper.h b/tools/llvm-pdbdump/PrettyVariableDumper.h
index a122bb86058cf..4ba3bc97d85b6 100644
--- a/tools/llvm-pdbdump/PrettyVariableDumper.h
+++ b/tools/llvm-pdbdump/PrettyVariableDumper.h
@@ -24,8 +24,10 @@ class VariableDumper : public PDBSymDumper {
public:
VariableDumper(LinePrinter &P);
- void start(const PDBSymbolData &Var);
+ void start(const PDBSymbolData &Var, uint32_t Offset = 0);
+ void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0);
+ void dump(const PDBSymbolTypeArray &Symbol) override;
void dump(const PDBSymbolTypeBuiltin &Symbol) override;
void dump(const PDBSymbolTypeEnum &Symbol) override;
void dump(const PDBSymbolTypeFunctionSig &Symbol) override;
@@ -33,9 +35,12 @@ public:
void dump(const PDBSymbolTypeTypedef &Symbol) override;
void dump(const PDBSymbolTypeUDT &Symbol) override;
+ void dumpRight(const PDBSymbolTypeArray &Symbol) override;
+ void dumpRight(const PDBSymbolTypeFunctionSig &Symbol) override;
+ void dumpRight(const PDBSymbolTypePointer &Symbol) override;
+
private:
void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name);
- bool tryDumpFunctionPointer(const PDBSymbol &Type, StringRef Name);
LinePrinter &Printer;
};
diff --git a/tools/llvm-pdbdump/StreamUtil.cpp b/tools/llvm-pdbdump/StreamUtil.cpp
new file mode 100644
index 0000000000000..db1e01aa01543
--- /dev/null
+++ b/tools/llvm-pdbdump/StreamUtil.cpp
@@ -0,0 +1,136 @@
+//===- StreamUtil.cpp - PDB stream utilities --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StreamUtil.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModInfo.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+namespace llvm {
+namespace pdb {
+void discoverStreamPurposes(PDBFile &File,
+ SmallVectorImpl<std::string> &Purposes) {
+
+ // It's OK if we fail to load some of these streams, we still attempt to print
+ // what we can.
+ auto Dbi = File.getPDBDbiStream();
+ auto Tpi = File.getPDBTpiStream();
+ auto Ipi = File.getPDBIpiStream();
+ auto Info = File.getPDBInfoStream();
+
+ uint32_t StreamCount = File.getNumStreams();
+ DenseMap<uint16_t, const ModuleInfoEx *> ModStreams;
+ DenseMap<uint16_t, std::string> NamedStreams;
+
+ if (Dbi) {
+ for (auto &ModI : Dbi->modules()) {
+ uint16_t SN = ModI.Info.getModuleStreamIndex();
+ if (SN != kInvalidStreamIndex)
+ ModStreams[SN] = &ModI;
+ }
+ }
+ if (Info) {
+ for (auto &NSE : Info->named_streams()) {
+ if (NSE.second != kInvalidStreamIndex)
+ NamedStreams[NSE.second] = NSE.first();
+ }
+ }
+
+ Purposes.resize(StreamCount);
+ for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
+ std::string Value;
+ if (StreamIdx == OldMSFDirectory)
+ Value = "Old MSF Directory";
+ else if (StreamIdx == StreamPDB)
+ Value = "PDB Stream";
+ else if (StreamIdx == StreamDBI)
+ Value = "DBI Stream";
+ else if (StreamIdx == StreamTPI)
+ Value = "TPI Stream";
+ else if (StreamIdx == StreamIPI)
+ Value = "IPI Stream";
+ else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
+ Value = "Global Symbol Hash";
+ else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
+ Value = "Public Symbol Hash";
+ else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
+ Value = "Public Symbol Records";
+ else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
+ Value = "TPI Hash";
+ else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
+ Value = "TPI Aux Hash";
+ else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
+ Value = "IPI Hash";
+ else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
+ Value = "IPI Aux Hash";
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
+ Value = "Exception Data";
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
+ Value = "Fixup Data";
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
+ Value = "FPO Data";
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
+ Value = "New FPO Data";
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
+ Value = "Omap From Source Data";
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
+ Value = "Omap To Source Data";
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
+ Value = "Pdata";
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
+ Value = "Section Header Data";
+ else if (Dbi &&
+ StreamIdx ==
+ Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
+ Value = "Section Header Original Data";
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
+ Value = "Token Rid Data";
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
+ Value = "Xdata";
+ else {
+ auto ModIter = ModStreams.find(StreamIdx);
+ auto NSIter = NamedStreams.find(StreamIdx);
+ if (ModIter != ModStreams.end()) {
+ Value = "Module \"";
+ Value += ModIter->second->Info.getModuleName().str();
+ Value += "\"";
+ } else if (NSIter != NamedStreams.end()) {
+ Value = "Named Stream \"";
+ Value += NSIter->second;
+ Value += "\"";
+ } else {
+ Value = "???";
+ }
+ }
+ Purposes[StreamIdx] = Value;
+ }
+
+ // Consume errors from missing streams.
+ if (!Dbi)
+ consumeError(Dbi.takeError());
+ if (!Tpi)
+ consumeError(Tpi.takeError());
+ if (!Ipi)
+ consumeError(Ipi.takeError());
+ if (!Info)
+ consumeError(Info.takeError());
+}
+}
+}
diff --git a/tools/llvm-pdbdump/StreamUtil.h b/tools/llvm-pdbdump/StreamUtil.h
new file mode 100644
index 0000000000000..b5c0beba44fed
--- /dev/null
+++ b/tools/llvm-pdbdump/StreamUtil.h
@@ -0,0 +1,25 @@
+//===- Streamutil.h - PDB stream utilities ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H
+#define LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <string>
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+void discoverStreamPurposes(PDBFile &File,
+ SmallVectorImpl<std::string> &Purposes);
+}
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/tools/llvm-pdbdump/YAMLOutputStyle.cpp
index 3f2733d701a85..5b53d2137166a 100644
--- a/tools/llvm-pdbdump/YAMLOutputStyle.cpp
+++ b/tools/llvm-pdbdump/YAMLOutputStyle.cpp
@@ -13,18 +13,20 @@
#include "llvm-pdbdump.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
-#include "llvm/DebugInfo/PDB/Raw/ModStream.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
using namespace llvm;
using namespace llvm::pdb;
YAMLOutputStyle::YAMLOutputStyle(PDBFile &File)
- : File(File), Out(outs()), Obj(File.getAllocator()) {}
+ : File(File), Out(outs()), Obj(File.getAllocator()) {
+ Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal);
+}
Error YAMLOutputStyle::dump() {
if (opts::pdb2yaml::StreamDirectory)
@@ -45,6 +47,9 @@ Error YAMLOutputStyle::dump() {
if (auto EC = dumpStreamDirectory())
return EC;
+ if (auto EC = dumpStringTable())
+ return EC;
+
if (auto EC = dumpPDBStream())
return EC;
@@ -83,6 +88,24 @@ Error YAMLOutputStyle::dumpFileHeaders() {
return Error::success();
}
+Error YAMLOutputStyle::dumpStringTable() {
+ if (!opts::pdb2yaml::StringTable)
+ return Error::success();
+
+ Obj.StringTable.emplace();
+ auto ExpectedST = File.getStringTable();
+ if (!ExpectedST)
+ return ExpectedST.takeError();
+
+ const auto &ST = ExpectedST.get();
+ for (auto ID : ST.name_ids()) {
+ StringRef S = ST.getStringForID(ID);
+ if (!S.empty())
+ Obj.StringTable->push_back(S);
+ }
+ return Error::success();
+}
+
Error YAMLOutputStyle::dumpStreamMetadata() {
if (!opts::pdb2yaml::StreamMetadata)
return Error::success();
@@ -122,12 +145,7 @@ Error YAMLOutputStyle::dumpPDBStream() {
Obj.PdbStream->Guid = InfoS.getGuid();
Obj.PdbStream->Signature = InfoS.getSignature();
Obj.PdbStream->Version = InfoS.getVersion();
- for (auto &NS : InfoS.named_streams()) {
- yaml::NamedStreamMapping Mapping;
- Mapping.StreamName = NS.getKey();
- Mapping.StreamNumber = NS.getValue();
- Obj.PdbStream->NamedStreams.push_back(Mapping);
- }
+ Obj.PdbStream->Features = InfoS.getFeatureSignatures();
return Error::success();
}
diff --git a/tools/llvm-pdbdump/YAMLOutputStyle.h b/tools/llvm-pdbdump/YAMLOutputStyle.h
index 3cd603a95b6a3..db9868db4a7e1 100644
--- a/tools/llvm-pdbdump/YAMLOutputStyle.h
+++ b/tools/llvm-pdbdump/YAMLOutputStyle.h
@@ -26,6 +26,7 @@ public:
Error dump() override;
private:
+ Error dumpStringTable();
Error dumpFileHeaders();
Error dumpStreamMetadata();
Error dumpStreamDirectory();
diff --git a/tools/llvm-pdbdump/YamlSymbolDumper.cpp b/tools/llvm-pdbdump/YamlSymbolDumper.cpp
index 210260a03b5fc..431bf404fb040 100644
--- a/tools/llvm-pdbdump/YamlSymbolDumper.cpp
+++ b/tools/llvm-pdbdump/YamlSymbolDumper.cpp
@@ -113,6 +113,7 @@ template <> struct ScalarEnumerationTraits<RegisterId> {
for (const auto &E : RegNames) {
io.enumCase(Reg, E.Name.str().c_str(), static_cast<RegisterId>(E.Value));
}
+ io.enumFallback<Hex16>(Reg);
}
};
diff --git a/tools/llvm-pdbdump/YamlTypeDumper.cpp b/tools/llvm-pdbdump/YamlTypeDumper.cpp
index 5c527c71c7e44..b4eb197e866a4 100644
--- a/tools/llvm-pdbdump/YamlTypeDumper.cpp
+++ b/tools/llvm-pdbdump/YamlTypeDumper.cpp
@@ -17,7 +17,7 @@
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -194,6 +194,13 @@ template <> struct ScalarEnumerationTraits<WindowsRTClassKind> {
}
};
+template <> struct ScalarEnumerationTraits<LabelType> {
+ static void enumeration(IO &IO, LabelType &Value) {
+ IO.enumCase(Value, "Near", LabelType::Near);
+ IO.enumCase(Value, "Far", LabelType::Far);
+ }
+};
+
template <> struct ScalarBitSetTraits<PointerOptions> {
static void bitset(IO &IO, PointerOptions &Options) {
IO.bitSetCase(Options, "None", PointerOptions::None);
@@ -291,7 +298,11 @@ void MappingTraits<StringIdRecord>::mapping(IO &IO, StringIdRecord &String) {
}
void MappingTraits<ArgListRecord>::mapping(IO &IO, ArgListRecord &Args) {
- IO.mapRequired("ArgIndices", Args.StringIndices);
+ IO.mapRequired("ArgIndices", Args.ArgIndices);
+}
+
+void MappingTraits<StringListRecord>::mapping(IO &IO, StringListRecord &Strings) {
+ IO.mapRequired("StringIndices", Strings.StringIndices);
}
void MappingTraits<ClassRecord>::mapping(IO &IO, ClassRecord &Class) {
@@ -427,6 +438,10 @@ void MappingTraits<BuildInfoRecord>::mapping(IO &IO, BuildInfoRecord &Args) {
IO.mapRequired("ArgIndices", Args.ArgIndices);
}
+void MappingTraits<LabelRecord>::mapping(IO &IO, LabelRecord &R) {
+ IO.mapRequired("Mode", R.Mode);
+}
+
void MappingTraits<NestedTypeRecord>::mapping(IO &IO,
NestedTypeRecord &Nested) {
IO.mapRequired("Type", Nested.Type);
@@ -573,8 +588,8 @@ struct MappingContextTraits<pdb::yaml::PdbTpiFieldListRecord,
assert(IO.outputting());
codeview::TypeVisitorCallbackPipeline Pipeline;
- msf::ByteStream Data(Obj.Record.Data);
- msf::StreamReader FieldReader(Data);
+ BinaryByteStream Data(Obj.Record.Data, llvm::support::little);
+ BinaryStreamReader FieldReader(Data);
codeview::FieldListDeserializer Deserializer(FieldReader);
// For PDB to Yaml, deserialize into a high level record type, then dump
diff --git a/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp b/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp
index e818dda32fc02..38eaf16c65b05 100644
--- a/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp
+++ b/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp
@@ -13,7 +13,7 @@
///
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
-#include "llvm/DebugInfo/CodeView/ByteStream.h"
+#include "llvm/DebugInfo/CodeView/BinaryByteStream.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/TypeDumper.h"
#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
@@ -28,14 +28,15 @@
using namespace llvm;
namespace {
-// We need a class which behaves like an immutable ByteStream, but whose data
+// We need a class which behaves like an immutable BinaryByteStream, but whose
+// data
// is backed by an llvm::MemoryBuffer. It also needs to own the underlying
// MemoryBuffer, so this simple adapter is a good way to achieve that.
-class InputByteStream : public codeview::ByteStream<false> {
+class InputByteStream : public codeview::BinaryByteStream<false> {
public:
explicit InputByteStream(std::unique_ptr<MemoryBuffer> Buffer)
- : ByteStream(ArrayRef<uint8_t>(Buffer->getBuffer().bytes_begin(),
- Buffer->getBuffer().bytes_end())),
+ : BinaryByteStream(ArrayRef<uint8_t>(Buffer->getBuffer().bytes_begin(),
+ Buffer->getBuffer().bytes_end())),
MemBuffer(std::move(Buffer)) {}
std::unique_ptr<MemoryBuffer> MemBuffer;
diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp
index d3495e524abcf..06c2afc0bc78a 100644
--- a/tools/llvm-pdbdump/llvm-pdbdump.cpp
+++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp
@@ -7,13 +7,14 @@
//
//===----------------------------------------------------------------------===//
//
-// Dumps debug information present in PDB files. This utility makes use of
-// the Microsoft Windows SDK, so will not compile or run on non-Windows
-// platforms.
+// Dumps debug information present in PDB files.
//
//===----------------------------------------------------------------------===//
#include "llvm-pdbdump.h"
+
+#include "Analyze.h"
+#include "Diff.h"
#include "LLVMOutputStyle.h"
#include "LinePrinter.h"
#include "OutputStyle.h"
@@ -29,29 +30,31 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/PDB/GenericError.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/PDB.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
-#include "llvm/DebugInfo/PDB/Raw/RawError.h"
-#include "llvm/DebugInfo/PDB/Raw/RawSession.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
+#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/COM.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ConvertUTF.h"
@@ -78,6 +81,9 @@ cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file");
cl::SubCommand
PrettySubcommand("pretty",
"Dump semantic information about types and symbols");
+
+cl::SubCommand DiffSubcommand("diff", "Diff the contents of 2 PDB files");
+
cl::SubCommand
YamlToPdbSubcommand("yaml2pdb",
"Generate a PDB file from a YAML description");
@@ -85,8 +91,12 @@ cl::SubCommand
PdbToYamlSubcommand("pdb2yaml",
"Generate a detailed YAML description of a PDB File");
+cl::SubCommand
+ AnalyzeSubcommand("analyze",
+ "Analyze various aspects of a PDB's structure");
+
cl::OptionCategory TypeCategory("Symbol Type Options");
-cl::OptionCategory FilterCategory("Filtering Options");
+cl::OptionCategory FilterCategory("Filtering and Sorting Options");
cl::OptionCategory OtherOptions("Other Options");
namespace pretty {
@@ -102,8 +112,41 @@ cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
-cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory),
- cl::sub(PrettySubcommand));
+cl::opt<bool>
+ Types("types",
+ cl::desc("Display all types (implies -classes, -enums, -typedefs)"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Classes("classes", cl::desc("Display class types"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Enums("enums", cl::desc("Display enum types"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<ClassSortMode> ClassOrder(
+ "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None),
+ cl::values(clEnumValN(ClassSortMode::None, "none",
+ "Undefined / no particular sort order"),
+ clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"),
+ clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"),
+ clEnumValN(ClassSortMode::Padding, "padding",
+ "Sort classes by amount of padding")),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+
+cl::opt<ClassDefinitionFormat> ClassFormat(
+ "class-definitions", cl::desc("Class definition format"),
+ cl::init(ClassDefinitionFormat::Standard),
+ cl::values(
+ clEnumValN(ClassDefinitionFormat::Standard, "all-members",
+ "Display all class members including data, constants, "
+ "typedefs, functions, etc"),
+ clEnumValN(ClassDefinitionFormat::Layout, "layout-members",
+ "Only display members that contribute to class size."),
+ clEnumValN(ClassDefinitionFormat::Graphical, "graphical",
+ "Display graphical representation of each class's layout."),
+ clEnumValN(ClassDefinitionFormat::None, "none",
+ "Don't display class definitions")),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+
cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory),
cl::sub(PrettySubcommand));
cl::opt<bool>
@@ -114,6 +157,12 @@ cl::opt<uint64_t> LoadAddress(
"load-address",
cl::desc("Assume the module is loaded at the specified address"),
cl::cat(OtherOptions), cl::sub(PrettySubcommand));
+cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"),
+ cl::cat(OtherOptions), cl::sub(PrettySubcommand));
+cl::opt<cl::boolOrDefault>
+ ColorOutput("color-output",
+ cl::desc("Override use of color (default = isatty)"),
+ cl::cat(OtherOptions), cl::sub(PrettySubcommand));
cl::list<std::string> ExcludeTypes(
"exclude-types", cl::desc("Exclude types by regular expression"),
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
@@ -136,6 +185,14 @@ cl::list<std::string> IncludeCompilands(
"include-compilands",
cl::desc("Include only compilands those which match a regular expression"),
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::opt<uint32_t> SizeThreshold(
+ "min-type-size", cl::desc("Displays only those types which are greater "
+ "than or equal to the specified size."),
+ cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::opt<uint32_t> PaddingThreshold(
+ "min-class-padding", cl::desc("Displays only those classes which have at "
+ "least the specified amount of padding."),
+ cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
cl::opt<bool> ExcludeCompilerGenerated(
"no-compiler-generated",
@@ -145,14 +202,23 @@ cl::opt<bool>
ExcludeSystemLibraries("no-system-libs",
cl::desc("Don't show symbols from system libraries"),
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-cl::opt<bool> NoClassDefs("no-class-definitions",
- cl::desc("Don't display full class definitions"),
- cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+
cl::opt<bool> NoEnumDefs("no-enum-definitions",
cl::desc("Don't display full enum definitions"),
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
}
+namespace diff {
+cl::opt<bool> Pedantic("pedantic",
+ cl::desc("Finds all differences (even structural ones "
+ "that produce otherwise identical PDBs)"),
+ cl::sub(DiffSubcommand));
+
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<first> <second>"),
+ cl::OneOrMore, cl::sub(DiffSubcommand));
+}
+
namespace raw {
cl::OptionCategory MsfOptions("MSF Container Options");
@@ -187,6 +253,11 @@ cl::list<uint32_t>
// TYPE OPTIONS
cl::opt<bool>
+ CompactRecords("compact-records",
+ cl::desc("Dump type and symbol records with less detail"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
+
+cl::opt<bool>
DumpTpiRecords("tpi-records",
cl::desc("dump CodeView type records from TPI stream"),
cl::cat(TypeOptions), cl::sub(RawSubcommand));
@@ -227,6 +298,9 @@ cl::opt<bool>
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
// MISCELLANEOUS OPTIONS
+cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
+ cl::cat(MiscOptions), cl::sub(RawSubcommand));
+
cl::opt<bool> DumpSectionContribs("section-contribs",
cl::desc("dump section contributions"),
cl::cat(MiscOptions), cl::sub(RawSubcommand));
@@ -262,6 +336,9 @@ cl::opt<bool>
cl::desc("Do not dump MSF file headers (you will not be able "
"to generate a fresh PDB from the resulting YAML)"),
cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> Minimal("minimal",
+ cl::desc("Don't write fields with default values"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
cl::opt<bool> StreamMetadata(
"stream-metadata",
@@ -274,6 +351,10 @@ cl::opt<bool> StreamDirectory(
cl::opt<bool> PdbStream("pdb-stream",
cl::desc("Dump the PDB Stream (Stream 1)"),
cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
cl::opt<bool> DbiStream("dbi-stream",
cl::desc("Dump the DBI Stream (Stream 2)"),
cl::sub(PdbToYamlSubcommand), cl::init(false));
@@ -305,6 +386,14 @@ cl::list<std::string> InputFilename(cl::Positional,
cl::desc("<input PDB file>"), cl::Required,
cl::sub(PdbToYamlSubcommand));
}
+
+namespace analyze {
+cl::opt<bool> StringTable("hash-collisions", cl::desc("Find hash collisions"),
+ cl::sub(AnalyzeSubcommand), cl::init(false));
+cl::list<std::string> InputFilename(cl::Positional,
+ cl::desc("<input PDB file>"), cl::Required,
+ cl::sub(AnalyzeSubcommand));
+}
}
static ExitOnError ExitOnErr;
@@ -324,13 +413,13 @@ static void yamlToPdb(StringRef Path) {
llvm::yaml::Input In(Buffer->getBuffer());
pdb::yaml::PdbObject YamlObj(Allocator);
In >> YamlObj;
- if (!YamlObj.Headers.hasValue())
- ExitOnErr(make_error<GenericError>(generic_error_code::unspecified,
- "Yaml does not contain MSF headers"));
PDBFileBuilder Builder(Allocator);
- ExitOnErr(Builder.initialize(YamlObj.Headers->SuperBlock.BlockSize));
+ uint32_t BlockSize = 4096;
+ if (YamlObj.Headers.hasValue())
+ BlockSize = YamlObj.Headers->SuperBlock.BlockSize;
+ ExitOnErr(Builder.initialize(BlockSize));
// Add each of the reserved streams. We ignore stream metadata in the
// yaml, because we will reconstruct our own view of the streams. For
// example, the YAML may say that there were 20 streams in the original
@@ -340,56 +429,74 @@ static void yamlToPdb(StringRef Path) {
for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
ExitOnErr(Builder.getMsfBuilder().addStream(0));
- if (YamlObj.PdbStream.hasValue()) {
- auto &InfoBuilder = Builder.getInfoBuilder();
- InfoBuilder.setAge(YamlObj.PdbStream->Age);
- InfoBuilder.setGuid(YamlObj.PdbStream->Guid);
- InfoBuilder.setSignature(YamlObj.PdbStream->Signature);
- InfoBuilder.setVersion(YamlObj.PdbStream->Version);
- for (auto &NM : YamlObj.PdbStream->NamedStreams)
- InfoBuilder.getNamedStreamsBuilder().addMapping(NM.StreamName,
- NM.StreamNumber);
+ if (YamlObj.StringTable.hasValue()) {
+ auto &Strings = Builder.getStringTableBuilder();
+ for (auto S : *YamlObj.StringTable)
+ Strings.insert(S);
}
- if (YamlObj.DbiStream.hasValue()) {
- auto &DbiBuilder = Builder.getDbiBuilder();
- DbiBuilder.setAge(YamlObj.DbiStream->Age);
- DbiBuilder.setBuildNumber(YamlObj.DbiStream->BuildNumber);
- DbiBuilder.setFlags(YamlObj.DbiStream->Flags);
- DbiBuilder.setMachineType(YamlObj.DbiStream->MachineType);
- DbiBuilder.setPdbDllRbld(YamlObj.DbiStream->PdbDllRbld);
- DbiBuilder.setPdbDllVersion(YamlObj.DbiStream->PdbDllVersion);
- DbiBuilder.setVersionHeader(YamlObj.DbiStream->VerHeader);
- for (const auto &MI : YamlObj.DbiStream->ModInfos) {
- ExitOnErr(DbiBuilder.addModuleInfo(MI.Obj, MI.Mod));
- for (auto S : MI.SourceFiles)
- ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
+ pdb::yaml::PdbInfoStream DefaultInfoStream;
+ pdb::yaml::PdbDbiStream DefaultDbiStream;
+ pdb::yaml::PdbTpiStream DefaultTpiStream;
+
+ const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream);
+
+ auto &InfoBuilder = Builder.getInfoBuilder();
+ InfoBuilder.setAge(Info.Age);
+ InfoBuilder.setGuid(Info.Guid);
+ InfoBuilder.setSignature(Info.Signature);
+ InfoBuilder.setVersion(Info.Version);
+ for (auto F : Info.Features)
+ InfoBuilder.addFeature(F);
+
+ const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream);
+ auto &DbiBuilder = Builder.getDbiBuilder();
+ DbiBuilder.setAge(Dbi.Age);
+ DbiBuilder.setBuildNumber(Dbi.BuildNumber);
+ DbiBuilder.setFlags(Dbi.Flags);
+ DbiBuilder.setMachineType(Dbi.MachineType);
+ DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld);
+ DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion);
+ DbiBuilder.setVersionHeader(Dbi.VerHeader);
+ for (const auto &MI : Dbi.ModInfos) {
+ auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod));
+
+ for (auto S : MI.SourceFiles)
+ ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
+ if (MI.Modi.hasValue()) {
+ const auto &ModiStream = *MI.Modi;
+ ModiBuilder.setObjFileName(MI.Obj);
+ for (auto Symbol : ModiStream.Symbols)
+ ModiBuilder.addSymbol(Symbol.Record);
}
}
- if (YamlObj.TpiStream.hasValue()) {
- auto &TpiBuilder = Builder.getTpiBuilder();
- TpiBuilder.setVersionHeader(YamlObj.TpiStream->Version);
- for (const auto &R : YamlObj.TpiStream->Records)
- TpiBuilder.addTypeRecord(R.Record);
- }
+ auto &TpiBuilder = Builder.getTpiBuilder();
+ const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream);
+ TpiBuilder.setVersionHeader(Tpi.Version);
+ for (const auto &R : Tpi.Records)
+ TpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash);
- if (YamlObj.IpiStream.hasValue()) {
- auto &IpiBuilder = Builder.getIpiBuilder();
- IpiBuilder.setVersionHeader(YamlObj.IpiStream->Version);
- for (const auto &R : YamlObj.IpiStream->Records)
- IpiBuilder.addTypeRecord(R.Record);
- }
+ const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultTpiStream);
+ auto &IpiBuilder = Builder.getIpiBuilder();
+ IpiBuilder.setVersionHeader(Ipi.Version);
+ for (const auto &R : Ipi.Records)
+ TpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash);
ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile));
}
+static PDBFile &loadPDB(StringRef Path, std::unique_ptr<IPDBSession> &Session) {
+ ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session));
+
+ NativeSession *NS = static_cast<NativeSession *>(Session.get());
+ return NS->getPDBFile();
+}
+
static void pdb2Yaml(StringRef Path) {
std::unique_ptr<IPDBSession> Session;
- ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session));
+ auto &File = loadPDB(Path, Session);
- RawSession *RS = static_cast<RawSession *>(Session.get());
- PDBFile &File = RS->getPDBFile();
auto O = llvm::make_unique<YAMLOutputStyle>(File);
O = llvm::make_unique<YAMLOutputStyle>(File);
@@ -398,24 +505,48 @@ static void pdb2Yaml(StringRef Path) {
static void dumpRaw(StringRef Path) {
std::unique_ptr<IPDBSession> Session;
- ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session));
+ auto &File = loadPDB(Path, Session);
- RawSession *RS = static_cast<RawSession *>(Session.get());
- PDBFile &File = RS->getPDBFile();
auto O = llvm::make_unique<LLVMOutputStyle>(File);
ExitOnErr(O->dump());
}
+static void dumpAnalysis(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ auto &File = loadPDB(Path, Session);
+ auto O = llvm::make_unique<AnalysisStyle>(File);
+
+ ExitOnErr(O->dump());
+}
+
+static void diff(StringRef Path1, StringRef Path2) {
+ std::unique_ptr<IPDBSession> Session1;
+ std::unique_ptr<IPDBSession> Session2;
+
+ auto &File1 = loadPDB(Path1, Session1);
+ auto &File2 = loadPDB(Path2, Session2);
+
+ auto O = llvm::make_unique<DiffStyle>(File1, File2);
+
+ ExitOnErr(O->dump());
+}
+
static void dumpPretty(StringRef Path) {
std::unique_ptr<IPDBSession> Session;
- ExitOnErr(loadDataForPDB(PDB_ReaderType::DIA, Path, Session));
+ const auto ReaderType =
+ opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA;
+ ExitOnErr(loadDataForPDB(ReaderType, Path, Session));
if (opts::pretty::LoadAddress)
Session->setLoadAddress(opts::pretty::LoadAddress);
- LinePrinter Printer(2, outs());
+ auto &Stream = outs();
+ const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET
+ ? Stream.has_colors()
+ : opts::pretty::ColorOutput == cl::BOU_TRUE;
+ LinePrinter Printer(2, UseColor, Stream);
auto GlobalScope(Session->getGlobalScope());
std::string FileName(GlobalScope->getSymbolsFileName());
@@ -465,7 +596,7 @@ static void dumpPretty(StringRef Path) {
Printer.Unindent();
}
- if (opts::pretty::Types) {
+ if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
Printer.Indent();
@@ -556,24 +687,34 @@ int main(int argc_, const char *argv_[]) {
}
}
- if (opts::RawSubcommand && opts::raw::RawAll) {
- opts::raw::DumpHeaders = true;
- opts::raw::DumpModules = true;
- opts::raw::DumpModuleFiles = true;
- opts::raw::DumpModuleSyms = true;
- opts::raw::DumpGlobals = true;
- opts::raw::DumpPublics = true;
- opts::raw::DumpSectionHeaders = true;
- opts::raw::DumpStreamSummary = true;
- opts::raw::DumpPageStats = true;
- opts::raw::DumpStreamBlocks = true;
- opts::raw::DumpTpiRecords = true;
- opts::raw::DumpTpiHash = true;
- opts::raw::DumpIpiRecords = true;
- opts::raw::DumpSectionMap = true;
- opts::raw::DumpSectionContribs = true;
- opts::raw::DumpLineInfo = true;
- opts::raw::DumpFpo = true;
+ if (opts::RawSubcommand) {
+ if (opts::raw::RawAll) {
+ opts::raw::DumpHeaders = true;
+ opts::raw::DumpModules = true;
+ opts::raw::DumpModuleFiles = true;
+ opts::raw::DumpModuleSyms = true;
+ opts::raw::DumpGlobals = true;
+ opts::raw::DumpPublics = true;
+ opts::raw::DumpSectionHeaders = true;
+ opts::raw::DumpStreamSummary = true;
+ opts::raw::DumpPageStats = true;
+ opts::raw::DumpStreamBlocks = true;
+ opts::raw::DumpTpiRecords = true;
+ opts::raw::DumpTpiHash = true;
+ opts::raw::DumpIpiRecords = true;
+ opts::raw::DumpSectionMap = true;
+ opts::raw::DumpSectionContribs = true;
+ opts::raw::DumpLineInfo = true;
+ opts::raw::DumpFpo = true;
+ opts::raw::DumpStringTable = true;
+ }
+
+ if (opts::raw::CompactRecords &&
+ (opts::raw::DumpTpiRecordBytes || opts::raw::DumpIpiRecordBytes)) {
+ errs() << "-compact-records is incompatible with -tpi-record-bytes and "
+ "-ipi-record-bytes.\n";
+ exit(1);
+ }
}
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
@@ -582,6 +723,8 @@ int main(int argc_, const char *argv_[]) {
pdb2Yaml(opts::pdb2yaml::InputFilename.front());
} else if (opts::YamlToPdbSubcommand) {
yamlToPdb(opts::yaml2pdb::InputFilename.front());
+ } else if (opts::AnalyzeSubcommand) {
+ dumpAnalysis(opts::analyze::InputFilename.front());
} else if (opts::PrettySubcommand) {
if (opts::pretty::Lines)
opts::pretty::Compilands = true;
@@ -595,6 +738,12 @@ int main(int argc_, const char *argv_[]) {
opts::pretty::Lines = true;
}
+ if (opts::pretty::Types) {
+ opts::pretty::Classes = true;
+ opts::pretty::Typedefs = true;
+ opts::pretty::Enums = true;
+ }
+
// When adding filters for excluded compilands and types, we need to
// remember that these are regexes. So special characters such as * and \
// need to be escaped in the regex. In the case of a literal \, this means
@@ -616,6 +765,12 @@ int main(int argc_, const char *argv_[]) {
} else if (opts::RawSubcommand) {
std::for_each(opts::raw::InputFilenames.begin(),
opts::raw::InputFilenames.end(), dumpRaw);
+ } else if (opts::DiffSubcommand) {
+ if (opts::diff::InputFilenames.size() != 2) {
+ errs() << "diff subcommand expects exactly 2 arguments.\n";
+ exit(1);
+ }
+ diff(opts::diff::InputFilenames[0], opts::diff::InputFilenames[1]);
}
outs().flush();
diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h
index 42d847a23fcc9..a5429a253df40 100644
--- a/tools/llvm-pdbdump/llvm-pdbdump.h
+++ b/tools/llvm-pdbdump/llvm-pdbdump.h
@@ -17,14 +17,19 @@
namespace opts {
namespace pretty {
+
+enum class ClassDefinitionFormat { None, Layout, Graphical, Standard };
+enum class ClassSortMode { None, Name, Size, Padding };
+
extern llvm::cl::opt<bool> Compilands;
extern llvm::cl::opt<bool> Symbols;
extern llvm::cl::opt<bool> Globals;
-extern llvm::cl::opt<bool> Types;
+extern llvm::cl::opt<bool> Classes;
+extern llvm::cl::opt<bool> Enums;
+extern llvm::cl::opt<bool> Typedefs;
extern llvm::cl::opt<bool> All;
extern llvm::cl::opt<bool> ExcludeCompilerGenerated;
-extern llvm::cl::opt<bool> NoClassDefs;
extern llvm::cl::opt<bool> NoEnumDefs;
extern llvm::cl::list<std::string> ExcludeTypes;
extern llvm::cl::list<std::string> ExcludeSymbols;
@@ -32,6 +37,10 @@ extern llvm::cl::list<std::string> ExcludeCompilands;
extern llvm::cl::list<std::string> IncludeTypes;
extern llvm::cl::list<std::string> IncludeSymbols;
extern llvm::cl::list<std::string> IncludeCompilands;
+extern llvm::cl::opt<ClassSortMode> ClassOrder;
+extern llvm::cl::opt<uint32_t> SizeThreshold;
+extern llvm::cl::opt<uint32_t> PaddingThreshold;
+extern llvm::cl::opt<ClassDefinitionFormat> ClassFormat;
}
namespace raw {
@@ -43,6 +52,7 @@ struct BlockRange {
extern llvm::Optional<BlockRange> DumpBlockRange;
extern llvm::cl::list<uint32_t> DumpStreamData;
+extern llvm::cl::opt<bool> CompactRecords;
extern llvm::cl::opt<bool> DumpGlobals;
extern llvm::cl::opt<bool> DumpHeaders;
extern llvm::cl::opt<bool> DumpStreamBlocks;
@@ -63,12 +73,19 @@ extern llvm::cl::opt<bool> DumpSectionMap;
extern llvm::cl::opt<bool> DumpSymRecordBytes;
extern llvm::cl::opt<bool> DumpSectionHeaders;
extern llvm::cl::opt<bool> DumpFpo;
+extern llvm::cl::opt<bool> DumpStringTable;
+}
+
+namespace diff {
+extern llvm::cl::opt<bool> Pedantic;
}
namespace pdb2yaml {
extern llvm::cl::opt<bool> NoFileHeaders;
+extern llvm::cl::opt<bool> Minimal;
extern llvm::cl::opt<bool> StreamMetadata;
extern llvm::cl::opt<bool> StreamDirectory;
+extern llvm::cl::opt<bool> StringTable;
extern llvm::cl::opt<bool> PdbStream;
extern llvm::cl::opt<bool> DbiStream;
extern llvm::cl::opt<bool> DbiModuleInfo;
diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp
index 6715566a166c2..a257910ecf776 100644
--- a/tools/llvm-profdata/llvm-profdata.cpp
+++ b/tools/llvm-profdata/llvm-profdata.cpp
@@ -446,8 +446,58 @@ static int merge_main(int argc, const char *argv[]) {
return 0;
}
+typedef struct ValueSitesStats {
+ ValueSitesStats()
+ : TotalNumValueSites(0), TotalNumValueSitesWithValueProfile(0),
+ TotalNumValues(0) {}
+ uint64_t TotalNumValueSites;
+ uint64_t TotalNumValueSitesWithValueProfile;
+ uint64_t TotalNumValues;
+ std::vector<unsigned> ValueSitesHistogram;
+} ValueSitesStats;
+
+static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
+ ValueSitesStats &Stats, raw_fd_ostream &OS,
+ InstrProfSymtab *Symtab) {
+ uint32_t NS = Func.getNumValueSites(VK);
+ Stats.TotalNumValueSites += NS;
+ for (size_t I = 0; I < NS; ++I) {
+ uint32_t NV = Func.getNumValueDataForSite(VK, I);
+ std::unique_ptr<InstrProfValueData[]> VD = Func.getValueForSite(VK, I);
+ Stats.TotalNumValues += NV;
+ if (NV) {
+ Stats.TotalNumValueSitesWithValueProfile++;
+ if (NV > Stats.ValueSitesHistogram.size())
+ Stats.ValueSitesHistogram.resize(NV, 0);
+ Stats.ValueSitesHistogram[NV - 1]++;
+ }
+ for (uint32_t V = 0; V < NV; V++) {
+ OS << "\t[ " << I << ", ";
+ if (Symtab == nullptr)
+ OS << VD[V].Value;
+ else
+ OS << Symtab->getFuncName(VD[V].Value);
+ OS << ", " << VD[V].Count << " ]\n";
+ }
+ }
+}
+
+static void showValueSitesStats(raw_fd_ostream &OS, uint32_t VK,
+ ValueSitesStats &Stats) {
+ OS << " Total number of sites: " << Stats.TotalNumValueSites << "\n";
+ OS << " Total number of sites with values: "
+ << Stats.TotalNumValueSitesWithValueProfile << "\n";
+ OS << " Total number of profiled values: " << Stats.TotalNumValues << "\n";
+
+ OS << " Value sites histogram:\n\tNumTargets, SiteCount\n";
+ for (unsigned I = 0; I < Stats.ValueSitesHistogram.size(); I++) {
+ if (Stats.ValueSitesHistogram[I] > 0)
+ OS << "\t" << I + 1 << ", " << Stats.ValueSitesHistogram[I] << "\n";
+ }
+}
+
static int showInstrProfile(const std::string &Filename, bool ShowCounts,
- bool ShowIndirectCallTargets,
+ bool ShowIndirectCallTargets, bool ShowMemOPSizes,
bool ShowDetailedSummary,
std::vector<uint32_t> DetailedSummaryCutoffs,
bool ShowAllFunctions,
@@ -465,10 +515,8 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
auto Reader = std::move(ReaderOrErr.get());
bool IsIRInstr = Reader->isIRLevelProfile();
size_t ShownFunctions = 0;
- uint64_t TotalNumValueSites = 0;
- uint64_t TotalNumValueSitesWithValueProfile = 0;
- uint64_t TotalNumValues = 0;
- std::vector<unsigned> ICHistogram;
+ int NumVPKind = IPVK_Last - IPVK_First + 1;
+ std::vector<ValueSitesStats> VPStats(NumVPKind);
for (const auto &Func : *Reader) {
bool Show =
ShowAllFunctions || (!ShowFunction.empty() &&
@@ -502,6 +550,11 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
OS << " Indirect Call Site Count: "
<< Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n";
+ uint32_t NumMemOPCalls = Func.getNumValueSites(IPVK_MemOPSize);
+ if (ShowMemOPSizes && NumMemOPCalls > 0)
+ OS << " Number of Memory Intrinsics Calls: " << NumMemOPCalls
+ << "\n";
+
if (ShowCounts) {
OS << " Block counts: [";
size_t Start = (IsIRInstr ? 0 : 1);
@@ -512,27 +565,16 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
}
if (ShowIndirectCallTargets) {
- InstrProfSymtab &Symtab = Reader->getSymtab();
- uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget);
- OS << " Indirect Target Results: \n";
- TotalNumValueSites += NS;
- for (size_t I = 0; I < NS; ++I) {
- uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I);
- std::unique_ptr<InstrProfValueData[]> VD =
- Func.getValueForSite(IPVK_IndirectCallTarget, I);
- TotalNumValues += NV;
- if (NV) {
- TotalNumValueSitesWithValueProfile++;
- if (NV > ICHistogram.size())
- ICHistogram.resize(NV, 0);
- ICHistogram[NV - 1]++;
- }
- for (uint32_t V = 0; V < NV; V++) {
- OS << "\t[ " << I << ", ";
- OS << Symtab.getFuncName(VD[V].Value) << ", " << VD[V].Count
- << " ]\n";
- }
- }
+ OS << " Indirect Target Results:\n";
+ traverseAllValueSites(Func, IPVK_IndirectCallTarget,
+ VPStats[IPVK_IndirectCallTarget], OS,
+ &(Reader->getSymtab()));
+ }
+
+ if (ShowMemOPSizes && NumMemOPCalls > 0) {
+ OS << " Memory Instrinsic Size Results:\n";
+ traverseAllValueSites(Func, IPVK_MemOPSize, VPStats[IPVK_MemOPSize], OS,
+ nullptr);
}
}
}
@@ -547,17 +589,16 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
OS << "Total functions: " << PS->getNumFunctions() << "\n";
OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n";
OS << "Maximum internal block count: " << PS->getMaxInternalCount() << "\n";
+
if (ShownFunctions && ShowIndirectCallTargets) {
- OS << "Total Number of Indirect Call Sites : " << TotalNumValueSites
- << "\n";
- OS << "Total Number of Sites With Values : "
- << TotalNumValueSitesWithValueProfile << "\n";
- OS << "Total Number of Profiled Values : " << TotalNumValues << "\n";
-
- OS << "IC Value histogram : \n\tNumTargets, SiteCount\n";
- for (unsigned I = 0; I < ICHistogram.size(); I++) {
- OS << "\t" << I + 1 << ", " << ICHistogram[I] << "\n";
- }
+ OS << "Statistics for indirect call sites profile:\n";
+ showValueSitesStats(OS, IPVK_IndirectCallTarget,
+ VPStats[IPVK_IndirectCallTarget]);
+ }
+
+ if (ShownFunctions && ShowMemOPSizes) {
+ OS << "Statistics for memory intrinsic calls sizes profile:\n";
+ showValueSitesStats(OS, IPVK_MemOPSize, VPStats[IPVK_MemOPSize]);
}
if (ShowDetailedSummary) {
@@ -608,6 +649,10 @@ static int show_main(int argc, const char *argv[]) {
cl::opt<bool> ShowIndirectCallTargets(
"ic-targets", cl::init(false),
cl::desc("Show indirect call site target values for shown functions"));
+ cl::opt<bool> ShowMemOPSizes(
+ "memop-sizes", cl::init(false),
+ cl::desc("Show the profiled sizes of the memory intrinsic calls "
+ "for shown functions"));
cl::opt<bool> ShowDetailedSummary("detailed-summary", cl::init(false),
cl::desc("Show detailed profile summary"));
cl::list<uint32_t> DetailedSummaryCutoffs(
@@ -646,8 +691,9 @@ static int show_main(int argc, const char *argv[]) {
DetailedSummaryCutoffs.end());
if (ProfileKind == instr)
return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets,
- ShowDetailedSummary, DetailedSummaryCutoffs,
- ShowAllFunctions, ShowFunction, TextFormat, OS);
+ ShowMemOPSizes, ShowDetailedSummary,
+ DetailedSummaryCutoffs, ShowAllFunctions,
+ ShowFunction, TextFormat, OS);
else
return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
ShowFunction, OS);
diff --git a/tools/llvm-readobj/ARMAttributeParser.cpp b/tools/llvm-readobj/ARMAttributeParser.cpp
deleted file mode 100644
index 877dd71c90706..0000000000000
--- a/tools/llvm-readobj/ARMAttributeParser.cpp
+++ /dev/null
@@ -1,682 +0,0 @@
-//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ARMAttributeParser.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/ScopedPrinter.h"
-
-using namespace llvm;
-using namespace llvm::ARMBuildAttrs;
-
-
-static const EnumEntry<unsigned> TagNames[] = {
- { "Tag_File", ARMBuildAttrs::File },
- { "Tag_Section", ARMBuildAttrs::Section },
- { "Tag_Symbol", ARMBuildAttrs::Symbol },
-};
-
-namespace llvm {
-#define ATTRIBUTE_HANDLER(Attr_) \
- { ARMBuildAttrs::Attr_, &ARMAttributeParser::Attr_ }
-
-const ARMAttributeParser::DisplayHandler
-ARMAttributeParser::DisplayRoutines[] = {
- { ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::StringAttribute, },
- { ARMBuildAttrs::CPU_name, &ARMAttributeParser::StringAttribute },
- ATTRIBUTE_HANDLER(CPU_arch),
- ATTRIBUTE_HANDLER(CPU_arch_profile),
- ATTRIBUTE_HANDLER(ARM_ISA_use),
- ATTRIBUTE_HANDLER(THUMB_ISA_use),
- ATTRIBUTE_HANDLER(FP_arch),
- ATTRIBUTE_HANDLER(WMMX_arch),
- ATTRIBUTE_HANDLER(Advanced_SIMD_arch),
- ATTRIBUTE_HANDLER(PCS_config),
- ATTRIBUTE_HANDLER(ABI_PCS_R9_use),
- ATTRIBUTE_HANDLER(ABI_PCS_RW_data),
- ATTRIBUTE_HANDLER(ABI_PCS_RO_data),
- ATTRIBUTE_HANDLER(ABI_PCS_GOT_use),
- ATTRIBUTE_HANDLER(ABI_PCS_wchar_t),
- ATTRIBUTE_HANDLER(ABI_FP_rounding),
- ATTRIBUTE_HANDLER(ABI_FP_denormal),
- ATTRIBUTE_HANDLER(ABI_FP_exceptions),
- ATTRIBUTE_HANDLER(ABI_FP_user_exceptions),
- ATTRIBUTE_HANDLER(ABI_FP_number_model),
- ATTRIBUTE_HANDLER(ABI_align_needed),
- ATTRIBUTE_HANDLER(ABI_align_preserved),
- ATTRIBUTE_HANDLER(ABI_enum_size),
- ATTRIBUTE_HANDLER(ABI_HardFP_use),
- ATTRIBUTE_HANDLER(ABI_VFP_args),
- ATTRIBUTE_HANDLER(ABI_WMMX_args),
- ATTRIBUTE_HANDLER(ABI_optimization_goals),
- ATTRIBUTE_HANDLER(ABI_FP_optimization_goals),
- ATTRIBUTE_HANDLER(compatibility),
- ATTRIBUTE_HANDLER(CPU_unaligned_access),
- ATTRIBUTE_HANDLER(FP_HP_extension),
- ATTRIBUTE_HANDLER(ABI_FP_16bit_format),
- ATTRIBUTE_HANDLER(MPextension_use),
- ATTRIBUTE_HANDLER(DIV_use),
- ATTRIBUTE_HANDLER(DSP_extension),
- ATTRIBUTE_HANDLER(T2EE_use),
- ATTRIBUTE_HANDLER(Virtualization_use),
- ATTRIBUTE_HANDLER(nodefaults)
-};
-
-#undef ATTRIBUTE_HANDLER
-
-uint64_t ARMAttributeParser::ParseInteger(const uint8_t *Data,
- uint32_t &Offset) {
- unsigned Length;
- uint64_t Value = decodeULEB128(Data + Offset, &Length);
- Offset = Offset + Length;
- return Value;
-}
-
-StringRef ARMAttributeParser::ParseString(const uint8_t *Data,
- uint32_t &Offset) {
- const char *String = reinterpret_cast<const char*>(Data + Offset);
- size_t Length = std::strlen(String);
- Offset = Offset + Length + 1;
- return StringRef(String, Length);
-}
-
-void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- SW.printNumber(ARMBuildAttrs::AttrTypeAsString(Tag),
- ParseInteger(Data, Offset));
-}
-
-void ARMAttributeParser::StringAttribute(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false);
-
- DictScope AS(SW, "Attribute");
- SW.printNumber("Tag", Tag);
- if (!TagName.empty())
- SW.printString("TagName", TagName);
- SW.printString("Value", ParseString(Data, Offset));
-}
-
-void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value,
- StringRef ValueDesc) {
- StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false);
-
- DictScope AS(SW, "Attribute");
- SW.printNumber("Tag", Tag);
- SW.printNumber("Value", Value);
- if (!TagName.empty())
- SW.printString("TagName", TagName);
- if (!ValueDesc.empty())
- SW.printString("Description", ValueDesc);
-}
-
-void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6",
- "ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M",
- "ARM v7E-M", "ARM v8"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- uint64_t Encoded = ParseInteger(Data, Offset);
-
- StringRef Profile;
- switch (Encoded) {
- default: Profile = "Unknown"; break;
- case 'A': Profile = "Application"; break;
- case 'R': Profile = "Real-time"; break;
- case 'M': Profile = "Microcontroller"; break;
- case 'S': Profile = "Classic"; break;
- case 0: Profile = "None"; break;
- }
-
- PrintAttribute(Tag, Encoded, Profile);
-}
-
-void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4",
- "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON", "ARMv8.1-a NEON"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004",
- "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "v6", "Static Base", "TLS", "Unused" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Absolute", "PC-relative", "SB-relative", "Not Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Absolute", "PC-relative", "Not Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Direct", "GOT-Indirect"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "IEEE-754", "Runtime" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Unsupported", "IEEE-754", "Sign Only"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "IEEE-754" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag,
- const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "IEEE-754" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Finite Only", "RTABI", "IEEE-754"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
-
- std::string Description;
- if (Value < array_lengthof(Strings))
- Description = std::string(Strings[Value]);
- else if (Value <= 12)
- Description = std::string("8-byte alignment, ") + utostr(1ULL << Value)
- + std::string("-byte extended alignment");
- else
- Description = "Invalid";
-
- PrintAttribute(Tag, Value, Description);
-}
-
-void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Required", "8-byte data alignment", "8-byte data and code alignment",
- "Reserved"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
-
- std::string Description;
- if (Value < array_lengthof(Strings))
- Description = std::string(Strings[Value]);
- else if (Value <= 12)
- Description = std::string("8-byte stack alignment, ") +
- utostr(1ULL << Value) + std::string("-byte data alignment");
- else
- Description = "Invalid";
-
- PrintAttribute(Tag, Value, Description);
-}
-
-void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Packed", "Int32", "External Int32"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "AAPCS", "AAPCS VFP", "Custom", "Not Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "AAPCS", "iWMMX", "Custom" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_optimization_goals(AttrType Tag,
- const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging",
- "Best Debugging"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag,
- const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Accuracy",
- "Best Accuracy"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- uint64_t Integer = ParseInteger(Data, Offset);
- StringRef String = ParseString(Data, Offset);
-
- DictScope AS(SW, "Attribute");
- SW.printNumber("Tag", Tag);
- SW.startLine() << "Value: " << Integer << ", " << String << '\n';
- SW.printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false));
- switch (Integer) {
- case 0:
- SW.printString("Description", StringRef("No Specific Requirements"));
- break;
- case 1:
- SW.printString("Description", StringRef("AEABI Conformant"));
- break;
- default:
- SW.printString("Description", StringRef("AEABI Non-Conformant"));
- break;
- }
-}
-
-void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "v6-style" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "If Available", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "If Available", "Not Permitted", "Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::DSP_extension(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "TrustZone", "Virtualization Extensions",
- "TrustZone + Virtualization Extensions"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::nodefaults(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- uint64_t Value = ParseInteger(Data, Offset);
- PrintAttribute(Tag, Value, "Unspecified Tags UNDEFINED");
-}
-
-void ARMAttributeParser::ParseIndexList(const uint8_t *Data, uint32_t &Offset,
- SmallVectorImpl<uint8_t> &IndexList) {
- for (;;) {
- unsigned Length;
- uint64_t Value = decodeULEB128(Data + Offset, &Length);
- Offset = Offset + Length;
- if (Value == 0)
- break;
- IndexList.push_back(Value);
- }
-}
-
-void ARMAttributeParser::ParseAttributeList(const uint8_t *Data,
- uint32_t &Offset, uint32_t Length) {
- while (Offset < Length) {
- unsigned Length;
- uint64_t Tag = decodeULEB128(Data + Offset, &Length);
- Offset += Length;
-
- bool Handled = false;
- for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines);
- AHI != AHE && !Handled; ++AHI) {
- if (DisplayRoutines[AHI].Attribute == Tag) {
- (this->*DisplayRoutines[AHI].Routine)(ARMBuildAttrs::AttrType(Tag),
- Data, Offset);
- Handled = true;
- break;
- }
- }
- if (!Handled) {
- if (Tag < 32) {
- errs() << "unhandled AEABI Tag " << Tag
- << " (" << ARMBuildAttrs::AttrTypeAsString(Tag) << ")\n";
- continue;
- }
-
- if (Tag % 2 == 0)
- IntegerAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
- else
- StringAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
- }
- }
-}
-
-void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) {
- uint32_t Offset = sizeof(uint32_t); /* SectionLength */
-
- SW.printNumber("SectionLength", Length);
-
- const char *VendorName = reinterpret_cast<const char*>(Data + Offset);
- size_t VendorNameLength = std::strlen(VendorName);
- SW.printString("Vendor", StringRef(VendorName, VendorNameLength));
- Offset = Offset + VendorNameLength + 1;
-
- if (StringRef(VendorName, VendorNameLength).lower() != "aeabi")
- return;
-
- while (Offset < Length) {
- /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
- uint8_t Tag = Data[Offset];
- SW.printEnum("Tag", Tag, makeArrayRef(TagNames));
- Offset = Offset + sizeof(Tag);
-
- uint32_t Size =
- *reinterpret_cast<const support::ulittle32_t*>(Data + Offset);
- SW.printNumber("Size", Size);
- Offset = Offset + sizeof(Size);
-
- if (Size > Length) {
- errs() << "subsection length greater than section length\n";
- return;
- }
-
- StringRef ScopeName, IndexName;
- SmallVector<uint8_t, 8> Indicies;
- switch (Tag) {
- case ARMBuildAttrs::File:
- ScopeName = "FileAttributes";
- break;
- case ARMBuildAttrs::Section:
- ScopeName = "SectionAttributes";
- IndexName = "Sections";
- ParseIndexList(Data, Offset, Indicies);
- break;
- case ARMBuildAttrs::Symbol:
- ScopeName = "SymbolAttributes";
- IndexName = "Symbols";
- ParseIndexList(Data, Offset, Indicies);
- break;
- default:
- errs() << "unrecognised tag: 0x" << utohexstr(Tag) << '\n';
- return;
- }
-
- DictScope ASS(SW, ScopeName);
-
- if (!Indicies.empty())
- SW.printList(IndexName, Indicies);
-
- ParseAttributeList(Data, Offset, Length);
- }
-}
-
-void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section) {
- size_t Offset = 1;
- unsigned SectionNumber = 0;
-
- while (Offset < Section.size()) {
- uint32_t SectionLength =
- *reinterpret_cast<const support::ulittle32_t*>(Section.data() + Offset);
-
- SW.startLine() << "Section " << ++SectionNumber << " {\n";
- SW.indent();
-
- ParseSubsection(Section.data() + Offset, SectionLength);
- Offset = Offset + SectionLength;
-
- SW.unindent();
- SW.startLine() << "}\n";
- }
-}
-}
-
diff --git a/tools/llvm-readobj/ARMAttributeParser.h b/tools/llvm-readobj/ARMAttributeParser.h
deleted file mode 100644
index 6936b70ca1230..0000000000000
--- a/tools/llvm-readobj/ARMAttributeParser.h
+++ /dev/null
@@ -1,126 +0,0 @@
-//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H
-#define LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H
-
-#include "llvm/Support/ARMBuildAttributes.h"
-#include "llvm/Support/ScopedPrinter.h"
-
-namespace llvm {
-class StringRef;
-
-class ARMAttributeParser {
- ScopedPrinter &SW;
-
- struct DisplayHandler {
- ARMBuildAttrs::AttrType Attribute;
- void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType,
- const uint8_t *, uint32_t &);
- };
- static const DisplayHandler DisplayRoutines[];
-
- uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset);
- StringRef ParseString(const uint8_t *Data, uint32_t &Offset);
-
- void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
-
- void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc);
-
- void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag,
- const uint8_t *Data, uint32_t &Offset);
- void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void DSP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
-
- void ParseAttributeList(const uint8_t *Data, uint32_t &Offset,
- uint32_t Length);
- void ParseIndexList(const uint8_t *Data, uint32_t &Offset,
- SmallVectorImpl<uint8_t> &IndexList);
- void ParseSubsection(const uint8_t *Data, uint32_t Length);
-public:
- ARMAttributeParser(ScopedPrinter &SW) : SW(SW) {}
-
- void Parse(ArrayRef<uint8_t> Section);
-};
-
-}
-
-#endif
-
diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt
index 0f8336ffd3265..0ad149538f635 100644
--- a/tools/llvm-readobj/CMakeLists.txt
+++ b/tools/llvm-readobj/CMakeLists.txt
@@ -4,10 +4,10 @@ set(LLVM_LINK_COMPONENTS
Support
DebugInfoCodeView
DebugInfoMSF
+ DebugInfoPDB
)
add_llvm_tool(llvm-readobj
- ARMAttributeParser.cpp
ARMWinEHPrinter.cpp
COFFDumper.cpp
COFFImportDumper.cpp
@@ -16,5 +16,6 @@ add_llvm_tool(llvm-readobj
llvm-readobj.cpp
MachODumper.cpp
ObjDumper.cpp
+ WasmDumper.cpp
Win64EHDumper.cpp
)
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index c83655fe4d223..9836c137ed2ca 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -35,14 +35,15 @@
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Win64EH.h"
@@ -55,7 +56,6 @@
using namespace llvm;
using namespace llvm::object;
using namespace llvm::codeview;
-using namespace llvm::msf;
using namespace llvm::support;
using namespace llvm::Win64EH;
@@ -79,7 +79,8 @@ public:
void printCOFFBaseReloc() override;
void printCOFFDebugDirectory() override;
void printCodeViewDebugInfo() override;
- void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) override;
+ void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
+ llvm::codeview::TypeTableBuilder &CVTypes) override;
void printStackMap() const override;
private:
void printSymbol(const SymbolRef &Sym);
@@ -154,7 +155,7 @@ public:
Sec = Obj->getCOFFSection(SR);
}
- uint32_t getRecordOffset(msf::StreamReader Reader) override {
+ uint32_t getRecordOffset(BinaryStreamReader Reader) override {
ArrayRef<uint8_t> Data;
if (auto EC = Reader.readLongestContiguousChunk(Data)) {
llvm::consumeError(std::move(EC));
@@ -840,8 +841,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
}
case ModuleSubstreamKind::FrameData: {
// First four bytes is a relocation against the function.
- msf::ByteStream S(Contents);
- msf::StreamReader SR(S);
+ BinaryByteStream S(Contents, llvm::support::little);
+ BinaryStreamReader SR(S);
const uint32_t *CodePtr;
error(SR.readObject(CodePtr));
StringRef LinkageName;
@@ -965,9 +966,9 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
CVSymbolDumper CVSD(W, TypeDB, std::move(CODD),
opts::CodeViewSubsectionBytes);
- ByteStream Stream(BinaryData);
+ BinaryByteStream Stream(BinaryData, llvm::support::little);
CVSymbolArray Symbols;
- StreamReader Reader(Stream);
+ BinaryStreamReader Reader(Stream);
if (auto EC = Reader.readArray(Symbols, Reader.getLength())) {
consumeError(std::move(EC));
W.flush();
@@ -982,8 +983,8 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
}
void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) {
- msf::ByteStream S(Subsection);
- msf::StreamReader SR(S);
+ BinaryByteStream S(Subsection, llvm::support::little);
+ BinaryStreamReader SR(S);
while (!SR.empty()) {
DictScope S(W, "FileChecksum");
const FileChecksum *FC;
@@ -1011,8 +1012,8 @@ void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) {
}
void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {
- msf::ByteStream S(Subsection);
- msf::StreamReader SR(S);
+ BinaryByteStream S(Subsection, llvm::support::little);
+ BinaryStreamReader SR(S);
uint32_t Signature;
error(SR.readInteger(Signature));
bool HasExtraFiles = Signature == unsigned(InlineeLinesSignature::ExtraFiles);
@@ -1064,7 +1065,8 @@ void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset);
}
-void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVTypes) {
+void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVIDs,
+ TypeTableBuilder &CVTypes) {
for (const SectionRef &S : Obj->sections()) {
StringRef SectionName;
error(S.getName(SectionName));
@@ -1077,17 +1079,17 @@ void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVTypes) {
error(object_error::parse_failed);
ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(Data.data()),
Data.size());
- ByteStream Stream(Bytes);
+ BinaryByteStream Stream(Bytes, llvm::support::little);
CVTypeArray Types;
- StreamReader Reader(Stream);
+ BinaryStreamReader Reader(Stream);
if (auto EC = Reader.readArray(Types, Reader.getLength())) {
consumeError(std::move(EC));
W.flush();
error(object_error::parse_failed);
}
- if (!mergeTypeStreams(CVTypes, Types))
- return error(object_error::parse_failed);
+ if (auto EC = mergeTypeStreams(CVIDs, CVTypes, nullptr, Types))
+ return error(std::move(EC));
}
}
}
@@ -1435,12 +1437,18 @@ void COFFDumper::printCOFFImports() {
StringRef Name;
error(I.getName(Name));
W.printString("Name", Name);
- uint32_t Addr;
- error(I.getImportLookupTableRVA(Addr));
- W.printHex("ImportLookupTableRVA", Addr);
- error(I.getImportAddressTableRVA(Addr));
- W.printHex("ImportAddressTableRVA", Addr);
- printImportedSymbols(I.imported_symbols());
+ uint32_t ILTAddr;
+ error(I.getImportLookupTableRVA(ILTAddr));
+ W.printHex("ImportLookupTableRVA", ILTAddr);
+ uint32_t IATAddr;
+ error(I.getImportAddressTableRVA(IATAddr));
+ W.printHex("ImportAddressTableRVA", IATAddr);
+ // The import lookup table can be missing with certain older linkers, so
+ // fall back to the import address table in that case.
+ if (ILTAddr)
+ printImportedSymbols(I.lookup_table_symbols());
+ else
+ printImportedSymbols(I.imported_symbols());
}
// Delay imports
@@ -1549,20 +1557,43 @@ void COFFDumper::printStackMap() const {
}
void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
+ llvm::codeview::TypeTableBuilder &IDTable,
llvm::codeview::TypeTableBuilder &CVTypes) {
// Flatten it first, then run our dumper on it.
- ListScope S(Writer, "MergedTypeStream");
- SmallString<0> Buf;
+ SmallString<0> TypeBuf;
CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
- Buf.append(Record.begin(), Record.end());
+ TypeBuf.append(Record.begin(), Record.end());
});
TypeDatabase TypeDB;
- CVTypeDumper CVTD(TypeDB);
- TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
- if (auto EC =
- CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()}, TDV)) {
- Writer.flush();
- error(llvm::errorToErrorCode(std::move(EC)));
+ {
+ ListScope S(Writer, "MergedTypeStream");
+ CVTypeDumper CVTD(TypeDB);
+ TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
+ if (auto EC = CVTD.dump(
+ {TypeBuf.str().bytes_begin(), TypeBuf.str().bytes_end()}, TDV)) {
+ Writer.flush();
+ error(std::move(EC));
+ }
+ }
+
+ // Flatten the id stream and print it next. The ID stream refers to names from
+ // the type stream.
+ SmallString<0> IDBuf;
+ IDTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
+ IDBuf.append(Record.begin(), Record.end());
+ });
+
+ {
+ ListScope S(Writer, "MergedIDStream");
+ TypeDatabase IDDB;
+ CVTypeDumper CVTD(IDDB);
+ TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
+ TDV.setItemDB(IDDB);
+ if (auto EC = CVTD.dump(
+ {IDBuf.str().bytes_begin(), IDBuf.str().bytes_end()}, TDV)) {
+ Writer.flush();
+ error(std::move(EC));
+ }
}
}
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
index 997af568d3944..7893eea5d2209 100644
--- a/tools/llvm-readobj/ELFDumper.cpp
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -12,7 +12,6 @@
///
//===----------------------------------------------------------------------===//
-#include "ARMAttributeParser.h"
#include "ARMEHABIPrinter.h"
#include "Error.h"
#include "ObjDumper.h"
@@ -22,6 +21,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
@@ -129,7 +129,7 @@ public:
void printMipsReginfo() override;
void printMipsOptions() override;
- void printAMDGPURuntimeMD() override;
+ void printAMDGPUCodeObjectMetadata() override;
void printStackMap() const override;
@@ -1003,6 +1003,7 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) {
LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO);
LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS);
LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_DWARF);
}
}
@@ -1892,7 +1893,7 @@ template <> void ELFDumper<ELFType<support::little, false>>::printAttributes() {
if (Contents.size() == 1)
continue;
- ARMAttributeParser(W).Parse(Contents);
+ ARMAttributeParser(&W).Parse(Contents, true);
}
}
}
@@ -2356,7 +2357,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() {
}
}
-template <class ELFT> void ELFDumper<ELFT>::printAMDGPURuntimeMD() {
+template <class ELFT> void ELFDumper<ELFT>::printAMDGPUCodeObjectMetadata() {
const Elf_Shdr *Shdr = findSectionByName(*Obj, ".note");
if (!Shdr) {
W.startLine() << "There is no .note section in the file.\n";
@@ -2364,7 +2365,7 @@ template <class ELFT> void ELFDumper<ELFT>::printAMDGPURuntimeMD() {
}
ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr));
- const uint32_t RuntimeMDNoteType = 7;
+ const uint32_t CodeObjectMetadataNoteType = 10;
for (auto I = reinterpret_cast<const Elf_Word *>(&Sec[0]),
E = I + Sec.size()/4; I != E;) {
uint32_t NameSZ = I[0];
@@ -2378,7 +2379,7 @@ template <class ELFT> void ELFDumper<ELFT>::printAMDGPURuntimeMD() {
I += alignTo<4>(NameSZ)/4;
}
- if (Name == "AMD" && Type == RuntimeMDNoteType) {
+ if (Name == "AMD" && Type == CodeObjectMetadataNoteType) {
StringRef Desc(reinterpret_cast<const char *>(I), DescSZ);
W.printString(Desc);
}
@@ -2627,6 +2628,8 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "MIPS_OPTIONS";
case SHT_MIPS_ABIFLAGS:
return "MIPS_ABIFLAGS";
+ case SHT_MIPS_DWARF:
+ return "SHT_MIPS_DWARF";
}
}
switch (Type) {
@@ -3337,9 +3340,38 @@ static std::string getGNUNoteTypeName(const uint32_t NT) {
return string;
}
+static std::string getFreeBSDNoteTypeName(const uint32_t NT) {
+ static const struct {
+ uint32_t ID;
+ const char *Name;
+ } Notes[] = {
+ {ELF::NT_FREEBSD_THRMISC, "NT_THRMISC (thrmisc structure)"},
+ {ELF::NT_FREEBSD_PROCSTAT_PROC, "NT_PROCSTAT_PROC (proc data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_FILES, "NT_PROCSTAT_FILES (files data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_VMMAP, "NT_PROCSTAT_VMMAP (vmmap data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_GROUPS, "NT_PROCSTAT_GROUPS (groups data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_UMASK, "NT_PROCSTAT_UMASK (umask data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_RLIMIT, "NT_PROCSTAT_RLIMIT (rlimit data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_OSREL, "NT_PROCSTAT_OSREL (osreldate data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_PSSTRINGS,
+ "NT_PROCSTAT_PSSTRINGS (ps_strings data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_AUXV, "NT_PROCSTAT_AUXV (auxv data)"},
+ };
+
+ for (const auto &Note : Notes)
+ if (Note.ID == NT)
+ return std::string(Note.Name);
+
+ std::string string;
+ raw_string_ostream OS(string);
+ OS << format("Unknown note type (0x%08x)", NT);
+ return string;
+}
+
template <typename ELFT>
static void printGNUNote(raw_ostream &OS, uint32_t NoteType,
- ArrayRef<typename ELFFile<ELFT>::Elf_Word> Words) {
+ ArrayRef<typename ELFFile<ELFT>::Elf_Word> Words,
+ size_t Size) {
switch (NoteType) {
default:
return;
@@ -3362,16 +3394,14 @@ static void printGNUNote(raw_ostream &OS, uint32_t NoteType,
}
case ELF::NT_GNU_BUILD_ID: {
OS << " Build ID: ";
- ArrayRef<uint8_t> ID(reinterpret_cast<const uint8_t *>(Words.data()),
- Words.size() * 4);
+ ArrayRef<uint8_t> ID(reinterpret_cast<const uint8_t *>(Words.data()), Size);
for (const auto &B : ID)
OS << format_hex_no_prefix(B, 2);
break;
}
case ELF::NT_GNU_GOLD_VERSION:
OS << " Version: "
- << StringRef(reinterpret_cast<const char *>(Words.data()),
- Words.size() * 4);
+ << StringRef(reinterpret_cast<const char *>(Words.data()), Size);
break;
}
@@ -3415,11 +3445,15 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
if (Name == "GNU") {
OS << getGNUNoteTypeName(Type) << '\n';
- printGNUNote<ELFT>(OS, Type, Descriptor);
+ printGNUNote<ELFT>(OS, Type, Descriptor, DescriptorSize);
+ } else if (Name == "FreeBSD") {
+ OS << getFreeBSDNoteTypeName(Type) << '\n';
+ } else {
+ OS << "Unknown note type: (" << format_hex(Type, 10) << ')';
}
OS << '\n';
- P = P + 3 * sizeof(Elf_Word) * alignTo<4>(NameSize) +
+ P = P + 3 * sizeof(Elf_Word) + alignTo<4>(NameSize) +
alignTo<4>(DescriptorSize);
}
};
diff --git a/tools/llvm-readobj/LLVMBuild.txt b/tools/llvm-readobj/LLVMBuild.txt
index 76dd436e21d6c..c0ed38e18d0c0 100644
--- a/tools/llvm-readobj/LLVMBuild.txt
+++ b/tools/llvm-readobj/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-readobj
parent = Tools
-required_libraries = all-targets BitReader Object DebugInfoCodeView DebugInfoMSF
+required_libraries = all-targets BitReader Object DebugInfoCodeView DebugInfoPDB DebugInfoMSF
diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp
index 01b074170ba53..39e9092799375 100644
--- a/tools/llvm-readobj/MachODumper.cpp
+++ b/tools/llvm-readobj/MachODumper.cpp
@@ -713,12 +713,30 @@ void MachODumper::printMachOVersionMin() {
case MachO::LC_VERSION_MIN_WATCHOS:
Cmd = "LC_VERSION_MIN_WATCHOS";
break;
+ case MachO::LC_BUILD_VERSION:
+ Cmd = "LC_BUILD_VERSION";
+ break;
default:
continue;
}
- MachO::version_min_command VMC = Obj->getVersionMinLoadCommand(Load);
DictScope Group(W, "MinVersion");
+ // Handle LC_BUILD_VERSION.
+ if (Load.C.cmd == MachO::LC_BUILD_VERSION) {
+ MachO::build_version_command BVC = Obj->getBuildVersionLoadCommand(Load);
+ W.printString("Cmd", Cmd);
+ W.printNumber("Size", BVC.cmdsize);
+ W.printString("Platform",
+ MachOObjectFile::getBuildPlatform(BVC.platform));
+ W.printString("Version", MachOObjectFile::getVersionString(BVC.minos));
+ if (BVC.sdk)
+ W.printString("SDK", MachOObjectFile::getVersionString(BVC.sdk));
+ else
+ W.printString("SDK", StringRef("n/a"));
+ continue;
+ }
+
+ MachO::version_min_command VMC = Obj->getVersionMinLoadCommand(Load);
W.printString("Cmd", Cmd);
W.printNumber("Size", VMC.cmdsize);
SmallString<32> Version;
diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h
index c91558ecbfa75..ff780dae57843 100644
--- a/tools/llvm-readobj/ObjDumper.h
+++ b/tools/llvm-readobj/ObjDumper.h
@@ -59,7 +59,7 @@ public:
virtual void printMipsOptions() { }
// Only implemented for AMDGPU ELF at this time.
- virtual void printAMDGPURuntimeMD() {}
+ virtual void printAMDGPUCodeObjectMetadata() {}
// Only implemented for PE/COFF.
virtual void printCOFFImports() { }
@@ -68,7 +68,8 @@ public:
virtual void printCOFFBaseReloc() { }
virtual void printCOFFDebugDirectory() { }
virtual void printCodeViewDebugInfo() { }
- virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) {}
+ virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
+ llvm::codeview::TypeTableBuilder &CVTypes) {}
// Only implemented for MachO.
virtual void printMachODataInCode() { }
@@ -96,10 +97,15 @@ std::error_code createMachODumper(const object::ObjectFile *Obj,
ScopedPrinter &Writer,
std::unique_ptr<ObjDumper> &Result);
+std::error_code createWasmDumper(const object::ObjectFile *Obj,
+ ScopedPrinter &Writer,
+ std::unique_ptr<ObjDumper> &Result);
+
void dumpCOFFImportFile(const object::COFFImportFile *File);
void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
- llvm::codeview::TypeTableBuilder &CVTypes);
+ llvm::codeview::TypeTableBuilder &IDTable,
+ llvm::codeview::TypeTableBuilder &TypeTable);
} // namespace llvm
diff --git a/tools/llvm-readobj/WasmDumper.cpp b/tools/llvm-readobj/WasmDumper.cpp
new file mode 100644
index 0000000000000..e27da3b96e5d5
--- /dev/null
+++ b/tools/llvm-readobj/WasmDumper.cpp
@@ -0,0 +1,177 @@
+//===-- WasmDumper.cpp - Wasm-specific object file dumper -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Wasm-specific dumper for llvm-readobj.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "ObjDumper.h"
+#include "llvm-readobj.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+
+static const EnumEntry<unsigned> WasmSymbolTypes[] = {
+#define ENUM_ENTRY(X) { #X, static_cast<unsigned>(WasmSymbol::SymbolType::X) }
+ ENUM_ENTRY(FUNCTION_IMPORT),
+ ENUM_ENTRY(FUNCTION_EXPORT),
+ ENUM_ENTRY(GLOBAL_IMPORT),
+ ENUM_ENTRY(GLOBAL_EXPORT),
+ ENUM_ENTRY(DEBUG_FUNCTION_NAME),
+#undef ENUM_ENTRY
+};
+
+static const EnumEntry<uint32_t> WasmSectionTypes[] = {
+#define ENUM_ENTRY(X) { #X, wasm::WASM_SEC_##X }
+ ENUM_ENTRY(CUSTOM),
+ ENUM_ENTRY(TYPE),
+ ENUM_ENTRY(IMPORT),
+ ENUM_ENTRY(FUNCTION),
+ ENUM_ENTRY(TABLE),
+ ENUM_ENTRY(MEMORY),
+ ENUM_ENTRY(GLOBAL),
+ ENUM_ENTRY(EXPORT),
+ ENUM_ENTRY(START),
+ ENUM_ENTRY(ELEM),
+ ENUM_ENTRY(CODE),
+ ENUM_ENTRY(DATA),
+#undef ENUM_ENTRY
+};
+
+class WasmDumper : public ObjDumper {
+public:
+ WasmDumper(const WasmObjectFile *Obj, ScopedPrinter &Writer)
+ : ObjDumper(Writer), Obj(Obj) {}
+
+ void printFileHeaders() override;
+ void printSections() override;
+ void printRelocations() override;
+ void printSymbols() override;
+ void printDynamicSymbols() override { llvm_unreachable("unimplemented"); }
+ void printUnwindInfo() override { llvm_unreachable("unimplemented"); }
+ void printStackMap() const override { llvm_unreachable("unimplemented"); }
+
+protected:
+ void printSymbol(const SymbolRef &Sym);
+ void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
+
+private:
+ const WasmObjectFile *Obj;
+};
+
+void WasmDumper::printFileHeaders() {
+ W.printHex("Version", Obj->getHeader().Version);
+}
+
+void WasmDumper::printRelocation(const SectionRef &Section,
+ const RelocationRef &Reloc) {
+ SmallString<64> RelocTypeName;
+ uint64_t RelocType = Reloc.getType();
+ Reloc.getTypeName(RelocTypeName);
+ const wasm::WasmRelocation &WasmReloc = Obj->getWasmRelocation(Reloc);
+
+ if (opts::ExpandRelocs) {
+ DictScope Group(W, "Relocation");
+ W.printNumber("Type", RelocTypeName, RelocType);
+ W.printHex("Offset", Reloc.getOffset());
+ W.printHex("Index", WasmReloc.Index);
+ W.printHex("Addend", WasmReloc.Addend);
+ } else {
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Reloc.getOffset())
+ << " " << RelocTypeName << "[" << WasmReloc.Index << "]"
+ << " " << W.hex(WasmReloc.Addend) << "\n";
+ }
+}
+
+void WasmDumper::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ int SectionNumber = 0;
+ for (const SectionRef &Section : Obj->sections()) {
+ bool PrintedGroup = false;
+ StringRef Name;
+ error(Section.getName(Name));
+ ++SectionNumber;
+
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ if (!PrintedGroup) {
+ W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(Section, Reloc);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+void WasmDumper::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ for (const SymbolRef &Symbol : Obj->symbols())
+ printSymbol(Symbol);
+}
+
+void WasmDumper::printSections() {
+ ListScope Group(W, "Sections");
+ for (const SectionRef &Section : Obj->sections()) {
+ const WasmSection &WasmSec = Obj->getWasmSection(Section);
+ DictScope SectionD(W, "Section");
+ W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes));
+ W.printNumber("Size", (uint64_t)WasmSec.Content.size());
+ W.printNumber("Offset", WasmSec.Offset);
+ if (WasmSec.Type == wasm::WASM_SEC_CUSTOM) {
+ W.printString("Name", WasmSec.Name);
+ }
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (const RelocationRef &Reloc : Section.relocations())
+ printRelocation(Section, Reloc);
+ }
+
+ if (opts::SectionData) {
+ W.printBinaryBlock("SectionData", WasmSec.Content);
+ }
+ }
+}
+
+void WasmDumper::printSymbol(const SymbolRef &Sym) {
+ DictScope D(W, "Symbol");
+ WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl());
+ W.printString("Name", Symbol.Name);
+ W.printEnum("Type", static_cast<unsigned>(Symbol.Type), makeArrayRef(WasmSymbolTypes));
+}
+
+}
+
+namespace llvm {
+
+std::error_code createWasmDumper(const object::ObjectFile *Obj,
+ ScopedPrinter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
+ const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(Obj);
+ assert(WasmObj && "createWasmDumper called with non-wasm object");
+
+ Result.reset(new WasmDumper(WasmObj, Writer));
+ return readobj_error::success;
+}
+
+} // namespace llvm
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index 970e1545de0ad..bc2a62e799ab0 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -186,9 +186,10 @@ namespace opts {
cl::opt<bool> MipsOptions("mips-options",
cl::desc("Display the MIPS .MIPS.options section"));
- // -amdgpu-runtime-metadata
- cl::opt<bool> AMDGPURuntimeMD("amdgpu-runtime-metadata",
- cl::desc("Display AMDGPU runtime metadata"));
+ // -amdgpu-code-object-metadata
+ cl::opt<bool> AMDGPUCodeObjectMetadata(
+ "amdgpu-code-object-metadata",
+ cl::desc("Display AMDGPU code object metadata"));
// -coff-imports
cl::opt<bool>
@@ -337,10 +338,12 @@ static bool isMipsArch(unsigned Arch) {
}
namespace {
struct ReadObjTypeTableBuilder {
- ReadObjTypeTableBuilder() : Allocator(), Builder(Allocator) {}
+ ReadObjTypeTableBuilder()
+ : Allocator(), IDTable(Allocator), TypeTable(Allocator) {}
llvm::BumpPtrAllocator Allocator;
- llvm::codeview::TypeTableBuilder Builder;
+ llvm::codeview::TypeTableBuilder IDTable;
+ llvm::codeview::TypeTableBuilder TypeTable;
};
}
static ReadObjTypeTableBuilder CVTypes;
@@ -358,6 +361,8 @@ static std::error_code createDumper(const ObjectFile *Obj,
return createELFDumper(Obj, Writer, Result);
if (Obj->isMachO())
return createMachODumper(Obj, Writer, Result);
+ if (Obj->isWasm())
+ return createWasmDumper(Obj, Writer, Result);
return readobj_error::unsupported_obj_file_format;
}
@@ -420,8 +425,8 @@ static void dumpObject(const ObjectFile *Obj) {
Dumper->printMipsOptions();
}
if (Obj->getArch() == llvm::Triple::amdgcn)
- if (opts::AMDGPURuntimeMD)
- Dumper->printAMDGPURuntimeMD();
+ if (opts::AMDGPUCodeObjectMetadata)
+ Dumper->printAMDGPUCodeObjectMetadata();
if (opts::SectionGroups)
Dumper->printGroupSections();
if (opts::HashHistogram)
@@ -443,7 +448,7 @@ static void dumpObject(const ObjectFile *Obj) {
if (opts::CodeView)
Dumper->printCodeViewDebugInfo();
if (opts::CodeViewMergedTypes)
- Dumper->mergeCodeViewTypes(CVTypes.Builder);
+ Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable);
}
if (Obj->isMachO()) {
if (opts::MachODataInCode)
@@ -548,7 +553,7 @@ int main(int argc, const char *argv[]) {
if (opts::CodeViewMergedTypes) {
ScopedPrinter W(outs());
- dumpCodeViewMergedTypes(W, CVTypes.Builder);
+ dumpCodeViewMergedTypes(W, CVTypes.IDTable, CVTypes.TypeTable);
}
return 0;
diff --git a/tools/llvm-shlib/CMakeLists.txt b/tools/llvm-shlib/CMakeLists.txt
index edadb82c3b435..c68a2b0e60eae 100644
--- a/tools/llvm-shlib/CMakeLists.txt
+++ b/tools/llvm-shlib/CMakeLists.txt
@@ -37,7 +37,7 @@ endif()
add_llvm_library(LLVM SHARED DISABLE_LLVM_LINK_LLVM_DYLIB SONAME ${SOURCES})
list(REMOVE_DUPLICATES LIB_NAMES)
-if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" OR MINGW) # FIXME: It should be "GNU ld for elf"
+if(("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") OR (MINGW) OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "DragonFly")) # FIXME: It should be "GNU ld for elf"
# GNU ld doesn't resolve symbols in the version script.
set(LIB_NAMES -Wl,--whole-archive ${LIB_NAMES} -Wl,--no-whole-archive)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp
index 731a24d0ac2d2..74b7735f8cd15 100644
--- a/tools/llvm-stress/llvm-stress.cpp
+++ b/tools/llvm-stress/llvm-stress.cpp
@@ -28,6 +28,7 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/ToolOutputFile.h"
#include <algorithm>
+#include <random>
#include <vector>
namespace llvm {
@@ -113,6 +114,12 @@ public:
return Rand64() % y;
}
+ /// Make this like a C++11 random device
+ typedef uint32_t result_type;
+ uint32_t operator()() { return Rand32(); }
+ static constexpr result_type min() { return 0; }
+ static constexpr result_type max() { return 0x7ffff; }
+
private:
unsigned Seed;
};
@@ -417,7 +424,9 @@ struct AllocaModifier: public Modifier {
void Act() override {
Type *Tp = pickType();
- PT->push_back(new AllocaInst(Tp, "A", BB->getFirstNonPHI()));
+ const DataLayout &DL = BB->getModule()->getDataLayout();
+ PT->push_back(new AllocaInst(Tp, DL.getAllocaAddrSpace(),
+ "A", BB->getFirstNonPHI()));
}
};
@@ -662,7 +671,7 @@ static void IntroduceControlFlow(Function *F, Random &R) {
BoolInst.push_back(&Instr);
}
- std::random_shuffle(BoolInst.begin(), BoolInst.end(), R);
+ std::shuffle(BoolInst.begin(), BoolInst.end(), R);
for (auto *Instr : BoolInst) {
BasicBlock *Curr = Instr->getParent();
diff --git a/tools/llvm-strings/llvm-strings.cpp b/tools/llvm-strings/llvm-strings.cpp
index e750995331e33..5053e9b97b78d 100644
--- a/tools/llvm-strings/llvm-strings.cpp
+++ b/tools/llvm-strings/llvm-strings.cpp
@@ -15,6 +15,7 @@
#include "llvm/Object/Binary.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
@@ -40,27 +41,50 @@ static cl::opt<int>
cl::init(4));
static cl::alias MinLengthShort("n", cl::desc(""), cl::aliasopt(MinLength));
+enum radix { none, octal, hexadecimal, decimal };
+static cl::opt<radix>
+ Radix("radix", cl::desc("print the offset within the file"),
+ cl::values(clEnumValN(octal, "o", "octal"),
+ clEnumValN(hexadecimal, "x", "hexadecimal"),
+ clEnumValN(decimal, "d", "decimal")),
+ cl::init(none));
+static cl::alias RadixShort("t", cl::desc(""), cl::aliasopt(Radix));
+
static void strings(raw_ostream &OS, StringRef FileName, StringRef Contents) {
- auto print = [&OS, FileName](StringRef L) {
+ auto print = [&OS, FileName](unsigned Offset, StringRef L) {
if (L.size() < static_cast<size_t>(MinLength))
return;
if (PrintFileName)
- OS << FileName << ": ";
- OS << L << '\n';
+ OS << FileName << ":";
+ switch (Radix) {
+ case none:
+ break;
+ case octal:
+ OS << format("%8o", Offset);
+ break;
+ case hexadecimal:
+ OS << format("%8x", Offset);
+ break;
+ case decimal:
+ OS << format("%8u", Offset);
+ break;
+ }
+ OS << " " << L << '\n';
};
+ const char *B = Contents.begin();
const char *P = nullptr, *E = nullptr, *S = nullptr;
for (P = Contents.begin(), E = Contents.end(); P < E; ++P) {
if (std::isgraph(*P) || std::isblank(*P)) {
if (S == nullptr)
S = P;
} else if (S) {
- print(StringRef(S, P - S));
+ print(S - B, StringRef(S, P - S));
S = nullptr;
}
}
if (S)
- print(StringRef(S, E - S));
+ print(S - B, StringRef(S, E - S));
}
int main(int argc, char **argv) {
diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp
index fc37dea4c484d..c9e0cc2b3b05c 100644
--- a/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -85,6 +85,9 @@ static cl::opt<int> ClPrintSourceContextLines(
"print-source-context-lines", cl::init(0),
cl::desc("Print N number of source file context"));
+static cl::opt<bool> ClVerbose("verbose", cl::init(false),
+ cl::desc("Print verbose line info"));
+
template<typename T>
static bool error(Expected<T> &ResOrErr) {
if (ResOrErr)
@@ -160,7 +163,7 @@ int main(int argc, char **argv) {
LLVMSymbolizer Symbolizer(Opts);
DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None,
- ClPrettyPrint, ClPrintSourceContextLines);
+ ClPrettyPrint, ClPrintSourceContextLines, ClVerbose);
const int kMaxInputStringLength = 1024;
char InputString[kMaxInputStringLength];
diff --git a/tools/llvm-xray/CMakeLists.txt b/tools/llvm-xray/CMakeLists.txt
index abcd7d932110a..3baf4e64e81cb 100644
--- a/tools/llvm-xray/CMakeLists.txt
+++ b/tools/llvm-xray/CMakeLists.txt
@@ -9,9 +9,11 @@ set(LLVM_LINK_COMPONENTS
set(LLVM_XRAY_TOOLS
func-id-helper.cc
xray-account.cc
+ xray-color-helper.cc
xray-converter.cc
xray-extract.cc
xray-extract.cc
+ xray-graph.cc
xray-registry.cc)
add_llvm_tool(llvm-xray llvm-xray.cc ${LLVM_XRAY_TOOLS})
diff --git a/tools/llvm-xray/llvm-xray.cc b/tools/llvm-xray/llvm-xray.cc
index ac5faaa408b50..98303e7be15c0 100644
--- a/tools/llvm-xray/llvm-xray.cc
+++ b/tools/llvm-xray/llvm-xray.cc
@@ -30,12 +30,20 @@ int main(int argc, char *argv[]) {
" This program consolidates multiple XRay trace "
"processing tools for convenient access.\n");
for (auto *SC : cl::getRegisteredSubcommands()) {
- if (*SC)
+ if (*SC) {
+ // If no subcommand was provided, we need to explicitly check if this is
+ // the top-level subcommand.
+ if (SC == &*cl::TopLevelSubCommand) {
+ cl::PrintHelpMessage(false, true);
+ return 0;
+ }
if (auto C = dispatch(SC)) {
ExitOnError("llvm-xray: ")(C());
return 0;
}
+ }
}
+ // If all else fails, we still print the usage message.
cl::PrintHelpMessage(false, true);
}
diff --git a/tools/llvm-xray/xray-account.cc b/tools/llvm-xray/xray-account.cc
index 671a5a073eecc..13654c3911f77 100644
--- a/tools/llvm-xray/xray-account.cc
+++ b/tools/llvm-xray/xray-account.cc
@@ -18,10 +18,10 @@
#include <utility>
#include "xray-account.h"
-#include "xray-extract.h"
#include "xray-registry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
using namespace llvm;
@@ -120,16 +120,6 @@ static cl::opt<std::string>
static cl::alias AccountInstrMap2("m", cl::aliasopt(AccountInstrMap),
cl::desc("Alias for -instr_map"),
cl::sub(Account));
-static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
- "instr-map-format", cl::desc("format of instrumentation map"),
- cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
- "instrumentation map in an ELF header"),
- clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
- "yaml", "instrumentation map in YAML")),
- cl::sub(Account), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
-static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
- cl::desc("Alias for -instr-map-format"),
- cl::sub(Account));
namespace {
@@ -418,67 +408,63 @@ void LatencyAccountant::exportStatsAsCSV(raw_ostream &OS,
using namespace llvm::xray;
static CommandRegistration Unused(&Account, []() -> Error {
- int Fd;
- auto EC = sys::fs::openFileForRead(AccountInput, Fd);
- if (EC)
- return make_error<StringError>(
- Twine("Cannot open file '") + AccountInput + "'", EC);
-
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(AccountInstrMap, InstrMapFormat,
- Err);
- if (auto E = handleErrors(
- std::move(Err), [&](std::unique_ptr<StringError> SE) -> Error {
- if (SE->convertToErrorCode() == std::errc::no_such_file_or_directory)
- return Error::success();
- return Error(std::move(SE));
- }))
- return E;
+ InstrumentationMap Map;
+ if (!AccountInstrMap.empty()) {
+ auto InstrumentationMapOrError = loadInstrumentationMap(AccountInstrMap);
+ if (!InstrumentationMapOrError)
+ return joinErrors(make_error<StringError>(
+ Twine("Cannot open instrumentation map '") +
+ AccountInstrMap + "'",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
+ Map = std::move(*InstrumentationMapOrError);
+ }
+ std::error_code EC;
raw_fd_ostream OS(AccountOutput, EC, sys::fs::OpenFlags::F_Text);
if (EC)
return make_error<StringError>(
Twine("Cannot open file '") + AccountOutput + "' for writing.", EC);
- const auto &FunctionAddresses = Extractor.getFunctionAddresses();
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
symbolize::LLVMSymbolizer::Options Opts(
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
symbolize::LLVMSymbolizer Symbolizer(Opts);
llvm::xray::FuncIdConversionHelper FuncIdHelper(AccountInstrMap, Symbolizer,
FunctionAddresses);
xray::LatencyAccountant FCA(FuncIdHelper, AccountDeduceSiblingCalls);
- if (auto TraceOrErr = loadTraceFile(AccountInput)) {
- auto &T = *TraceOrErr;
- for (const auto &Record : T) {
- if (FCA.accountRecord(Record))
- continue;
- for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) {
- errs() << "Thread ID: " << ThreadStack.first << "\n";
- auto Level = ThreadStack.second.size();
- for (const auto &Entry : llvm::reverse(ThreadStack.second))
- errs() << "#" << Level-- << "\t"
- << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n';
- }
- if (!AccountKeepGoing)
- return make_error<StringError>(
- Twine("Failed accounting function calls in file '") + AccountInput +
- "'.",
- std::make_error_code(std::errc::executable_format_error));
- }
- switch (AccountOutputFormat) {
- case AccountOutputFormats::TEXT:
- FCA.exportStatsAsText(OS, T.getFileHeader());
- break;
- case AccountOutputFormats::CSV:
- FCA.exportStatsAsCSV(OS, T.getFileHeader());
- break;
- }
- } else {
+ auto TraceOrErr = loadTraceFile(AccountInput);
+ if (!TraceOrErr)
return joinErrors(
make_error<StringError>(
Twine("Failed loading input file '") + AccountInput + "'",
std::make_error_code(std::errc::executable_format_error)),
TraceOrErr.takeError());
+
+ auto &T = *TraceOrErr;
+ for (const auto &Record : T) {
+ if (FCA.accountRecord(Record))
+ continue;
+ for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) {
+ errs() << "Thread ID: " << ThreadStack.first << "\n";
+ auto Level = ThreadStack.second.size();
+ for (const auto &Entry : llvm::reverse(ThreadStack.second))
+ errs() << "#" << Level-- << "\t"
+ << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n';
+ }
+ if (!AccountKeepGoing)
+ return make_error<StringError>(
+ Twine("Failed accounting function calls in file '") + AccountInput +
+ "'.",
+ std::make_error_code(std::errc::executable_format_error));
+ }
+ switch (AccountOutputFormat) {
+ case AccountOutputFormats::TEXT:
+ FCA.exportStatsAsText(OS, T.getFileHeader());
+ break;
+ case AccountOutputFormats::CSV:
+ FCA.exportStatsAsCSV(OS, T.getFileHeader());
+ break;
}
return Error::success();
diff --git a/tools/llvm-xray/xray-color-helper.cc b/tools/llvm-xray/xray-color-helper.cc
new file mode 100644
index 0000000000000..925bb7483d8f0
--- /dev/null
+++ b/tools/llvm-xray/xray-color-helper.cc
@@ -0,0 +1,198 @@
+//===-- xray-graph.cc - XRay Function Call Graph Renderer -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A class to get a color from a specified gradient.
+//
+//===----------------------------------------------------------------------===//
+#include <algorithm>
+
+#include "xray-color-helper.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace xray;
+
+// Sequential ColorMaps, which are used to represent information
+// from some minimum to some maximum.
+
+static const std::tuple<uint8_t, uint8_t, uint8_t> SequentialMaps[][9] = {
+ {// The greys color scheme from http://colorbrewer2.org/
+ std::make_tuple(255, 255, 255), std::make_tuple(240, 240, 240),
+ std::make_tuple(217, 217, 217), std::make_tuple(189, 189, 189),
+ std::make_tuple(150, 150, 150), std::make_tuple(115, 115, 115),
+ std::make_tuple(82, 82, 82), std::make_tuple(37, 37, 37),
+ std::make_tuple(0, 0, 0)},
+ {// The OrRd color scheme from http://colorbrewer2.org/
+ std::make_tuple(255, 247, 236), std::make_tuple(254, 232, 200),
+ std::make_tuple(253, 212, 158), std::make_tuple(253, 187, 132),
+ std::make_tuple(252, 141, 89), std::make_tuple(239, 101, 72),
+ std::make_tuple(215, 48, 31), std::make_tuple(179, 0, 0),
+ std::make_tuple(127, 0, 0)},
+ {// The PuBu color scheme from http://colorbrewer2.org/
+ std::make_tuple(255, 247, 251), std::make_tuple(236, 231, 242),
+ std::make_tuple(208, 209, 230), std::make_tuple(166, 189, 219),
+ std::make_tuple(116, 169, 207), std::make_tuple(54, 144, 192),
+ std::make_tuple(5, 112, 176), std::make_tuple(4, 90, 141),
+ std::make_tuple(2, 56, 88)}};
+
+ColorHelper::ColorHelper(ColorHelper::SequentialScheme S)
+ : MinIn(0.0), MaxIn(1.0), ColorMap(SequentialMaps[static_cast<int>(S)]) {}
+
+// Diverging ColorMaps, which are used to represent information
+// representing differenes, or a range that goes from negative to positive.
+// These take an input in the range [-1,1].
+
+static const std::tuple<uint8_t, uint8_t, uint8_t> DivergingCoeffs[][11] = {
+ {// The PiYG color scheme from http://colorbrewer2.org/
+ std::make_tuple(142, 1, 82), std::make_tuple(197, 27, 125),
+ std::make_tuple(222, 119, 174), std::make_tuple(241, 182, 218),
+ std::make_tuple(253, 224, 239), std::make_tuple(247, 247, 247),
+ std::make_tuple(230, 245, 208), std::make_tuple(184, 225, 134),
+ std::make_tuple(127, 188, 65), std::make_tuple(77, 146, 33),
+ std::make_tuple(39, 100, 25)}};
+
+ColorHelper::ColorHelper(ColorHelper::DivergingScheme S)
+ : MinIn(-1.0), MaxIn(1.0), ColorMap(DivergingCoeffs[static_cast<int>(S)]) {}
+
+// Takes a tuple of uint8_ts representing a color in RGB and converts them to
+// HSV represented by a tuple of doubles
+static std::tuple<double, double, double>
+convertToHSV(const std::tuple<uint8_t, uint8_t, uint8_t> &Color) {
+ double Scaled[3] = {std::get<0>(Color) / 255.0, std::get<1>(Color) / 255.0,
+ std::get<2>(Color) / 255.0};
+ int Min = 0;
+ int Max = 0;
+ for (int i = 1; i < 3; ++i) {
+ if (Scaled[i] < Scaled[Min])
+ Min = i;
+ if (Scaled[i] > Scaled[Max])
+ Max = i;
+ }
+
+ double C = Scaled[Max] - Scaled[Min];
+
+ double HPrime = (Scaled[(Max + 1) % 3] - Scaled[(Max + 2) % 3]) / C;
+ HPrime = HPrime + 2.0 * Max;
+
+ double H = (HPrime < 0) ? (HPrime + 6.0) * 60
+ : HPrime * 60; // Scale to between 0 and 360
+
+ double V = Scaled[Max];
+
+ double S = (V == 0.0) ? 0.0 : C / V;
+
+ return std::make_tuple(H, S, V);
+}
+
+// Takes a double precision number, clips it between 0 and 1 and then converts
+// that to an integer between 0x00 and 0xFF with proxpper rounding.
+static uint8_t unitIntervalTo8BitChar(double B) {
+ double n = std::max(std::min(B, 1.0), 0.0);
+ return static_cast<uint8_t>(255 * n + 0.5);
+}
+
+// Takes a typle of doubles representing a color in HSV and converts them to
+// RGB represented as a tuple of uint8_ts
+static std::tuple<uint8_t, uint8_t, uint8_t>
+convertToRGB(const std::tuple<double, double, double> &Color) {
+ const double &H = std::get<0>(Color);
+ const double &S = std::get<1>(Color);
+ const double &V = std::get<2>(Color);
+
+ double C = V * S;
+
+ double HPrime = H / 60;
+ double X = C * (1 - std::abs(std::fmod(HPrime, 2.0) - 1));
+
+ double RGB1[3];
+ int HPrimeInt = static_cast<int>(HPrime);
+ if (HPrimeInt % 2 == 0) {
+ RGB1[(HPrimeInt / 2) % 3] = C;
+ RGB1[(HPrimeInt / 2 + 1) % 3] = X;
+ RGB1[(HPrimeInt / 2 + 2) % 3] = 0.0;
+ } else {
+ RGB1[(HPrimeInt / 2) % 3] = X;
+ RGB1[(HPrimeInt / 2 + 1) % 3] = C;
+ RGB1[(HPrimeInt / 2 + 2) % 3] = 0.0;
+ }
+
+ double Min = V - C;
+ double RGB2[3] = {RGB1[0] + Min, RGB1[1] + Min, RGB1[2] + Min};
+
+ return std::make_tuple(unitIntervalTo8BitChar(RGB2[0]),
+ unitIntervalTo8BitChar(RGB2[1]),
+ unitIntervalTo8BitChar(RGB2[2]));
+}
+
+// The Hue component of the HSV interpolation Routine
+static double interpolateHue(double H0, double H1, double T) {
+ double D = H1 - H0;
+ if (H0 > H1) {
+ std::swap(H0, H1);
+
+ D = -D;
+ T = 1 - T;
+ }
+
+ if (D <= 180) {
+ return H0 + T * (H1 - H0);
+ } else {
+ H0 = H0 + 360;
+ return std::fmod(H0 + T * (H1 - H0) + 720, 360);
+ }
+}
+
+// Interpolates between two HSV Colors both represented as a tuple of doubles
+// Returns an HSV Color represented as a tuple of doubles
+static std::tuple<double, double, double>
+interpolateHSV(const std::tuple<double, double, double> &C0,
+ const std::tuple<double, double, double> &C1, double T) {
+ double H = interpolateHue(std::get<0>(C0), std::get<0>(C1), T);
+ double S = std::get<1>(C0) + T * (std::get<1>(C1) - std::get<1>(C0));
+ double V = std::get<2>(C0) + T * (std::get<2>(C1) - std::get<2>(C0));
+ return std::make_tuple(H, S, V);
+}
+
+// Get the Color as a tuple of uint8_ts
+std::tuple<uint8_t, uint8_t, uint8_t>
+ColorHelper::getColorTuple(double Point) const {
+ assert(!ColorMap.empty() && "ColorMap must not be empty!");
+ size_t MaxIndex = ColorMap.size() - 1;
+ double IntervalWidth = MaxIn - MinIn;
+ double OffsetP = Point - MinIn;
+ double SectionWidth = IntervalWidth / static_cast<double>(MaxIndex);
+ size_t SectionNo = std::floor(OffsetP / SectionWidth);
+ double T = (OffsetP - SectionNo * SectionWidth) / SectionWidth;
+
+ auto &RGBColor0 = ColorMap[SectionNo];
+ auto &RGBColor1 = ColorMap[std::min(SectionNo + 1, MaxIndex)];
+
+ auto HSVColor0 = convertToHSV(RGBColor0);
+ auto HSVColor1 = convertToHSV(RGBColor1);
+
+ auto InterpolatedHSVColor = interpolateHSV(HSVColor0, HSVColor1, T);
+ return convertToRGB(InterpolatedHSVColor);
+}
+
+// A helper method to convert a color represented as tuple of uint8s to a hex
+// string.
+std::string
+ColorHelper::getColorString(std::tuple<uint8_t, uint8_t, uint8_t> t) {
+ return llvm::formatv("#{0:X-2}{1:X-2}{2:X-2}", std::get<0>(t), std::get<1>(t),
+ std::get<2>(t));
+}
+
+// Gets a color in a gradient given a number in the interval [0,1], it does this
+// by evaluating a polynomial which maps [0, 1] -> [0, 1] for each of the R G
+// and B values in the color. It then converts this [0,1] colors to a 24 bit
+// color as a hex string.
+std::string ColorHelper::getColorString(double Point) const {
+ return getColorString(getColorTuple(Point));
+}
diff --git a/tools/llvm-xray/xray-color-helper.h b/tools/llvm-xray/xray-color-helper.h
new file mode 100644
index 0000000000000..d3c77de03cb29
--- /dev/null
+++ b/tools/llvm-xray/xray-color-helper.h
@@ -0,0 +1,81 @@
+//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A class to get a color from a specified gradient.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef XRAY_COLOR_HELPER_H
+#define XRAY_COLOR_HELPER_H
+
+#include <tuple>
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace llvm {
+namespace xray {
+
+/// The color helper class it a healper class which allows you to easily get a
+/// color in a gradient. This is used to color-code edges in XRay-Graph tools.
+///
+/// There are two types of color schemes in this class:
+/// - Sequential schemes, which are used to represent information from some
+/// minimum to some maximum. These take an input in the range [0,1]
+/// - Diverging schemes, which are used to represent information representing
+/// differenes, or a range that goes from negative to positive. These take
+/// an input in the range [-1,1].
+/// Usage;
+/// ColorHelper S(ColorHelper::SequentialScheme::OrRd); //Chose a color scheme.
+/// for (double p = 0.0; p <= 1; p += 0.1){
+/// cout() << S.getColor(p) << " \n"; // Sample the gradient at 0.1 intervals
+/// }
+///
+/// ColorHelper D(ColorHelper::DivergingScheme::Spectral); // Choose a color
+/// // scheme.
+/// for (double p= -1; p <= 1 ; p += 0.1){
+/// cout() << D.getColor(p) << " \n"; // sample the gradient at 0.1 intervals
+/// }
+class ColorHelper {
+ double MinIn;
+ double MaxIn;
+
+ ArrayRef<std::tuple<uint8_t, uint8_t, uint8_t>> ColorMap;
+
+public:
+ /// Enum of the availible Sequential Color Schemes
+ enum class SequentialScheme {
+ // Schemes based on the ColorBrewer Color schemes of the same name from
+ // http://www.colorbrewer.org/ by Cynthis A Brewer Penn State University.
+ Greys,
+ OrRd,
+ PuBu
+ };
+
+ ColorHelper(SequentialScheme S);
+
+ /// Enum of the availible Diverging Color Schemes
+ enum class DivergingScheme {
+ // Schemes based on the ColorBrewer Color schemes of the same name from
+ // http://www.colorbrewer.org/ by Cynthis A Brewer Penn State University.
+ PiYG
+ };
+
+ ColorHelper(DivergingScheme S);
+
+ // Sample the gradient at the input point.
+ std::tuple<uint8_t, uint8_t, uint8_t> getColorTuple(double Point) const;
+
+ std::string getColorString(double Point) const;
+
+ // Convert a tuple to a string
+ static std::string getColorString(std::tuple<uint8_t, uint8_t, uint8_t> t);
+};
+}
+}
+#endif
diff --git a/tools/llvm-xray/xray-converter.cc b/tools/llvm-xray/xray-converter.cc
index 1bc9b15ae12cd..2583ec951495b 100644
--- a/tools/llvm-xray/xray-converter.cc
+++ b/tools/llvm-xray/xray-converter.cc
@@ -12,13 +12,14 @@
//===----------------------------------------------------------------------===//
#include "xray-converter.h"
-#include "xray-extract.h"
#include "xray-registry.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
#include "llvm/XRay/YAMLXRayRecord.h"
@@ -72,18 +73,7 @@ static cl::opt<bool> ConvertSortInput(
static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput),
cl::desc("Alias for -sort"),
cl::sub(Convert));
-static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
- "instr-map-format", cl::desc("format of instrumentation map"),
- cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
- "instrumentation map in an ELF header"),
- clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
- "yaml", "instrumentation map in YAML")),
- cl::sub(Convert), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
-static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
- cl::desc("Alias for -instr-map-format"),
- cl::sub(Convert));
-
-using llvm::yaml::IO;
+
using llvm::yaml::Output;
void TraceConverter::exportAsYAML(const Trace &Records, raw_ostream &OS) {
@@ -95,7 +85,7 @@ void TraceConverter::exportAsYAML(const Trace &Records, raw_ostream &OS) {
for (const auto &R : Records) {
Trace.Records.push_back({R.RecordType, R.CPU, R.Type, R.FuncId,
Symbolize ? FuncIdHelper.SymbolOrNumber(R.FuncId)
- : std::to_string(R.FuncId),
+ : llvm::to_string(R.FuncId),
R.TSC, R.TId});
}
Output Out(OS, nullptr, 0);
@@ -128,7 +118,9 @@ void TraceConverter::exportAsRAWv1(const Trace &Records, raw_ostream &OS) {
// format.
for (const auto &R : Records) {
Writer.write(R.RecordType);
- Writer.write(R.CPU);
+ // The on disk naive raw format uses 8 bit CPUs, but the record has 16.
+ // There's no choice but truncation.
+ Writer.write(static_cast<uint8_t>(R.CPU));
switch (R.Type) {
case RecordTypes::ENTER:
Writer.write(uint8_t{0});
@@ -151,25 +143,26 @@ namespace xray {
static CommandRegistration Unused(&Convert, []() -> Error {
// FIXME: Support conversion to BINARY when upgrading XRay trace versions.
- int Fd;
- auto EC = sys::fs::openFileForRead(ConvertInput, Fd);
- if (EC)
- return make_error<StringError>(
- Twine("Cannot open file '") + ConvertInput + "'", EC);
-
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(ConvertInstrMap, InstrMapFormat,
- Err);
- handleAllErrors(std::move(Err),
- [&](const ErrorInfoBase &E) { E.log(errs()); });
+ InstrumentationMap Map;
+ if (!ConvertInstrMap.empty()) {
+ auto InstrumentationMapOrError = loadInstrumentationMap(ConvertInstrMap);
+ if (!InstrumentationMapOrError)
+ return joinErrors(make_error<StringError>(
+ Twine("Cannot open instrumentation map '") +
+ ConvertInstrMap + "'",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
+ Map = std::move(*InstrumentationMapOrError);
+ }
- const auto &FunctionAddresses = Extractor.getFunctionAddresses();
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
symbolize::LLVMSymbolizer::Options Opts(
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
symbolize::LLVMSymbolizer Symbolizer(Opts);
llvm::xray::FuncIdConversionHelper FuncIdHelper(ConvertInstrMap, Symbolizer,
FunctionAddresses);
llvm::xray::TraceConverter TC(FuncIdHelper, ConvertSymbolize);
+ std::error_code EC;
raw_fd_ostream OS(ConvertOutput, EC,
ConvertOutputFormat == ConvertFormats::BINARY
? sys::fs::OpenFlags::F_None
@@ -178,22 +171,22 @@ static CommandRegistration Unused(&Convert, []() -> Error {
return make_error<StringError>(
Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC);
- if (auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput)) {
- auto &T = *TraceOrErr;
- switch (ConvertOutputFormat) {
- case ConvertFormats::YAML:
- TC.exportAsYAML(T, OS);
- break;
- case ConvertFormats::BINARY:
- TC.exportAsRAWv1(T, OS);
- break;
- }
- } else {
+ auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput);
+ if (!TraceOrErr)
return joinErrors(
make_error<StringError>(
Twine("Failed loading input file '") + ConvertInput + "'.",
std::make_error_code(std::errc::executable_format_error)),
TraceOrErr.takeError());
+
+ auto &T = *TraceOrErr;
+ switch (ConvertOutputFormat) {
+ case ConvertFormats::YAML:
+ TC.exportAsYAML(T, OS);
+ break;
+ case ConvertFormats::BINARY:
+ TC.exportAsRAWv1(T, OS);
+ break;
}
return Error::success();
});
diff --git a/tools/llvm-xray/xray-extract.cc b/tools/llvm-xray/xray-extract.cc
index ecd535114a62a..26e461869a083 100644
--- a/tools/llvm-xray/xray-extract.cc
+++ b/tools/llvm-xray/xray-extract.cc
@@ -16,10 +16,7 @@
#include <type_traits>
#include <utility>
-#include "xray-extract.h"
-
#include "xray-registry.h"
-#include "xray-sleds.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
@@ -28,8 +25,8 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/XRay/InstrumentationMap.h"
using namespace llvm;
using namespace llvm::xray;
@@ -49,243 +46,40 @@ static cl::alias ExtractOutput2("o", cl::aliasopt(ExtractOutput),
cl::desc("Alias for -output"),
cl::sub(Extract));
-struct YAMLXRaySledEntry {
- int32_t FuncId;
- Hex64 Address;
- Hex64 Function;
- SledEntry::FunctionKinds Kind;
- bool AlwaysInstrument;
-};
-
-namespace llvm {
-namespace yaml {
-
-template <> struct ScalarEnumerationTraits<SledEntry::FunctionKinds> {
- static void enumeration(IO &IO, SledEntry::FunctionKinds &Kind) {
- IO.enumCase(Kind, "function-enter", SledEntry::FunctionKinds::ENTRY);
- IO.enumCase(Kind, "function-exit", SledEntry::FunctionKinds::EXIT);
- IO.enumCase(Kind, "tail-exit", SledEntry::FunctionKinds::TAIL);
- }
-};
-
-template <> struct MappingTraits<YAMLXRaySledEntry> {
- static void mapping(IO &IO, YAMLXRaySledEntry &Entry) {
- IO.mapRequired("id", Entry.FuncId);
- IO.mapRequired("address", Entry.Address);
- IO.mapRequired("function", Entry.Function);
- IO.mapRequired("kind", Entry.Kind);
- IO.mapRequired("always-instrument", Entry.AlwaysInstrument);
- }
-
- static constexpr bool flow = true;
-};
-}
-}
-
-LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLXRaySledEntry)
-
namespace {
-llvm::Error LoadBinaryInstrELF(
- StringRef Filename, std::deque<SledEntry> &OutputSleds,
- InstrumentationMapExtractor::FunctionAddressMap &InstrMap,
- InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) {
- auto ObjectFile = object::ObjectFile::createObjectFile(Filename);
-
- if (!ObjectFile)
- return ObjectFile.takeError();
-
- // FIXME: Maybe support other ELF formats. For now, 64-bit Little Endian only.
- if (!ObjectFile->getBinary()->isELF())
- return make_error<StringError>(
- "File format not supported (only does ELF).",
- std::make_error_code(std::errc::not_supported));
- if (ObjectFile->getBinary()->getArch() != Triple::x86_64)
- return make_error<StringError>(
- "File format not supported (only does ELF little endian 64-bit).",
- std::make_error_code(std::errc::not_supported));
-
- // Find the section named "xray_instr_map".
- StringRef Contents = "";
- const auto &Sections = ObjectFile->getBinary()->sections();
- auto I = find_if(Sections, [&](object::SectionRef Section) {
- StringRef Name = "";
- if (Section.getName(Name))
- return false;
- return Name == "xray_instr_map";
- });
- if (I == Sections.end())
- return make_error<StringError>(
- "Failed to find XRay instrumentation map.",
- std::make_error_code(std::errc::not_supported));
- if (I->getContents(Contents))
- return make_error<StringError>(
- "Failed to get contents of 'xray_instr_map' section.",
- std::make_error_code(std::errc::executable_format_error));
-
- // Copy the instrumentation map data into the Sleds data structure.
- auto C = Contents.bytes_begin();
- static constexpr size_t ELF64SledEntrySize = 32;
-
- if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
- return make_error<StringError>(
- "Instrumentation map entries not evenly divisible by size of an XRay "
- "sled entry in ELF64.",
- std::make_error_code(std::errc::executable_format_error));
-
- int32_t FuncId = 1;
- uint64_t CurFn = 0;
- std::deque<SledEntry> Sleds;
- for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
- DataExtractor Extractor(
- StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true,
- 8);
- Sleds.push_back({});
- auto &Entry = Sleds.back();
- uint32_t OffsetPtr = 0;
- Entry.Address = Extractor.getU64(&OffsetPtr);
- Entry.Function = Extractor.getU64(&OffsetPtr);
- auto Kind = Extractor.getU8(&OffsetPtr);
- switch (Kind) {
- case 0: // ENTRY
- Entry.Kind = SledEntry::FunctionKinds::ENTRY;
- break;
- case 1: // EXIT
- Entry.Kind = SledEntry::FunctionKinds::EXIT;
- break;
- case 2: // TAIL
- Entry.Kind = SledEntry::FunctionKinds::TAIL;
- break;
- default:
- return make_error<StringError>(
- Twine("Encountered unknown sled type ") + "'" + Twine(int32_t{Kind}) +
- "'.",
- std::make_error_code(std::errc::executable_format_error));
- }
- Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
-
- // We replicate the function id generation scheme implemented in the runtime
- // here. Ideally we should be able to break it out, or output this map from
- // the runtime, but that's a design point we can discuss later on. For now,
- // we replicate the logic and move on.
- if (CurFn == 0) {
- CurFn = Entry.Function;
- InstrMap[FuncId] = Entry.Function;
- FunctionIds[Entry.Function] = FuncId;
- }
- if (Entry.Function != CurFn) {
- ++FuncId;
- CurFn = Entry.Function;
- InstrMap[FuncId] = Entry.Function;
- FunctionIds[Entry.Function] = FuncId;
- }
- }
- OutputSleds = std::move(Sleds);
- return llvm::Error::success();
-}
-
-Error LoadYAMLInstrMap(
- StringRef Filename, std::deque<SledEntry> &Sleds,
- InstrumentationMapExtractor::FunctionAddressMap &InstrMap,
- InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) {
- int Fd;
- if (auto EC = sys::fs::openFileForRead(Filename, Fd))
- return make_error<StringError>(
- Twine("Failed opening file '") + Filename + "' for reading.", EC);
-
- uint64_t FileSize;
- if (auto EC = sys::fs::file_size(Filename, FileSize))
- return make_error<StringError>(
- Twine("Failed getting size of file '") + Filename + "'.", EC);
-
- std::error_code EC;
- sys::fs::mapped_file_region MappedFile(
- Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
- if (EC)
- return make_error<StringError>(
- Twine("Failed memory-mapping file '") + Filename + "'.", EC);
-
- std::vector<YAMLXRaySledEntry> YAMLSleds;
- Input In(StringRef(MappedFile.data(), MappedFile.size()));
- In >> YAMLSleds;
- if (In.error())
- return make_error<StringError>(
- Twine("Failed loading YAML document from '") + Filename + "'.",
- In.error());
-
- for (const auto &Y : YAMLSleds) {
- InstrMap[Y.FuncId] = Y.Function;
- FunctionIds[Y.Function] = Y.FuncId;
- Sleds.push_back(
- SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument});
- }
- return Error::success();
-}
-
-} // namespace
-
-InstrumentationMapExtractor::InstrumentationMapExtractor(std::string Filename,
- InputFormats Format,
- Error &EC) {
- ErrorAsOutParameter ErrAsOutputParam(&EC);
- if (Filename.empty()) {
- EC = Error::success();
- return;
- }
- switch (Format) {
- case InputFormats::ELF: {
- EC = handleErrors(
- LoadBinaryInstrELF(Filename, Sleds, FunctionAddresses, FunctionIds),
- [&](std::unique_ptr<ErrorInfoBase> E) {
- return joinErrors(
- make_error<StringError>(
- Twine("Cannot extract instrumentation map from '") +
- Filename + "'.",
- std::make_error_code(std::errc::executable_format_error)),
- std::move(E));
- });
- break;
- }
- case InputFormats::YAML: {
- EC = handleErrors(
- LoadYAMLInstrMap(Filename, Sleds, FunctionAddresses, FunctionIds),
- [&](std::unique_ptr<ErrorInfoBase> E) {
- return joinErrors(
- make_error<StringError>(
- Twine("Cannot load YAML instrumentation map from '") +
- Filename + "'.",
- std::make_error_code(std::errc::executable_format_error)),
- std::move(E));
- });
- break;
- }
- }
-}
-
-void InstrumentationMapExtractor::exportAsYAML(raw_ostream &OS) {
+void exportAsYAML(const InstrumentationMap &Map, raw_ostream &OS) {
// First we translate the sleds into the YAMLXRaySledEntry objects in a deque.
std::vector<YAMLXRaySledEntry> YAMLSleds;
- YAMLSleds.reserve(Sleds.size());
+ auto Sleds = Map.sleds();
+ YAMLSleds.reserve(std::distance(Sleds.begin(), Sleds.end()));
for (const auto &Sled : Sleds) {
- YAMLSleds.push_back({FunctionIds[Sled.Function], Sled.Address,
- Sled.Function, Sled.Kind, Sled.AlwaysInstrument});
+ auto FuncId = Map.getFunctionId(Sled.Function);
+ if (!FuncId)
+ return;
+ YAMLSleds.push_back({*FuncId, Sled.Address, Sled.Function, Sled.Kind,
+ Sled.AlwaysInstrument});
}
Output Out(OS, nullptr, 0);
Out << YAMLSleds;
}
+} // namespace
+
static CommandRegistration Unused(&Extract, []() -> Error {
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(
- ExtractInput, InstrumentationMapExtractor::InputFormats::ELF, Err);
- if (Err)
- return Err;
+ auto InstrumentationMapOrError = loadInstrumentationMap(ExtractInput);
+ if (!InstrumentationMapOrError)
+ return joinErrors(make_error<StringError>(
+ Twine("Cannot extract instrumentation map from '") +
+ ExtractInput + "'.",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
std::error_code EC;
raw_fd_ostream OS(ExtractOutput, EC, sys::fs::OpenFlags::F_Text);
if (EC)
return make_error<StringError>(
Twine("Cannot open file '") + ExtractOutput + "' for writing.", EC);
- Extractor.exportAsYAML(OS);
+ exportAsYAML(*InstrumentationMapOrError, OS);
return Error::success();
});
diff --git a/tools/llvm-xray/xray-extract.h b/tools/llvm-xray/xray-extract.h
deleted file mode 100644
index 91e4db36805fe..0000000000000
--- a/tools/llvm-xray/xray-extract.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//===- xray-extract.h - XRay Instrumentation Map Extraction ---------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the interface for extracting the instrumentation map from an
-// XRay-instrumented binary.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_XRAY_EXTRACT_H
-#define LLVM_TOOLS_XRAY_EXTRACT_H
-
-#include <deque>
-#include <map>
-#include <string>
-#include <unordered_map>
-
-#include "xray-sleds.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace llvm {
-namespace xray {
-
-class InstrumentationMapExtractor {
-public:
- typedef std::unordered_map<int32_t, uint64_t> FunctionAddressMap;
- typedef std::unordered_map<uint64_t, int32_t> FunctionAddressReverseMap;
-
- enum class InputFormats { ELF, YAML };
-
-private:
- std::deque<SledEntry> Sleds;
- FunctionAddressMap FunctionAddresses;
- FunctionAddressReverseMap FunctionIds;
-
-public:
- /// Loads the instrumentation map from |Filename|. Updates |EC| in case there
- /// were errors encountered opening the file. |Format| defines what the input
- /// instrumentation map is in.
- InstrumentationMapExtractor(std::string Filename, InputFormats Format,
- Error &EC);
-
- const FunctionAddressMap &getFunctionAddresses() { return FunctionAddresses; }
-
- /// Exports the loaded function address map as YAML through |OS|.
- void exportAsYAML(raw_ostream &OS);
-};
-
-} // namespace xray
-} // namespace llvm
-
-#endif // LLVM_TOOLS_XRAY_EXTRACT_H
diff --git a/tools/llvm-xray/xray-graph.cc b/tools/llvm-xray/xray-graph.cc
new file mode 100644
index 0000000000000..9be0b70c2cdd8
--- /dev/null
+++ b/tools/llvm-xray/xray-graph.cc
@@ -0,0 +1,529 @@
+//===-- xray-graph.cc - XRay Function Call Graph Renderer -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Generate a DOT file to represent the function call graph encountered in
+// the trace.
+//
+//===----------------------------------------------------------------------===//
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <system_error>
+#include <utility>
+
+#include "xray-graph.h"
+#include "xray-registry.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/XRay/InstrumentationMap.h"
+#include "llvm/XRay/Trace.h"
+#include "llvm/XRay/YAMLXRayRecord.h"
+
+using namespace llvm;
+using namespace llvm::xray;
+
+// Setup llvm-xray graph subcommand and its options.
+static cl::SubCommand GraphC("graph", "Generate function-call graph");
+static cl::opt<std::string> GraphInput(cl::Positional,
+ cl::desc("<xray log file>"),
+ cl::Required, cl::sub(GraphC));
+
+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));
+
+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));
+
+static cl::opt<std::string>
+ GraphInstrMap("instr_map",
+ cl::desc("binary with the instrumrntation map, or "
+ "a separate instrumentation map"),
+ 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));
+
+static cl::opt<bool> GraphDeduceSiblingCalls(
+ "deduce-sibling-calls",
+ cl::desc("Deduce sibling calls when unrolling function call stacks"),
+ cl::sub(GraphC), cl::init(false));
+static cl::alias
+ GraphDeduceSiblingCalls2("d", cl::aliasopt(GraphDeduceSiblingCalls),
+ cl::desc("Alias for -deduce-sibling-calls"),
+ cl::sub(GraphC));
+
+static cl::opt<GraphRenderer::StatType>
+ GraphEdgeLabel("edge-label",
+ cl::desc("Output graphs with edges labeled with this field"),
+ cl::value_desc("field"), cl::sub(GraphC),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not label Edges"),
+ clEnumValN(GraphRenderer::StatType::COUNT,
+ "count", "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ 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));
+
+static cl::opt<GraphRenderer::StatType> GraphVertexLabel(
+ "vertex-label",
+ cl::desc("Output graphs with vertices labeled with this field"),
+ cl::value_desc("field"), cl::sub(GraphC),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not label Edges"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ 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));
+
+static cl::opt<GraphRenderer::StatType> GraphEdgeColorType(
+ "color-edges",
+ cl::desc("Output graphs with edge colors determined by this field"),
+ cl::value_desc("field"), cl::sub(GraphC),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not label Edges"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ 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));
+
+static cl::opt<GraphRenderer::StatType> GraphVertexColorType(
+ "color-vertices",
+ cl::desc("Output graphs with vertex colors determined by this field"),
+ cl::value_desc("field"), cl::sub(GraphC),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not label Edges"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ 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));
+
+template <class T> T diff(T L, T R) { return std::max(L, R) - std::min(L, R); }
+
+// Updates the statistics for a GraphRenderer::TimeStat
+static void updateStat(GraphRenderer::TimeStat &S, int64_t L) {
+ S.Count++;
+ if (S.Min > L || S.Min == 0)
+ S.Min = L;
+ if (S.Max < L)
+ S.Max = L;
+ S.Sum += L;
+}
+
+// Evaluates an XRay record and performs accounting on it.
+//
+// If the record is an ENTER record it pushes the FuncID and TSC onto a
+// structure representing the call stack for that function.
+// If the record is an EXIT record it checks computes computes the ammount of
+// time the function took to complete and then stores that information in an
+// edge of the graph. If there is no matching ENTER record the function tries
+// to recover by assuming that there were EXIT records which were missed, for
+// example caused by tail call elimination and if the option is enabled then
+// then tries to recover from this.
+//
+// This funciton will also error if the records are out of order, as the trace
+// is expected to be sorted.
+//
+// The graph generated has an immaginary root for functions called by no-one at
+// FuncId 0.
+//
+// FIXME: Refactor this and account subcommand to reduce code duplication.
+Error GraphRenderer::accountRecord(const XRayRecord &Record) {
+ using std::make_error_code;
+ using std::errc;
+ if (CurrentMaxTSC == 0)
+ CurrentMaxTSC = Record.TSC;
+
+ if (Record.TSC < CurrentMaxTSC)
+ return make_error<StringError>("Records not in order",
+ make_error_code(errc::invalid_argument));
+
+ auto &ThreadStack = PerThreadFunctionStack[Record.TId];
+ switch (Record.Type) {
+ case RecordTypes::ENTER: {
+ if (G.count(Record.FuncId) == 0)
+ G[Record.FuncId].SymbolName = FuncIdHelper.SymbolOrNumber(Record.FuncId);
+ ThreadStack.push_back({Record.FuncId, Record.TSC});
+ break;
+ }
+ case RecordTypes::EXIT: {
+ // FIXME: Refactor this and the account subcommand to reduce code
+ // duplication
+ if (ThreadStack.size() == 0 || ThreadStack.back().FuncId != Record.FuncId) {
+ if (!DeduceSiblingCalls)
+ return make_error<StringError>("No matching ENTRY record",
+ make_error_code(errc::invalid_argument));
+ auto Parent = std::find_if(
+ ThreadStack.rbegin(), ThreadStack.rend(),
+ [&](const FunctionAttr &A) { return A.FuncId == Record.FuncId; });
+ if (Parent == ThreadStack.rend())
+ return make_error<StringError>(
+ "No matching Entry record in stack",
+ make_error_code(errc::invalid_argument)); // There is no matching
+ // Function for this exit.
+ while (ThreadStack.back().FuncId != Record.FuncId) {
+ TimestampT D = diff(ThreadStack.back().TSC, Record.TSC);
+ VertexIdentifier TopFuncId = ThreadStack.back().FuncId;
+ ThreadStack.pop_back();
+ assert(ThreadStack.size() != 0);
+ EdgeIdentifier EI(ThreadStack.back().FuncId, TopFuncId);
+ auto &EA = G[EI];
+ EA.Timings.push_back(D);
+ updateStat(EA.S, D);
+ updateStat(G[TopFuncId].S, D);
+ }
+ }
+ uint64_t D = diff(ThreadStack.back().TSC, Record.TSC);
+ ThreadStack.pop_back();
+ VertexIdentifier VI = ThreadStack.empty() ? 0 : ThreadStack.back().FuncId;
+ EdgeIdentifier EI(VI, Record.FuncId);
+ auto &EA = G[EI];
+ EA.Timings.push_back(D);
+ updateStat(EA.S, D);
+ updateStat(G[Record.FuncId].S, D);
+ break;
+ }
+ }
+
+ return Error::success();
+}
+
+template <typename U>
+void GraphRenderer::getStats(U begin, U end, GraphRenderer::TimeStat &S) {
+ if (begin == end) return;
+ std::ptrdiff_t MedianOff = S.Count / 2;
+ std::nth_element(begin, begin + MedianOff, end);
+ S.Median = *(begin + MedianOff);
+ std::ptrdiff_t Pct90Off = (S.Count * 9) / 10;
+ std::nth_element(begin, begin + Pct90Off, end);
+ S.Pct90 = *(begin + Pct90Off);
+ std::ptrdiff_t Pct99Off = (S.Count * 99) / 100;
+ std::nth_element(begin, begin + Pct99Off, end);
+ S.Pct99 = *(begin + Pct99Off);
+}
+
+void GraphRenderer::updateMaxStats(const GraphRenderer::TimeStat &S,
+ GraphRenderer::TimeStat &M) {
+ M.Count = std::max(M.Count, S.Count);
+ M.Min = std::max(M.Min, S.Min);
+ M.Median = std::max(M.Median, S.Median);
+ M.Pct90 = std::max(M.Pct90, S.Pct90);
+ M.Pct99 = std::max(M.Pct99, S.Pct99);
+ M.Max = std::max(M.Max, S.Max);
+ M.Sum = std::max(M.Sum, S.Sum);
+}
+
+void GraphRenderer::calculateEdgeStatistics() {
+ assert(!G.edges().empty());
+ for (auto &E : G.edges()) {
+ auto &A = E.second;
+ assert(!A.Timings.empty());
+ getStats(A.Timings.begin(), A.Timings.end(), A.S);
+ updateMaxStats(A.S, G.GraphEdgeMax);
+ }
+}
+
+void GraphRenderer::calculateVertexStatistics() {
+ std::vector<uint64_t> TempTimings;
+ for (auto &V : G.vertices()) {
+ if (V.first != 0) {
+ for (auto &E : G.inEdges(V.first)) {
+ auto &A = E.second;
+ TempTimings.insert(TempTimings.end(), A.Timings.begin(),
+ A.Timings.end());
+ }
+ getStats(TempTimings.begin(), TempTimings.end(), G[V.first].S);
+ updateMaxStats(G[V.first].S, G.GraphVertexMax);
+ TempTimings.clear();
+ }
+ }
+}
+
+// A Helper function for normalizeStatistics which normalises a single
+// TimeStat element.
+static void normalizeTimeStat(GraphRenderer::TimeStat &S,
+ double CycleFrequency) {
+ S.Min /= CycleFrequency;
+ S.Median /= CycleFrequency;
+ S.Max /= CycleFrequency;
+ S.Sum /= CycleFrequency;
+ S.Pct90 /= CycleFrequency;
+ S.Pct99 /= CycleFrequency;
+}
+
+// Normalises the statistics in the graph for a given TSC frequency.
+void GraphRenderer::normalizeStatistics(double CycleFrequency) {
+ for (auto &E : G.edges()) {
+ auto &S = E.second.S;
+ normalizeTimeStat(S, CycleFrequency);
+ }
+ for (auto &V : G.vertices()) {
+ auto &S = V.second.S;
+ normalizeTimeStat(S, CycleFrequency);
+ }
+
+ normalizeTimeStat(G.GraphEdgeMax, CycleFrequency);
+ normalizeTimeStat(G.GraphVertexMax, CycleFrequency);
+}
+
+// Returns a string containing the value of statistic field T
+std::string
+GraphRenderer::TimeStat::getAsString(GraphRenderer::StatType T) const {
+ std::string St;
+ raw_string_ostream S{St};
+ switch (T) {
+ case GraphRenderer::StatType::COUNT:
+ S << Count;
+ break;
+ case GraphRenderer::StatType::MIN:
+ S << Min;
+ break;
+ case GraphRenderer::StatType::MED:
+ S << Median;
+ break;
+ case GraphRenderer::StatType::PCT90:
+ S << Pct90;
+ break;
+ case GraphRenderer::StatType::PCT99:
+ S << Pct99;
+ break;
+ case GraphRenderer::StatType::MAX:
+ S << Max;
+ break;
+ case GraphRenderer::StatType::SUM:
+ S << Sum;
+ break;
+ case GraphRenderer::StatType::NONE:
+ break;
+ }
+ return S.str();
+}
+
+// Returns the quotient between the property T of this and another TimeStat as
+// a double
+double GraphRenderer::TimeStat::compare(StatType T, const TimeStat &O) const {
+ double retval = 0;
+ switch (T) {
+ case GraphRenderer::StatType::COUNT:
+ retval = static_cast<double>(Count) / static_cast<double>(O.Count);
+ break;
+ case GraphRenderer::StatType::MIN:
+ retval = Min / O.Min;
+ break;
+ case GraphRenderer::StatType::MED:
+ retval = Median / O.Median;
+ break;
+ case GraphRenderer::StatType::PCT90:
+ retval = Pct90 / O.Pct90;
+ break;
+ case GraphRenderer::StatType::PCT99:
+ retval = Pct99 / O.Pct99;
+ break;
+ case GraphRenderer::StatType::MAX:
+ retval = Max / O.Max;
+ break;
+ case GraphRenderer::StatType::SUM:
+ retval = Sum / O.Sum;
+ break;
+ case GraphRenderer::StatType::NONE:
+ retval = 0.0;
+ break;
+ }
+ return std::sqrt(
+ retval); // the square root here provides more dynamic contrast for
+ // low runtime edges, giving better separation and
+ // coloring lower down the call stack.
+}
+
+// Outputs a DOT format version of the Graph embedded in the GraphRenderer
+// object on OS. It does this in the expected way by itterating
+// through all edges then vertices and then outputting them and their
+// annotations.
+//
+// FIXME: output more information, better presented.
+void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H,
+ StatType ET, StatType EC, StatType VT,
+ StatType VC) {
+ G.GraphEdgeMax = {};
+ G.GraphVertexMax = {};
+ calculateEdgeStatistics();
+ calculateVertexStatistics();
+
+ if (H.CycleFrequency)
+ normalizeStatistics(H.CycleFrequency);
+
+ OS << "digraph xray {\n";
+
+ if (VT != StatType::NONE)
+ OS << "node [shape=record];\n";
+
+ for (const auto &E : G.edges()) {
+ const auto &S = E.second.S;
+ OS << "F" << E.first.first << " -> "
+ << "F" << E.first.second << " [label=\"" << S.getAsString(ET) << "\"";
+ if (EC != StatType::NONE)
+ OS << " color=\"" << CHelper.getColorString(S.compare(EC, G.GraphEdgeMax))
+ << "\"";
+ OS << "];\n";
+ }
+
+ for (const auto &V : G.vertices()) {
+ const auto &VA = V.second;
+ if (V.first == 0)
+ continue;
+ OS << "F" << V.first << " [label=\"" << (VT != StatType::NONE ? "{" : "")
+ << (VA.SymbolName.size() > 40 ? VA.SymbolName.substr(0, 40) + "..."
+ : VA.SymbolName);
+ if (VT != StatType::NONE)
+ OS << "|" << VA.S.getAsString(VT) << "}\"";
+ else
+ OS << "\"";
+ if (VC != StatType::NONE)
+ OS << " color=\"" << CHelper.getColorString(VA.S.compare(VC, G.GraphVertexMax))
+ << "\"";
+ OS << "];\n";
+ }
+ OS << "}\n";
+}
+
+// Here we register and implement the llvm-xray graph subcommand.
+// The bulk of this code reads in the options, opens the required files, uses
+// those files to create a context for analysing the xray trace, then there is a
+// short loop which actually analyses the trace, generates the graph and then
+// outputs it as a DOT.
+//
+// FIXME: include additional filtering and annalysis passes to provide more
+// specific useful information.
+static CommandRegistration Unused(&GraphC, []() -> Error {
+ InstrumentationMap Map;
+ if (!GraphInstrMap.empty()) {
+ auto InstrumentationMapOrError = loadInstrumentationMap(GraphInstrMap);
+ if (!InstrumentationMapOrError)
+ return joinErrors(
+ make_error<StringError>(
+ Twine("Cannot open instrumentation map '") + GraphInstrMap + "'",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
+ Map = std::move(*InstrumentationMapOrError);
+ }
+
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
+ symbolize::LLVMSymbolizer::Options Opts(
+ symbolize::FunctionNameKind::LinkageName, true, true, false, "");
+ symbolize::LLVMSymbolizer Symbolizer(Opts);
+ llvm::xray::FuncIdConversionHelper FuncIdHelper(GraphInstrMap, Symbolizer,
+ FunctionAddresses);
+ xray::GraphRenderer GR(FuncIdHelper, GraphDeduceSiblingCalls);
+ std::error_code EC;
+ raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::F_Text);
+ if (EC)
+ return make_error<StringError>(
+ Twine("Cannot open file '") + GraphOutput + "' for writing.", EC);
+
+ auto TraceOrErr = loadTraceFile(GraphInput, true);
+ if (!TraceOrErr)
+ return joinErrors(
+ make_error<StringError>(Twine("Failed loading input file '") +
+ GraphInput + "'",
+ make_error_code(llvm::errc::invalid_argument)),
+ TraceOrErr.takeError());
+
+ auto &Trace = *TraceOrErr;
+ const auto &Header = Trace.getFileHeader();
+
+ // Here we generate the call graph from entries we find in the trace.
+ for (const auto &Record : Trace) {
+ auto E = GR.accountRecord(Record);
+ if (!E)
+ continue;
+
+ for (const auto &ThreadStack : GR.getPerThreadFunctionStack()) {
+ errs() << "Thread ID: " << ThreadStack.first << "\n";
+ auto Level = ThreadStack.second.size();
+ for (const auto &Entry : llvm::reverse(ThreadStack.second))
+ errs() << "#" << Level-- << "\t"
+ << FuncIdHelper.SymbolOrNumber(Entry.FuncId) << '\n';
+ }
+
+ if (!GraphKeepGoing)
+ return joinErrors(make_error<StringError>(
+ "Error encountered generating the call graph.",
+ std::make_error_code(std::errc::invalid_argument)),
+ std::move(E));
+
+ handleAllErrors(std::move(E),
+ [&](const ErrorInfoBase &E) { E.log(errs()); });
+ }
+ GR.exportGraphAsDOT(OS, Header, GraphEdgeLabel, GraphEdgeColorType,
+ GraphVertexLabel, GraphVertexColorType);
+ return Error::success();
+});
diff --git a/tools/llvm-xray/xray-graph.h b/tools/llvm-xray/xray-graph.h
new file mode 100644
index 0000000000000..1c7a3c0ef454b
--- /dev/null
+++ b/tools/llvm-xray/xray-graph.h
@@ -0,0 +1,164 @@
+//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Generate a DOT file to represent the function call graph encountered in
+// the trace.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef XRAY_GRAPH_H
+#define XRAY_GRAPH_H
+
+#include <string>
+#include <vector>
+
+#include "func-id-helper.h"
+#include "xray-color-helper.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/XRay/Graph.h"
+#include "llvm/XRay/Trace.h"
+#include "llvm/XRay/XRayRecord.h"
+
+namespace llvm {
+namespace xray {
+
+/// A class encapsulating the logic related to analyzing XRay traces, producting
+/// Graphs from them and then exporting those graphs for review.
+class GraphRenderer {
+public:
+ /// An enum for enumerating the various statistics gathered on latencies
+ enum class StatType { NONE, COUNT, MIN, MED, PCT90, PCT99, MAX, SUM };
+
+ /// An inner struct for common timing statistics information
+ struct TimeStat {
+ uint64_t Count = 0;
+ double Min = 0;
+ double Median = 0;
+ double Pct90 = 0;
+ double Pct99 = 0;
+ double Max = 0;
+ double Sum = 0;
+ std::string getAsString(StatType T) const;
+ double compare(StatType T, const TimeStat &Other) const;
+ };
+ typedef uint64_t TimestampT;
+
+ /// An inner struct for storing edge attributes for our graph. Here the
+ /// attributes are mainly function call statistics.
+ ///
+ /// FIXME: expand to contain more information eg call latencies.
+ struct CallStats {
+ TimeStat S;
+ std::vector<TimestampT> Timings;
+ };
+
+ /// An Inner Struct for storing vertex attributes, at the moment just
+ /// SymbolNames, however in future we could store bulk function statistics.
+ ///
+ /// FIXME: Store more attributes based on instrumentation map.
+ struct FunctionStats {
+ std::string SymbolName;
+ TimeStat S;
+ };
+
+ struct FunctionAttr {
+ int32_t FuncId;
+ uint64_t TSC;
+ };
+
+ typedef SmallVector<FunctionAttr, 4> FunctionStack;
+
+ typedef DenseMap<llvm::sys::ProcessInfo::ProcessId, FunctionStack>
+ PerThreadFunctionStackMap;
+
+ class GraphT : public Graph<FunctionStats, CallStats, int32_t> {
+ public:
+ TimeStat GraphEdgeMax = {};
+ TimeStat GraphVertexMax = {};
+ };
+
+ GraphT G;
+ typedef typename decltype(G)::VertexIdentifier VertexIdentifier;
+ typedef typename decltype(G)::EdgeIdentifier EdgeIdentifier;
+
+ /// Use a Map to store the Function stack for each thread whilst building the
+ /// graph.
+ ///
+ /// FIXME: Perhaps we can Build this into LatencyAccountant? or vise versa?
+ PerThreadFunctionStackMap PerThreadFunctionStack;
+
+ /// Usefull object for getting human readable Symbol Names.
+ const FuncIdConversionHelper &FuncIdHelper;
+ bool DeduceSiblingCalls = false;
+ TimestampT CurrentMaxTSC = 0;
+
+ /// A private function to help implement the statistic generation functions;
+ template <typename U>
+ void getStats(U begin, U end, GraphRenderer::TimeStat &S);
+ void updateMaxStats(const TimeStat &S, TimeStat &M);
+
+ /// Calculates latency statistics for each edge and stores the data in the
+ /// Graph
+ void calculateEdgeStatistics();
+
+ /// Calculates latency statistics for each vertex and stores the data in the
+ /// Graph
+ void calculateVertexStatistics();
+
+ /// Normalises latency statistics for each edge and vertex by CycleFrequency;
+ void normalizeStatistics(double CycleFrequency);
+
+ /// An object to color gradients
+ ColorHelper CHelper;
+
+public:
+ /// Takes in a reference to a FuncIdHelper in order to have ready access to
+ /// Symbol names.
+ explicit GraphRenderer(const FuncIdConversionHelper &FuncIdHelper, bool DSC)
+ : FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC),
+ CHelper(ColorHelper::SequentialScheme::OrRd) {
+ G[0] = {};
+ }
+
+ /// Process an Xray record and expand the graph.
+ ///
+ /// This Function will return true on success, or false if records are not
+ /// presented in per-thread call-tree DFS order. (That is for each thread the
+ /// Records should be in order runtime on an ideal system.)
+ ///
+ /// FIXME: Make this more robust against small irregularities.
+ Error accountRecord(const XRayRecord &Record);
+
+ const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
+ return PerThreadFunctionStack;
+ }
+
+ /// Output the Embedded graph in DOT format on \p OS, labeling the edges by
+ /// \p T
+ void exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H,
+ StatType EdgeLabel = StatType::NONE,
+ StatType EdgeColor = StatType::NONE,
+ StatType VertexLabel = StatType::NONE,
+ StatType VertexColor = StatType::NONE);
+
+ /// Get a reference to the internal graph.
+ const GraphT &getGraph() {
+ calculateEdgeStatistics();
+ calculateVertexStatistics();
+ return G;
+ }
+};
+}
+}
+
+#endif // XRAY_GRAPH_H
diff --git a/tools/llvm-xray/xray-sleds.h b/tools/llvm-xray/xray-sleds.h
deleted file mode 100644
index 99279579ed471..0000000000000
--- a/tools/llvm-xray/xray-sleds.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//===- xray-sleds.h - XRay Sleds Data Structure ---------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the structure used to represent XRay instrumentation map entries.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
-#define LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
-
-namespace llvm {
-namespace xray {
-
-struct SledEntry {
- enum class FunctionKinds { ENTRY, EXIT, TAIL };
-
- uint64_t Address;
- uint64_t Function;
- FunctionKinds Kind;
- bool AlwaysInstrument;
-};
-
-} // namespace xray
-} // namespace llvm
-
-#endif // LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp
index a1dd4ebbccba5..1b218a64cbf56 100644
--- a/tools/lto/lto.cpp
+++ b/tools/lto/lto.cpp
@@ -44,9 +44,13 @@ static cl::opt<bool>
DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
cl::desc("Do not run the GVN load PRE pass"));
-static cl::opt<bool>
-DisableLTOVectorization("disable-lto-vectorization", cl::init(false),
- cl::desc("Do not run loop or slp vectorization during LTO"));
+static cl::opt<bool> DisableLTOVectorization(
+ "disable-lto-vectorization", cl::init(false),
+ cl::desc("Do not run loop or slp vectorization during LTO"));
+
+static cl::opt<bool> EnableFreestanding(
+ "lto-freestanding", cl::init(false),
+ cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"));
#ifdef NDEBUG
static bool VerifyByDefault = false;
@@ -159,6 +163,7 @@ static void lto_add_attrs(lto_code_gen_t cg) {
if (OptLevel < '0' || OptLevel > '3')
report_fatal_error("Optimization level must be between 0 and 3");
CG->setOptLevel(OptLevel - '0');
+ CG->setFreestanding(EnableFreestanding);
}
extern const char* lto_get_version() {
@@ -267,7 +272,7 @@ lto_module_t lto_module_create_in_local_context(const void *mem, size_t length,
lto_initialize();
llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
- // Create a local context. Ownership will be transfered to LTOModule.
+ // Create a local context. Ownership will be transferred to LTOModule.
std::unique_ptr<LLVMContext> Context = llvm::make_unique<LLVMContext>();
Context->setDiagnosticHandler(diagnosticHandler, nullptr, true);
@@ -464,6 +469,7 @@ thinlto_code_gen_t thinlto_create_codegen(void) {
lto_initialize();
ThinLTOCodeGenerator *CodeGen = new ThinLTOCodeGenerator();
CodeGen->setTargetOptions(InitTargetOptionsFromCodeGenFlags());
+ CodeGen->setFreestanding(EnableFreestanding);
if (OptLevel.getNumOccurrences()) {
if (OptLevel < '0' || OptLevel > '3')
diff --git a/tools/msbuild/CMakeLists.txt b/tools/msbuild/CMakeLists.txt
index 4f471e5408ba4..9d132ea58d5d9 100644
--- a/tools/msbuild/CMakeLists.txt
+++ b/tools/msbuild/CMakeLists.txt
@@ -1,4 +1,4 @@
-if (WIN32)
+if (MSVC)
# CPack will install a registry key in this format that we wish to reference.
set(REG_KEY "${CPACK_PACKAGE_INSTALL_REGISTRY_KEY}")
set(LIB_PATH_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
diff --git a/tools/obj2yaml/CMakeLists.txt b/tools/obj2yaml/CMakeLists.txt
index 0fab6d104dce9..ecd958d75b37b 100644
--- a/tools/obj2yaml/CMakeLists.txt
+++ b/tools/obj2yaml/CMakeLists.txt
@@ -11,5 +11,6 @@ add_llvm_tool(obj2yaml
dwarf2yaml.cpp
elf2yaml.cpp
macho2yaml.cpp
+ wasm2yaml.cpp
Error.cpp
)
diff --git a/tools/obj2yaml/dwarf2yaml.cpp b/tools/obj2yaml/dwarf2yaml.cpp
index cbf34ed5388a2..d41b44c068108 100644
--- a/tools/obj2yaml/dwarf2yaml.cpp
+++ b/tools/obj2yaml/dwarf2yaml.cpp
@@ -17,6 +17,13 @@
using namespace llvm;
+void dumpInitialLength(DataExtractor &Data, uint32_t &Offset,
+ DWARFYAML::InitialLength &InitialLength) {
+ InitialLength.TotalLength = Data.getU32(&Offset);
+ if (InitialLength.isDWARF64())
+ InitialLength.TotalLength64 = Data.getU64(&Offset);
+}
+
void dumpDebugAbbrev(DWARFContextInMemory &DCtx, DWARFYAML::Data &Y) {
auto AbbrevSetPtr = DCtx.getDebugAbbrev();
if (AbbrevSetPtr) {
@@ -31,6 +38,8 @@ void dumpDebugAbbrev(DWARFContextInMemory &DCtx, DWARFYAML::Data &Y) {
DWARFYAML::AttributeAbbrev AttAbrv;
AttAbrv.Attribute = Attribute.Attr;
AttAbrv.Form = Attribute.Form;
+ if (AttAbrv.Form == dwarf::DW_FORM_implicit_const)
+ AttAbrv.Value = *Attribute.ByteSizeOrValue;
Abbrv.Attributes.push_back(AttAbrv);
}
Y.AbbrevDecls.push_back(Abbrv);
@@ -55,7 +64,7 @@ void dumpDebugARanges(DWARFContextInMemory &DCtx, DWARFYAML::Data &Y) {
while (Set.extract(ArangesData, &Offset)) {
DWARFYAML::ARange Range;
- Range.Length = Set.getHeader().Length;
+ Range.Length.setLength(Set.getHeader().Length);
Range.Version = Set.getHeader().Version;
Range.CuOffset = Set.getHeader().CuOffset;
Range.AddrSize = Set.getHeader().AddrSize;
@@ -74,11 +83,11 @@ void dumpPubSection(DWARFContextInMemory &DCtx, DWARFYAML::PubSection &Y,
StringRef Section) {
DataExtractor PubSectionData(Section, DCtx.isLittleEndian(), 0);
uint32_t Offset = 0;
- Y.Length = PubSectionData.getU32(&Offset);
+ dumpInitialLength(PubSectionData, Offset, Y.Length);
Y.Version = PubSectionData.getU16(&Offset);
Y.UnitOffset = PubSectionData.getU32(&Offset);
Y.UnitSize = PubSectionData.getU32(&Offset);
- while (Offset < Y.Length) {
+ while (Offset < Y.Length.getLength()) {
DWARFYAML::PubEntry NewEntry;
NewEntry.DieOffset = PubSectionData.getU32(&Offset);
if (Y.IsGNUStyle)
@@ -105,8 +114,10 @@ void dumpDebugPubSections(DWARFContextInMemory &DCtx, DWARFYAML::Data &Y) {
void dumpDebugInfo(DWARFContextInMemory &DCtx, DWARFYAML::Data &Y) {
for (const auto &CU : DCtx.compile_units()) {
DWARFYAML::Unit NewUnit;
- NewUnit.Length = CU->getLength();
+ NewUnit.Length.setLength(CU->getLength());
NewUnit.Version = CU->getVersion();
+ if(NewUnit.Version >= 5)
+ NewUnit.Type = (dwarf::UnitType)CU->getUnitType();
NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset();
NewUnit.AddrSize = CU->getAddressByteSize();
for (auto DIE : CU->dies()) {
@@ -126,7 +137,7 @@ void dumpDebugInfo(DWARFContextInMemory &DCtx, DWARFYAML::Data &Y) {
DWARFYAML::FormValue NewValue;
NewValue.Value = 0xDEADBEEFDEADBEEF;
DWARFDie DIEWrapper(CU.get(), &DIE);
- auto FormValue = DIEWrapper.getAttributeValue(AttrSpec.Attr);
+ auto FormValue = DIEWrapper.find(AttrSpec.Attr);
if (!FormValue)
return;
auto Form = FormValue.getValue().getForm();
@@ -168,6 +179,8 @@ void dumpDebugInfo(DWARFContextInMemory &DCtx, DWARFYAML::Data &Y) {
case dwarf::DW_FORM_data8:
case dwarf::DW_FORM_sdata:
case dwarf::DW_FORM_udata:
+ case dwarf::DW_FORM_ref_sup4:
+ case dwarf::DW_FORM_ref_sup8:
if (auto Val = FormValue.getValue().getAsUnsignedConstant())
NewValue.Value = Val.getValue();
break;
@@ -189,7 +202,6 @@ void dumpDebugInfo(DWARFContextInMemory &DCtx, DWARFYAML::Data &Y) {
case dwarf::DW_FORM_GNU_strp_alt:
case dwarf::DW_FORM_line_strp:
case dwarf::DW_FORM_strp_sup:
- case dwarf::DW_FORM_ref_sup:
case dwarf::DW_FORM_GNU_str_index:
if (auto Val = FormValue.getValue().getAsCStringOffset())
NewValue.Value = Val.getValue();
@@ -228,19 +240,14 @@ void dumpDebugLines(DWARFContextInMemory &DCtx, DWARFYAML::Data &Y) {
if (!CUDIE)
continue;
if (auto StmtOffset =
- CUDIE.getAttributeValueAsSectionOffset(dwarf::DW_AT_stmt_list)) {
+ dwarf::toSectionOffset(CUDIE.find(dwarf::DW_AT_stmt_list))) {
DWARFYAML::LineTable DebugLines;
DataExtractor LineData(DCtx.getLineSection().Data, DCtx.isLittleEndian(),
CU->getAddressByteSize());
uint32_t Offset = *StmtOffset;
- uint64_t SizeOfPrologueLength = 4;
- DebugLines.TotalLength = LineData.getU32(&Offset);
- uint64_t LineTableLength = DebugLines.TotalLength;
- if (DebugLines.TotalLength == UINT32_MAX) {
- DebugLines.TotalLength64 = LineData.getU64(&Offset);
- LineTableLength = DebugLines.TotalLength64;
- SizeOfPrologueLength = 8;
- }
+ dumpInitialLength(LineData, Offset, DebugLines.Length);
+ uint64_t LineTableLength = DebugLines.Length.getLength();
+ uint64_t SizeOfPrologueLength = DebugLines.Length.isDWARF64() ? 8 : 4;
DebugLines.Version = LineData.getU16(&Offset);
DebugLines.PrologueLength =
LineData.getUnsigned(&Offset, SizeOfPrologueLength);
diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp
index 697ab79d3b50e..9f9ef99265dcb 100644
--- a/tools/obj2yaml/elf2yaml.cpp
+++ b/tools/obj2yaml/elf2yaml.cpp
@@ -228,10 +228,18 @@ std::error_code ELFDumper<ELFT>::dumpRelocation(const RelT *Rel,
return errorToErrorCode(StrTabOrErr.takeError());
StringRef StrTab = *StrTabOrErr;
- Expected<StringRef> NameOrErr = Sym->getName(StrTab);
- if (!NameOrErr)
- return errorToErrorCode(NameOrErr.takeError());
- R.Symbol = NameOrErr.get();
+ if (Sym) {
+ Expected<StringRef> NameOrErr = Sym->getName(StrTab);
+ if (!NameOrErr)
+ return errorToErrorCode(NameOrErr.takeError());
+ R.Symbol = NameOrErr.get();
+ } else {
+ // We have some edge cases of relocations without a symbol associated,
+ // e.g. an object containing the invalid (according to the System V
+ // ABI) R_X86_64_NONE reloc. Create a symbol with an empty name instead
+ // of crashing.
+ R.Symbol = "";
+ }
return obj2yaml_error::success;
}
diff --git a/tools/obj2yaml/macho2yaml.cpp b/tools/obj2yaml/macho2yaml.cpp
index 0c30dc7575ecc..9ad2a6d979f58 100644
--- a/tools/obj2yaml/macho2yaml.cpp
+++ b/tools/obj2yaml/macho2yaml.cpp
@@ -163,6 +163,23 @@ const char *MachODumper::processLoadCommandData<MachO::rpath_command>(
return readString<MachO::rpath_command>(LC, LoadCmd);
}
+template <>
+const char *MachODumper::processLoadCommandData<MachO::build_version_command>(
+ MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
+ auto Start = LoadCmd.Ptr + sizeof(MachO::build_version_command);
+ auto NTools = LC.Data.build_version_command_data.ntools;
+ for (unsigned i = 0; i < NTools; ++i) {
+ auto Curr = Start + i * sizeof(MachO::build_tool_version);
+ MachO::build_tool_version BV;
+ memcpy((void *)&BV, Curr, sizeof(MachO::build_tool_version));
+ if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(BV);
+ LC.Tools.push_back(BV);
+ }
+ return Start + NTools * sizeof(MachO::build_tool_version);
+}
+
Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() {
auto Y = make_unique<MachOYAML::Object>();
Y->IsLittleEndian = Obj.isLittleEndian();
diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp
index 3f9373ee17e38..31712af263627 100644
--- a/tools/obj2yaml/obj2yaml.cpp
+++ b/tools/obj2yaml/obj2yaml.cpp
@@ -24,6 +24,8 @@ static std::error_code dumpObject(const ObjectFile &Obj) {
return coff2yaml(outs(), cast<COFFObjectFile>(Obj));
if (Obj.isELF())
return elf2yaml(outs(), Obj);
+ if (Obj.isWasm())
+ return wasm2yaml(outs(), cast<WasmObjectFile>(Obj));
return obj2yaml_error::unsupported_obj_file_format;
}
diff --git a/tools/obj2yaml/obj2yaml.h b/tools/obj2yaml/obj2yaml.h
index 70d4ebdd3d14e..69c753296efda 100644
--- a/tools/obj2yaml/obj2yaml.h
+++ b/tools/obj2yaml/obj2yaml.h
@@ -14,6 +14,7 @@
#define LLVM_TOOLS_OBJ2YAML_OBJ2YAML_H
#include "llvm/Object/COFF.h"
+#include "llvm/Object/Wasm.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
@@ -23,6 +24,8 @@ std::error_code elf2yaml(llvm::raw_ostream &Out,
const llvm::object::ObjectFile &Obj);
std::error_code macho2yaml(llvm::raw_ostream &Out,
const llvm::object::Binary &Obj);
+std::error_code wasm2yaml(llvm::raw_ostream &Out,
+ const llvm::object::WasmObjectFile &Obj);
// Forward decls for dwarf2yaml
namespace llvm {
diff --git a/tools/obj2yaml/wasm2yaml.cpp b/tools/obj2yaml/wasm2yaml.cpp
new file mode 100644
index 0000000000000..f6b530c41969d
--- /dev/null
+++ b/tools/obj2yaml/wasm2yaml.cpp
@@ -0,0 +1,219 @@
+//===------ utils/wasm2yaml.cpp - obj2yaml conversion tool ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "obj2yaml.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/ObjectYAML/WasmYAML.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace llvm;
+
+namespace {
+
+class WasmDumper {
+ const object::WasmObjectFile &Obj;
+
+public:
+ WasmDumper(const object::WasmObjectFile &O) : Obj(O) {}
+ ErrorOr<WasmYAML::Object *> dump();
+};
+
+ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
+ auto Y = make_unique<WasmYAML::Object>();
+
+ // Dump header
+ Y->Header.Version = Obj.getHeader().Version;
+
+ // Dump sections
+ for (const auto &Sec : Obj.sections()) {
+ const object::WasmSection &WasmSec = Obj.getWasmSection(Sec);
+ std::unique_ptr<WasmYAML::Section> S;
+ switch (WasmSec.Type) {
+ case wasm::WASM_SEC_CUSTOM: {
+ if (WasmSec.Name.startswith("reloc.")) {
+ // Relocations are attached the sections they apply to rather than
+ // being represented as a custom section in the YAML output.
+ continue;
+ }
+ auto CustomSec = make_unique<WasmYAML::CustomSection>();
+ CustomSec->Name = WasmSec.Name;
+ CustomSec->Payload = yaml::BinaryRef(WasmSec.Content);
+ S = std::move(CustomSec);
+ break;
+ }
+ case wasm::WASM_SEC_TYPE: {
+ auto TypeSec = make_unique<WasmYAML::TypeSection>();
+ uint32_t Index = 0;
+ for (const auto &FunctionSig : Obj.types()) {
+ WasmYAML::Signature Sig;
+ Sig.Index = Index++;
+ Sig.ReturnType = FunctionSig.ReturnType;
+ for (const auto &ParamType : FunctionSig.ParamTypes)
+ Sig.ParamTypes.push_back(ParamType);
+ TypeSec->Signatures.push_back(Sig);
+ }
+ S = std::move(TypeSec);
+ break;
+ }
+ case wasm::WASM_SEC_IMPORT: {
+ auto ImportSec = make_unique<WasmYAML::ImportSection>();
+ for (auto &Import : Obj.imports()) {
+ WasmYAML::Import Ex;
+ Ex.Module = Import.Module;
+ Ex.Field = Import.Field;
+ Ex.Kind = Import.Kind;
+ if (Ex.Kind == wasm::WASM_EXTERNAL_FUNCTION) {
+ Ex.SigIndex = Import.SigIndex;
+ } else if (Ex.Kind == wasm::WASM_EXTERNAL_GLOBAL) {
+ Ex.GlobalType = Import.GlobalType;
+ Ex.GlobalMutable = Import.GlobalMutable;
+ }
+ ImportSec->Imports.push_back(Ex);
+ }
+ S = std::move(ImportSec);
+ break;
+ }
+ case wasm::WASM_SEC_FUNCTION: {
+ auto FuncSec = make_unique<WasmYAML::FunctionSection>();
+ for (const auto &Func : Obj.functionTypes()) {
+ FuncSec->FunctionTypes.push_back(Func);
+ }
+ S = std::move(FuncSec);
+ break;
+ }
+ case wasm::WASM_SEC_TABLE: {
+ auto TableSec = make_unique<WasmYAML::TableSection>();
+ for (auto &Table : Obj.tables()) {
+ WasmYAML::Table T;
+ T.ElemType = Table.ElemType;
+ T.TableLimits.Flags = Table.Limits.Flags;
+ T.TableLimits.Initial = Table.Limits.Initial;
+ T.TableLimits.Maximum = Table.Limits.Maximum;
+ TableSec->Tables.push_back(T);
+ }
+ S = std::move(TableSec);
+ break;
+ }
+ case wasm::WASM_SEC_MEMORY: {
+ auto MemorySec = make_unique<WasmYAML::MemorySection>();
+ for (auto &Memory : Obj.memories()) {
+ WasmYAML::Limits L;
+ L.Flags = Memory.Flags;
+ L.Initial = Memory.Initial;
+ L.Maximum = Memory.Maximum;
+ MemorySec->Memories.push_back(L);
+ }
+ S = std::move(MemorySec);
+ break;
+ }
+ case wasm::WASM_SEC_GLOBAL: {
+ auto GlobalSec = make_unique<WasmYAML::GlobalSection>();
+ for (auto &Global : Obj.globals()) {
+ WasmYAML::Global G;
+ G.Type = Global.Type;
+ G.Mutable = Global.Mutable;
+ G.InitExpr = Global.InitExpr;
+ GlobalSec->Globals.push_back(G);
+ }
+ S = std::move(GlobalSec);
+ break;
+ }
+ case wasm::WASM_SEC_START: {
+ auto StartSec = make_unique<WasmYAML::StartSection>();
+ StartSec->StartFunction = Obj.startFunction();
+ S = std::move(StartSec);
+ break;
+ }
+ case wasm::WASM_SEC_EXPORT: {
+ auto ExportSec = make_unique<WasmYAML::ExportSection>();
+ for (auto &Export : Obj.exports()) {
+ WasmYAML::Export Ex;
+ Ex.Name = Export.Name;
+ Ex.Kind = Export.Kind;
+ Ex.Index = Export.Index;
+ ExportSec->Exports.push_back(Ex);
+ }
+ S = std::move(ExportSec);
+ break;
+ }
+ case wasm::WASM_SEC_ELEM: {
+ auto ElemSec = make_unique<WasmYAML::ElemSection>();
+ for (auto &Segment : Obj.elements()) {
+ WasmYAML::ElemSegment Seg;
+ Seg.TableIndex = Segment.TableIndex;
+ Seg.Offset = Segment.Offset;
+ for (auto &Func : Segment.Functions) {
+ Seg.Functions.push_back(Func);
+ }
+ ElemSec->Segments.push_back(Seg);
+ }
+ S = std::move(ElemSec);
+ break;
+ }
+ case wasm::WASM_SEC_CODE: {
+ auto CodeSec = make_unique<WasmYAML::CodeSection>();
+ for (auto &Func : Obj.functions()) {
+ WasmYAML::Function Function;
+ for (auto &Local : Func.Locals) {
+ WasmYAML::LocalDecl LocalDecl;
+ LocalDecl.Type = Local.Type;
+ LocalDecl.Count = Local.Count;
+ Function.Locals.push_back(LocalDecl);
+ }
+ Function.Body = yaml::BinaryRef(Func.Body);
+ CodeSec->Functions.push_back(Function);
+ }
+ S = std::move(CodeSec);
+ break;
+ }
+ case wasm::WASM_SEC_DATA: {
+ auto DataSec = make_unique<WasmYAML::DataSection>();
+ for (auto &Segment : Obj.dataSegments()) {
+ WasmYAML::DataSegment Seg;
+ Seg.Index = Segment.Index;
+ Seg.Offset = Segment.Offset;
+ Seg.Content = yaml::BinaryRef(Segment.Content);
+ DataSec->Segments.push_back(Seg);
+ }
+ S = std::move(DataSec);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown section type");
+ break;
+ }
+ for (const wasm::WasmRelocation &Reloc: WasmSec.Relocations) {
+ WasmYAML::Relocation R;
+ R.Type = Reloc.Type;
+ R.Index = Reloc.Index;
+ R.Offset = Reloc.Offset;
+ R.Addend = Reloc.Addend;
+ S->Relocations.push_back(R);
+ }
+ Y->Sections.push_back(std::move(S));
+ }
+
+ return Y.release();
+}
+
+} // namespace
+
+std::error_code wasm2yaml(raw_ostream &Out, const object::WasmObjectFile &Obj) {
+ WasmDumper Dumper(Obj);
+ ErrorOr<WasmYAML::Object *> YAMLOrErr = Dumper.dump();
+ if (std::error_code EC = YAMLOrErr.getError())
+ return EC;
+
+ std::unique_ptr<WasmYAML::Object> YAML(YAMLOrErr.get());
+ yaml::Output Yout(Out);
+ Yout << *YAML;
+
+ return std::error_code();
+}
diff --git a/tools/opt/GraphPrinters.cpp b/tools/opt/GraphPrinters.cpp
index 640edfee41dec..a8bb12f3e0184 100644
--- a/tools/opt/GraphPrinters.cpp
+++ b/tools/opt/GraphPrinters.cpp
@@ -35,7 +35,7 @@ namespace {
}
bool runOnFunction(Function &F) override {
- getAnalysis<DominatorTreeWrapperPass>().dump();
+ getAnalysis<DominatorTreeWrapperPass>().print(dbgs());
return false;
}
};
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index a93c06c1d13d0..40459e559986b 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -102,6 +102,11 @@ static cl::opt<bool>
OutputThinLTOBC("thinlto-bc",
cl::desc("Write output as ThinLTO-ready bitcode"));
+static cl::opt<std::string> ThinLinkBitcodeFile(
+ "thin-link-bitcode-file", cl::value_desc("filename"),
+ cl::desc(
+ "A file in which to write minimized bitcode for the thin link only"));
+
static cl::opt<bool>
NoVerify("disable-verify", cl::desc("Do not run the verifier"), cl::Hidden);
@@ -201,10 +206,10 @@ static cl::opt<bool>
PrintBreakpoints("print-breakpoints-for-testing",
cl::desc("Print select breakpoints location for testing"));
-static cl::opt<std::string>
-DefaultDataLayout("default-data-layout",
- cl::desc("data layout string to use if not specified by module"),
- cl::value_desc("layout-string"), cl::init(""));
+static cl::opt<std::string> ClDataLayout("data-layout",
+ cl::desc("data layout string to use"),
+ cl::value_desc("layout-string"),
+ cl::init(""));
static cl::opt<bool> PreserveBitcodeUseListOrder(
"preserve-bc-uselistorder",
@@ -268,7 +273,7 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
if (DisableInline) {
// No inlining pass
} else if (OptLevel > 1) {
- Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel);
+ Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false);
} else {
Builder.Inliner = createAlwaysInlinerLegacyPass();
}
@@ -287,13 +292,8 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
Builder.SLPVectorize =
DisableSLPVectorization ? false : OptLevel > 1 && SizeLevel < 2;
- // Add target-specific passes that need to run as early as possible.
if (TM)
- Builder.addExtension(
- PassManagerBuilder::EP_EarlyAsPossible,
- [&](const PassManagerBuilder &, legacy::PassManagerBase &PM) {
- TM->addEarlyAsPossiblePasses(PM);
- });
+ TM->adjustPassManager(Builder);
if (Coroutines)
addCoroutinePassesToExtensionPoints(Builder);
@@ -453,12 +453,15 @@ int main(int argc, char **argv) {
return 1;
}
- // If we are supposed to override the target triple, do so now.
+ // If we are supposed to override the target triple or data layout, do so now.
if (!TargetTriple.empty())
M->setTargetTriple(Triple::normalize(TargetTriple));
+ if (!ClDataLayout.empty())
+ M->setDataLayout(ClDataLayout);
// Figure out what stream we are supposed to write to...
std::unique_ptr<tool_output_file> Out;
+ std::unique_ptr<tool_output_file> ThinLinkOut;
if (NoOutput) {
if (!OutputFilename.empty())
errs() << "WARNING: The -o (output filename) option is ignored when\n"
@@ -474,6 +477,15 @@ int main(int argc, char **argv) {
errs() << EC.message() << '\n';
return 1;
}
+
+ if (!ThinLinkBitcodeFile.empty()) {
+ ThinLinkOut.reset(
+ new tool_output_file(ThinLinkBitcodeFile, EC, sys::fs::F_None));
+ if (EC) {
+ errs() << EC.message() << '\n';
+ return 1;
+ }
+ }
}
Triple ModuleTriple(M->getTargetTriple());
@@ -535,12 +547,6 @@ int main(int argc, char **argv) {
TLII.disableAllFunctions();
Passes.add(new TargetLibraryInfoWrapperPass(TLII));
- // Add an appropriate DataLayout instance for this module.
- const DataLayout &DL = M->getDataLayout();
- if (DL.isDefault() && !DefaultDataLayout.empty()) {
- M->setDataLayout(DefaultDataLayout);
- }
-
// Add internal analysis passes from the target machine.
Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis()
: TargetIRAnalysis()));
@@ -709,7 +715,8 @@ int main(int argc, char **argv) {
report_fatal_error("Text output is incompatible with -module-hash");
Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder));
} else if (OutputThinLTOBC)
- Passes.add(createWriteThinLTOBitcodePass(*OS));
+ Passes.add(createWriteThinLTOBitcodePass(
+ *OS, ThinLinkOut ? &ThinLinkOut->os() : nullptr));
else
Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder,
EmitSummaryIndex, EmitModuleHash));
@@ -756,5 +763,8 @@ int main(int argc, char **argv) {
if (YamlFile)
YamlFile->keep();
+ if (ThinLinkOut)
+ ThinLinkOut->keep();
+
return 0;
}
diff --git a/tools/sancov/coverage-report-server.py b/tools/sancov/coverage-report-server.py
index ac3206cba393b..428276f95d3b3 100755
--- a/tools/sancov/coverage-report-server.py
+++ b/tools/sancov/coverage-report-server.py
@@ -138,7 +138,7 @@ class ServerHandler(http.server.BaseHTTPRequestHandler):
if not file_coverage:
continue
filelist.append(
- "<tr><td><a href=\"/{name}\">{name}</a></td>"
+ "<tr><td><a href=\"./{name}\">{name}</a></td>"
"<td>{coverage}%</td></tr>".format(
name=html.escape(filename, quote=True),
coverage=format_pct(file_coverage)))
@@ -165,7 +165,7 @@ class ServerHandler(http.server.BaseHTTPRequestHandler):
["<span class='{cls}'>{line}&nbsp;</span>".format(
line=html.escape(line.rstrip()),
cls=linemap.get(line_no, ""))
- for line_no, line in enumerate(f)])
+ for line_no, line in enumerate(f, start=1)])
response = string.Template(CONTENT_PAGE_TMPL).safe_substitute(
path=self.path[1:],
diff --git a/tools/sancov/sancov.cc b/tools/sancov/sancov.cc
index ff2039de35ebe..7f103ebb904b6 100644
--- a/tools/sancov/sancov.cc
+++ b/tools/sancov/sancov.cc
@@ -96,7 +96,8 @@ cl::opt<ActionType> Action(
static cl::list<std::string>
ClInputFiles(cl::Positional, cl::OneOrMore,
- cl::desc("(<binary file>|<.sancov file>)..."));
+ cl::desc("<action> <binary files...> <.sancov files...> "
+ "<.symcov files...>"));
static cl::opt<bool> ClDemangle("demangle", cl::init(true),
cl::desc("Print demangled function name."));
@@ -179,7 +180,7 @@ struct CoverageStats {
// --------- ERROR HANDLING ---------
static void fail(const llvm::Twine &E) {
- errs() << "Error: " << E << "\n";
+ errs() << "ERROR: " << E << "\n";
exit(1);
}
@@ -191,7 +192,7 @@ static void failIf(bool B, const llvm::Twine &E) {
static void failIfError(std::error_code Error) {
if (!Error)
return;
- errs() << "Error: " << Error.message() << "(" << Error.value() << ")\n";
+ errs() << "ERROR: " << Error.message() << "(" << Error.value() << ")\n";
exit(1);
}
@@ -201,7 +202,7 @@ template <typename T> static void failIfError(const ErrorOr<T> &E) {
static void failIfError(Error Err) {
if (Err) {
- logAllUnhandledErrors(std::move(Err), errs(), "Error: ");
+ logAllUnhandledErrors(std::move(Err), errs(), "ERROR: ");
exit(1);
}
}
@@ -946,7 +947,15 @@ symbolize(const RawCoverage &Data, const std::string ObjectFile) {
Hasher.update((*BufOrErr)->getBuffer());
Coverage->BinaryHash = toHex(Hasher.final());
+ Blacklists B;
+ auto Symbolizer(createSymbolizer());
+
for (uint64_t Addr : *Data.Addrs) {
+ auto LineInfo = Symbolizer->symbolizeCode(ObjectFile, Addr);
+ failIfError(LineInfo);
+ if (B.isBlacklisted(*LineInfo))
+ continue;
+
Coverage->CoveredIds.insert(utohexstr(Addr, true));
}
@@ -1077,6 +1086,9 @@ static void readAndPrintRawCoverage(const std::vector<std::string> &FileNames,
static std::unique_ptr<SymbolizedCoverage>
merge(const std::vector<std::unique_ptr<SymbolizedCoverage>> &Coverages) {
+ if (Coverages.empty())
+ return nullptr;
+
auto Result = make_unique<SymbolizedCoverage>();
for (size_t I = 0; I < Coverages.size(); ++I) {
@@ -1159,11 +1171,17 @@ readSymbolizeAndMergeCmdArguments(std::vector<std::string> FileNames) {
CoverageByObjFile[Iter->second].push_back(FileName);
};
+ for (const auto &Pair : ObjFiles) {
+ auto FileName = Pair.second;
+ if (CoverageByObjFile.find(FileName) == CoverageByObjFile.end())
+ errs() << "WARNING: No coverage file for " << FileName << "\n";
+ }
+
// Read raw coverage and symbolize it.
for (const auto &Pair : CoverageByObjFile) {
if (findSanitizerCovFunctions(Pair.first).empty()) {
errs()
- << "Ignoring " << Pair.first
+ << "WARNING: Ignoring " << Pair.first
<< " and its coverage because __sanitizer_cov* functions were not "
"found.\n";
continue;
@@ -1192,7 +1210,17 @@ int main(int Argc, char **Argv) {
llvm::InitializeAllTargetMCs();
llvm::InitializeAllDisassemblers();
- cl::ParseCommandLineOptions(Argc, Argv, "Sanitizer Coverage Processing Tool");
+ cl::ParseCommandLineOptions(Argc, Argv,
+ "Sanitizer Coverage Processing Tool (sancov)\n\n"
+ " This tool can extract various coverage-related information from: \n"
+ " coverage-instrumented binary files, raw .sancov files and their "
+ "symbolized .symcov version.\n"
+ " Depending on chosen action the tool expects different input files:\n"
+ " -print-coverage-pcs - coverage-instrumented binary files\n"
+ " -print-coverage - .sancov files\n"
+ " <other actions> - .sancov files & corresponding binary "
+ "files, .symcov files\n"
+ );
// -print doesn't need object files.
if (Action == PrintAction) {
diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt
index 5e726496003f7..a885547598d85 100644
--- a/tools/yaml2obj/CMakeLists.txt
+++ b/tools/yaml2obj/CMakeLists.txt
@@ -8,7 +8,7 @@ set(LLVM_LINK_COMPONENTS
add_llvm_tool(yaml2obj
yaml2obj.cpp
yaml2coff.cpp
- yaml2dwarf.cpp
yaml2elf.cpp
yaml2macho.cpp
+ yaml2wasm.cpp
)
diff --git a/tools/yaml2obj/yaml2dwarf.cpp b/tools/yaml2obj/yaml2dwarf.cpp
deleted file mode 100644
index 3ceb7772b9691..0000000000000
--- a/tools/yaml2obj/yaml2dwarf.cpp
+++ /dev/null
@@ -1,330 +0,0 @@
-//===- yaml2dwarf - Convert YAML to DWARF binary data ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief The DWARF component of yaml2obj.
-///
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ObjectYAML/DWARFYAML.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/SwapByteOrder.h"
-
-#include <algorithm>
-
-using namespace llvm;
-
-template <typename T>
-void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) {
- if (IsLittleEndian != sys::IsLittleEndianHost)
- sys::swapByteOrder(Integer);
- OS.write(reinterpret_cast<char *>(&Integer), sizeof(T));
-}
-
-void writeVariableSizedInteger(uint64_t Integer, size_t Size, raw_ostream &OS,
- bool IsLittleEndian) {
- if (8 == Size)
- writeInteger((uint64_t)Integer, OS, IsLittleEndian);
- else if (4 == Size)
- writeInteger((uint32_t)Integer, OS, IsLittleEndian);
- else if (2 == Size)
- writeInteger((uint16_t)Integer, OS, IsLittleEndian);
- else if (1 == Size)
- writeInteger((uint8_t)Integer, OS, IsLittleEndian);
- else
- assert(false && "Invalid integer write size.");
-}
-
-void ZeroFillBytes(raw_ostream &OS, size_t Size) {
- std::vector<uint8_t> FillData;
- FillData.insert(FillData.begin(), Size, 0);
- OS.write(reinterpret_cast<char *>(FillData.data()), Size);
-}
-
-void yaml2debug_str(raw_ostream &OS, const DWARFYAML::Data &DI) {
- for (auto Str : DI.DebugStrings) {
- OS.write(Str.data(), Str.size());
- OS.write('\0');
- }
-}
-
-void yaml2debug_abbrev(raw_ostream &OS, const DWARFYAML::Data &DI) {
- for (auto AbbrevDecl : DI.AbbrevDecls) {
- encodeULEB128(AbbrevDecl.Code, OS);
- encodeULEB128(AbbrevDecl.Tag, OS);
- OS.write(AbbrevDecl.Children);
- for (auto Attr : AbbrevDecl.Attributes) {
- encodeULEB128(Attr.Attribute, OS);
- encodeULEB128(Attr.Form, OS);
- }
- encodeULEB128(0, OS);
- encodeULEB128(0, OS);
- }
-}
-
-void yaml2debug_aranges(raw_ostream &OS, const DWARFYAML::Data &DI) {
- for (auto Range : DI.ARanges) {
- auto HeaderStart = OS.tell();
- writeInteger((uint32_t)Range.Length, OS, DI.IsLittleEndian);
- writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian);
- writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian);
-
- auto HeaderSize = OS.tell() - HeaderStart;
- auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2);
- ZeroFillBytes(OS, FirstDescriptor - HeaderSize);
-
- for (auto Descriptor : Range.Descriptors) {
- writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS,
- DI.IsLittleEndian);
- writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS,
- DI.IsLittleEndian);
- }
- ZeroFillBytes(OS, Range.AddrSize * 2);
- }
-}
-
-void yaml2pubsection(raw_ostream &OS, const DWARFYAML::PubSection &Sect,
- bool IsLittleEndian) {
- writeInteger((uint32_t)Sect.Length, OS, IsLittleEndian);
- writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian);
- writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian);
- writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian);
- for (auto Entry : Sect.Entries) {
- writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian);
- if (Sect.IsGNUStyle)
- writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian);
- OS.write(Entry.Name.data(), Entry.Name.size());
- OS.write('\0');
- }
-}
-
-void yaml2debug_info(raw_ostream &OS, const DWARFYAML::Data &DI) {
-
- for (auto CU : DI.CompileUnits) {
- writeInteger((uint32_t)CU.Length, OS, DI.IsLittleEndian);
- writeInteger((uint16_t)CU.Version, OS, DI.IsLittleEndian);
- writeInteger((uint32_t)CU.AbbrOffset, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)CU.AddrSize, OS, DI.IsLittleEndian);
-
- auto FirstAbbrevCode = CU.Entries[0].AbbrCode;
-
- for (auto Entry : CU.Entries) {
- encodeULEB128(Entry.AbbrCode, OS);
- if (Entry.AbbrCode == 0u)
- continue;
- bool Indirect = false;
- assert(Entry.AbbrCode - FirstAbbrevCode < DI.AbbrevDecls.size() &&
- "Out of range AbbCode");
- auto &Abbrev = DI.AbbrevDecls[Entry.AbbrCode - FirstAbbrevCode];
-
- auto FormVal = Entry.Values.begin();
- auto AbbrForm = Abbrev.Attributes.begin();
- for (;
- FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end();
- ++FormVal, ++AbbrForm) {
- dwarf::Form Form = AbbrForm->Form;
- do {
- Indirect = false;
- switch (Form) {
- case dwarf::DW_FORM_addr:
- writeVariableSizedInteger(FormVal->Value, CU.AddrSize, OS,
- DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_ref_addr: {
- // TODO: Handle DWARF32/DWARF64 after Line Table data is done
- auto writeSize = CU.Version == 2 ? CU.AddrSize : 4;
- writeVariableSizedInteger(FormVal->Value, writeSize, OS,
- DI.IsLittleEndian);
- break;
- }
- case dwarf::DW_FORM_exprloc:
- case dwarf::DW_FORM_block:
- encodeULEB128(FormVal->BlockData.size(), OS);
- OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
- FormVal->BlockData.size());
- break;
- case dwarf::DW_FORM_block1: {
- auto writeSize = FormVal->BlockData.size();
- writeInteger((uint8_t)writeSize, OS, DI.IsLittleEndian);
- OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
- FormVal->BlockData.size());
- break;
- }
- case dwarf::DW_FORM_block2: {
- auto writeSize = FormVal->BlockData.size();
- writeInteger((uint16_t)writeSize, OS, DI.IsLittleEndian);
- OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
- FormVal->BlockData.size());
- break;
- }
- case dwarf::DW_FORM_block4: {
- auto writeSize = FormVal->BlockData.size();
- writeInteger((uint32_t)writeSize, OS, DI.IsLittleEndian);
- OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
- FormVal->BlockData.size());
- break;
- }
- case dwarf::DW_FORM_data1:
- case dwarf::DW_FORM_ref1:
- case dwarf::DW_FORM_flag:
- writeInteger((uint8_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_data2:
- case dwarf::DW_FORM_ref2:
- writeInteger((uint16_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_data4:
- case dwarf::DW_FORM_ref4:
- writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_data8:
- case dwarf::DW_FORM_ref8:
- writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_sdata:
- encodeSLEB128(FormVal->Value, OS);
- break;
- case dwarf::DW_FORM_udata:
- case dwarf::DW_FORM_ref_udata:
- encodeULEB128(FormVal->Value, OS);
- break;
- case dwarf::DW_FORM_string:
- OS.write(FormVal->CStr.data(), FormVal->CStr.size());
- OS.write('\0');
- break;
- case dwarf::DW_FORM_indirect:
- encodeULEB128(FormVal->Value, OS);
- Indirect = true;
- Form = static_cast<dwarf::Form>((uint64_t)FormVal->Value);
- ++FormVal;
- break;
- case dwarf::DW_FORM_strp:
- case dwarf::DW_FORM_sec_offset:
- case dwarf::DW_FORM_GNU_ref_alt:
- case dwarf::DW_FORM_GNU_strp_alt:
- case dwarf::DW_FORM_line_strp:
- case dwarf::DW_FORM_strp_sup:
- case dwarf::DW_FORM_ref_sup:
- // TODO: Handle DWARF32/64
- writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_ref_sig8:
- writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_GNU_addr_index:
- case dwarf::DW_FORM_GNU_str_index:
- encodeULEB128(FormVal->Value, OS);
- break;
- default:
- break;
- }
- } while (Indirect);
- }
- }
- }
-}
-
-void yaml2FileEntry(raw_ostream &OS, const DWARFYAML::File &File) {
- OS.write(File.Name.data(), File.Name.size());
- OS.write('\0');
- encodeULEB128(File.DirIdx, OS);
- encodeULEB128(File.ModTime, OS);
- encodeULEB128(File.Length, OS);
-}
-
-void yaml2debug_line(raw_ostream &OS, const DWARFYAML::Data &DI) {
- for (const auto LineTable : DI.DebugLines) {
- writeInteger((uint32_t)LineTable.TotalLength, OS, DI.IsLittleEndian);
- uint64_t SizeOfPrologueLength = 4;
- if (LineTable.TotalLength == UINT32_MAX) {
- writeInteger((uint64_t)LineTable.TotalLength64, OS, DI.IsLittleEndian);
- SizeOfPrologueLength = 8;
- }
- writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian);
- writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength,
- OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian);
- if (LineTable.Version >= 4)
- writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian);
-
- for (auto OpcodeLength : LineTable.StandardOpcodeLengths)
- writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian);
-
- for (auto IncludeDir : LineTable.IncludeDirs) {
- OS.write(IncludeDir.data(), IncludeDir.size());
- OS.write('\0');
- }
- OS.write('\0');
-
- for (auto File : LineTable.Files)
- yaml2FileEntry(OS, File);
- OS.write('\0');
-
- for (auto Op : LineTable.Opcodes) {
- writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian);
- if (Op.Opcode == 0) {
- encodeULEB128(Op.ExtLen, OS);
- writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian);
- switch (Op.SubOpcode) {
- case dwarf::DW_LNE_set_address:
- case dwarf::DW_LNE_set_discriminator:
- writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS,
- DI.IsLittleEndian);
- break;
- case dwarf::DW_LNE_define_file:
- yaml2FileEntry(OS, Op.FileEntry);
- break;
- case dwarf::DW_LNE_end_sequence:
- break;
- default:
- for (auto OpByte : Op.UnknownOpcodeData)
- writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian);
- }
- } else if (Op.Opcode < LineTable.OpcodeBase) {
- switch (Op.Opcode) {
- case dwarf::DW_LNS_copy:
- case dwarf::DW_LNS_negate_stmt:
- case dwarf::DW_LNS_set_basic_block:
- case dwarf::DW_LNS_const_add_pc:
- case dwarf::DW_LNS_set_prologue_end:
- case dwarf::DW_LNS_set_epilogue_begin:
- break;
-
- case dwarf::DW_LNS_advance_pc:
- case dwarf::DW_LNS_set_file:
- case dwarf::DW_LNS_set_column:
- case dwarf::DW_LNS_set_isa:
- encodeULEB128(Op.Data, OS);
- break;
-
- case dwarf::DW_LNS_advance_line:
- encodeSLEB128(Op.SData, OS);
- break;
-
- case dwarf::DW_LNS_fixed_advance_pc:
- writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian);
- break;
-
- default:
- for (auto OpData : Op.StandardOpcodeData) {
- encodeULEB128(OpData, OS);
- }
- }
- }
- }
- }
-}
diff --git a/tools/yaml2obj/yaml2macho.cpp b/tools/yaml2obj/yaml2macho.cpp
index cbc4d7ff50d5e..92b736e5298e3 100644
--- a/tools/yaml2obj/yaml2macho.cpp
+++ b/tools/yaml2obj/yaml2macho.cpp
@@ -14,6 +14,7 @@
#include "yaml2obj.h"
#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/ObjectYAML/DWARFEmitter.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MachO.h"
@@ -179,6 +180,21 @@ size_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC,
return writePayloadString(LC, OS);
}
+template <>
+size_t writeLoadCommandData<MachO::build_version_command>(
+ MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
+ size_t BytesWritten = 0;
+ for (const auto &T : LC.Tools) {
+ struct MachO::build_tool_version tool = T;
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(tool);
+ OS.write(reinterpret_cast<const char *>(&tool),
+ sizeof(MachO::build_tool_version));
+ BytesWritten += sizeof(MachO::build_tool_version);
+ }
+ return BytesWritten;
+}
+
void ZeroFillBytes(raw_ostream &OS, size_t Size) {
std::vector<uint8_t> FillData;
FillData.insert(FillData.begin(), Size, 0);
@@ -269,19 +285,21 @@ Error MachOWriter::writeSectionData(raw_ostream &OS) {
"Wrote too much data somewhere, section offsets don't line up.");
if (0 == strncmp(&Sec.segname[0], "__DWARF", 16)) {
if (0 == strncmp(&Sec.sectname[0], "__debug_str", 16)) {
- yaml2debug_str(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugStr(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_abbrev", 16)) {
- yaml2debug_abbrev(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugAbbrev(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_aranges", 16)) {
- yaml2debug_aranges(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugAranges(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_pubnames", 16)) {
- yaml2pubsection(OS, Obj.DWARF.PubNames, Obj.IsLittleEndian);
+ DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubNames,
+ Obj.IsLittleEndian);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_pubtypes", 16)) {
- yaml2pubsection(OS, Obj.DWARF.PubTypes, Obj.IsLittleEndian);
+ DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubTypes,
+ Obj.IsLittleEndian);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_info", 16)) {
- yaml2debug_info(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugInfo(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_line", 16)) {
- yaml2debug_line(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugLine(OS, Obj.DWARF);
}
} else {
// Fills section data with 0xDEADBEEF
diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp
index f746d84a38985..e64e3dc1d1798 100644
--- a/tools/yaml2obj/yaml2obj.cpp
+++ b/tools/yaml2obj/yaml2obj.cpp
@@ -40,31 +40,33 @@ DocNum("docnum", cl::init(1),
static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
cl::value_desc("filename"));
+LLVM_ATTRIBUTE_NORETURN static void error(Twine Message) {
+ errs() << Message << "\n";
+ exit(1);
+}
+
static int convertYAML(yaml::Input &YIn, raw_ostream &Out) {
unsigned CurDocNum = 0;
do {
if (++CurDocNum == DocNum) {
yaml::YamlObjectFile Doc;
YIn >> Doc;
- if (YIn.error()) {
- errs() << "yaml2obj: Failed to parse YAML file!\n";
- return 1;
- }
-
+ if (YIn.error())
+ error("yaml2obj: Failed to parse YAML file!");
if (Doc.Elf)
return yaml2elf(*Doc.Elf, Out);
if (Doc.Coff)
return yaml2coff(*Doc.Coff, Out);
if (Doc.MachO || Doc.FatMachO)
return yaml2macho(Doc, Out);
- errs() << "yaml2obj: Unknown document type!\n";
- return 1;
+ if (Doc.Wasm)
+ return yaml2wasm(*Doc.Wasm, Out);
+ error("yaml2obj: Unknown document type!");
}
} while (YIn.nextDocument());
- errs() << "yaml2obj: Cannot find the " << DocNum
- << llvm::getOrdinalSuffix(DocNum) << " document\n";
- return 1;
+ error("yaml2obj: Cannot find the " + utostr(DocNum) +
+ llvm::getOrdinalSuffix(DocNum) + " document");
}
int main(int argc, char **argv) {
@@ -79,10 +81,8 @@ int main(int argc, char **argv) {
std::error_code EC;
std::unique_ptr<tool_output_file> Out(
new tool_output_file(OutputFilename, EC, sys::fs::F_None));
- if (EC) {
- errs() << EC.message() << '\n';
- return 1;
- }
+ if (EC)
+ error("yaml2obj: Error opening '" + OutputFilename + "': " + EC.message());
ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
MemoryBuffer::getFileOrSTDIN(Input);
diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h
index 4a637366e1a16..cb8f11904916c 100644
--- a/tools/yaml2obj/yaml2obj.h
+++ b/tools/yaml2obj/yaml2obj.h
@@ -23,9 +23,8 @@ namespace ELFYAML {
struct Object;
}
-namespace DWARFYAML {
-struct Data;
-struct PubSection;
+namespace WasmYAML {
+struct Object;
}
namespace yaml {
@@ -37,15 +36,6 @@ struct YamlObjectFile;
int yaml2coff(llvm::COFFYAML::Object &Doc, llvm::raw_ostream &Out);
int yaml2elf(llvm::ELFYAML::Object &Doc, llvm::raw_ostream &Out);
int yaml2macho(llvm::yaml::YamlObjectFile &Doc, llvm::raw_ostream &Out);
-
-void yaml2debug_abbrev(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
-void yaml2debug_str(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
-
-void yaml2debug_aranges(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
-void yaml2pubsection(llvm::raw_ostream &OS,
- const llvm::DWARFYAML::PubSection &Sect,
- bool IsLittleEndian);
-void yaml2debug_info(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
-void yaml2debug_line(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
+int yaml2wasm(llvm::WasmYAML::Object &Doc, llvm::raw_ostream &Out);
#endif
diff --git a/tools/yaml2obj/yaml2wasm.cpp b/tools/yaml2obj/yaml2wasm.cpp
new file mode 100644
index 0000000000000..55267ce0392d9
--- /dev/null
+++ b/tools/yaml2obj/yaml2wasm.cpp
@@ -0,0 +1,377 @@
+//===- yaml2wasm - Convert YAML to a Wasm object file --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief The Wasm component of yaml2obj.
+///
+//===----------------------------------------------------------------------===//
+//
+#include "yaml2obj.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/LEB128.h"
+
+using namespace llvm;
+
+/// This parses a yaml stream that represents a Wasm object file.
+/// See docs/yaml2obj for the yaml scheema.
+class WasmWriter {
+public:
+ WasmWriter(WasmYAML::Object &Obj) : Obj(Obj) {}
+ int writeWasm(raw_ostream &OS);
+ int writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::TypeSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::ImportSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::FunctionSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::MemorySection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::GlobalSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::StartSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::CodeSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::DataSection &Section);
+
+private:
+ WasmYAML::Object &Obj;
+};
+
+static int writeUint64(raw_ostream &OS, uint64_t Value) {
+ char Data[sizeof(Value)];
+ support::endian::write64le(Data, Value);
+ OS.write(Data, sizeof(Data));
+ return 0;
+}
+
+static int writeUint32(raw_ostream &OS, uint32_t Value) {
+ char Data[sizeof(Value)];
+ support::endian::write32le(Data, Value);
+ OS.write(Data, sizeof(Data));
+ return 0;
+}
+
+static int writeUint8(raw_ostream &OS, uint8_t Value) {
+ char Data[sizeof(Value)];
+ memcpy(Data, &Value, sizeof(Data));
+ OS.write(Data, sizeof(Data));
+ return 0;
+}
+
+static int writeStringRef(StringRef &Str, raw_ostream &OS) {
+ encodeULEB128(Str.size(), OS);
+ OS << Str;
+ return 0;
+}
+
+static int writeLimits(WasmYAML::Limits Lim, raw_ostream &OS) {
+ encodeULEB128(Lim.Flags, OS);
+ encodeULEB128(Lim.Initial, OS);
+ if (Lim.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
+ encodeULEB128(Lim.Maximum, OS);
+ return 0;
+}
+
+static int writeInitExpr(wasm::WasmInitExpr InitExpr, raw_ostream &OS) {
+ writeUint8(OS, InitExpr.Opcode);
+ switch (InitExpr.Opcode) {
+ case wasm::WASM_OPCODE_I32_CONST:
+ encodeSLEB128(InitExpr.Value.Int32, OS);
+ break;
+ case wasm::WASM_OPCODE_I64_CONST:
+ encodeSLEB128(InitExpr.Value.Int64, OS);
+ break;
+ case wasm::WASM_OPCODE_F32_CONST:
+ writeUint32(OS, InitExpr.Value.Float32);
+ break;
+ case wasm::WASM_OPCODE_F64_CONST:
+ writeUint64(OS, InitExpr.Value.Float64);
+ break;
+ case wasm::WASM_OPCODE_GET_GLOBAL:
+ encodeULEB128(InitExpr.Value.Global, OS);
+ break;
+ default:
+ errs() << "Unknown opcode in init_expr: " << InitExpr.Opcode;
+ return 1;
+ }
+ writeUint8(OS, wasm::WASM_OPCODE_END);
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::CustomSection &Section) {
+ // writeStringRef(Section.Name, OS);
+ // encodeULEB128(Section.Payload.binary_size(), OS);
+ Section.Payload.writeAsBinary(OS);
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::TypeSection &Section) {
+ encodeULEB128(Section.Signatures.size(), OS);
+ for (auto &Sig : Section.Signatures) {
+ encodeSLEB128(Sig.Form, OS);
+ encodeULEB128(Sig.ParamTypes.size(), OS);
+ for (auto ParamType : Sig.ParamTypes)
+ encodeSLEB128(ParamType, OS);
+ if (Sig.ReturnType == wasm::WASM_TYPE_NORESULT) {
+ encodeSLEB128(0, OS);
+ } else {
+ encodeULEB128(1, OS);
+ encodeSLEB128(Sig.ReturnType, OS);
+ }
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::ImportSection &Section) {
+ encodeULEB128(Section.Imports.size(), OS);
+ for (auto &Import : Section.Imports) {
+ writeStringRef(Import.Module, OS);
+ writeStringRef(Import.Field, OS);
+ encodeULEB128(Import.Kind, OS);
+ switch (Import.Kind) {
+ case wasm::WASM_EXTERNAL_FUNCTION:
+ encodeULEB128(Import.SigIndex, OS);
+ break;
+ case wasm::WASM_EXTERNAL_GLOBAL:
+ encodeSLEB128(Import.GlobalType, OS);
+ writeUint8(OS, Import.GlobalMutable);
+ break;
+ default:
+ errs() << "Unknown import type: " << Import.Kind;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::FunctionSection &Section) {
+ encodeULEB128(Section.FunctionTypes.size(), OS);
+ for (uint32_t FuncType : Section.FunctionTypes) {
+ encodeULEB128(FuncType, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::ExportSection &Section) {
+ encodeULEB128(Section.Exports.size(), OS);
+ for (auto &Export : Section.Exports) {
+ writeStringRef(Export.Name, OS);
+ encodeULEB128(Export.Kind, OS);
+ encodeULEB128(Export.Index, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::StartSection &Section) {
+ encodeULEB128(Section.StartFunction, OS);
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::TableSection &Section) {
+ encodeULEB128(Section.Tables.size(), OS);
+ for (auto &Table : Section.Tables) {
+ encodeSLEB128(Table.ElemType, OS);
+ writeLimits(Table.TableLimits, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::MemorySection &Section) {
+ encodeULEB128(Section.Memories.size(), OS);
+ for (auto &Mem : Section.Memories) {
+ writeLimits(Mem, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::GlobalSection &Section) {
+ encodeULEB128(Section.Globals.size(), OS);
+ for (auto &Global : Section.Globals) {
+ encodeSLEB128(Global.Type, OS);
+ writeUint8(OS, Global.Mutable);
+ writeInitExpr(Global.InitExpr, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::ElemSection &Section) {
+ encodeULEB128(Section.Segments.size(), OS);
+ for (auto &Segment : Section.Segments) {
+ encodeULEB128(Segment.TableIndex, OS);
+ writeInitExpr(Segment.Offset, OS);
+
+ encodeULEB128(Segment.Functions.size(), OS);
+ for (auto &Function : Segment.Functions) {
+ encodeULEB128(Function, OS);
+ }
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::CodeSection &Section) {
+ encodeULEB128(Section.Functions.size(), OS);
+ for (auto &Func : Section.Functions) {
+ std::string OutString;
+ raw_string_ostream StringStream(OutString);
+
+ encodeULEB128(Func.Locals.size(), StringStream);
+ for (auto &LocalDecl : Func.Locals) {
+ encodeULEB128(LocalDecl.Count, StringStream);
+ encodeSLEB128(LocalDecl.Type, StringStream);
+ }
+
+ Func.Body.writeAsBinary(StringStream);
+
+ // Write the section size followed by the content
+ StringStream.flush();
+ encodeULEB128(OutString.size(), OS);
+ OS << OutString;
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::DataSection &Section) {
+ encodeULEB128(Section.Segments.size(), OS);
+ for (auto &Segment : Section.Segments) {
+ encodeULEB128(Segment.Index, OS);
+ writeInitExpr(Segment.Offset, OS);
+ encodeULEB128(Segment.Content.binary_size(), OS);
+ Segment.Content.writeAsBinary(OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeRelocSection(raw_ostream &OS,
+ WasmYAML::Section &Sec) {
+ StringRef Name;
+ switch (Sec.Type) {
+ case wasm::WASM_SEC_CODE:
+ Name = "reloc.CODE";
+ break;
+ case wasm::WASM_SEC_DATA:
+ Name = "reloc.DATA";
+ break;
+ default:
+ llvm_unreachable("not yet implemented");
+ return 1;
+ }
+
+ writeStringRef(Name, OS);
+ encodeULEB128(Sec.Type, OS);
+ encodeULEB128(Sec.Relocations.size(), OS);
+
+ for (auto Reloc: Sec.Relocations) {
+ encodeULEB128(Reloc.Type, OS);
+ encodeULEB128(Reloc.Offset, OS);
+ encodeULEB128(Reloc.Index, OS);
+ switch (Reloc.Type) {
+ case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
+ case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
+ case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
+ encodeULEB128(Reloc.Addend, OS);
+ }
+ }
+ return 0;
+}
+
+
+int WasmWriter::writeWasm(raw_ostream &OS) {
+ // Write headers
+ OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
+ writeUint32(OS, Obj.Header.Version);
+
+ // Write each section
+ for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) {
+ encodeULEB128(Sec->Type, OS);
+
+ std::string OutString;
+ raw_string_ostream StringStream(OutString);
+ if (auto S = dyn_cast<WasmYAML::CustomSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::TypeSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::ImportSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::FunctionSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::TableSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::MemorySection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::GlobalSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::ExportSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::StartSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::ElemSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::CodeSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::DataSection>(Sec.get())) {
+ if (auto Err = writeSectionContent(StringStream, *S))
+ return Err;
+ } else {
+ errs() << "Unknown section type: " << Sec->Type << "\n";
+ return 1;
+ }
+ StringStream.flush();
+
+ // Write the section size followed by the content
+ encodeULEB128(OutString.size(), OS);
+ OS << OutString;
+ }
+
+ // write reloc sections for any section that have relocations
+ for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) {
+ if (Sec->Relocations.empty())
+ continue;
+
+ encodeULEB128(wasm::WASM_SEC_CUSTOM, OS);
+ std::string OutString;
+ raw_string_ostream StringStream(OutString);
+ writeRelocSection(StringStream, *Sec);
+ StringStream.flush();
+
+ encodeULEB128(OutString.size(), OS);
+ OS << OutString;
+ }
+
+ return 0;
+}
+
+int yaml2wasm(llvm::WasmYAML::Object &Doc, raw_ostream &Out) {
+ WasmWriter Writer(Doc);
+
+ return Writer.writeWasm(Out);
+}