Add the start of DIE hashing for DWARF4 type units and split dwarf
authorEric Christopher <echristo@gmail.com>
Tue, 13 Aug 2013 01:21:55 +0000 (01:21 +0000)
committerEric Christopher <echristo@gmail.com>
Tue, 13 Aug 2013 01:21:55 +0000 (01:21 +0000)
CUs.

Currently only hashes the name of CUs and the names of any children,
but it's an obvious first step to show the framework. The testcase
should continue to be correct, however, as it's an empty TU.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188243 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/AsmPrinter/DIEHash.cpp
lib/CodeGen/AsmPrinter/DIEHash.h
lib/CodeGen/AsmPrinter/DwarfDebug.cpp
test/DebugInfo/X86/fission-hash.ll [new file with mode: 0644]

index 783e2d2b399c53a8d2084093aa400d060b53d363..c9c4541e93e4ece0b3e4d7e0bb5d8d60df107493 100644 (file)
@@ -102,6 +102,92 @@ void DIEHash::addParentContext(DIE *Parent) {
   }
 }
 
+// Collect all of the attributes for a particular DIE in single structure.
+void DIEHash::collectAttributes(DIE *Die, DIEAttrs Attrs) {
+  const SmallVectorImpl<DIEValue *> &Values = Die->getValues();
+  const DIEAbbrev &Abbrevs = Die->getAbbrev();
+
+#define COLLECT_ATTR(NAME)                                                     \
+  Attrs.NAME.Val = Values[i];                                                  \
+  Attrs.NAME.Desc = &Abbrevs.getData()[i];
+
+  for (size_t i = 0, e = Values.size(); i != e; ++i) {
+    DEBUG(dbgs() << "Attribute: "
+                 << dwarf::AttributeString(Abbrevs.getData()[i].getAttribute())
+                 << " added.\n");
+    switch (Abbrevs.getData()[i].getAttribute()) {
+    case dwarf::DW_AT_name:
+      COLLECT_ATTR(DW_AT_name);
+      break;
+    default:
+      break;
+    }
+  }
+}
+
+// Hash an individual attribute \param Attr based on the type of attribute and
+// the form.
+void DIEHash::hashAttribute(AttrEntry Attr) {
+  const DIEValue *Value = Attr.Val;
+  const DIEAbbrevData *Desc = Attr.Desc;
+
+  // TODO: Add support for types.
+
+  // Add the letter A to the hash.
+  addULEB128('A');
+
+  // Then the attribute code and form.
+  addULEB128(Desc->getAttribute());
+  addULEB128(Desc->getForm());
+
+  // TODO: Add support for additional forms.
+  switch (Desc->getForm()) {
+  case dwarf::DW_FORM_strp:
+    addString(cast<DIEString>(Value)->getString());
+    break;
+  }
+}
+
+// Go through the attributes from \param Attrs in the order specified in 7.27.4
+// and hash them.
+void DIEHash::hashAttributes(DIEAttrs Attrs) {
+#define ADD_ATTR(ATTR)                                                         \
+  {                                                                            \
+    if (ATTR.Val != 0)                                                         \
+      hashAttribute(ATTR);                                                     \
+  }
+
+  // FIXME: Add the rest.
+  ADD_ATTR(Attrs.DW_AT_name);
+}
+
+// Add all of the attributes for \param Die to the hash.
+void DIEHash::addAttributes(DIE *Die) {
+  DIEAttrs Attrs;
+  memset(&Attrs, 0, sizeof(Attrs));
+  collectAttributes(Die, Attrs);
+  hashAttributes(Attrs);
+}
+
+// Compute the hash of a DIE. This is based on the type signature computation
+// given in section 7.27 of the DWARF4 standard. It is the md5 hash of a
+// flattened description of the DIE.
+void DIEHash::computeHash(DIE *Die) {
+
+  // Append the letter 'D', followed by the DWARF tag of the DIE.
+  addULEB128('D');
+  addULEB128(Die->getTag());
+
+  // Add each of the attributes of the DIE.
+  addAttributes(Die);
+
+  // Then hash each of the children of the DIE.
+  for (std::vector<DIE *>::const_iterator I = Die->getChildren().begin(),
+                                          E = Die->getChildren().end();
+       I != E; ++I)
+    computeHash(*I);
+}
+
 /// This is based on the type signature computation given in section 7.27 of the
 /// DWARF4 standard. It is the md5 hash of a flattened description of the DIE
 /// with the exception that we are hashing only the context and the name of the
@@ -134,3 +220,21 @@ uint64_t DIEHash::computeDIEODRSignature(DIE *Die) {
   // appropriately.
   return *reinterpret_cast<support::ulittle64_t *>(Result + 8);
 }
