]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/DebugInfo/PDB/Native/GlobalsStream.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / DebugInfo / PDB / Native / GlobalsStream.cpp
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
24 #include "llvm/DebugInfo/CodeView/RecordName.h"
25 #include "llvm/DebugInfo/PDB/Native/Hash.h"
26 #include "llvm/DebugInfo/PDB/Native/RawError.h"
27 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
28 #include "llvm/Support/BinaryStreamReader.h"
29 #include "llvm/Support/Error.h"
30 #include <algorithm>
31
32 using namespace llvm;
33 using namespace llvm::msf;
34 using namespace llvm::pdb;
35
36 GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream)
37     : Stream(std::move(Stream)) {}
38
39 GlobalsStream::~GlobalsStream() = default;
40
41 Error GlobalsStream::reload() {
42   BinaryStreamReader Reader(*Stream);
43   if (auto E = GlobalsTable.read(Reader))
44     return E;
45   return Error::success();
46 }
47
48 std::vector<std::pair<uint32_t, codeview::CVSymbol>>
49 GlobalsStream::findRecordsByName(StringRef Name,
50                                  const SymbolStream &Symbols) const {
51   std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result;
52
53   // Hash the name to figure out which bucket this goes into.
54   size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH;
55   int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex];
56   if (CompressedBucketIndex == -1)
57     return Result;
58
59   uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1;
60   uint32_t StartRecordIndex =
61       GlobalsTable.HashBuckets[CompressedBucketIndex] / 12;
62   uint32_t EndRecordIndex = 0;
63   if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) {
64     EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1];
65   } else {
66     // If this is the last bucket, it consists of all hash records until the end
67     // of the HashRecords array.
68     EndRecordIndex = GlobalsTable.HashRecords.size() * 12;
69   }
70
71   EndRecordIndex /= 12;
72
73   assert(EndRecordIndex <= GlobalsTable.HashRecords.size());
74   while (StartRecordIndex < EndRecordIndex) {
75     PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex];
76     uint32_t Off = PSH.Off - 1;
77     codeview::CVSymbol Record = Symbols.readRecord(Off);
78     if (codeview::getSymbolName(Record) == Name)
79       Result.push_back(std::make_pair(Off, std::move(Record)));
80     ++StartRecordIndex;
81   }
82   return Result;
83 }
84
85 static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
86   if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)
87     return make_error<RawError>(
88         raw_error_code::feature_unsupported,
89         "Encountered unsupported globals stream version.");
90
91   return Error::success();
92 }
93
94 static Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
95                                BinaryStreamReader &Reader) {
96   if (Reader.readObject(HashHdr))
97     return make_error<RawError>(raw_error_code::corrupt_file,
98                                 "Stream does not contain a GSIHashHeader.");
99
100   if (HashHdr->VerSignature != GSIHashHeader::HdrSignature)
101     return make_error<RawError>(
102         raw_error_code::feature_unsupported,
103         "GSIHashHeader signature (0xffffffff) not found.");
104
105   return Error::success();
106 }
107
108 static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
109                                 const GSIHashHeader *HashHdr,
110                                 BinaryStreamReader &Reader) {
111   if (auto EC = checkHashHdrVersion(HashHdr))
112     return EC;
113
114   // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have.
115   // Verify that we can read them all.
116   if (HashHdr->HrSize % sizeof(PSHashRecord))
117     return make_error<RawError>(raw_error_code::corrupt_file,
118                                 "Invalid HR array size.");
119   uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
120   if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
121     return joinErrors(std::move(EC),
122                       make_error<RawError>(raw_error_code::corrupt_file,
123                                            "Error reading hash records."));
124
125   return Error::success();
126 }
127
128 static Error
129 readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
130                    FixedStreamArray<support::ulittle32_t> &HashBitmap,
131                    const GSIHashHeader *HashHdr,
132                    MutableArrayRef<int32_t> BucketMap,
133                    BinaryStreamReader &Reader) {
134   if (auto EC = checkHashHdrVersion(HashHdr))
135     return EC;
136
137   // Before the actual hash buckets, there is a bitmap of length determined by
138   // IPHR_HASH.
139   size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
140   uint32_t NumBitmapEntries = BitmapSizeInBits / 32;
141   if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries))
142     return joinErrors(std::move(EC),
143                       make_error<RawError>(raw_error_code::corrupt_file,
144                                            "Could not read a bitmap."));
145   uint32_t NumBuckets1 = 0;
146   uint32_t CompressedBucketIdx = 0;
147   for (uint32_t I = 0; I <= IPHR_HASH; ++I) {
148     uint8_t WordIdx = I / 32;
149     uint8_t BitIdx = I % 32;
150     bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx);
151     if (IsSet) {
152       ++NumBuckets1;
153       BucketMap[I] = CompressedBucketIdx++;
154     } else {
155       BucketMap[I] = -1;
156     }
157   }
158
159   uint32_t NumBuckets = 0;
160   for (uint32_t B : HashBitmap)
161     NumBuckets += countPopulation(B);
162
163   // Hash buckets follow.
164   if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
165     return joinErrors(std::move(EC),
166                       make_error<RawError>(raw_error_code::corrupt_file,
167                                            "Hash buckets corrupted."));
168
169   return Error::success();
170 }
171
172 Error GSIHashTable::read(BinaryStreamReader &Reader) {
173   if (auto EC = readGSIHashHeader(HashHdr, Reader))
174     return EC;
175   if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
176     return EC;
177   if (HashHdr->HrSize > 0)
178     if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr,
179                                      BucketMap, Reader))
180       return EC;
181   return Error::success();
182 }