From 3da46a9dc92eb3d2a6c2defa8144d8aa0663d5ec Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Fri, 2 Dec 2011 16:28:56 +0200 Subject: [PATCH] moving on with line program stuffz --- elftools/dwarf/constants.py | 18 +++++++ elftools/dwarf/dwarfinfo.py | 16 ++++-- elftools/dwarf/lineprogram.py | 97 ++++++++++++++++++++++++++++++++++- 3 files changed, 125 insertions(+), 6 deletions(-) diff --git a/elftools/dwarf/constants.py b/elftools/dwarf/constants.py index 8dd489e..ae7e6b2 100644 --- a/elftools/dwarf/constants.py +++ b/elftools/dwarf/constants.py @@ -118,3 +118,21 @@ DW_ORD_row_major=0 DW_ORD_col_major=1 +# Line program opcodes +# +DW_LNS_copy = 0x01 +DW_LNS_advance_pc = 0x02 +DW_LNS_advance_line = 0x03 +DW_LNS_set_file = 0x04 +DW_LNS_set_column = 0x05 +DW_LNS_negate_stmt = 0x06 +DW_LNS_set_basic_block = 0x07 +DW_LNS_const_add_pc = 0x08 +DW_LNS_fixed_advance_pc = 0x09 +DW_LNS_set_prologue_end = 0x0a +DW_LNS_set_epilogue_begin = 0x0b +DW_LNS_set_isa = 0x0c +DW_LNE_end_sequence = 0x01 +DW_LNE_set_address = 0x02 +DW_LNE_define_file = 0x03 + diff --git a/elftools/dwarf/dwarfinfo.py b/elftools/dwarf/dwarfinfo.py index 64bf123..90ba52a 100644 --- a/elftools/dwarf/dwarfinfo.py +++ b/elftools/dwarf/dwarfinfo.py @@ -199,18 +199,26 @@ class DWARFInfo(object): dwarf_format=dwarf_format, address_size=4) + # Now parse the header fully using up-to-date structs. After this, + # the section stream will point at the beginning of the program + # itself, right after the header. lineprog_header = struct_parse( lineprog_structs.Dwarf_lineprog_header, self.debug_line_sec.stream, offset) + # Calculate the offset to the next line program (see DWARF 6.2.4) + end_offset = ( offset + lineprog_header['unit_length'] + + lineprog_structs.initial_length_field_size())) + lineprograms.append(LineProgram( header=lineprog_header, dwarfinfo=self, - structs=lineprog_structs)) + structs=lineprog_structs, + program_start_offset=self.debug_line_sec.stream.tell()), + program_end_offset=end_offset) + + offset = end_offset - # Calculate the offset to the next line program (see DWARF 6.2.4) - offset += ( lineprog_header['unit_length'] + - lineprog_structs.initial_length_field_size()) return lineprograms diff --git a/elftools/dwarf/lineprogram.py b/elftools/dwarf/lineprogram.py index d865141..ce92075 100644 --- a/elftools/dwarf/lineprogram.py +++ b/elftools/dwarf/lineprogram.py @@ -6,13 +6,65 @@ # Eli Bendersky (eliben@gmail.com) # This code is in the public domain #------------------------------------------------------------------------------- +from ..common.utils import struct_parse +from .constants import * + + +class LineState(object): + """ Represents a line program state (or a "row" in the matrix + describing debug location information for addresses). + """ + def __init__(self, default_is_stmt): + self.address = 0 + self.file = 1 + self.line = 1 + self.column = 0 + self.is_stmt = default_is_stmt + self.basic_block = False + self.end_sequence = False + self.prologue_end = False + self.epilogue_begin = False + self.isa = 0 class LineProgram(object): - def __init__(self, header, dwarfinfo, structs): + """ 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, + program_start_offset, program_end_offset): + """ + header: + The header of this line program + + dwarfinfo: + The DWARFInfo context object which created this one + + 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] + """ self.dwarfinfo = dwarfinfo + self.stream = self.dwarfinfo.debug_line_sec.stream self.header = header - pass + self.structs = structs + self.program_start_offset = program_start_offset + self.program_end_offset = program_end_offset + + self._line_table = None + + def get_line_table(self): + """ Get the decoded line table for this line program + """ + if self._line_table is None: + self._line_table = self._decode_line_program() + return self._line_table #------ PRIVATE ------# @@ -21,3 +73,44 @@ class LineProgram(object): """ return self.header[name] + def _decode_line_program(self): + linetable = [] + state = LineState(self.header['default_is_stmt']) + + offset = self.program_start_offset + while offset < self.program_end_offset: + opcode = struct_parse( + self.structs.Dwarf_uint8, + self.stream, + offset) + + # As an exercise in avoiding premature optimization, if...elif + # chains are used here for standard and extended opcodes instead + # of dispatch tables. This keeps the code much cleaner. Besides, + # the majority of instructions are special opcodes anyway. + if opcode == 0: + # Extended opcode: start with a zero byte, followed by + # instruction size and the instruction itself. + pass + elif opcode < self.header['opcode_base']: + # Standard opcode + if opcode == DW_LNS_copy: + linetable.append(state) + state.basic_block = False + state.prologue_end = False + state.epilogue_begin = False + elif opcode == DW_LNS_advance_pc: + operand = struct_parse(self.Dwarf_uleb128, self.stream) + state.address += ( + operand * self.header['minimum_instruction_length']) + elif opcode = DW_LNS_advance_line: + operand = struct_parse(self.Dwarf_sleb128, self.stream) + state.line += operand + # ZZZ! go on now... + else: + # Special opcode + pass + + def _handle_LNS_copy(self, opcode, state, linetable): + pass + -- 2.30.2