GlobalsStream.cpp 6.6 KB

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