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