GlobalsStream.cpp revision 327952
1//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- C++ -*-===//
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 on-disk structores used 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//===----------------------------------------------------------------------===//
21
22#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
23#include "llvm/DebugInfo/PDB/Native/RawError.h"
24#include "llvm/Support/BinaryStreamReader.h"
25#include "llvm/Support/Error.h"
26#include <algorithm>
27
28using namespace llvm;
29using namespace llvm::msf;
30using namespace llvm::pdb;
31
32GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream)
33    : Stream(std::move(Stream)) {}
34
35GlobalsStream::~GlobalsStream() = default;
36
37Error GlobalsStream::reload() {
38  BinaryStreamReader Reader(*Stream);
39  if (auto E = GlobalsTable.read(Reader))
40    return E;
41  return Error::success();
42}
43
44static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
45  if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)
46    return make_error<RawError>(
47        raw_error_code::feature_unsupported,
48        "Encountered unsupported globals stream version.");
49
50  return Error::success();
51}
52
53static Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
54                               BinaryStreamReader &Reader) {
55  if (Reader.readObject(HashHdr))
56    return make_error<RawError>(raw_error_code::corrupt_file,
57                                "Stream does not contain a GSIHashHeader.");
58
59  if (HashHdr->VerSignature != GSIHashHeader::HdrSignature)
60    return make_error<RawError>(
61        raw_error_code::feature_unsupported,
62        "GSIHashHeader signature (0xffffffff) not found.");
63
64  return Error::success();
65}
66
67static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
68                                const GSIHashHeader *HashHdr,
69                                BinaryStreamReader &Reader) {
70  if (auto EC = checkHashHdrVersion(HashHdr))
71    return EC;
72
73  // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have.
74  // Verify that we can read them all.
75  if (HashHdr->HrSize % sizeof(PSHashRecord))
76    return make_error<RawError>(raw_error_code::corrupt_file,
77                                "Invalid HR array size.");
78  uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
79  if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
80    return joinErrors(std::move(EC),
81                      make_error<RawError>(raw_error_code::corrupt_file,
82                                           "Error reading hash records."));
83
84  return Error::success();
85}
86
87static Error
88readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
89                   ArrayRef<uint8_t> &HashBitmap, const GSIHashHeader *HashHdr,
90                   BinaryStreamReader &Reader) {
91  if (auto EC = checkHashHdrVersion(HashHdr))
92    return EC;
93
94  // Before the actual hash buckets, there is a bitmap of length determined by
95  // IPHR_HASH.
96  size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
97  uint32_t NumBitmapEntries = BitmapSizeInBits / 8;
98  if (auto EC = Reader.readBytes(HashBitmap, NumBitmapEntries))
99    return joinErrors(std::move(EC),
100                      make_error<RawError>(raw_error_code::corrupt_file,
101                                           "Could not read a bitmap."));
102  uint32_t NumBuckets = 0;
103  for (uint8_t B : HashBitmap)
104    NumBuckets += countPopulation(B);
105
106  // Hash buckets follow.
107  if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
108    return joinErrors(std::move(EC),
109                      make_error<RawError>(raw_error_code::corrupt_file,
110                                           "Hash buckets corrupted."));
111
112  return Error::success();
113}
114
115Error GSIHashTable::read(BinaryStreamReader &Reader) {
116  if (auto EC = readGSIHashHeader(HashHdr, Reader))
117    return EC;
118  if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
119    return EC;
120  if (HashHdr->HrSize > 0)
121    if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader))
122      return EC;
123  return Error::success();
124}
125