Package vtrace :: Module qt
[hide private]
[frames] | no frames]

Source Code for Module vtrace.qt

  1  '''
 
  2  QtGui objects which assist in GUIs which use vtrace parts.
 
  3  ''' 
  4  from PyQt4 import QtCore, QtGui 
  5  
 
  6  import vtrace 
  7  
 
  8  import envi.qt as envi_qt 
  9  
 
 10  import vqt.tree as vq_tree 
 11  import vqt.colors as vq_colors 
 12  
 
 13  from envi.threads import firethread 
 14  from vqt.main import idlethread, idlethreadsync 
15 16 -class VQTraceNotifier(vtrace.Notifier):
17 ''' 18 A bit of shared mixin code for the handling of vtrace 19 notifier callbacks in various VQTreeViews... 20 '''
21 - def __init__(self, trace=None):
22 self.trace = trace 23 vtrace.Notifier.__init__(self) 24 self.trace.registerNotifier(vtrace.NOTIFY_ALL, self)
25 26 @idlethreadsync 27 # FIXME this should be part of a shared API!
28 - def notify(self, event, trace):
29 if event in [vtrace.NOTIFY_CONTINUE, vtrace.NOTIFY_DETACH, vtrace.NOTIFY_EXIT]: 30 self.setEnabled(False) 31 32 else: 33 # If the trace is just going to run again, skip the update. 34 if not trace.shouldRunAgain(): 35 self.setEnabled(True) 36 self.vqLoad()
37
38 -class VQRegisterListModel(vq_tree.VQTreeModel):
39 columns = ('Name', 'Hex', 'Dec')
40
41 -class VQRegistersListView(vq_tree.VQTreeView, VQTraceNotifier):
42 43 ''' 44 A pure "list view" object for registers 45 ''' 46
47 - def __init__(self, trace=None, parent=None):
48 VQTraceNotifier.__init__(self, trace) 49 vq_tree.VQTreeView.__init__(self, parent=parent) 50 self.setModel(VQRegisterListModel(parent=self)) 51 self.setAlternatingRowColors(True) 52 self.regnames = None 53 self.lastregs = {} 54 self.regvals = {} 55 56 self.vqLoad()
57
58 - def vqLoad(self):
59 60 self.lastregs = self.regvals 61 62 if not self.trace.isAttached(): 63 self.setEnabled(False) 64 return 65 66 if self.trace.isRunning(): 67 self.setEnabled(False) 68 return 69 70 model = VQRegisterListModel(parent=self) 71 self.setModel(model) 72 73 regs = self.trace.getRegisters() 74 75 names = self.regnames 76 if names == None: 77 names = regs.keys() 78 names.sort() 79 80 for rname in names: 81 rval = regs.get(rname) 82 model.append( (rname, '0x%.8x' % rval, rval) ) 83 84 self.regvals = regs
85
86 -class RegColorDelegate(QtGui.QStyledItemDelegate):
87
88 - def __init__(self, parent):
89 QtGui.QStyledItemDelegate.__init__(self, parent) 90 self.reglist = parent
91
92 - def paint(self, painter, option, index):
93 node = index.internalPointer() 94 weight = QtGui.QFont.Normal 95 if self.reglist.lastregs.get(node.rowdata[0]) != node.rowdata[2]: 96 weight = QtGui.QFont.Bold 97 option.font.setWeight(weight) 98 return QtGui.QStyledItemDelegate.paint(self, painter, option, index)
99
100 101 -class VQRegistersView(QtGui.QWidget):
102 103 ''' 104 A register view which includes the idea of "sub views" for particular 105 sets of registers per-architecture. 106 ''' 107
108 - def __init__(self, trace=None, parent=None):
109 QtGui.QWidget.__init__(self, parent=parent) 110 self.setWindowTitle('Registers') 111 112 vbox = QtGui.QVBoxLayout(self) 113 vbox.setMargin(2) 114 vbox.setSpacing(4) 115 116 self.viewnames = QtGui.QComboBox(self) 117 self.viewnames.addItem('all') 118 self.regviews = {} 119 120 arch = trace.getMeta('Architecture') 121 122 # FIXME make this in envi or something once and for all... 123 124 if arch == 'i386': 125 self.regviews['general'] = ['eax','ebx','ecx','edx','esi','edi','ebp','esp','eip'] 126 127 elif arch == 'amd64': 128 self.regviews['general'] = ['rax','rbx','rcx','rdx','rsi','rdi','rbp','rsp','rip', 129 'r8','r9','r10','r11','r12','r13','r14','r15'] 130 131 for name in self.regviews.keys(): 132 self.viewnames.addItem(name) 133 134 sig = QtCore.SIGNAL('currentIndexChanged(QString)') 135 self.viewnames.connect(self.viewnames, sig, self.regViewNameSelected) 136 137 self.reglist = VQRegistersListView(trace=trace, parent=self) 138 self.regdelegate = RegColorDelegate(self.reglist) 139 self.reglist.setItemDelegate(self.regdelegate) 140 141 vbox.addWidget(self.viewnames) 142 vbox.addWidget(self.reglist) 143 144 self.setLayout(vbox)
145
146 - def regViewNameSelected(self, name):
147 self.reglist.regnames = self.regviews.get(str(name), None) 148 self.reglist.vqLoad()
149
150 -class VQProcessListModel(vq_tree.VQTreeModel):
151 columns = ('Pid','Name')
152
153 -class VQProcessListView(vq_tree.VQTreeView):
154 - def __init__(self, trace=None, parent=None):
155 vq_tree.VQTreeView.__init__(self, parent=parent) 156 if trace == None: 157 trace = vtrace.getTrace() 158 self.trace = trace 159 160 model = VQProcessListModel(parent=self) 161 self.setModel(model) 162 self.setAlternatingRowColors(True) 163 164 for pid,name in self.trace.ps(): 165 model.append((pid,name))
166
167 -class VQProcessSelectDialog(QtGui.QDialog):
168
169 - def __init__(self, trace=None, parent=None):
170 QtGui.QDialog.__init__(self, parent=parent) 171 172 self.pid = None 173 174 self.setWindowTitle('Select a process...') 175 176 vlyt = QtGui.QVBoxLayout() 177 hlyt = QtGui.QHBoxLayout() 178 179 self.plisttree = VQProcessListView(trace=trace, parent=self) 180 181 hbox = QtGui.QWidget(parent=self) 182 183 ok = QtGui.QPushButton("Ok", parent=hbox) 184 cancel = QtGui.QPushButton("Cancel", parent=hbox) 185 186 self.plisttree.doubleClicked.connect( self.dialog_activated ) 187 188 ok.clicked.connect(self.dialog_ok) 189 cancel.clicked.connect(self.dialog_cancel) 190 191 hlyt.addStretch(1) 192 hlyt.addWidget(cancel) 193 hlyt.addWidget(ok) 194 hbox.setLayout(hlyt) 195 196 vlyt.addWidget(self.plisttree) 197 vlyt.addWidget(hbox) 198 self.setLayout(vlyt) 199 200 self.resize(300, 500)
201
202 - def dialog_activated(self, idx):
203 node = idx.internalPointer() 204 if node: 205 self.pid = node.rowdata[0] 206 self.accept()
207
208 - def dialog_ok(self):
209 for idx in self.plisttree.selectedIndexes(): 210 node = idx.internalPointer() 211 if node: 212 self.pid = node.rowdata[0] 213 break 214 self.accept()
215
216 - def dialog_cancel(self):
217 self.reject()
218
219 @idlethreadsync 220 -def getProcessPid(trace=None, parent=None):
221 d = VQProcessSelectDialog(trace=trace, parent=parent) 222 r = d.exec_() 223 return d.pid
224
225 -class FileDescModel(vq_tree.VQTreeModel):
226 columns = ('Fd','Type','Name')
227
228 -class VQFileDescView(vq_tree.VQTreeView, VQTraceNotifier):
229
230 - def __init__(self, trace, parent=None):
231 VQTraceNotifier.__init__(self, trace) 232 vq_tree.VQTreeView.__init__(self, parent=parent) 233 self.setWindowTitle('File Descriptors') 234 self.setModel(FileDescModel(parent=self)) 235 self.vqLoad()
236
237 - def vqLoad(self):
238 239 if not self.trace.isAttached(): 240 self.setEnabled(False) 241 return 242 243 if self.trace.isRunning(): 244 self.setEnabled(False) 245 return 246 247 model = FileDescModel(parent=self) 248 for fd,fdtype,bestname in self.trace.getFds(): 249 model.append((fd, fdtype, bestname)) 250 self.setModel(model)
251
252 -class VQTraceToolBar(QtGui.QToolBar, vtrace.Notifier):
253
254 - def __init__(self, trace, parent=None):
255 QtGui.QToolBar.__init__(self, parent=parent) 256 vtrace.Notifier.__init__(self) 257 self.trace = trace 258 259 self.setObjectName('VtraceToolbar') 260 261 self.attach_action = self.addAction('Attach') 262 self.attach_action.setStatusTip('Attach to a process') 263 self.attach_action.triggered.connect(self.actAttach) 264 265 self.detach_action = self.addAction('Detach') 266 self.detach_action.setStatusTip('Detach from current process') 267 self.detach_action.triggered.connect(self.actDetach) 268 269 self.continue_action = self.addAction('Continue') 270 self.continue_action.setStatusTip('Continue current process') 271 self.continue_action.triggered.connect(self.actContinue) 272 273 self.break_action = self.addAction('Break') 274 self.break_action.setStatusTip('Break current process') 275 self.break_action.triggered.connect(self.actBreak) 276 277 self.stepi_action = self.addAction('Stepi') 278 self.stepi_action.setStatusTip('Single step the current process') 279 self.stepi_action.triggered.connect(self.actStepi) 280 281 trace.registerNotifier(vtrace.NOTIFY_ALL, self) 282 self._updateActions(trace.isAttached(), trace.isRunning())
283
284 - def actAttach(self, *args, **kwargs):
285 pid = getProcessPid(trace=self.trace) 286 if pid != None: 287 firethread(self.trace.attach)(pid)
288
289 - def actDetach(self, thing):
290 if self.trace.isAttached(): 291 firethread(self.trace.detach)()
292
293 - def actContinue(self, thing):
294 firethread(self.trace.run)()
295
296 - def actBreak(self, thing):
297 if self.trace.getMeta('PendingBreak'): 298 return 299 self.trace.setMeta('PendingBreak', True) 300 firethread(self.trace.sendBreak)()
301
302 - def actStepi(self, thing):
303 firethread(self.trace.stepi)()
304 305 @idlethread
306 - def _updateActions(self, attached, running):
307 if not attached: 308 self.attach_action.setEnabled(True) 309 self.detach_action.setEnabled(False) 310 self.continue_action.setEnabled(False) 311 self.break_action.setEnabled(False) 312 self.stepi_action.setEnabled(False) 313 else: 314 if running: 315 self.attach_action.setEnabled(False) 316 self.detach_action.setEnabled(False) 317 self.continue_action.setEnabled(False) 318 self.break_action.setEnabled(True) 319 self.stepi_action.setEnabled(False) 320 else: 321 self.attach_action.setEnabled(False) 322 self.detach_action.setEnabled(True) 323 self.continue_action.setEnabled(True) 324 self.break_action.setEnabled(True) 325 self.stepi_action.setEnabled(True)
326
327 - def notify(self, event, trace):
328 if event == vtrace.NOTIFY_DETACH: 329 self._updateActions(False, False) 330 331 elif event == vtrace.NOTIFY_CONTINUE: 332 self._updateActions(True, True) 333 334 else: 335 self._updateActions(trace.isAttached(), trace.shouldRunAgain())
336
337 -class VQMemoryMapView(envi_qt.VQMemoryMapView, VQTraceNotifier):
338 ''' 339 A memory map view which is sensitive to the status of a 340 trace object. 341 '''
342 - def __init__(self, trace, parent=None):
343 VQTraceNotifier.__init__(self, trace) 344 envi_qt.VQMemoryMapView.__init__(self, trace, parent=parent)
345
346 - def vqLoad(self):
347 348 if not self.trace.isAttached(): 349 self.setEnabled(False) 350 return 351 352 if self.trace.isRunning(): 353 self.setEnabled(False) 354 return 355 356 envi_qt.VQMemoryMapView.vqLoad(self)
357
358 -class VQThreadListModel(vq_tree.VQTreeModel):
359 columns = ('Thread Id','Thread Info', 'State')
360
361 -class VQThreadsView(vq_tree.VQTreeView, VQTraceNotifier):
362
363 - def __init__(self, trace=None, parent=None, selectthread=None):
364 # selectthread is an optional endpoint to connect to 365 VQTraceNotifier.__init__(self, trace) 366 vq_tree.VQTreeView.__init__(self, parent=parent) 367 self.setWindowTitle('Threads') 368 self.setModel(VQThreadListModel(parent=self)) 369 self.setAlternatingRowColors(True) 370 self.vqLoad() 371 self.selectthread = selectthread
372
373 - def selectionChanged(self, selected, deselected):
374 idx = self.selectedIndexes()[0] 375 node = idx.internalPointer() 376 if node: 377 self.trace.selectThread(node.rowdata[0]) 378 379 return vq_tree.VQTreeView.selectionChanged(self, selected, deselected)
380
381 - def vqLoad(self):
382 383 if not self.trace.isAttached(): 384 self.setEnabled(False) 385 return 386 387 if self.trace.isRunning(): 388 self.setEnabled(False) 389 return 390 391 model = VQThreadListModel(parent=self) 392 393 stid = self.trace.getMeta('ThreadId') 394 for i, (tid, tinfo) in enumerate(self.trace.getThreads().items()): 395 state = '' 396 if self.trace.isThreadSuspended(tid): 397 state = 'suspended' 398 model.append((tid, tinfo, state)) 399 400 self.setModel(model)
401