initial commit with a little terminal code to gdb
[pygdb.git] / DbgTerminal.py
1 #!/usr/bin/python
2
3
4 import select
5 import sys
6 import thread
7 import threading
8 import time
9 import os
10 import pty
11
12
13 class DbgTerminal:
14
15 def __init__ (self, binary, gdbReadCallback, childReadCallback):
16
17 #Set some members
18 self.gdbReadCallback = gdbReadCallback
19 self.childReadCallback = childReadCallback
20 self.binary = binary
21 self.stopped = False
22
23 #Connect to sub-process
24 self.__connect()
25
26 def __connect( self ):
27
28
29 #Open pseudo-terminal where to-be-debugged process reads/writes to
30 self.ptymaster, self.ptyslave = pty.openpty()
31 self.childout = os.fdopen(self.ptymaster, "r", 0)
32 self.childin = os.fdopen(self.ptymaster, "w", 0)
33
34 #Open the subprocess and get in- and out-streams
35 cmd = self.getCommand(self.binary)
36 self.gdbin, self.gdbout = os.popen4( cmd, bufsize=0)
37
38
39 #Set up a reading thread to gdb output
40 self.gdbReadThread = self.ReadThread(self.gdbout, self.gdbReadCallback)
41 self.gdbReadThread.start()
42
43 #Set up a reading thread to gdb output
44 self.childReadThread = self.ReadThread(self.childout, self.childReadCallback)
45 self.childReadThread.start()
46
47 #Set up tty gdb-childs process
48 time.sleep(0.1)
49 self.sendSetTTY(os.ttyname(self.ptyslave))
50 time.sleep(0.1)
51
52
53
54 def getCommand( self, binary ):
55 """Get the command to execute"""
56 raise NotImplementedError()
57
58
59 def iseof( self ):
60 """Check if terminal is closed already"""
61
62 return self.gdbReadThread.eventFin.isSet()
63
64
65 def stop( self ):
66
67 if not self.stopped:
68
69 self.stopped = True
70
71 #Finish the reading-thread
72 self.gdbReadThread.fin = True
73 self.childReadThread.fin = True
74 self.gdbReadThread.eventFin.wait(1)
75 self.childReadThread.eventFin.wait(1)
76
77
78 def sendBreak(self, file, lineno):
79 raise NotImplementedError()
80
81 def sendContinue(self):
82 raise NotImplementedError()
83
84 def sendRun(self):
85 raise NotImplementedError()
86
87 def sendInspectVar(self, var):
88 raise NotImplementedError()
89
90 def sendInspectExpr(self, expr):
91 raise NotImplementedError()
92
93 def sendSetTTY(self, ttyname):
94 raise NotImplementedError()
95
96 def sendQuit(self):
97 raise NotImplementedError()
98
99
100 class ReadThread (threading.Thread):
101 """Thread which reads from sub-process output"""
102
103 def __init__( self, stream, callback, sleep=0.1):
104 self.stream = stream
105 self.fin = False
106 self.callback = callback
107 self.sleep = sleep
108 self.eventFin = threading.Event()
109 threading.Thread.__init__(self)
110
111 def run(self):
112
113 try:
114 while True:
115 #Wait until data is available
116 rlist, wlist, xlist = select.select([self.stream], [], [], self.sleep)
117
118 #If we should finish, finish
119 if self.fin:
120 break
121
122 #Got new data
123 if len(rlist) > 0:
124 fd = rlist[0]
125 str = fd.read(1)
126 #Call callbacks
127 self.callback(str)
128 except:
129 pass
130
131 #Set the finished event
132 self.eventFin.set()
133
134
135
136
137 class GdbTerminal (DbgTerminal):
138
139 def getCommand( self, binary ):
140 return "gdb --fullname %s" % (binary,)
141
142 def sendBreak(self, file, lineno):
143 self.gdbin.write("break %s:%d\n" % (file, lineno))
144
145 def sendContinue(self):
146 self.gdbin.write("cont\n")
147
148 def sendRun(self):
149 self.gdbin.write("run\n")
150
151 def sendInspectVar(self, var):
152 self.sendInspectExpr(var)
153
154 def sendInspectExpr(self, expr):
155 self.gdbin.write("print %s\n" % (expr,))
156
157 def sendSetTTY(self, ttyname):
158 self.gdbin.write("set inferior-tty %s\n" % (ttyname,))
159
160 def sendQuit(self):
161 self.gdbin.write("quit\n")
162 DbgTerminal.stop(self)
163
164
165
166 if __name__ == "__main__":
167
168 def tostdout(str):
169 sys.stdout.write(str)
170 sys.stdout.flush()
171
172 try:
173
174 term = GdbTerminal( "./main", tostdout, tostdout)
175 term.sendBreak("main.cpp", 13)
176 term.sendRun()
177 term.childin.write("1\n");
178 term.childin.write("2\n");
179 term.sendInspectVar("a+b")
180 term.sendContinue()
181
182
183 while not term.iseof():
184
185 cmd = sys.stdin.readline()
186
187 if term.iseof():
188 break
189
190 if cmd == "quit\n":
191 term.sendQuit()
192 else:
193 term.gdbin.write(cmd)
194
195 except Exception, e:
196 print e
197 except:
198 pass
199
200
201 print "stopping..."
202 term.stop()
203
204
205