<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Wed, Nov 9, 2016 at 1:39 PM Greg Clayton <<a href="mailto:clayborg@gmail.com">clayborg@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">clayborg created this revision.<br class="gmail_msg">
clayborg added reviewers: aprantl, dblaikie, echristo, llvm-commits.<br class="gmail_msg">
clayborg set the repository for this revision to rL LLVM.<br class="gmail_msg">
Herald added subscribers: modocache, mgorny, mehdi_amini.<br class="gmail_msg">
<br class="gmail_msg">
If you take a look at large DWARF files you will notice there are not that many abbreviation declarations. For a large binary that has debug inforamtion for LLVM, Clang and LLDB, there are only ~500 abbreviations. By adding some new data members to the DWARFAbbreviationDeclaration class, we can parse DWARF faster and also retrieve DWARF attribute values faster.<br class="gmail_msg">
<br class="gmail_msg">
To speed up the DWARF parsing we do a little extra work when parsing the DWARFAbbreviationDeclaration. We determine if a DWARFAbbreviationDeclaration has a fixed byte size and we remember how to calculate the fixed byte size using a new DWARFAbbreviationDeclaration::FixedSizeInfo structure that is stored as a optional value inside the DWARFAbbreviationDeclaration. When parsing DWARF the DIEs in a compile unit, we must extract DWARFDebugInfoEntryMinimal objects. In the extract function we check this DWARFAbbreviationDeclaration::FixedAttributeSize optional value to see if the byte size if fixed and if so, we can skip all attributes in one operation instead of iterating through all of the attribute/form pairs and individually skipping each one.<br class="gmail_msg">
<br class="gmail_msg">
To speed up attribute value extraction, we get rid of the DWARFFormValue::getFixedFormSizes(...) static function and store an optional byte size with each attribute/form pair. The old DWARFAbbreviationDeclaration::AttributeSpec was:<br class="gmail_msg">
<br class="gmail_msg">
  class DWARFAbbreviationDeclaration {<br class="gmail_msg">
    struct AttributeSpec {<br class="gmail_msg">
      dwarf::Attribute Attr;<br class="gmail_msg">
      dwarf::Form Form;<br class="gmail_msg">
    };<br class="gmail_msg">
  };<br class="gmail_msg">
