added extra description for DW_AT_import to conform with readelf
authorEli Bendersky <eliben@gmail.com>
Sat, 19 Nov 2011 13:29:51 +0000 (15:29 +0200)
committerEli Bendersky <eliben@gmail.com>
Sat, 19 Nov 2011 13:29:51 +0000 (15:29 +0200)
elftools/dwarf/descriptions.py

index 950ff43e049201c57b8ad2cbfc2d1e52aa7fcd7b..66768275f61485510640b2bc92e5fb55273f256b 100644 (file)
@@ -10,6 +10,8 @@ from collections import defaultdict
 
 from .constants import *
 from .location_expr import LocationExpressionDumper
+from .die import DIE
+from ..common.utils import preserve_stream_pos
 
 
 def describe_attr_value(attr, die, section_offset):
@@ -224,6 +226,34 @@ def _location_list_extra(attr, die, section_offset):
         return '(' + location_expr_dumper.get_str() + ')'
 
 
+def _import_extra(attr, die, section_offset):
+    # For DW_AT_import the value points to a DIE (that can be either in the
+    # current DIE's CU or in another CU, depending on the FORM). The extra
+    # information for it is the abbreviation number in this DIE and its tag.
+    if attr.form == 'DW_FORM_ref_addr':
+        # Absolute offset value
+        ref_die_offset = section_offset + attr.value
+    else:
+        # Relative offset to the current DIE's CU
+        ref_die_offset = attr.value + die.cu.cu_offset
+    #print '&&&', attr.form, attr.value, ref_die_offset, ref_die_offset - section_offset
+
+    # Now find the CU this DIE belongs to (since we have to find its abbrev
+    # table). This is done by linearly scanning through all CUs, looking for
+    # one spanning an address space containing the referred DIE's offset.
+    for cu in die.dwarfinfo.iter_CUs():
+        if cu['unit_length'] + cu.cu_offset > ref_die_offset >= cu.cu_offset:
+            # Once we have the CU, we can actually parse this DIE from the
+            # stream.
+            with preserve_stream_pos(die.stream):
+                ref_die = DIE(cu, die.stream, ref_die_offset)
+            #print '&&& ref_die', ref_die
+            return '[Abbrev Number: %s (%s)]' % (
+                ref_die.abbrev_code, ref_die.tag)
+
+    return '[unknown]'
+
+
 _EXTRA_INFO_DESCRIPTION_MAP = defaultdict(
     lambda: _make_extra_string(''), # default_factory
     
@@ -258,6 +288,7 @@ _EXTRA_INFO_DESCRIPTION_MAP = defaultdict(
     DW_AT_associated=_location_list_extra,
     DW_AT_data_location=_location_list_extra,
     DW_AT_stride=_location_list_extra,
+    DW_AT_import=_import_extra,
 )