Skip to content

Commit

Permalink
24 bit integer support, forms strx3, addrx3 (#553)
Browse files Browse the repository at this point in the history
* 24 bit integer support, forms strx3, addrx3

* More DWARFv1 constants

* More DWARFv1 constants

* LLVM lineprog header content type codes

* No global declarations
  • Loading branch information
sevaa committed Apr 19, 2024
1 parent 9257a0f commit 7336640
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 4 deletions.
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()

0 comments on commit 7336640

Please sign in to comment.