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