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