e6c735f585e3a94f63d4cb9f148786d553f5ea29
1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/locationlists.py
4 # DWARF location lists section decoding (.debug_loc)
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
10 from collections
import namedtuple
12 from ..common
.utils
import struct_parse
14 LocationExpr
= namedtuple('LocationExpr', 'loc_expr')
15 LocationEntry
= namedtuple('LocationEntry', 'entry_offset begin_offset end_offset loc_expr')
16 BaseAddressEntry
= namedtuple('BaseAddressEntry', 'entry_offset base_address')
18 class LocationLists(object):
19 """ A single location list is a Python list consisting of LocationEntry or
20 BaseAddressEntry objects.
22 def __init__(self
, stream
, structs
):
24 self
.structs
= structs
25 self
._max
_addr
= 2 ** (self
.structs
.address_size
* 8) - 1
27 def get_location_list_at_offset(self
, offset
):
28 """ Get a location list at the given offset in the section.
30 self
.stream
.seek(offset
, os
.SEEK_SET
)
31 return self
._parse
_location
_list
_from
_stream
()
33 def iter_location_lists(self
):
34 """ Yield all location lists found in the section.
36 # Just call _parse_location_list_from_stream until the stream ends
37 self
.stream
.seek(0, os
.SEEK_END
)
38 endpos
= self
.stream
.tell()
40 self
.stream
.seek(0, os
.SEEK_SET
)
41 while self
.stream
.tell() < endpos
:
42 yield self
._parse
_location
_list
_from
_stream
()
44 #------ PRIVATE ------#
46 def _parse_location_list_from_stream(self
):
49 entry_offset
= self
.stream
.tell()
50 begin_offset
= struct_parse(
51 self
.structs
.Dwarf_target_addr(''), self
.stream
)
52 end_offset
= struct_parse(
53 self
.structs
.Dwarf_target_addr(''), self
.stream
)
54 if begin_offset
== 0 and end_offset
== 0:
55 # End of list - we're done.
57 elif begin_offset
== self
._max
_addr
:
58 # Base address selection entry
59 lst
.append(BaseAddressEntry(entry_offset
=entry_offset
, base_address
=end_offset
))
62 expr_len
= struct_parse(
63 self
.structs
.Dwarf_uint16(''), self
.stream
)
64 loc_expr
= [struct_parse(self
.structs
.Dwarf_uint8(''),
66 for i
in range(expr_len
)]
67 lst
.append(LocationEntry(
68 entry_offset
=entry_offset
,
69 begin_offset
=begin_offset
,
70 end_offset
=end_offset
,
74 class LocationParser(object):
75 """ A parser for location information in DIEs.
76 Handles both location information contained within the attribute
77 itself (represented as a LocationExpr object) and references to
78 location lists in the .debug_loc section (represented as a
81 def __init__(self
, location_lists
):
82 self
.location_lists
= location_lists
85 def attribute_has_location(attr
, dwarf_version
):
86 """ Checks if a DIE attribute contains location information.
88 return (LocationParser
._attribute
_is
_loclistptr
_class
(attr
) and
89 (LocationParser
._attribute
_has
_loc
_expr
(attr
, dwarf_version
) or
90 LocationParser
._attribute
_has
_loc
_list
(attr
, dwarf_version
)))
92 def parse_from_attribute(self
, attr
, dwarf_version
):
93 """ Parses a DIE attribute and returns either a LocationExpr or
96 if self
.attribute_has_location(attr
, dwarf_version
):
97 if self
._attribute
_has
_loc
_expr
(attr
, dwarf_version
):
98 return LocationExpr(attr
.value
)
99 elif self
._attribute
_has
_loc
_list
(attr
, dwarf_version
):
100 return self
.location_lists
.get_location_list_at_offset(
103 raise ValueError("Attribute does not have location information")
105 #------ PRIVATE ------#
108 def _attribute_has_loc_expr(attr
, dwarf_version
):
109 return ((dwarf_version
< 4 and attr
.form
.startswith('DW_FORM_block') and
110 not attr
.name
== 'DW_AT_const_value') or
111 attr
.form
== 'DW_FORM_exprloc')
114 def _attribute_has_loc_list(attr
, dwarf_version
):
115 return ((dwarf_version
< 4 and
116 attr
.form
in ('DW_FORM_data4', 'DW_FORM_data8') and
117 not attr
.name
== 'DW_AT_const_value') or
118 attr
.form
== 'DW_FORM_sec_offset')
121 def _attribute_is_loclistptr_class(attr
):
122 return (attr
.name
in ( 'DW_AT_location', 'DW_AT_string_length',
123 'DW_AT_const_value', 'DW_AT_return_addr',
124 'DW_AT_data_member_location',
125 'DW_AT_frame_base', 'DW_AT_segment',
126 'DW_AT_static_link', 'DW_AT_use_location',
127 'DW_AT_vtable_elem_location',
128 'DW_AT_GNU_call_site_value',
129 'DW_AT_GNU_call_site_target',
130 'DW_AT_GNU_call_site_data_value'))