[llvm] r272888 - [codeview] Use CVTypeVisitor instead of a hand-written switch-cases.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 16 06:14:42 PDT 2016


Author: ruiu
Date: Thu Jun 16 08:14:42 2016
New Revision: 272888

URL: http://llvm.org/viewvc/llvm-project?rev=272888&view=rev
Log:
[codeview] Use CVTypeVisitor instead of a hand-written switch-cases.

Differential Revision: http://reviews.llvm.org/D21418

Modified:
    llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h
    llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h?rev=272888&r1=272887&r2=272888&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/TpiStream.h Thu Jun 16 08:14:42 2016
@@ -52,6 +52,8 @@ public:
   iterator_range<codeview::CVTypeArray::Iterator> types(bool *HadError) const;
 
 private:
+  Error verifyHashValues();
+
   const PDBFile &Pdb;
   std::unique_ptr<MappedBlockStream> Stream;
   HashFunctionType HashFunction;

Modified: llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp?rev=272888&r1=272887&r2=272888&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp Thu Jun 16 08:14:42 2016
@@ -9,6 +9,7 @@
 
 #include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
 
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/CodeView/StreamReader.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
@@ -24,6 +25,7 @@
 #include "llvm/Support/Endian.h"
 
 using namespace llvm;
+using namespace llvm::codeview;
 using namespace llvm::support;
 using namespace llvm::pdb;
 
