diff options
-rw-r--r-- | llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h | 2 | ||||
-rw-r--r-- | llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h | 20 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp | 22 | ||||
-rw-r--r-- | llvm/test/tools/llvm-pdbdump/explain-dbi-stream.test | 207 | ||||
-rw-r--r-- | llvm/test/tools/llvm-pdbdump/explain-pdb-stream.test | 46 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp | 200 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbutil/ExplainOutputStyle.h | 4 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbutil/StreamUtil.cpp | 81 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbutil/StreamUtil.h | 15 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp | 12 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbutil/llvm-pdbutil.h | 2 |
11 files changed, 538 insertions, 73 deletions
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h b/llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h index 4be113f28d6..760d19ac3f8 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h @@ -63,6 +63,8 @@ public: PDB_Machine getMachineType() const; + const DbiStreamHeader *getHeader() const { return Header; } + BinarySubstreamRef getSectionContributionData() const; BinarySubstreamRef getSecMapSubstreamData() const; BinarySubstreamRef getModiSubstreamData() const; diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h b/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h index 499d2d6e2ea..caeb423af72 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h @@ -36,6 +36,8 @@ public: uint32_t getStreamSize() const; + const InfoStreamHeader *getHeader() const { return Header; } + bool containsIdStream() const; PdbRaw_ImplVer getVersion() const; uint32_t getSignature() const; @@ -56,23 +58,7 @@ public: private: std::unique_ptr<msf::MappedBlockStream> Stream; - // PDB file format version. We only support VC70. See the enumeration - // `PdbRaw_ImplVer` for the other possible values. - uint32_t Version; - - // A 32-bit signature unique across all PDBs. This is generated with - // a call to time() when the PDB is written, but obviously this is not - // universally unique. - uint32_t Signature; - - // The number of times the PDB has been written. Might also be used to - // ensure that the PDB matches the executable. - uint32_t Age; - - // Due to the aforementioned limitations with `Signature`, this is a new - // signature present on VC70 and higher PDBs which is guaranteed to be - // universally unique. - codeview::GUID Guid; + const InfoStreamHeader *Header; BinarySubstreamRef SubNamedStreams; diff --git a/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp b/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp index b4f217abf85..e9ae5a1a193 100644 --- a/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -21,19 +21,18 @@ using namespace llvm::msf; using namespace llvm::pdb; InfoStream::InfoStream(std::unique_ptr<MappedBlockStream> Stream) - : Stream(std::move(Stream)) {} + : Stream(std::move(Stream)), Header(nullptr) {} Error InfoStream::reload() { BinaryStreamReader Reader(*Stream); - const InfoStreamHeader *H; - if (auto EC = Reader.readObject(H)) + if (auto EC = Reader.readObject(Header)) return joinErrors( std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "PDB Stream does not contain a header.")); - switch (H->Version) { + switch (Header->Version) { case PdbImplVC70: case PdbImplVC80: case PdbImplVC110: @@ -44,11 +43,6 @@ Error InfoStream::reload() { "Unsupported PDB stream version."); } - Version = H->Version; - Signature = H->Signature; - Age = H->Age; - Guid = H->Guid; - uint32_t Offset = Reader.getOffset(); if (auto EC = NamedStreams.load(Reader)) return EC; @@ -108,14 +102,16 @@ bool InfoStream::containsIdStream() const { } PdbRaw_ImplVer InfoStream::getVersion() const { - return static_cast<PdbRaw_ImplVer>(Version); + return static_cast<PdbRaw_ImplVer>(uint32_t(Header->Version)); } -uint32_t InfoStream::getSignature() const { return Signature; } +uint32_t InfoStream::getSignature() const { + return uint32_t(Header->Signature); +} -uint32_t InfoStream::getAge() const { return Age; } +uint32_t InfoStream::getAge() const { return uint32_t(Header->Age); } -GUID InfoStream::getGuid() const { return Guid; } +GUID InfoStream::getGuid() const { return Header->Guid; } uint32_t InfoStream::getNamedStreamMapByteSize() const { return NamedStreamMapByteSize; diff --git a/llvm/test/tools/llvm-pdbdump/explain-dbi-stream.test b/llvm/test/tools/llvm-pdbdump/explain-dbi-stream.test new file mode 100644 index 00000000000..f393f976caa --- /dev/null +++ b/llvm/test/tools/llvm-pdbdump/explain-dbi-stream.test @@ -0,0 +1,207 @@ +; RUN: llvm-pdbutil explain \ +; RUN: -offset=0xF000 \ +; RUN: -offset=0xF004 \ +; RUN: -offset=0xF008 \ +; RUN: -offset=0xF00C \ +; RUN: -offset=0xF00E \ +; RUN: -offset=0xF010 \ +; RUN: -offset=0xF012 \ +; RUN: -offset=0xF014 \ +; RUN: -offset=0xF016 \ +; RUN: -offset=0xF018 \ +; RUN: -offset=0xF01C \ +; RUN: -offset=0xF020 \ +; RUN: -offset=0xF024 \ +; RUN: -offset=0xF028 \ +; RUN: -offset=0xF02C \ +; RUN: -offset=0xF030 \ +; RUN: -offset=0xF034 \ +; RUN: -offset=0xF038 \ +; RUN: -offset=0xF03A \ +; RUN: -offset=0xF03C \ +; RUN: -offset=0xF03E \ +; RUN: -offset=0xF040 \ +; RUN: -offset=0xF0DC \ +; RUN: %p/Inputs/InjectedSource.pdb | FileCheck %s + +CHECK: Block:Offset = F:0000. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 0/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 0/64 of the DBI Stream Header. +CHECK-NEXT: which contains the DBI Stream Version Signature. +CHECK-NEXT: The current value is -1. + +CHECK: Block:Offset = F:0004. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 4/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 4/64 of the DBI Stream Header. +CHECK-NEXT: which contains the DBI Stream Version Header. +CHECK-NEXT: The current value is 19990903. + +CHECK: Block:Offset = F:0008. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 8/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 8/64 of the DBI Stream Header. +CHECK-NEXT: which contains the age of the DBI Stream. +CHECK-NEXT: The current value is 1. + +CHECK: Block:Offset = F:000C. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 12/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 12/64 of the DBI Stream Header. +CHECK-NEXT: which contains the index of the Global Symbol Stream. +CHECK-NEXT: The current value is 7. + +CHECK: Block:Offset = F:000E. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 14/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 14/64 of the DBI Stream Header. +CHECK-NEXT: which contains the build number. +CHECK-NEXT: The current value is 36363. + +CHECK: Block:Offset = F:0010. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 16/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 16/64 of the DBI Stream Header. +CHECK-NEXT: which contains the index of the Public Symbol Stream. +CHECK-NEXT: The current value is 8. + +CHECK: Block:Offset = F:0012. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 18/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 18/64 of the DBI Stream Header. +CHECK-NEXT: which contains the version of mspdb.dll. +CHECK-NEXT: The current value is 25547. + +CHECK: Block:Offset = F:0014. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 20/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 20/64 of the DBI Stream Header. +CHECK-NEXT: which contains the index of the Symbol Record Stream. +CHECK-NEXT: The current value is 9. + +CHECK: Block:Offset = F:0016. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 22/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 22/64 of the DBI Stream Header. +CHECK-NEXT: which contains the rbld of mspdb.dll. +CHECK-NEXT: The current value is 0. + +CHECK: Block:Offset = F:0018. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 24/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 24/64 of the DBI Stream Header. +CHECK-NEXT: which contains the size of the Module Info Substream. +CHECK-NEXT: The current value is 232. + +CHECK: Block:Offset = F:001C. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 28/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 28/64 of the DBI Stream Header. +CHECK-NEXT: which contains the size of the Section Contribution Substream. +CHECK-NEXT: The current value is 172. + +CHECK: Block:Offset = F:0020. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 32/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 32/64 of the DBI Stream Header. +CHECK-NEXT: which contains the size of the Section Map Substream. +CHECK-NEXT: The current value is 84. + +CHECK: Block:Offset = F:0024. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 36/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 36/64 of the DBI Stream Header. +CHECK-NEXT: which contains the size of the File Info Substream. +CHECK-NEXT: The current value is 132. + +CHECK: Block:Offset = F:0028. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 40/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 40/64 of the DBI Stream Header. +CHECK-NEXT: which contains the size of the Type Server Map. +CHECK-NEXT: The current value is 0. + +CHECK: Block:Offset = F:002C. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 44/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 44/64 of the DBI Stream Header. +CHECK-NEXT: which contains the index of the MFC Type Server stream. +CHECK-NEXT: The current value is 0. + +CHECK: Block:Offset = F:0030. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 48/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 48/64 of the DBI Stream Header. +CHECK-NEXT: which contains the size of the Optional Debug Stream array. +CHECK-NEXT: The current value is 22. + +CHECK: Block:Offset = F:0034. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 52/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 52/64 of the DBI Stream Header. +CHECK-NEXT: which contains the size of the Edit & Continue Substream. +CHECK-NEXT: The current value is 75. + +CHECK: Block:Offset = F:0038. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 56/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 56/64 of the DBI Stream Header. +CHECK-NEXT: which contains the DBI Stream flags. +CHECK-NEXT: The current value is 0. + +CHECK: Block:Offset = F:003A. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 58/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 58/64 of the DBI Stream Header. +CHECK-NEXT: which contains the machine type. +CHECK-NEXT: The current value is 34404. + +CHECK: Block:Offset = F:003C. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 60/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 60/64 of the DBI Stream Header. +CHECK-NEXT: which contains reserved data. +CHECK-NEXT: The current value is 0. + +CHECK: Block:Offset = F:003E. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 62/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 62/64 of the DBI Stream Header. +CHECK-NEXT: which contains reserved data. +CHECK-NEXT: The current value is 0. + +CHECK: Block:Offset = F:0040. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 64/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 0/232 of the Module Info Substream. +CHECK-NEXT: which contains the descriptor for module 0 (D:\sandbox\nvtest\nvtest\x64\Debug\nvtest.obj). + +CHECK: Block:Offset = F:00DC. +CHECK-NEXT: Address is in block 15 (allocated). +CHECK-NEXT: Address is at offset 220/781 of Stream 3 (DBI Stream). +CHECK-NEXT: Within the DBI stream: +CHECK-NEXT: address is at offset 156/232 of the Module Info Substream. +CHECK-NEXT: which contains the descriptor for module 1 (* Linker *). diff --git a/llvm/test/tools/llvm-pdbdump/explain-pdb-stream.test b/llvm/test/tools/llvm-pdbdump/explain-pdb-stream.test new file mode 100644 index 00000000000..10efb5b6459 --- /dev/null +++ b/llvm/test/tools/llvm-pdbdump/explain-pdb-stream.test @@ -0,0 +1,46 @@ +; RUN: llvm-pdbutil explain \ +; RUN: -offset=0x11000 \ +; RUN: -offset=0x11004 \ +; RUN: -offset=0x11008 \ +; RUN: -offset=0x1100C \ +; RUN: -offset=0x1101C \ +; RUN: %p/Inputs/InjectedSource.pdb | FileCheck %s + + +CHECK: Block:Offset = 11:0000. +CHECK-NEXT: Address is in block 17 (allocated). +CHECK-NEXT: Address is at offset 0/202 of Stream 1 (PDB Stream). +CHECK-NEXT: Within the PDB stream: +CHECK-NEXT: address is at offset 0/28 of the PDB Stream Header. +CHECK-NEXT: which contains the PDB Stream Version Signature. +CHECK-NEXT: The current value is 20000404. + +CHECK: Block:Offset = 11:0004. +CHECK-NEXT: Address is in block 17 (allocated). +CHECK-NEXT: Address is at offset 4/202 of Stream 1 (PDB Stream). +CHECK-NEXT: Within the PDB stream: +CHECK-NEXT: address is at offset 4/28 of the PDB Stream Header. +CHECK-NEXT: which contains the signature of the PDB Stream. +CHECK-NEXT: The current value is 1521153653. + +CHECK: Block:Offset = 11:0008. +CHECK-NEXT: Address is in block 17 (allocated). +CHECK-NEXT: Address is at offset 8/202 of Stream 1 (PDB Stream). +CHECK-NEXT: Within the PDB stream: +CHECK-NEXT: address is at offset 8/28 of the PDB Stream Header. +CHECK-NEXT: which contains the age of the PDB. +CHECK-NEXT: The current value is 1. + +CHECK: Block:Offset = 11:000C. +CHECK-NEXT: Address is in block 17 (allocated). +CHECK-NEXT: Address is at offset 12/202 of Stream 1 (PDB Stream). +CHECK-NEXT: Within the PDB stream: +CHECK-NEXT: address is at offset 12/28 of the PDB Stream Header. +CHECK-NEXT: which contains the guid of the PDB. +CHECK-NEXT: The current value is {826BE46E-02ED-7043-9C27-20CCC07E92A7}. + +CHECK: Block:Offset = 11:001C. +CHECK-NEXT: Address is in block 17 (allocated). +CHECK-NEXT: Address is at offset 28/202 of Stream 1 (PDB Stream). +CHECK-NEXT: Within the PDB stream: +CHECK-NEXT: address is at offset 0/166 of the Named Stream Map. diff --git a/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp b/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp index c4fbde22e75..70deb2e7277 100644 --- a/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp +++ b/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp @@ -13,8 +13,14 @@ #include "StreamUtil.h" #include "llvm-pdbutil.h" +#include "llvm/DebugInfo/CodeView/Formatters.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/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/Error.h" using namespace llvm; using namespace llvm::codeview; @@ -201,6 +207,20 @@ void ExplainOutputStyle::explainStreamOffset(uint32_t Stream) { P.formatLine("Address is at offset {0}/{1} of Stream {2} ({3}){4}.", StreamOff, Layout.Length, Stream, S.getLongName(), (StreamOff > Layout.Length) ? " in unused space" : ""); + switch (S.getPurpose()) { + case StreamPurpose::DBI: + explainDbiStream(Stream, StreamOff); + break; + case StreamPurpose::PDB: + explainPdbStream(Stream, StreamOff); + break; + case StreamPurpose::IPI: + case StreamPurpose::TPI: + case StreamPurpose::ModuleStream: + case StreamPurpose::NamedStream: + default: + break; + } } void ExplainOutputStyle::explainStreamDirectoryOffset() { @@ -218,3 +238,183 @@ void ExplainOutputStyle::explainStreamDirectoryOffset() { void ExplainOutputStyle::explainUnknownBlock() { P.formatLine("Address has unknown purpose."); } + +template <typename T> +static void printStructField(LinePrinter &P, StringRef Label, T Value) { + P.formatLine("which contains {0}.", Label); + P.formatLine("The current value is {0}.", Value); +} + +static void explainDbiHeaderOffset(LinePrinter &P, DbiStream &Dbi, + uint32_t Offset) { + const DbiStreamHeader *Header = Dbi.getHeader(); + assert(Header != nullptr); + + if (Offset < endof(DbiStreamHeader, VersionSignature)) + printStructField(P, "the DBI Stream Version Signature", + int32_t(Header->VersionSignature)); + else if (Offset < endof(DbiStreamHeader, VersionHeader)) + printStructField(P, "the DBI Stream Version Header", + uint32_t(Header->VersionHeader)); + else if (Offset < endof(DbiStreamHeader, Age)) + printStructField(P, "the age of the DBI Stream", uint32_t(Header->Age)); + else if (Offset < endof(DbiStreamHeader, GlobalSymbolStreamIndex)) + printStructField(P, "the index of the Global Symbol Stream", + uint16_t(Header->GlobalSymbolStreamIndex)); + else if (Offset < endof(DbiStreamHeader, BuildNumber)) + printStructField(P, "the build number", uint16_t(Header->BuildNumber)); + else if (Offset < endof(DbiStreamHeader, PublicSymbolStreamIndex)) + printStructField(P, "the index of the Public Symbol Stream", + uint16_t(Header->PublicSymbolStreamIndex)); + else if (Offset < endof(DbiStreamHeader, PdbDllVersion)) + printStructField(P, "the version of mspdb.dll", + uint16_t(Header->PdbDllVersion)); + else if (Offset < endof(DbiStreamHeader, SymRecordStreamIndex)) + printStructField(P, "the index of the Symbol Record Stream", + uint16_t(Header->SymRecordStreamIndex)); + else if (Offset < endof(DbiStreamHeader, PdbDllRbld)) + printStructField(P, "the rbld of mspdb.dll", uint16_t(Header->PdbDllRbld)); + else if (Offset < endof(DbiStreamHeader, ModiSubstreamSize)) + printStructField(P, "the size of the Module Info Substream", + int32_t(Header->ModiSubstreamSize)); + else if (Offset < endof(DbiStreamHeader, SecContrSubstreamSize)) + printStructField(P, "the size of the Section Contribution Substream", + int32_t(Header->SecContrSubstreamSize)); + else if (Offset < endof(DbiStreamHeader, SectionMapSize)) + printStructField(P, "the size of the Section Map Substream", + int32_t(Header->SectionMapSize)); + else if (Offset < endof(DbiStreamHeader, FileInfoSize)) + printStructField(P, "the size of the File Info Substream", + int32_t(Header->FileInfoSize)); + else if (Offset < endof(DbiStreamHeader, TypeServerSize)) + printStructField(P, "the size of the Type Server Map", + int32_t(Header->TypeServerSize)); + else if (Offset < endof(DbiStreamHeader, MFCTypeServerIndex)) + printStructField(P, "the index of the MFC Type Server stream", + uint32_t(Header->MFCTypeServerIndex)); + else if (Offset < endof(DbiStreamHeader, OptionalDbgHdrSize)) + printStructField(P, "the size of the Optional Debug Stream array", + int32_t(Header->OptionalDbgHdrSize)); + else if (Offset < endof(DbiStreamHeader, ECSubstreamSize)) + printStructField(P, "the size of the Edit & Continue Substream", + int32_t(Header->ECSubstreamSize)); + else if (Offset < endof(DbiStreamHeader, Flags)) + printStructField(P, "the DBI Stream flags", uint16_t(Header->Flags)); + else if (Offset < endof(DbiStreamHeader, MachineType)) + printStructField(P, "the machine type", uint16_t(Header->MachineType)); + else if (Offset < endof(DbiStreamHeader, Reserved)) + printStructField(P, "reserved data", uint32_t(Header->Reserved)); +} + +static void explainDbiModiSubstreamOffset(LinePrinter &P, DbiStream &Dbi, + uint32_t Offset) { + VarStreamArray<DbiModuleDescriptor> ModuleDescriptors; + BinaryStreamRef ModiSubstreamData = Dbi.getModiSubstreamData().StreamData; + BinaryStreamReader Reader(ModiSubstreamData); + + cantFail(Reader.readArray(ModuleDescriptors, ModiSubstreamData.getLength())); + auto Prev = ModuleDescriptors.begin(); + assert(Prev.offset() == 0); + auto Current = Prev; + uint32_t Index = 0; + while (true) { + Prev = Current; + ++Current; + if (Current == ModuleDescriptors.end() || Offset < Current.offset()) + break; + ++Index; + } + + DbiModuleDescriptor &Descriptor = *Prev; + P.formatLine("which contains the descriptor for module {0} ({1}).", Index, + Descriptor.getModuleName()); +} + +template <typename T> +static void dontExplain(LinePrinter &Printer, T &Stream, uint32_t Offset) {} + +template <typename T, typename SubstreamRangeT> +static void explainSubstreamOffset(LinePrinter &P, uint32_t OffsetInStream, + T &Stream, + const SubstreamRangeT &Substreams) { + uint32_t SubOffset = OffsetInStream; + for (const auto &Entry : Substreams) { + if (Entry.Size == 0) + continue; + if (SubOffset < Entry.Size) { + P.formatLine("address is at offset {0}/{1} of the {2}.", SubOffset, + Entry.Size, Entry.Label); + Entry.Explain(P, Stream, SubOffset); + return; + } + SubOffset -= Entry.Size; + } +} + +void ExplainOutputStyle::explainDbiStream(uint32_t StreamIdx, + uint32_t OffsetInStream) { + P.printLine("Within the DBI stream:"); + DbiStream &Dbi = cantFail(File.getPDBDbiStream()); + AutoIndent Indent(P); + const DbiStreamHeader *Header = Dbi.getHeader(); + assert(Header != nullptr); + + struct SubstreamInfo { + uint32_t Size; + StringRef Label; + void (*Explain)(LinePrinter &, DbiStream &, uint32_t); + } Substreams[] = { + {sizeof(DbiStreamHeader), "DBI Stream Header", explainDbiHeaderOffset}, + {Header->ModiSubstreamSize, "Module Info Substream", + explainDbiModiSubstreamOffset}, + {Header->SecContrSubstreamSize, "Section Contribution Substream", + dontExplain<DbiStream>}, + {Header->SectionMapSize, "Section Map", dontExplain<DbiStream>}, + {Header->FileInfoSize, "File Info Substream", dontExplain<DbiStream>}, + {Header->TypeServerSize, "Type Server Map Substream", + dontExplain<DbiStream>}, + {Header->ECSubstreamSize, "Edit & Continue Substream", + dontExplain<DbiStream>}, + {Header->OptionalDbgHdrSize, "Optional Debug Stream Array", + dontExplain<DbiStream>}, + }; + + explainSubstreamOffset(P, OffsetInStream, Dbi, Substreams); +} + +static void explainPdbStreamHeaderOffset(LinePrinter &P, InfoStream &Info, + uint32_t Offset) { + const InfoStreamHeader *Header = Info.getHeader(); + assert(Header != nullptr); + + if (Offset < endof(InfoStreamHeader, Version)) + printStructField(P, "the PDB Stream Version Signature", + uint32_t(Header->Version)); + else if (Offset < endof(InfoStreamHeader, Signature)) + printStructField(P, "the signature of the PDB Stream", + uint32_t(Header->Signature)); + else if (Offset < endof(InfoStreamHeader, Age)) + printStructField(P, "the age of the PDB", uint32_t(Header->Age)); + else if (Offset < endof(InfoStreamHeader, Guid)) + printStructField(P, "the guid of the PDB", fmt_guid(Header->Guid.Guid)); +} + +void ExplainOutputStyle::explainPdbStream(uint32_t StreamIdx, + uint32_t OffsetInStream) { + P.printLine("Within the PDB stream:"); + InfoStream &Info = cantFail(File.getPDBInfoStream()); + AutoIndent Indent(P); + + struct SubstreamInfo { + uint32_t Size; + StringRef Label; + void (*Explain)(LinePrinter &, InfoStream &, uint32_t); + } Substreams[] = {{sizeof(InfoStreamHeader), "PDB Stream Header", + explainPdbStreamHeaderOffset}, + {Info.getNamedStreamMapByteSize(), "Named Stream Map", + dontExplain<InfoStream>}, + {Info.getStreamSize(), "PDB Feature Signatures", + dontExplain<InfoStream>}}; + + explainSubstreamOffset(P, OffsetInStream, Info, Substreams); +} diff --git a/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h b/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h index 386f6156a89..383007b84c5 100644 --- a/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h +++ b/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h @@ -19,6 +19,7 @@ namespace llvm { namespace pdb { +class DbiStream; class PDBFile; class ExplainOutputStyle : public OutputStyle { @@ -47,6 +48,9 @@ private: void explainStreamOffset(uint32_t Stream); void explainUnknownBlock(); + void explainDbiStream(uint32_t StreamIdx, uint32_t OffsetInStream); + void explainPdbStream(uint32_t StreamIdx, uint32_t OffsetInStream); + PDBFile &File; const uint64_t FileOffset; const uint64_t BlockIndex; diff --git a/llvm/tools/llvm-pdbutil/StreamUtil.cpp b/llvm/tools/llvm-pdbutil/StreamUtil.cpp index 991c99aa868..367d947d25e 100644 --- a/llvm/tools/llvm-pdbutil/StreamUtil.cpp +++ b/llvm/tools/llvm-pdbutil/StreamUtil.cpp @@ -49,16 +49,9 @@ StreamInfo StreamInfo::createModuleStream(StringRef Module, return Result; } -static inline StreamInfo otherStream(StringRef Label, uint32_t Idx) { - return StreamInfo::createStream(StreamPurpose::Other, Label, Idx); -} - -static inline StreamInfo namedStream(StringRef Label, uint32_t Idx) { - return StreamInfo::createStream(StreamPurpose::NamedStream, Label, Idx); -} - -static inline StreamInfo symbolStream(StringRef Label, uint32_t Idx) { - return StreamInfo::createStream(StreamPurpose::Symbols, Label, Idx); +static inline StreamInfo stream(StreamPurpose Purpose, StringRef Label, + uint32_t Idx) { + return StreamInfo::createStream(Purpose, Label, Idx); } static inline StreamInfo moduleStream(StringRef Label, uint32_t StreamIdx, @@ -105,60 +98,75 @@ void llvm::pdb::discoverStreamPurposes(PDBFile &File, Streams.resize(StreamCount); for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { if (StreamIdx == OldMSFDirectory) - Streams[StreamIdx] = otherStream("Old MSF Directory", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Old MSF Directory", StreamIdx); else if (StreamIdx == StreamPDB) - Streams[StreamIdx] = otherStream("PDB Stream", StreamIdx); + Streams[StreamIdx] = stream(StreamPurpose::PDB, "PDB Stream", StreamIdx); else if (StreamIdx == StreamDBI) - Streams[StreamIdx] = otherStream("DBI Stream", StreamIdx); + Streams[StreamIdx] = stream(StreamPurpose::DBI, "DBI Stream", StreamIdx); else if (StreamIdx == StreamTPI) - Streams[StreamIdx] = otherStream("TPI Stream", StreamIdx); + Streams[StreamIdx] = stream(StreamPurpose::TPI, "TPI Stream", StreamIdx); else if (StreamIdx == StreamIPI) - Streams[StreamIdx] = otherStream("IPI Stream", StreamIdx); + Streams[StreamIdx] = stream(StreamPurpose::IPI, "IPI Stream", StreamIdx); else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex()) - Streams[StreamIdx] = otherStream("Global Symbol Hash", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::GlobalHash, "Global Symbol Hash", StreamIdx); else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex()) - Streams[StreamIdx] = otherStream("Public Symbol Hash", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::PublicHash, "Public Symbol Hash", StreamIdx); else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex()) - Streams[StreamIdx] = symbolStream("Symbol Records", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Symbols, "Symbol Records", StreamIdx); else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex()) - Streams[StreamIdx] = otherStream("TPI Hash", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::TpiHash, "TPI Hash", StreamIdx); else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex()) - Streams[StreamIdx] = otherStream("TPI Aux Hash", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "TPI Aux Hash", StreamIdx); else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex()) - Streams[StreamIdx] = otherStream("IPI Hash", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::IpiHash, "IPI Hash", StreamIdx); else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex()) - Streams[StreamIdx] = otherStream("IPI Aux Hash", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "IPI Aux Hash", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception)) - Streams[StreamIdx] = otherStream("Exception Data", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Exception Data", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup)) - Streams[StreamIdx] = otherStream("Fixup Data", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Fixup Data", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO)) - Streams[StreamIdx] = otherStream("FPO Data", StreamIdx); + Streams[StreamIdx] = stream(StreamPurpose::Other, "FPO Data", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO)) - Streams[StreamIdx] = otherStream("New FPO Data", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "New FPO Data", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc)) - Streams[StreamIdx] = otherStream("Omap From Source Data", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Omap From Source Data", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc)) - Streams[StreamIdx] = otherStream("Omap To Source Data", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Omap To Source Data", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata)) - Streams[StreamIdx] = otherStream("Pdata", StreamIdx); + Streams[StreamIdx] = stream(StreamPurpose::Other, "Pdata", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr)) - Streams[StreamIdx] = otherStream("Section Header Data", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Section Header Data", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig)) - Streams[StreamIdx] = - otherStream("Section Header Original Data", StreamIdx); + Streams[StreamIdx] = stream(StreamPurpose::Other, + "Section Header Original Data", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap)) - Streams[StreamIdx] = otherStream("Token Rid Data", StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Token Rid Data", StreamIdx); else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata)) - Streams[StreamIdx] = otherStream("Xdata", StreamIdx); + Streams[StreamIdx] = stream(StreamPurpose::Other, "Xdata", StreamIdx); else { auto ModIter = ModStreams.find(StreamIdx); auto NSIter = NamedStreams.find(StreamIdx); @@ -167,9 +175,10 @@ void llvm::pdb::discoverStreamPurposes(PDBFile &File, moduleStream(ModIter->second.Descriptor.getModuleName(), StreamIdx, ModIter->second.Modi); } else if (NSIter != NamedStreams.end()) { - Streams[StreamIdx] = namedStream(NSIter->second, StreamIdx); + Streams[StreamIdx] = + stream(StreamPurpose::NamedStream, NSIter->second, StreamIdx); } else { - Streams[StreamIdx] = otherStream("???", StreamIdx); + Streams[StreamIdx] = stream(StreamPurpose::Other, "???", StreamIdx); } } } diff --git a/llvm/tools/llvm-pdbutil/StreamUtil.h b/llvm/tools/llvm-pdbutil/StreamUtil.h index 443267ca329..0e2e8070736 100644 --- a/llvm/tools/llvm-pdbutil/StreamUtil.h +++ b/llvm/tools/llvm-pdbutil/StreamUtil.h @@ -19,7 +19,20 @@ namespace llvm { namespace pdb { class PDBFile; -enum class StreamPurpose { NamedStream, ModuleStream, Symbols, Other }; +enum class StreamPurpose { + NamedStream, + ModuleStream, + Symbols, + PDB, + DBI, + TPI, + IPI, + GlobalHash, + PublicHash, + TpiHash, + IpiHash, + Other +}; struct StreamInfo { public: diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp index f472bfa5fa3..c96761f3ead 100644 --- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -615,9 +615,8 @@ cl::list<std::string> InputFilename(cl::Positional, cl::desc("<input PDB file>"), cl::Required, cl::sub(ExplainSubcommand)); -cl::opt<uint64_t> Offset("offset", cl::desc("The file offset to explain"), - cl::sub(ExplainSubcommand), cl::Required, - cl::OneOrMore); +cl::list<uint64_t> Offsets("offset", cl::desc("The file offset to explain"), + cl::sub(ExplainSubcommand), cl::OneOrMore); } // namespace explain } @@ -1091,9 +1090,12 @@ static void mergePdbs() { static void explain() { std::unique_ptr<IPDBSession> Session; PDBFile &File = loadPDB(opts::explain::InputFilename.front(), Session); - auto O = llvm::make_unique<ExplainOutputStyle>(File, opts::explain::Offset); - ExitOnErr(O->dump()); + for (uint64_t Off : opts::explain::Offsets) { + auto O = llvm::make_unique<ExplainOutputStyle>(File, Off); + + ExitOnErr(O->dump()); + } } static bool parseRange(StringRef Str, diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h index 6765b93146f..e7ad269444e 100644 --- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h +++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h @@ -191,7 +191,7 @@ extern llvm::cl::opt<bool> DumpModuleSyms; namespace explain { extern llvm::cl::list<std::string> InputFilename; -extern llvm::cl::opt<uint64_t> Offset; +extern llvm::cl::list<uint64_t> Offsets; } // namespace explain } |