TpiStream.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. //===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===//
  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. #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
  9. #include "llvm/ADT/iterator_range.h"
  10. #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
  11. #include "llvm/DebugInfo/CodeView/RecordName.h"
  12. #include "llvm/DebugInfo/CodeView/TypeRecord.h"
  13. #include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
  14. #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
  15. #include "llvm/DebugInfo/PDB/Native/Hash.h"
  16. #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
  17. #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
  18. #include "llvm/DebugInfo/PDB/Native/RawError.h"
  19. #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
  20. #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
  21. #include "llvm/Support/BinaryStreamReader.h"
  22. #include "llvm/Support/Endian.h"
  23. #include "llvm/Support/Error.h"
  24. #include <algorithm>
  25. #include <cstdint>
  26. #include <vector>
  27. using namespace llvm;
  28. using namespace llvm::codeview;
  29. using namespace llvm::support;
  30. using namespace llvm::msf;
  31. using namespace llvm::pdb;
  32. TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
  33. : Pdb(File), Stream(std::move(Stream)) {}
  34. TpiStream::~TpiStream() = default;
  35. Error TpiStream::reload() {
  36. BinaryStreamReader Reader(*Stream);
  37. if (Reader.bytesRemaining() < sizeof(TpiStreamHeader))
  38. return make_error<RawError>(raw_error_code::corrupt_file,
  39. "TPI Stream does not contain a header.");
  40. if (Reader.readObject(Header))
  41. return make_error<RawError>(raw_error_code::corrupt_file,
  42. "TPI Stream does not contain a header.");
  43. if (Header->Version != PdbTpiV80)
  44. return make_error<RawError>(raw_error_code::corrupt_file,
  45. "Unsupported TPI Version.");
  46. if (Header->HeaderSize != sizeof(TpiStreamHeader))
  47. return make_error<RawError>(raw_error_code::corrupt_file,
  48. "Corrupt TPI Header size.");
  49. if (Header->HashKeySize != sizeof(ulittle32_t))
  50. return make_error<RawError>(raw_error_code::corrupt_file,
  51. "TPI Stream expected 4 byte hash key size.");
  52. if (Header->NumHashBuckets < MinTpiHashBuckets ||
  53. Header->NumHashBuckets > MaxTpiHashBuckets)
  54. return make_error<RawError>(raw_error_code::corrupt_file,
  55. "TPI Stream Invalid number of hash buckets.");
  56. // The actual type records themselves come from this stream
  57. if (auto EC =
  58. Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes))
  59. return EC;
  60. BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData);
  61. if (auto EC =
  62. RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size()))
  63. return EC;
  64. // Hash indices, hash values, etc come from the hash stream.
  65. if (Header->HashStreamIndex != kInvalidStreamIndex) {
  66. auto HS = Pdb.safelyCreateIndexedStream(Header->HashStreamIndex);
  67. if (!HS) {
  68. consumeError(HS.takeError());
  69. return make_error<RawError>(raw_error_code::corrupt_file,
  70. "Invalid TPI hash stream index.");
  71. }
  72. BinaryStreamReader HSR(**HS);
  73. // There should be a hash value for every type record, or no hashes at all.
  74. uint32_t NumHashValues =
  75. Header->HashValueBuffer.Length / sizeof(ulittle32_t);
  76. if (NumHashValues != getNumTypeRecords() && NumHashValues != 0)
  77. return make_error<RawError>(
  78. raw_error_code::corrupt_file,
  79. "TPI hash count does not match with the number of type records.");
  80. HSR.setOffset(Header->HashValueBuffer.Off);
  81. if (auto EC = HSR.readArray(HashValues, NumHashValues))
  82. return EC;
  83. HSR.setOffset(Header->IndexOffsetBuffer.Off);
  84. uint32_t NumTypeIndexOffsets =
  85. Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
  86. if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
  87. return EC;
  88. if (Header->HashAdjBuffer.Length > 0) {
  89. HSR.setOffset(Header->HashAdjBuffer.Off);
  90. if (auto EC = HashAdjusters.load(HSR))
  91. return EC;
  92. }
  93. HashStream = std::move(*HS);
  94. }
  95. Types = std::make_unique<LazyRandomTypeCollection>(
  96. TypeRecords, getNumTypeRecords(), getTypeIndexOffsets());
  97. return Error::success();
  98. }
  99. PdbRaw_TpiVer TpiStream::getTpiVersion() const {
  100. uint32_t Value = Header->Version;
  101. return static_cast<PdbRaw_TpiVer>(Value);
  102. }
  103. uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; }
  104. uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }
  105. uint32_t TpiStream::getNumTypeRecords() const {
  106. return TypeIndexEnd() - TypeIndexBegin();
  107. }
  108. uint16_t TpiStream::getTypeHashStreamIndex() const {
  109. return Header->HashStreamIndex;
  110. }
  111. uint16_t TpiStream::getTypeHashStreamAuxIndex() const {
  112. return Header->HashAuxStreamIndex;
  113. }
  114. uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; }
  115. uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
  116. void TpiStream::buildHashMap() {
  117. if (!HashMap.empty())
  118. return;
  119. if (HashValues.empty())
  120. return;
  121. HashMap.resize(Header->NumHashBuckets);
  122. TypeIndex TIB{Header->TypeIndexBegin};
  123. TypeIndex TIE{Header->TypeIndexEnd};
  124. while (TIB < TIE) {
  125. uint32_t HV = HashValues[TIB.toArrayIndex()];
  126. HashMap[HV].push_back(TIB++);
  127. }
  128. }
  129. std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const {
  130. if (!supportsTypeLookup())
  131. const_cast<TpiStream*>(this)->buildHashMap();
  132. uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets;
  133. if (Bucket > HashMap.size())
  134. return {};
  135. std::vector<TypeIndex> Result;
  136. for (TypeIndex TI : HashMap[Bucket]) {
  137. std::string ThisName = computeTypeName(*Types, TI);
  138. if (ThisName == Name)
  139. Result.push_back(TI);
  140. }
  141. return Result;
  142. }
  143. bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
  144. Expected<TypeIndex>
  145. TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const {
  146. if (!supportsTypeLookup())
  147. const_cast<TpiStream*>(this)->buildHashMap();
  148. CVType F = Types->getType(ForwardRefTI);
  149. if (!isUdtForwardRef(F))
  150. return ForwardRefTI;
  151. Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);
  152. if (!ForwardTRH)
  153. return ForwardTRH.takeError();
  154. uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;
  155. for (TypeIndex TI : HashMap[BucketIdx]) {
  156. CVType CVT = Types->getType(TI);
  157. if (CVT.kind() != F.kind())
  158. continue;
  159. Expected<TagRecordHash> FullTRH = hashTagRecord(CVT);
  160. if (!FullTRH)
  161. return FullTRH.takeError();
  162. if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)
  163. continue;
  164. TagRecord &ForwardTR = ForwardTRH->getRecord();
  165. TagRecord &FullTR = FullTRH->getRecord();
  166. if (!ForwardTR.hasUniqueName()) {
  167. if (ForwardTR.getName() == FullTR.getName())
  168. return TI;
  169. continue;
  170. }
  171. if (!FullTR.hasUniqueName())
  172. continue;
  173. if (ForwardTR.getUniqueName() == FullTR.getUniqueName())
  174. return TI;
  175. }
  176. return ForwardRefTI;
  177. }
  178. codeview::CVType TpiStream::getType(codeview::TypeIndex Index) {
  179. assert(!Index.isSimple());
  180. return Types->getType(Index);
  181. }
  182. BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const {
  183. return TypeRecordsSubstream;
  184. }
  185. FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const {
  186. return HashValues;
  187. }
  188. FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const {
  189. return TypeIndexOffsets;
  190. }
  191. HashTable<support::ulittle32_t> &TpiStream::getHashAdjusters() {
  192. return HashAdjusters;
  193. }
  194. CVTypeRange TpiStream::types(bool *HadError) const {
  195. return make_range(TypeRecords.begin(HadError), TypeRecords.end());
  196. }
  197. Error TpiStream::commit() { return Error::success(); }