@@ -70,77 +72,76 @@ TpiStream::TpiStream(const PDBFile &File
 TpiStream::~TpiStream() {}
 
 // Computes a hash for a given TPI record.
-template <typename T, codeview::TypeRecordKind K>
-static Error getTpiHash(const codeview::CVType &Rec, uint32_t &Hash) {
-  ArrayRef<uint8_t> Data = Rec.Data;
-  ErrorOr<T> Obj = T::deserialize(K, Data);
-  if (Obj.getError())
-    return llvm::make_error<codeview::CodeViewError>(
-        codeview::cv_error_code::corrupt_record);
-
-  auto Opts = static_cast<uint16_t>(Obj->getOptions());
-  if (Opts & static_cast<uint16_t>(codeview::ClassOptions::ForwardReference)) {
-    // We don't know how to calculate a hash value for this yet.
-    // Currently we just skip it.
-    Hash = 0;
-    return Error::success();
+template <typename T> static uint32_t getTpiHash(T &Rec) {
+  auto Opts = static_cast<uint16_t>(Rec.getOptions());
+
+  // We don't know how to calculate a hash value for this yet.
+  // Currently we just skip it.
+  if (Opts & static_cast<uint16_t>(codeview::ClassOptions::ForwardReference))
+    return 0;
+
+  if (!(Opts & static_cast<uint16_t>(codeview::ClassOptions::Scoped)))
+    return hashStringV1(Rec.getName());
+
+  if (Opts & static_cast<uint16_t>(codeview::ClassOptions::HasUniqueName))
+    return hashStringV1(Rec.getUniqueName());
+
+  // This case is not implemented yet.
+  return 0;
+}
+
+namespace {
+class TpiHashVerifier : public CVTypeVisitor<TpiHashVerifier> {
+public:
+  TpiHashVerifier(FixedStreamArray<support::ulittle32_t> &HashValues,
+                  uint32_t NumHashBuckets)
+      : HashValues(HashValues), NumHashBuckets(NumHashBuckets) {}
+
+  void visitUdtSourceLine(TypeLeafKind, UdtSourceLineRecord &Rec) {
+    verifySourceLine(Rec);
+  }
+
+  void visitUdtModSourceLine(TypeLeafKind, UdtModSourceLineRecord &Rec) {
+    verifySourceLine(Rec);
   }
 
-  if (!(Opts & static_cast<uint16_t>(codeview::ClassOptions::Scoped))) {
-    Hash = hashStringV1(Obj->getName());
-    return Error::success();
+  void visitClass(TypeLeafKind, ClassRecord &Rec) { verify(Rec); }
+  void visitEnum(TypeLeafKind, EnumRecord &Rec) { verify(Rec); }
+  void visitInterface(TypeLeafKind, ClassRecord &Rec) { verify(Rec); }
+  void visitStruct(TypeLeafKind, ClassRecord &Rec) { verify(Rec); }
+  void visitUnion(TypeLeafKind, UnionRecord &Rec) { verify(Rec); }
+
+  void visitTypeEnd(TypeLeafKind Leaf, ArrayRef<uint8_t> RecordData) {
+    ++Index;
   }
 
-  if (Opts & static_cast<uint16_t>(codeview::ClassOptions::HasUniqueName)) {
-    Hash = hashStringV1(Obj->getUniqueName());
-    return Error::success();
+private:
+  template <typename T> void verify(T &Rec) {
+    uint32_t Hash = getTpiHash(Rec);
+    if (Hash && Hash % NumHashBuckets != HashValues[Index])
+      parseError();
   }
 
-  // This case is not implemented yet.
-  Hash = 0;
-  return Error::success();
+  template <typename T> void verifySourceLine(T &Rec) {
+    char Buf[4];
+    support::endian::write32le(Buf, Rec.getUDT().getIndex());
+    uint32_t Hash = hashStringV1(StringRef(Buf, 4));
+    if (Hash % NumHashBuckets != HashValues[Index])
+      parseError();
+  }
+
+  FixedStreamArray<support::ulittle32_t> HashValues;
+  uint32_t NumHashBuckets;
+  uint32_t Index = 0;
+};
 }
 
 // Verifies that a given type record matches with a given hash value.
 // Currently we only verify SRC_LINE records.
-static Error verifyTIHash(const codeview::CVType &Rec, uint32_t Expected,
-                          uint32_t NumHashBuckets) {
-  using namespace codeview;
-
-  ArrayRef<uint8_t> D = Rec.Data;
-  uint32_t Hash;
-
-  switch (Rec.Type) {
-  case LF_UDT_SRC_LINE:
-  case LF_UDT_MOD_SRC_LINE:
-    Hash = hashStringV1(StringRef((const char *)D.data(), 4));
-    break;
-  case LF_CLASS:
-    if (auto EC = getTpiHash<ClassRecord, TypeRecordKind::Class>(Rec, Hash))
-      return EC;
-    break;
-  case LF_ENUM:
-    if (auto EC = getTpiHash<EnumRecord, TypeRecordKind::Enum>(Rec, Hash))
-      return EC;
-    break;
-  case LF_INTERFACE:
-    if (auto EC = getTpiHash<ClassRecord, TypeRecordKind::Interface>(Rec, Hash))
-      return EC;
-    break;
-  case LF_STRUCTURE:
-    if (auto EC = getTpiHash<ClassRecord, TypeRecordKind::Struct>(Rec, Hash))
-      return EC;
-    break;
-  case LF_UNION:
-    if (auto EC = getTpiHash<UnionRecord, TypeRecordKind::Union>(Rec, Hash))
-      return EC;
-    break;
-  default:
-    // This pattern is not implemented yet.
-    return Error::success();
-  }
-
-  if (Hash && (Hash % NumHashBuckets) != Expected)
+Error TpiStream::verifyHashValues() {
+  TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets);
+  Verifier.visitTypeStream(TypeRecords);
+  if (Verifier.hadError())
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "Corrupt TPI hash table.");
   return Error::success();
@@ -216,13 +217,8 @@ Error TpiStream::reload() {
 
   // TPI hash table is a parallel array for the type records.
   // Verify that the hash values match with type records.
-  size_t I = 0;
-  bool HasError;
-  for (const codeview::CVType &Rec : types(&HasError)) {
-    if (auto EC = verifyTIHash(Rec, HashValues[I], Header->NumHashBuckets))
-      return EC;
-    ++I;
-  }
+  if (auto EC = verifyHashValues())
+    return EC;
 
   return Error::success();
 }




More information about the llvm-commits mailing list