From 07c8c0b99405f018a5f86518e3b9076860ac27fb Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 9 Jul 2015 06:37:01 -0700 Subject: [PATCH] Better DWARF v4 support for decoding function ranges. --- CHANGES | 6 +++++ elftools/dwarf/constants.py | 2 -- elftools/dwarf/descriptions.py | 39 ++++++++++++++++++++++++++++++++ examples/dwarf_decode_address.py | 19 +++++++++++++++- 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index b453a26..5bba7df 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,12 @@ Changelog - Retrieve symbols by name - get_symbol_by_name (#58). - Symbol/section names are strings internally now, not bytestrings (this may affect API usage in Python 3) (#76). + - Added DT_MIPS_* constants to ENUM_D_TAG (#79) + - Made dwarf_decode_address example a bit more useful for command-line + invocation. + - More DWARF v4 support w.r.t decoding function ranges; DW_AT_high_pc value + is now either absolute or relative to DW_AT_low_pc, depending on the class + of the form encoded in the file. + Version 0.23 (08.11.2014) diff --git a/elftools/dwarf/constants.py b/elftools/dwarf/constants.py index 8bf38e8..b79c124 100644 --- a/elftools/dwarf/constants.py +++ b/elftools/dwarf/constants.py @@ -173,5 +173,3 @@ DW_CFA_def_cfa_offset_sf = 0x13 DW_CFA_val_offset = 0x14 DW_CFA_val_offset_sf = 0x15 DW_CFA_val_expression = 0x16 - - diff --git a/elftools/dwarf/descriptions.py b/elftools/dwarf/descriptions.py index 4cd62fe..9c56d67 100644 --- a/elftools/dwarf/descriptions.py +++ b/elftools/dwarf/descriptions.py @@ -166,6 +166,18 @@ def describe_reg_name(regnum, machine_arch=None, default=True): else: return None +def describe_form_class(form): + """For a given form name, determine its value class. + + For example, given 'DW_FORM_data1' returns 'constant'. + + For some forms, like DW_FORM_indirect and DW_FORM_sec_offset, the class is + not hard-coded and extra information is required. For these, None is + returned. + """ + return _FORM_CLASS[form] + + #------------------------------------------------------------------------------- # The machine architecture. Set globally via set_global_machine_arch @@ -244,6 +256,33 @@ _ATTR_DESCRIPTION_MAP = defaultdict( DW_FORM_ref_sig8=_describe_attr_ref, ) +_FORM_CLASS = dict( + DW_FORM_addr='address', + DW_FORM_block2='block', + DW_FORM_block4='block', + DW_FORM_data2='constant', + DW_FORM_data4='constant', + DW_FORM_data8='constant', + DW_FORM_string='string', + DW_FORM_block='block', + DW_FORM_block1='block', + DW_FORM_data1='constant', + DW_FORM_flag='flag', + DW_FORM_sdata='constant', + DW_FORM_strp='string', + DW_FORM_udata='constant', + DW_FORM_ref_addr='reference', + DW_FORM_ref1='reference', + DW_FORM_ref2='reference', + DW_FORM_ref4='reference', + DW_FORM_ref8='reference', + DW_FORM_ref_udata='reference', + DW_FORM_indirect=None, + DW_FORM_sec_offset=None, + DW_FORM_exprloc='exprloc', + DW_FORM_flag_present='flag', + DW_FORM_ref_sig8='reference', +) _DESCR_DW_INL = { DW_INL_not_inlined: '(not inlined)', diff --git a/examples/dwarf_decode_address.py b/examples/dwarf_decode_address.py index 3f5108e..7b7d3e0 100644 --- a/examples/dwarf_decode_address.py +++ b/examples/dwarf_decode_address.py @@ -15,6 +15,7 @@ import sys sys.path[0:0] = ['.', '..'] from elftools.common.py3compat import maxint, bytes2str +from elftools.dwarf.descriptions import describe_form_class from elftools.elf.elffile import ELFFile @@ -49,7 +50,23 @@ def decode_funcname(dwarfinfo, address): try: if DIE.tag == 'DW_TAG_subprogram': lowpc = DIE.attributes['DW_AT_low_pc'].value - highpc = DIE.attributes['DW_AT_high_pc'].value + + # DWARF v4 in section 2.17 describes how to interpret the + # DW_AT_high_pc attribute based on the class of its form. + # For class 'address' it's taken as an absolute address + # (similarly to DW_AT_low_pc); for class 'constant', it's + # an offset from DW_AT_low_pc. + highpc_attr = DIE.attributes['DW_AT_high_pc'] + highpc_attr_class = describe_form_class(highpc_attr.form) + if highpc_attr_class == 'address': + highpc = highpc_attr.value + elif highpc_attr_class == 'constant': + highpc = lowpc + highpc_attr.value + else: + print('Error: invalid DW_AT_high_pc class:', + highpc_attr_class) + continue + if lowpc <= address <= highpc: return DIE.attributes['DW_AT_name'].value except KeyError: -- 2.30.2