зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
869bbdab6a
Коммит
4fe8a051b2
|
@ -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 ¤t = 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 ¶ms,
|
||||
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 ¶ms) {
|
||||
void ParseCompilationUnit(const DwarfHeaderParams ¶ms, 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(
|
||||
|
|
Загрузка…
Ссылка в новой задаче