Line data Source code
1 : //===- PublicsStream.cpp - PDB Public Symbol Stream -----------------------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // The data structures defined in this file are based on the reference
11 : // implementation which is available at
12 : // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
13 : //
14 : // When you are reading the reference source code, you'd find the
15 : // information below useful.
16 : //
17 : // - ppdb1->m_fMinimalDbgInfo seems to be always true.
18 : // - SMALLBUCKETS macro is defined.
19 : //
20 : // The reference doesn't compile, so I learned just by reading code.
21 : // It's not guaranteed to be correct.
22 : //
23 : //===----------------------------------------------------------------------===//
24 :
25 : #include "GSI.h"
26 : #include "llvm/ADT/iterator_range.h"
27 : #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
28 : #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
29 : #include "llvm/DebugInfo/MSF/StreamReader.h"
30 : #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
31 : #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
32 : #include "llvm/DebugInfo/PDB/Raw/RawError.h"
33 : #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
34 : #include "llvm/Support/Endian.h"
35 : #include "llvm/Support/Error.h"
36 : #include <algorithm>
37 : #include <cstdint>
38 :
39 : using namespace llvm;
40 : using namespace llvm::msf;
41 : using namespace llvm::support;
42 : using namespace llvm::pdb;
43 :
44 : // This is PSGSIHDR struct defined in
45 : // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
46 : struct PublicsStream::HeaderInfo {
47 : ulittle32_t SymHash;
48 : ulittle32_t AddrMap;
49 : ulittle32_t NumThunks;
50 : ulittle32_t SizeOfThunk;
51 : ulittle16_t ISectThunkTable;
52 : char Padding[2];
53 : ulittle32_t OffThunkTable;
54 : ulittle32_t NumSections;
55 : };
56 :
57 2 : PublicsStream::PublicsStream(PDBFile &File,
58 2 : std::unique_ptr<MappedBlockStream> Stream)
59 16 : : Pdb(File), Stream(std::move(Stream)) {}
60 :
61 : PublicsStream::~PublicsStream() = default;
62 :
63 4 : uint32_t PublicsStream::getSymHash() const { return Header->SymHash; }
64 4 : uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; }
65 :
66 : // Publics stream contains fixed-size headers and a serialized hash table.
67 : // This implementation is not complete yet. It reads till the end of the
68 : // stream so that we verify the stream is at least not corrupted. However,
69 : // we skip over the hash table which we believe contains information about
70 : // public symbols.
71 2 : Error PublicsStream::reload() {
72 4 : StreamReader Reader(*Stream);
73 :
74 : // Check stream size.
75 2 : if (Reader.bytesRemaining() < sizeof(HeaderInfo) + sizeof(GSIHashHeader))
76 : return make_error<RawError>(raw_error_code::corrupt_file,
77 0 : "Publics Stream does not contain a header.");
78 :
79 : // Read PSGSIHDR and GSIHashHdr structs.
80 6 : if (Reader.readObject(Header))
81 : return make_error<RawError>(raw_error_code::corrupt_file,
82 0 : "Publics Stream does not contain a header.");
83 :
84 6 : if (auto EC = readGSIHashHeader(HashHdr, Reader))
85 0 : return EC;
86 :
87 6 : if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
88 0 : return EC;
89 :
90 6 : if (auto EC = readGSIHashBuckets(HashBuckets, HashHdr, Reader))
91 0 : return EC;
92 4 : NumBuckets = HashBuckets.size();
93 :
94 : // Something called "address map" follows.
95 4 : uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t);
96 6 : if (auto EC = Reader.readArray(AddressMap, NumAddressMapEntries))
97 0 : return joinErrors(std::move(EC),
98 0 : make_error<RawError>(raw_error_code::corrupt_file,
99 0 : "Could not read an address map."));
100 :
101 : // Something called "thunk map" follows.
102 8 : if (auto EC = Reader.readArray(ThunkMap, Header->NumThunks))
103 0 : return joinErrors(std::move(EC),
104 0 : make_error<RawError>(raw_error_code::corrupt_file,
105 0 : "Could not read a thunk map."));
106 :
107 : // Something called "section map" follows.
108 8 : if (auto EC = Reader.readArray(SectionOffsets, Header->NumSections))
109 0 : return joinErrors(std::move(EC),
110 0 : make_error<RawError>(raw_error_code::corrupt_file,
111 0 : "Could not read a section map."));
112 :
113 2 : if (Reader.bytesRemaining() > 0)
114 : return make_error<RawError>(raw_error_code::corrupt_file,
115 0 : "Corrupted publics stream.");
116 6 : return Error::success();
117 : }
118 :
119 : iterator_range<codeview::CVSymbolArray::Iterator>
120 2 : PublicsStream::getSymbols(bool *HadError) const {
121 4 : auto SymbolS = Pdb.getPDBSymbolStream();
122 6 : if (SymbolS.takeError()) {
123 0 : codeview::CVSymbolArray::Iterator Iter;
124 0 : return make_range(Iter, Iter);
125 : }
126 2 : SymbolStream &SS = SymbolS.get();
127 :
128 2 : return SS.getSymbols(HadError);
129 : }
130 :
131 0 : Error PublicsStream::commit() { return Error::success(); }
|