# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------------
+from ..common.utils import struct_parse, dwarf_assert
class AbbrevTable(object):
- def __init__(self, structs, stream):
+ """ Represents a DWARF abbreviation table.
+ """
+ def __init__(self, structs, stream, offset):
+ """ Create new abbreviation table. Parses the actual table from the
+ stream and stores it internally.
+
+ structs:
+ A DWARFStructs instance for parsing the data
+
+ stream, offset:
+ The stream and offset into the stream where this abbreviation
+ table lives.
+ Note that this is the absolute offset into the stream, not
+ relative to the debug_abbrev section.
+ """
self.structs = structs
self.stream = stream
+ self.offset = offset
+
+ self._abbrev_map = self._parse_abbrev_table()
+
+ def get_abbrev(self, code):
+ """ Get the AbbrevDecl for a given code. Raise KeyError if no
+ declaration for this code exists.
+ """
+ return AbbrevDecl(code, self._abbrev_map[code])
+
+ def _parse_abbrev_table(self):
+ """ Parse the abbrev table from the stream
+ """
+ map = {}
+ self.stream.seek(self.offset)
+ while True:
+ decl_code = struct_parse(
+ struct=self.structs.Dwarf_uleb128(''),
+ stream=self.stream)
+ if decl_code == 0:
+ break
+ declaration = struct_parse(
+ struct=self.structs.Dwarf_abbrev_declaration,
+ stream=self.stream)
+ map[decl_code] = declaration
+ return map
+
+
+class AbbrevDecl(object):
+ """ Wraps a parsed abbreviation declaration, exposing its fields with
+ dict-like access, and adding some convenience methods.
+ """
+ def __init__(self, code, decl):
+ self.code = code
+ self.decl = decl
+
+ def has_children(self):
+ return self['children_flag'] == 'DW_CHILDREN_yes'
+
+ def __getitem__(self, entry):
+ return self.decl[entry]
+
+
class CompileUnit(object):
- def __init__(self, dwarfinfo, header, structs):
- """ dwarfinfo:
- The DWARFInfo context object which created this one
-
- header:
+ def __init__(self, header, dwarfinfo, structs):
+ """ 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
"""
AbbrevTable objects are cached internally (two calls for the same
offset will return the same object).
"""
- section_boundary = self.debug_abbrev_loc.offset + self.debug_abbrev_loc.size
dwarf_assert(
- self.debug_abbrev_loc.offset <= offset < section_boundary,
+ offset < self.debug_abbrev_loc.size,
"Offset '0x%x' to abbrev table out of section bounds" % offset)
if offset not in self._abbrevtable_cache:
self._abbrevtable_cache[offset] = AbbrevTable(
structs=self.structs,
- stream=self.stream)
-
+ stream=self.stream,
+ offset=offset + self.debug_abbrev_loc.offset)
return self._abbrevtable_cache[offset]
def _parse_CUs(self):
dwarf_assert(
self._is_supported_version(cu_header['version']),
"Expected supported DWARF version. Got '%s'" % cu_header['version'])
- CUlist.append(CompileUnit(cu_header, cu_structs, None))
+ CUlist.append(CompileUnit(
+ header=cu_header,
+ dwarfinfo=self,
+ structs=cu_structs))
# 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.
from ..construct import (
UBInt8, UBInt16, UBInt32, UBInt64,
ULInt8, ULInt16, ULInt32, ULInt64,
- Adapter, Struct, ConstructError, If, RepeatUntil, Field, Rename,
+ Adapter, Struct, ConstructError, If, RepeatUntil, Field, Rename, Enum,
)
from .enums import *
Dwarf_CU_header:
Compilation unit header
- Dwarf_abbrev_entry:
- Abbreviation table entry - doesn't include the initial code,
- only the contents.
+ Dwarf_abbrev_declaration:
+ Abbreviation table declaration - doesn't include the initial
+ code, only the contents.
See also the documentation of public methods.
"""
self._create_initial_length()
self._create_leb128()
self._create_cu_header()
- self._create_abbrev_entry()
+ self._create_abbrev_declaration()
def _create_initial_length(self):
def _InitialLength(name):
self.Dwarf_offset('debug_abbrev_offset'),
self.Dwarf_uint8('address_size'))
- def _create_abbrev_entry(self):
- self.Dwarf_abbrev_entry = Struct('Dwarf_abbrev_entry',
- self.Dwarf_uleb128('tag'), # ZZZ: wrap in enums
- self.Dwarf_uint8('children_flag'),
- RepeatUntil(lambda obj, ctx: obj.name == obj.form == 0,
+ def _create_abbrev_declaration(self):
+ self.Dwarf_abbrev_declaration = Struct('Dwarf_abbrev_entry',
+ Enum(self.Dwarf_uleb128('tag'), **ENUM_DW_TAG),
+ Enum(self.Dwarf_uint8('children_flag'), **ENUM_DW_CHILDREN),
+ RepeatUntil(
+ lambda obj, ctx:
+ obj.name == 'DW_AT_null' and obj.form == 'DW_FORM_null',
Struct('spec',
- self.Dwarf_uleb128('name'),
- self.Dwarf_uleb128('form'))))
+ Enum(self.Dwarf_uleb128('name'), **ENUM_DW_AT),
+ Enum(self.Dwarf_uleb128('form'), **ENUM_DW_FORM))))
class _InitialLengthAdapter(Adapter):
# please ignore it!
#
-import sys
+import sys, pprint
from elftools.elf.structs import ELFStructs
from elftools.elf.elffile import ELFFile
from elftools.elf.sections import *
print efile.has_dwarf_info()
dwarfinfo = efile.get_dwarf_info()
-print dwarfinfo
-for cu in dwarfinfo._CU:
- print cu, cu.header
+
+#~ print dwarfinfo.structs.Dwarf_abbrev_entry.parse('\x13\x01\x01\x03\x50\x04\x00\x00')
+
+print id(dwarfinfo.get_abbrev_table(0))
+print id(dwarfinfo.get_abbrev_table(0))
+pprint.pprint(dwarfinfo.get_abbrev_table(0)._abbrev_map)
+
+print dwarfinfo.get_abbrev_table(0).get_abbrev(1).decl
+print dwarfinfo.get_abbrev_table(0).get_abbrev(1).has_children()
+
+#~ for cu in dwarfinfo._CU:
+ #~ print cu, cu.header
+
+
#~ print efile.get_section_by_name('.debug_info').name