diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-06-26 20:32:52 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-06-26 20:32:52 +0000 |
commit | 08bbd35a80bf7765fe0d3043f9eb5a2f2786b649 (patch) | |
tree | 80108f0f128657f8623f8f66ad9735b4d88e7b47 /tools | |
parent | 7c7aba6e5fef47a01a136be655b0a92cfd7090f6 (diff) | |
download | src-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')
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); } |