DWARF v4 lineprograms add additional debugging information for VLIW architectures, specifically they add an op_index field identifying the operation within the instruction to which this lineprogram refers.
This field has been added to the LineState object. On non-VLIW architectures and for non DWARF v4 lineprograms this field will always be 0.
self.file = 1
self.line = 1
self.column = 0
+ self.op_index = 0
self.is_stmt = default_is_stmt
self.basic_block = False
self.end_sequence = False
# opcodes anyway.
if opcode >= self.header['opcode_base']:
# Special opcode (follow the recipe in 6.2.5.1)
+ maximum_operations_per_instruction = self['maximum_operations_per_instruction']
+
+
adjusted_opcode = opcode - self['opcode_base']
- address_addend = ((adjusted_opcode // self['line_range']) *
- self['minimum_instruction_length'])
+ operation_advance = adjusted_opcode // self['line_range']
+
+ address_addend = self['minimum_instruction_length'] * ((state.op_index + operation_advance) // maximum_operations_per_instruction)
+
state.address += address_addend
- line_addend = (self['line_base'] +
- adjusted_opcode % self['line_range'])
+
+ state.op_index = (state.op_index + operation_advance) % maximum_operations_per_instruction
+
+ line_addend = self['line_base'] + (adjusted_opcode % self['line_range'])
+
state.line += line_addend
- add_entry_new_state(opcode, [line_addend, address_addend])
+
+ add_entry_new_state(opcode, [line_addend, address_addend, state.op_index])
+
+
elif opcode == 0:
# Extended opcode: start with a zero byte, followed by
# instruction size and the instruction itself.
self.Dwarf_uint16('version'),
self.Dwarf_offset('header_length'),
self.Dwarf_uint8('minimum_instruction_length'),
+
+ If(lambda ctx: ctx['version'] >= 4,
+ self.Dwarf_uint8("maximum_operations_per_instruction"),
+ 1),
+
self.Dwarf_uint8('default_is_stmt'),
self.Dwarf_int8('line_base'),
self.Dwarf_uint8('line_range'),
# readelf doesn't print the state after end_sequence
# instructions. I think it's a bug but to be compatible
# I don't print them too.
- self._emitline('%-35s %11d %18s' % (
- bytes2str(lineprogram['file_entry'][state.file - 1].name),
- state.line,
- '0' if state.address == 0 else
- self._format_hex(state.address)))
+ if lineprogram['version'] < 4:
+ self._emitline('%-35s %11d %18s' % (
+ bytes2str(lineprogram['file_entry'][state.file - 1].name),
+ state.line,
+ '0' if state.address == 0 else
+ self._format_hex(state.address)))
+ else:
+ self._emitline('%-35s %11d %18s[%d]' % (
+ bytes2str(lineprogram['file_entry'][state.file - 1].name),
+ state.line,
+ '0' if state.address == 0 else
+ self._format_hex(state.address),
+ state.op_index))
if entry.command == DW_LNS_copy:
# Another readelf oddity...
self._emitline()
self.assertEqual(linetable[0].args, [0x239])
self.assertLineState(linetable[1].state, address=0x239, line=3)
self.assertEqual(linetable[1].command, 0xb)
- self.assertEqual(linetable[1].args, [2, 0])
+ self.assertEqual(linetable[1].args, [2, 0, 0])
self.assertLineState(linetable[2].state, address=0x23c, line=5)
self.assertLineState(linetable[3].state, address=0x244, line=6)
self.assertLineState(linetable[4].state, address=0x24b, line=7, end_sequence=False)
ds = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
c = ds.Dwarf_lineprog_header.parse(
- b'\x04\x10\x00\x00' + # initial lenght
- b'\x05\x02' + # version
+ b'\x04\x10\x00\x00' + # initial length
+ b'\x02\x00' + # version
b'\x20\x00\x00\x00' + # header length
b'\x05\x10\x40\x50' + # until and including line_range
b'\x06' + # opcode_base
# and another entry
b'\x45\x50\x51\x00\x86\x12\x07\x08' +
# followed by NULL
- b'\x00')
-
- self.assertEqual(c.version, 0x205)
+ b'\x00')
+ self.assertEqual(c.version, 2)
self.assertEqual(c.opcode_base, 6)
self.assertEqual(c.standard_opcode_lengths, [0, 1, 4, 8, 12])
self.assertEqual(c.include_directory, [b'ab', b'p'])