aboutsummaryrefslogtreecommitdiff
path: root/src/common/dwarf
diff options
context:
space:
mode:
authorjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-02-01 15:01:54 +0000
committerjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-02-01 15:01:54 +0000
commit5e4f6feaf64a5a85690916e5f34a889f9d2a0c45 (patch)
tree53de9b8148cb366219d8a11a540d8f8d47399ce6 /src/common/dwarf
parentBreakpad DWARF support: Remove extraneous breaks following returns in dwarf2r... (diff)
downloadbreakpad-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/dwarf')
-rw-r--r--src/common/dwarf/dwarf2diehandler.cc10
-rw-r--r--src/common/dwarf/dwarf2diehandler.h7
-rw-r--r--src/common/dwarf/dwarf2diehandler_unittest.cc13
-rw-r--r--src/common/dwarf/dwarf2enums.h8
-rw-r--r--src/common/dwarf/dwarf2reader.cc21
-rw-r--r--src/common/dwarf/dwarf2reader.h9
-rw-r--r--src/common/dwarf/dwarf2reader_die_unittest.cc119
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 &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
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 &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(