+
+/// This is based on the type signature computation given in section 7.27 of the
+/// DWARF4 standard. It is an md5 hash of the flattened description of the DIE
+/// with the inclusion of the full CU and all top level CU entities.
+uint64_t DIEHash::computeCUSignature(DIE *Die) {
+
+  // Hash the DIE.
+  computeHash(Die);
+
+  // Now return the result.
+  MD5::MD5Result Result;
+  Hash.final(Result);
+
+  // ... take the least significant 8 bytes and return those. Our MD5
+  // implementation always returns its results in little endian, swap bytes
+  // appropriately.
+  return *reinterpret_cast<support::ulittle64_t *>(Result + 8);
+}
index 27e3c576318f8cfa3752818bdcbba8f98fdfc1e7..3c025bb58ee7aec1b261d4c1ea3e3a2d01b1e171 100644 (file)
@@ -20,15 +20,35 @@ class CompileUnit;
 /// \brief An object containing the capability of hashing and adding hash
 /// attributes onto a DIE.
 class DIEHash {
+  // The entry for a particular attribute.
+  struct AttrEntry {
+    const DIEValue *Val;
+    const DIEAbbrevData *Desc;
+  };
+
+  // Collection of all attributes used in hashing a particular DIE.
+  struct DIEAttrs {
+    AttrEntry DW_AT_name;
+  };
+
 public:
   /// \brief Computes the ODR signature
   uint64_t computeDIEODRSignature(DIE *Die);
 
+  /// \brief Computes the CU signature
+  uint64_t computeCUSignature(DIE *Die);
+
   // Helper routines to process parts of a DIE.
- private:
+private:
   /// \brief Adds the parent context of \param Die to the hash.
   void addParentContext(DIE *Die);
-  
+
+  /// \brief Adds the attributes of \param Die to the hash.
+  void addAttributes(DIE *Die);
+
+  /// \brief Computes the full DWARF4 7.27 hash of the DIE.
+  void computeHash(DIE *Die);
+
   // Routines that add DIEValues to the hash.
 private:
   /// \brief Encodes and adds \param Value to the hash as a ULEB128.
@@ -36,7 +56,17 @@ private:
 
   /// \brief Adds \param Str to the hash and includes a NULL byte.
   void addString(StringRef Str);
-  
+
+  /// \brief Collects the attributes of DIE \param Die into the \param Attrs
+  /// structure.
+  void collectAttributes(DIE *Die, DIEAttrs Attrs);
+
+  /// \brief Hashes the attributes in \param Attrs in order.
+  void hashAttributes(DIEAttrs Attrs);
+
+  /// \brief Hashes an individual attribute.
+  void hashAttribute(AttrEntry Attr);
+
 private:
   MD5 Hash;
 };
index d3f6ec661e51fb5c9a86992db85493daa94ef2b2..e81b933ee590afd2f908692e2cd030a781a94fe2 100644 (file)
@@ -67,6 +67,11 @@ GenerateODRHash("generate-odr-hash", cl::Hidden,
                 cl::desc("Add an ODR hash to external type DIEs."),
                 cl::init(false));
 
+static cl::opt<bool>
+GenerateCUHash("generate-cu-hash", cl::Hidden,
+               cl::desc("Add the CU hash as the dwo_id."),
+               cl::init(false));
+
 namespace {
 enum DefaultOnOff {
   Default,
@@ -1024,14 +1029,19 @@ void DwarfDebug::finalizeModuleInfo() {
     // If we're splitting the dwarf out now that we've got the entire
     // CU then construct a skeleton CU based upon it.
     if (useSplitDwarf()) {
+      uint64_t ID = 0;
+      if (GenerateCUHash) {
+        DIEHash CUHash;
+        ID = CUHash.computeCUSignature(TheCU->getCUDie());
+      }
       // This should be a unique identifier when we want to build .dwp files.
       TheCU->addUInt(TheCU->getCUDie(), dwarf::DW_AT_GNU_dwo_id,
-                     dwarf::DW_FORM_data8, 0);
+                     dwarf::DW_FORM_data8, ID);
       // Now construct the skeleton CU associated.
       CompileUnit *SkCU = constructSkeletonCU(CUI->first);
       // This should be a unique identifier when we want to build .dwp files.
       SkCU->addUInt(SkCU->getCUDie(), dwarf::DW_AT_GNU_dwo_id,
-                    dwarf::DW_FORM_data8, 0);
+                    dwarf::DW_FORM_data8, ID);
     }
   }
 
diff --git a/test/DebugInfo/X86/fission-hash.ll b/test/DebugInfo/X86/fission-hash.ll
new file mode 100644 (file)
index 0000000..8ece061
--- /dev/null
@@ -0,0 +1,15 @@
+; RUN: llc -split-dwarf=Enable -generate-cu-hash -O0 %s -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t
+; RUN: llvm-dwarfdump -debug-dump=all %t | FileCheck %s
+
+; The source is an empty file.
+
+; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x356a7d50a77f5177)
+; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x356a7d50a77f5177)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.4 (trunk 188230) (llvm/trunk 188234)", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !2, metadata !2, metadata !2, metadata !"foo.dwo"} ; [ DW_TAG_compile_unit ] [/usr/local/google/home/echristo/tmp/foo.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"foo.c", metadata !"/usr/local/google/home/echristo/tmp"}
+!2 = metadata !{i32 0}
+!3 = metadata !{i32 2, metadata !"Dwarf Version", i32 3}