mirror of
https://github.com/RPCS3/llvm.git
synced 2025-02-20 18:52:46 +00:00
[llvm-pdbutil] Dig deeper into the PDB and DBI streams when explaining.
This will show more detail when using `llvm-pdbutil explain` on an offset in the DBI or PDB streams. Specifically, it will dig into individual header fields and substreams to give a more precise description of what the byte represents. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@328878 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
97f19f4b51
commit
21ff13f9ff
@ -63,6 +63,8 @@ public:
|
||||
|
||||
PDB_Machine getMachineType() const;
|
||||
|
||||
const DbiStreamHeader *getHeader() const { return Header; }
|
||||
|
||||
BinarySubstreamRef getSectionContributionData() const;
|
||||
BinarySubstreamRef getSecMapSubstreamData() const;
|
||||
BinarySubstreamRef getModiSubstreamData() const;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
207
test/tools/llvm-pdbdump/explain-dbi-stream.test
Normal file
207
test/tools/llvm-pdbdump/explain-dbi-stream.test
Normal file
@ -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 *).
|
46
test/tools/llvm-pdbdump/explain-pdb-stream.test
Normal file
46
test/tools/llvm-pdbdump/explain-pdb-stream.test
Normal file
@ -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.
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user