1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/lineprogram.py
4 # DWARF line number program
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 *
13 class LineState(object):
14 """ Represents a line program state (or a "row" in the matrix
15 describing debug location information for addresses).
17 def __init__(self
, default_is_stmt
):
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
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.
36 def __init__(self
, header
, dwarfinfo
, structs
,
37 program_start_offset
, program_end_offset
):
40 The header of this line program
43 The DWARFInfo context object which created this one
46 A DWARFStructs instance suitable for this line program
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]
53 self
.dwarfinfo
= dwarfinfo
54 self
.stream
= self
.dwarfinfo
.debug_line_sec
.stream
56 self
.structs
= structs
57 self
.program_start_offset
= program_start_offset
58 self
.program_end_offset
= program_end_offset
60 self
._line
_table
= None
62 def get_line_table(self
):
63 """ Get the decoded line table for this line program
65 if self
._line
_table
is None:
66 self
._line
_table
= self
._decode
_line
_program
()
67 return self
._line
_table
69 #------ PRIVATE ------#
71 def __getitem__(self
, name
):
72 """ Implement dict-like access to header entries
74 return self
.header
[name
]
76 def _decode_line_program(self
):
78 state
= LineState(self
.header
['default_is_stmt'])
80 offset
= self
.program_start_offset
81 while offset
< self
.program_end_offset
:
82 opcode
= struct_parse(
83 self
.structs
.Dwarf_uint8
,
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.
92 # Extended opcode: start with a zero byte, followed by
93 # instruction size and the instruction itself.
95 elif opcode
< self
.header
['opcode_base']:
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
)
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
114 def _handle_LNS_copy(self
, opcode
, state
, linetable
):