moving on with line program stuffz
authorEli Bendersky <eliben@gmail.com>
Fri, 2 Dec 2011 14:28:56 +0000 (16:28 +0200)
committerEli Bendersky <eliben@gmail.com>
Fri, 2 Dec 2011 14:28:56 +0000 (16:28 +0200)
elftools/dwarf/constants.py
elftools/dwarf/dwarfinfo.py
elftools/dwarf/lineprogram.py

index 8dd489e756d46978fe7e95b31bfbe159e0e40e13..ae7e6b2e4a7e5269059db4c865147925839eca5a 100644 (file)
@@ -118,3 +118,21 @@ DW_ORD_row_major=0
 DW_ORD_col_major=1\r
 \r
 \r
+# Line program opcodes\r
+#\r
+DW_LNS_copy = 0x01\r
+DW_LNS_advance_pc = 0x02\r
+DW_LNS_advance_line = 0x03\r
+DW_LNS_set_file = 0x04\r
+DW_LNS_set_column = 0x05\r
+DW_LNS_negate_stmt = 0x06\r
+DW_LNS_set_basic_block = 0x07\r
+DW_LNS_const_add_pc = 0x08\r
+DW_LNS_fixed_advance_pc = 0x09\r
+DW_LNS_set_prologue_end = 0x0a\r
+DW_LNS_set_epilogue_begin = 0x0b\r
+DW_LNS_set_isa = 0x0c\r
+DW_LNE_end_sequence = 0x01\r
+DW_LNE_set_address = 0x02\r
+DW_LNE_define_file = 0x03\r
+\r
index 64bf12364b12f3c518d0cbe1dada23a8dafea64d..90ba52a197bdc4afc093f179a65905338a3cc6f0 100644 (file)
@@ -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
 
index d865141e5f544b8717877d1bbae8688cdd62dfd3..ce92075282d842ab928f56b45567e89cfbdab052 100644 (file)
@@ -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
+