moving on with line program stuffz
[pyelftools.git] / elftools / dwarf / lineprogram.py
1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/lineprogram.py
3 #
4 # DWARF line number program
5 #
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from ..common.utils import struct_parse
10 from .constants import *
11
12
13 class LineState(object):
14 """ Represents a line program state (or a "row" in the matrix
15 describing debug location information for addresses).
16 """
17 def __init__(self, default_is_stmt):
18 self.address = 0
19 self.file = 1
20 self.line = 1
21 self.column = 0
22 self.is_stmt = default_is_stmt
23 self.basic_block = False
24 self.end_sequence = False
25 self.prologue_end = False
26 self.epilogue_begin = False
27 self.isa = 0
28
29
30 class LineProgram(object):
31 """ Builds a "line table", which is essentially the matrix described
32 in section 6.2 of DWARFv3. It's a list of LineState objects,
33 sorted by increasing address, so it can be used to obtain the
34 state information for each address.
35 """
36 def __init__(self, header, dwarfinfo, structs,
37 program_start_offset, program_end_offset):
38 """
39 header:
40 The header of this line program
41
42 dwarfinfo:
43 The DWARFInfo context object which created this one
44
45 structs:
46 A DWARFStructs instance suitable for this line program
47
48 program_{start|end}_offset:
49 Offset in the debug_line section stream where this program
50 starts, and where it ends. The actual range includes start
51 but not end: [start, end - 1]
52 """
53 self.dwarfinfo = dwarfinfo
54 self.stream = self.dwarfinfo.debug_line_sec.stream
55 self.header = header
56 self.structs = structs
57 self.program_start_offset = program_start_offset
58 self.program_end_offset = program_end_offset
59
60 self._line_table = None
61
62 def get_line_table(self):
63 """ Get the decoded line table for this line program
64 """
65 if self._line_table is None:
66 self._line_table = self._decode_line_program()
67 return self._line_table
68
69 #------ PRIVATE ------#
70
71 def __getitem__(self, name):
72 """ Implement dict-like access to header entries
73 """
74 return self.header[name]
75
76 def _decode_line_program(self):
77 linetable = []
78 state = LineState(self.header['default_is_stmt'])
79
80 offset = self.program_start_offset
81 while offset < self.program_end_offset:
82 opcode = struct_parse(
83 self.structs.Dwarf_uint8,
84 self.stream,
85 offset)
86
87 # As an exercise in avoiding premature optimization, if...elif
88 # chains are used here for standard and extended opcodes instead
89 # of dispatch tables. This keeps the code much cleaner. Besides,
90 # the majority of instructions are special opcodes anyway.
91 if opcode == 0:
92 # Extended opcode: start with a zero byte, followed by
93 # instruction size and the instruction itself.
94 pass
95 elif opcode < self.header['opcode_base']:
96 # Standard opcode
97 if opcode == DW_LNS_copy:
98 linetable.append(state)
99 state.basic_block = False
100 state.prologue_end = False
101 state.epilogue_begin = False
102 elif opcode == DW_LNS_advance_pc:
103 operand = struct_parse(self.Dwarf_uleb128, self.stream)
104 state.address += (
105 operand * self.header['minimum_instruction_length'])
106 elif opcode = DW_LNS_advance_line:
107 operand = struct_parse(self.Dwarf_sleb128, self.stream)
108 state.line += operand
109 # ZZZ! go on now...
110 else:
111 # Special opcode
112 pass
113
114 def _handle_LNS_copy(self, opcode, state, linetable):
115 pass
116