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>
This commit is contained in:
Sterling Augustine 2020-10-09 09:56:29 -07:00
parent 9ecccc5512
commit a9afca9c06
4 changed files with 89 additions and 14 deletions

View file

@ -162,20 +162,25 @@ enum DwarfForm {
// 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,

View file

@ -160,10 +160,15 @@ void CompilationUnit::ReadAbbrevs() {
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 @@ const uint8_t* CompilationUnit::SkipDIE(const uint8_t* start,
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 @@ const uint8_t* CompilationUnit::SkipAttribute(const uint8_t* start,
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 @@ const uint8_t* CompilationUnit::SkipAttribute(const uint8_t* start,
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 @@ const uint8_t* CompilationUnit::SkipAttribute(const uint8_t* start,
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 @@ void CompilationUnit::ProcessFormStringIndex(
// 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 @@ const uint8_t* CompilationUnit::ProcessAttribute(
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 @@ const uint8_t* CompilationUnit::ProcessAttribute(
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 @@ const uint8_t* CompilationUnit::ProcessAttribute(
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 @@ const uint8_t* CompilationUnit::ProcessAttribute(
// 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 @@ const uint8_t* CompilationUnit::ProcessDIE(uint64_t dieoffset,
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

View file

@ -72,8 +72,19 @@ typedef std::map<string, std::pair<const uint8_t*, uint64_t> > SectionMap;
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 @@ class CompilationUnit {
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

View file

@ -463,6 +463,35 @@ TEST_P(DwarfForms, ref_sig8_not_first) {
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(