blob: f4fc2cb01d862268531ec64f0e96e7ba4a1cfd3f [file] [log] [blame]
#-------------------------------------------------------------------------------
# elftools: dwarf/die.py
#
# DWARF Debugging Information Entry
#
# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------------
from collections import namedtuple
from ..common.ordereddict import OrderedDict
from ..common.utils import struct_parse, preserve_stream_pos
# AttributeValue - describes an attribute value in the DIE:
#
# form:
# The DW_FORM_* name of this attribute
#
# value:
# The value parsed from the section and translated accordingly to the form
# (e.g. for a DW_FORM_strp it's the actual string taken from the string table)
#
# raw_value:
# Raw value as parsed from the section - used for debugging and presentation
# (e.g. for a DW_FORM_strp it's the raw string offset into the table)
#
AttributeValue = namedtuple('AttributeValue', 'form value raw_value')
class DIE(object):
""" A DWARF debugging information entry. On creation, parses itself from
the stream. Each DIE is held by a CU.
Accessible attributes:
tag:
The DIE tag
size:
The size this DIE occupies in the section
attributes:
An ordered dictionary mapping attribute names to values. It's
ordered to enable both efficient name->value mapping and
preserve the order of attributes in the section
has_children:
Specifies whether this DIE has children
"""
def __init__(self, cu, stream, offset):
""" cu:
CompileUnit object this DIE belongs to. Used to obtain context
information (structs, abbrev table, etc.)
stream, offset:
The stream and offset into it where this DIE's data is located
"""
self.cu = cu
self.dwarfinfo = self.cu.dwarfinfo # get DWARFInfo context
self.stream = stream
self.offset = offset
self.attributes = OrderedDict()
self._parse_DIE()
def _parse_DIE(self):
""" Parses the DIE info from the section, based on the abbreviation
table of the CU
"""
structs = self.cu.structs
# A DIE begins with the abbreviation code. Read it and use it to
# obtain the abbrev declaration for this DIE.
# Note: here and elsewhere, preserve_stream_pos is used on operations
# that manipulate the stream by reading data from it.
#
abbrev_code = struct_parse(
structs.Dwarf_uleb128(''), self.stream, self.offset)
with preserve_stream_pos(self.stream):
abbrev_decl = self.cu.get_abbrev_table().get_abbrev(abbrev_code)
self.has_children = abbrev_decl.has_children()
# Guided by the attributes listed in the abbreviation declaration, parse
# values from the stream.
#
for name, form in abbrev_decl.iter_attr_specs():
raw_value = struct_parse(structs.Dwarf_dw_form[form], self.stream)
value = self._translate_attr_value(form, raw_value)
self.attributes[name] = AttributeValue(form, value, raw_value)
self.size = self.stream.tell() - self.offset
def _translate_attr_value(self, form, raw_value):
""" Translate a raw attr value according to the form
"""
value = None
if form == 'DW_FORM_strp':
with preserve_stream_pos(self.stream):
value = self.dwarfinfo.get_string_from_table(raw_value)
elif form == 'DW_FORM_flag':
value = not raw_value == 0
elif form == 'DW_FORM_indirect':
form = raw_value
raw_value = struct_parse(
structs.Dwarf_dw_form[form], self.stream)
# Let's hope this doesn't get too deep :-)
return self._translate_attr_value(form, raw_value)
else:
value = raw_value
return value