class CompileUnit(object):
- def __init__(self, header, format_bits, cu_die):
+ def __init__(self, dwarfinfo, header, structs):
+ """ Arguments:
+
+ dwarfinfo:
+ The DWARFInfo context object which created this one
+
+ header:
+ CU header for this compile unit
+
+ structs:
+ A DWARFStructs instance suitable for this compile unit
+ """
+ self.dwarfinfo = dwarfinfo
self.header = header
- self.format_bits = format_bits
+ self.structs = structs
self.cu_die = cu_die
def __getitem__(self, name):
""" Implement dict-like access to header entries
"""
return self.header[name]
+
+
+
+
""" Creation: the constructor accepts a stream (file-like object) that
contains debug sections, along with locators (DebugSectionLocator)
of the required sections. In addition, little_endian is a boolean
- parameter specifying endianity, and dwarfclass is 32 or 64, depending
- on the type of file the DWARF info was read from.
+ parameter specifying endianity.
"""
def __init__(self,
stream,
little_endian,
- dwarfclass,
debug_info_loc,
debug_abbrev_loc,
debug_str_loc,
self.debug_line_loc = debug_line_loc
self.little_endian = little_endian
- self.dwarfclass = dwarfclass
+ self.dwarf_format = 32
self.structs = DWARFStructs(
little_endian=self.little_endian,
- dwarfclass=self.dwarfclass)
+ dwarf_format=self.dwarf_format)
+ # Populate the list with CUs found in debug_info
self._CU = self._parse_CUs()
- def initial_lenght_field_size(self):
- """ Size of an initial length field.
- """
- return 4 if self.dwarfclass == 32 else 12
-
def _parse_CUs(self):
- """ Parse CU entries from debug_info and return them as a list of
- containers.
+ """ Parse CU entries from debug_info.
"""
offset = self.debug_info_loc.offset
- print 'loc', self.debug_info_loc
section_boundary = self.debug_info_loc.offset + self.debug_info_loc.size
CUlist = []
while offset < section_boundary:
+ # Section 7.4 (32-bit and 64-bit DWARF Formats) of the DWARF spec v3
+ # states that the first 32-bit word of the CU header determines
+ # whether the CU is represented with 32-bit or 64-bit DWARF format.
+ #
+ # So we peek at the first byte in the CU header to determine its
+ # dwarf format. Based on it, we then create a new DWARFStructs
+ # instance suitable for this CU and use it to parse the rest.
+ #
+ initial_length = struct_parse(
+ self.structs.Dwarf_uint32(''), self.stream, offset)
+ if initial_length == 0xFFFFFFFF:
+ self.dwarf_format = 64
+ cu_structs = DWARFStructs(
+ little_endian=self.little_endian,
+ dwarf_format=self.dwarf_format)
+
cu_header = struct_parse(
self.structs.Dwarf_CU_header, self.stream, offset)
- print offset, cu_header
dwarf_assert(
self._is_supported_version(cu_header['version']),
"Expected supported DWARF version. Got '%s'" % cu_header['version'])
- CUlist.append(CompileUnit(cu_header, None))
+ CUlist.append(CompileUnit(cu_header, cu_structs, None))
# Compute the offset of the next CU in the section. The unit_length
# field of the CU header contains its size not including the length
# field itself.
offset = ( offset +
cu_header['unit_length'] +
- self.initial_lenght_field_size())
+ cu_structs.initial_lenght_field_size())
return CUlist
def _is_supported_version(self, version):
"""
return 2 <= version <= 3
-
-
-
class DWARFStructs(object):
- """ Accessible attributes (mostly described by in chapter 7 of the DWARF
+ """ Exposes Construct structs suitable for parsing information from DWARF
+ sections. Configurable with endianity and format (32 or 64-bit)
+
+ Accessible attributes (mostly described by in chapter 7 of the DWARF
spec v3):
Dwarf_uint{8,16,32,64):
Data chunks of the common sizes
- Dwarf_xword, Dwarf_offset:
- 32-bit or 64-bit word, depending on dwarfclass (xword and offset
- are synonyms here).
+ Dwarf_offset:
+ 32-bit or 64-bit word, depending on dwarf_format
Dwarf_initial_length:
"Initial length field" encoding
Dwarf_CU_header:
Compilation unit header
+
+ See also the documentation of public methods.
"""
- def __init__(self, little_endian=True, dwarfclass=32):
- assert dwarfclass == 32 or dwarfclass == 64
+ def __init__(self, little_endian=True, dwarf_format=32):
+ assert dwarf_format == 32 or dwarf_format == 64
self.little_endian = little_endian
- self.dwarfclass = dwarfclass
+ self.dwarf_format = dwarf_format
self._create_structs()
+ def initial_lenght_field_size(self):
+ """ Size of an initial length field.
+ """
+ return 4 if self.dwarf_format == 32 else 12
+
def _create_structs(self):
if self.little_endian:
self.Dwarf_uint8 = ULInt8
self.Dwarf_uint16 = ULInt16
self.Dwarf_uint32 = ULInt32
self.Dwarf_uint64 = ULInt64
- self.Dwarf_xword = ULInt32 if self.dwarfclass == 32 else ULInt64
+ self.Dwarf_offset = ULInt32 if self.dwarf_format == 32 else ULInt64
else:
self.Dwarf_uint8 = UBInt8
self.Dwarf_uint16 = UBInt16
self.Dwarf_uint32 = UBInt32
self.Dwarf_uint64 = UBInt64
- self.Dwarf_xword = UBInt32 if self.dwarfclass == 32 else UBInt64
- self.Dwarf_offset = self.Dwarf_xword
+ self.Dwarf_offest = UBInt32 if self.dwarf_format == 32 else UBInt64
self._create_initial_length()
self._create_leb128()
return DWARFInfo(
stream=self.stream,
little_endian=self.little_endian,
- dwarfclass=self.elfclass,
debug_info_loc=debug_sections['.debug_info'],
debug_abbrev_loc=debug_sections['.debug_abbrev'],
debug_str_loc=debug_sections['.debug_str'],
print efile.has_dwarf_info()
-print efile.get_dwarf_info()
+dwarfinfo = efile.get_dwarf_info()
+print dwarfinfo
+for cu in dwarfinfo._CU:
+ print cu, cu.header
#~ print efile.get_section_by_name('.debug_info').name
from elftools.dwarf.dwarfinfo import DWARFInfo\r
\r
\r
-ds = DWARFStructs(\r
- little_endian=True,\r
+ds = DWARFStructs(little_endian=True,\r
dwarfclass=32)\r
\r
print ds.Dwarf_xword('x').parse('\x04\x01\x00\x00')\r