TpiHashing.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. //===- TpiHashing.cpp -----------------------------------------------------===//
  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/TpiHashing.h"
  9. #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
  10. #include "llvm/DebugInfo/PDB/Native/Hash.h"
  11. #include "llvm/Support/CRC.h"
  12. using namespace llvm;
  13. using namespace llvm::codeview;
  14. using namespace llvm::pdb;
  15. // Corresponds to `fUDTAnon`.
  16. static bool isAnonymous(StringRef Name) {
  17. return Name == "<unnamed-tag>" || Name == "__unnamed" ||
  18. Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed");
  19. }
  20. // Computes the hash for a user-defined type record. This could be a struct,
  21. // class, union, or enum.
  22. static uint32_t getHashForUdt(const TagRecord &Rec,
  23. ArrayRef<uint8_t> FullRecord) {
  24. ClassOptions Opts = Rec.getOptions();
  25. bool ForwardRef = bool(Opts & ClassOptions::ForwardReference);
  26. bool Scoped = bool(Opts & ClassOptions::Scoped);
  27. bool HasUniqueName = bool(Opts & ClassOptions::HasUniqueName);
  28. bool IsAnon = HasUniqueName && isAnonymous(Rec.getName());
  29. if (!ForwardRef && !Scoped && !IsAnon)
  30. return hashStringV1(Rec.getName());
  31. if (!ForwardRef && HasUniqueName && !IsAnon)
  32. return hashStringV1(Rec.getUniqueName());
  33. return hashBufferV8(FullRecord);
  34. }
  35. template <typename T>
  36. static Expected<uint32_t> getHashForUdt(const CVType &Rec) {
  37. T Deserialized;
  38. if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
  39. Deserialized))
  40. return std::move(E);
  41. return getHashForUdt(Deserialized, Rec.data());
  42. }
  43. template <typename T>
  44. static Expected<TagRecordHash> getTagRecordHashForUdt(const CVType &Rec) {
  45. T Deserialized;
  46. if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
  47. Deserialized))
  48. return std::move(E);
  49. ClassOptions Opts = Deserialized.getOptions();
  50. bool ForwardRef = bool(Opts & ClassOptions::ForwardReference);
  51. uint32_t ThisRecordHash = getHashForUdt(Deserialized, Rec.data());
  52. // If we don't have a forward ref we can't compute the hash of it from the
  53. // full record because it requires hashing the entire buffer.
  54. if (!ForwardRef)
  55. return TagRecordHash{std::move(Deserialized), ThisRecordHash, 0};
  56. bool Scoped = bool(Opts & ClassOptions::Scoped);
  57. StringRef NameToHash =
  58. Scoped ? Deserialized.getUniqueName() : Deserialized.getName();
  59. uint32_t FullHash = hashStringV1(NameToHash);
  60. return TagRecordHash{std::move(Deserialized), FullHash, ThisRecordHash};
  61. }
  62. template <typename T>
  63. static Expected<uint32_t> getSourceLineHash(const CVType &Rec) {
  64. T Deserialized;
  65. if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
  66. Deserialized))
  67. return std::move(E);
  68. char Buf[4];
  69. support::endian::write32le(Buf, Deserialized.getUDT().getIndex());
  70. return hashStringV1(StringRef(Buf, 4));
  71. }
  72. Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) {
  73. switch (Type.kind()) {
  74. case LF_CLASS:
  75. case LF_STRUCTURE:
  76. case LF_INTERFACE:
  77. return getTagRecordHashForUdt<ClassRecord>(Type);
  78. case LF_UNION:
  79. return getTagRecordHashForUdt<UnionRecord>(Type);
  80. case LF_ENUM:
  81. return getTagRecordHashForUdt<EnumRecord>(Type);
  82. default:
  83. assert(false && "Type is not a tag record!");
  84. }
  85. return make_error<StringError>("Invalid record type",
  86. inconvertibleErrorCode());
  87. }
  88. Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) {
  89. switch (Rec.kind()) {
  90. case LF_CLASS:
  91. case LF_STRUCTURE:
  92. case LF_INTERFACE:
  93. return getHashForUdt<ClassRecord>(Rec);
  94. case LF_UNION:
  95. return getHashForUdt<UnionRecord>(Rec);
  96. case LF_ENUM:
  97. return getHashForUdt<EnumRecord>(Rec);
  98. case LF_UDT_SRC_LINE:
  99. return getSourceLineHash<UdtSourceLineRecord>(Rec);
  100. case LF_UDT_MOD_SRC_LINE:
  101. return getSourceLineHash<UdtModSourceLineRecord>(Rec);
  102. default:
  103. break;
  104. }
  105. // Run CRC32 over the bytes. This corresponds to `hashBufv8`.
  106. JamCRC JC(/*Init=*/0U);
  107. JC.update(Rec.data());
  108. return JC.getCRC();
  109. }