return LineProgram(
header=lineprog_header,
- dwarfinfo=self,
+ stream=self.debug_line_sec.stream,
structs=structs,
program_start_offset=self.debug_line_sec.stream.tell(),
program_end_offset=end_offset)
a.append(' %s = %s' % (attr, getattr(self, attr)))
return '\n'.join(a) + '>\n'
+
class LineProgram(object):
""" Builds a "line table", which is essentially the matrix described
in section 6.2 of DWARFv3. It's a list of LineState objects,
sorted by increasing address, so it can be used to obtain the
state information for each address.
"""
- def __init__(self, header, dwarfinfo, structs,
+ def __init__(self, header, stream, structs,
program_start_offset, program_end_offset):
"""
header:
its header by appending file entries if DW_LNE_define_file
instructions are encountered.
- dwarfinfo:
- The DWARFInfo context object which created this one
+ stream:
+ The stream this program can be read from.
structs:
A DWARFStructs instance suitable for this line program
program_{start|end}_offset:
Offset in the debug_line section stream where this program
- starts, and where it ends. The actual range includes start
- but not end: [start, end - 1]
+ starts (the actual program, after the header), and where it
+ ends.
+ The actual range includes start but not end: [start, end - 1]
"""
- self.dwarfinfo = dwarfinfo
- self.stream = self.dwarfinfo.debug_line_sec.stream
+ self.stream = stream
self.header = header
self.structs = structs
self.program_start_offset = program_start_offset
state.address += ((adjusted_opcode / self['line_range']) *
self['minimum_instruction_length'])
elif opcode == DW_LNS_fixed_advance_pc:
- operand = struct_parse(self.structs.Dwarf_uint16,
+ operand = struct_parse(self.structs.Dwarf_uint16(''),
self.stream)
state.address += operand
elif opcode == DW_LNS_set_prologue_end:
--- /dev/null
+#!/usr/bin/env python
+#-------------------------------------------------------------------------------
+# tests/run_all_unittests.py
+#
+# Run all unit tests
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+from unittest import TestLoader, TextTestRunner
+
+
+if __name__ == '__main__':
+ try:
+ tests = TestLoader().discover('tests', 'test*.py', 'tests')
+ TextTestRunner().run(tests)
+ except ImportError as err:
+ print err
+ print '!! Please execute from the root directory of pyelfutils'
+
--- /dev/null
+import sys, unittest
+from cStringIO import StringIO
+
+sys.path.extend(['.', '..'])
+from elftools.dwarf.lineprogram import LineProgram, LineState
+from elftools.dwarf.structs import DWARFStructs
+
+
+class TestLineProgram(unittest.TestCase):
+ def _make_program_in_stream(self, stream):
+ """ Create a LineProgram from the given program encoded in a stream
+ """
+ ds = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
+ header = ds.Dwarf_lineprog_header.parse(
+ '\x04\x10\x00\x00' + # initial lenght
+ '\x03\x00' + # version
+ '\x20\x00\x00\x00' + # header length
+ '\x01\x01\x01\x0F' + # flags
+ '\x0A' + # opcode_base
+ '\x00\x01\x04\x08\x0C\x01\x01\x01\x00' + # 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')
+
+ lp = LineProgram(header, stream, ds, 0, len(stream.getvalue()))
+ return lp
+
+ def assertLineState(self, state, **kwargs):
+ """ Assert that the state attributes specified in kwargs have the given
+ values (the rest are default).
+ """
+ for k, v in kwargs.iteritems():
+ self.assertEqual(getattr(state, k), v)
+
+ def test_spec_sample_59(self):
+ # Sample in figure 59 of DWARFv3
+ s = StringIO()
+ s.write(
+ '\x02\xb9\x04' +
+ '\x0b' +
+ '\x38' +
+ '\x82' +
+ '\x73' +
+ '\x02\x02' +
+ '\x00\x01\x01')
+
+ lp = self._make_program_in_stream(s)
+ linetable = lp.get_line_table()
+
+ self.assertLineState(linetable[0], address=0x239, line=3)
+ self.assertLineState(linetable[1], address=0x23c, line=5)
+ self.assertLineState(linetable[2], address=0x244, line=6)
+ self.assertLineState(linetable[3], address=0x24b, line=7, end_sequence=False)
+ self.assertLineState(linetable[4], address=0x24d, line=7, end_sequence=True)
+
+ def test_spec_sample_60(self):
+ # Sample in figure 60 of DWARFv3
+ s = StringIO()
+ s.write(
+ '\x09\x39\x02' +
+ '\x0b' +
+ '\x09\x03\x00' +
+ '\x0b' +
+ '\x09\x08\x00' +
+ '\x0a' +
+ '\x09\x07\x00' +
+ '\x0a' +
+ '\x09\x02\x00' +
+ '\x00\x01\x01')
+
+ lp = self._make_program_in_stream(s)
+ linetable = lp.get_line_table()
+
+ self.assertLineState(linetable[0], address=0x239, line=3)
+ self.assertLineState(linetable[1], address=0x23c, line=5)
+ self.assertLineState(linetable[2], address=0x244, line=6)
+ self.assertLineState(linetable[3], address=0x24b, line=7, end_sequence=False)
+ self.assertLineState(linetable[4], address=0x24d, line=7, end_sequence=True)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
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')
+ '\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)
dwarfinfo = efile.get_dwarf_info()
CUs = list(dwarfinfo.iter_CUs())
print 'num CUs:', len(CUs)
-print 'first CU:', CUs[0]
+print 'CU:', CUs[2]
-lp = dwarfinfo.line_program_for_CU(CUs[0])
+lp = dwarfinfo.line_program_for_CU(CUs[2])
print 'lp:', lp, lp.header
print 'linetable:', lp.get_line_table()
#for lp in dwarfinfo.iter_line_programs():