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(