Skip to content

Commit 29da5db

Browse files
author
Zachary Turner
committed
[pdb] Correctly parse the hash adjusters table from TPI stream.
This is not a list of pairs, it is a hash table data structure. We now correctly parse this out and dump it from llvm-pdbdump. We still need to understand the conditions that lead to a type getting an entry in the hash adjuster table. That will be done in a followup investigation / patch. Differential Revision: https://reviews.llvm.org/D29090 llvm-svn: 293090
1 parent 6ec3b46 commit 29da5db

File tree

4 files changed

+95
-77
lines changed

4 files changed

+95
-77
lines changed

llvm/include/llvm/DebugInfo/PDB/Raw/TpiStream.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
1414
#include "llvm/DebugInfo/MSF/StreamArray.h"
1515
#include "llvm/DebugInfo/PDB/PDBTypes.h"
16+
#include "llvm/DebugInfo/PDB/Raw/HashTable.h"
1617
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
1718
#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
1819
#include "llvm/Support/raw_ostream.h"
@@ -47,7 +48,7 @@ class TpiStream {
4748
uint32_t NumHashBuckets() const;
4849
msf::FixedStreamArray<support::ulittle32_t> getHashValues() const;
4950
msf::FixedStreamArray<TypeIndexOffset> getTypeIndexOffsets() const;
50-
msf::FixedStreamArray<TypeIndexOffset> getHashAdjustments() const;
51+
HashTable &getHashAdjusters();
5152

5253
iterator_range<codeview::CVTypeArray::Iterator> types(bool *HadError) const;
5354

@@ -64,7 +65,7 @@ class TpiStream {
6465
std::unique_ptr<msf::ReadableStream> HashStream;
6566
msf::FixedStreamArray<support::ulittle32_t> HashValues;
6667
msf::FixedStreamArray<TypeIndexOffset> TypeIndexOffsets;
67-
msf::FixedStreamArray<TypeIndexOffset> HashAdjustments;
68+
HashTable HashAdjusters;
6869

6970
const TpiStreamHeader *Header;
7071
};

llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ Error TpiStream::reload() {
113113
if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
114114
return EC;
115115

116-
HSR.setOffset(Header->HashAdjBuffer.Off);
117-
uint32_t NumHashAdjustments =
118-
Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset);
119-
if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments))
120-
return EC;
116+
if (Header->HashAdjBuffer.Length > 0) {
117+
HSR.setOffset(Header->HashAdjBuffer.Off);
118+
if (auto EC = HashAdjusters.load(HSR))
119+
return EC;
120+
}
121121

122122
HashStream = std::move(HS);
123123

@@ -164,10 +164,7 @@ TpiStream::getTypeIndexOffsets() const {
164164
return TypeIndexOffsets;
165165
}
166166

167-
FixedStreamArray<TypeIndexOffset>
168-
TpiStream::getHashAdjustments() const {
169-
return HashAdjustments;
170-
}
167+
HashTable &TpiStream::getHashAdjusters() { return HashAdjusters; }
171168

172169
iterator_range<CVTypeArray::Iterator>
173170
TpiStream::types(bool *HadError) const {

llvm/test/DebugInfo/PDB/pdbdump-headers.test

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,11 @@
152152
; EMPTY-NEXT: Number of Hash Buckets: 262143
153153
; EMPTY-NEXT: Hash Key Size: 4
154154
; EMPTY-NEXT: Values: [205956, 163561, 59811, 208239, 16377, 247078, 194342, 254156, 194536, 167492, 185421, 119540, 261871, 198119, 48056, 251486, 134580, 148190, 113636, 53336, 55779, 220695, 198114, 148734, 81128, 60158, 217249, 174209, 159978, 249504, 141941, 238785, 6214, 94935, 151449, 135589, 73373, 96512, 254299, 17744, 239514, 173189, 130544, 204437, 238560, 144673, 115151, 197306, 256035, 101096, 231280, 52156, 48854, 170035, 177041, 102745, 16947, 183703, 98548, 35693, 171328, 203640, 139292, 49018, 43821, 202555, 165040, 215835, 142625, 52534, 44186, 103930, 110942, 17991, 213215]
155-
; EMPTY-NEXT: Type Index Offsets: [{4096, 0}]
156155
; EMPTY-NEXT: Hash Adjustments: []
157156
; EMPTY-NEXT: }
157+
; EMPTY-NEXT: TypeIndexOffsets [
158+
; EMPTY-NEXT: Index: 0x1000, Offset: 0
159+
; EMPTY-NEXT: ]
158160
; EMPTY: Type Info Stream (IPI) {
159161
; EMPTY-NEXT: IPI Version: 20040203
160162
; EMPTY-NEXT: Record count: 15
@@ -231,13 +233,9 @@
231233
; EMPTY-NEXT: 0000: 42100000 01000000 6C000000 0100F2F1 |B.......l.......|
232234
; EMPTY-NEXT: )
233235
; EMPTY-NEXT: }
234-
; EMPTY: Hash {
235-
; EMPTY-NEXT: Number of Hash Buckets: 262143
236-
; EMPTY-NEXT: Hash Key Size: 4
237-
; EMPTY-NEXT: Values: [7186, 7198, 7180, 7191, 7201, 7241, 7249, 80727, 154177, 75189, 253662, 193467, 222705, 186099, 257108]
238-
; EMPTY-NEXT: Type Index Offsets: [{4096, 0}]
239-
; EMPTY-NEXT: Hash Adjustments: []
240-
; EMPTY-NEXT: }
236+
; EMPTY: TypeIndexOffsets [
237+
; EMPTY-NEXT: Index: 0x1000, Offset: 0
238+
; EMPTY-NEXT: ]
241239
; EMPTY: DBI Stream {
242240
; EMPTY-NEXT: Dbi Version: 19990903
243241
; EMPTY-NEXT: Age: 1

llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp

Lines changed: 80 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -510,24 +510,27 @@ static void printTypeIndexOffset(raw_ostream &OS,
510510
OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}";
511511
}
512512

