diff options
author | jimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2012-02-01 15:01:54 +0000 |
---|---|---|
committer | jimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2012-02-01 15:01:54 +0000 |
commit | 5e4f6feaf64a5a85690916e5f34a889f9d2a0c45 (patch) | |
tree | 53de9b8148cb366219d8a11a540d8f8d47399ce6 /src/common | |
parent | Breakpad DWARF support: Remove extraneous breaks following returns in dwarf2r... (diff) | |
download | breakpad-5e4f6feaf64a5a85690916e5f34a889f9d2a0c45.tar.xz |
Breakpad DWARF: Add support for DWARF 4 attribute forms.
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.
a=jimb, r=ted.mielczarek
Review URL: http://breakpad.appspot.com/343003/
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@912 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/dwarf/dwarf2diehandler.cc | 10 | ||||
-rw-r--r-- | src/common/dwarf/dwarf2diehandler.h | 7 | ||||
-rw-r--r-- | src/common/dwarf/dwarf2diehandler_unittest.cc | 13 | ||||
-rw-r--r-- | src/common/dwarf/dwarf2enums.h | 8 | ||||
-rw-r--r-- | src/common/dwarf/dwarf2reader.cc | 21 | ||||
-rw-r--r-- | src/common/dwarf/dwarf2reader.h | 9 | ||||
-rw-r--r-- | src/common/dwarf/dwarf2reader_die_unittest.cc | 119 |
7 files changed, 179 insertions, 8 deletions
diff --git a/src/common/dwarf/dwarf2diehandler.cc b/src/common/dwarf/dwarf2diehandler.cc index d9abe958..16399547 100644 --- a/src/common/dwarf/dwarf2diehandler.cc +++ b/src/common/dwarf/dwarf2diehandler.cc @@ -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 diff --git a/src/common/dwarf/dwarf2diehandler.h b/src/common/dwarf/dwarf2diehandler.h index 401dd2b8..5d899bf8 100644 --- a/src/common/dwarf/dwarf2diehandler.h +++ b/src/common/dwarf/dwarf2diehandler.h @@ -209,6 +209,9 @@ class DIEHandler { virtual void ProcessAttributeString(enum DwarfAttribute attr, enum DwarfForm form, const std::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 std::string &data); + void ProcessAttributeSignature(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 signature); void EndDIE(uint64 offset); private: diff --git a/src/common/dwarf/dwarf2diehandler_unittest.cc b/src/common/dwarf/dwarf2diehandler_unittest.cc index 1e05fd5c..186b951c 100644 --- a/src/common/dwarf/dwarf2diehandler_unittest.cc +++ b/src/common/dwarf/dwarf2diehandler_unittest.cc @@ -71,6 +71,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 &)); @@ -89,6 +91,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 &)); @@ -244,6 +248,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(_, _, _)) @@ -285,6 +294,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); diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h index 832a17ca..5565d66e 100644 --- a/src/common/dwarf/dwarf2enums.h +++ b/src/common/dwarf/dwarf2enums.h @@ -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 diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index 2d2edf45..fadce485 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -151,6 +151,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: @@ -163,6 +165,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; @@ -192,11 +195,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"); @@ -310,6 +315,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, @@ -347,6 +355,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, @@ -388,6 +400,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); @@ -407,7 +423,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); diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index c43bb93b..cd61fb55 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -393,6 +393,15 @@ class Dwarf2Handler { enum DwarfForm form, const std::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 diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index 50c01dd6..e76fcae7 100644 --- a/src/common/dwarf/dwarf2reader_die_unittest.cc +++ b/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -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( |