--- /dev/null
+#-------------------------------------------------------------------------------
+# elftools: common/construct_utils.py
+#
+# Some complementary construct utilities
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+from ..construct import Subconstruct, ConstructError, ArrayError
+
+
+class RepeatUntilExcluding(Subconstruct):
+ """ A version of construct's RepeatUntil that doesn't include the last
+ element (which casued the repeat to exit) in the return value.
+
+ Only parsing is currently implemented.
+
+ P.S. removed some code duplication
+ """
+ __slots__ = ["predicate"]
+ def __init__(self, predicate, subcon):
+ Subconstruct.__init__(self, subcon)
+ self.predicate = predicate
+ self._clear_flag(self.FLAG_COPY_CONTEXT)
+ self._set_flag(self.FLAG_DYNAMIC)
+ def _parse(self, stream, context):
+ obj = []
+ try:
+ context_for_subcon = context
+ if self.subcon.conflags & self.FLAG_COPY_CONTEXT:
+ context_for_subcon = context.__copy__()
+
+ while True:
+ subobj = self.subcon._parse(stream, context_for_subcon)
+ if self.predicate(subobj, context):
+ break
+ obj.append(subobj)
+ except ConstructError, ex:
+ raise ArrayError("missing terminator", ex)
+ return obj
+ def _build(self, obj, stream, context):
+ raise NotImplementedError('no building')
+ def _sizeof(self, context):
+ raise SizeofError("can't calculate size")
+
UBInt8, UBInt16, UBInt32, UBInt64, ULInt8, ULInt16, ULInt32, ULInt64,
SBInt8, SBInt16, SBInt32, SBInt64, SLInt8, SLInt16, SLInt32, SLInt64,
Adapter, Struct, ConstructError, If, RepeatUntil, Field, Rename, Enum,
- PrefixedArray, CString,
+ Array, PrefixedArray, CString, Embed,
)
+from ..common.construct_utils import RepeatUntilExcluding
from .enums import *
A dictionary mapping 'DW_FORM_*' keys into construct Structs
that parse such forms. These Structs have already been given
dummy names.
+
+ Dwarf_lineprog_header (+):
+ Line program header
See also the documentation of public methods.
"""
self._create_cu_header()
self._create_abbrev_declaration()
self._create_dw_form()
+ self._create_lineprog_header()
def _create_initial_length(self):
def _InitialLength(name):
DW_FORM_indirect=self.Dwarf_uleb128(''),
)
+ def _create_lineprog_header(self):
+ # A file entry is terminated by a NULL byte, so we don't want to parse
+ # past it. Therefore an If is used.
+ file_entry = Struct('file_entry',
+ CString('name'),
+ If(lambda ctx: len(ctx.name) != 0,
+ Embed(Struct('',
+ self.Dwarf_uleb128('dir_index'),
+ self.Dwarf_uleb128('mtime'),
+ self.Dwarf_uleb128('length')))))
+
+ self.Dwarf_lineprog_header = Struct('Dwarf_lineprog_header',
+ self.Dwarf_initial_length('unit_length'),
+ self.Dwarf_uint16('version'),
+ self.Dwarf_offset('header_length'),
+ self.Dwarf_uint8('minimum_instruction_length'),
+ self.Dwarf_uint8('default_is_stmt'),
+ self.Dwarf_int8('line_base'),
+ self.Dwarf_uint8('line_range'),
+ self.Dwarf_uint8('opcode_base'),
+ Array(lambda ctx: ctx['opcode_base'] - 1,
+ self.Dwarf_uint8('standard_opcode_lengths')),
+ RepeatUntilExcluding(
+ lambda obj, ctx: obj == '',
+ CString('include_directory')),
+ RepeatUntilExcluding(
+ lambda obj, ctx: len(obj.name) == 0,
+ file_entry),
+ )
+
def _make_block_struct(self, length_field):
""" Create a struct for DW_FORM_block<size>
"""
--- /dev/null
+import sys, unittest
+
+sys.path.extend(['.', '..'])
+from elftools.dwarf.structs import DWARFStructs
+
+
+class TestDWARFStructs(unittest.TestCase):
+ def test_lineprog_header(self):
+ ds = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
+
+ c = ds.Dwarf_lineprog_header.parse(
+ '\x04\x10\x00\x00' + # initial lenght
+ '\x05\x02' + # version
+ '\x20\x00\x00\x00' + # header length
+ '\x05\x10\x40\x50' + # until and including line_range
+ '\x06' + # opcode_base
+ '\x00\x01\x04\x08\x0C' + # standard_opcode_lengths
+ # 2 dir names followed by a NULL
+ '\x61\x62\x00\x70\x00\x00' +
+ # a file entry
+ '\x61\x72\x00\x0C\x0D\x0F' +
+ # and another entry
+ '\x45\x50\x51\x00\x86\x12\x07\x08' +
+ # followed by NULL
+ '\x00')
+
+ self.assertEqual(c.version, 0x205)
+ self.assertEqual(c.opcode_base, 6)
+ self.assertEqual(c.standard_opcode_lengths, [0, 1, 4, 8, 12])
+ self.assertEqual(c.include_directory, ['ab', 'p'])
+ self.assertEqual(len(c.file_entry), 2)
+ self.assertEqual(c.file_entry[0].name, 'ar')
+ self.assertEqual(c.file_entry[1].name, 'EPQ')
+ self.assertEqual(c.file_entry[1].dir_index, 0x12 * 128 + 6)
+
+
+if __name__ == '__main__':
+ unittest.main()
+