513-
static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) {
514-
if (!opts::raw::DumpTpiHash)
515-
return;
516-
DictScope DD(P, "Hash");
517-
P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets());
518-
P.printNumber("Hash Key Size", Tpi.getHashKeySize());
519-
P.printList("Values", Tpi.getHashValues());
520-
P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(),
521-
printTypeIndexOffset);
522-
P.printList("Hash Adjustments", Tpi.getHashAdjustments(),
523-
printTypeIndexOffset);
513+
namespace {
514+
class RecordBytesVisitor : public TypeVisitorCallbacks {
515+
public:
516+
explicit RecordBytesVisitor(ScopedPrinter &P) : P(P) {}
517+
518+
Error visitTypeEnd(CVType &Record) override {
519+
P.printBinaryBlock("Bytes", Record.content());
520+
return Error::success();
521+
}
522+
523+
private:
524+
ScopedPrinter &P;
525+
};
524526
}
525527

526528
Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
527529
assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
528530

529531
bool DumpRecordBytes = false;
530532
bool DumpRecords = false;
533+
bool DumpTpiHash = false;
531534
StringRef Label;
532535
StringRef VerLabel;
533536
if (StreamIdx == StreamTPI) {
@@ -537,6 +540,7 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
537540
}
538541
DumpRecordBytes = opts::raw::DumpTpiRecordBytes;
539542
DumpRecords = opts::raw::DumpTpiRecords;
543+
DumpTpiHash = opts::raw::DumpTpiHash;
540544
Label = "Type Info Stream (TPI)";
541545
VerLabel = "TPI Version";
542546
} else if (StreamIdx == StreamIPI) {
@@ -549,80 +553,98 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
549553
Label = "Type Info Stream (IPI)";
550554
VerLabel = "IPI Version";
551555
}
552-
if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms)
556+
if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash &&
557+
!opts::raw::DumpModuleSyms)
553558
return Error::success();
554559

560+
bool IsSilentDatabaseBuild = !DumpRecordBytes && !DumpRecords && !DumpTpiHash;
561+
555562
auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
556563
: File.getPDBIpiStream();
557564
if (!Tpi)
558565
return Tpi.takeError();
559566

560-
// Even if the user doesn't want to dump type records, we still need to
561-
// iterate them in order to build the type database. So when they want to
562-
// dump symbols but not types, don't stick a dumper on the end, just build
563-
// the type database.
567+
std::unique_ptr<DictScope> StreamScope;
568+
std::unique_ptr<ListScope> RecordScope;
569+
570+
if (!IsSilentDatabaseBuild) {
571+
StreamScope = llvm::make_unique<DictScope>(P, Label);
572+
P.printNumber(VerLabel, Tpi->getTpiVersion());
573+
P.printNumber("Record count", Tpi->NumTypeRecords());
574+
}
575+
564576
TypeDatabaseVisitor DBV(TypeDB);
565577
CompactTypeDumpVisitor CTDV(TypeDB, &P);
566578
TypeDumpVisitor TDV(TypeDB, &P, false);
579+
RecordBytesVisitor RBV(P);
567580
TypeDeserializer Deserializer;
581+
582+
// We always need to deserialize and add it to the type database. This is
583+
// true if even if we're not dumping anything, because we could need the
584+
// type database for the purposes of dumping symbols.
568585
TypeVisitorCallbackPipeline Pipeline;
569586
Pipeline.addCallbackToPipeline(Deserializer);
570587
Pipeline.addCallbackToPipeline(DBV);
571588

