from PyQt4 import QtCore, QtGui
import vtrace
import envi.qt as envi_qt
import vqt.tree as vq_tree
import vqt.colors as vq_colors
from envi.threads import firethread
from vqt.main import idlethread, idlethreadsync
'''
QtGui objects which assist in GUIs which use vtrace parts.
'''
[docs]class VQTraceNotifier(vtrace.Notifier):
'''
A bit of shared mixin code for the handling of vtrace
notifier callbacks in various VQTreeViews...
'''
def __init__(self, trace=None):
self.trace = trace
vtrace.Notifier.__init__(self)
self.trace.registerNotifier(vtrace.NOTIFY_ALL, self)
@idlethreadsync
# FIXME this should be part of a shared API!
[docs] def notify(self, event, trace):
if event in [vtrace.NOTIFY_CONTINUE, vtrace.NOTIFY_DETACH, vtrace.NOTIFY_EXIT]:
self.setEnabled(False)
else:
# If the trace is just going to run again, skip the update.
if not trace.shouldRunAgain():
self.setEnabled(True)
self.vqLoad()
[docs]class VQRegisterListModel(vq_tree.VQTreeModel):
columns = ('Name', 'Hex', 'Dec')
[docs]class VQRegistersListView(vq_tree.VQTreeView, VQTraceNotifier):
'''
A pure "list view" object for registers
'''
def __init__(self, trace=None, parent=None):
VQTraceNotifier.__init__(self, trace)
vq_tree.VQTreeView.__init__(self, parent=parent)
self.setModel(VQRegisterListModel(parent=self))
self.setAlternatingRowColors(True)
self.regnames = None
self.lastregs = {}
self.regvals = {}
self.vqLoad()
[docs] def vqLoad(self):
self.lastregs = self.regvals
if not self.trace.isAttached():
self.setEnabled(False)
return
if self.trace.isRunning():
self.setEnabled(False)
return
model = VQRegisterListModel(parent=self)
self.setModel(model)
regs = self.trace.getRegisters()
names = self.regnames
if names == None:
names = regs.keys()
names.sort()
for rname in names:
rval = regs.get(rname)
model.append( (rname, '0x%.8x' % rval, rval) )
self.regvals = regs
[docs]class RegColorDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent):
QtGui.QStyledItemDelegate.__init__(self, parent)
self.reglist = parent
[docs] def paint(self, painter, option, index):
node = index.internalPointer()
weight = QtGui.QFont.Normal
if self.reglist.lastregs.get(node.rowdata[0]) != node.rowdata[2]:
weight = QtGui.QFont.Bold
option.font.setWeight(weight)
return QtGui.QStyledItemDelegate.paint(self, painter, option, index)
[docs]class VQRegistersView(QtGui.QWidget):
'''
A register view which includes the idea of "sub views" for particular
sets of registers per-architecture.
'''
def __init__(self, trace=None, parent=None):
QtGui.QWidget.__init__(self, parent=parent)
self.setWindowTitle('Registers')
vbox = QtGui.QVBoxLayout(self)
vbox.setMargin(2)
vbox.setSpacing(4)
self.viewnames = QtGui.QComboBox(self)
self.viewnames.addItem('all')
self.regviews = {}
arch = trace.getMeta('Architecture')
# FIXME make this in envi or something once and for all...
if arch == 'i386':
self.regviews['general'] = ['eax','ebx','ecx','edx','esi','edi','ebp','esp','eip']
elif arch == 'amd64':
self.regviews['general'] = ['rax','rbx','rcx','rdx','rsi','rdi','rbp','rsp','rip',
'r8','r9','r10','r11','r12','r13','r14','r15']
for name in self.regviews.keys():
self.viewnames.addItem(name)
sig = QtCore.SIGNAL('currentIndexChanged(QString)')
self.viewnames.connect(self.viewnames, sig, self.regViewNameSelected)
self.reglist = VQRegistersListView(trace=trace, parent=self)
self.regdelegate = RegColorDelegate(self.reglist)
self.reglist.setItemDelegate(self.regdelegate)
vbox.addWidget(self.viewnames)
vbox.addWidget(self.reglist)
self.setLayout(vbox)
[docs] def regViewNameSelected(self, name):
self.reglist.regnames = self.regviews.get(str(name), None)
self.reglist.vqLoad()
[docs]class VQProcessListModel(vq_tree.VQTreeModel):
columns = ('Pid','Name')
[docs]class VQProcessListView(vq_tree.VQTreeView):
def __init__(self, trace=None, parent=None):
vq_tree.VQTreeView.__init__(self, parent=parent)
if trace == None:
trace = vtrace.getTrace()
self.trace = trace
model = VQProcessListModel(parent=self)
self.setModel(model)
self.setAlternatingRowColors(True)
for pid,name in self.trace.ps():
model.append((pid,name))
[docs]class VQProcessSelectDialog(QtGui.QDialog):
def __init__(self, trace=None, parent=None):
QtGui.QDialog.__init__(self, parent=parent)
self.pid = None
self.setWindowTitle('Select a process...')
vlyt = QtGui.QVBoxLayout()
hlyt = QtGui.QHBoxLayout()
self.plisttree = VQProcessListView(trace=trace, parent=self)
hbox = QtGui.QWidget(parent=self)
ok = QtGui.QPushButton("Ok", parent=hbox)
cancel = QtGui.QPushButton("Cancel", parent=hbox)
self.plisttree.doubleClicked.connect( self.dialog_activated )
ok.clicked.connect(self.dialog_ok)
cancel.clicked.connect(self.dialog_cancel)
hlyt.addStretch(1)
hlyt.addWidget(cancel)
hlyt.addWidget(ok)
hbox.setLayout(hlyt)
vlyt.addWidget(self.plisttree)
vlyt.addWidget(hbox)
self.setLayout(vlyt)
self.resize(300, 500)
[docs] def dialog_activated(self, idx):
node = idx.internalPointer()
if node:
self.pid = node.rowdata[0]
self.accept()
[docs] def dialog_ok(self):
for idx in self.plisttree.selectedIndexes():
node = idx.internalPointer()
if node:
self.pid = node.rowdata[0]
break
self.accept()
[docs] def dialog_cancel(self):
self.reject()
@idlethreadsync
def getProcessPid(trace=None, parent=None):
d = VQProcessSelectDialog(trace=trace, parent=parent)
r = d.exec_()
return d.pid
[docs]class FileDescModel(vq_tree.VQTreeModel):
columns = ('Fd','Type','Name')
[docs]class VQFileDescView(vq_tree.VQTreeView, VQTraceNotifier):
def __init__(self, trace, parent=None):
VQTraceNotifier.__init__(self, trace)
vq_tree.VQTreeView.__init__(self, parent=parent)
self.setWindowTitle('File Descriptors')
self.setModel(FileDescModel(parent=self))
self.vqLoad()
[docs] def vqLoad(self):
if not self.trace.isAttached():
self.setEnabled(False)
return
if self.trace.isRunning():
self.setEnabled(False)
return
model = FileDescModel(parent=self)
for fd,fdtype,bestname in self.trace.getFds():
model.append((fd, fdtype, bestname))
self.setModel(model)
[docs]class VQMemoryMapView(envi_qt.VQMemoryMapView, VQTraceNotifier):
'''
A memory map view which is sensitive to the status of a
trace object.
'''
def __init__(self, trace, parent=None):
VQTraceNotifier.__init__(self, trace)
envi_qt.VQMemoryMapView.__init__(self, trace, parent=parent)
[docs] def vqLoad(self):
if not self.trace.isAttached():
self.setEnabled(False)
return
if self.trace.isRunning():
self.setEnabled(False)
return
envi_qt.VQMemoryMapView.vqLoad(self)
[docs]class VQThreadListModel(vq_tree.VQTreeModel):
columns = ('Thread Id','Thread Info', 'State')
[docs]class VQThreadsView(vq_tree.VQTreeView, VQTraceNotifier):
def __init__(self, trace=None, parent=None, selectthread=None):
# selectthread is an optional endpoint to connect to
VQTraceNotifier.__init__(self, trace)
vq_tree.VQTreeView.__init__(self, parent=parent)
self.setWindowTitle('Threads')
self.setModel(VQThreadListModel(parent=self))
self.setAlternatingRowColors(True)
self.vqLoad()
self.selectthread = selectthread
[docs] def selectionChanged(self, selected, deselected):
idx = self.selectedIndexes()[0]
node = idx.internalPointer()
if node:
self.trace.selectThread(node.rowdata[0])
return vq_tree.VQTreeView.selectionChanged(self, selected, deselected)
[docs] def vqLoad(self):
if not self.trace.isAttached():
self.setEnabled(False)
return
if self.trace.isRunning():
self.setEnabled(False)
return
model = VQThreadListModel(parent=self)
stid = self.trace.getMeta('ThreadId')
for i, (tid, tinfo) in enumerate(self.trace.getThreads().items()):
state = ''
if self.trace.isThreadSuspended(tid):
state = 'suspended'
model.append((tid, tinfo, state))
self.setModel(model)