Skip to content

Commit

Permalink
Performance enhancements (#557)
Browse files Browse the repository at this point in the history
* Performance enhancements

* Exception wording
  • Loading branch information
sevaa authored Apr 23, 2024
1 parent d7bf99d commit 75f0f98
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 225 deletions.
72 changes: 33 additions & 39 deletions elftools/common/construct_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from struct import Struct
from ..construct import (
Subconstruct, ConstructError, ArrayError, Adapter, Field, RepeatUntil,
Rename, SizeofError, Construct, StaticField
Rename, SizeofError, Construct, StaticField, FieldError
)


Expand Down Expand Up @@ -47,49 +47,43 @@ def _build(self, obj, stream, context):
def _sizeof(self, context):
raise SizeofError("can't calculate size")

class ULEB128(Construct):
"""A construct based parser for ULEB128 encoding.
def _LEB128_reader():
""" Read LEB128 variable-length data from the stream. The data is terminated
by a byte with 0 in its highest bit.
Incompatible with Python 2 - assumes that the return of read()
is an indexed collection of numbers.
"""
return RepeatUntil(
lambda obj, ctx: ord(obj) < 0x80,
Field(None, 1))


class _ULEB128Adapter(Adapter):
""" An adapter for ULEB128, given a sequence of bytes in a sub-construct.
"""
def _decode(self, obj, context):
def _parse(self, stream, context):
value = 0
for b in reversed(obj):
value = (value << 7) + (ord(b) & 0x7F)
return value


class _SLEB128Adapter(Adapter):
""" An adapter for SLEB128, given a sequence of bytes in a sub-construct.
shift = 0
while True:
data = stream.read(1)
if len(data) != 1:
raise FieldError("unexpected end of stream while parsing a ULEB128 encoded value")
b = data[0]
value |= (b & 0x7F) << shift
shift += 7
if b & 0x80 == 0:
return value

class SLEB128(Construct):
"""A construct based parser for SLEB128 encoding.
Incompatible with Python 2 - assumes that the return of read()
is an indexed collection of numbers.
"""
def _decode(self, obj, context):
def _parse(self, stream, context):
value = 0
for b in reversed(obj):
value = (value << 7) + (ord(b) & 0x7F)
if ord(obj[-1]) & 0x40:
# negative -> sign extend
value |= - (1 << (7 * len(obj)))
return value


def ULEB128(name):
""" A construct creator for ULEB128 encoding.
"""
return Rename(name, _ULEB128Adapter(_LEB128_reader()))


def SLEB128(name):
""" A construct creator for SLEB128 encoding.
"""
return Rename(name, _SLEB128Adapter(_LEB128_reader()))
shift = 0
while True:
data = stream.read(1)
if len(data) != 1:
raise FieldError("unexpected end of stream while parsing a SLEB128 encoded value")
b = data[0]
value |= (b & 0x7F) << shift
shift += 7
if b & 0x80 == 0:
return value | (~0 << shift) if b & 0x40 else value

class StreamOffset(Construct):
"""
Expand Down
9 changes: 5 additions & 4 deletions elftools/dwarf/abbrevtable.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
class AbbrevTable(object):
""" Represents a DWARF abbreviation table.
"""
__slots__ = ('structs', 'stream', 'offset', '_abbrev_map')
def __init__(self, structs, stream, offset):
""" Create new abbreviation table. Parses the actual table from the
stream and stores it internally.
Expand Down Expand Up @@ -42,7 +43,7 @@ def _parse_abbrev_table(self):
self.stream.seek(self.offset)
while True:
decl_code = struct_parse(
struct=self.structs.Dwarf_uleb128(''),
struct=self.structs.the_Dwarf_uleb128,
stream=self.stream)
if decl_code == 0:
break
Expand All @@ -59,14 +60,14 @@ class AbbrevDecl(object):
The abbreviation declaration represents an "entry" that points to it.
"""
__slots__ = ('code', 'decl', '_has_children')
def __init__(self, code, decl):
self.code = code
self.decl = decl
self._has_children = decl['children_flag'] == 'DW_CHILDREN_yes'

def has_children(self):
""" Does the entry have children?
"""
return self['children_flag'] == 'DW_CHILDREN_yes'
return self._has_children

def iter_attr_specs(self):
""" Iterate over the attribute specifications for the entry. Yield
Expand Down
32 changes: 16 additions & 16 deletions elftools/dwarf/callframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def _parse_entry_at(self, offset):
return self._entry_cache[offset]

entry_length = struct_parse(
self.base_structs.Dwarf_uint32(''), self.stream, offset)
self.base_structs.the_Dwarf_uint32, self.stream, offset)

