Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 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 | |
Adrian McCarthy | 6b6b8c4 | 2017-01-25 22:38:55 +0000 | [diff] [blame] | 10 | #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 11 | |
Zachary Turner | f8a2e04 | 2017-06-15 23:04:42 +0000 | [diff] [blame] | 12 | #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" |
Adrian McCarthy | 6b6b8c4 | 2017-01-25 22:38:55 +0000 | [diff] [blame] | 13 | #include "llvm/DebugInfo/PDB/Native/Hash.h" |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 14 | #include "llvm/Support/JamCRC.h" |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 15 | |
| 16 | using namespace llvm; |
| 17 | using namespace llvm::codeview; |
| 18 | using namespace llvm::pdb; |
| 19 | |
| 20 | // Corresponds to `fUDTAnon`. |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 21 | static bool isAnonymous(StringRef Name) { |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 22 | return Name == "<unnamed-tag>" || Name == "__unnamed" || |
| 23 | Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed"); |
| 24 | } |
| 25 | |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 26 | // Computes the hash for a user-defined type record. This could be a struct, |
| 27 | // class, union, or enum. |
| 28 | static uint32_t getHashForUdt(const TagRecord &Rec, |
| 29 | ArrayRef<uint8_t> FullRecord) { |
| 30 | ClassOptions Opts = Rec.getOptions(); |
| 31 | bool ForwardRef = bool(Opts & ClassOptions::ForwardReference); |
| 32 | bool Scoped = bool(Opts & ClassOptions::Scoped); |
| 33 | bool HasUniqueName = bool(Opts & ClassOptions::HasUniqueName); |
| 34 | bool IsAnon = HasUniqueName && isAnonymous(Rec.getName()); |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 35 | |
| 36 | if (!ForwardRef && !Scoped && !IsAnon) |
| 37 | return hashStringV1(Rec.getName()); |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 38 | if (!ForwardRef && HasUniqueName && !IsAnon) |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 39 | return hashStringV1(Rec.getUniqueName()); |
| 40 | return hashBufferV8(FullRecord); |
| 41 | } |
| 42 | |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 43 | template <typename T> |
| 44 | static Expected<uint32_t> getHashForUdt(const CVType &Rec) { |
| 45 | T Deserialized; |
| 46 | if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), |
| 47 | Deserialized)) |
| 48 | return std::move(E); |
| 49 | return getHashForUdt(Deserialized, Rec.data()); |
| 50 | } |
| 51 | |
| 52 | template <typename T> |
| 53 | static Expected<uint32_t> getSourceLineHash(const CVType &Rec) { |
| 54 | T Deserialized; |
| 55 | if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), |
| 56 | Deserialized)) |
| 57 | return std::move(E); |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 58 | char Buf[4]; |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 59 | support::endian::write32le(Buf, Deserialized.getUDT().getIndex()); |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 60 | return hashStringV1(StringRef(Buf, 4)); |
| 61 | } |
| 62 | |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 63 | Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) { |
| 64 | switch (Rec.kind()) { |
| 65 | case LF_CLASS: |
| 66 | case LF_STRUCTURE: |
| 67 | case LF_INTERFACE: |
| 68 | return getHashForUdt<ClassRecord>(Rec); |
| 69 | case LF_UNION: |
| 70 | return getHashForUdt<UnionRecord>(Rec); |
| 71 | case LF_ENUM: |
| 72 | return getHashForUdt<EnumRecord>(Rec); |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 73 | |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 74 | case LF_UDT_SRC_LINE: |
| 75 | return getSourceLineHash<UdtSourceLineRecord>(Rec); |
| 76 | case LF_UDT_MOD_SRC_LINE: |
| 77 | return getSourceLineHash<UdtModSourceLineRecord>(Rec); |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 78 | |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 79 | default: |
| 80 | break; |
| 81 | } |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 82 | |
Reid Kleckner | c50349d | 2017-07-18 00:33:45 +0000 | [diff] [blame] | 83 | // Run CRC32 over the bytes. This corresponds to `hashBufv8`. |
| 84 | JamCRC JC(/*Init=*/0U); |
| 85 | ArrayRef<char> Bytes(reinterpret_cast<const char *>(Rec.data().data()), |
| 86 | Rec.data().size()); |
| 87 | JC.update(Bytes); |
| 88 | return JC.getCRC(); |
Zachary Turner | 620961d | 2016-09-14 23:00:02 +0000 | [diff] [blame] | 89 | } |