class CompileUnit(object):
- """ A DWARF compilation unit (CU).
-
+ """ A DWARF compilation unit (CU).
+
A normal compilation unit typically represents the text and data
contributed to an executable by a single relocatable object file.
- It may be derived from several source files,
+ It may be derived from several source files,
including pre-processed "include files"
-
+
Serves as a container and context to DIEs that describe objects and code
belonging to a compilation unit.
-
+
CU header entries can be accessed as dict keys from this object, i.e.
cu = CompileUnit(...)
cu['version'] # version field of the CU header
-
- To get the top-level DIE describing the compilation unit, call the
+
+ To get the top-level DIE describing the compilation unit, call the
get_top_DIE method.
"""
def __init__(self, header, dwarfinfo, structs, cu_offset, cu_die_offset):
""" header:
CU header for this compile unit
-
+
dwarfinfo:
The DWARFInfo context object which created this one
-
+
structs:
A DWARFStructs instance suitable for this compile unit
-
+
cu_offset:
Offset in the stream to the beginning of this CU (its header)
-
+
cu_die_offset:
Offset in the stream of the top DIE of this CU
"""
self.structs = structs
self.cu_offset = cu_offset
self.cu_die_offset = cu_die_offset
-
- # The abbreviation table for this CU. Filled lazily when DIEs are
+
+ # The abbreviation table for this CU. Filled lazily when DIEs are
# requested.
self._abbrev_table = None
-
+
# A list of DIEs belonging to this CU. Lazily parsed.
self._dielist = []
-
+
def dwarf_format(self):
""" Get the DWARF format (32 or 64) for this CU
"""
return self.structs.dwarf_format
-
+
def get_abbrev_table(self):
""" Get the abbreviation table (AbbrevTable object) for this CU
"""
return self._abbrev_table
def get_top_DIE(self):
- """ Get the top DIE (which is either a DW_TAG_compile_unit or
+ """ Get the top DIE (which is either a DW_TAG_compile_unit or
DW_TAG_partial_unit) of this CU
"""
return self._get_DIE(0)
-
+
def iter_DIEs(self):
""" Iterate over all the DIEs in the CU, in order of their appearance.
Note that null DIEs will also be returned.
"""
self._parse_DIEs()
return iter(self._dielist)
-
+
#------ PRIVATE ------#
-
+
def __getitem__(self, name):
""" Implement dict-like access to header entries
"""
return self.header[name]
def _get_DIE(self, index):
- """ Get the DIE at the given index
+ """ Get the DIE at the given index
"""
self._parse_DIEs()
return self._dielist[index]
-
+
def _parse_DIEs(self):
""" Parse all the DIEs pertaining to this CU from the stream and shove
them sequentially into self._dielist.
"""
if len(self._dielist) > 0:
return
-
- # Compute the boundary (one byte past the bounds) of this CU in the
+
+ # Compute the boundary (one byte past the bounds) of this CU in the
# stream
- cu_boundary = ( self.cu_offset +
- self['unit_length'] +
+ cu_boundary = ( self.cu_offset +
+ self['unit_length'] +
self.structs.initial_length_field_size())
-
+
# First pass: parse all DIEs and place them into self._dielist
die_offset = self.cu_die_offset
while die_offset < cu_boundary:
# Second pass - unflatten the DIE tree
self._unflatten_tree()
-
+
def _unflatten_tree(self):
""" "Unflatten" the DIE tree from it serial representation, by setting
the child/sibling/parent links of DIEs.
-
+
Assumes self._dielist was already populated by a linear list of DIEs
read from the stream section
"""
# the first DIE in the list is the root node
root = self._dielist[0]
parentstack = [root]
-
+
for die in self._dielist[1:]:
if not die.is_null():
cur_parent = parentstack[-1]
def __init__(self, entry, elffile):
self.entry = entry
self.elffile = elffile
-
+
def is_RELA(self):
""" Is this a RELA relocation? If not, it's REL.
"""
return 'r_addend' in self.entry
-
+
def __getitem__(self, name):
""" Dict-like access to entries
"""
relsection.name in reloc_section_names):
return relsection
return None
-
+
def apply_section_relocations(self, stream, reloc_section):
""" Apply all relocations in reloc_section (a RelocationSection object)
to the given stream, that contains the data of the section that is
elif recipe.bytesize == 8:
value_struct = self.elffile.structs.Elf_word64('')
else:
- raise ELFRelocationError('Invalid bytesize %s for relocation' %
+ raise ELFRelocationError('Invalid bytesize %s for relocation' %
recipe_bytesize)
# 1. Read the value from the stream (with correct size and endianness)
def _reloc_calc_sym_plus_value_pcrel(value, sym_value, offset, addend=0):
return sym_value + value - offset
-
+
def _reloc_calc_sym_plus_addend(value, sym_value, offset, addend=0):
return sym_value + addend
-
+
_RELOCATION_RECIPES_X86 = {
ENUM_RELOC_TYPE_i386['R_386_NONE']: _RELOCATION_RECIPE_TYPE(
bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
bytesize=4, has_addend=False,
calc_func=_reloc_calc_sym_plus_value_pcrel),
}
-
+
_RELOCATION_RECIPES_X64 = {
ENUM_RELOC_TYPE_x64['R_X86_64_NONE']: _RELOCATION_RECIPE_TYPE(
bytesize=8, has_addend=True, calc_func=_reloc_calc_identity),