Support miscelaneous dwarf5 forms.

Most of this is simple, "Read the form, get the data, then
call ProcessAttribute."

Handling DW_FORM_implcit_const is a little trickier, as it
is the only form that stores its value inline in the abbrev
table itself. Add a test for that.

Print errors for supplementary object files.

Change-Id: I0999b039848bded1891998a866e5059acd538a09
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2446627
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h
index b93510a..b9aae05 100644
--- a/src/common/dwarf/dwarf2enums.h
+++ b/src/common/dwarf/dwarf2enums.h
@@ -162,20 +162,25 @@
 
   // Added in DWARF 5:
   DW_FORM_strx = 0x1a,
+  DW_FORM_addrx = 0x1b,
+  DW_FORM_ref_sup4 = 0x1c,
   DW_FORM_strp_sup = 0x1d,
+  DW_FORM_data16 = 0x1e,
   DW_FORM_line_strp = 0x1f,
 
   // DWARF 4, but value out of order.
   DW_FORM_ref_sig8 = 0x20,
 
   // Added in DWARF 5:
+  DW_FORM_implicit_const = 0x21,
+  DW_FORM_loclistx = 0x22,
   DW_FORM_rnglistx = 0x23,
+  DW_FORM_ref_sup8 = 0x24,
   DW_FORM_strx1 = 0x25,
   DW_FORM_strx2 = 0x26,
   DW_FORM_strx3 = 0x27,
   DW_FORM_strx4 = 0x28,
 
-  DW_FORM_addrx = 0x1b,
   DW_FORM_addrx1 = 0x29,
   DW_FORM_addrx2 = 0x2a,
   DW_FORM_addrx3 = 0x2b,
diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc
index f1f4007..367d936 100644
--- a/src/common/dwarf/dwarf2reader.cc
+++ b/src/common/dwarf/dwarf2reader.cc
@@ -160,10 +160,15 @@
       if (nametemp == 0 && formtemp == 0)
         break;
 
-      const enum DwarfAttribute name =
-        static_cast<enum DwarfAttribute>(nametemp);
-      const enum DwarfForm form = static_cast<enum DwarfForm>(formtemp);
-      abbrev.attributes.push_back(std::make_pair(name, form));
+      uint64_t value = 0;
+      if (formtemp == DW_FORM_implicit_const) {
+        value = reader_->ReadUnsignedLEB128(abbrevptr, &len);
+        abbrevptr += len;
+      }
+      AttrForm abbrev_attr(static_cast<enum DwarfAttribute>(nametemp),
+                           static_cast<enum DwarfForm>(formtemp),
+                           value);
+      abbrev.attributes.push_back(abbrev_attr);
     }
     assert(abbrev.number == abbrevs_->size());
     abbrevs_->push_back(abbrev);
@@ -176,7 +181,7 @@
   for (AttributeList::const_iterator i = abbrev.attributes.begin();
        i != abbrev.attributes.end();
        i++)  {
-    start = SkipAttribute(start, i->second);
+    start = SkipAttribute(start, i->form_);
   }
   return start;
 }
@@ -194,6 +199,7 @@
       return SkipAttribute(start, form);
 
     case DW_FORM_flag_present:
+    case DW_FORM_implicit_const:
       return start;
     case DW_FORM_addrx1:
     case DW_FORM_data1:
@@ -213,11 +219,15 @@
     case DW_FORM_ref4:
     case DW_FORM_data4:
     case DW_FORM_strx4:
+    case DW_FORM_ref_sup4:
       return start + 4;
     case DW_FORM_ref8:
     case DW_FORM_data8:
     case DW_FORM_ref_sig8:
+    case DW_FORM_ref_sup8:
       return start + 8;
+    case DW_FORM_data16:
+      return start + 16;
     case DW_FORM_string:
       return start + strlen(reinterpret_cast<const char*>(start)) + 1;
     case DW_FORM_udata:
@@ -227,6 +237,7 @@
     case DW_FORM_GNU_addr_index:
     case DW_FORM_addrx:
     case DW_FORM_rnglistx:
+    case DW_FORM_loclistx:
       reader_->ReadUnsignedLEB128(start, &len);
       return start + len;
 
@@ -458,7 +469,7 @@
 // This is all boring data manipulation and calling of the handler.
 const uint8_t* CompilationUnit::ProcessAttribute(
     uint64_t dieoffset, const uint8_t* start, enum DwarfAttribute attr,
-    enum DwarfForm form) {
+    enum DwarfForm form, uint64_t implicit_const) {
   size_t len;
 
   switch (form) {
@@ -468,7 +479,7 @@
       form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start,
                                                                      &len));
       start += len;
-      return ProcessAttribute(dieoffset, start, attr, form);
+      return ProcessAttribute(dieoffset, start, attr, form, implicit_const);
 
     case DW_FORM_flag_present:
       ProcessAttributeUnsigned(dieoffset, attr, form, 1);
@@ -490,6 +501,10 @@
       ProcessAttributeUnsigned(dieoffset, attr, form,
                                reader_->ReadEightBytes(start));
       return start + 8;
