| #------------------------------------------------------------------------------- |
| # elftools: dwarf/abbrevtable.py |
| # |
| # DWARF abbreviation table |
| # |
| # Eli Bendersky (eliben@gmail.com) |
| # This code is in the public domain |
| #------------------------------------------------------------------------------- |
| from ..common.utils import struct_parse, dwarf_assert |
| |
| |
| class AbbrevTable(object): |
| """ 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. |
| """ |
| 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. |
| |
| The abbreviation declaration represents an "entry" that points to it. |
| """ |
| def __init__(self, code, decl): |
| self.code = code |
| self.decl = decl |
| |
| def has_children(self): |
| """ Does the entry have children? |
| """ |
| return self['children_flag'] == 'DW_CHILDREN_yes' |
| |
| def iter_attr_specs(self): |
| """ Iterate over the attribute specifications for the entry. Yield |
| (name, form) pairs. |
| """ |
| for attr_spec in self['attr_spec']: |
| yield attr_spec.name, attr_spec.form |
| |
| def __getitem__(self, entry): |
| return self.decl[entry] |
| |