aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-06-26 20:32:52 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-06-26 20:32:52 +0000
commit08bbd35a80bf7765fe0d3043f9eb5a2f2786b649 (patch)
tree80108f0f128657f8623f8f66ad9735b4d88e7b47 /tools
parent7c7aba6e5fef47a01a136be655b0a92cfd7090f6 (diff)
downloadsrc-08bbd35a80bf7765fe0d3043f9eb5a2f2786b649.tar.gz
src-08bbd35a80bf7765fe0d3043f9eb5a2f2786b649.zip
Vendor import of llvm trunk r306325:vendor/llvm/llvm-trunk-r306325
Notes
Notes: svn path=/vendor/llvm/dist/; revision=320374 svn path=/vendor/llvm/llvm-trunk-r306325/; revision=320375; tag=vendor/llvm/llvm-trunk-r306325
Diffstat (limited to 'tools')
-rw-r--r--tools/bugpoint/CMakeLists.txt1
-rw-r--r--tools/bugpoint/LLVMBuild.txt1
-rw-r--r--tools/bugpoint/bugpoint.cpp8
-rw-r--r--tools/dsymutil/DwarfLinker.cpp14
-rw-r--r--tools/lli/OrcLazyJIT.cpp80
-rw-r--r--tools/lli/OrcLazyJIT.h135
-rw-r--r--tools/llvm-cvtres/llvm-cvtres.cpp70
-rw-r--r--tools/llvm-cvtres/llvm-cvtres.h17
-rw-r--r--tools/llvm-dwp/llvm-dwp.cpp4
-rw-r--r--tools/llvm-nm/llvm-nm.cpp597
-rw-r--r--tools/llvm-objdump/MachODump.cpp82
-rw-r--r--tools/llvm-pdbutil/Analyze.cpp28
-rw-r--r--tools/llvm-pdbutil/BytesOutputStyle.cpp501
-rw-r--r--tools/llvm-pdbutil/BytesOutputStyle.h67
-rw-r--r--tools/llvm-pdbutil/CMakeLists.txt4
-rw-r--r--tools/llvm-pdbutil/CompactTypeDumpVisitor.cpp59
-rw-r--r--tools/llvm-pdbutil/CompactTypeDumpVisitor.h49
-rw-r--r--tools/llvm-pdbutil/Diff.cpp273
-rw-r--r--tools/llvm-pdbutil/DumpOutputStyle.cpp (renamed from tools/llvm-pdbutil/RawOutputStyle.cpp)229
-rw-r--r--tools/llvm-pdbutil/DumpOutputStyle.h (renamed from tools/llvm-pdbutil/RawOutputStyle.h)14
-rw-r--r--tools/llvm-pdbutil/LinePrinter.cpp140
-rw-r--r--tools/llvm-pdbutil/LinePrinter.h15
-rw-r--r--tools/llvm-pdbutil/MinimalSymbolDumper.cpp16
-rw-r--r--tools/llvm-pdbutil/llvm-pdbutil.cpp332
-rw-r--r--tools/llvm-pdbutil/llvm-pdbutil.h42
-rw-r--r--tools/llvm-profdata/llvm-profdata.cpp8
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp140
-rw-r--r--tools/llvm-readobj/ObjDumper.h1
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp7
-rw-r--r--tools/llvm-stress/llvm-stress.cpp87
-rw-r--r--tools/obj2yaml/obj2yaml.cpp25
-rw-r--r--tools/obj2yaml/wasm2yaml.cpp73
-rw-r--r--tools/yaml2obj/yaml2wasm.cpp39
33 files changed, 2256 insertions, 902 deletions
diff --git a/tools/bugpoint/CMakeLists.txt b/tools/bugpoint/CMakeLists.txt
index 7598657427e8..8975e6763434 100644
--- a/tools/bugpoint/CMakeLists.txt
+++ b/tools/bugpoint/CMakeLists.txt
@@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
Analysis
BitWriter
CodeGen
diff --git a/tools/bugpoint/LLVMBuild.txt b/tools/bugpoint/LLVMBuild.txt
index 37a605870548..68ecb8c8f4f9 100644
--- a/tools/bugpoint/LLVMBuild.txt
+++ b/tools/bugpoint/LLVMBuild.txt
@@ -30,3 +30,4 @@ required_libraries =
Linker
ObjCARC
Scalar
+ all-targets
diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp
index 85c1ddd8277d..4ddea8dbec19 100644
--- a/tools/bugpoint/bugpoint.cpp
+++ b/tools/bugpoint/bugpoint.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Valgrind.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
@@ -138,6 +139,13 @@ int main(int argc, char **argv) {
polly::initializePollyPasses(Registry);
#endif
+ if (std::getenv("bar") == (char*) -1) {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+ }
+
cl::ParseCommandLineOptions(argc, argv,
"LLVM automatic testcase reducer. See\nhttp://"
"llvm.org/cmds/bugpoint.html"
diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp
index 88de2706544e..ba5c63846b50 100644
--- a/tools/dsymutil/DwarfLinker.cpp
+++ b/tools/dsymutil/DwarfLinker.cpp
@@ -2063,10 +2063,12 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
DataExtractor Data = Unit.getDebugInfoExtractor();
for (unsigned i = 0; i < Idx; ++i)
- DWARFFormValue::skipValue(Abbrev->getFormByIndex(i), Data, &Offset, &Unit);
+ DWARFFormValue::skipValue(Abbrev->getFormByIndex(i), Data, &Offset,
+ Unit.getFormParams());
uint32_t End = Offset;
- DWARFFormValue::skipValue(Abbrev->getFormByIndex(Idx), Data, &End, &Unit);
+ DWARFFormValue::skipValue(Abbrev->getFormByIndex(Idx), Data, &End,
+ Unit.getFormParams());
return std::make_pair(Offset, End);
}
@@ -2219,7 +2221,8 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr,
DWARFFormValue Val(AttrSpec.Form);
if (!Val.isFormClass(DWARFFormValue::FC_Reference)) {
- DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, &Unit);
+ DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
+ Unit.getFormParams());
continue;
}
@@ -2779,7 +2782,8 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
for (const auto &AttrSpec : Abbrev->attributes()) {
if (shouldSkipAttribute(AttrSpec, Die->getTag(), Info.InDebugMap,
Flags & TF_SkipPC, Flags & TF_InFunctionScope)) {
- DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, &U);
+ DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
+ U.getFormParams());
// FIXME: dsymutil-classic keeps the old abbreviation around
// even if it's not used. We can remove this (and the copyAbbrev
// helper) as soon as bit-for-bit compatibility is not a goal anymore.
@@ -3077,7 +3081,7 @@ void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
// prologue over and that works because we act as both producer and
// consumer. It would be nicer to have a real configurable line
// table emitter.
- if (LineTable.Prologue.Version != 2 ||
+ if (LineTable.Prologue.getVersion() != 2 ||
LineTable.Prologue.DefaultIsStmt != DWARF2_LINE_DEFAULT_IS_STMT ||
LineTable.Prologue.OpcodeBase > 13)
reportWarning("line table parameters mismatch. Cannot emit.");
diff --git a/tools/lli/OrcLazyJIT.cpp b/tools/lli/OrcLazyJIT.cpp
index ec61ce5e1545..2e15894152f9 100644
--- a/tools/lli/OrcLazyJIT.cpp
+++ b/tools/lli/OrcLazyJIT.cpp
@@ -1,4 +1,4 @@
-//===------ OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution -------===//
+//===- OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution ------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,51 +8,56 @@
//===----------------------------------------------------------------------===//
#include "OrcLazyJIT.h"
-#include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
-#include "llvm/Support/Debug.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include <cstdint>
#include <cstdio>
+#include <cstdlib>
#include <system_error>
using namespace llvm;
namespace {
- enum class DumpKind { NoDump, DumpFuncsToStdOut, DumpModsToStdOut,
- DumpModsToDisk };
-
- cl::opt<DumpKind> OrcDumpKind("orc-lazy-debug",
- cl::desc("Debug dumping for the orc-lazy JIT."),
- cl::init(DumpKind::NoDump),
- cl::values(
- clEnumValN(DumpKind::NoDump, "no-dump",
- "Don't dump anything."),
- clEnumValN(DumpKind::DumpFuncsToStdOut,
- "funcs-to-stdout",
- "Dump function names to stdout."),
- clEnumValN(DumpKind::DumpModsToStdOut,
- "mods-to-stdout",
- "Dump modules to stdout."),
- clEnumValN(DumpKind::DumpModsToDisk,
- "mods-to-disk",
- "Dump modules to the current "
- "working directory. (WARNING: "
- "will overwrite existing files).")),
- cl::Hidden);
-
- cl::opt<bool> OrcInlineStubs("orc-lazy-inline-stubs",
- cl::desc("Try to inline stubs"),
- cl::init(true), cl::Hidden);
-}
+enum class DumpKind {
+ NoDump,
+ DumpFuncsToStdOut,
+ DumpModsToStdOut,
+ DumpModsToDisk
+};
+
+} // end anonymous namespace
+
+static cl::opt<DumpKind> OrcDumpKind(
+ "orc-lazy-debug", cl::desc("Debug dumping for the orc-lazy JIT."),
+ cl::init(DumpKind::NoDump),
+ cl::values(clEnumValN(DumpKind::NoDump, "no-dump", "Don't dump anything."),
+ clEnumValN(DumpKind::DumpFuncsToStdOut, "funcs-to-stdout",
+ "Dump function names to stdout."),
+ clEnumValN(DumpKind::DumpModsToStdOut, "mods-to-stdout",
+ "Dump modules to stdout."),
+ clEnumValN(DumpKind::DumpModsToDisk, "mods-to-disk",
+ "Dump modules to the current "
+ "working directory. (WARNING: "
+ "will overwrite existing files).")),
+ cl::Hidden);
+
+static cl::opt<bool> OrcInlineStubs("orc-lazy-inline-stubs",
+ cl::desc("Try to inline stubs"),
+ cl::init(true), cl::Hidden);
OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
-
switch (OrcDumpKind) {
case DumpKind::NoDump:
- return [](std::unique_ptr<Module> M) { return M; };
+ return [](std::shared_ptr<Module> M) { return M; };
case DumpKind::DumpFuncsToStdOut:
- return [](std::unique_ptr<Module> M) {
+ return [](std::shared_ptr<Module> M) {
printf("[ ");
for (const auto &F : *M) {
@@ -71,7 +76,7 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
};
case DumpKind::DumpModsToStdOut:
- return [](std::unique_ptr<Module> M) {
+ return [](std::shared_ptr<Module> M) {
outs() << "----- Module Start -----\n" << *M
<< "----- Module End -----\n";
@@ -79,7 +84,7 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
};
case DumpKind::DumpModsToDisk:
- return [](std::unique_ptr<Module> M) {
+ return [](std::shared_ptr<Module> M) {
std::error_code EC;
raw_fd_ostream Out(M->getModuleIdentifier() + ".ll", EC,
sys::fs::F_Text);
@@ -98,7 +103,6 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
// Defined in lli.cpp.
CodeGenOpt::Level getOptLevel();
-
template <typename PtrTy>
static PtrTy fromTargetAddress(JITTargetAddress Addr) {
return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr));
@@ -143,7 +147,8 @@ int llvm::runOrcLazyJIT(std::vector<std::unique_ptr<Module>> Ms,
OrcInlineStubs);
// Add the module, look up main and run it.
- J.addModuleSet(std::move(Ms));
+ for (auto &M : Ms)
+ J.addModule(std::shared_ptr<Module>(std::move(M)));
auto MainSym = J.findSymbol("main");
if (!MainSym) {
@@ -151,11 +156,10 @@ int llvm::runOrcLazyJIT(std::vector<std::unique_ptr<Module>> Ms,
return 1;
}
- typedef int (*MainFnPtr)(int, const char*[]);
+ using MainFnPtr = int (*)(int, const char*[]);
std::vector<const char *> ArgV;
for (auto &Arg : Args)
ArgV.push_back(Arg.c_str());
auto Main = fromTargetAddress<MainFnPtr>(MainSym.getAddress());
return Main(ArgV.size(), (const char**)ArgV.data());
}
-
diff --git a/tools/lli/OrcLazyJIT.h b/tools/lli/OrcLazyJIT.h
index 56e7d36d05fb..fc02a10b514e 100644
--- a/tools/lli/OrcLazyJIT.h
+++ b/tools/lli/OrcLazyJIT.h
@@ -1,4 +1,4 @@
-//===--- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution --*- C++ -*-===//
+//===- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,38 +15,53 @@
#ifndef LLVM_TOOLS_LLI_ORCLAZYJIT_H
#define LLVM_TOOLS_LLI_ORCLAZYJIT_H
-#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
+#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
namespace llvm {
class OrcLazyJIT {
public:
- typedef orc::JITCompileCallbackManager CompileCallbackMgr;
- typedef orc::RTDyldObjectLinkingLayer<> ObjLayerT;
- typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT;
- typedef std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>
- TransformFtor;
- typedef orc::IRTransformLayer<CompileLayerT, TransformFtor> IRDumpLayerT;
- typedef orc::CompileOnDemandLayer<IRDumpLayerT, CompileCallbackMgr> CODLayerT;
- typedef CODLayerT::IndirectStubsManagerBuilderT
- IndirectStubsManagerBuilder;
- typedef CODLayerT::ModuleSetHandleT ModuleSetHandleT;
+ using CompileCallbackMgr = orc::JITCompileCallbackManager;
+ using ObjLayerT = orc::RTDyldObjectLinkingLayer;
+ using CompileLayerT = orc::IRCompileLayer<ObjLayerT, orc::SimpleCompiler>;
+ using TransformFtor =
+ std::function<std::shared_ptr<Module>(std::shared_ptr<Module>)>;
+ using IRDumpLayerT = orc::IRTransformLayer<CompileLayerT, TransformFtor>;
+ using CODLayerT = orc::CompileOnDemandLayer<IRDumpLayerT, CompileCallbackMgr>;
+ using IndirectStubsManagerBuilder = CODLayerT::IndirectStubsManagerBuilderT;
+ using ModuleHandleT = CODLayerT::ModuleHandleT;
OrcLazyJIT(std::unique_ptr<TargetMachine> TM,
std::unique_ptr<CompileCallbackMgr> CCMgr,
IndirectStubsManagerBuilder IndirectStubsMgrBuilder,
bool InlineStubs)
: TM(std::move(TM)), DL(this->TM->createDataLayout()),
- CCMgr(std::move(CCMgr)),
- ObjectLayer(),
+ CCMgr(std::move(CCMgr)),
CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)),
IRDumpLayer(CompileLayer, createDebugDumper()),
CODLayer(IRDumpLayer, extractSingleFunction, *this->CCMgr,
@@ -62,11 +77,9 @@ public:
DtorRunner.runViaLayer(CODLayer);
}
- ModuleSetHandleT addModuleSet(std::vector<std::unique_ptr<Module>> Ms) {
- // Attach a data-layouts if they aren't already present.
- for (auto &M : Ms)
- if (M->getDataLayout().isDefault())
- M->setDataLayout(DL);
+ void addModule(std::shared_ptr<Module> M) {
+ if (M->getDataLayout().isDefault())
+ M->setDataLayout(DL);
// Rename, bump linkage and record static constructors and destructors.
// We have to do this before we hand over ownership of the module to the
@@ -74,21 +87,19 @@ public:
std::vector<std::string> CtorNames, DtorNames;
{
unsigned CtorId = 0, DtorId = 0;
- for (auto &M : Ms) {
- for (auto Ctor : orc::getConstructors(*M)) {
- std::string NewCtorName = ("$static_ctor." + Twine(CtorId++)).str();
- Ctor.Func->setName(NewCtorName);
- Ctor.Func->setLinkage(GlobalValue::ExternalLinkage);
- Ctor.Func->setVisibility(GlobalValue::HiddenVisibility);
- CtorNames.push_back(mangle(NewCtorName));
- }
- for (auto Dtor : orc::getDestructors(*M)) {
- std::string NewDtorName = ("$static_dtor." + Twine(DtorId++)).str();
- Dtor.Func->setLinkage(GlobalValue::ExternalLinkage);
- Dtor.Func->setVisibility(GlobalValue::HiddenVisibility);
- DtorNames.push_back(mangle(Dtor.Func->getName()));
- Dtor.Func->setName(NewDtorName);
- }
+ for (auto Ctor : orc::getConstructors(*M)) {
+ std::string NewCtorName = ("$static_ctor." + Twine(CtorId++)).str();
+ Ctor.Func->setName(NewCtorName);
+ Ctor.Func->setLinkage(GlobalValue::ExternalLinkage);
+ Ctor.Func->setVisibility(GlobalValue::HiddenVisibility);
+ CtorNames.push_back(mangle(NewCtorName));
+ }
+ for (auto Dtor : orc::getDestructors(*M)) {
+ std::string NewDtorName = ("$static_dtor." + Twine(DtorId++)).str();
+ Dtor.Func->setLinkage(GlobalValue::ExternalLinkage);
+ Dtor.Func->setVisibility(GlobalValue::HiddenVisibility);
+ DtorNames.push_back(mangle(Dtor.Func->getName()));
+ Dtor.Func->setName(NewDtorName);
}
}
@@ -96,46 +107,49 @@ public:
// 1) Search the JIT symbols.
// 2) Check for C++ runtime overrides.
// 3) Search the host process (LLI)'s symbol table.
- auto Resolver =
- orc::createLambdaResolver(
- [this](const std::string &Name) -> JITSymbol {
- if (auto Sym = CODLayer.findSymbol(Name, true))
- return Sym;
- return CXXRuntimeOverrides.searchOverrides(Name);
- },
- [](const std::string &Name) {
- if (auto Addr =
- RTDyldMemoryManager::getSymbolAddressInProcess(Name))
- return JITSymbol(Addr, JITSymbolFlags::Exported);
- return JITSymbol(nullptr);
- }
- );
-
- // Add the module to the JIT.
- auto H = CODLayer.addModuleSet(std::move(Ms),
- llvm::make_unique<SectionMemoryManager>(),
- std::move(Resolver));
+ if (ModulesHandle == CODLayerT::ModuleHandleT()) {
+ auto Resolver =
+ orc::createLambdaResolver(
+ [this](const std::string &Name) -> JITSymbol {
+ if (auto Sym = CODLayer.findSymbol(Name, true))
+ return Sym;
+ return CXXRuntimeOverrides.searchOverrides(Name);
+ },
+ [](const std::string &Name) {
+ if (auto Addr =
+ RTDyldMemoryManager::getSymbolAddressInProcess(Name))
+ return JITSymbol(Addr, JITSymbolFlags::Exported);
+ return JITSymbol(nullptr);
+ }
+ );
+
+ // Add the module to the JIT.
+ ModulesHandle =
+ CODLayer.addModule(std::move(M),
+ llvm::make_unique<SectionMemoryManager>(),
+ std::move(Resolver));
+ } else
+ CODLayer.addExtraModule(ModulesHandle, std::move(M));
// Run the static constructors, and save the static destructor runner for
// execution when the JIT is torn down.
- orc::CtorDtorRunner<CODLayerT> CtorRunner(std::move(CtorNames), H);
+ orc::CtorDtorRunner<CODLayerT> CtorRunner(std::move(CtorNames),
+ ModulesHandle);
CtorRunner.runViaLayer(CODLayer);
- IRStaticDestructorRunners.emplace_back(std::move(DtorNames), H);
-
- return H;
+ IRStaticDestructorRunners.emplace_back(std::move(DtorNames),
+ ModulesHandle);
}
JITSymbol findSymbol(const std::string &Name) {
return CODLayer.findSymbol(mangle(Name), true);
}
- JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name) {
+ JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name) {
return CODLayer.findSymbolIn(H, mangle(Name), true);
}
private:
-
std::string mangle(const std::string &Name) {
std::string MangledName;
{
@@ -165,6 +179,7 @@ private:
orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides;
std::vector<orc::CtorDtorRunner<CODLayerT>> IRStaticDestructorRunners;
+ CODLayerT::ModuleHandleT ModulesHandle;
};
int runOrcLazyJIT(std::vector<std::unique_ptr<Module>> Ms,
@@ -172,4 +187,4 @@ int runOrcLazyJIT(std::vector<std::unique_ptr<Module>> Ms,
} // end namespace llvm
-#endif
+#endif // LLVM_TOOLS_LLI_ORCLAZYJIT_H
diff --git a/tools/llvm-cvtres/llvm-cvtres.cpp b/tools/llvm-cvtres/llvm-cvtres.cpp
index 1e463399a598..36c15925e84f 100644
--- a/tools/llvm-cvtres/llvm-cvtres.cpp
+++ b/tools/llvm-cvtres/llvm-cvtres.cpp
@@ -12,8 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm-cvtres.h"
-
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/WindowsResource.h"
@@ -29,6 +27,8 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
using namespace llvm;
using namespace object;
@@ -37,7 +37,7 @@ namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) \
+ HELPTEXT, METAVAR, VALUES) \
OPT_##ID,
#include "Opts.inc"
#undef OPTION
@@ -49,12 +49,12 @@ enum ID {
static const opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) \
+ HELPTEXT, METAVAR, VALUES) \
{ \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS},
+ PREFIX, NAME, HELPTEXT, \
+ METAVAR, OPT_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, \
+ OPT_##ALIAS, ALIASARGS, VALUES},
#include "Opts.inc"
#undef OPTION
};
@@ -89,6 +89,12 @@ void error(Error EC) {
[&](const ErrorInfoBase &EI) { reportError(EI.message()); });
}
+template <typename T> T error(Expected<T> EC) {
+ if (!EC)
+ error(EC.takeError());
+ return std::move(EC.get());
+}
+
int main(int argc_, const char *argv_[]) {
sys::PrintStackTraceOnErrorSignal(argv_[0]);
PrettyStackTraceProgram X(argc_, argv_);
@@ -114,21 +120,21 @@ int main(int argc_, const char *argv_[]) {
bool Verbose = InputArgs.hasArg(OPT_VERBOSE);
- Machine MachineType;
+ COFF::MachineTypes MachineType;
if (InputArgs.hasArg(OPT_MACHINE)) {
std::string MachineString = InputArgs.getLastArgValue(OPT_MACHINE).upper();
- MachineType = StringSwitch<Machine>(MachineString)
- .Case("ARM", Machine::ARM)
- .Case("X64", Machine::X64)
- .Case("X86", Machine::X86)
- .Default(Machine::UNKNOWN);
- if (MachineType == Machine::UNKNOWN)
+ MachineType = StringSwitch<COFF::MachineTypes>(MachineString)
+ .Case("ARM", COFF::IMAGE_FILE_MACHINE_ARMNT)
+ .Case("X64", COFF::IMAGE_FILE_MACHINE_AMD64)
+ .Case("X86", COFF::IMAGE_FILE_MACHINE_I386)
+ .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
+ if (MachineType == COFF::IMAGE_FILE_MACHINE_UNKNOWN)
reportError("Unsupported machine architecture");
} else {
if (Verbose)
outs() << "Machine architecture not specified; assumed X64.\n";
- MachineType = Machine::X64;
+ MachineType = COFF::IMAGE_FILE_MACHINE_AMD64;
}
std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
@@ -142,17 +148,17 @@ int main(int argc_, const char *argv_[]) {
if (InputArgs.hasArg(OPT_OUT)) {
OutputFile = InputArgs.getLastArgValue(OPT_OUT);
} else {
- OutputFile = llvm::sys::path::filename(StringRef(InputFiles[0]));
- llvm::sys::path::replace_extension(OutputFile, ".obj");
+ OutputFile = sys::path::filename(StringRef(InputFiles[0]));
+ sys::path::replace_extension(OutputFile, ".obj");
}
if (Verbose) {
outs() << "Machine: ";
switch (MachineType) {
- case Machine::ARM:
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
outs() << "ARM\n";
break;
- case Machine::X86:
+ case COFF::IMAGE_FILE_MACHINE_I386:
outs() << "X86\n";
break;
default:
@@ -163,8 +169,7 @@ int main(int argc_, const char *argv_[]) {
WindowsResourceParser Parser;
for (const auto &File : InputFiles) {
- Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
- object::createBinary(File);
+ Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
if (!BinaryOrErr)
reportError(File, errorToErrorCode(BinaryOrErr.takeError()));
@@ -176,10 +181,7 @@ int main(int argc_, const char *argv_[]) {
if (Verbose) {
int EntryNumber = 0;
- Expected<ResourceEntryRef> EntryOrErr = RF->getHeadEntry();
- if (!EntryOrErr)
- error(EntryOrErr.takeError());
- ResourceEntryRef Entry = EntryOrErr.get();
+ ResourceEntryRef Entry = error(RF->getHeadEntry());
bool End = false;
while (!End) {
error(Entry.moveNext(End));
@@ -193,15 +195,21 @@ int main(int argc_, const char *argv_[]) {
if (Verbose) {
Parser.printTree(outs());
- Parser.printTree(errs());
}
- error(
- llvm::object::writeWindowsResourceCOFF(OutputFile, MachineType, Parser));
+ std::unique_ptr<MemoryBuffer> OutputBuffer =
+ error(llvm::object::writeWindowsResourceCOFF(MachineType, Parser));
+ auto FileOrErr =
+ FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
+ if (!FileOrErr)
+ reportError(OutputFile, FileOrErr.getError());
+ std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
+ std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
+ FileBuffer->getBufferStart());
+ error(FileBuffer->commit());
if (Verbose) {
- Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
- object::createBinary(OutputFile);
+ Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(OutputFile);
if (!BinaryOrErr)
reportError(OutputFile, errorToErrorCode(BinaryOrErr.takeError()));
Binary &Binary = *BinaryOrErr.get().getBinary();
diff --git a/tools/llvm-cvtres/llvm-cvtres.h b/tools/llvm-cvtres/llvm-cvtres.h
deleted file mode 100644
index f7b14faeebe3..000000000000
--- a/tools/llvm-cvtres/llvm-cvtres.h
+++ /dev/null
@@ -1,17 +0,0 @@
-//===- llvm-cvtres.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_LLVMCVTRES_LLVMCVTRES_H
-#define LLVM_TOOLS_LLVMCVTRES_LLVMCVTRES_H
-
-#include <system_error>
-
-void error(std::error_code EC);
-
-#endif
diff --git a/tools/llvm-dwp/llvm-dwp.cpp b/tools/llvm-dwp/llvm-dwp.cpp
index f8d00b3b5534..7a6922d8a3fc 100644
--- a/tools/llvm-dwp/llvm-dwp.cpp
+++ b/tools/llvm-dwp/llvm-dwp.cpp
@@ -182,8 +182,8 @@ static Expected<CompileUnitIdentifiers> getCUIdentifiers(StringRef Abbrev,
ID.Signature = InfoData.getU64(&Offset);
break;
default:
- DWARFFormValue::skipValue(Form, InfoData, &Offset, Version, AddrSize,
- Format);
+ DWARFFormValue::skipValue(Form, InfoData, &Offset,
+ DWARFFormParams({Version, AddrSize, Format}));
}
}
return ID;
diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp
index 722cb9e7e449..513e1b87558f 100644
--- a/tools/llvm-nm/llvm-nm.cpp
+++ b/tools/llvm-nm/llvm-nm.cpp
@@ -48,6 +48,7 @@
#include <cstring>
#include <system_error>
#include <vector>
+#include <string.h>
using namespace llvm;
using namespace object;
@@ -167,6 +168,15 @@ cl::list<std::string> SegSect("s", cl::Positional, cl::ZeroOrMore,
cl::opt<bool> FormatMachOasHex("x", cl::desc("Print symbol entry in hex, "
"Mach-O only"), cl::Grouping);
+cl::opt<bool> AddDyldInfo("add-dyldinfo",
+ cl::desc("Add symbols from the dyldinfo not already "
+ "in the symbol table, Mach-O only"));
+cl::opt<bool> NoDyldInfo("no-dyldinfo",
+ cl::desc("Don't add any symbols from the dyldinfo, "
+ "Mach-O only"));
+cl::opt<bool> DyldInfoOnly("dyldinfo-only",
+ cl::desc("Show only symbols from the dyldinfo, "
+ "Mach-O only"));
cl::opt<bool> NoLLVMBitcode("no-llvm-bc",
cl::desc("Disable LLVM bitcode reader"));
@@ -247,6 +257,17 @@ struct NMSymbol {
char TypeChar;
StringRef Name;
BasicSymbolRef Sym;
+ // The Sym field above points to the native symbol in the object file,
+ // for Mach-O when we are creating symbols from the dyld info the above
+ // pointer is null as there is no native symbol. In these cases the fields
+ // below are filled in to represent what would have been a Mach-O nlist
+ // native symbol.
+ uint32_t SymFlags;
+ SectionRef Section;
+ uint8_t NType;
+ uint8_t NSect;
+ uint16_t NDesc;
+ StringRef IndirectName;
};
} // anonymous namespace
@@ -331,22 +352,38 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
H_64 = MachO->MachOObjectFile::getHeader64();
Filetype = H_64.filetype;
Flags = H_64.flags;
- MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
- NType = STE_64.n_type;
- NSect = STE_64.n_sect;
- NDesc = STE_64.n_desc;
- NStrx = STE_64.n_strx;
- NValue = STE_64.n_value;
+ if (SymDRI.p){
+ MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
+ NType = STE_64.n_type;
+ NSect = STE_64.n_sect;
+ NDesc = STE_64.n_desc;
+ NStrx = STE_64.n_strx;
+ NValue = STE_64.n_value;
+ } else {
+ NType = I->NType;
+ NSect = I->NSect;
+ NDesc = I->NDesc;
+ NStrx = 0;
+ NValue = I->Address;
+ }
} else {
H = MachO->MachOObjectFile::getHeader();
Filetype = H.filetype;
Flags = H.flags;
- MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
- NType = STE.n_type;
- NSect = STE.n_sect;
- NDesc = STE.n_desc;
- NStrx = STE.n_strx;
- NValue = STE.n_value;
+ if (SymDRI.p){
+ MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
+ NType = STE.n_type;
+ NSect = STE.n_sect;
+ NDesc = STE.n_desc;
+ NStrx = STE.n_strx;
+ NValue = STE.n_value;
+ } else {
+ NType = I->NType;
+ NSect = I->NSect;
+ NDesc = I->NDesc;
+ NStrx = 0;
+ NValue = I->Address;
+ }
}
}
@@ -363,7 +400,22 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
outs() << Str << ' ';
format("%08x", NStrx).print(Str, sizeof(Str));
outs() << Str << ' ';
- outs() << I->Name << "\n";
+ outs() << I->Name;
+ if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
+ outs() << " (indirect for ";
+ format(printFormat, NValue).print(Str, sizeof(Str));
+ outs() << Str << ' ';
+ StringRef IndirectName;
+ if (I->Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ outs() << "?)";
+ else
+ outs() << IndirectName << ")";
+ }
+ else
+ outs() << I->IndirectName << ")";
+ }
+ outs() << "\n";
return;
}
@@ -419,14 +471,19 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
outs() << "(?,?) ";
break;
}
- Expected<section_iterator> SecOrErr =
- MachO->getSymbolSection(I->Sym.getRawDataRefImpl());
- if (!SecOrErr) {
- consumeError(SecOrErr.takeError());
- outs() << "(?,?) ";
- break;
+ section_iterator Sec = SectionRef();
+ if (I->Sym.getRawDataRefImpl().p) {
+ Expected<section_iterator> SecOrErr =
+ MachO->getSymbolSection(I->Sym.getRawDataRefImpl());
+ if (!SecOrErr) {
+ consumeError(SecOrErr.takeError());
+ outs() << "(?,?) ";
+ break;
+ }
+ Sec = *SecOrErr;
+ } else {
+ Sec = I->Section;
}
- section_iterator Sec = *SecOrErr;
DataRefImpl Ref = Sec->getRawDataRefImpl();
StringRef SectionName;
MachO->getSectionName(Ref, SectionName);
@@ -485,11 +542,17 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
outs() << I->Name << " (for ";
StringRef IndirectName;
- if (!MachO ||
- MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ if (MachO) {
+ if (I->Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ outs() << "?)";
+ else
+ outs() << IndirectName << ")";
+ }
+ else
+ outs() << I->IndirectName << ")";
+ } else
outs() << "?)";
- else
- outs() << IndirectName << ")";
} else
outs() << I->Name;
@@ -660,7 +723,12 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
for (SymbolListT::iterator I = SymbolList.begin(), E = SymbolList.end();
I != E; ++I) {
- uint32_t SymFlags = I->Sym.getFlags();
+ uint32_t SymFlags;
+ if (I->Sym.getRawDataRefImpl().p)
+ SymFlags = I->Sym.getFlags();
+ else
+ SymFlags = I->SymFlags;
+
bool Undefined = SymFlags & SymbolRef::SF_Undefined;
bool Global = SymFlags & SymbolRef::SF_Global;
if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) ||
@@ -699,10 +767,13 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
}
}
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
// Otherwise, print the symbol address and size.
if (symbolIsDefined(*I)) {
if (Obj.isIR())
strcpy(SymbolAddrStr, printDashes);
+ else if(MachO && I->TypeChar == 'I')
+ strcpy(SymbolAddrStr, printBlanks);
else
format(printFormat, I->Address)
.print(SymbolAddrStr, sizeof(SymbolAddrStr));
@@ -714,7 +785,6 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
// nm(1) -m output or hex, else if OutputFormat is darwin or we are
// printing Mach-O symbols in hex and not a Mach-O object fall back to
// OutputFormat bsd (see below).
- MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) {
darwinPrintSymbol(Obj, I, SymbolAddrStr, printBlanks, printDashes,
printFormat);
@@ -734,7 +804,19 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
outs() << I->TypeChar;
if (I->TypeChar == '-' && MachO)
darwinPrintStab(MachO, I);
- outs() << " " << I->Name << "\n";
+ outs() << " " << I->Name;
+ if (I->TypeChar == 'I' && MachO) {
+ outs() << " (indirect for ";
+ if (I->Sym.getRawDataRefImpl().p) {
+ StringRef IndirectName;
+ if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ outs() << "?)";
+ else
+ outs() << IndirectName << ")";
+ } else
+ outs() << I->IndirectName << ")";
+ }
+ outs() << "\n";
} else if (OutputFormat == sysv) {
std::string PaddedName(I->Name);
while (PaddedName.length() < 20)
@@ -1022,51 +1104,439 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
if (Nsect == 0)
return;
}
- for (BasicSymbolRef Sym : Symbols) {
- uint32_t SymFlags = Sym.getFlags();
- if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific))
- continue;
- if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect))
- continue;
- // If a "-s segname sectname" option was specified and this is a Mach-O
- // file and this section appears in this file, Nsect will be non-zero then
- // see if this symbol is a symbol from that section and if not skip it.
- if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
- continue;
- NMSymbol S;
- S.Size = 0;
- S.Address = 0;
- if (PrintSize) {
- if (isa<ELFObjectFileBase>(&Obj))
- S.Size = ELFSymbolRef(Sym).getSize();
- }
- if (PrintAddress && isa<ObjectFile>(Obj)) {
- SymbolRef SymRef(Sym);
- Expected<uint64_t> AddressOrErr = SymRef.getAddress();
- if (!AddressOrErr) {
- consumeError(AddressOrErr.takeError());
- break;
+ if (!MachO || !DyldInfoOnly) {
+ for (BasicSymbolRef Sym : Symbols) {
+ uint32_t SymFlags = Sym.getFlags();
+ if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific))
+ continue;
+ if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect))
+ continue;
+ // If a "-s segname sectname" option was specified and this is a Mach-O
+ // file and this section appears in this file, Nsect will be non-zero then
+ // see if this symbol is a symbol from that section and if not skip it.
+ if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
+ continue;
+ NMSymbol S;
+ memset(&S, '\0', sizeof(S));
+ S.Size = 0;
+ S.Address = 0;
+ if (PrintSize) {
+ if (isa<ELFObjectFileBase>(&Obj))
+ S.Size = ELFSymbolRef(Sym).getSize();
+ }
+ if (PrintAddress && isa<ObjectFile>(Obj)) {
+ SymbolRef SymRef(Sym);
+ Expected<uint64_t> AddressOrErr = SymRef.getAddress();
+ if (!AddressOrErr) {
+ consumeError(AddressOrErr.takeError());
+ break;
+ }
+ S.Address = *AddressOrErr;
}
- S.Address = *AddressOrErr;
+ S.TypeChar = getNMTypeChar(Obj, Sym);
+ std::error_code EC = Sym.printName(OS);
+ if (EC && MachO)
+ OS << "bad string index";
+ else
+ error(EC);
+ OS << '\0';
+ S.Sym = Sym;
+ SymbolList.push_back(S);
}
- S.TypeChar = getNMTypeChar(Obj, Sym);
- std::error_code EC = Sym.printName(OS);
- if (EC && MachO)
- OS << "bad string index";
- else
- error(EC);
- OS << '\0';
- S.Sym = Sym;
- SymbolList.push_back(S);
}
OS.flush();
const char *P = NameBuffer.c_str();
- for (unsigned I = 0; I < SymbolList.size(); ++I) {
+ unsigned I;
+ for (I = 0; I < SymbolList.size(); ++I) {
SymbolList[I].Name = P;
P += strlen(P) + 1;
}
+ // If this is a Mach-O file where the nlist symbol table is out of sync
+ // with the dyld export trie then look through exports and fake up symbols
+ // for the ones that are missing (also done with the -add-dyldinfo flag).
+ // This is needed if strip(1) -T is run on a binary containing swift
+ // language symbols for example. The option -only-dyldinfo will fake up
+ // all symbols from the dyld export trie as well as the bind info.
+ std::string ExportsNameBuffer;
+ raw_string_ostream EOS(ExportsNameBuffer);
+ std::string BindsNameBuffer;
+ raw_string_ostream BOS(BindsNameBuffer);
+ std::string LazysNameBuffer;
+ raw_string_ostream LOS(LazysNameBuffer);
+ std::string WeaksNameBuffer;
+ raw_string_ostream WOS(WeaksNameBuffer);
+ if (MachO && !NoDyldInfo) {
+ MachO::mach_header H;
+ MachO::mach_header_64 H_64;
+ uint32_t HFlags = 0;
+ if (MachO->is64Bit()) {
+ H_64 = MachO->MachOObjectFile::getHeader64();
+ HFlags = H_64.flags;
+ } else {
+ H = MachO->MachOObjectFile::getHeader();
+ HFlags = H.flags;
+ }
+ uint64_t BaseSegmentAddress = 0;
+ for (const auto &Command : MachO->load_commands()) {
+ if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = MachO->getSegmentLoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ }
+ }
+ if (DyldInfoOnly || AddDyldInfo ||
+ HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
+ unsigned ExportsAdded = 0;
+ for (const llvm::object::ExportEntry &Entry : MachO->exports()) {
+ bool found = false;
+ bool ReExport = false;
+ if (!DyldInfoOnly) {
+ for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Address == Entry.address() + BaseSegmentAddress &&
+ SymbolList[J].Name == Entry.name())
+ found = true;
+ }
+ }
+ if (!found) {
+ NMSymbol S;
+ memset(&S, '\0', sizeof(NMSymbol));
+ S.Address = Entry.address() + BaseSegmentAddress;
+ S.Size = 0;
+ S.TypeChar = '\0';
+ S.Name = Entry.name();
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ S.Sym = BasicSymbolRef();
+ S.SymFlags = SymbolRef::SF_Global;
+ S.Section = SectionRef();
+ S.NType = 0;
+ S.NSect = 0;
+ S.NDesc = 0;
+ S.IndirectName = StringRef();
+
+ uint64_t EFlags = Entry.flags();
+ bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
+ MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
+ bool Resolver = (EFlags &
+ MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+ ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
+ bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+ if (WeakDef)
+ S.NDesc |= MachO::N_WEAK_DEF;
+ if (Abs) {
+ S.NType = MachO::N_EXT | MachO::N_ABS;
+ S.TypeChar = 'A';
+ } else if (ReExport) {
+ S.NType = MachO::N_EXT | MachO::N_INDR;
+ S.TypeChar = 'I';
+ } else {
+ S.NType = MachO::N_EXT | MachO::N_SECT;
+ if (Resolver) {
+ S.Address = Entry.other() + BaseSegmentAddress;
+ if ((S.Address & 1) != 0 &&
+ !MachO->is64Bit() && H.cputype == MachO::CPU_TYPE_ARM){
+ S.Address &= ~1LL;
+ S.NDesc |= MachO::N_ARM_THUMB_DEF;
+ }
+ } else {
+ S.Address = Entry.address() + BaseSegmentAddress;
+ }
+ StringRef SegmentName = StringRef();
+ StringRef SectionName = StringRef();
+ for (const SectionRef &Section : MachO->sections()) {
+ S.NSect++;
+ Section.getName(SectionName);
+ SegmentName = MachO->getSectionFinalSegmentName(
+ Section.getRawDataRefImpl());
+ if (S.Address >= Section.getAddress() &&
+ S.Address < Section.getAddress() + Section.getSize()) {
+ S.Section = Section;
+ break;
+ } else if (Entry.name() == "__mh_execute_header" &&
+ SegmentName == "__TEXT" && SectionName == "__text") {
+ S.Section = Section;
+ S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
+ break;
+ }
+ }
+ if (SegmentName == "__TEXT" && SectionName == "__text")
+ S.TypeChar = 'T';
+ else if (SegmentName == "__DATA" && SectionName == "__data")
+ S.TypeChar = 'D';
+ else if (SegmentName == "__DATA" && SectionName == "__bss")
+ S.TypeChar = 'B';
+ else
+ S.TypeChar = 'S';
+ }
+ SymbolList.push_back(S);
+
+ EOS << Entry.name();
+ EOS << '\0';
+ ExportsAdded++;
+
+ // For ReExports there are a two more things to do, first add the
+ // indirect name and second create the undefined symbol using the
+ // referened dynamic library.
+ if (ReExport) {
+
+ // Add the indirect name.
+ if (Entry.otherName().empty())
+ EOS << Entry.name();
+ else
+ EOS << Entry.otherName();
+ EOS << '\0';
+
+ // Now create the undefined symbol using the referened dynamic
+ // library.
+ NMSymbol U;
+ memset(&U, '\0', sizeof(NMSymbol));
+ U.Address = 0;
+ U.Size = 0;
+ U.TypeChar = 'U';
+ if (Entry.otherName().empty())
+ U.Name = Entry.name();
+ else
+ U.Name = Entry.otherName();
+ // Again there is no symbol in the nlist symbol table for this so
+ // we set Sym effectivly to null and the rest of code in here must
+ // test for it and not do things like Sym.getFlags() for it.
+ U.Sym = BasicSymbolRef();
+ U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ U.Section = SectionRef();
+ U.NType = MachO::N_EXT | MachO::N_UNDF;
+ U.NSect = 0;
+ U.NDesc = 0;
+ // The library ordinal for this undefined symbol is in the export
+ // trie Entry.other().
+ MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
+ U.IndirectName = StringRef();
+ SymbolList.push_back(U);
+
+ // Finally add the undefined symbol's name.
+ if (Entry.otherName().empty())
+ EOS << Entry.name();
+ else
+ EOS << Entry.otherName();
+ EOS << '\0';
+ ExportsAdded++;
+ }
+ }
+ }
+ // Set the symbol names and indirect names for the added symbols.
+ if (ExportsAdded) {
+ EOS.flush();
+ const char *Q = ExportsNameBuffer.c_str();
+ for (unsigned K = 0; K < ExportsAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Add the undefined symbols from the bind entries.
+ unsigned BindsAdded = 0;
+ Error BErr = Error::success();
+ StringRef LastSymbolName = StringRef();
+ for (const llvm::object::MachOBindEntry &Entry : MachO->bindTable(BErr)) {
+ bool found = false;
+ if (LastSymbolName == Entry.symbolName())
+ found = true;
+ else if(!DyldInfoOnly) {
+ for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Name == Entry.symbolName())
+ found = true;
+ }
+ }
+ if (!found) {
+ LastSymbolName = Entry.symbolName();
+ NMSymbol B;
+ memset(&B, '\0', sizeof(NMSymbol));
+ B.Address = 0;
+ B.Size = 0;
+ B.TypeChar = 'U';
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ B.Sym = BasicSymbolRef();
+ B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ B.NType = MachO::N_EXT | MachO::N_UNDF;
+ B.NSect = 0;
+ B.NDesc = 0;
+ B.NDesc = 0;
+ MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
+ B.IndirectName = StringRef();
+ B.Name = Entry.symbolName();
+ SymbolList.push_back(B);
+ BOS << Entry.symbolName();
+ BOS << '\0';
+ BindsAdded++;
+ }
+ }
+ if (BErr)
+ error(std::move(BErr), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (BindsAdded) {
+ BOS.flush();
+ const char *Q = BindsNameBuffer.c_str();
+ for (unsigned K = 0; K < BindsAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Add the undefined symbols from the lazy bind entries.
+ unsigned LazysAdded = 0;
+ Error LErr = Error::success();
+ LastSymbolName = StringRef();
+ for (const llvm::object::MachOBindEntry &Entry :
+ MachO->lazyBindTable(LErr)) {
+ bool found = false;
+ if (LastSymbolName == Entry.symbolName())
+ found = true;
+ else {
+ // Here we must check to see it this symbol is already in the
+ // SymbolList as it might have already have been added above via a
+ // non-lazy (bind) entry.
+ for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Name == Entry.symbolName())
+ found = true;
+ }
+ }
+ if (!found) {
+ LastSymbolName = Entry.symbolName();
+ NMSymbol L;
+ memset(&L, '\0', sizeof(NMSymbol));
+ L.Name = Entry.symbolName();
+ L.Address = 0;
+ L.Size = 0;
+ L.TypeChar = 'U';
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ L.Sym = BasicSymbolRef();
+ L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ L.NType = MachO::N_EXT | MachO::N_UNDF;
+ L.NSect = 0;
+ // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
+ // makes sence since we are creating this from a lazy bind entry.
+ L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
+ MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
+ L.IndirectName = StringRef();
+ SymbolList.push_back(L);
+ LOS << Entry.symbolName();
+ LOS << '\0';
+ LazysAdded++;
+ }
+ }
+ if (LErr)
+ error(std::move(LErr), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (LazysAdded) {
+ LOS.flush();
+ const char *Q = LazysNameBuffer.c_str();
+ for (unsigned K = 0; K < LazysAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Add the undefineds symbol from the weak bind entries which are not
+ // strong symbols.
+ unsigned WeaksAdded = 0;
+ Error WErr = Error::success();
+ LastSymbolName = StringRef();
+ for (const llvm::object::MachOBindEntry &Entry :
+ MachO->weakBindTable(WErr)) {
+ bool found = false;
+ unsigned J = 0;
+ if (LastSymbolName == Entry.symbolName() ||
+ Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
+ found = true;
+ } else {
+ for (J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Name == Entry.symbolName()) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ LastSymbolName = Entry.symbolName();
+ NMSymbol W;
+ memset(&W, '\0', sizeof(NMSymbol));
+ W.Name = Entry.symbolName();
+ W.Address = 0;
+ W.Size = 0;
+ W.TypeChar = 'U';
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ W.Sym = BasicSymbolRef();
+ W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ W.NType = MachO::N_EXT | MachO::N_UNDF;
+ W.NSect = 0;
+ // Odd that we are using N_WEAK_DEF on an undefined symbol but that is
+ // what is created in this case by the linker when there are real
+ // symbols in the nlist structs.
+ W.NDesc = MachO::N_WEAK_DEF;
+ W.IndirectName = StringRef();
+ SymbolList.push_back(W);
+ WOS << Entry.symbolName();
+ WOS << '\0';
+ WeaksAdded++;
+ } else {
+ // This is the case the symbol was previously been found and it could
+ // have been added from a bind or lazy bind symbol. If so and not
+ // a definition also mark it as weak.
+ if (SymbolList[J].TypeChar == 'U')
+ // See comment above about N_WEAK_DEF.
+ SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
+ }
+ }
+ if (WErr)
+ error(std::move(WErr), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (WeaksAdded) {
+ WOS.flush();
+ const char *Q = WeaksNameBuffer.c_str();
+ for (unsigned K = 0; K < WeaksAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+ }
+ }
+
CurrentFilename = Obj.getFileName();
sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName);
}
@@ -1456,6 +1926,9 @@ int main(int argc, char **argv) {
error("bad number of arguments (must be two arguments)",
"for the -s option");
+ if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
+ error("-no-dyldinfo can't be used with -add-dyldinfo or -dyldinfo-only");
+
std::for_each(InputFilenames.begin(), InputFilenames.end(),
dumpSymbolNamesFromFile);
diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp
index 8927f57cc97f..05c2c3f7c4cb 100644
--- a/tools/llvm-objdump/MachODump.cpp
+++ b/tools/llvm-objdump/MachODump.cpp
@@ -1135,7 +1135,8 @@ static void DumpInfoPlistSectionContents(StringRef Filename,
DataRefImpl Ref = Section.getRawDataRefImpl();
StringRef SegName = O->getSectionFinalSegmentName(Ref);
if (SegName == "__TEXT" && SectName == "__info_plist") {
- outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+ if (!NoLeadingHeaders)
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
StringRef BytesStr;
Section.getContents(BytesStr);
const char *sect = reinterpret_cast<const char *>(BytesStr.data());
@@ -1223,8 +1224,13 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
if (Error Err = MachOOF->checkSymbolTable())
report_error(ArchiveName, FileName, std::move(Err), ArchitectureName);
- if (Disassemble)
- DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");
+ if (Disassemble) {
+ if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&
+ MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)
+ DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text");
+ else
+ DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");
+ }
if (IndirectSymbols)
PrintIndirectSymbols(MachOOF, !NonVerbose);
if (DataInCode)
@@ -1920,11 +1926,45 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
if (Arch == Triple::x86_64) {
if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
return 0;
+ // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external
+ // relocation entries of a linked image (if any) for an entry that matches
+ // this segment offset.
if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
- // TODO:
- // Search the external relocation entries of a fully linked image
- // (if any) for an entry that matches this segment offset.
- // uint64_t seg_offset = (Pc + Offset);
+ uint64_t seg_offset = Pc + Offset;
+ bool reloc_found = false;
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ SymbolRef Symbol;
+ for (const RelocationRef &Reloc : info->O->external_relocations()) {
+ uint64_t RelocOffset = Reloc.getOffset();
+ if (RelocOffset == seg_offset) {
+ Rel = Reloc.getRawDataRefImpl();
+ RE = info->O->getRelocation(Rel);
+ // external relocation entries should always be external.
+ isExtern = info->O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Symbol = *RelocSym;
+ }
+ reloc_found = true;
+ break;
+ }
+ }
+ if (reloc_found && isExtern) {
+ // The Value passed in will be adjusted by the Pc if the instruction
+ // adds the Pc. But for x86_64 external relocation entries the Value
+ // is the offset from the external symbol.
+ if (info->O->getAnyRelocationPCRel(RE))
+ op_info->Value -= Pc + Offset + Size;
+ Expected<StringRef> SymName = Symbol.getName();
+ if (!SymName)
+ report_error(info->O->getFileName(), SymName.takeError());
+ const char *name = SymName->data();
+ op_info->AddSymbol.Present = 1;
+ op_info->AddSymbol.Name = name;
+ return 1;
+ }
return 0;
}
// In MH_OBJECT filetypes search the section's relocation entries (if any)
@@ -4572,6 +4612,12 @@ static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
n_value, c.superclass);
if (name != nullptr)
outs() << " " << name;
+ else {
+ name = get_dyld_bind_info_symbolname(S.getAddress() +
+ offset + offsetof(struct class64_t, superclass), info);
+ if (name != nullptr)
+ outs() << " " << name;
+ }
outs() << "\n";
outs() << " cache " << format("0x%" PRIx64, c.cache);
@@ -7634,6 +7680,10 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype,
outs() << " APP_EXTENSION_SAFE";
f &= ~MachO::MH_APP_EXTENSION_SAFE;
}
+ if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
+ outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";
+ f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;
+ }
if (f != 0 || flags == 0)
outs() << format(" 0x%08" PRIx32, f);
} else {
@@ -9336,6 +9386,22 @@ void llvm::printMachOLoadCommands(const object::ObjectFile *Obj) {
//===----------------------------------------------------------------------===//
void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
+ uint64_t BaseSegmentAddress = 0;
+ for (const auto &Command : Obj->load_commands()) {
+ if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = Obj->getSegmentLoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ }
+ }
for (const llvm::object::ExportEntry &Entry : Obj->exports()) {
uint64_t Flags = Entry.flags();
bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
@@ -9349,7 +9415,7 @@ void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
outs() << "[re-export] ";
else
outs() << format("0x%08llX ",
- Entry.address()); // FIXME:add in base address
+ Entry.address() + BaseSegmentAddress);
outs() << Entry.name();
if (WeakDef || ThreadLocal || Resolver || Abs) {
bool NeedsComma = false;
diff --git a/tools/llvm-pdbutil/Analyze.cpp b/tools/llvm-pdbutil/Analyze.cpp
index b503cdcbf1ea..6c603dd8542b 100644
--- a/tools/llvm-pdbutil/Analyze.cpp
+++ b/tools/llvm-pdbutil/Analyze.cpp
@@ -12,10 +12,8 @@
#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/LazyRandomTypeCollection.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"
@@ -73,16 +71,14 @@ Error AnalysisStyle::dump() {
if (!Tpi)
return Tpi.takeError();
- TypeDatabase TypeDB(Tpi->getNumTypeRecords());
- TypeDatabaseVisitor DBV(TypeDB);
- TypeVisitorCallbackPipeline Pipeline;
HashLookupVisitor Hasher(*Tpi);
- // Add them to the database
- Pipeline.addCallbackToPipeline(DBV);
- // Store their hash values
- Pipeline.addCallbackToPipeline(Hasher);
- if (auto EC = codeview::visitTypeStream(Tpi->typeArray(), Pipeline))
+ uint32_t RecordCount = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ auto Types = llvm::make_unique<LazyRandomTypeCollection>(
+ Tpi->typeArray(), RecordCount, Offsets);
+
+ if (auto EC = codeview::visitTypeStream(*Types, Hasher))
return EC;
auto &Adjusters = Tpi->getHashAdjusters();
@@ -109,7 +105,7 @@ Error AnalysisStyle::dump() {
}
StringRef LeafName = getLeafTypeName(R.Record.Type);
uint32_t TI = R.TI.getIndex();
- StringRef TypeName = TypeDB.getTypeName(R.TI);
+ StringRef TypeName = Types->getTypeName(R.TI);
outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI,
TypeName);
}
@@ -119,8 +115,8 @@ Error AnalysisStyle::dump() {
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);
+ StringRef TypeName = Types->getTypeName(TI);
+ const CVType &HeadRecord = Types->getType(TI);
assert(HeadRecord.Hash.hasValue());
auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash);
@@ -134,10 +130,10 @@ Error AnalysisStyle::dump() {
for (const auto &Chain : Collisions) {
if (Chain.TI == TI)
continue;
- const CVType &TailRecord = TypeDB.getTypeRecord(Chain.TI);
+ const CVType &TailRecord = Types->getType(Chain.TI);
outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(),
getLeafTypeName(TailRecord.Type),
- TypeDB.getTypeName(Chain.TI));
+ Types->getTypeName(Chain.TI));
}
}
outs() << formatv("There are {0} orphaned hash adjusters\n",
diff --git a/tools/llvm-pdbutil/BytesOutputStyle.cpp b/tools/llvm-pdbutil/BytesOutputStyle.cpp
new file mode 100644
index 000000000000..9e5a28c2b98b
--- /dev/null
+++ b/tools/llvm-pdbutil/BytesOutputStyle.cpp
@@ -0,0 +1,501 @@
+//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BytesOutputStyle.h"
+
+#include "FormatUtil.h"
+#include "StreamUtil.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.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/BinaryStreamReader.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace {
+struct StreamSpec {
+ uint32_t SI = 0;
+ uint32_t Begin = 0;
+ uint32_t Size = 0;
+};
+} // namespace
+
+static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
+ StreamSpec Result;
+ if (Str.consumeInteger(0, Result.SI))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ if (Str.consume_front(":")) {
+ if (Str.consumeInteger(0, Result.Begin))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ }
+ if (Str.consume_front("@")) {
+ if (Str.consumeInteger(0, Result.Size))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ }
+
+ if (!Str.empty())
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ return Result;
+}
+
+static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
+ SmallVector<StreamSpec, 2> Result;
+
+ for (auto &Str : opts::bytes::DumpStreamData) {
+ auto ESS = parseStreamSpec(Str);
+ if (!ESS) {
+ P.formatLine("Error parsing stream spec {0}: {1}", Str,
+ toString(ESS.takeError()));
+ continue;
+ }
+ Result.push_back(*ESS);
+ }
+ return Result;
+}
+
+static void printHeader(LinePrinter &P, const Twine &S) {
+ P.NewLine();
+ P.formatLine("{0,=60}", S);
+ P.formatLine("{0}", fmt_repeat('=', 60));
+}
+
+BytesOutputStyle::BytesOutputStyle(PDBFile &File)
+ : File(File), P(2, false, outs()) {}
+
+Error BytesOutputStyle::dump() {
+
+ if (opts::bytes::DumpBlockRange.hasValue()) {
+ auto &R = *opts::bytes::DumpBlockRange;
+ uint32_t Max = R.Max.getValueOr(R.Min);
+
+ if (Max < R.Min)
+ return make_error<StringError>(
+ "Invalid block range specified. Max < Min",
+ inconvertibleErrorCode());
+ if (Max >= File.getBlockCount())
+ return make_error<StringError>(
+ "Invalid block range specified. Requested block out of bounds",
+ inconvertibleErrorCode());
+
+ dumpBlockRanges(R.Min, Max);
+ P.NewLine();
+ }
+
+ if (opts::bytes::DumpByteRange.hasValue()) {
+ auto &R = *opts::bytes::DumpByteRange;
+ uint32_t Max = R.Max.getValueOr(File.getFileSize());
+
+ if (Max < R.Min)
+ return make_error<StringError>("Invalid byte range specified. Max < Min",
+ inconvertibleErrorCode());
+ if (Max >= File.getFileSize())
+ return make_error<StringError>(
+ "Invalid byte range specified. Requested byte larger than file size",
+ inconvertibleErrorCode());
+
+ dumpByteRanges(R.Min, Max);
+ P.NewLine();
+ }
+
+ if (!opts::bytes::DumpStreamData.empty()) {
+ dumpStreamBytes();
+ P.NewLine();
+ }
+
+ if (opts::bytes::NameMap) {
+ dumpNameMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::SectionContributions) {
+ dumpSectionContributions();
+ P.NewLine();
+ }
+
+ if (opts::bytes::SectionMap) {
+ dumpSectionMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleInfos) {
+ dumpModuleInfos();
+ P.NewLine();
+ }
+
+ if (opts::bytes::FileInfo) {
+ dumpFileInfo();
+ P.NewLine();
+ }
+
+ if (opts::bytes::TypeServerMap) {
+ dumpTypeServerMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ECData) {
+ dumpECData();
+ P.NewLine();
+ }
+
+ if (!opts::bytes::TypeIndex.empty()) {
+ dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);
+ P.NewLine();
+ }
+
+ if (!opts::bytes::IdIndex.empty()) {
+ dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleSyms) {
+ dumpModuleSyms();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleC11) {
+ dumpModuleC11();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleC13) {
+ dumpModuleC13();
+ P.NewLine();
+ }
+
+ return Error::success();
+}
+
+void BytesOutputStyle::dumpNameMap() {
+ printHeader(P, "Named Stream Map");
+
+ AutoIndent Indent(P);
+
+ auto &InfoS = Err(File.getPDBInfoStream());
+ BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();
+ auto Layout = File.getStreamLayout(StreamPDB);
+ P.formatMsfStreamData("Named Stream Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
+ printHeader(P, "MSF Blocks");
+
+ AutoIndent Indent(P);
+ for (uint32_t I = Min; I <= Max; ++I) {
+ uint64_t Base = I;
+ Base *= File.getBlockSize();
+
+ auto ExpectedData = File.getBlockData(I, File.getBlockSize());
+ if (!ExpectedData) {
+ P.formatLine("Could not get block {0}. Reason = {1}", I,
+ toString(ExpectedData.takeError()));
+ continue;
+ }
+ std::string Label = formatv("Block {0}", I).str();
+ P.formatBinary(Label, *ExpectedData, Base, 0);
+ }
+}
+
+void BytesOutputStyle::dumpSectionContributions() {
+ printHeader(P, "Section Contributions");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getSectionContributionData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Section Contributions", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpSectionMap() {
+ printHeader(P, "Section Map");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Section Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpModuleInfos() {
+ printHeader(P, "Module Infos");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getModiSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Module Infos", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpFileInfo() {
+ printHeader(P, "File Info");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("File Info", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpTypeServerMap() {
+ printHeader(P, "Type Server Map");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Type Server Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpECData() {
+ printHeader(P, "Edit and Continue Data");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getECSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
+ ArrayRef<uint32_t> Indices) {
+ assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
+ assert(!Indices.empty());
+
+ bool IsTpi = (StreamIdx == StreamTPI);
+
+ StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";
+ printHeader(P, Label);
+ auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());
+
+ AutoIndent Indent(P);
+
+ auto Substream = Stream.getTypeRecordsSubstream();
+ auto &Types = Err(initializeTypes(StreamIdx));
+ auto Layout = File.getStreamLayout(StreamIdx);
+ for (const auto &Id : Indices) {
+ TypeIndex TI(Id);
+ if (TI.toArrayIndex() >= Types.capacity()) {
+ P.formatLine("Error: TypeIndex {0} does not exist", TI);
+ continue;
+ }
+
+ auto Type = Types.getType(TI);
+ uint32_t Offset = Types.getOffsetOfType(TI);
+ auto OneType = Substream.slice(Offset, Type.length());
+ P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);
+ }
+}
+
+template <typename CallbackT>
+static void iterateOneModule(PDBFile &File, LinePrinter &P,
+ const DbiModuleList &Modules, uint32_t I,
+ uint32_t Digits, uint32_t IndentLevel,
+ CallbackT Callback) {
+ if (I >= Modules.getModuleCount()) {
+ P.formatLine("Mod {0:4} | Invalid module index ",
+ fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)));
+ return;
+ }
+
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | `{1}`: ",
+ fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)),
+ Modi.getModuleName());
+
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ AutoIndent Indent2(P, IndentLevel);
+ if (ModiStream == kInvalidStreamIndex)
+ return;
+
+ auto ModStreamData = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+ ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));
+ if (auto EC = ModStream.reload()) {
+ P.formatLine("Could not parse debug information.");
+ return;
+ }
+ auto Layout = File.getStreamLayout(ModiStream);
+ Callback(I, ModStream, Layout);
+}
+
+template <typename CallbackT>
+static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
+ CallbackT Callback) {
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return;
+ }
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+
+ if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) {
+ iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel,
+ Callback);
+ } else {
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback);
+ }
+ }
+}
+
+void BytesOutputStyle::dumpModuleSyms() {
+ printHeader(P, "Module Symbols");
+
+ AutoIndent Indent(P);
+
+ iterateModules(File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Symbols = Stream.getSymbolsSubstream();
+ P.formatMsfStreamData("Symbols", File, Layout, Symbols);
+ });
+}
+
+void BytesOutputStyle::dumpModuleC11() {
+ printHeader(P, "C11 Debug Chunks");
+
+ AutoIndent Indent(P);
+
+ iterateModules(File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Chunks = Stream.getC11LinesSubstream();
+ P.formatMsfStreamData("C11 Debug Chunks", File, Layout,
+ Chunks);
+ });
+}
+
+static std::string formatChunkKind(DebugSubsectionKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(DebugSubsectionKind, None, "none");
+ RETURN_CASE(DebugSubsectionKind, Symbols, "symbols");
+ RETURN_CASE(DebugSubsectionKind, Lines, "lines");
+ RETURN_CASE(DebugSubsectionKind, StringTable, "strings");
+ RETURN_CASE(DebugSubsectionKind, FileChecksums, "checksums");
+ RETURN_CASE(DebugSubsectionKind, FrameData, "frames");
+ RETURN_CASE(DebugSubsectionKind, InlineeLines, "inlinee lines");
+ RETURN_CASE(DebugSubsectionKind, CrossScopeImports, "xmi");
+ RETURN_CASE(DebugSubsectionKind, CrossScopeExports, "xme");
+ RETURN_CASE(DebugSubsectionKind, ILLines, "il lines");
+ RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap, "func md token map");
+ RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap, "type md token map");
+ RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput,
+ "merged assembly input");
+ RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA, "coff symbol rva");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+void BytesOutputStyle::dumpModuleC13() {
+ printHeader(P, "Debug Chunks");
+
+ AutoIndent Indent(P);
+
+ iterateModules(
+ File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Chunks = Stream.getC13LinesSubstream();
+ if (opts::bytes::SplitChunks) {
+ for (const auto &SS : Stream.subsections()) {
+ BinarySubstreamRef ThisChunk;
+ std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength());
+ P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout,
+ ThisChunk);
+ }
+ } else {
+ P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks);
+ }
+ });
+}
+
+void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
+ printHeader(P, "MSF Bytes");
+
+ AutoIndent Indent(P);
+
+ BinaryStreamReader Reader(File.getMsfBuffer());
+ ArrayRef<uint8_t> Data;
+ consumeError(Reader.skip(Min));
+ uint32_t Size = Max - Min + 1;
+ auto EC = Reader.readBytes(Data, Size);
+ assert(!EC);
+ consumeError(std::move(EC));
+ P.formatBinary("Bytes", Data, Min);
+}
+
+Expected<codeview::LazyRandomTypeCollection &>
+BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {
+ auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;
+ if (TypeCollection)
+ return *TypeCollection;
+
+ auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
+ : File.getPDBIpiStream();
+ if (!Tpi)
+ return Tpi.takeError();
+
+ auto &Types = Tpi->typeArray();
+ uint32_t Count = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ TypeCollection =
+ llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
+
+ return *TypeCollection;
+}
+
+void BytesOutputStyle::dumpStreamBytes() {
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
+
+ printHeader(P, "Stream Data");
+ ExitOnError Err("Unexpected error reading stream data");
+
+ auto Specs = parseStreamSpecs(P);
+
+ for (const auto &Spec : Specs) {
+ AutoIndent Indent(P);
+ if (Spec.SI >= StreamPurposes.size()) {
+ P.formatLine("Stream {0}: Not present", Spec.SI);
+ continue;
+ }
+ P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI],
+ Spec.Begin, Spec.Size);
+ }
+}
diff --git a/tools/llvm-pdbutil/BytesOutputStyle.h b/tools/llvm-pdbutil/BytesOutputStyle.h
new file mode 100644
index 000000000000..c162163fdd01
--- /dev/null
+++ b/tools/llvm-pdbutil/BytesOutputStyle.h
@@ -0,0 +1,67 @@
+//===- BytesOutputStyle.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_BYTESOUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
+
+#include "LinePrinter.h"
+#include "OutputStyle.h"
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+
+class PDBFile;
+
+class BytesOutputStyle : public OutputStyle {
+public:
+ BytesOutputStyle(PDBFile &File);
+
+ Error dump() override;
+
+private:
+ void dumpNameMap();
+ void dumpBlockRanges(uint32_t Min, uint32_t Max);
+ void dumpByteRanges(uint32_t Min, uint32_t Max);
+ void dumpStreamBytes();
+
+ void dumpSectionContributions();
+ void dumpSectionMap();
+ void dumpModuleInfos();
+ void dumpFileInfo();
+ void dumpTypeServerMap();
+ void dumpECData();
+
+ void dumpModuleSyms();
+ void dumpModuleC11();
+ void dumpModuleC13();
+
+ void dumpTypeIndex(uint32_t StreamIdx, ArrayRef<uint32_t> Indices);
+
+ Expected<codeview::LazyRandomTypeCollection &>
+ initializeTypes(uint32_t StreamIdx);
+
+ std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes;
+
+ PDBFile &File;
+ LinePrinter P;
+ ExitOnError Err;
+ SmallVector<std::string, 8> StreamPurposes;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-pdbutil/CMakeLists.txt b/tools/llvm-pdbutil/CMakeLists.txt
index d09fa31d8b6a..7a3245424efc 100644
--- a/tools/llvm-pdbutil/CMakeLists.txt
+++ b/tools/llvm-pdbutil/CMakeLists.txt
@@ -9,8 +9,9 @@ set(LLVM_LINK_COMPONENTS
add_llvm_tool(llvm-pdbutil
Analyze.cpp
- CompactTypeDumpVisitor.cpp
+ BytesOutputStyle.cpp
Diff.cpp
+ DumpOutputStyle.cpp
llvm-pdbutil.cpp
FormatUtil.cpp
LinePrinter.cpp
@@ -27,7 +28,6 @@ add_llvm_tool(llvm-pdbutil
PrettyTypeDumper.cpp
PrettyTypedefDumper.cpp
PrettyVariableDumper.cpp
- RawOutputStyle.cpp
StreamUtil.cpp
YAMLOutputStyle.cpp
)
diff --git a/tools/llvm-pdbutil/CompactTypeDumpVisitor.cpp b/tools/llvm-pdbutil/CompactTypeDumpVisitor.cpp
deleted file mode 100644
index 6dd54e0dbec1..000000000000
--- a/tools/llvm-pdbutil/CompactTypeDumpVisitor.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-//===-- 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/CodeViewTypes.def"
-};
-
-static StringRef getLeafName(TypeLeafKind K) {
- for (const auto &E : LeafTypeNames) {
- if (E.Value == K)
- return E.Name;
- }
- return StringRef();
-}
-
-CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types,
- ScopedPrinter *W)
- : CompactTypeDumpVisitor(Types, TypeIndex(TypeIndex::FirstNonSimpleIndex),
- W) {}
-
-CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types,
- TypeIndex FirstTI,
- ScopedPrinter *W)
- : W(W), TI(FirstTI), Offset(0), Types(Types) {}
-
-Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) {
- return Error::success();
-}
-
-Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) {
- uint32_t I = TI.getIndex();
- StringRef Leaf = getLeafName(Record.Type);
- StringRef Name = Types.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();
- TI.setIndex(TI.getIndex() + 1);
-
- return Error::success();
-}
diff --git a/tools/llvm-pdbutil/CompactTypeDumpVisitor.h b/tools/llvm-pdbutil/CompactTypeDumpVisitor.h
deleted file mode 100644
index 41ccea0c2e90..000000000000
--- a/tools/llvm-pdbutil/CompactTypeDumpVisitor.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//===-- 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 TypeCollection;
-}
-
-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::TypeCollection &Types, ScopedPrinter *W);
- CompactTypeDumpVisitor(codeview::TypeCollection &Types,
- codeview::TypeIndex FirstTI, 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::TypeCollection &Types;
-};
-
-} // end namespace pdb
-} // end namespace llvm
-
-#endif
diff --git a/tools/llvm-pdbutil/Diff.cpp b/tools/llvm-pdbutil/Diff.cpp
index 3fe6c511d35f..9b38ae1d603e 100644
--- a/tools/llvm-pdbutil/Diff.cpp
+++ b/tools/llvm-pdbutil/Diff.cpp
@@ -198,17 +198,6 @@ Error DiffStyle::diffSuperBlock() {
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();
@@ -222,114 +211,72 @@ Error DiffStyle::diffStreamDirectory() {
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;
- }
- }
+ auto PI = to_vector<32>(enumerate(P));
+ auto QI = to_vector<32>(enumerate(Q));
- 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());
- }
+ 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 (!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 (!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";
+ if (!HasCommonDifferences)
+ outs().indent(2) << "Common Streams: No differences detected!\n";
}
+ if (!HasDifferences)
+ outs() << "Stream Directory: No differences detected!\n";
return Error::success();
}
@@ -384,77 +331,39 @@ Error DiffStyle::diffStringTable() {
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];
- if (auto Result = ST1.getStringForID(*Id1))
- S1 = *Result;
- else
- return Result.takeError();
- }
- if (I < IdList2.size()) {
- Id2 = IdList2[I];
- if (auto Result = ST2.getStringForID(*Id2))
- S2 = *Result;
- else
- return Result.takeError();
- }
- 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) {
- auto S = ST1.getStringForID(ID);
- if (!S)
- return S.takeError();
- Strings1.push_back(*S);
- }
- for (auto ID : IdList2) {
- auto S = ST2.getStringForID(ID);
- if (!S)
- return S.takeError();
- Strings2.push_back(*S);
- }
+ std::vector<StringRef> Strings1, Strings2;
+ Strings1.reserve(IdList1.size());
+ Strings2.reserve(IdList2.size());
+ for (auto ID : IdList1) {
+ auto S = ST1.getStringForID(ID);
+ if (!S)
+ return S.takeError();
+ Strings1.push_back(*S);
+ }
+ for (auto ID : IdList2) {
+ auto S = ST2.getStringForID(ID);
+ if (!S)
+ return S.takeError();
+ Strings2.push_back(*S);
+ }
- 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());
- }
+ 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";
diff --git a/tools/llvm-pdbutil/RawOutputStyle.cpp b/tools/llvm-pdbutil/DumpOutputStyle.cpp
index b204a89ec317..f76635f9e511 100644
--- a/tools/llvm-pdbutil/RawOutputStyle.cpp
+++ b/tools/llvm-pdbutil/DumpOutputStyle.cpp
@@ -1,4 +1,4 @@
-//===- RawOutputStyle.cpp ------------------------------------ *- C++ --*-===//
+//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,9 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#include "RawOutputStyle.h"
+#include "DumpOutputStyle.h"
-#include "CompactTypeDumpVisitor.h"
#include "FormatUtil.h"
#include "MinimalSymbolDumper.h"
#include "MinimalTypeDumper.h"
@@ -65,96 +64,84 @@ using namespace llvm::codeview;
using namespace llvm::msf;
using namespace llvm::pdb;
-RawOutputStyle::RawOutputStyle(PDBFile &File)
+DumpOutputStyle::DumpOutputStyle(PDBFile &File)
: File(File), P(2, false, outs()) {}
-Error RawOutputStyle::dump() {
- if (opts::raw::DumpSummary) {
+Error DumpOutputStyle::dump() {
+ if (opts::dump::DumpSummary) {
if (auto EC = dumpFileSummary())
return EC;
P.NewLine();
}
- if (opts::raw::DumpStreams) {
+ if (opts::dump::DumpStreams) {
if (auto EC = dumpStreamSummary())
return EC;
P.NewLine();
}
- if (opts::raw::DumpBlockRange.hasValue()) {
- if (auto EC = dumpBlockRanges())
- return EC;
- P.NewLine();
- }
-
- if (!opts::raw::DumpStreamData.empty()) {
- if (auto EC = dumpStreamBytes())
- return EC;
- P.NewLine();
- }
-
- if (opts::raw::DumpStringTable) {
+ if (opts::dump::DumpStringTable) {
if (auto EC = dumpStringTable())
return EC;
P.NewLine();
}
- if (opts::raw::DumpModules) {
+ if (opts::dump::DumpModules) {
if (auto EC = dumpModules())
return EC;
}
- if (opts::raw::DumpModuleFiles) {
+ if (opts::dump::DumpModuleFiles) {
if (auto EC = dumpModuleFiles())
return EC;
}
- if (opts::raw::DumpLines) {
+ if (opts::dump::DumpLines) {
if (auto EC = dumpLines())
return EC;
}
- if (opts::raw::DumpInlineeLines) {
+ if (opts::dump::DumpInlineeLines) {
if (auto EC = dumpInlineeLines())
return EC;
}
- if (opts::raw::DumpXmi) {
+ if (opts::dump::DumpXmi) {
if (auto EC = dumpXmi())
return EC;
}
- if (opts::raw::DumpXme) {
+ if (opts::dump::DumpXme) {
if (auto EC = dumpXme())
return EC;
}
- if (opts::raw::DumpTypes || opts::raw::DumpTypeExtras) {
+ if (opts::dump::DumpTypes || opts::dump::DumpTypeExtras) {
if (auto EC = dumpTpiStream(StreamTPI))
return EC;
}
- if (opts::raw::DumpIds || opts::raw::DumpIdExtras) {
+ if (opts::dump::DumpIds || opts::dump::DumpIdExtras) {
if (auto EC = dumpTpiStream(StreamIPI))
return EC;
}
- if (opts::raw::DumpPublics) {
+ if (opts::dump::DumpPublics) {
if (auto EC = dumpPublics())
return EC;
}
- if (opts::raw::DumpSymbols) {
+ if (opts::dump::DumpSymbols) {
if (auto EC = dumpModuleSyms())
return EC;
}
- if (opts::raw::DumpSectionContribs) {
+ if (opts::dump::DumpSectionContribs) {
if (auto EC = dumpSectionContribs())
return EC;
}
- if (opts::raw::DumpSectionMap) {
+ if (opts::dump::DumpSectionMap) {
if (auto EC = dumpSectionMap())
return EC;
}
@@ -168,7 +155,7 @@ static void printHeader(LinePrinter &P, const Twine &S) {
P.formatLine("{0}", fmt_repeat('=', 60));
}
-Error RawOutputStyle::dumpFileSummary() {
+Error DumpOutputStyle::dumpFileSummary() {
printHeader(P, "Summary");
ExitOnError Err("Invalid PDB Format");
@@ -198,7 +185,7 @@ Error RawOutputStyle::dumpFileSummary() {
return Error::success();
}
-Error RawOutputStyle::dumpStreamSummary() {
+Error DumpOutputStyle::dumpStreamSummary() {
printHeader(P, "Streams");
if (StreamPurposes.empty())
@@ -212,105 +199,15 @@ Error RawOutputStyle::dumpStreamSummary() {
"Stream {0}: [{1}] ({2} bytes)",
fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
- }
-
- return Error::success();
-}
-
-Error RawOutputStyle::dumpBlockRanges() {
- printHeader(P, "MSF Blocks");
-
- auto &R = *opts::raw::DumpBlockRange;
- uint32_t Max = R.Max.getValueOr(R.Min);
-
- AutoIndent Indent(P);
- if (Max < R.Min)
- return make_error<StringError>(
- "Invalid block range specified. Max < Min",
- std::make_error_code(std::errc::bad_address));
- if (Max >= File.getBlockCount())
- return make_error<StringError>(
- "Invalid block range specified. Requested block out of bounds",
- std::make_error_code(std::errc::bad_address));
-
- for (uint32_t I = R.Min; I <= Max; ++I) {
- auto ExpectedData = File.getBlockData(I, File.getBlockSize());
- if (!ExpectedData)
- return ExpectedData.takeError();
- std::string Label = formatv("Block {0}", I).str();
- P.formatBinary(Label, *ExpectedData, 0);
- }
-
- return Error::success();
-}
-
-static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
- uint32_t &Size) {
- if (Str.consumeInteger(0, SI))
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- if (Str.consume_front(":")) {
- if (Str.consumeInteger(0, Offset))
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- }
- if (Str.consume_front("@")) {
- if (Str.consumeInteger(0, Size))
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- }
- if (!Str.empty())
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- return Error::success();
-}
-
-Error RawOutputStyle::dumpStreamBytes() {
- if (StreamPurposes.empty())
- discoverStreamPurposes(File, StreamPurposes);
-
- printHeader(P, "Stream Data");
- ExitOnError Err("Unexpected error reading stream data");
-
- for (auto &Str : opts::raw::DumpStreamData) {
- uint32_t SI = 0;
- uint32_t Begin = 0;
- uint32_t Size = 0;
- uint32_t End = 0;
-
- if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
- return EC;
-
- AutoIndent Indent(P);
- if (SI >= File.getNumStreams()) {
- P.formatLine("Stream {0}: Not present", SI);
- continue;
- }
-
- auto S = MappedBlockStream::createIndexedStream(
- File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
- if (!S) {
- P.NewLine();
- P.formatLine("Stream {0}: Not present", SI);
- continue;
+ if (opts::dump::DumpStreamBlocks) {
+ auto Blocks = File.getStreamBlockList(StreamIdx);
+ std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
+ P.formatLine(" {0} Blocks: [{1}]",
+ fmt_repeat(' ', NumDigits(StreamCount)),
+ make_range(BV.begin(), BV.end()));
}
-
- if (Size == 0)
- End = S->getLength();
- else
- End = std::min(Begin + Size, S->getLength());
-
- P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
- StreamPurposes[SI]);
- AutoIndent Indent2(P);
-
- BinaryStreamReader R(*S);
- ArrayRef<uint8_t> StreamData;
- Err(R.readBytes(StreamData, S->getLength()));
- Size = End - Begin;
- StreamData = StreamData.slice(Begin, Size);
- P.formatBinary("Data", StreamData, Begin);
}
+
return Error::success();
}
@@ -494,7 +391,7 @@ static void iterateModuleSubsections(
});
}
-Error RawOutputStyle::dumpModules() {
+Error DumpOutputStyle::dumpModules() {
printHeader(P, "Modules");
AutoIndent Indent(P);
@@ -522,7 +419,7 @@ Error RawOutputStyle::dumpModules() {
return Error::success();
}
-Error RawOutputStyle::dumpModuleFiles() {
+Error DumpOutputStyle::dumpModuleFiles() {
printHeader(P, "Files");
ExitOnError Err("Unexpected error processing modules");
@@ -574,7 +471,7 @@ static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P,
}
}
-Error RawOutputStyle::dumpLines() {
+Error DumpOutputStyle::dumpLines() {
printHeader(P, "Lines");
uint32_t LastModi = UINT32_MAX;
@@ -610,7 +507,7 @@ Error RawOutputStyle::dumpLines() {
return Error::success();
}
-Error RawOutputStyle::dumpInlineeLines() {
+Error DumpOutputStyle::dumpInlineeLines() {
printHeader(P, "Inlinee Lines");
iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
@@ -629,7 +526,7 @@ Error RawOutputStyle::dumpInlineeLines() {
return Error::success();
}
-Error RawOutputStyle::dumpXmi() {
+Error DumpOutputStyle::dumpXmi() {
printHeader(P, "Cross Module Imports");
iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
File, P, 2,
@@ -664,7 +561,7 @@ Error RawOutputStyle::dumpXmi() {
return Error::success();
}
-Error RawOutputStyle::dumpXme() {
+Error DumpOutputStyle::dumpXme() {
printHeader(P, "Cross Module Exports");
iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
@@ -681,7 +578,7 @@ Error RawOutputStyle::dumpXme() {
return Error::success();
}
-Error RawOutputStyle::dumpStringTable() {
+Error DumpOutputStyle::dumpStringTable() {
printHeader(P, "String Table");
AutoIndent Indent(P);
@@ -723,25 +620,30 @@ Error RawOutputStyle::dumpStringTable() {
return Error::success();
}
-Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
+Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
bool Present = false;
bool DumpTypes = false;
bool DumpBytes = false;
bool DumpExtras = false;
+ std::vector<uint32_t> Indices;
if (StreamIdx == StreamTPI) {
printHeader(P, "Types (TPI Stream)");
Present = File.hasPDBTpiStream();
- DumpTypes = opts::raw::DumpTypes;
- DumpBytes = opts::raw::DumpTypeData;
- DumpExtras = opts::raw::DumpTypeExtras;
+ DumpTypes = opts::dump::DumpTypes;
+ DumpBytes = opts::dump::DumpTypeData;
+ DumpExtras = opts::dump::DumpTypeExtras;
+ Indices.assign(opts::dump::DumpTypeIndex.begin(),
+ opts::dump::DumpTypeIndex.end());
} else if (StreamIdx == StreamIPI) {
printHeader(P, "Types (IPI Stream)");
Present = File.hasPDBIpiStream();
- DumpTypes = opts::raw::DumpIds;
- DumpBytes = opts::raw::DumpIdData;
- DumpExtras = opts::raw::DumpIdExtras;
+ DumpTypes = opts::dump::DumpIds;
+ DumpBytes = opts::dump::DumpIdData;
+ DumpExtras = opts::dump::DumpIdExtras;
+ Indices.assign(opts::dump::DumpIdIndex.begin(),
+ opts::dump::DumpIdIndex.end());
}
AutoIndent Indent(P);
@@ -755,7 +657,7 @@ Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream()
: File.getPDBIpiStream());
- auto &Types = Err(initializeTypeDatabase(StreamIdx));
+ auto &Types = Err(initializeTypes(StreamIdx));
if (DumpTypes) {
P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
@@ -765,10 +667,19 @@ Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, DumpExtras, Types,
Stream.getHashValues());
- Optional<TypeIndex> I = Types.getFirst();
- if (auto EC = codeview::visitTypeStream(Types, V)) {
- P.formatLine("An error occurred dumping type records: {0}",
- toString(std::move(EC)));
+ if (Indices.empty()) {
+ if (auto EC = codeview::visitTypeStream(Types, V)) {
+ P.formatLine("An error occurred dumping type records: {0}",
+ toString(std::move(EC)));
+ }
+ } else {
+ for (const auto &I : Indices) {
+ TypeIndex TI(I);
+ CVType Type = Types.getType(TI);
+ if (auto EC = codeview::visitTypeRecord(Type, TI, V))
+ P.formatLine("An error occurred dumping type record {0}: {1}", TI,
+ toString(std::move(EC)));
+ }
}
}
@@ -801,7 +712,7 @@ Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
}
Expected<codeview::LazyRandomTypeCollection &>
-RawOutputStyle::initializeTypeDatabase(uint32_t SN) {
+DumpOutputStyle::initializeTypes(uint32_t SN) {
auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
auto Tpi =
(SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
@@ -819,7 +730,7 @@ RawOutputStyle::initializeTypeDatabase(uint32_t SN) {
return *TypeCollection;
}
-Error RawOutputStyle::dumpModuleSyms() {
+Error DumpOutputStyle::dumpModuleSyms() {
printHeader(P, "Symbols");
AutoIndent Indent(P);
@@ -832,7 +743,7 @@ Error RawOutputStyle::dumpModuleSyms() {
auto &Stream = Err(File.getPDBDbiStream());
- auto &Types = Err(initializeTypeDatabase(StreamTPI));
+ auto &Types = Err(initializeTypes(StreamTPI));
const DbiModuleList &Modules = Stream.modules();
uint32_t Count = Modules.getModuleCount();
@@ -859,7 +770,7 @@ Error RawOutputStyle::dumpModuleSyms() {
SymbolVisitorCallbackPipeline Pipeline;
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
- MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types);
+ MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
Pipeline.addCallbackToPipeline(Deserializer);
Pipeline.addCallbackToPipeline(Dumper);
@@ -873,7 +784,7 @@ Error RawOutputStyle::dumpModuleSyms() {
return Error::success();
}
-Error RawOutputStyle::dumpPublics() {
+Error DumpOutputStyle::dumpPublics() {
printHeader(P, "Public Symbols");
AutoIndent Indent(P);
@@ -884,11 +795,11 @@ Error RawOutputStyle::dumpPublics() {
ExitOnError Err("Error dumping publics stream");
- auto &Types = Err(initializeTypeDatabase(StreamTPI));
+ auto &Types = Err(initializeTypes(StreamTPI));
auto &Publics = Err(File.getPDBPublicsStream());
SymbolVisitorCallbackPipeline Pipeline;
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
- MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types);
+ MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
Pipeline.addCallbackToPipeline(Deserializer);
Pipeline.addCallbackToPipeline(Dumper);
@@ -988,7 +899,7 @@ static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
return typesetItemList(Opts, IndentLevel, 4, " | ");
}
-Error RawOutputStyle::dumpSectionContribs() {
+Error DumpOutputStyle::dumpSectionContribs() {
printHeader(P, "Section Contributions");
ExitOnError Err("Error dumping publics stream");
@@ -1034,7 +945,7 @@ Error RawOutputStyle::dumpSectionContribs() {
return Error::success();
}
-Error RawOutputStyle::dumpSectionMap() {
+Error DumpOutputStyle::dumpSectionMap() {
printHeader(P, "Section Map");
ExitOnError Err("Error dumping section map");
diff --git a/tools/llvm-pdbutil/RawOutputStyle.h b/tools/llvm-pdbutil/DumpOutputStyle.h
index 803f588961bb..296a6c14942e 100644
--- a/tools/llvm-pdbutil/RawOutputStyle.h
+++ b/tools/llvm-pdbutil/DumpOutputStyle.h
@@ -1,4 +1,4 @@
-//===- RawOutputStyle.h -------------------------------------- *- C++ --*-===//
+//===- DumpOutputStyle.h -------------------------------------- *- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,15 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H
-#define LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H
#include "LinePrinter.h"
#include "OutputStyle.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include <string>
@@ -27,15 +26,14 @@ class LazyRandomTypeCollection;
}
namespace pdb {
-class RawOutputStyle : public OutputStyle {
+class DumpOutputStyle : public OutputStyle {
public:
- RawOutputStyle(PDBFile &File);
+ DumpOutputStyle(PDBFile &File);
Error dump() override;
private:
- Expected<codeview::LazyRandomTypeCollection &>
- initializeTypeDatabase(uint32_t SN);
+ Expected<codeview::LazyRandomTypeCollection &> initializeTypes(uint32_t SN);
Error dumpFileSummary();
Error dumpStreamSummary();
diff --git a/tools/llvm-pdbutil/LinePrinter.cpp b/tools/llvm-pdbutil/LinePrinter.cpp
index 718d3394e211..6e4d95af944a 100644
--- a/tools/llvm-pdbutil/LinePrinter.cpp
+++ b/tools/llvm-pdbutil/LinePrinter.cpp
@@ -12,13 +12,21 @@
#include "llvm-pdbutil.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Regex.h"
#include <algorithm>
using namespace llvm;
+using namespace llvm::msf;
using namespace llvm::pdb;
namespace {
@@ -106,6 +114,138 @@ void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
OS << ")";
}
+void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+ uint64_t Base, uint32_t StartOffset) {
+ NewLine();
+ OS << Label << " (";
+ if (!Data.empty()) {
+ OS << "\n";
+ Base += StartOffset;
+ OS << format_bytes_with_ascii(Data, Base, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ NewLine();
+ }
+ OS << ")";
+}
+
+namespace {
+struct Run {
+ Run() = default;
+ explicit Run(uint32_t Block) : Block(Block) {}
+ uint32_t Block = 0;
+ uint32_t ByteLen = 0;
+};
+} // namespace
+
+static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
+ const msf::MSFStreamLayout &Layout) {
+ std::vector<Run> Runs;
+ if (Layout.Length == 0)
+ return Runs;
+
+ ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;
+ assert(!Blocks.empty());
+ uint32_t StreamBytesRemaining = Layout.Length;
+ uint32_t CurrentBlock = Blocks[0];
+ Runs.emplace_back(CurrentBlock);
+ while (!Blocks.empty()) {
+ Run *CurrentRun = &Runs.back();
+ uint32_t NextBlock = Blocks.front();
+ if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {
+ Runs.emplace_back(NextBlock);
+ CurrentRun = &Runs.back();
+ }
+ uint32_t Used = std::min(BlockSize, StreamBytesRemaining);
+ CurrentRun->ByteLen += Used;
+ StreamBytesRemaining -= Used;
+ CurrentBlock = NextBlock;
+ Blocks = Blocks.drop_front();
+ }
+ return Runs;
+}
+
+static std::pair<Run, uint32_t> findRun(uint32_t Offset, ArrayRef<Run> Runs) {
+ for (const auto &R : Runs) {
+ if (Offset < R.ByteLen)
+ return std::make_pair(R, Offset);
+ Offset -= R.ByteLen;
+ }
+ llvm_unreachable("Invalid offset!");
+}
+
+void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
+ uint32_t StreamIdx,
+ StringRef StreamPurpose, uint32_t Offset,
+ uint32_t Size) {
+ if (StreamIdx >= File.getNumStreams()) {
+ formatLine("Stream {0}: Not present", StreamIdx);
+ return;
+ }
+ if (Size + Offset > File.getStreamByteSize(StreamIdx)) {
+ formatLine(
+ "Stream {0}: Invalid offset and size, range out of stream bounds",
+ StreamIdx);
+ return;
+ }
+
+ auto S = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), StreamIdx, File.getAllocator());
+ if (!S) {
+ NewLine();
+ formatLine("Stream {0}: Not present", StreamIdx);
+ return;
+ }
+
+ uint32_t End =
+ (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
+ Size = End - Offset;
+
+ formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,
+ StreamPurpose, Size, S->getLength());
+ AutoIndent Indent(*this);
+ BinaryStreamRef Slice(*S);
+ BinarySubstreamRef Substream;
+ Substream.Offset = Offset;
+ Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);
+
+ auto Layout = File.getStreamLayout(StreamIdx);
+ formatMsfStreamData(Label, File, Layout, Substream);
+}
+
+void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinarySubstreamRef Substream) {
+ BinaryStreamReader Reader(Substream.StreamData);
+
+ auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
+
+ NewLine();
+ OS << Label << " (";
+ while (Reader.bytesRemaining() > 0) {
+ OS << "\n";
+
+ Run FoundRun;
+ uint32_t RunOffset;
+ std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);
+ assert(FoundRun.ByteLen >= RunOffset);
+ uint32_t Len = FoundRun.ByteLen - RunOffset;
+ Len = std::min(Len, Reader.bytesRemaining());
+ uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
+ ArrayRef<uint8_t> Data;
+ consumeError(Reader.readBytes(Data, Len));
+ OS << format_bytes_with_ascii(Data, Base, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ if (Reader.bytesRemaining() > 0) {
+ NewLine();
+ OS << formatv(" {0}",
+ fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
+ }
+ Substream.Offset += Len;
+ }
+ NewLine();
+ OS << ")";
+}
+
bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
return true;
diff --git a/tools/llvm-pdbutil/LinePrinter.h b/tools/llvm-pdbutil/LinePrinter.h
index f4fd22bcb6f4..68ce321a27ec 100644
--- a/tools/llvm-pdbutil/LinePrinter.h
+++ b/tools/llvm-pdbutil/LinePrinter.h
@@ -13,6 +13,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
@@ -20,9 +21,14 @@
#include <list>
namespace llvm {
+class BinaryStreamReader;
+namespace msf {
+class MSFStreamLayout;
+} // namespace msf
namespace pdb {
class ClassLayout;
+class PDBFile;
class LinePrinter {
friend class WithColor;
@@ -45,6 +51,15 @@ public:
void formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
uint32_t StartOffset);
+ void formatBinary(StringRef Label, ArrayRef<uint8_t> Data, uint64_t BaseAddr,
+ uint32_t StartOffset);
+
+ void formatMsfStreamData(StringRef Label, PDBFile &File, uint32_t StreamIdx,
+ StringRef StreamPurpose, uint32_t Offset,
+ uint32_t Size);
+ void formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinarySubstreamRef Substream);
bool hasColor() const { return UseColor; }
raw_ostream &getStream() { return OS; }
diff --git a/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
index 8b36de0b7157..7f5412d59885 100644
--- a/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
+++ b/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
@@ -146,6 +146,19 @@ static std::string formatFrameProcedureOptions(uint32_t IndentLevel,
return typesetItemList(Opts, 4, IndentLevel, " | ");
}
+static std::string formatPublicSymFlags(uint32_t IndentLevel,
+ PublicSymFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == PublicSymFlags::None)
+ return "none";
+
+ PUSH_FLAG(PublicSymFlags, Code, Flags, "code");
+ PUSH_FLAG(PublicSymFlags, Function, Flags, "function");
+ PUSH_FLAG(PublicSymFlags, Managed, Flags, "managed");
+ PUSH_FLAG(PublicSymFlags, MSIL, Flags, "msil");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
static std::string formatProcSymFlags(uint32_t IndentLevel,
ProcSymFlags Flags) {
std::vector<std::string> Opts;
@@ -659,7 +672,8 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
PublicSym32 &Public) {
P.format(" `{0}`", Public.Name);
AutoIndent Indent(P);
- P.formatLine("type = {0}, addr = {1}", typeIndex(Public.Index),
+ P.formatLine("flags = {0}, addr = {1}",
+ formatPublicSymFlags(P.getIndentLevel() + 9, Public.Flags),
formatSegmentOffset(Public.Segment, Public.Offset));
return Error::success();
}
diff --git a/tools/llvm-pdbutil/llvm-pdbutil.cpp b/tools/llvm-pdbutil/llvm-pdbutil.cpp
index 9088783876e0..4a176fb13590 100644
--- a/tools/llvm-pdbutil/llvm-pdbutil.cpp
+++ b/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -14,7 +14,9 @@
#include "llvm-pdbutil.h"
#include "Analyze.h"
+#include "BytesOutputStyle.h"
#include "Diff.h"
+#include "DumpOutputStyle.h"
#include "LinePrinter.h"
#include "OutputStyle.h"
#include "PrettyCompilandDumper.h"
@@ -22,7 +24,6 @@
#include "PrettyFunctionDumper.h"
#include "PrettyTypeDumper.h"
#include "PrettyVariableDumper.h"
-#include "RawOutputStyle.h"
#include "YAMLOutputStyle.h"
#include "llvm/ADT/ArrayRef.h"
@@ -86,7 +87,9 @@ using namespace llvm::pdb;
namespace opts {
-cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file");
+cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info");
+cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from the PDB file");
+
cl::SubCommand
PrettySubcommand("pretty",
"Dump semantic information about types and symbols");
@@ -111,6 +114,31 @@ cl::OptionCategory TypeCategory("Symbol Type Options");
cl::OptionCategory FilterCategory("Filtering and Sorting Options");
cl::OptionCategory OtherOptions("Other Options");
+cl::ValuesClass ChunkValues = cl::values(
+ clEnumValN(ModuleSubsection::CrossScopeExports, "cme",
+ "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
+ clEnumValN(ModuleSubsection::CrossScopeImports, "cmi",
+ "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
+ clEnumValN(ModuleSubsection::FileChecksums, "fc",
+ "File checksums (DEBUG_S_CHECKSUMS subsection)"),
+ clEnumValN(ModuleSubsection::InlineeLines, "ilines",
+ "Inlinee lines (DEBUG_S_INLINEELINES subsection)"),
+ clEnumValN(ModuleSubsection::Lines, "lines",
+ "Lines (DEBUG_S_LINES subsection)"),
+ clEnumValN(ModuleSubsection::StringTable, "strings",
+ "String Table (DEBUG_S_STRINGTABLE subsection) (not "
+ "typically present in PDB file)"),
+ clEnumValN(ModuleSubsection::FrameData, "frames",
+ "Frame Data (DEBUG_S_FRAMEDATA subsection)"),
+ clEnumValN(ModuleSubsection::Symbols, "symbols",
+ "Symbols (DEBUG_S_SYMBOLS subsection) (not typically "
+ "present in PDB file)"),
+ clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas",
+ "COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"),
+ clEnumValN(ModuleSubsection::Unknown, "unknown",
+ "Any subsection not covered by another option"),
+ clEnumValN(ModuleSubsection::All, "all", "All known subsections"));
+
namespace pretty {
cl::list<std::string> InputFilenames(cl::Positional,
cl::desc("<input PDB files>"),
@@ -256,11 +284,6 @@ cl::opt<bool> NoEnumDefs("no-enum-definitions",
}
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));
@@ -268,7 +291,83 @@ cl::list<std::string> InputFilenames(cl::Positional,
cl::OptionCategory FileOptions("Module & File Options");
-namespace raw {
+namespace bytes {
+cl::OptionCategory MsfBytes("MSF File Options");
+cl::OptionCategory DbiBytes("Dbi Stream Options");
+cl::OptionCategory PdbBytes("PDB Stream Options");
+cl::OptionCategory Types("Type Options");
+cl::OptionCategory ModuleCategory("Module Options");
+
+llvm::Optional<NumberRange> DumpBlockRange;
+llvm::Optional<NumberRange> DumpByteRange;
+
+cl::opt<std::string> DumpBlockRangeOpt(
+ "block-range", cl::value_desc("start[-end]"),
+ cl::desc("Dump binary data from specified range of blocks."),
+ cl::sub(BytesSubcommand), cl::cat(MsfBytes));
+
+cl::opt<std::string>
+ DumpByteRangeOpt("byte-range", cl::value_desc("start[-end]"),
+ cl::desc("Dump binary data from specified range of bytes"),
+ cl::sub(BytesSubcommand), cl::cat(MsfBytes));
+
+cl::list<std::string>
+ DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
+ cl::desc("Dump binary data from specified streams. Format "
+ "is SN[:Start][@Size]"),
+ cl::sub(BytesSubcommand), cl::cat(MsfBytes));
+
+cl::opt<bool> NameMap("name-map", cl::desc("Dump bytes of PDB Name Map"),
+ cl::sub(BytesSubcommand), cl::cat(PdbBytes));
+
+cl::opt<bool> SectionContributions("sc", cl::desc("Dump section contributions"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> SectionMap("sm", cl::desc("Dump section map"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> ModuleInfos("modi", cl::desc("Dump module info"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> FileInfo("files", cl::desc("Dump source file info"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> TypeServerMap("type-server", cl::desc("Dump type server map"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> ECData("ec", cl::desc("Dump edit and continue map"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+
+cl::list<uint32_t>
+ TypeIndex("type",
+ cl::desc("Dump the type record with the given type index"),
+ cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand),
+ cl::cat(TypeCategory));
+cl::list<uint32_t>
+ IdIndex("id", cl::desc("Dump the id record with the given type index"),
+ cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand),
+ cl::cat(TypeCategory));
+
+cl::opt<uint32_t> ModuleIndex(
+ "mod",
+ cl::desc(
+ "Limit options in the Modules category to the specified module index"),
+ cl::Optional, cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> ModuleSyms("syms", cl::desc("Dump symbol record substream"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> ModuleC11("c11-chunks", cl::Hidden,
+ cl::desc("Dump C11 CodeView debug chunks"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> ModuleC13("chunks",
+ cl::desc("Dump C13 CodeView debug chunk subsection"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> SplitChunks(
+ "split-chunks",
+ cl::desc(
+ "When dumping debug chunks, show a different section for each chunk"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore, cl::sub(BytesSubcommand));
+
+} // namespace bytes
+
+namespace dump {
cl::OptionCategory MsfOptions("MSF Container Options");
cl::OptionCategory TypeOptions("Type Record Options");
@@ -277,100 +376,103 @@ cl::OptionCategory MiscOptions("Miscellaneous Options");
// MSF OPTIONS
cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpStreams("streams",
cl::desc("dump summary of the PDB streams"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-cl::opt<std::string>
- DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
- cl::desc("Dump binary data from specified range."),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-llvm::Optional<BlockRange> DumpBlockRange;
-
-cl::list<std::string>
- DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
- cl::desc("Dump binary data from specified streams. Format "
- "is SN[:Start][@Size]"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpStreamBlocks(
+ "stream-blocks",
+ cl::desc("Add block information to the output of -streams"),
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
// TYPE OPTIONS
cl::opt<bool> DumpTypes("types",
cl::desc("dump CodeView type records from TPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpTypeData(
"type-data",
cl::desc("dump CodeView type record raw bytes from TPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpTypeExtras("type-extras",
cl::desc("dump type hashes and index offsets"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::list<uint32_t> DumpTypeIndex(
+ "type-index", cl::ZeroOrMore,
+ cl::desc("only dump types with the specified hexadecimal type index"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpIds("ids",
cl::desc("dump CodeView type records from IPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
cl::opt<bool>
DumpIdData("id-data",
cl::desc("dump CodeView type record raw bytes from IPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpIdExtras("id-extras",
cl::desc("dump id hashes and index offsets"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+cl::list<uint32_t> DumpIdIndex(
+ "id-index", cl::ZeroOrMore,
+ cl::desc("only dump ids with the specified hexadecimal type index"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
// SYMBOL OPTIONS
cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
- cl::cat(SymbolOptions), cl::sub(RawSubcommand));
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"),
- cl::cat(SymbolOptions), cl::sub(RawSubcommand));
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
cl::opt<bool>
DumpSymRecordBytes("sym-data",
cl::desc("dump CodeView symbol record raw bytes"),
- cl::cat(SymbolOptions), cl::sub(RawSubcommand));
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
// MODULE & FILE OPTIONS
cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
- cl::cat(FileOptions), cl::sub(RawSubcommand));
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpModuleFiles(
"files",
cl::desc("Dump the source files that contribute to each module's."),
- cl::cat(FileOptions), cl::sub(RawSubcommand));
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpLines(
"l",
cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"),
- cl::cat(FileOptions), cl::sub(RawSubcommand));
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpInlineeLines(
"il",
cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"),
- cl::cat(FileOptions), cl::sub(RawSubcommand));
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpXmi(
"xmi",
cl::desc(
"dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
- cl::cat(FileOptions), cl::sub(RawSubcommand));
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpXme(
"xme",
cl::desc(
"dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
- cl::cat(FileOptions), cl::sub(RawSubcommand));
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
// MISCELLANEOUS OPTIONS
cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
- cl::cat(MiscOptions), cl::sub(RawSubcommand));
+ cl::cat(MiscOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpSectionContribs("section-contribs",
cl::desc("dump section contributions"),
- cl::cat(MiscOptions), cl::sub(RawSubcommand));
+ cl::cat(MiscOptions),
+ cl::sub(DumpSubcommand));
cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
- cl::cat(MiscOptions), cl::sub(RawSubcommand));
+ cl::cat(MiscOptions), cl::sub(DumpSubcommand));
cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
- cl::cat(MiscOptions), cl::sub(RawSubcommand));
+ cl::cat(MiscOptions), cl::sub(DumpSubcommand));
cl::list<std::string> InputFilenames(cl::Positional,
cl::desc("<input PDB files>"),
- cl::OneOrMore, cl::sub(RawSubcommand));
+ cl::OneOrMore, cl::sub(DumpSubcommand));
}
namespace yaml2pdb {
@@ -429,33 +531,7 @@ cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
cl::sub(PdbToYamlSubcommand));
cl::list<ModuleSubsection> DumpModuleSubsections(
"subsections", cl::ZeroOrMore, cl::CommaSeparated,
- cl::desc("dump subsections from each module's debug stream"),
- cl::values(
- clEnumValN(
- ModuleSubsection::CrossScopeExports, "cme",
- "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
- clEnumValN(
- ModuleSubsection::CrossScopeImports, "cmi",
- "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
- clEnumValN(ModuleSubsection::FileChecksums, "fc",
- "File checksums (DEBUG_S_CHECKSUMS subsection)"),
- clEnumValN(ModuleSubsection::InlineeLines, "ilines",
- "Inlinee lines (DEBUG_S_INLINEELINES subsection)"),
- clEnumValN(ModuleSubsection::Lines, "lines",
- "Lines (DEBUG_S_LINES subsection)"),
- clEnumValN(ModuleSubsection::StringTable, "strings",
- "String Table (DEBUG_S_STRINGTABLE subsection) (not "
- "typically present in PDB file)"),
- clEnumValN(ModuleSubsection::FrameData, "frames",
- "Frame Data (DEBUG_S_FRAMEDATA subsection)"),
- clEnumValN(ModuleSubsection::Symbols, "symbols",
- "Symbols (DEBUG_S_SYMBOLS subsection) (not typically "
- "present in PDB file)"),
- clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas",
- "COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"),
- clEnumValN(ModuleSubsection::Unknown, "unknown",
- "Any subsection not covered by another option"),
- clEnumValN(ModuleSubsection::All, "all", "All known subsections")),
+ cl::desc("dump subsections from each module's debug stream"), ChunkValues,
cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
cl::cat(FileOptions),
@@ -616,7 +692,16 @@ static void dumpRaw(StringRef Path) {
std::unique_ptr<IPDBSession> Session;
auto &File = loadPDB(Path, Session);
- auto O = llvm::make_unique<RawOutputStyle>(File);
+ auto O = llvm::make_unique<DumpOutputStyle>(File);
+
+ ExitOnErr(O->dump());
+}
+
+static void dumpBytes(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ auto &File = loadPDB(Path, Session);
+
+ auto O = llvm::make_unique<BytesOutputStyle>(File);
ExitOnErr(O->dump());
}
@@ -877,6 +962,37 @@ static void mergePdbs() {
ExitOnErr(Builder.commit(OutFile));
}
+static bool parseRange(StringRef Str,
+ Optional<opts::bytes::NumberRange> &Parsed) {
+ if (Str.empty())
+ return true;
+
+ llvm::Regex R("^([^-]+)(-([^-]+))?$");
+ llvm::SmallVector<llvm::StringRef, 2> Matches;
+ if (!R.match(Str, &Matches))
+ return false;
+
+ Parsed.emplace();
+ if (!to_integer(Matches[1], Parsed->Min))
+ return false;
+
+ if (!Matches[3].empty()) {
+ Parsed->Max.emplace();
+ if (!to_integer(Matches[3], *Parsed->Max))
+ return false;
+ }
+ return true;
+}
+
+static void simplifyChunkList(llvm::cl::list<opts::ModuleSubsection> &Chunks) {
+ // If this list contains "All" plus some other stuff, remove the other stuff
+ // and just keep "All" in the list.
+ if (!llvm::is_contained(Chunks, opts::ModuleSubsection::All))
+ return;
+ Chunks.reset();
+ Chunks.push_back(opts::ModuleSubsection::All);
+}
+
int main(int argc_, const char *argv_[]) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal(argv_[0]);
@@ -892,43 +1008,45 @@ int main(int argc_, const char *argv_[]) {
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
- if (!opts::raw::DumpBlockRangeOpt.empty()) {
- llvm::Regex R("^([0-9]+)(-([0-9]+))?$");
- llvm::SmallVector<llvm::StringRef, 2> Matches;
- if (!R.match(opts::raw::DumpBlockRangeOpt, &Matches)) {
- errs() << "Argument '" << opts::raw::DumpBlockRangeOpt
+
+ if (opts::BytesSubcommand) {
+ if (!parseRange(opts::bytes::DumpBlockRangeOpt,
+ opts::bytes::DumpBlockRange)) {
+ errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
<< "' invalid format.\n";
errs().flush();
exit(1);
}
- opts::raw::DumpBlockRange.emplace();
- Matches[1].getAsInteger(10, opts::raw::DumpBlockRange->Min);
- if (!Matches[3].empty()) {
- opts::raw::DumpBlockRange->Max.emplace();
- Matches[3].getAsInteger(10, *opts::raw::DumpBlockRange->Max);
+ if (!parseRange(opts::bytes::DumpByteRangeOpt,
+ opts::bytes::DumpByteRange)) {
+ errs() << "Argument '" << opts::bytes::DumpByteRangeOpt
+ << "' invalid format.\n";
+ errs().flush();
+ exit(1);
}
}
- if (opts::RawSubcommand) {
- if (opts::raw::RawAll) {
- opts::raw::DumpLines = true;
- opts::raw::DumpInlineeLines = true;
- opts::raw::DumpXme = true;
- opts::raw::DumpXmi = true;
- opts::raw::DumpIds = true;
- opts::raw::DumpPublics = true;
- opts::raw::DumpSectionContribs = true;
- opts::raw::DumpSectionMap = true;
- opts::raw::DumpStreams = true;
- opts::raw::DumpStringTable = true;
- opts::raw::DumpSummary = true;
- opts::raw::DumpSymbols = true;
- opts::raw::DumpIds = true;
- opts::raw::DumpIdExtras = true;
- opts::raw::DumpTypes = true;
- opts::raw::DumpTypeExtras = true;
- opts::raw::DumpModules = true;
- opts::raw::DumpModuleFiles = true;
+ if (opts::DumpSubcommand) {
+ if (opts::dump::RawAll) {
+ opts::dump::DumpLines = true;
+ opts::dump::DumpInlineeLines = true;
+ opts::dump::DumpXme = true;
+ opts::dump::DumpXmi = true;
+ opts::dump::DumpIds = true;
+ opts::dump::DumpPublics = true;
+ opts::dump::DumpSectionContribs = true;
+ opts::dump::DumpSectionMap = true;
+ opts::dump::DumpStreams = true;
+ opts::dump::DumpStreamBlocks = true;
+ opts::dump::DumpStringTable = true;
+ opts::dump::DumpSummary = true;
+ opts::dump::DumpSymbols = true;
+ opts::dump::DumpIds = true;
+ opts::dump::DumpIdExtras = true;
+ opts::dump::DumpTypes = true;
+ opts::dump::DumpTypeExtras = true;
+ opts::dump::DumpModules = true;
+ opts::dump::DumpModuleFiles = true;
}
}
if (opts::PdbToYamlSubcommand) {
@@ -945,13 +1063,8 @@ int main(int argc_, const char *argv_[]) {
opts::pdb2yaml::DumpModuleSyms = true;
opts::pdb2yaml::DumpModuleSubsections.push_back(
opts::ModuleSubsection::All);
- if (llvm::is_contained(opts::pdb2yaml::DumpModuleSubsections,
- opts::ModuleSubsection::All)) {
- opts::pdb2yaml::DumpModuleSubsections.reset();
- opts::pdb2yaml::DumpModuleSubsections.push_back(
- opts::ModuleSubsection::All);
- }
}
+ simplifyChunkList(opts::pdb2yaml::DumpModuleSubsections);
if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles)
opts::pdb2yaml::DumpModules = true;
@@ -1010,9 +1123,12 @@ int main(int argc_, const char *argv_[]) {
}
std::for_each(opts::pretty::InputFilenames.begin(),
opts::pretty::InputFilenames.end(), dumpPretty);
- } else if (opts::RawSubcommand) {
- std::for_each(opts::raw::InputFilenames.begin(),
- opts::raw::InputFilenames.end(), dumpRaw);
+ } else if (opts::DumpSubcommand) {
+ std::for_each(opts::dump::InputFilenames.begin(),
+ opts::dump::InputFilenames.end(), dumpRaw);
+ } else if (opts::BytesSubcommand) {
+ std::for_each(opts::bytes::InputFilenames.begin(),
+ opts::bytes::InputFilenames.end(), dumpBytes);
} else if (opts::DiffSubcommand) {
if (opts::diff::InputFilenames.size() != 2) {
errs() << "diff subcommand expects exactly 2 arguments.\n";
diff --git a/tools/llvm-pdbutil/llvm-pdbutil.h b/tools/llvm-pdbutil/llvm-pdbutil.h
index a41b032d2b13..837d8ebbaf9e 100644
--- a/tools/llvm-pdbutil/llvm-pdbutil.h
+++ b/tools/llvm-pdbutil/llvm-pdbutil.h
@@ -92,16 +92,39 @@ extern llvm::cl::opt<ClassDefinitionFormat> ClassFormat;
extern llvm::cl::opt<uint32_t> ClassRecursionDepth;
}
-namespace raw {
-struct BlockRange {
- uint32_t Min;
- llvm::Optional<uint32_t> Max;
+namespace bytes {
+struct NumberRange {
+ uint64_t Min;
+ llvm::Optional<uint64_t> Max;
};
+extern llvm::Optional<NumberRange> DumpBlockRange;
+extern llvm::Optional<NumberRange> DumpByteRange;
+extern llvm::cl::list<std::string> DumpStreamData;
+extern llvm::cl::opt<bool> NameMap;
+
+extern llvm::cl::opt<bool> SectionContributions;
+extern llvm::cl::opt<bool> SectionMap;
+extern llvm::cl::opt<bool> ModuleInfos;
+extern llvm::cl::opt<bool> FileInfo;
+extern llvm::cl::opt<bool> TypeServerMap;
+extern llvm::cl::opt<bool> ECData;
+
+extern llvm::cl::list<uint32_t> TypeIndex;
+extern llvm::cl::list<uint32_t> IdIndex;
+
+extern llvm::cl::opt<uint32_t> ModuleIndex;
+extern llvm::cl::opt<bool> ModuleSyms;
+extern llvm::cl::opt<bool> ModuleC11;
+extern llvm::cl::opt<bool> ModuleC13;
+extern llvm::cl::opt<bool> SplitChunks;
+} // namespace bytes
+
+namespace dump {
+
extern llvm::cl::opt<bool> DumpSummary;
extern llvm::cl::opt<bool> DumpStreams;
-extern llvm::Optional<BlockRange> DumpBlockRange;
-extern llvm::cl::list<std::string> DumpStreamData;
+extern llvm::cl::opt<bool> DumpStreamBlocks;
extern llvm::cl::opt<bool> DumpLines;
extern llvm::cl::opt<bool> DumpInlineeLines;
@@ -111,9 +134,12 @@ extern llvm::cl::opt<bool> DumpStringTable;
extern llvm::cl::opt<bool> DumpTypes;
extern llvm::cl::opt<bool> DumpTypeData;
extern llvm::cl::opt<bool> DumpTypeExtras;
+extern llvm::cl::list<uint32_t> DumpTypeIndex;
+
extern llvm::cl::opt<bool> DumpIds;
extern llvm::cl::opt<bool> DumpIdData;
extern llvm::cl::opt<bool> DumpIdExtras;
+extern llvm::cl::list<uint32_t> DumpIdIndex;
extern llvm::cl::opt<bool> DumpSymbols;
extern llvm::cl::opt<bool> DumpSymRecordBytes;
extern llvm::cl::opt<bool> DumpPublics;
@@ -124,10 +150,6 @@ extern llvm::cl::opt<bool> DumpModuleFiles;
extern llvm::cl::opt<bool> RawAll;
}
-namespace diff {
-extern llvm::cl::opt<bool> Pedantic;
-}
-
namespace pdb2yaml {
extern llvm::cl::opt<bool> All;
extern llvm::cl::opt<bool> NoFileHeaders;
diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp
index 4867acf70983..e9bc2de82bdf 100644
--- a/tools/llvm-profdata/llvm-profdata.cpp
+++ b/tools/llvm-profdata/llvm-profdata.cpp
@@ -246,10 +246,12 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
exitWithError(std::move(WC->Err), WC->ErrWhence);
InstrProfWriter &Writer = Contexts[0]->Writer;
- if (OutputFormat == PF_Text)
- Writer.writeText(Output);
- else
+ if (OutputFormat == PF_Text) {
+ if (Error E = Writer.writeText(Output))
+ exitWithError(std::move(E));
+ } else {
Writer.write(Output);
+ }
}
static sampleprof::SampleProfileFormat FormatMap[] = {
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index 216c9adad9a7..daa7a643a72f 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -36,7 +36,6 @@
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
@@ -69,6 +68,14 @@ using namespace llvm::Win64EH;
namespace {
+struct LoadConfigTables {
+ uint64_t SEHTableVA = 0;
+ uint64_t SEHTableCount = 0;
+ uint32_t GuardFlags = 0;
+ uint64_t GuardFidTableVA = 0;
+ uint64_t GuardFidTableCount = 0;
+};
+
class COFFDumper : public ObjDumper {
public:
friend class COFFObjectDumpDelegate;
@@ -87,6 +94,7 @@ public:
void printCOFFBaseReloc() override;
void printCOFFDebugDirectory() override;
void printCOFFResources() override;
+ void printCOFFLoadConfig() override;
void printCodeViewDebugInfo() override;
void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
llvm::codeview::TypeTableBuilder &CVTypes) override;
@@ -101,6 +109,11 @@ private:
template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
void printBaseOfDataField(const pe32_header *Hdr);
void printBaseOfDataField(const pe32plus_header *Hdr);
+ template <typename T>
+ void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables);
+ typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *);
+ void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize,
+ PrintExtraCB PrintExtra = 0);
void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section);
void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section);
@@ -746,6 +759,129 @@ void COFFDumper::printCOFFDebugDirectory() {
}
}
+void COFFDumper::printRVATable(uint64_t TableVA, uint64_t Count,
+ uint64_t EntrySize, PrintExtraCB PrintExtra) {
+ uintptr_t TableStart, TableEnd;
+ error(Obj->getVaPtr(TableVA, TableStart));
+ error(Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd));
+ TableEnd++;
+ for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) {
+ uint32_t RVA = *reinterpret_cast<const ulittle32_t *>(I);
+ raw_ostream &OS = W.startLine();
+ OS << "0x" << utohexstr(Obj->getImageBase() + RVA);
+ if (PrintExtra)
+ PrintExtra(OS, reinterpret_cast<const uint8_t *>(I));
+ OS << '\n';
+ }
+}
+
+void COFFDumper::printCOFFLoadConfig() {
+ LoadConfigTables Tables;
+ if (Obj->is64())
+ printCOFFLoadConfig(Obj->getLoadConfig64(), Tables);
+ else
+ printCOFFLoadConfig(Obj->getLoadConfig32(), Tables);
+
+ if (Tables.SEHTableVA) {
+ ListScope LS(W, "SEHTable");
+ printRVATable(Tables.SEHTableVA, Tables.SEHTableCount, 4);
+ }
+
+ if (Tables.GuardFidTableVA) {
+ ListScope LS(W, "GuardFidTable");
+ if (Tables.GuardFlags & uint32_t(coff_guard_flags::FidTableHasFlags)) {
+ auto PrintGuardFlags = [](raw_ostream &OS, const uint8_t *Entry) {
+ uint8_t Flags = *reinterpret_cast<const uint8_t *>(Entry + 4);
+ if (Flags)
+ OS << " flags " << utohexstr(Flags);
+ };
+ printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 5,
+ PrintGuardFlags);
+ } else {
+ printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 4);
+ }
+ }
+}
+
+template <typename T>
+void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
+ if (!Conf)
+ return;
+
+ ListScope LS(W, "LoadConfig");
+ char FormattedTime[20] = {};
+ time_t TDS = Conf->TimeDateStamp;
+ strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+ W.printHex("Size", Conf->Size);
+
+ // Print everything before SecurityCookie. The vast majority of images today
+ // have all these fields.
+ if (Conf->Size < offsetof(T, SEHandlerTable))
+ return;
+ W.printHex("TimeDateStamp", FormattedTime, TDS);
+ W.printHex("MajorVersion", Conf->MajorVersion);
+ W.printHex("MinorVersion", Conf->MinorVersion);
+ W.printHex("GlobalFlagsClear", Conf->GlobalFlagsClear);
+ W.printHex("GlobalFlagsSet", Conf->GlobalFlagsSet);
+ W.printHex("CriticalSectionDefaultTimeout",
+ Conf->CriticalSectionDefaultTimeout);
+ W.printHex("DeCommitFreeBlockThreshold", Conf->DeCommitFreeBlockThreshold);
+ W.printHex("DeCommitTotalFreeThreshold", Conf->DeCommitTotalFreeThreshold);
+ W.printHex("LockPrefixTable", Conf->LockPrefixTable);
+ W.printHex("MaximumAllocationSize", Conf->MaximumAllocationSize);
+ W.printHex("VirtualMemoryThreshold", Conf->VirtualMemoryThreshold);
+ W.printHex("ProcessHeapFlags", Conf->ProcessHeapFlags);
+ W.printHex("ProcessAffinityMask", Conf->ProcessAffinityMask);
+ W.printHex("CSDVersion", Conf->CSDVersion);
+ W.printHex("DependentLoadFlags", Conf->DependentLoadFlags);
+ W.printHex("EditList", Conf->EditList);
+ W.printHex("SecurityCookie", Conf->SecurityCookie);
+
+ // Print the safe SEH table if present.
+ if (Conf->Size < offsetof(coff_load_configuration32, GuardCFCheckFunction))
+ return;
+ W.printHex("SEHandlerTable", Conf->SEHandlerTable);
+ W.printNumber("SEHandlerCount", Conf->SEHandlerCount);
+
+ Tables.SEHTableVA = Conf->SEHandlerTable;
+ Tables.SEHTableCount = Conf->SEHandlerCount;
+
+ // Print everything before CodeIntegrity. (2015)
+ if (Conf->Size < offsetof(T, CodeIntegrity))
+ return;
+ W.printHex("GuardCFCheckFunction", Conf->GuardCFCheckFunction);
+ W.printHex("GuardCFCheckDispatch", Conf->GuardCFCheckDispatch);
+ W.printHex("GuardCFFunctionTable", Conf->GuardCFFunctionTable);
+ W.printNumber("GuardCFFunctionCount", Conf->GuardCFFunctionCount);
+ W.printHex("GuardFlags", Conf->GuardFlags);
+
+ Tables.GuardFidTableVA = Conf->GuardCFFunctionTable;
+ Tables.GuardFidTableCount = Conf->GuardCFFunctionCount;
+ Tables.GuardFlags = Conf->GuardFlags;
+
+ // Print the rest. (2017)
+ if (Conf->Size < sizeof(T))
+ return;
+ W.printHex("GuardAddressTakenIatEntryTable",
+ Conf->GuardAddressTakenIatEntryTable);
+ W.printNumber("GuardAddressTakenIatEntryCount",
+ Conf->GuardAddressTakenIatEntryCount);
+ W.printHex("GuardLongJumpTargetTable", Conf->GuardLongJumpTargetTable);
+ W.printNumber("GuardLongJumpTargetCount", Conf->GuardLongJumpTargetCount);
+ W.printHex("DynamicValueRelocTable", Conf->DynamicValueRelocTable);
+ W.printHex("CHPEMetadataPointer", Conf->CHPEMetadataPointer);
+ W.printHex("GuardRFFailureRoutine", Conf->GuardRFFailureRoutine);
+ W.printHex("GuardRFFailureRoutineFunctionPointer",
+ Conf->GuardRFFailureRoutineFunctionPointer);
+ W.printHex("DynamicValueRelocTableOffset",
+ Conf->DynamicValueRelocTableOffset);
+ W.printNumber("DynamicValueRelocTableSection",
+ Conf->DynamicValueRelocTableSection);
+ W.printHex("GuardRFVerifyStackPointerFunctionPointer",
+ Conf->GuardRFVerifyStackPointerFunctionPointer);
+ W.printHex("HotPatchTableOffset", Conf->HotPatchTableOffset);
+}
+
void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
W.printHex("BaseOfData", Hdr->BaseOfData);
}
@@ -1100,7 +1236,7 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
if (Magic != COFF::DEBUG_SECTION_MAGIC)
return error(object_error::parse_failed);
- Types.reset(Data);
+ Types.reset(Data, 100);
TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes);
error(codeview::visitTypeStream(Types, TDV));
diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h
index 48f825c527c1..43883c2d2176 100644
--- a/tools/llvm-readobj/ObjDumper.h
+++ b/tools/llvm-readobj/ObjDumper.h
@@ -68,6 +68,7 @@ public:
virtual void printCOFFBaseReloc() { }
virtual void printCOFFDebugDirectory() { }
virtual void printCOFFResources() {}
+ virtual void printCOFFLoadConfig() { }
virtual void printCodeViewDebugInfo() { }
virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
llvm::codeview::TypeTableBuilder &CVTypes) {}
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index cd7244a8f970..51991a3f067b 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -218,6 +218,11 @@ namespace opts {
cl::opt<bool> COFFResources("coff-resources",
cl::desc("Display the PE/COFF .rsrc section"));
+ // -coff-load-config
+ cl::opt<bool>
+ COFFLoadConfig("coff-load-config",
+ cl::desc("Display the PE/COFF load config"));
+
// -macho-data-in-code
cl::opt<bool>
MachODataInCode("macho-data-in-code",
@@ -444,6 +449,8 @@ static void dumpObject(const ObjectFile *Obj) {
Dumper->printCOFFDebugDirectory();
if (opts::COFFResources)
Dumper->printCOFFResources();
+ if (opts::COFFLoadConfig)
+ Dumper->printCOFFLoadConfig();
if (opts::CodeView)
Dumper->printCodeViewDebugInfo();
if (opts::CodeViewMergedTypes)
diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp
index 0ed7adb46ddc..3cf8b37bc2e2 100644
--- a/tools/llvm-stress/llvm-stress.cpp
+++ b/tools/llvm-stress/llvm-stress.cpp
@@ -96,17 +96,13 @@ public:
return Seed & 0x7ffff;
}
- /// Return a random 32 bit integer.
- uint32_t Rand32() {
- uint32_t Val = Rand();
- Val &= 0xffff;
- return Val | (Rand() << 16);
- }
-
/// Return a random 64 bit integer.
uint64_t Rand64() {
- uint64_t Val = Rand32();
- return Val | (uint64_t(Rand32()) << 32);
+ uint64_t Val = Rand() & 0xffff;
+ Val |= uint64_t(Rand() & 0xffff) << 16;
+ Val |= uint64_t(Rand() & 0xffff) << 32;
+ Val |= uint64_t(Rand() & 0xffff) << 48;
+ return Val;
}
/// Rand operator for STL algorithms.
@@ -116,10 +112,14 @@ public:
/// 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; }
-
+ uint32_t operator()() {
+ uint32_t Val = Rand();
+ assert(Val <= max() && "Random value out of range");
+ return Val;
+ }
+
private:
unsigned Seed;
};
@@ -168,19 +168,24 @@ public:
}
protected:
+ /// Return a random integer.
+ uint32_t getRandom() {
+ return Ran->Rand();
+ }
+
/// Return a random value from the list of known values.
Value *getRandomVal() {
assert(PT->size());
- return PT->at(Ran->Rand() % PT->size());
+ return PT->at(getRandom() % PT->size());
}
Constant *getRandomConstant(Type *Tp) {
if (Tp->isIntegerTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return ConstantInt::getAllOnesValue(Tp);
return ConstantInt::getNullValue(Tp);
} else if (Tp->isFloatingPointTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return ConstantFP::getAllOnesValue(Tp);
return ConstantFP::getNullValue(Tp);
}
@@ -189,7 +194,7 @@ protected:
/// Return a random value with a known type.
Value *getRandomValue(Type *Tp) {
- unsigned index = Ran->Rand();
+ unsigned index = getRandom();
for (unsigned i=0; i<PT->size(); ++i) {
Value *V = PT->at((index + i) % PT->size());
if (V->getType() == Tp)
@@ -198,11 +203,11 @@ protected:
// If the requested type was not found, generate a constant value.
if (Tp->isIntegerTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return ConstantInt::getAllOnesValue(Tp);
return ConstantInt::getNullValue(Tp);
} else if (Tp->isFloatingPointTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return ConstantFP::getAllOnesValue(Tp);
return ConstantFP::getNullValue(Tp);
} else if (Tp->isVectorTy()) {
@@ -222,7 +227,7 @@ protected:
/// Return a random value of any pointer type.
Value *getRandomPointerValue() {
- unsigned index = Ran->Rand();
+ unsigned index = getRandom();
for (unsigned i=0; i<PT->size(); ++i) {
Value *V = PT->at((index + i) % PT->size());
if (V->getType()->isPointerTy())
@@ -233,7 +238,7 @@ protected:
/// Return a random value of any vector type.
Value *getRandomVectorValue() {
- unsigned index = Ran->Rand();
+ unsigned index = getRandom();
for (unsigned i=0; i<PT->size(); ++i) {
Value *V = PT->at((index + i) % PT->size());
if (V->getType()->isVectorTy())
@@ -244,7 +249,7 @@ protected:
/// Pick a random type.
Type *pickType() {
- return (Ran->Rand() & 1 ? pickVectorType() : pickScalarType());
+ return (getRandom() & 1 ? pickVectorType() : pickScalarType());
}
/// Pick a random pointer type.
@@ -258,7 +263,7 @@ protected:
// Pick a random vector width in the range 2**0 to 2**4.
// by adding two randoms we are generating a normal-like distribution
// around 2**3.
- unsigned width = 1<<((Ran->Rand() % 3) + (Ran->Rand() % 3));
+ unsigned width = 1<<((getRandom() % 3) + (getRandom() % 3));
Type *Ty;
// Vectors of x86mmx are illegal; keep trying till we get something else.
@@ -288,7 +293,7 @@ protected:
AdditionalScalarTypes.begin(), AdditionalScalarTypes.end());
}
- return ScalarTypes[Ran->Rand() % ScalarTypes.size()];
+ return ScalarTypes[getRandom() % ScalarTypes.size()];
}
/// Basic block to populate
@@ -348,7 +353,7 @@ struct BinModifier: public Modifier {
bool isFloat = Val0->getType()->getScalarType()->isFloatingPointTy();
Instruction* Term = BB->getTerminator();
- unsigned R = Ran->Rand() % (isFloat ? 7 : 13);
+ unsigned R = getRandom() % (isFloat ? 7 : 13);
Instruction::BinaryOps Op;
switch (R) {
@@ -379,7 +384,7 @@ struct ConstModifier: public Modifier {
Type *Ty = pickType();
if (Ty->isVectorTy()) {
- switch (Ran->Rand() % 2) {
+ switch (getRandom() % 2) {
case 0: if (Ty->getScalarType()->isIntegerTy())
return PT->push_back(ConstantVector::getAllOnesValue(Ty));
break;
@@ -398,25 +403,27 @@ struct ConstModifier: public Modifier {
APInt RandomInt(Ty->getPrimitiveSizeInBits(), makeArrayRef(RandomBits));
APFloat RandomFloat(Ty->getFltSemantics(), RandomInt);
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return PT->push_back(ConstantFP::getNullValue(Ty));
return PT->push_back(ConstantFP::get(Ty->getContext(), RandomFloat));
}
if (Ty->isIntegerTy()) {
- switch (Ran->Rand() % 7) {
+ switch (getRandom() % 7) {
case 0:
return PT->push_back(ConstantInt::get(
Ty, APInt::getAllOnesValue(Ty->getPrimitiveSizeInBits())));
case 1:
return PT->push_back(ConstantInt::get(
Ty, APInt::getNullValue(Ty->getPrimitiveSizeInBits())));
- case 2: case 3: case 4: case 5:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
case 6:
- PT->push_back(ConstantInt::get(Ty, Ran->Rand()));
+ PT->push_back(ConstantInt::get(Ty, getRandom()));
}
}
-
}
};
@@ -439,7 +446,7 @@ struct ExtractElementModifier: public Modifier {
Value *Val0 = getRandomVectorValue();
Value *V = ExtractElementInst::Create(Val0,
ConstantInt::get(Type::getInt32Ty(BB->getContext()),
- Ran->Rand() % cast<VectorType>(Val0->getType())->getNumElements()),
+ getRandom() % cast<VectorType>(Val0->getType())->getNumElements()),
"E", BB->getTerminator());
return PT->push_back(V);
}
@@ -457,9 +464,9 @@ struct ShuffModifier: public Modifier {
Type *I32 = Type::getInt32Ty(BB->getContext());
for (unsigned i=0; i<Width; ++i) {
- Constant *CI = ConstantInt::get(I32, Ran->Rand() % (Width*2));
+ Constant *CI = ConstantInt::get(I32, getRandom() % (Width*2));
// Pick some undef values.
- if (!(Ran->Rand() % 5))
+ if (!(getRandom() % 5))
CI = UndefValue::get(I32);
Idxs.push_back(CI);
}
@@ -482,7 +489,7 @@ struct InsertElementModifier: public Modifier {
Value *V = InsertElementInst::Create(Val0, Val1,
ConstantInt::get(Type::getInt32Ty(BB->getContext()),
- Ran->Rand() % cast<VectorType>(Val0->getType())->getNumElements()),
+ getRandom() % cast<VectorType>(Val0->getType())->getNumElements()),
"I", BB->getTerminator());
return PT->push_back(V);
}
@@ -518,7 +525,7 @@ struct CastModifier: public Modifier {
unsigned DestSize = DestTy->getScalarType()->getPrimitiveSizeInBits();
// Generate lots of bitcasts.
- if ((Ran->Rand() & 1) && VSize == DestSize) {
+ if ((getRandom() & 1) && VSize == DestSize) {
return PT->push_back(
new BitCastInst(V, DestTy, "BC", BB->getTerminator()));
}
@@ -531,7 +538,7 @@ struct CastModifier: public Modifier {
new TruncInst(V, DestTy, "Tr", BB->getTerminator()));
} else {
assert(VSize < DestSize && "Different int types with the same size?");
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return PT->push_back(
new ZExtInst(V, DestTy, "ZE", BB->getTerminator()));
return PT->push_back(new SExtInst(V, DestTy, "Se", BB->getTerminator()));
@@ -541,7 +548,7 @@ struct CastModifier: public Modifier {
// Fp to int.
if (VTy->getScalarType()->isFloatingPointTy() &&
DestTy->getScalarType()->isIntegerTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return PT->push_back(
new FPToSIInst(V, DestTy, "FC", BB->getTerminator()));
return PT->push_back(new FPToUIInst(V, DestTy, "FC", BB->getTerminator()));
@@ -550,7 +557,7 @@ struct CastModifier: public Modifier {
// Int to fp.
if (VTy->getScalarType()->isIntegerTy() &&
DestTy->getScalarType()->isFloatingPointTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return PT->push_back(
new SIToFPInst(V, DestTy, "FC", BB->getTerminator()));
return PT->push_back(new UIToFPInst(V, DestTy, "FC", BB->getTerminator()));
@@ -587,7 +594,7 @@ struct SelectModifier: public Modifier {
// If the value type is a vector, and we allow vector select, then in 50%
// of the cases generate a vector select.
- if (Val0->getType()->isVectorTy() && (Ran->Rand() % 1)) {
+ if (Val0->getType()->isVectorTy() && (getRandom() % 1)) {
unsigned NumElem = cast<VectorType>(Val0->getType())->getNumElements();
CondTy = VectorType::get(CondTy, NumElem);
}
@@ -611,11 +618,11 @@ struct CmpModifier: public Modifier {
int op;
if (fp) {
- op = Ran->Rand() %
+ op = getRandom() %
(CmpInst::LAST_FCMP_PREDICATE - CmpInst::FIRST_FCMP_PREDICATE) +
CmpInst::FIRST_FCMP_PREDICATE;
} else {
- op = Ran->Rand() %
+ op = getRandom() %
(CmpInst::LAST_ICMP_PREDICATE - CmpInst::FIRST_ICMP_PREDICATE) +
CmpInst::FIRST_ICMP_PREDICATE;
}
diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp
index 31712af26362..8bf09c2164bf 100644
--- a/tools/obj2yaml/obj2yaml.cpp
+++ b/tools/obj2yaml/obj2yaml.cpp
@@ -30,21 +30,32 @@ static std::error_code dumpObject(const ObjectFile &Obj) {
return obj2yaml_error::unsupported_obj_file_format;
}
-static std::error_code dumpInput(StringRef File) {
+static Error dumpInput(StringRef File) {
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
if (!BinaryOrErr)
- return errorToErrorCode(BinaryOrErr.takeError());
+ return BinaryOrErr.takeError();
Binary &Binary = *BinaryOrErr.get().getBinary();
// Universal MachO is not a subclass of ObjectFile, so it needs to be handled
// here with the other binary types.
if (Binary.isMachO() || Binary.isMachOUniversalBinary())
- return macho2yaml(outs(), Binary);
+ return errorCodeToError(macho2yaml(outs(), Binary));
// TODO: If this is an archive, then burst it and dump each entry
if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
- return dumpObject(*Obj);
+ return errorCodeToError(dumpObject(*Obj));
- return obj2yaml_error::unrecognized_file_format;
+ return Error::success();
+}
+
+static void reportError(StringRef Input, Error Err) {
+ if (Input == "-")
+ Input = "<stdin>";
+ std::string ErrMsg;
+ raw_string_ostream OS(ErrMsg);
+ logAllUnhandledErrors(std::move(Err), OS, "");
+ OS.flush();
+ errs() << "Error reading file: " << Input << ": " << ErrMsg;
+ errs().flush();
}
cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"),
@@ -56,8 +67,8 @@ int main(int argc, char *argv[]) {
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
- if (std::error_code EC = dumpInput(InputFilename)) {
- errs() << "Error: '" << EC.message() << "'\n";
+ if (Error Err = dumpInput(InputFilename)) {
+ reportError(InputFilename, std::move(Err));
return 1;
}
diff --git a/tools/obj2yaml/wasm2yaml.cpp b/tools/obj2yaml/wasm2yaml.cpp
index d4d978f028e2..ad0075caac1d 100644
--- a/tools/obj2yaml/wasm2yaml.cpp
+++ b/tools/obj2yaml/wasm2yaml.cpp
@@ -14,6 +14,7 @@
#include "llvm/Support/YAMLTraits.h"
using namespace llvm;
+using object::WasmSection;
namespace {
@@ -22,10 +23,16 @@ class WasmDumper {
public:
WasmDumper(const object::WasmObjectFile &O) : Obj(O) {}
+
ErrorOr<WasmYAML::Object *> dump();
+
+ std::unique_ptr<WasmYAML::CustomSection>
+ dumpCustomSection(const WasmSection &WasmSec);
};
-WasmYAML::Table make_table(const wasm::WasmTable &Table) {
+} // namespace
+
+static WasmYAML::Table make_table(const wasm::WasmTable &Table) {
WasmYAML::Table T;
T.ElemType = Table.ElemType;
T.TableLimits.Flags = Table.Limits.Flags;
@@ -34,7 +41,7 @@ WasmYAML::Table make_table(const wasm::WasmTable &Table) {
return T;
}
-WasmYAML::Limits make_limits(const wasm::WasmLimits &Limits) {
+static WasmYAML::Limits make_limits(const wasm::WasmLimits &Limits) {
WasmYAML::Limits L;
L.Flags = Limits.Flags;
L.Initial = Limits.Initial;
@@ -42,6 +49,42 @@ WasmYAML::Limits make_limits(const wasm::WasmLimits &Limits) {
return L;
}
+std::unique_ptr<WasmYAML::CustomSection> WasmDumper::dumpCustomSection(const WasmSection &WasmSec) {
+ std::unique_ptr<WasmYAML::CustomSection> CustomSec;
+ if (WasmSec.Name == "name") {
+ std::unique_ptr<WasmYAML::NameSection> NameSec = make_unique<WasmYAML::NameSection>();
+ for (const object::SymbolRef& Sym: Obj.symbols()) {
+ uint32_t Flags = Sym.getFlags();
+ // Skip over symbols that come from imports or exports
+ if (Flags &
+ (object::SymbolRef::SF_Global | object::SymbolRef::SF_Undefined))
+ continue;
+ Expected<StringRef> NameOrError = Sym.getName();
+ if (!NameOrError)
+ continue;
+ WasmYAML::NameEntry NameEntry;
+ NameEntry.Name = *NameOrError;
+ NameEntry.Index = Sym.getValue();
+ NameSec->FunctionNames.push_back(NameEntry);
+ }
+ CustomSec = std::move(NameSec);
+ } else if (WasmSec.Name == "linking") {
+ std::unique_ptr<WasmYAML::LinkingSection> LinkingSec = make_unique<WasmYAML::LinkingSection>();
+ for (const object::SymbolRef& Sym: Obj.symbols()) {
+ const object::WasmSymbol Symbol = Obj.getWasmSymbol(Sym);
+ if (Symbol.Flags != 0) {
+ WasmYAML::SymbolInfo Info = { Symbol.Name, Symbol.Flags };
+ LinkingSec->SymbolInfos.push_back(Info);
+ }
+ }
+ CustomSec = std::move(LinkingSec);
+ } else {
+ CustomSec = make_unique<WasmYAML::CustomSection>(WasmSec.Name);
+ }
+ CustomSec->Payload = yaml::BinaryRef(WasmSec.Content);
+ return CustomSec;
+}
+
ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
auto Y = make_unique<WasmYAML::Object>();
@@ -50,7 +93,7 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
// Dump sections
for (const auto &Sec : Obj.sections()) {
- const object::WasmSection &WasmSec = Obj.getWasmSection(Sec);
+ const WasmSection &WasmSec = Obj.getWasmSection(Sec);
std::unique_ptr<WasmYAML::Section> S;
switch (WasmSec.Type) {
case wasm::WASM_SEC_CUSTOM: {
@@ -59,27 +102,7 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
// being represented as a custom section in the YAML output.
continue;
}
- auto CustomSec = make_unique<WasmYAML::CustomSection>();
- CustomSec->Name = WasmSec.Name;
- if (CustomSec->Name == "name") {
- for (const object::SymbolRef& Sym: Obj.symbols()) {
- uint32_t Flags = Sym.getFlags();
- // Skip over symbols that come from imports or exports
- if (Flags &
- (object::SymbolRef::SF_Global | object::SymbolRef::SF_Undefined))
- continue;
- Expected<StringRef> NameOrError = Sym.getName();
- if (!NameOrError)
- continue;
- WasmYAML::NameEntry NameEntry;
- NameEntry.Name = *NameOrError;
- NameEntry.Index = Sym.getValue();
- CustomSec->FunctionNames.push_back(NameEntry);
- }
- } else {
- CustomSec->Payload = yaml::BinaryRef(WasmSec.Content);
- }
- S = std::move(CustomSec);
+ S = dumpCustomSection(WasmSec);
break;
}
case wasm::WASM_SEC_TYPE: {
@@ -237,8 +260,6 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
return Y.release();
}
-} // namespace
-
std::error_code wasm2yaml(raw_ostream &Out, const object::WasmObjectFile &Obj) {
WasmDumper Dumper(Obj);
ErrorOr<WasmYAML::Object *> YAMLOrErr = Dumper.dump();
diff --git a/tools/yaml2obj/yaml2wasm.cpp b/tools/yaml2obj/yaml2wasm.cpp
index 5c8aba33ee80..cf591e16317c 100644
--- a/tools/yaml2obj/yaml2wasm.cpp
+++ b/tools/yaml2obj/yaml2wasm.cpp
@@ -26,8 +26,9 @@ class WasmWriter {
public:
WasmWriter(WasmYAML::Object &Obj) : Obj(Obj) {}
int writeWasm(raw_ostream &OS);
+
+private:
int writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec);
- int writeNameSection(raw_ostream &OS, WasmYAML::CustomSection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::TypeSection &Section);
@@ -42,7 +43,9 @@ public:
int writeSectionContent(raw_ostream &OS, WasmYAML::CodeSection &Section);
int writeSectionContent(raw_ostream &OS, WasmYAML::DataSection &Section);
-private:
+ // Custom section types
+ int writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section);
WasmYAML::Object &Obj;
};
@@ -107,12 +110,30 @@ static int writeInitExpr(const wasm::WasmInitExpr &InitExpr, raw_ostream &OS) {
return 0;
}
-int WasmWriter::writeNameSection(raw_ostream &OS,
- WasmYAML::CustomSection &Section) {
+int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section) {
+ writeStringRef(Section.Name, OS);
+ if (Section.SymbolInfos.size()) {
+ encodeULEB128(wasm::WASM_SYMBOL_INFO, OS);
+ std::string OutString;
+ raw_string_ostream StringStream(OutString);
+
+ encodeULEB128(Section.SymbolInfos.size(), StringStream);
+ for (const WasmYAML::SymbolInfo &Info : Section.SymbolInfos) {
+ writeStringRef(Info.Name, StringStream);
+ encodeULEB128(Info.Flags, StringStream);
+ }
+
+ StringStream.flush();
+ encodeULEB128(OutString.size(), OS);
+ OS << OutString;
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section) {
writeStringRef(Section.Name, OS);
if (Section.FunctionNames.size()) {
encodeULEB128(wasm::WASM_NAMES_FUNCTION, OS);
-
std::string OutString;
raw_string_ostream StringStream(OutString);
@@ -131,8 +152,12 @@ int WasmWriter::writeNameSection(raw_ostream &OS,
int WasmWriter::writeSectionContent(raw_ostream &OS,
WasmYAML::CustomSection &Section) {
- if (Section.Name == "name") {
- writeNameSection(OS, Section);
+ if (auto S = dyn_cast<WasmYAML::NameSection>(&Section)) {
+ if (auto Err = writeSectionContent(OS, *S))
+ return Err;
+ } else if (auto S = dyn_cast<WasmYAML::LinkingSection>(&Section)) {
+ if (auto Err = writeSectionContent(OS, *S))
+ return Err;
} else {
Section.Payload.writeAsBinary(OS);
}