diff --git a/elftools/common/construct_utils.py b/elftools/common/construct_utils.py index 6ef7f461..425b7c59 100644 --- a/elftools/common/construct_utils.py +++ b/elftools/common/construct_utils.py @@ -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 ) @@ -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("> 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) diff --git a/elftools/dwarf/constants.py b/elftools/dwarf/constants.py index 0ca82bdc..a2596a8f 100644 --- a/elftools/dwarf/constants.py +++ b/elftools/dwarf/constants.py @@ -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 diff --git a/elftools/dwarf/enums.py b/elftools/dwarf/enums.py index bd8db2d5..25bf2b64 100644 --- a/elftools/dwarf/enums.py +++ b/elftools/dwarf/enums.py @@ -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, @@ -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, @@ -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 ) diff --git a/elftools/dwarf/structs.py b/elftools/dwarf/structs.py index 8fa6b58a..bad6a8cc 100644 --- a/elftools/dwarf/structs.py +++ b/elftools/dwarf/structs.py @@ -16,7 +16,7 @@ String, Switch, Value ) from ..common.construct_utils import (RepeatUntilExcluding, ULEB128, SLEB128, - StreamOffset) + StreamOffset, ULInt24, UBInt24) from .enums import * @@ -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 @@ -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 @@ -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), @@ -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(''), diff --git a/test/test_int24.py b/test/test_int24.py new file mode 100644 index 00000000..00c634db --- /dev/null +++ b/test/test_int24.py @@ -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() \ No newline at end of file