if self.for_eh_frame and entry_length == 0:
return ZERO(offset)
Expand All @@ -104,7 +104,7 @@ def _parse_entry_at(self, offset):

# Read the next field to see whether this is a CIE or FDE
CIE_id = struct_parse(
entry_structs.Dwarf_offset(''), self.stream)
entry_structs.the_Dwarf_offset, self.stream)

if self.for_eh_frame:
is_CIE = CIE_id == 0
Expand Down Expand Up @@ -184,7 +184,7 @@ def _parse_instructions(self, structs, offset, end_offset):
"""
instructions = []
while offset < end_offset:
opcode = struct_parse(structs.Dwarf_uint8(''), self.stream, offset)
opcode = struct_parse(structs.the_Dwarf_uint8, self.stream, offset)
args = []

primary = opcode & _PRIMARY_MASK
Expand All @@ -194,7 +194,7 @@ def _parse_instructions(self, structs, offset, end_offset):
elif primary == DW_CFA_offset:
args = [
primary_arg,
struct_parse(structs.Dwarf_uleb128(''), self.stream)]
struct_parse(structs.the_Dwarf_uleb128, self.stream)]
elif primary == DW_CFA_restore:
args = [primary_arg]
# primary == 0 and real opcode is extended
Expand All @@ -203,39 +203,39 @@ def _parse_instructions(self, structs, offset, end_offset):
args = []
elif opcode == DW_CFA_set_loc:
args = [
struct_parse(structs.Dwarf_target_addr(''), self.stream)]
struct_parse(structs.the_Dwarf_target_addr, self.stream)]
elif opcode == DW_CFA_advance_loc1:
args = [struct_parse(structs.Dwarf_uint8(''), self.stream)]
args = [struct_parse(structs.the_Dwarf_uint8, self.stream)]
elif opcode == DW_CFA_advance_loc2:
args = [struct_parse(structs.Dwarf_uint16(''), self.stream)]
args = [struct_parse(structs.the_Dwarf_uint16, self.stream)]
elif opcode == DW_CFA_advance_loc4:
args = [struct_parse(structs.Dwarf_uint32(''), self.stream)]
args = [struct_parse(structs.the_Dwarf_uint32, self.stream)]
elif opcode in (DW_CFA_offset_extended, DW_CFA_register,
DW_CFA_def_cfa, DW_CFA_val_offset):
args = [
struct_parse(structs.Dwarf_uleb128(''), self.stream),
struct_parse(structs.Dwarf_uleb128(''), self.stream)]
struct_parse(structs.the_Dwarf_uleb128, self.stream),
struct_parse(structs.the_Dwarf_uleb128, self.stream)]
elif opcode in (DW_CFA_restore_extended, DW_CFA_undefined,
DW_CFA_same_value, DW_CFA_def_cfa_register,
DW_CFA_def_cfa_offset):
args = [struct_parse(structs.Dwarf_uleb128(''), self.stream)]
args = [struct_parse(structs.the_Dwarf_uleb128, self.stream)]
elif opcode == DW_CFA_def_cfa_offset_sf:
args = [struct_parse(structs.Dwarf_sleb128(''), self.stream)]
args = [struct_parse(structs.the_Dwarf_sleb128, self.stream)]
elif opcode == DW_CFA_def_cfa_expression:
args = [struct_parse(
structs.Dwarf_dw_form['DW_FORM_block'], self.stream)]
elif opcode in (DW_CFA_expression, DW_CFA_val_expression):
args = [
struct_parse(structs.Dwarf_uleb128(''), self.stream),
struct_parse(structs.the_Dwarf_uleb128, self.stream),
struct_parse(
structs.Dwarf_dw_form['DW_FORM_block'], self.stream)]
elif opcode in (DW_CFA_offset_extended_sf,
DW_CFA_def_cfa_sf, DW_CFA_val_offset_sf):
args = [
struct_parse(structs.Dwarf_uleb128(''), self.stream),
struct_parse(structs.Dwarf_sleb128(''), self.stream)]
struct_parse(structs.the_Dwarf_uleb128, self.stream),
struct_parse(structs.the_Dwarf_sleb128, self.stream)]
elif opcode == DW_CFA_GNU_args_size:
args = [struct_parse(structs.Dwarf_uleb128(''), self.stream)]
args = [struct_parse(structs.the_Dwarf_uleb128, self.stream)]

else:
dwarf_assert(False, 'Unknown CFI opcode: 0x%x' % opcode)
Expand Down
Loading

0 comments on commit 75f0f98

Please sign in to comment.