aboutsummaryrefslogtreecommitdiff
path: root/src/common/linux/dwarf_cu_to_module_unittest.cc
diff options
context:
space:
mode:
authorjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-02-10 17:55:24 +0000
committerjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-02-10 17:55:24 +0000
commitdd5067f391baee2561404f8e2915429b3d638ff7 (patch)
tree0efae97bac0c1ebb82718de14de38d31b2766229 /src/common/linux/dwarf_cu_to_module_unittest.cc
parentBreakpad Linux dumper: Don't be silly about global functions. (diff)
downloadbreakpad-dd5067f391baee2561404f8e2915429b3d638ff7.tar.xz
Linux DWARF reader: Follow DW_AT_abstract_origin links to find function names.
Without this patch, debugging information like the following will produce FUNC records with no names, because the dumper (correctly) ignores the DW_TAG_subprogram DIEs that lack DW_AT_low_pc/DW_AT_high_pc attributes, but won't follow the DW_AT_abstract_origin link from the DIE that does have code addresses to find its name. <1><168>: Abbrev Number: 5 (DW_TAG_class_type) <169> DW_AT_name : Foo <2><183>: Abbrev Number: 7 (DW_TAG_subprogram) <185> DW_AT_name : Foo <18b> DW_AT_declaration : 1 <1><1b7>: Abbrev Number: 12 (DW_TAG_subprogram) <1b8> DW_AT_specification: <0x183> <1bc> DW_AT_inline : 2 (declared as inline but ignored) <1><1dc>: Abbrev Number: 16 (DW_TAG_subprogram) <1dd> DW_AT_abstract_origin: <0x1b7> <1e1> DW_AT_low_pc : 0x8048578 <1e5> DW_AT_high_pc : 0x8048588 a=dmuir, r=jimblandy git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@520 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/common/linux/dwarf_cu_to_module_unittest.cc')
-rw-r--r--src/common/linux/dwarf_cu_to_module_unittest.cc161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/common/linux/dwarf_cu_to_module_unittest.cc b/src/common/linux/dwarf_cu_to_module_unittest.cc
index d9e4ac0a..4e9062cf 100644
--- a/src/common/linux/dwarf_cu_to_module_unittest.cc
+++ b/src/common/linux/dwarf_cu_to_module_unittest.cc
@@ -43,6 +43,7 @@ using dwarf2reader::DIEHandler;
using dwarf2reader::DwarfTag;
using dwarf2reader::DwarfAttribute;
using dwarf2reader::DwarfForm;
+using dwarf2reader::DwarfInline;
using dwarf2reader::RootDIEHandler;
using google_breakpad::DwarfCUToModule;
using google_breakpad::Module;
@@ -74,6 +75,7 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter {
: DwarfCUToModule::WarningReporter(filename, cu_offset) { }
MOCK_METHOD1(SetCUName, void(const string &name));
MOCK_METHOD2(UnknownSpecification, void(uint64 offset, uint64 target));
+ MOCK_METHOD2(UnknownAbstractOrigin, void(uint64 offset, uint64 target));
MOCK_METHOD1(MissingSection, void(const string &section_name));
MOCK_METHOD1(BadLineInfoOffset, void(uint64 offset));
MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
@@ -128,6 +130,7 @@ class CUFixtureBase {
// these expectations.
EXPECT_CALL(reporter_, SetCUName("compilation-unit-name")).Times(1);
EXPECT_CALL(reporter_, UnknownSpecification(_, _)).Times(0);
+ EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, _)).Times(0);
EXPECT_CALL(reporter_, MissingSection(_)).Times(0);
EXPECT_CALL(reporter_, BadLineInfoOffset(_)).Times(0);
EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0);
@@ -210,6 +213,22 @@ class CUFixtureBase {
uint64 specification, const string &name,
Module::Address address = 0, Module::Address size = 0);
+ // Create an inline DW_TAG_subprogram DIE as a child of PARENT. If
+ // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at
+ // offset SPECIFICATION as its specification. If Name is non-empty, pass it
+ // as the DW_AT_name attribute.
+ void AbstractInstanceDIE(DIEHandler *parent, uint64 offset,
+ DwarfInline type, uint64 specification,
+ const string &name,
+ DwarfForm form = dwarf2reader::DW_FORM_data1);
+
+ // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to
+ // ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty
+ // string, don't provide a DW_AT_name attribute.
+ void DefineInlineInstanceDIE(DIEHandler *parent, const string &name,
+ uint64 origin, Module::Address address,
+ Module::Address size);
+
// The following Test* functions should be called after calling
// this.root_handler_.Finish. After that point, no further calls
// should be made on the handler.
@@ -520,6 +539,83 @@ void CUFixtureBase::DefinitionDIE(DIEHandler *parent,
delete die;
}
+void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent,
+ uint64 offset,
+ DwarfInline type,
+ uint64 specification,
+ const string &name,
+ DwarfForm form) {
+ dwarf2reader::AttributeList attrs;
+ if (specification != 0ULL)
+ attrs.push_back(make_pair(dwarf2reader::DW_AT_specification,
+ dwarf2reader::DW_FORM_ref4));
+ attrs.push_back(make_pair(dwarf2reader::DW_AT_inline, form));
+ if (!name.empty())
+ attrs.push_back(make_pair(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp));
+ dwarf2reader::DIEHandler *die
+ = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram, attrs);
+ ASSERT_TRUE(die != NULL);
+ if (specification != 0ULL)
+ die->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
+ dwarf2reader::DW_FORM_ref4,
+ specification);
+ if (form == dwarf2reader::DW_FORM_sdata) {
+ die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type);
+ } else {
+ die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type);
+ }
+ if (!name.empty())
+ die->ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ name);
+
+ EXPECT_TRUE(die->EndAttributes());
+ die->Finish();
+ delete die;
+}
+
+void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent,
+ const string &name,
+ uint64 origin,
+ Module::Address address,
+ Module::Address size) {
+ dwarf2reader::AttributeList func_attrs;
+ if (!name.empty())
+ func_attrs.push_back(make_pair(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp));
+ func_attrs.push_back(make_pair(dwarf2reader::DW_AT_low_pc,
+ dwarf2reader::DW_FORM_addr));
+ func_attrs.push_back(make_pair(dwarf2reader::DW_AT_high_pc,
+ dwarf2reader::DW_FORM_addr));
+ func_attrs.push_back(make_pair(dwarf2reader::DW_AT_abstract_origin,
+ dwarf2reader::DW_FORM_ref4));
+ PushBackStrangeAttributes(&func_attrs);
+ dwarf2reader::DIEHandler *func
+ = parent->FindChildHandler(0x11c70f94c6e87ccdLL,
+ dwarf2reader::DW_TAG_subprogram,
+ func_attrs);
+ ASSERT_TRUE(func != NULL);
+ if (!name.empty()) {
+ func->ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ name);
+ }
+ func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
+ dwarf2reader::DW_FORM_addr,
+ address);
+ func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
+ dwarf2reader::DW_FORM_addr,
+ address + size);
+ func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin,
+ dwarf2reader::DW_FORM_ref4,
+ origin);
+ ProcessStrangeAttributes(func);
+ EXPECT_TRUE(func->EndAttributes());
+ func->Finish();
+ delete func;
+}
+
void CUFixtureBase::FillFunctions() {
if (functions_filled_)
return;
@@ -629,6 +725,53 @@ TEST_F(Simple, UnusedFileContext) {
reporter_.SetCUName("compilation-unit-name");
}
+TEST_F(Simple, InlineFunction) {
+ PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
+
+ StartCU();
+ AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
+ dwarf2reader::DW_INL_inlined, 0, "inline-name");
+ DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "inline-name",
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+}
+
+TEST_F(Simple, InlineFunctionSignedAttribute) {
+ PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
+
+ StartCU();
+ AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
+ dwarf2reader::DW_INL_inlined, 0, "inline-name",
+ dwarf2reader::DW_FORM_sdata);
+ DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "inline-name",
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+}
+
+TEST_F(Simple, UnknownAbstractOrigin) {
+ EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return());
+ PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
+
+ StartCU();
+ AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
+ dwarf2reader::DW_INL_inlined, 0, "inline-name");
+ DefineInlineInstanceDIE(&root_handler_, "", 1ULL,
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "",
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+}
+
// An address range.
struct Range {
Module::Address start, end;
@@ -1114,6 +1257,24 @@ TEST_F(Specifications, NamedScopeDeclarationParent) {
0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL);
}
+// This test recreates bug 364.
+TEST_F(Specifications, InlineFunction) {
+ PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
+
+ StartCU();
+ DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
+ dwarf2reader::DW_TAG_subprogram, "inline-name");
+ AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
+ dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, "");
+ DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "inline-name",
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+}
+
// Check name construction for a long chain containing each combination of:
// - struct, union, class, namespace
// - direct and definition