572-
CVTypeVisitor Visitor(Pipeline);
573-
574-
if (DumpRecords || DumpRecordBytes) {
575-
DictScope D(P, Label);
576-
577-
P.printNumber(VerLabel, Tpi->getTpiVersion());
578-
P.printNumber("Record count", Tpi->NumTypeRecords());
579-
ListScope L(P, "Records");
580-
581-
bool HadError = false;
589+
// If we're in dump mode, add a dumper with the appropriate detail level.
590+
if (DumpRecords) {
582591
if (opts::raw::CompactRecords)
583592
Pipeline.addCallbackToPipeline(CTDV);
584593
else
585594
Pipeline.addCallbackToPipeline(TDV);
595+
}
596+
if (DumpRecordBytes)
597+
Pipeline.addCallbackToPipeline(RBV);
586598

587-
for (auto Type : Tpi->types(&HadError)) {
588-
std::unique_ptr<DictScope> Scope;
589-
if (!opts::raw::CompactRecords)
590-
Scope.reset(new DictScope(P, ""));
599+
CVTypeVisitor Visitor(Pipeline);
591600

592-
if (DumpRecords) {
593-
if (auto EC = Visitor.visitTypeRecord(Type))
594-
return EC;
595-
}
601+
if (DumpRecords || DumpRecordBytes)
602+
RecordScope = llvm::make_unique<ListScope>(P, "Records");
596603

597-
if (DumpRecordBytes)
598-
P.printBinaryBlock("Bytes", Type.content());
599-
}
600-
dumpTpiHash(P, *Tpi);
601-
if (HadError)
602-
return make_error<RawError>(raw_error_code::corrupt_file,
603-
"TPI stream contained corrupt record");
604-
{
605-
ListScope L(P, "TypeIndexOffsets");
606-
for (const auto &IO : Tpi->getTypeIndexOffsets()) {
607-
P.printString(formatv("Index: {0:x}, Offset: {1:N}", IO.Type.getIndex(),
608-
(uint32_t)IO.Offset)
609-
.str());
610-
}
611-
}
604+
bool HadError = false;
605+
606+
TypeIndex T(TypeIndex::FirstNonSimpleIndex);
607+
for (auto Type : Tpi->types(&HadError)) {
608+
std::unique_ptr<DictScope> OneRecordScope;
612609

613-
} else if (opts::raw::DumpModuleSyms) {
610+
if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords)
611+
OneRecordScope = llvm::make_unique<DictScope>(P, "");
614612

615-
bool HadError = false;
616-
for (auto Type : Tpi->types(&HadError)) {
617-
if (auto EC = Visitor.visitTypeRecord(Type))
618-
return EC;
613+
if (auto EC = Visitor.visitTypeRecord(Type))
614+
return EC;
615+
}
616+
if (HadError)
617+
return make_error<RawError>(raw_error_code::corrupt_file,
618+
"TPI stream contained corrupt record");
619+
620+
if (DumpTpiHash) {
621+
DictScope DD(P, "Hash");
622+
P.printNumber("Number of Hash Buckets", Tpi->NumHashBuckets());
623+
P.printNumber("Hash Key Size", Tpi->getHashKeySize());
624+
P.printList("Values", Tpi->getHashValues());
625+
626+
ListScope LHA(P, "Adjusters");
627+
auto ExpectedST = File.getStringTable();
628+
if (!ExpectedST)
629+
return ExpectedST.takeError();
630+
const auto &ST = *ExpectedST;
631+
for (const auto &E : Tpi->getHashAdjusters()) {
632+
DictScope DHA(P);
633+
StringRef Name = ST.getStringForID(E.first);
634+
P.printString("Type", Name);
635+
P.printHex("TI", E.second);
619636
}
637+
}
620638

621-
dumpTpiHash(P, *Tpi);
622-
if (HadError)
623-
return make_error<RawError>(raw_error_code::corrupt_file,
624-
"TPI stream contained corrupt record");
639+
if (!IsSilentDatabaseBuild) {
640+
ListScope L(P, "TypeIndexOffsets");
641+
for (const auto &IO : Tpi->getTypeIndexOffsets()) {
642+
P.printString(formatv("Index: {0:x}, Offset: {1:N}", IO.Type.getIndex(),
643+
(uint32_t)IO.Offset)
644+
.str());
645+
}
625646
}
647+
626648
P.flush();
627649
return Error::success();
628650
}

0 commit comments

Comments
 (0)