--- /dev/null
+#!/usr/bin/python
+
+
+import select
+import sys
+import thread
+import threading
+import time
+import os
+import pty
+
+
+class DbgTerminal:
+
+ def __init__ (self, binary, gdbReadCallback, childReadCallback):
+
+ #Set some members
+ self.gdbReadCallback = gdbReadCallback
+ self.childReadCallback = childReadCallback
+ self.binary = binary
+ self.stopped = False
+
+ #Connect to sub-process
+ self.__connect()
+
+ def __connect( self ):
+
+
+ #Open pseudo-terminal where to-be-debugged process reads/writes to
+ self.ptymaster, self.ptyslave = pty.openpty()
+ self.childout = os.fdopen(self.ptymaster, "r", 0)
+ self.childin = os.fdopen(self.ptymaster, "w", 0)
+
+ #Open the subprocess and get in- and out-streams
+ cmd = self.getCommand(self.binary)
+ self.gdbin, self.gdbout = os.popen4( cmd, bufsize=0)
+
+
+ #Set up a reading thread to gdb output
+ self.gdbReadThread = self.ReadThread(self.gdbout, self.gdbReadCallback)
+ self.gdbReadThread.start()
+
+ #Set up a reading thread to gdb output
+ self.childReadThread = self.ReadThread(self.childout, self.childReadCallback)
+ self.childReadThread.start()
+
+ #Set up tty gdb-childs process
+ time.sleep(0.1)
+ self.sendSetTTY(os.ttyname(self.ptyslave))
+ time.sleep(0.1)
+
+
+
+ def getCommand( self, binary ):
+ """Get the command to execute"""
+ raise NotImplementedError()
+
+
+ def iseof( self ):
+ """Check if terminal is closed already"""
+
+ return self.gdbReadThread.eventFin.isSet()
+
+
+ def stop( self ):
+
+ if not self.stopped:
+
+ self.stopped = True
+
+ #Finish the reading-thread
+ self.gdbReadThread.fin = True
+ self.childReadThread.fin = True
+ self.gdbReadThread.eventFin.wait(1)
+ self.childReadThread.eventFin.wait(1)
+
+
+ def sendBreak(self, file, lineno):
+ raise NotImplementedError()
+
+ def sendContinue(self):
+ raise NotImplementedError()
+
+ def sendRun(self):
+ raise NotImplementedError()
+
+ def sendInspectVar(self, var):
+ raise NotImplementedError()
+
+ def sendInspectExpr(self, expr):
+ raise NotImplementedError()
+
+ def sendSetTTY(self, ttyname):
+ raise NotImplementedError()
+
+ def sendQuit(self):
+ raise NotImplementedError()
+
+
+ class ReadThread (threading.Thread):
+ """Thread which reads from sub-process output"""
+
+ def __init__( self, stream, callback, sleep=0.1):
+ self.stream = stream
+ self.fin = False
+ self.callback = callback
+ self.sleep = sleep
+ self.eventFin = threading.Event()
+ threading.Thread.__init__(self)
+
+ def run(self):
+
+ try:
+ while True:
+ #Wait until data is available
+ rlist, wlist, xlist = select.select([self.stream], [], [], self.sleep)
+
+ #If we should finish, finish
+ if self.fin:
+ break
+
+ #Got new data
+ if len(rlist) > 0:
+ fd = rlist[0]
+ str = fd.read(1)
+ #Call callbacks
+ self.callback(str)
+ except:
+ pass
+
+ #Set the finished event
+ self.eventFin.set()
+
+
+
+
+class GdbTerminal (DbgTerminal):
+
+ def getCommand( self, binary ):
+ return "gdb --fullname %s" % (binary,)
+
+ def sendBreak(self, file, lineno):
+ self.gdbin.write("break %s:%d\n" % (file, lineno))
+
+ def sendContinue(self):
+ self.gdbin.write("cont\n")
+
+ def sendRun(self):
+ self.gdbin.write("run\n")
+
+ def sendInspectVar(self, var):
+ self.sendInspectExpr(var)
+
+ def sendInspectExpr(self, expr):
+ self.gdbin.write("print %s\n" % (expr,))
+
+ def sendSetTTY(self, ttyname):
+ self.gdbin.write("set inferior-tty %s\n" % (ttyname,))
+
+ def sendQuit(self):
+ self.gdbin.write("quit\n")
+ DbgTerminal.stop(self)
+
+
+
+if __name__ == "__main__":
+
+ def tostdout(str):
+ sys.stdout.write(str)
+ sys.stdout.flush()
+
+ try:
+
+ term = GdbTerminal( "./main", tostdout, tostdout)
+ term.sendBreak("main.cpp", 13)
+ term.sendRun()
+ term.childin.write("1\n");
+ term.childin.write("2\n");
+ term.sendInspectVar("a+b")
+ term.sendContinue()
+
+
+ while not term.iseof():
+
+ cmd = sys.stdin.readline()
+
+ if term.iseof():
+ break
+
+ if cmd == "quit\n":
+ term.sendQuit()
+ else:
+ term.gdbin.write(cmd)
+
+ except Exception, e:
+ print e
+ except:
+ pass
+
+
+ print "stopping..."
+ term.stop()
+
+
+