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 "llvm/DebugInfo/PDB/Raw/PublicsStream.h" 26 27 #include "llvm/DebugInfo/CodeView/CodeView.h" 28 #include "llvm/DebugInfo/CodeView/StreamReader.h" 29 #include "llvm/DebugInfo/CodeView/TypeRecord.h" 30 #include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" 31 #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" 32 #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" 33 #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" 34 #include "llvm/DebugInfo/PDB/Raw/RawError.h" 35 #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" 36 37 #include "llvm/ADT/BitVector.h" 38 #include "llvm/Support/Endian.h" 39 #include "llvm/Support/Format.h" 40 #include "llvm/Support/MathExtras.h" 41 42 using namespace llvm; 43 using namespace llvm::support; 44 using namespace llvm::pdb; 45 46 47 static const unsigned IPHR_HASH = 4096; 48 49 // This is PSGSIHDR struct defined in 50 // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h 51 struct PublicsStream::HeaderInfo { 52 ulittle32_t SymHash; 53 ulittle32_t AddrMap; 54 ulittle32_t NumThunks; 55 ulittle32_t SizeOfThunk; 56 ulittle16_t ISectThunkTable; 57 char Padding[2]; 58 ulittle32_t OffThunkTable; 59 ulittle32_t NumSections; 60 }; 61 62 // This is GSIHashHdr. 63 struct PublicsStream::GSIHashHeader { 64 enum : unsigned { 65 HdrSignature = ~0U, 66 HdrVersion = 0xeffe0000 + 19990810, 67 }; 68 ulittle32_t VerSignature; 69 ulittle32_t VerHdr; 70 ulittle32_t HrSize; 71 ulittle32_t NumBuckets; 72 }; 73 74 PublicsStream::PublicsStream(PDBFile &File, 75 std::unique_ptr<MappedBlockStream> Stream) 76 : Pdb(File), Stream(std::move(Stream)) {} 77 78 PublicsStream::~PublicsStream() {} 79 80 uint32_t PublicsStream::getSymHash() const { return Header->SymHash; } 81 uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; } 82 83 // Publics stream contains fixed-size headers and a serialized hash table. 84 // This implementation is not complete yet. It reads till the end of the 85 // stream so that we verify the stream is at least not corrupted. However, 86 // we skip over the hash table which we believe contains information about 87 // public symbols. 88 Error PublicsStream::reload() { 89 codeview::StreamReader Reader(*Stream); 90 91 // Check stream size. 92 if (Reader.bytesRemaining() < sizeof(HeaderInfo) + sizeof(GSIHashHeader)) 93 return make_error<RawError>(raw_error_code::corrupt_file, 94 "Publics Stream does not contain a header."); 95 96 // Read PSGSIHDR and GSIHashHdr structs. 97 if (Reader.readObject(Header)) 98 return make_error<RawError>(raw_error_code::corrupt_file, 99 "Publics Stream does not contain a header."); 100 101 if (Reader.readObject(HashHdr)) 102 return make_error<RawError>(raw_error_code::corrupt_file, 103 "Publics Stream does not contain a header."); 104 105 // An array of HashRecord follows. Read them. 106 if (HashHdr->HrSize % sizeof(PSHashRecord)) 107 return make_error<RawError>(raw_error_code::corrupt_file, 108 "Invalid HR array size."); 109 uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord); 110 if (auto EC = Reader.readArray(HashRecords, NumHashRecords)) 111 return joinErrors(std::move(EC), 112 make_error<RawError>(raw_error_code::corrupt_file, 113 "Could not read an HR array")); 114 115 // A bitmap of a fixed length follows. 116 size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); 117 uint32_t NumBitmapEntries = BitmapSizeInBits / 8; 118 if (auto EC = Reader.readBytes(Bitmap, NumBitmapEntries)) 119 return joinErrors(std::move(EC), 120 make_error<RawError>(raw_error_code::corrupt_file, 121 "Could not read a bitmap.")); 122 for (uint8_t B : Bitmap) 123 NumBuckets += countPopulation(B); 124 125 // We don't yet understand the following data structures completely, 126 // but we at least know the types and sizes. Here we are trying 127 // to read the stream till end so that we at least can detect 128 // corrupted streams. 129 130 // Hash buckets follow. 131 if (auto EC = Reader.readArray(HashBuckets, NumBuckets)) 132 return joinErrors(std::move(EC), 133 make_error<RawError>(raw_error_code::corrupt_file, 134 "Hash buckets corrupted.")); 135 136 // Something called "address map" follows. 137 uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t); 138 if (auto EC = Reader.readArray(AddressMap, NumAddressMapEntries)) 139 return joinErrors(std::move(EC), 140 make_error<RawError>(raw_error_code::corrupt_file, 141 "Could not read an address map.")); 142 143 // Something called "thunk map" follows. 144 if (auto EC = Reader.readArray(ThunkMap, Header->NumThunks)) 145 return joinErrors(std::move(EC), 146 make_error<RawError>(raw_error_code::corrupt_file, 147 "Could not read a thunk map.")); 148 149 // Something called "section map" follows. 150 if (auto EC = Reader.readArray(SectionOffsets, Header->NumSections)) 151 return joinErrors(std::move(EC), 152 make_error<RawError>(raw_error_code::corrupt_file, 153 "Could not read a section map.")); 154 155 if (Reader.bytesRemaining() > 0) 156 return make_error<RawError>(raw_error_code::corrupt_file, 157 "Corrupted publics stream."); 158 return Error::success(); 159 } 160 161 iterator_range<codeview::CVSymbolArray::Iterator> 162 PublicsStream::getSymbols(bool *HadError) const { 163 auto SymbolS = Pdb.getPDBSymbolStream(); 164 if (SymbolS.takeError()) { 165 codeview::CVSymbolArray::Iterator Iter; 166 return llvm::make_range(Iter, Iter); 167 } 168 SymbolStream &SS = SymbolS.get(); 169 170 return SS.getSymbols(HadError); 171 } 172 173 Error PublicsStream::commit() { return Error::success(); } 174