diff --git a/lib/CodeGen/AsmPrinter/DIEHash.cpp b/lib/CodeGen/AsmPrinter/DIEHash.cpp index 783e2d2b399..c9c4541e93e 100644 --- a/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ b/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -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 &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(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::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(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(Result + 8); +} diff --git a/lib/CodeGen/AsmPrinter/DIEHash.h b/lib/CodeGen/AsmPrinter/DIEHash.h index 27e3c576318..3c025bb58ee 100644 --- a/lib/CodeGen/AsmPrinter/DIEHash.h +++ b/lib/CodeGen/AsmPrinter/DIEHash.h @@ -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; }; diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index d3f6ec661e5..e81b933ee59 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -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 +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 index 00000000000..8ece061ba78 --- /dev/null +++ b/test/DebugInfo/X86/fission-hash.ll @@ -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}