+    case DW_FORM_data16:
+      // This form is designed for an md5 checksum inside line tables.
+      fprintf(stderr, "Unhandled form type: DW_FORM_data16\n");
+      return start + 16;
     case DW_FORM_string: {
       const char* str = reinterpret_cast<const char*>(start);
       ProcessAttributeString(dieoffset, attr, form, str);
@@ -557,7 +572,10 @@
       handler_->ProcessAttributeSignature(dieoffset, attr, form,
                                           reader_->ReadEightBytes(start));
       return start + 8;
-
+    case DW_FORM_implicit_const:
+      handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
+                                         implicit_const);
+      return start;
     case DW_FORM_block1: {
       uint64_t datalen = reader_->ReadOneByte(start);
       handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 1,
@@ -609,7 +627,18 @@
       // No support currently for suplementary object files.
       fprintf(stderr, "Unhandled form type: DW_FORM_strp_sup\n");
       return start + 4;
-
+    case DW_FORM_ref_sup4:
+      // No support currently for suplementary object files.
+      fprintf(stderr, "Unhandled form type: DW_FORM_ref_sup4\n");
+      return start + 4;
+    case DW_FORM_ref_sup8:
+      // No support currently for suplementary object files.
+      fprintf(stderr, "Unhandled form type: DW_FORM_ref_sup8\n");
+      return start + 8;
+    case DW_FORM_loclistx:
+      ProcessAttributeUnsigned(dieoffset, attr, form,
+                               reader_->ReadUnsignedLEB128(start, &len));
+      return start + len;
     case DW_FORM_strx:
     case DW_FORM_GNU_str_index: {
       uint64_t str_index = reader_->ReadUnsignedLEB128(start, &len);
@@ -673,7 +702,7 @@
   for (AttributeList::const_iterator i = abbrev.attributes.begin();
        i != abbrev.attributes.end();
        i++)  {
-    start = ProcessAttribute(dieoffset, start, i->first, i->second);
+    start = ProcessAttribute(dieoffset, start, i->attr_, i->form_, i->value_);
   }
 
   // If this is a compilation unit in a split DWARF object, verify that
diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h
index d041dd8..8da190c 100644
--- a/src/common/dwarf/dwarf2reader.h
+++ b/src/common/dwarf/dwarf2reader.h
@@ -72,8 +72,19 @@
 const SectionMap::const_iterator GetSectionByName(const SectionMap&
                                                   sections, const char* name);
 
-typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> >
-    AttributeList;
+// Most of the time, this struct functions as a simple attribute and form pair.
+// However, Dwarf5 DW_FORM_implicit_const means that a form may have its value
+// in line in the abbrev table, and that value must be associated with the
+// pair until the attr's value is needed.
+struct AttrForm {
+  AttrForm(enum DwarfAttribute attr, enum DwarfForm form, uint64_t value) :
+      attr_(attr), form_(form), value_(value) { }
+
+  enum DwarfAttribute attr_;
+  enum DwarfForm form_;
+  uint64_t value_;
+};
+typedef std::list<AttrForm> AttributeList;
 typedef AttributeList::iterator AttributeIterator;
 typedef AttributeList::const_iterator ConstAttributeIterator;
 
@@ -527,7 +538,8 @@
   const uint8_t* ProcessAttribute(uint64_t dieoffset,
                                   const uint8_t* start,
                                   enum DwarfAttribute attr,
-                                  enum DwarfForm form);
+                                  enum DwarfForm form,
+                                  uint64_t implicit_const);
 
   // Called when we have an attribute with unsigned data to give to
   // our handler.  The attribute is for the DIE at OFFSET from the
diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc
index 0d8811b..57b8f71 100644
--- a/src/common/dwarf/dwarf2reader_die_unittest.cc
+++ b/src/common/dwarf/dwarf2reader_die_unittest.cc
@@ -463,6 +463,35 @@
   ParseCompilationUnit(GetParam(), 98);
 }
 
+TEST_P(DwarfForms, implicit_const) {
+  const DwarfHeaderParams& params = GetParam();
+  const uint64_t implicit_constant_value = 0x1234;
+  // Create the abbreviation table.
+  Label abbrev_table = abbrevs.Here();
+  abbrevs.Abbrev(1, (DwarfTag) 0x253e7b2b, dwarf2reader::DW_children_no)
+      .Attribute((DwarfAttribute) 0xd708d908,
+                 dwarf2reader::DW_FORM_implicit_const)
+      .ULEB128(implicit_constant_value);
+  abbrevs.EndAbbrev().EndTable();
+
+  info.set_format_size(params.format_size);
+  info.set_endianness(params.endianness);
+  info.Header(params.version, abbrev_table, params.address_size)
+          .ULEB128(1);                    // abbrev code
+  info.Finish();
+
+  ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
+  EXPECT_CALL(handler,
+              ProcessAttributeUnsigned(_, (DwarfAttribute) 0xd708d908,
+                                       dwarf2reader::DW_FORM_implicit_const,
+                                       implicit_constant_value))
+      .InSequence(s)
+      .WillOnce(Return());
+  ExpectEndCompilationUnit();
+
+  ParseCompilationUnit(GetParam());
+}
+
 // Tests for the other attribute forms could go here.
 
 INSTANTIATE_TEST_CASE_P(