Bug 714129: Breakpad DWARF: Add support for DWARF 4 attribute forms. r=ted

This patch allows Breakpad's DWARF reader to at least read or skip
attributes using the new forms defined in version 4 of the DWARF
specification, instead of crashing.

Attributes encoded using DW_FORM_flag_present, DW_FORM_sec_offset, and
DW_FORM_exprloc should work fine now. However, compilation units using
DW_FORM_ref_sig8 to refer to types in .debug_types will need further work
to support. (GCC 4.6.2 does not emit .debug_types sections.)

Specifically:

- dwarf2reader::DwarfForm gets new values.
- dwarf2reader::Dwarf2Handler and dwarf2reader::DIEHandler get new handler
  methods, named ProcessAttributeSignature, for DW_FORM_ref_sig8 attributes.
- dwarf2reader::CompilationUnit reads DW_FORM_ref_sig8 attributes, and
  passes them to ProcessAttributeSignature. It also gets support for
  DW_FORM_sec_offset, DW_FORM_exprloc, and DW_FORM_flag_present, using the
  existing appropriate ProcessAttribute* methods.
- dwarf2reader::DIEDispatcher passes through ProcessAttributeSignature
  attributes to its DIEHandler.
- Unit tests are updated.
This commit is contained in:
Jim Blandy 2012-02-01 11:27:33 -08:00
Родитель 869bbdab6a
Коммит 4fe8a051b2
7 изменённых файлов: 179 добавлений и 8 удалений

Просмотреть файл

@ -183,4 +183,14 @@ void DIEDispatcher::ProcessAttributeString(uint64 offset,
current.handler_->ProcessAttributeString(attr, form, data);
}
void DIEDispatcher::ProcessAttributeSignature(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 signature) {
HandlerStack &current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeSignature(attr, form, signature);
}
} // namespace dwarf2reader

Просмотреть файл

@ -209,6 +209,9 @@ class DIEHandler {
virtual void ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
const string& data) { }
virtual void ProcessAttributeSignature(enum DwarfAttribute attr,
enum DwarfForm form,
uint64 signture) { }
// Once we have reported all the DIE's attributes' values, we call
// this member function. If it returns false, we skip all the DIE's
@ -314,6 +317,10 @@ class DIEDispatcher: public Dwarf2Handler {
enum DwarfAttribute attr,
enum DwarfForm form,
const string &data);
void ProcessAttributeSignature(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 signature);
void EndDIE(uint64 offset);
private:

Просмотреть файл

@ -65,6 +65,8 @@ class MockDIEHandler: public DIEHandler {
void(DwarfAttribute, DwarfForm, const char *, uint64));
MOCK_METHOD3(ProcessAttributeString,
void(DwarfAttribute, DwarfForm, const string &));
MOCK_METHOD3(ProcessAttributeSignature,
void(DwarfAttribute, DwarfForm, uint64));
MOCK_METHOD0(EndAttributes, bool());
MOCK_METHOD3(FindChildHandler, DIEHandler *(uint64, DwarfTag,
const AttributeList &));
@ -83,6 +85,8 @@ class MockRootDIEHandler: public RootDIEHandler {
void(DwarfAttribute, DwarfForm, const char *, uint64));
MOCK_METHOD3(ProcessAttributeString,
void(DwarfAttribute, DwarfForm, const string &));
MOCK_METHOD3(ProcessAttributeSignature,
void(DwarfAttribute, DwarfForm, uint64));
MOCK_METHOD0(EndAttributes, bool());
MOCK_METHOD3(FindChildHandler, DIEHandler *(uint64, DwarfTag,
const AttributeList &));
@ -238,6 +242,11 @@ TEST(Dwarf2DIEHandler, PassAttributeValues) {
(DwarfForm) 0x15762fec,
StrEq(str)))
.WillOnce(Return());
EXPECT_CALL(mock_root_handler,
ProcessAttributeSignature((DwarfAttribute) 0x58790d72,
(DwarfForm) 0x4159f138,
0x94682463613e6a5fULL))
.WillOnce(Return());
EXPECT_CALL(mock_root_handler, EndAttributes())
.WillOnce(Return(true));
EXPECT_CALL(mock_root_handler, FindChildHandler(_, _, _))
@ -279,6 +288,10 @@ TEST(Dwarf2DIEHandler, PassAttributeValues) {
(DwarfAttribute) 0x310ed065,
(DwarfForm) 0x15762fec,
str);
die_dispatcher.ProcessAttributeSignature(0xe2222da01e29f2a9LL,
(DwarfAttribute) 0x58790d72,
(DwarfForm) 0x4159f138,
0x94682463613e6a5fULL);
// Finish the root DIE (and thus the CU).
die_dispatcher.EndDIE(0xe2222da01e29f2a9LL);

