LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - TpiHashing.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 80 100 80.0 %
Date: 2018-09-23 13:06:45 Functions: 10 12 83.3 %
Legend: Lines: hit not hit

          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         270 : static bool isAnonymous(StringRef Name) {
      22             :   return Name == "<unnamed-tag>" || Name == "__unnamed" ||
      23         270 :          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         270 : static uint32_t getHashForUdt(const TagRecord &Rec,
      29             :                               ArrayRef<uint8_t> FullRecord) {
      30         270 :   ClassOptions Opts = Rec.getOptions();
      31             :   bool ForwardRef = bool(Opts & ClassOptions::ForwardReference);
      32             :   bool Scoped = bool(Opts & ClassOptions::Scoped);
      33         270 :   bool HasUniqueName = bool(Opts & ClassOptions::HasUniqueName);
      34         270 :   bool IsAnon = HasUniqueName && isAnonymous(Rec.getName());
      35             : 
      36         270 :   if (!ForwardRef && !Scoped && !IsAnon)
      37         157 :     return hashStringV1(Rec.getName());
      38         113 :   if (!ForwardRef && HasUniqueName && !IsAnon)
      39           2 :     return hashStringV1(Rec.getUniqueName());
      40         111 :   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         116 :   uint32_t FullHash = hashStringV1(NameToHash);
      75             :   return TagRecordHash{std::move(Deserialized), FullHash, ThisRecordHash};
      76         232 : }
      77             : 
      78             : template <typename T>
      79             : static Expected<uint32_t> getSourceLineHash(const CVType &Rec) {
      80         116 :   T Deserialized;
      81             :   if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
      82             :                                                Deserialized))
      83             :     return std::move(E);
      84         116 :   char Buf[4];
      85             :   support::endian::write32le(Buf, Deserialized.getUDT().getIndex());
      86             :   return hashStringV1(StringRef(Buf, 4));
      87             : }
      88         116 : 
      89         116 : Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) {
      90             :   switch (Type.kind()) {
      91             :   case LF_CLASS:
      92             :   case LF_STRUCTURE:
      93          58 :   case LF_INTERFACE:
      94          58 :     return getTagRecordHashForUdt<ClassRecord>(Type);
      95          58 :   case LF_UNION:
      96         116 :     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 : }

Generated by: LCOV version 1.13