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