Просмотреть файл

@ -143,7 +143,13 @@ enum DwarfForm {
DW_FORM_ref4 = 0x13,
DW_FORM_ref8 = 0x14,
DW_FORM_ref_udata = 0x15,
DW_FORM_indirect = 0x16
DW_FORM_indirect = 0x16,
// Added in DWARF 4:
DW_FORM_sec_offset = 0x17,
DW_FORM_exprloc = 0x18,
DW_FORM_flag_present = 0x19,
DW_FORM_ref_sig8 = 0x20
};
// Attribute names and codes

Просмотреть файл

@ -152,6 +152,8 @@ const char* CompilationUnit::SkipAttribute(const char* start,
start += len;
return SkipAttribute(start, form);
case DW_FORM_flag_present:
return start;
case DW_FORM_data1:
case DW_FORM_flag:
case DW_FORM_ref1:
@ -164,6 +166,7 @@ const char* CompilationUnit::SkipAttribute(const char* start,
return start + 4;
case DW_FORM_ref8:
case DW_FORM_data8:
case DW_FORM_ref_sig8:
return start + 8;
case DW_FORM_string:
return start + strlen(start) + 1;
@ -193,11 +196,13 @@ const char* CompilationUnit::SkipAttribute(const char* start,
return start + 2 + reader_->ReadTwoBytes(start);
case DW_FORM_block4:
return start + 4 + reader_->ReadFourBytes(start);
case DW_FORM_block: {
case DW_FORM_block:
case DW_FORM_exprloc: {
uint64 size = reader_->ReadUnsignedLEB128(start, &len);
return start + size + len;
}
case DW_FORM_strp:
case DW_FORM_sec_offset:
return start + reader_->OffsetSize();
}
fprintf(stderr,"Unhandled form type");
@ -311,6 +316,9 @@ const char* CompilationUnit::ProcessAttribute(
start += len;
return ProcessAttribute(dieoffset, start, attr, form);
case DW_FORM_flag_present:
handler_->ProcessAttributeUnsigned(dieoffset, attr, form, 1);
return start;
case DW_FORM_data1:
case DW_FORM_flag:
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
@ -348,6 +356,10 @@ const char* CompilationUnit::ProcessAttribute(
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadAddress(start));
return start + reader_->AddressSize();
case DW_FORM_sec_offset:
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadOffset(start));
return start + reader_->OffsetSize();
case DW_FORM_ref1:
handler_->ProcessAttributeReference(dieoffset, attr, form,
@ -389,6 +401,10 @@ const char* CompilationUnit::ProcessAttribute(
return start + reader_->OffsetSize();
}
break;
case DW_FORM_ref_sig8:
handler_->ProcessAttributeSignature(dieoffset, attr, form,
reader_->ReadEightBytes(start));
return start + 8;
case DW_FORM_block1: {
uint64 datalen = reader_->ReadOneByte(start);
@ -408,7 +424,8 @@ const char* CompilationUnit::ProcessAttribute(
datalen);
return start + 4 + datalen;
}
case DW_FORM_block: {
case DW_FORM_block:
case DW_FORM_exprloc: {
uint64 datalen = reader_->ReadUnsignedLEB128(start, &len);
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + len,
datalen);

Просмотреть файл

@ -394,6 +394,15 @@ class Dwarf2Handler {
enum DwarfForm form,
const string& data) { }
// Called when we have an attribute whose value is the 64-bit signature
// of a type unit in the .debug_types section. OFFSET is the offset of
// the DIE whose attribute we're reporting. ATTR and FORM are the
// attribute's name and form. SIGNATURE is the type unit's signature.
virtual void ProcessAttributeSignature(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 signature) { }
// Called when finished processing the DIE at OFFSET.
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
// before ends of the previous DIE, as we process children before

Просмотреть файл

@ -99,6 +99,10 @@ class MockDwarf2Handler: public Dwarf2Handler {
enum DwarfAttribute attr,
enum DwarfForm form,
const std::string& data));
MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset,
DwarfAttribute attr,
enum DwarfForm form,
uint64 signature));
MOCK_METHOD1(EndDIE, void(uint64 offset));
};
@ -251,9 +255,9 @@ struct DwarfFormsFixture: public DIEFixture {
// containing one childless DIE of the given tag, in the sequence s. Stop
// just before the expectations.
void ExpectBeginCompilationUnit(const DwarfHeaderParams &params,
DwarfTag tag) {
DwarfTag tag, uint64 offset=0) {
EXPECT_CALL(handler,
StartCompilationUnit(0, params.address_size,
StartCompilationUnit(offset, params.address_size,
params.format_size, _,
params.version))
.InSequence(s)
@ -269,11 +273,11 @@ struct DwarfFormsFixture: public DIEFixture {
.WillOnce(Return());
}
void ParseCompilationUnit(const DwarfHeaderParams &params) {
void ParseCompilationUnit(const DwarfHeaderParams &params, uint64 offset=0) {
ByteReader byte_reader(params.endianness == kLittleEndian ?
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
CompilationUnit parser(MakeSectionMap(), 0, &byte_reader, &handler);
EXPECT_EQ(parser.Start(), info_contents.size());
CompilationUnit parser(MakeSectionMap(), offset, &byte_reader, &handler);
EXPECT_EQ(offset + parser.Start(), info_contents.size());
}
// The sequence to which the fixture's methods append expectations.
@ -347,6 +351,111 @@ TEST_P(DwarfForms, block2) {
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, flag_present) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2,
(DwarfAttribute) 0x359d1972,
dwarf2reader::DW_FORM_flag_present);
// DW_FORM_flag_present occupies no space in the DIE.
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2);
EXPECT_CALL(handler,
ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972,
dwarf2reader::DW_FORM_flag_present,
1))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, sec_offset) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
(DwarfAttribute) 0xa060bfd1,
dwarf2reader::DW_FORM_sec_offset);
u_int64_t value;
if (GetParam().format_size == 4) {
value = 0xacc9c388;
info.D32(value);
} else {
value = 0xcffe5696ffe3ed0aULL;
info.D64(value);
}
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689);
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1,
dwarf2reader::DW_FORM_sec_offset,
value))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, exprloc) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb,
(DwarfAttribute) 0xba3ae5cb,
dwarf2reader::DW_FORM_exprloc);
info.ULEB128(29)
.Append(29, 173);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb);
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb,
dwarf2reader::DW_FORM_exprloc,
Pointee(173), 29))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, ref_sig8) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
(DwarfAttribute) 0xd708d908,
dwarf2reader::DW_FORM_ref_sig8);
info.D64(0xf72fa0cb6ddcf9d6ULL);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
dwarf2reader::DW_FORM_ref_sig8,
0xf72fa0cb6ddcf9d6ULL))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
// A value passed to ProcessAttributeSignature is just an absolute number,
// not an offset within the compilation unit as most of the other
// DW_FORM_ref forms are. Check that the reader doesn't try to apply any
// offset to the signature, by reading it from a compilation unit that does
// not start at the beginning of the section.
TEST_P(DwarfForms, ref_sig8_not_first) {
info.Append(98, '*');
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
(DwarfAttribute) 0xd708d908,
dwarf2reader::DW_FORM_ref_sig8);
info.D64(0xf72fa0cb6ddcf9d6ULL);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98);
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
dwarf2reader::DW_FORM_ref_sig8,
0xf72fa0cb6ddcf9d6ULL))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam(), 98);
}
// Tests for the other attribute forms could go here.
INSTANTIATE_TEST_CASE_P(