Home | History | Annotate | Download | only in Raw
      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