/
debugcontroller.py
176 lines (145 loc) · 6.45 KB
/
debugcontroller.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# ricodebug - A GDB frontend which focuses on visually supported
# debugging using data structure graphs and SystemC features.
#
# Copyright (C) 2011 The ricodebug project team at the
# Upper Austrian University Of Applied Sciences Hagenberg,
# Department Embedded Systems Design
#
# This file is part of ricodebug.
#
# ricodebug is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# For further information see <http://syscdbg.hagenberg.servus.at/>.
import os
from PyQt4.QtCore import QObject, SIGNAL, Qt, QSettings
from helpers.ptyhandler import PtyHandler
from helpers.gdboutput import GdbOutput
import logging
class DebugController(QObject):
def __init__(self, distributedObjects):
QObject.__init__(self)
self.settings = QSettings("fh-hagenberg", "SysCDbg")
self.ptyhandler = PtyHandler()
self.distributedObjects = distributedObjects
self.connector = self.distributedObjects.gdb_connector
self.editorController = self.distributedObjects.editorController
self.breakpointController = self.distributedObjects.breakpointController
self.signalProxy = self.distributedObjects.signalProxy
self.executableName = None
self.lastCmdWasStep = False
self.ptyhandler.start()
self.connector.start()
QObject.connect(self.connector.reader, SIGNAL('asyncRecordReceived(PyQt_PyObject)'), self.handleAsyncRecord, Qt.QueuedConnection)
def openExecutable(self, filename):
# die if the file does not exist or has been provided without at least a
# relative path; files without a path work with pythons os.* functions
# but fail in gdb, so do an extra check for those
if not os.path.exists(filename) or os.path.dirname(filename) == "":
logging.error("File %s was not found." % filename)
return
if self.editorController.closeOpenedFiles(): #closing source files may be canceled by user
if self.executableName != None:
#clear variables, tracepoints, watches,... by connecting to this signal
self.signalProxy.emitCleanupModels()
self.connector.changeWorkingDirectory(os.path.dirname(filename))
self.connector.openFile(filename)
self.emit(SIGNAL('executableOpened'), filename)
self.executableName = filename
def run(self):
self.connector.setTty(self.ptyhandler.ptyname)
self.connector.run()
# FIXME: Add check or option in settings menu
self.connector.record()
self.lastCmdWasStep = False
self.signalProxy.emitRunClicked()
def next_(self):
self.connector.next_()
self.lastCmdWasStep = True
def reverse_next(self):
self.connector.reverse_next()
self.lastCmdWasStep = True
def step(self):
self.connector.step()
self.lastCmdWasStep = True
def reverse_step(self):
self.connector.reverse_step()
self.lastCmdWasStep = True
def cont(self):
self.connector.cont()
self.lastCmdWasStep = False
def interrupt(self):
self.connector.interrupt()
self.lastCmdWasStep = False
def finish(self):
self.connector.finish()
self.lastCmdWasStep = False
def until(self, file_, line):
self.connector.until(file_, line)
self.lastCmdWasStep = False
def evaluateExpression(self, exp):
if exp == "":
return None
exp = exp.replace('"', '\"')
return self.connector.evaluate("\"" + exp + "\"")
def executeCliCommand(self, cmd):
return self.connector.executeCliCommand(cmd)
def handleAsyncRecord(self, rec):
if rec.type_ == GdbOutput.EXEC_ASYN:
if rec.class_ == GdbOutput.STOPPED:
self.handleStoppedRecord(rec)
elif rec.class_ == GdbOutput.RUNNING:
self.signalProxy.emitInferiorIsRunning(rec)
def handleStoppedRecord(self, rec):
for r in rec.results:
if r.dest == 'reason':
reason = r.src
if r.dest == 'frame':
frame = r.src
if r.dest == 'signal-name':
signal_name = r.src
if r.dest == 'signal-meaning':
signal_meaning = r.src
if r.dest == 'frame':
frame = r.src
if r.dest == "bkptno":
bkptno = int(r.src)
if reason in ['exited-normally', 'exited']:
self.signalProxy.emitInferiorHasExited(rec)
elif reason == 'breakpoint-hit':
stop = False
tp = self.distributedObjects.tracepointController.model().getTracepointIfAvailable(frame)
if self.distributedObjects.breakpointController.model().isBreakpointByNumber(bkptno) or self.lastCmdWasStep:
self.signalProxy.emitInferiorStoppedNormally(rec)
stop = True
self.lastCmdWasStep = False
if tp != None:
tp.tracePointOccurred(stop)
self.distributedObjects.signalProxy.emitTracepointOccurred()
elif reason == "signal-received":
logging.warning("Signal received: %s (%s) in %s:%s", signal_name, signal_meaning, frame.file, frame.line)
self.signalProxy.emitInferiorReceivedSignal(rec)
else:
self.signalProxy.emitInferiorStoppedNormally(rec)
def executePythonCode(self, code):
exec(code, {'do': self.distributedObjects})
def inferiorUntil(self):
current_opened_file = self.editorController.editor_view.getCurrentOpenedFile()
line, _ = current_opened_file.edit.getCursorPosition()
self.until(current_opened_file.filename, line + 1)
def getExecutableName(self):
return self.executableName
def getStackDepth(self):
return self.connector.getStackDepth()
def selectStackFrame(self, exp):
return self.connector.selectStackFrame(exp)