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 static bool isAnonymous(StringRef Name) { 22 return Name == "<unnamed-tag>" || Name == "__unnamed" || 23 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 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()); 35 36 if (!ForwardRef && !Scoped && !IsAnon) 37 return hashStringV1(Rec.getName()); 38 if (!ForwardRef && HasUniqueName && !IsAnon) 39 return hashStringV1(Rec.getUniqueName()); 40 return hashBufferV8(FullRecord); 41 } 42 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); 58 char Buf[4]; 59 support::endian::write32le(Buf, Deserialized.getUDT().getIndex()); 60 return hashStringV1(StringRef(Buf, 4)); 61 } 62 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); 73 74 case LF_UDT_SRC_LINE: 75 return getSourceLineHash<UdtSourceLineRecord>(Rec); 76 case LF_UDT_MOD_SRC_LINE: 77 return getSourceLineHash<UdtModSourceLineRecord>(Rec); 78 79 default: 80 break; 81 } 82 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(); 89 } 90