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