<br class="gmail_msg">
The new one add an optional ByteSize:<br class="gmail_msg">
<br class="gmail_msg">
  class DWARFAbbreviationDeclaration {<br class="gmail_msg">
  public:<br class="gmail_msg">
    struct AttributeSpec {<br class="gmail_msg">
      dwarf::Attribute Attr;<br class="gmail_msg">
      dwarf::Form Form;<br class="gmail_msg">
      Optional<uint8_t> ByteSize;<br class="gmail_msg">
  };<br class="gmail_msg">
<br class="gmail_msg">
This allows us to not have to calculate fixed form sizes each time we parse a DIE. Member fucntions were added to DWARFAbbreviationDeclaration, DWARFAbbreviationDeclaration::AttributeSpec and DWARFFormValue to centralize the information for each AttributeSpec and to be able to calculate the byte size given a DWARFUnit for a DWARFAbbreviationDeclaration as a whole, and if that fails, each AttributeSpec individually. We also added a map to convert dwarf::Attribute enum values into attribute indexes.<br class="gmail_msg">
<br class="gmail_msg">
These fixes improve DWARF parsing speed by around 7 percent. The test was done by parsing an LLDB build that contains full debug info for LLDB, Clang and LLVM where we grab all compile units, extract all DIEs, traverses each DIE in the hierachy and asking each one for its name by extracting the DW_AT_name attribute (if any) and extracting the DW_AT_low_pc attribute.<br class="gmail_msg">
<br class="gmail_msg">
Previously there we no DWARF unittests that actually tested DWARF parsing. I have added a dwarf_gen::DWARFGenerator class that allows C++ code to easily create DWARF debug info and encode it into. Example code for generating DWARF:<br class="gmail_msg">
<br class="gmail_msg">
  using namespace dwarf_gen;<br class="gmail_msg">
  // Create a DWARF generator object<br class="gmail_msg">
  DWARFGenerator Dwarf;<br class="gmail_msg">
  // Create a compile unit with the specified DWARF version and address size<br class="gmail_msg">
  CompileUnit &CU = Dwarf.appendCompileUnit(Version, AddrSize);<br class="gmail_msg">
<br class="gmail_msg">
  // Append a few attributes to the compile unit's DIE:<br class="gmail_msg">
  CU.Die.appendAttribute({DW_AT_name, DW_FORM_strp, "/tmp/main.c"});<br class="gmail_msg">
  CU.Die.appendAttribute({DW_AT_language, DW_FORM_data2, DW_LANG_C});<br class="gmail_msg">
<br class="gmail_msg">
  // Create a DW_TAG_subprogram DIE as a child of the compile unit DIE and<br class="gmail_msg">
  // add some attributes to it<br class="gmail_msg">
  DIE &SubprogramDie = CU.Die.appendChild(DW_TAG_subprogram);<br class="gmail_msg">
  SubprogramDie.appendAttribute({DW_AT_name, DW_FORM_strp, "main"});<br class="gmail_msg">
  SubprogramDie.appendAttribute({DW_AT_low_pc, DW_FORM_addr, 0x1000U});<br class="gmail_msg">
  SubprogramDie.appendAttribute({DW_AT_high_pc, DW_FORM_addr, 0x2000U});<br class="gmail_msg">
<br class="gmail_msg">
  // Create a DW_TAG_base_type type DIE as a child of the compile unit DIE and<br class="gmail_msg">
  // add some attributes to it<br class="gmail_msg">
  DIE &IntDie = CU.Die.appendChild(DW_TAG_base_type);<br class="gmail_msg">
  IntDie.appendAttribute({DW_AT_name, DW_FORM_strp, "int"});<br class="gmail_msg">
  IntDie.appendAttribute({DW_AT_encoding, DW_FORM_data1, DW_ATE_signed});<br class="gmail_msg">
  IntDie.appendAttribute({DW_AT_byte_size, DW_FORM_data1, 4});<br class="gmail_msg">
<br class="gmail_msg">
  // Create a DW_TAG_base_type type DIE as a child of the subprogram DIE and<br class="gmail_msg">
  // add some attributes to it.<br class="gmail_msg">
  DIE &ArgcDie = SubprogramDie.appendChild(DW_TAG_formal_parameter);<br class="gmail_msg">
  ArgcDie.appendAttribute({DW_AT_name, DW_FORM_strp, "argc"});<br class="gmail_msg">
  ArgcDie.appendAttribute({DW_AT_type, DW_FORM_ref4, &IntDie});<br class="gmail_msg">
<br class="gmail_msg">
  // Generate the DWARF<br class="gmail_msg">
  DWARFSections DwarfSections;<br class="gmail_msg">
  Dwarf.generate(DwarfSections);<br class="gmail_msg">
<br class="gmail_msg">
  // Now make a DWARFContextInMemory using the given section data that was<br class="gmail_msg">
  // generated and use LLVM's DWARF API to extract info from it.<br class="gmail_msg">
  DWARFContextInMemory dwarfContext(<br class="gmail_msg">
      LittleEndian, AddrSize, DwarfSections.getDebugAbbrevData(),<br class="gmail_msg">
      DwarfSections.getDebugInfoData(), DwarfSections.getDebugStrData());<br class="gmail_msg">
  uint32_t NumCUs = dwarfContext.getNumCompileUnits();<br class="gmail_msg">
  DWARFCompileUnit *U = dwarfContext.getCompileUnitAtIndex(0);<br class="gmail_msg">
  DWARFDebugInfoEntryMinimal* Die = U->getUnitDIE(false);<br class="gmail_msg">
<br class="gmail_msg">
The DWARF generator is a separate code base from the parser and that ensures that we don't end up with symmetric encode/decode errors.<br class="gmail_msg"></blockquote><div><br>I'd rather use the same codebase/reduce duplication and test the encoding/decoding from known files/byte dumps if needed.<br><br>Also - it'd be good if the DWARF generation code was the same as the code LLVM uses to generate DWARF, rather than having two generators - unless there's a particularly compelling benefit/difference in use cases.<br><br>(& could be unit tested separately - but the DWARF generation code already in LLVM's pretty well tested in the LLVM tests)<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br class="gmail_msg">
A full suite of unit tests were added that test decoding all DW_FORM_XXX values that we currently support using DWARF version 2, 3, and 4. Tests we also added for parsing a known chunk of DWARF and ensuring that we can extract it, and get the children and sibling DIEs as expected.<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
Repository:<br class="gmail_msg">
  rL LLVM<br class="gmail_msg">
<br class="gmail_msg">
<a href="https://reviews.llvm.org/D26469" rel="noreferrer" class="gmail_msg" target="_blank">https://reviews.llvm.org/D26469</a><br class="gmail_msg">
<br class="gmail_msg">
Files:<br class="gmail_msg">
  include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h<br class="gmail_msg">
  include/llvm/DebugInfo/DWARF/DWARFContext.h<br class="gmail_msg">
  include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h<br class="gmail_msg">
  include/llvm/DebugInfo/DWARF/DWARFFormValue.h<br class="gmail_msg">
  lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp<br class="gmail_msg">
  lib/DebugInfo/DWARF/DWARFContext.cpp<br class="gmail_msg">
  lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp<br class="gmail_msg">
  lib/DebugInfo/DWARF/DWARFFormValue.cpp<br class="gmail_msg">
  lib/DebugInfo/DWARF/DWARFUnit.cpp<br class="gmail_msg">
  unittests/DebugInfo/DWARF/CMakeLists.txt<br class="gmail_msg">
  unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp<br class="gmail_msg">
  unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp<br class="gmail_msg">
  unittests/DebugInfo/DWARF/DWARFGenerator.cpp<br class="gmail_msg">
  unittests/DebugInfo/DWARF/DWARFGenerator.h<br class="gmail_msg">
<br class="gmail_msg">
</blockquote></div></div>