Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / amd64 / lib / python2.4 / idlelib / RemoteDebugger.py
CommitLineData
920dae64
AT
1"""Support for remote Python debugging.
2
3Some ASCII art to describe the structure:
4
5 IN PYTHON SUBPROCESS # IN IDLE PROCESS
6 #
7 # oid='gui_adapter'
8 +----------+ # +------------+ +-----+
9 | GUIProxy |--remote#call-->| GUIAdapter |--calls-->| GUI |
10+-----+--calls-->+----------+ # +------------+ +-----+
11| Idb | # /
12+-----+<-calls--+------------+ # +----------+<--calls-/
13 | IdbAdapter |<--remote#call--| IdbProxy |
14 +------------+ # +----------+
15 oid='idb_adapter' #
16
17The purpose of the Proxy and Adapter classes is to translate certain
18arguments and return values that cannot be transported through the RPC
19barrier, in particular frame and traceback objects.
20
21"""
22
23import sys
24import types
25import rpc
26import Debugger
27
28debugging = 0
29
30idb_adap_oid = "idb_adapter"
31gui_adap_oid = "gui_adapter"
32
33#=======================================
34#
35# In the PYTHON subprocess:
36
37frametable = {}
38dicttable = {}
39codetable = {}
40tracebacktable = {}
41
42def wrap_frame(frame):
43 fid = id(frame)
44 frametable[fid] = frame
45 return fid
46
47def wrap_info(info):
48 "replace info[2], a traceback instance, by its ID"
49 if info is None:
50 return None
51 else:
52 traceback = info[2]
53 assert isinstance(traceback, types.TracebackType)
54 traceback_id = id(traceback)
55 tracebacktable[traceback_id] = traceback
56 modified_info = (info[0], info[1], traceback_id)
57 return modified_info
58
59class GUIProxy:
60
61 def __init__(self, conn, gui_adap_oid):
62 self.conn = conn
63 self.oid = gui_adap_oid
64
65 def interaction(self, message, frame, info=None):
66 # calls rpc.SocketIO.remotecall() via run.MyHandler instance
67 # pass frame and traceback object IDs instead of the objects themselves
68 self.conn.remotecall(self.oid, "interaction",
69 (message, wrap_frame(frame), wrap_info(info)),
70 {})
71
72class IdbAdapter:
73
74 def __init__(self, idb):
75 self.idb = idb
76
77 #----------called by an IdbProxy----------
78
79 def set_step(self):
80 self.idb.set_step()
81
82 def set_quit(self):
83 self.idb.set_quit()
84
85 def set_continue(self):
86 self.idb.set_continue()
87
88 def set_next(self, fid):
89 frame = frametable[fid]
90 self.idb.set_next(frame)
91
92 def set_return(self, fid):
93 frame = frametable[fid]
94 self.idb.set_return(frame)
95
96 def get_stack(self, fid, tbid):
97 ##print >>sys.__stderr__, "get_stack(%r, %r)" % (fid, tbid)
98 frame = frametable[fid]
99 if tbid is None:
100 tb = None
101 else:
102 tb = tracebacktable[tbid]
103 stack, i = self.idb.get_stack(frame, tb)
104 ##print >>sys.__stderr__, "get_stack() ->", stack
105 stack = [(wrap_frame(frame), k) for frame, k in stack]
106 ##print >>sys.__stderr__, "get_stack() ->", stack
107 return stack, i
108
109 def run(self, cmd):
110 import __main__
111 self.idb.run(cmd, __main__.__dict__)
112
113 def set_break(self, filename, lineno):
114 msg = self.idb.set_break(filename, lineno)
115 return msg
116
117 def clear_break(self, filename, lineno):
118 msg = self.idb.clear_break(filename, lineno)
119 return msg
120
121 def clear_all_file_breaks(self, filename):
122 msg = self.idb.clear_all_file_breaks(filename)
123 return msg
124
125 #----------called by a FrameProxy----------
126
127 def frame_attr(self, fid, name):
128 frame = frametable[fid]
129 return getattr(frame, name)
130
131 def frame_globals(self, fid):
132 frame = frametable[fid]
133 dict = frame.f_globals
134 did = id(dict)
135 dicttable[did] = dict
136 return did
137
138 def frame_locals(self, fid):
139 frame = frametable[fid]
140 dict = frame.f_locals
141 did = id(dict)
142 dicttable[did] = dict
143 return did
144
145 def frame_code(self, fid):
146 frame = frametable[fid]
147 code = frame.f_code
148 cid = id(code)
149 codetable[cid] = code
150 return cid
151
152 #----------called by a CodeProxy----------
153
154 def code_name(self, cid):
155 code = codetable[cid]
156 return code.co_name
157
158 def code_filename(self, cid):
159 code = codetable[cid]
160 return code.co_filename
161
162 #----------called by a DictProxy----------
163
164 def dict_keys(self, did):
165 dict = dicttable[did]
166 return dict.keys()
167
168 def dict_item(self, did, key):
169 dict = dicttable[did]
170 value = dict[key]
171 value = repr(value)
172 return value
173
174#----------end class IdbAdapter----------
175
176
177def start_debugger(rpchandler, gui_adap_oid):
178 """Start the debugger and its RPC link in the Python subprocess
179
180 Start the subprocess side of the split debugger and set up that side of the
181 RPC link by instantiating the GUIProxy, Idb debugger, and IdbAdapter
182 objects and linking them together. Register the IdbAdapter with the
183 RPCServer to handle RPC requests from the split debugger GUI via the
184 IdbProxy.
185
186 """
187 gui_proxy = GUIProxy(rpchandler, gui_adap_oid)
188 idb = Debugger.Idb(gui_proxy)
189 idb_adap = IdbAdapter(idb)
190 rpchandler.register(idb_adap_oid, idb_adap)
191 return idb_adap_oid
192
193
194#=======================================
195#
196# In the IDLE process:
197
198
199class FrameProxy:
200
201 def __init__(self, conn, fid):
202 self._conn = conn
203 self._fid = fid
204 self._oid = "idb_adapter"
205 self._dictcache = {}
206
207 def __getattr__(self, name):
208 if name[:1] == "_":
209 raise AttributeError, name
210 if name == "f_code":
211 return self._get_f_code()
212 if name == "f_globals":
213 return self._get_f_globals()
214 if name == "f_locals":
215 return self._get_f_locals()
216 return self._conn.remotecall(self._oid, "frame_attr",
217 (self._fid, name), {})
218
219 def _get_f_code(self):
220 cid = self._conn.remotecall(self._oid, "frame_code", (self._fid,), {})
221 return CodeProxy(self._conn, self._oid, cid)
222
223 def _get_f_globals(self):
224 did = self._conn.remotecall(self._oid, "frame_globals",
225 (self._fid,), {})
226 return self._get_dict_proxy(did)
227
228 def _get_f_locals(self):
229 did = self._conn.remotecall(self._oid, "frame_locals",
230 (self._fid,), {})
231 return self._get_dict_proxy(did)
232
233 def _get_dict_proxy(self, did):
234 if self._dictcache.has_key(did):
235 return self._dictcache[did]
236 dp = DictProxy(self._conn, self._oid, did)
237 self._dictcache[did] = dp
238 return dp
239
240
241class CodeProxy:
242
243 def __init__(self, conn, oid, cid):
244 self._conn = conn
245 self._oid = oid
246 self._cid = cid
247
248 def __getattr__(self, name):
249 if name == "co_name":
250 return self._conn.remotecall(self._oid, "code_name",
251 (self._cid,), {})
252 if name == "co_filename":
253 return self._conn.remotecall(self._oid, "code_filename",
254 (self._cid,), {})
255
256
257class DictProxy:
258
259 def __init__(self, conn, oid, did):
260 self._conn = conn
261 self._oid = oid
262 self._did = did
263
264 def keys(self):
265 return self._conn.remotecall(self._oid, "dict_keys", (self._did,), {})
266
267 def __getitem__(self, key):
268 return self._conn.remotecall(self._oid, "dict_item",
269 (self._did, key), {})
270
271 def __getattr__(self, name):
272 ##print >>sys.__stderr__, "failed DictProxy.__getattr__:", name
273 raise AttributeError, name
274
275
276class GUIAdapter:
277
278 def __init__(self, conn, gui):
279 self.conn = conn
280 self.gui = gui
281
282 def interaction(self, message, fid, modified_info):
283 ##print "interaction: (%s, %s, %s)" % (message, fid, modified_info)
284 frame = FrameProxy(self.conn, fid)
285 self.gui.interaction(message, frame, modified_info)
286
287
288class IdbProxy:
289
290 def __init__(self, conn, shell, oid):
291 self.oid = oid
292 self.conn = conn
293 self.shell = shell
294
295 def call(self, methodname, *args, **kwargs):
296 ##print "**IdbProxy.call %s %s %s" % (methodname, args, kwargs)
297 value = self.conn.remotecall(self.oid, methodname, args, kwargs)
298 ##print "**IdbProxy.call %s returns %r" % (methodname, value)
299 return value
300
301 def run(self, cmd, locals):
302 # Ignores locals on purpose!
303 seq = self.conn.asyncqueue(self.oid, "run", (cmd,), {})
304 self.shell.interp.active_seq = seq
305
306 def get_stack(self, frame, tbid):
307 # passing frame and traceback IDs, not the objects themselves
308 stack, i = self.call("get_stack", frame._fid, tbid)
309 stack = [(FrameProxy(self.conn, fid), k) for fid, k in stack]
310 return stack, i
311
312 def set_continue(self):
313 self.call("set_continue")
314
315 def set_step(self):
316 self.call("set_step")
317
318 def set_next(self, frame):
319 self.call("set_next", frame._fid)
320
321 def set_return(self, frame):
322 self.call("set_return", frame._fid)
323
324 def set_quit(self):
325 self.call("set_quit")
326
327 def set_break(self, filename, lineno):
328 msg = self.call("set_break", filename, lineno)
329 return msg
330
331 def clear_break(self, filename, lineno):
332 msg = self.call("clear_break", filename, lineno)
333 return msg
334
335 def clear_all_file_breaks(self, filename):
336 msg = self.call("clear_all_file_breaks", filename)
337 return msg
338
339def start_remote_debugger(rpcclt, pyshell):
340 """Start the subprocess debugger, initialize the debugger GUI and RPC link
341
342 Request the RPCServer start the Python subprocess debugger and link. Set
343 up the Idle side of the split debugger by instantiating the IdbProxy,
344 debugger GUI, and debugger GUIAdapter objects and linking them together.
345
346 Register the GUIAdapter with the RPCClient to handle debugger GUI
347 interaction requests coming from the subprocess debugger via the GUIProxy.
348
349 The IdbAdapter will pass execution and environment requests coming from the
350 Idle debugger GUI to the subprocess debugger via the IdbProxy.
351
352 """
353 global idb_adap_oid
354
355 idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\
356 (gui_adap_oid,), {})
357 idb_proxy = IdbProxy(rpcclt, pyshell, idb_adap_oid)
358 gui = Debugger.Debugger(pyshell, idb_proxy)
359 gui_adap = GUIAdapter(rpcclt, gui)
360 rpcclt.register(gui_adap_oid, gui_adap)
361 return gui
362
363def close_remote_debugger(rpcclt):
364 """Shut down subprocess debugger and Idle side of debugger RPC link
365
366 Request that the RPCServer shut down the subprocess debugger and link.
367 Unregister the GUIAdapter, which will cause a GC on the Idle process
368 debugger and RPC link objects. (The second reference to the debugger GUI
369 is deleted in PyShell.close_remote_debugger().)
370
371 """
372 close_subprocess_debugger(rpcclt)
373 rpcclt.unregister(gui_adap_oid)
374
375def close_subprocess_debugger(rpcclt):
376 rpcclt.remotecall("exec", "stop_the_debugger", (idb_adap_oid,), {})
377
378def restart_subprocess_debugger(rpcclt):
379 idb_adap_oid_ret = rpcclt.remotecall("exec", "start_the_debugger",\
380 (gui_adap_oid,), {})
381 assert idb_adap_oid_ret == idb_adap_oid, 'Idb restarted with different oid'