GlobalsStream.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // The on-disk structores used in this file are based on the reference
  10. // implementation which is available at
  11. // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
  12. //
  13. // When you are reading the reference source code, you'd find the
  14. // information below useful.
  15. //
  16. // - ppdb1->m_fMinimalDbgInfo seems to be always true.
  17. // - SMALLBUCKETS macro is defined.
  18. //
  19. //===----------------------------------------------------------------------===//
  20. #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
  21. #include "llvm/DebugInfo/CodeView/RecordName.h"
  22. #include "llvm/DebugInfo/PDB/Native/Hash.h"
  23. #include "llvm/DebugInfo/PDB/Native/RawError.h"
  24. #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
  25. #include "llvm/Support/BinaryStreamReader.h"
  26. #include "llvm/Support/Error.h"
  27. #include <algorithm>
  28. using namespace llvm;
  29. using namespace llvm::msf;
  30. using namespace llvm::pdb;
  31. GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream)
  32. : Stream(std::move(Stream)) {}
  33. GlobalsStream::~GlobalsStream() = default;
  34. Error GlobalsStream::reload() {
  35. BinaryStreamReader Reader(*Stream);
  36. if (auto E = GlobalsTable.read(Reader))
  37. return E;
  38. return Error::success();
  39. }
  40. std::vector<std::pair<uint32_t, codeview::CVSymbol>>
  41. GlobalsStream::findRecordsByName(StringRef Name,
  42. const SymbolStream &Symbols) const {
  43. std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result;
  44. // Hash the name to figure out which bucket this goes into.
  45. size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH;
  46. int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex];
  47. if (CompressedBucketIndex == -1)
  48. return Result;
  49. uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1;
  50. uint32_t StartRecordIndex =
  51. GlobalsTable.HashBuckets[CompressedBucketIndex] / 12;
  52. uint32_t EndRecordIndex = 0;
  53. if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) {
  54. EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1];
  55. } else {
  56. // If this is the last bucket, it consists of all hash records until the end
  57. // of the HashRecords array.
  58. EndRecordIndex = GlobalsTable.HashRecords.size() * 12;
  59. }
  60. EndRecordIndex /= 12;
  61. assert(EndRecordIndex <= GlobalsTable.HashRecords.size());
  62. while (StartRecordIndex < EndRecordIndex) {
  63. PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex];
  64. uint32_t Off = PSH.Off - 1;
  65. codeview::CVSymbol Record = Symbols.readRecord(Off);
  66. if (codeview::getSymbolName(Record) == Name)
  67. Result.push_back(std::make_pair(Off, std::move(Record)));
  68. ++StartRecordIndex;
  69. }
  70. return Result;
  71. }
  72. static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
  73. if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)
  74. return make_error<RawError>(
  75. raw_error_code::feature_unsupported,
  76. "Encountered unsupported globals stream version.");
  77. return Error::success();
  78. }
  79. static Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
  80. BinaryStreamReader &Reader) {
  81. if (Reader.readObject(HashHdr))
  82. return make_error<RawError>(raw_error_code::corrupt_file,
  83. "Stream does not contain a GSIHashHeader.");
  84. if (HashHdr->VerSignature != GSIHashHeader::HdrSignature)
  85. return make_error<RawError>(
  86. raw_error_code::feature_unsupported,
  87. "GSIHashHeader signature (0xffffffff) not found.");
  88. return Error::success();
  89. }
  90. static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
  91. const GSIHashHeader *HashHdr,
  92. BinaryStreamReader &Reader) {
  93. if (auto EC = checkHashHdrVersion(HashHdr))
  94. return EC;
  95. // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have.
  96. // Verify that we can read them all.
  97. if (HashHdr->HrSize % sizeof(PSHashRecord))
  98. return make_error<RawError>(raw_error_code::corrupt_file,
  99. "Invalid HR array size.");
  100. uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
  101. if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
  102. return joinErrors(std::move(EC),
  103. make_error<RawError>(raw_error_code::corrupt_file,
  104. "Error reading hash records."));
  105. return Error::success();
  106. }
  107. static Error
  108. readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
  109. FixedStreamArray<support::ulittle32_t> &HashBitmap,
  110. const GSIHashHeader *HashHdr,
  111. MutableArrayRef<int32_t> BucketMap,
  112. BinaryStreamReader &Reader) {
  113. if (auto EC = checkHashHdrVersion(HashHdr))
  114. return EC;
  115. // Before the actual hash buckets, there is a bitmap of length determined by
  116. // IPHR_HASH.
  117. size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
  118. uint32_t NumBitmapEntries = BitmapSizeInBits / 32;
  119. if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries))
  120. return joinErrors(std::move(EC),
  121. make_error<RawError>(raw_error_code::corrupt_file,
  122. "Could not read a bitmap."));
  123. uint32_t NumBuckets1 = 0;
  124. uint32_t CompressedBucketIdx = 0;
  125. for (uint32_t I = 0; I <= IPHR_HASH; ++I) {
  126. uint8_t WordIdx = I / 32;
  127. uint8_t BitIdx = I % 32;
  128. bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx);
  129. if (IsSet) {
  130. ++NumBuckets1;
  131. BucketMap[I] = CompressedBucketIdx++;
  132. } else {
  133. BucketMap[I] = -1;
  134. }
  135. }
  136. uint32_t NumBuckets = 0;
  137. for (uint32_t B : HashBitmap)
  138. NumBuckets += countPopulation(B);
  139. // Hash buckets follow.
  140. if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
  141. return joinErrors(std::move(EC),
  142. make_error<RawError>(raw_error_code::corrupt_file,
  143. "Hash buckets corrupted."));
  144. return Error::success();
  145. }
  146. Error GSIHashTable::read(BinaryStreamReader &Reader) {
  147. if (auto EC = readGSIHashHeader(HashHdr, Reader))
  148. return EC;
  149. if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
  150. return EC;
  151. if (HashHdr->HrSize > 0)
  152. if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr,
  153. BucketMap, Reader))
  154. return EC;
  155. return Error::success();
  156. }