}
}
+// 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
// 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);
+}
/// \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.
/// \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;
};
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,
// 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);
}
}
--- /dev/null
+; 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}