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:
parent
9ecccc5512
commit
a9afca9c06
4 changed files with 89 additions and 14 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue