Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

24 bit integer support, forms strx3, addrx3 #553

Merged
merged 6 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion elftools/common/construct_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------------
from struct import Struct
from ..construct import (
Subconstruct, ConstructError, ArrayError, Adapter, Field, RepeatUntil,
Rename, SizeofError, Construct
Rename, SizeofError, Construct, StaticField
)


Expand Down Expand Up @@ -110,3 +111,30 @@ def _build(self, obj, stream, context):
context[self.name] = stream.tell()
def _sizeof(self, context):
return 0

_UBInt24_packer = Struct(">BH")
_ULInt24_packer = Struct("<HB")

class UBInt24(StaticField):
"""unsigned, big endian 24-bit integer"""
def __init__(self, name):
StaticField.__init__(self, name, 3)

def _parse(self, stream, context):
(h, l) = _UBInt24_packer.unpack(StaticField._parse(self, stream, context))
return l | (h << 16)

def _build(self, obj, stream, context):
StaticField._build(self, _UBInt24_packer.pack(obj >> 16, obj & 0xFFFF), stream, context)

class ULInt24(StaticField):
"""unsigned, little endian 24-bit integer"""
def __init__(self, name):
StaticField.__init__(self, name, 3)

def _parse(self, stream, context):
(l, h) = _ULInt24_packer.unpack(StaticField._parse(self, stream, context))
return l | (h << 16)

def _build(self, obj, stream, context):
StaticField._build(self, _ULInt24_packer.pack(obj & 0xFFFF, obj >> 16), stream, context)
2 changes: 2 additions & 0 deletions elftools/dwarf/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@
DW_LNCT_size = 0x04
DW_LNCT_MD5 = 0x05
DW_LNCT_lo_user = 0x2000
DW_LNCT_LLVM_source = 0x2001
DW_LNCT_LLVM_is_MD5 = 0x2002
DW_LNCT_hi_user = 0x3fff

# Call frame instructions
Expand Down
5 changes: 5 additions & 0 deletions elftools/dwarf/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
DW_AT_const_value = 0x1c,
DW_AT_containing_type = 0x1d,
DW_AT_default_value = 0x1e,
DW_AT_friends = 0x1f,
DW_AT_inline = 0x20,
DW_AT_is_optional = 0x21,
DW_AT_lower_bound = 0x22,
Expand All @@ -152,7 +153,9 @@
DW_AT_protected = 0x26,
DW_AT_prototyped = 0x27,
DW_AT_public = 0x28,
DW_AT_pure_virtual = 0x29,
DW_AT_return_addr = 0x2a,
# In DWARFv1, DW_AT_specification was at 0x2b, moved to 0x47 in v2
DW_AT_start_scope = 0x2c,
DW_AT_bit_stride = 0x2e,
DW_AT_stride_size = 0x2e,
Expand Down Expand Up @@ -413,6 +416,8 @@
DW_LNCT_size = 0x4,
DW_LNCT_MD5 = 0x5,
DW_LNCT_lo_user = 0x2000,
DW_LNCT_LLVM_source = 0x2001,
DW_LNCT_LLVM_is_MD5 = 0x2002,
DW_LNCT_hi_user = 0x3fff
)

Expand Down
8 changes: 5 additions & 3 deletions elftools/dwarf/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
String, Switch, Value
)
from ..common.construct_utils import (RepeatUntilExcluding, ULEB128, SLEB128,
StreamOffset)
StreamOffset, ULInt24, UBInt24)
from .enums import *


Expand Down Expand Up @@ -121,6 +121,7 @@ def _create_structs(self):
if self.little_endian:
self.Dwarf_uint8 = ULInt8
self.Dwarf_uint16 = ULInt16
self.Dwarf_uint24 = ULInt24
self.Dwarf_uint32 = ULInt32
self.Dwarf_uint64 = ULInt64
self.Dwarf_offset = ULInt32 if self.dwarf_format == 32 else ULInt64
Expand All @@ -134,6 +135,7 @@ def _create_structs(self):
else:
self.Dwarf_uint8 = UBInt8
self.Dwarf_uint16 = UBInt16
self.Dwarf_uint24 = UBInt24
self.Dwarf_uint32 = UBInt32
self.Dwarf_uint64 = UBInt64
self.Dwarf_offset = UBInt32 if self.dwarf_format == 32 else UBInt64
Expand Down Expand Up @@ -253,7 +255,7 @@ def _create_dw_form(self):
DW_FORM_addrx=self.Dwarf_uleb128(''),
DW_FORM_addrx1=self.Dwarf_uint8(''),
DW_FORM_addrx2=self.Dwarf_uint16(''),
# DW_FORM_addrx3=self.Dwarf_uint24(''), # TODO
DW_FORM_addrx3=self.Dwarf_uint24(''),
DW_FORM_addrx4=self.Dwarf_uint32(''),

DW_FORM_block1=self._make_block_struct(self.Dwarf_uint8),
Expand All @@ -276,7 +278,7 @@ def _create_dw_form(self):
DW_FORM_line_strp=self.Dwarf_offset(''),
DW_FORM_strx1=self.Dwarf_uint8(''),
DW_FORM_strx2=self.Dwarf_uint16(''),
# DW_FORM_strx3=self.Dwarf_uint24(''), # TODO
DW_FORM_strx3=self.Dwarf_uint24(''),
DW_FORM_strx4=self.Dwarf_uint64(''),
DW_FORM_flag=self.Dwarf_uint8(''),

Expand Down
30 changes: 30 additions & 0 deletions test/test_int24.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#------------------------------------------------------------------------------
# elftools tests
#
# Seva Alekseyev (sevaa@sprynet.com)
# This code is in the public domain
#------------------------------------------------------------------------------
import unittest
import random
from io import BytesIO

from elftools.common.construct_utils import ULInt24, UBInt24
from elftools.common.utils import struct_parse

class TestInt24(unittest.TestCase):
def test_main(self):
# Testing parsing and building, both LE and BE
b = random.randbytes(3)

n = struct_parse(UBInt24(''), BytesIO(b))
self.assertEqual(n, (b[0] << 16) | (b[1] << 8) | b[2])
s = UBInt24('').build(n)
self.assertEqual(s, b)

n = struct_parse(ULInt24(''), BytesIO(b))
self.assertEqual(n, b[0] | (b[1] << 8) | (b[2] << 16))
s = ULInt24('').build(n)
self.assertEqual(s, b)

if __name__ == '__main__':
unittest.main()
Loading