From a8426a5c6607c5f3384e948c74e7cab29c3809ff Mon Sep 17 00:00:00 2001 From: jimblandy Date: Tue, 8 Jan 2013 02:14:44 +0000 Subject: [PATCH] DWARF can store DW_AT_high_pc as either an address or a constant. In the latter case it's the length of the function. breakpad always treats it as an address. a=mattdr, r=jimb git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1094 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/common/dwarf_cu_to_module.cc | 15 +++++- src/common/dwarf_cu_to_module_unittest.cc | 65 +++++++++++++++++------ 2 files changed, 61 insertions(+), 19 deletions(-) diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc index 04b8843f..127beacb 100644 --- a/src/common/dwarf_cu_to_module.cc +++ b/src/common/dwarf_cu_to_module.cc @@ -385,7 +385,8 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { FuncHandler(CUContext *cu_context, DIEContext *parent_context, uint64 offset) : GenericDIEHandler(cu_context, parent_context, offset), - low_pc_(0), high_pc_(0), abstract_origin_(NULL), inline_(false) { } + low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr), + abstract_origin_(NULL), inline_(false) { } void ProcessAttributeUnsigned(enum DwarfAttribute attr, enum DwarfForm form, uint64 data); @@ -404,6 +405,7 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { // specification_, parent_context_. Computed in EndAttributes. string name_; uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc + DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address. const AbstractOrigin* abstract_origin_; bool inline_; }; @@ -419,7 +421,11 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( case dwarf2reader::DW_AT_inline: inline_ = true; break; case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break; - case dwarf2reader::DW_AT_high_pc: high_pc_ = data; break; + case dwarf2reader::DW_AT_high_pc: + high_pc_form_ = form; + high_pc_ = data; + break; + default: GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); break; @@ -473,6 +479,11 @@ bool DwarfCUToModule::FuncHandler::EndAttributes() { } void DwarfCUToModule::FuncHandler::Finish() { + // Make high_pc_ an address, if it isn't already. + if (high_pc_form_ != dwarf2reader::DW_FORM_addr) { + high_pc_ += low_pc_; + } + // Did we collect the information we need? Not all DWARF function // entries have low and high addresses (for example, inlined // functions that were never used), but all the ones we're diff --git a/src/common/dwarf_cu_to_module_unittest.cc b/src/common/dwarf_cu_to_module_unittest.cc index e71d344b..37061d2a 100644 --- a/src/common/dwarf_cu_to_module_unittest.cc +++ b/src/common/dwarf_cu_to_module_unittest.cc @@ -193,12 +193,15 @@ class CUFixtureBase { DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag, uint64 specification, const char *name = NULL); - // Define a function as a child of PARENT with the given name, - // address, and size. Call EndAttributes and Finish; one cannot - // define children of the defined function's DIE. + // Define a function as a child of PARENT with the given name, address, and + // size. If high_pc_form is DW_FORM_addr then the DW_AT_high_pc attribute + // will be written as an address; otherwise it will be written as the + // function's size. Call EndAttributes and Finish; one cannot define + // children of the defined function's DIE. void DefineFunction(DIEHandler *parent, const string &name, Module::Address address, Module::Address size, - const char* mangled_name); + const char* mangled_name, + DwarfForm high_pc_form = dwarf2reader::DW_FORM_addr); // Create a declaration DIE as a child of PARENT with the given // offset, tag and name. If NAME is the empty string, don't provide @@ -414,7 +417,8 @@ DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent, void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent, const string &name, Module::Address address, Module::Address size, - const char* mangled_name) { + const char* mangled_name, + DwarfForm high_pc_form) { dwarf2reader::DIEHandler *func = parent->FindChildHandler(0xe34797c7e68590a8LL, dwarf2reader::DW_TAG_subprogram); @@ -425,9 +429,15 @@ void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent, func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, dwarf2reader::DW_FORM_addr, address); + + Module::Address high_pc = size; + if (high_pc_form == dwarf2reader::DW_FORM_addr) { + high_pc += address; + } func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr, - address + size); + high_pc_form, + high_pc); + if (mangled_name) func->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name, dwarf2reader::DW_FORM_strp, @@ -598,16 +608,20 @@ void CUFixtureBase::TestLine(int i, int j, // Include caller locations for our test subroutines. #define TRACE(call) do { SCOPED_TRACE("called from here"); call; } while (0) -#define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d))) -#define SetLanguage(a) TRACE(SetLanguage(a)) -#define StartCU() TRACE(StartCU()) -#define DefineFunction(a,b,c,d,e) TRACE(DefineFunction((a),(b),(c),(d),(e))) -#define DeclarationDIE(a,b,c,d,e) TRACE(DeclarationDIE((a),(b),(c),(d),(e))) -#define DefinitionDIE(a,b,c,d,e,f) TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f))) -#define TestFunctionCount(a) TRACE(TestFunctionCount(a)) -#define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d))) -#define TestLineCount(a,b) TRACE(TestLineCount((a),(b))) -#define TestLine(a,b,c,d,e,f) TRACE(TestLine((a),(b),(c),(d),(e),(f))) +#define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d))) +#define SetLanguage(a) TRACE(SetLanguage(a)) +#define StartCU() TRACE(StartCU()) +#define DefineFunction(a,b,c,d,e) TRACE(DefineFunction((a),(b),(c),(d),(e))) +// (DefineFunction) instead of DefineFunction to avoid macro expansion. +#define DefineFunction6(a,b,c,d,e,f) \ + TRACE((DefineFunction)((a),(b),(c),(d),(e),(f))) +#define DeclarationDIE(a,b,c,d,e) TRACE(DeclarationDIE((a),(b),(c),(d),(e))) +#define DefinitionDIE(a,b,c,d,e,f) \ + TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f))) +#define TestFunctionCount(a) TRACE(TestFunctionCount(a)) +#define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d))) +#define TestLineCount(a,b) TRACE(TestLineCount((a),(b))) +#define TestLine(a,b,c,d,e,f) TRACE(TestLine((a),(b),(c),(d),(e),(f))) class SimpleCU: public CUFixtureBase, public Test { }; @@ -627,6 +641,23 @@ TEST_F(SimpleCU, OneFunc) { 246571772); } +// As above, only DW_AT_high_pc is a length rather than an address. +TEST_F(SimpleCU, OneFuncHighPcIsLength) { + PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); + + StartCU(); + DefineFunction6(&root_handler_, "function1", + 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL, + dwarf2reader::DW_FORM_udata); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); + TestLineCount(0, 1); + TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", + 246571772); +} + TEST_F(SimpleCU, MangledName) { PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772);