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 42using namespace llvm; 43using namespace llvm::support; 44using namespace llvm::pdb; 45 46 47static 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 51struct 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. 63struct 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 74PublicsStream::PublicsStream(PDBFile &File, 75 std::unique_ptr<MappedBlockStream> Stream) 76 : Pdb(File), Stream(std::move(Stream)) {} 77 78PublicsStream::~PublicsStream() {} 79 80uint32_t PublicsStream::getSymHash() const { return Header->SymHash; } 81uint32_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. 88Error 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 161iterator_range<codeview::CVSymbolArray::Iterator> 162PublicsStream::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 173Error PublicsStream::commit() { return Error::success(); } 174