llvm.org GIT mirror llvm / cffc876
[PDB] Add the ability to lookup global symbols by name. The Globals table is a hash table keyed on symbol name, so it's possible to lookup symbols by name in O(1) time. Add a function to the globals stream to do this, and add an option to llvm-pdbutil to exercise this, then use it to write some tests to verify correctness. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@343951 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 11 months ago
12 changed file(s) with 158 addition(s) and 16 deletion(s). Raw diff Collapse all Expand all
357357 // S_PUB32
358358 class PublicSym32 : public SymbolRecord {
359359 public:
360 PublicSym32() : SymbolRecord(SymbolRecordKind::PublicSym32) {}
360361 explicit PublicSym32(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
361362 explicit PublicSym32(uint32_t RecordOffset)
362363 : SymbolRecord(SymbolRecordKind::PublicSym32),
635636 // S_OBJNAME
636637 class ObjNameSym : public SymbolRecord {
637638 public:
639 explicit ObjNameSym() : SymbolRecord(SymbolRecordKind::ObjNameSym) {}
638640 explicit ObjNameSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
639641 ObjNameSym(uint32_t RecordOffset)
640642 : SymbolRecord(SymbolRecordKind::ObjNameSym), RecordOffset(RecordOffset) {
717719 // S_COMPILE3
718720 class Compile3Sym : public SymbolRecord {
719721 public:
722 Compile3Sym() : SymbolRecord(SymbolRecordKind::Compile3Sym) {}
720723 explicit Compile3Sym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
721724 Compile3Sym(uint32_t RecordOffset)
722725 : SymbolRecord(SymbolRecordKind::Compile3Sym),
738741 Flags = CompileSym3Flags((uint32_t(Flags) & 0xFFFFFF00) | uint32_t(Lang));
739742 }
740743
741 uint8_t getLanguage() const { return static_cast(Flags) & 0xFF; }
742 uint32_t getFlags() const { return static_cast(Flags) & ~0xFF; }
744 SourceLanguage getLanguage() const {
745 return static_cast(static_cast(Flags) & 0xFF);
746 }
747 CompileSym3Flags getFlags() const {
748 return static_cast(static_cast(Flags) & ~0xFF);
749 }
750
751 bool hasOptimizations() const {
752 return CompileSym3Flags::None !=
753 (getFlags() & (CompileSym3Flags::PGO | CompileSym3Flags::LTCG));
754 }
743755
744756 uint32_t RecordOffset;
745757 };
7777
7878 const DbiModuleList &modules() const;
7979
80 FixedStreamArray getSectionHeaders();
80 FixedStreamArray getSectionHeaders() const;
8181
8282 FixedStreamArray getFpoRecords();
8383
99 #ifndef LLVM_DEBUGINFO_PDB_RAW_GLOBALS_STREAM_H
1010 #define LLVM_DEBUGINFO_PDB_RAW_GLOBALS_STREAM_H
1111
12 #include "llvm/ADT/iterator.h"
13 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
1214 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
1315 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
1416 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
1517 #include "llvm/DebugInfo/PDB/PDBTypes.h"
1618 #include "llvm/Support/BinaryStreamArray.h"
1719 #include "llvm/Support/Error.h"
18 #include "llvm/ADT/iterator.h"
1920
2021 namespace llvm {
2122 namespace pdb {
2223 class DbiStream;
2324 class PDBFile;
25 class SymbolStream;
2426
2527 /// Iterator over hash records producing symbol record offsets. Abstracts away
2628 /// the fact that symbol record offsets on disk are off-by-one.
4951 public:
5052 const GSIHashHeader *HashHdr;
5153 FixedStreamArray HashRecords;
52 ArrayRef8_t> HashBitmap;
54 ArrayRef32_t> HashBitmap;
5355 FixedStreamArray HashBuckets;
56 std::array BucketMap;
5457
5558 Error read(BinaryStreamReader &Reader);
5659
7174 const GSIHashTable &getGlobalsTable() const { return GlobalsTable; }
7275 Error reload();
7376
77 std::vector>
78 findRecordsByName(StringRef Name, const SymbolStream &Symbols) const;
79
7480 private:
7581 GSIHashTable GlobalsTable;
7682 std::unique_ptr Stream;
1414 #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
1515 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
1616 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
17 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
1718 #include "llvm/Support/BinaryStreamRef.h"
1819 #include "llvm/Support/Error.h"
1920 #include
5051
5152 ModuleDebugStreamRef &operator=(ModuleDebugStreamRef &&Other) = delete;
5253
54 codeview::CVSymbol readSymbolAtOffset(uint32_t Offset) const;
55
5356 iterator_range subsections() const;
5457 codeview::DebugSubsectionArray getSubsectionsArray() const {
5558 return Subsections;
6366 findChecksumsSubsection() const;
6467
6568 private:
66 const DbiModuleDescriptor &Mod;
69 DbiModuleDescriptor Mod;
6770
6871 uint32_t Signature;
6972
261261 Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
262262 Compile3Sym &Compile3) {
263263 W.printEnum("Language", Compile3.getLanguage(), getSourceLanguageNames());
264 W.printFlags("Flags", Compile3.getFlags(), getCompileSym3FlagNames());
264 W.printFlags("Flags", uint32_t(Compile3.getFlags()),
265 getCompileSym3FlagNames());
265266 W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames());
266267 CompilationCPUType = Compile3.Machine;
267268 std::string FrontendVersion;
196196 return static_cast(Machine);
197197 }
198198
199 FixedStreamArray DbiStream::getSectionHeaders() {
199 FixedStreamArray DbiStream::getSectionHeaders() const {
200200 return SectionHeaders;
201201 }
202202
1919 //===----------------------------------------------------------------------===//
2020
2121 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
22
23 #include "llvm/DebugInfo/CodeView/RecordName.h"
24 #include "llvm/DebugInfo/PDB/Native/Hash.h"
2225 #include "llvm/DebugInfo/PDB/Native/RawError.h"
26 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
2327 #include "llvm/Support/BinaryStreamReader.h"
2428 #include "llvm/Support/Error.h"
2529 #include
3842 if (auto E = GlobalsTable.read(Reader))
3943 return E;
4044 return Error::success();
45 }
46
47 std::vector>
48 GlobalsStream::findRecordsByName(StringRef Name,
49 const SymbolStream &Symbols) const {
50 std::vector> Result;
51
52 // Hash the name to figure out which bucket this goes into.
53 size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH;
54 uint32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex];
55 if (CompressedBucketIndex == -1)
56 return Result;
57
58 uint32_t ChainStartOffset = GlobalsTable.HashBuckets[CompressedBucketIndex];
59 uint32_t NextChainStart = GlobalsTable.HashBuckets.size();
60 if (CompressedBucketIndex + 1 < GlobalsTable.HashBuckets.size())
61 NextChainStart = GlobalsTable.HashBuckets[CompressedBucketIndex + 1];
62 ChainStartOffset /= 12;
63 NextChainStart /= 12;
64
65 while (ChainStartOffset < NextChainStart) {
66 PSHashRecord PSH = GlobalsTable.HashRecords[ChainStartOffset];
67 uint32_t Off = PSH.Off - 1;
68 codeview::CVSymbol Record = Symbols.readRecord(Off);
69 if (codeview::getSymbolName(Record) == Name)
70 Result.push_back(std::make_pair(Off, std::move(Record)));
71 ++ChainStartOffset;
72 }
73 return Result;
4174 }
4275
4376 static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
85118
86119 static Error
87120 readGSIHashBuckets(FixedStreamArray &HashBuckets,
88 ArrayRef8_t> &HashBitmap, const GSIHashHeader *HashHdr,
121 ArrayRef32_t> &HashBitmap, const GSIHashHeader *HashHdr,
122 MutableArrayRef BucketMap,
89123 BinaryStreamReader &Reader) {
90124 if (auto EC = checkHashHdrVersion(HashHdr))
91125 return EC;
93127 // Before the actual hash buckets, there is a bitmap of length determined by
94128 // IPHR_HASH.
95129 size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
96 uint32_t NumBitmapEntries = BitmapSizeInBits / 8;
97 if (auto EC = Reader.readBytes(HashBitmap, NumBitmapEntries))
130 uint32_t NumBitmapEntries = BitmapSizeInBits / 32;
131 if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries))
98132 return joinErrors(std::move(EC),
99133 make_error(raw_error_code::corrupt_file,
100134 "Could not read a bitmap."));
135 uint32_t NumBuckets1 = 0;
136 uint32_t CompressedBucketIdx = 0;
137 for (uint32_t I = 0; I <= IPHR_HASH; ++I) {
138 uint8_t WordIdx = I / 32;
139 uint8_t BitIdx = I % 32;
140 bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx);
141 if (IsSet) {
142 ++NumBuckets1;
143 BucketMap[I] = CompressedBucketIdx++;
144 } else {
145 BucketMap[I] = -1;
146 }
147 }
148
101149 uint32_t NumBuckets = 0;
102 for (uint8_t B : HashBitmap)
150 for (uint32_t B : HashBitmap)
103151 NumBuckets += countPopulation(B);
104152
105153 // Hash buckets follow.
117165 if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
118166 return EC;
119167 if (HashHdr->HrSize > 0)
120 if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader))
168 if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr,
169 BucketMap, Reader))
121170 return EC;
122171 return Error::success();
123172 }
9696 return make_range(SymbolArray.begin(HadError), SymbolArray.end());
9797 }
9898
99 CVSymbol ModuleDebugStreamRef::readSymbolAtOffset(uint32_t Offset) const {
100 // Offsets include the size of the 4-byte magic at the beginning, but lookup
101 // doesn't take that into account, so subtract it here.
102 auto Iter = SymbolArray.at(Offset - 4);
103 assert(Iter != SymbolArray.end());
104 return *Iter;
105 }
106
99107 iterator_range
100108 ModuleDebugStreamRef::subsections() const {
101109 return make_range(Subsections.begin(), Subsections.end());
0 ; RUN: llvm-pdbutil dump -globals \
1 ; RUN: -global-name="operator delete" \
2 ; RUN: -global-name=main \
3 ; RUN: -global-name=abcdefg \
4 ; RUN: -global-name="Base2::`vbase destructor'" \
5 ; RUN: %p/Inputs/every-function.pdb | FileCheck %s
6
7 CHECK: Global Symbols
8 CHECK-NEXT: ============================================================
9 CHECK-NEXT: Global Name `operator delete`
10 CHECK-NEXT: 1516 | S_PROCREF [size = 32] `operator delete`
11 CHECK-NEXT: module = 1, sum name = 0, offset = 324
12 CHECK-NEXT: 1484 | S_PROCREF [size = 32] `operator delete`
13 CHECK-NEXT: module = 1, sum name = 0, offset = 184
14 CHECK-NEXT: Global Name `main`
15 CHECK-NEXT: 2016 | S_PROCREF [size = 20] `main`
16 CHECK-NEXT: module = 1, sum name = 0, offset = 1952
17 CHECK-NEXT: Global Name `abcdefg`
18 CHECK-NEXT: (no matching records found)
19 CHECK-NEXT: Global Name `Base2::`vbase destructor'`
20 CHECK-NEXT: 2288 | S_PROCREF [size = 40] `Base2::`vbase destructor'`
21 CHECK-NEXT: module = 1, sum name = 0, offset = 2852
15711571 ExitOnError Err("Error dumping globals stream: ");
15721572 auto &Globals = Err(getPdb().getPDBGlobalsStream());
15731573
1574 const GSIHashTable &Table = Globals.getGlobalsTable();
1575 Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
1574 if (opts::dump::DumpGlobalNames.empty()) {
1575 const GSIHashTable &Table = Globals.getGlobalsTable();
1576 Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
1577 } else {
1578 SymbolStream &SymRecords = cantFail(getPdb().getPDBSymbolStream());
1579 auto &Types = File.types();
1580 auto &Ids = File.ids();
1581
1582 SymbolVisitorCallbackPipeline Pipeline;
1583 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
1584 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
1585
1586 Pipeline.addCallbackToPipeline(Deserializer);
1587 Pipeline.addCallbackToPipeline(Dumper);
1588 CVSymbolVisitor Visitor(Pipeline);
1589
1590 using ResultEntryType = std::pair;
1591 for (StringRef Name : opts::dump::DumpGlobalNames) {
1592 AutoIndent Indent(P);
1593 P.formatLine("Global Name `{0}`", Name);
1594 std::vector Results =
1595 Globals.findRecordsByName(Name, SymRecords);
1596 if (Results.empty()) {
1597 AutoIndent Indent(P);
1598 P.printLine("(no matching records found)");
1599 continue;
1600 }
1601
1602 for (ResultEntryType Result : Results) {
1603 if (auto E = Visitor.visitSymbolRecord(Result.second, Result.first))
1604 return E;
1605 }
1606 }
1607 }
15761608 return Error::success();
15771609 }
15781610
16751707
16761708 // Return early if we aren't dumping public hash table and address map info.
16771709 if (HashExtras) {
1678 P.formatBinary("Hash Bitmap", Table.HashBitmap, 0);
1710 ArrayRef BitmapBytes(
1711 reinterpret_cast(Table.HashBitmap.data()),
1712 Table.HashBitmap.size() * sizeof(uint32_t));
1713 P.formatBinary("Hash Bitmap", BitmapBytes, 0);
16791714
16801715 P.formatLine("Hash Entries");
16811716 {
525525 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
526526 cl::opt DumpGlobalExtras("global-extras", cl::desc("dump Globals hashes"),
527527 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
528 cl::list DumpGlobalNames(
529 "global-name",
530 cl::desc(
531 "With -globals, only dump globals whose name matches the given value"),
532 cl::cat(SymbolOptions), cl::sub(DumpSubcommand), cl::ZeroOrMore);
528533 cl::opt DumpPublics("publics", cl::desc("dump Publics stream data"),
529534 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
530535 cl::opt DumpPublicExtras("public-extras",
168168 extern llvm::cl::opt DumpSymRecordBytes;
169169 extern llvm::cl::opt DumpGSIRecords;
170170 extern llvm::cl::opt DumpGlobals;
171 extern llvm::cl::list DumpGlobalNames;
171172 extern llvm::cl::opt DumpGlobalExtras;
172173 extern llvm::cl::opt DumpPublics;
173174 extern llvm::cl::opt DumpPublicExtras;