"+methnm+"<" not in ln:
+ continue
+ if "= 0 | " in ln:
+ return True
+ return False
+
+
+
+def hack(appdir):
+ """Convenience function for hacking a frozen PySide app down to size.
+
+ This function is a simple convenience wrapper that creates a Hatchet
+ instance and calls its main "hack" method.
+ """
+ h = Hatchet(appdir)
+ h.hack()
+
+
+if __name__ == "__main__":
+ import optparse
+ usage = "usage: Hatchet [options] /path/to/frozen/app [extra files]"
+ op = optparse.OptionParser(usage=usage)
+ op.add_option("-d","--debug",default="DEBUG",
+ help="set the logging debug level")
+ op.add_option("","--follow-imports",
+ action="store_true",
+ dest="follow_imports",
+ help="follow import when loading code",
+ default=True)
+ op.add_option("","--no-follow-imports",
+ action="store_false",
+ help="don't follow imports when loading code",
+ dest="follow_imports")
+ op.add_option("","--analyse-only",
+ action="store_true",
+ help="just analyse the code, don't hack it",
+ dest="analyse_only")
+ (opts,args) = op.parse_args()
+ try:
+ opts.debugs = int(opts.debug)
+ except ValueError:
+ try:
+ opts.debug = getattr(logging,opts.debug)
+ except AttributeError:
+ print >>sys.stderr, "unknown debug level:", opts.debug
+ sys.exit(1)
+ logging.basicConfig(level=opts.debug,format="%(name)-12s: %(message)s")
+ if len(args) < 1:
+ op.print_help()
+ sys.exit(1)
+ if not os.path.isdir(args[0]):
+ print >>sys.stderr, "error: not a directory:", args[0]
+ sys.exit(2)
+ h = Hatchet(args[0])
+ for fnm in args[1:]:
+ if os.path.isdir(fnm):
+ h.add_directory(fnm,follow_imports=opts.follow_imports)
+ if fnm.endswith(".zip") or fnm.endswith(".exe"):
+ h.add_zipfile(fnm,follow_imports=opts.follow_imports)
+ else:
+ h.add_file(fnm,follow_imports=opts.follow_imports)
+ if not opts.analyse_only:
+ h.hack()
+ else:
+ logger = logging.getLogger("PySideKick.Hatchet")
+ if not h.mf.modules:
+ h.add_directory(h.appdir)
+ num_rejected_classes = 0
+ num_rejected_methods = 0
+ h.analyse_code()
+ for rej in h.find_rejections():
+ if len(rej) == 1:
+ logger.debug("reject %s",rej[0])
+ num_rejected_classes += 1
+ else:
+ logger.debug("reject %s::%s",rej[0],rej[1])
+ num_rejected_methods += 1
+ logger.info("keeping %d classes",len(h.keep_classes))
+ logger.info("rejecting %d classes, %d methods",num_rejected_classes,
+ num_rejected_methods)
+
+ sys.exit(0)
+
+
diff --git a/samples/dbg/PySideKick/__init__.py b/samples/dbg/PySideKick/__init__.py
new file mode 100644
index 0000000..ec58456
--- /dev/null
+++ b/samples/dbg/PySideKick/__init__.py
@@ -0,0 +1,56 @@
+# Copyright (c) 2009-2010, Cloud Matrix Pty. Ltd.
+# All rights reserved; available under the terms of the BSD License.
+"""
+
+PySideKick: helpful utilities for working with PySide
+======================================================
+
+
+This package is a rather ad-hoc collection of helpers, utilities and custom
+widgets for building applications with PySide. So far we have:
+
+ * PySideKick.Call: helpers for calling functions in a variety of ways,
+ e.g. qCallAfter, qCallInMainThread
+
+ * PySideKick.Console: a simple interactive console to embed in your
+ application
+
+ * PySideKick.Hatchet: a tool for hacking frozen PySide apps down to size,
+ by rebuilding PySide with a minimal set of classes
+
+"""
+
+__ver_major__ = 0
+__ver_minor__ = 2
+__ver_patch__ = 3
+__ver_sub__ = ""
+__ver_tuple__ = (__ver_major__,__ver_minor__,__ver_patch__,__ver_sub__)
+__version__ = "%d.%d.%d%s" % __ver_tuple__
+
+
+import thread
+
+from PySide import QtCore, QtGui
+from PySide.QtCore import Qt
+
+
+# Older versions of PySide don't expose the 'thread' attribute of QObject.
+# In this case, assume the thread importing this module is the main thread.
+if hasattr(QtCore.QCoreApplication,"thread"):
+ def qIsMainThread():
+ app = QtCore.QCoreApplication.instance()
+ if app is None:
+ return False
+ return QtCore.QThread.currentThread() is app.thread()
+else:
+ _MAIN_THREAD_ID = thread.get_ident()
+ def qIsMainThread():
+ return thread.get_ident() == _MAIN_THREAD_ID
+
+
+# PySideKick.Call needs to create a singleton object in the main gui thread.
+# Since this is *usually* the thread that imports this module, loading it here
+# will provide a small speedup in the common case.
+import PySideKick.Call
+
+
diff --git a/samples/dbg/commands/__init__.py b/samples/dbg/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/samples/dbg/commands/dbgcmd.py b/samples/dbg/commands/dbgcmd.py
new file mode 100644
index 0000000..371bf64
--- /dev/null
+++ b/samples/dbg/commands/dbgcmd.py
@@ -0,0 +1,54 @@
+from widget import *
+
+class DebuggerController(BaseController):
+
+ def __init__(self,dbgCore,mainWindow):
+ BaseController.__init__(self,dbgCore,mainWindow)
+ debugMenu = QMenu( "Debug" )
+
+ self.breakAction = QAction("Break", debugMenu )
+ self.breakAction.triggered.connect( self.onBreak )
+ self.breakAction.setDisabled(True)
+ debugMenu.addAction( self.breakAction )
+
+ self.goAction = QAction("Go", debugMenu )
+ self.goAction.triggered.connect( self.onGo )
+ self.goAction.setDisabled(True)
+ debugMenu.addAction( self.goAction )
+
+ self.stepAction = QAction("Step", debugMenu )
+ self.stepAction.triggered.connect( self.onStep )
+ self.stepAction.setDisabled(True)
+ debugMenu.addAction( self.stepAction )
+
+ mainWindow.menuBar().addMenu( debugMenu )
+
+ def onBreak( self ):
+ self.dbgCore.breakin()
+
+ def onGo( self ):
+ self.dbgCore.go()
+
+ def onStep( self ):
+ self.dbgCore.step()
+
+ def onDbgBreak(self):
+ self.breakAction.setDisabled(True)
+ self.goAction.setDisabled(False)
+ self.stepAction.setDisabled(False)
+
+ def onDbgRun(self):
+ self.breakAction.setDisabled(False)
+ self.goAction.setDisabled(True)
+ self.stepAction.setDisabled(True)
+
+ def onDbgAttach(self):
+ self.breakAction.setDisabled(False)
+ self.goAction.setDisabled(False)
+ self.stepAction.setDisabled(False)
+
+ def onDbgDetach(self):
+ self.breakAction.setDisabled(False)
+ self.goAction.setDisabled(False)
+ self.stepAction.setDisabled(False)
+
diff --git a/samples/dbg/commands/processcmd.py b/samples/dbg/commands/processcmd.py
new file mode 100644
index 0000000..58aa135
--- /dev/null
+++ b/samples/dbg/commands/processcmd.py
@@ -0,0 +1,38 @@
+
+from widget import *
+
+class ProcessController(BaseController):
+
+ def __init__(self, dbgCore, mainWindow):
+ BaseController.__init__(self,dbgCore,mainWindow)
+
+ self.openProcessAction = QAction( "Open process...", mainWindow.fileMenu )
+ self.openProcessAction.triggered.connect(self.onOpenProcess)
+ mainWindow.fileMenu.addAction(self.openProcessAction)
+
+ self.detachProcessAction = QAction( "Detach process", mainWindow.fileMenu )
+ self.detachProcessAction.triggered.connect(self.onDetachProcess)
+ self.detachProcessAction.setDisabled(True)
+ mainWindow.fileMenu.addAction(self.detachProcessAction)
+
+ def onOpenProcess(self):
+ fileDlg = QFileDialog( self.mainWnd )
+ fileDlg.setNameFilter( "Executable (*.exe)" )
+ self.dbgCore.openProcess( fileDlg.getOpenFileName()[0] )
+
+ def onDetachProcess(self):
+ self.dbgCore.detachProcess()
+
+ def onDbgAttach(self):
+ self.openProcessAction.setDisabled(True)
+ self.detachProcessAction.setDisabled(True)
+
+ def onDbgDetach(self):
+ self.openProcessAction.setDisabled(False)
+ self.detachProcessAction.setDisabled(True)
+
+ def onDbgBreak(self):
+ self.detachProcessAction.setDisabled(False)
+
+ def onDbgRun(self):
+ self.detachProcessAction.setDisabled(True)
\ No newline at end of file
diff --git a/samples/dbg/dbg.py b/samples/dbg/dbg.py
new file mode 100644
index 0000000..d18fe2b
--- /dev/null
+++ b/samples/dbg/dbg.py
@@ -0,0 +1,40 @@
+
+from PySide.QtCore import *
+from PySide.QtGui import *
+
+
+from dbgcore import DbgCore
+from settings import settings
+
+class MainForm(QMainWindow):
+
+ def __init__(self):
+ QMainWindow.__init__(self, None)
+ self.resize( 800, 600 )
+ self.setWindowTitle("Pykd Debugger Sample")
+ self.setDockNestingEnabled( True )
+
+ self.dbgCore = DbgCore()
+
+ self.fileMenu = QMenu( "&File" )
+ self.menuBar().addMenu( self.fileMenu )
+
+ self.viewMenu = QMenu( "View" )
+ self.menuBar().addMenu( self.viewMenu )
+
+ self.widgets = settings["default"](self.dbgCore, self )
+
+ self.fileMenu.addAction( "Exit", self.onExit )
+
+ def onExit(self):
+ self.dbgCore.close()
+ self.close()
+
+def main():
+ app = QApplication( [] )
+ mainForm = MainForm()
+ mainForm.show()
+ exitres = app.exec_()
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/samples/dbg/dbgcore.py b/samples/dbg/dbgcore.py
new file mode 100644
index 0000000..075005d
--- /dev/null
+++ b/samples/dbg/dbgcore.py
@@ -0,0 +1,70 @@
+
+import pykd
+
+from PySide.QtCore import QThread
+from PySide.QtCore import QObject
+from PySide.QtCore import Signal
+
+class DbgThread( QThread ):
+
+ def __init__(self, func):
+ QThread.__init__(self)
+ self.func = func
+
+ def run(self):
+ self.func()
+ self.exit()
+
+class DbgCore( QObject ):
+
+ targetBreak = Signal()
+ targetRunning = Signal()
+ targetAttached = Signal()
+ targetDetached = Signal()
+
+ def close(self):
+ if self.processOpened:
+ if self.thread != None:
+ self.breakin()
+
+ def openProcess( self, name ):
+ pykd.startProcess( name )
+ self.processOpened = True
+ self.targetAttached.emit()
+ self.targetBreak.emit()
+
+ def detachProcess(self):
+ pykd.detachProcess()
+ self.processOpened = False
+ self.targetDetached.emit()
+
+ def killProcess(self):
+ pykd.killProcess()
+ self.processOpened = False
+ self.targetDetached.emit()
+
+
+ def breakin( self ):
+ pykd.breakin()
+
+ def go( self ):
+ self.thread = DbgThread( pykd.go )
+ self.thread.finished.connect( self.onDebugStop )
+ self.targetRunning.emit()
+ self.thread.start()
+
+ def step( self ):
+ self.thread = DbgThread( pykd.step )
+ self.thread.finished.connect( self.onDebugStop )
+ self.targetRunning.emit()
+ self.thread.start()
+
+ def onDebugStop(self):
+ self.thread.wait(100)
+ self.thread = None
+ self.targetBreak.emit()
+
+ def __init__(self):
+ QObject.__init__(self)
+ self.thread = None
+ self.processOpened = False
\ No newline at end of file
diff --git a/samples/dbg/settings.py b/samples/dbg/settings.py
new file mode 100644
index 0000000..7418a69
--- /dev/null
+++ b/samples/dbg/settings.py
@@ -0,0 +1,18 @@
+
+from commands.processcmd import ProcessController
+from commands.dbgcmd import DebuggerController
+
+from widgets.registers import RegisterWidget
+from widgets.cmd import CmdWidget
+
+
+class DefaultSettings:
+
+ def __init__( self, dbgcore, parentwnd ):
+ self.processCmd = ProcessController( dbgcore, parentwnd )
+ self.debugCmd = DebuggerController( dbgcore, parentwnd )
+
+ self.regWidget = RegisterWidget( dbgcore, parentwnd )
+ self.cmdWidget = CmdWidget( dbgcore, parentwnd )
+
+settings = { "default" : DefaultSettings }
diff --git a/samples/dbg/widget.py b/samples/dbg/widget.py
new file mode 100644
index 0000000..79f4ec8
--- /dev/null
+++ b/samples/dbg/widget.py
@@ -0,0 +1,97 @@
+
+from PySide.QtCore import *
+from PySide.QtGui import *
+
+class BaseWidget( QDockWidget ):
+
+ def __init__( self, dbgCore, mainWindow, title = "", visible = False ):
+ QDockWidget.__init__( self )
+ self.setWindowTitle( title )
+ self.setVisible( visible )
+ mainWindow.addDockWidget( Qt.LeftDockWidgetArea, self )
+
+ self.dbgCore=dbgCore
+ self.mainWnd = mainWindow
+ dbgCore.targetBreak.connect( self.onDbgBreak )
+ dbgCore.targetRunning.connect( self.onDbgRun )
+ dbgCore.targetAttached.connect( self.onDbgAttach )
+ dbgCore.targetDetached.connect( self.onDbgDetach )
+
+ def addMenuTriggerAction( self, actionName ):
+ self.action = QAction( actionName, self.mainWnd )
+ self.action.triggered.connect(self.onTriggerAction)
+ self.action.setDisabled( True )
+ self.mainWnd.viewMenu.addAction(self.action)
+
+ def onDbgBreak(self):
+ pass
+
+ def onDbgRun(self):
+ pass
+
+ def onDbgAttach(self):
+ pass
+
+ def onDbgDetach(self):
+ pass
+
+ def onTriggerAction(self):
+ self.setVisible( not self.isVisible() )
+
+
+class DebugWidget( BaseWidget ):
+
+ def __init__( self, dbgCore, mainWindow, title = "", visible = False ):
+ BaseWidget.__init__( self, dbgCore, mainWindow, title, visible )
+ self.action = None
+
+ def onDbgAttach(self):
+ if self.action != None:
+ self.action.setDisabled( True )
+ self.setDisabled( True )
+
+ def onDbgDetach(self):
+ if self.action != None:
+ self.action.setDisabled( True )
+ self.setDisabled( True )
+
+ def onDbgBreak(self):
+ if self.action != None:
+ self.action.setDisabled( False )
+ self.setDisabled( False )
+ self.updateView()
+
+ def onDbgRun(self):
+ if self.action != None:
+ self.action.setDisabled( True )
+ self.setDisabled( True )
+
+ def updateView(self):
+ pass
+
+
+class BaseController(QObject):
+
+ def __init__(self,dbgCore,mainWindow):
+ QObject.__init__(self,mainWindow)
+ self.dbgCore=dbgCore
+ self.mainWnd = mainWindow
+ dbgCore.targetBreak.connect( self.onDbgBreak )
+ dbgCore.targetRunning.connect( self.onDbgRun )
+ dbgCore.targetAttached.connect( self.onDbgAttach )
+ dbgCore.targetDetached.connect( self.onDbgDetach )
+
+ def onDbgBreak(self):
+ self.onStateChange()
+
+ def onDbgRun(self):
+ self.onStateChange()
+
+ def onDbgAttach(self):
+ self.onStateChange()
+
+ def onDbgDetach(self):
+ self.onStateChange()
+
+ def onStateChange(self):
+ pass
\ No newline at end of file
diff --git a/samples/dbg/widgets/__init__.py b/samples/dbg/widgets/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/samples/dbg/widgets/cmd.py b/samples/dbg/widgets/cmd.py
new file mode 100644
index 0000000..22e383c
--- /dev/null
+++ b/samples/dbg/widgets/cmd.py
@@ -0,0 +1,23 @@
+
+from widget import *
+from PySideKick.Console import QPythonConsole
+
+class CmdWidget( DebugWidget ):
+
+ def __init__(self, dbgCore, mainWindow, visible = False ):
+ BaseWidget.__init__( self, dbgCore, mainWindow, "Commands", visible )
+
+ self.addMenuTriggerAction( "Commands" )
+ self.console = QPythonConsole()
+ self.setWidget( self.console )
+ self.console.interpreter.push("from pykd import *")
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/dbg/widgets/registers.py b/samples/dbg/widgets/registers.py
new file mode 100644
index 0000000..7a55f58
--- /dev/null
+++ b/samples/dbg/widgets/registers.py
@@ -0,0 +1,40 @@
+from widget import *
+import pykd
+
+class RegisterWidget( DebugWidget ):
+
+ def __init__(self, dbgCore, mainWindow, visible = False ):
+ BaseWidget.__init__( self, dbgCore, mainWindow, "Registers", visible )
+
+ self.addMenuTriggerAction( "Registers" )
+
+ self.textArea = QTextEdit()
+ self.setWidget( self.textArea )
+
+ def updateView(self):
+
+ s = ""
+
+ try:
+ i = 0
+ while True:
+ reg = pykd.reg(i)
+ s += "%s %x ( %d )\r\n" % ( reg.name(), reg, reg )
+ i += 1
+
+ except pykd.BaseException:
+ pass
+
+ self.textArea.setPlainText( s )
+
+
+
+
+
+
+
+
+
+
+
+