From c6db4c4e4899052670cd519dc4632051688f3b21 Mon Sep 17 00:00:00 2001 From: eliben Date: Tue, 20 Sep 2011 16:03:59 +0300 Subject: [PATCH] abbrev table almost functioning --- elftools/dwarf/abbrevtable.py | 60 ++++++++++++++++++++++++++++++++++- elftools/dwarf/compileunit.py | 10 +++--- elftools/dwarf/dwarfinfo.py | 12 ++++--- elftools/dwarf/structs.py | 26 ++++++++------- z.py | 19 ++++++++--- 5 files changed, 100 insertions(+), 27 deletions(-) diff --git a/elftools/dwarf/abbrevtable.py b/elftools/dwarf/abbrevtable.py index 63485bd..14f88f5 100644 --- a/elftools/dwarf/abbrevtable.py +++ b/elftools/dwarf/abbrevtable.py @@ -6,11 +6,69 @@ # 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] + + diff --git a/elftools/dwarf/compileunit.py b/elftools/dwarf/compileunit.py index 6eb5afa..92198e4 100644 --- a/elftools/dwarf/compileunit.py +++ b/elftools/dwarf/compileunit.py @@ -9,13 +9,13 @@ 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 """ diff --git a/elftools/dwarf/dwarfinfo.py b/elftools/dwarf/dwarfinfo.py index f49458f..6e96f14 100644 --- a/elftools/dwarf/dwarfinfo.py +++ b/elftools/dwarf/dwarfinfo.py @@ -71,15 +71,14 @@ class DWARFInfo(object): 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): @@ -110,7 +109,10 @@ class DWARFInfo(object): 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. diff --git a/elftools/dwarf/structs.py b/elftools/dwarf/structs.py index ab27269..e77f98e 100644 --- a/elftools/dwarf/structs.py +++ b/elftools/dwarf/structs.py @@ -10,7 +10,7 @@ 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 * @@ -39,9 +39,9 @@ class DWARFStructs(object): 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. """ @@ -73,7 +73,7 @@ class DWARFStructs(object): 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): @@ -100,14 +100,16 @@ class DWARFStructs(object): 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): diff --git a/z.py b/z.py index b16ef69..6481458 100644 --- a/z.py +++ b/z.py @@ -2,7 +2,7 @@ # 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 * @@ -20,9 +20,20 @@ print '===> %s sections!' % efile.num_sections() 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 -- 2.30.2