183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""Support for remote Python debugging.
283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehSome ASCII art to describe the structure:
483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh       IN PYTHON SUBPROCESS          #             IN IDLE PROCESS
683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                     #
783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                     #        oid='gui_adapter'
883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                 +----------+        #       +------------+          +-----+
983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                 | GUIProxy |--remote#call-->| GUIAdapter |--calls-->| GUI |
1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh+-----+--calls-->+----------+        #       +------------+          +-----+
1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh| Idb |                               #                             /
1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh+-----+<-calls--+------------+         #      +----------+<--calls-/
1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                | IdbAdapter |<--remote#call--| IdbProxy |
1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                +------------+         #      +----------+
1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                oid='idb_adapter'      #
1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehThe purpose of the Proxy and Adapter classes is to translate certain
1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieharguments and return values that cannot be transported through the RPC
1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehbarrier, in particular frame and traceback objects.
2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""
2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport types
2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom idlelib import rpc
2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom idlelib import Debugger
2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdebugging = 0
2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehidb_adap_oid = "idb_adapter"
3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehgui_adap_oid = "gui_adapter"
3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#=======================================
3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# In the PYTHON subprocess:
3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehframetable = {}
3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdicttable = {}
3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehcodetable = {}
3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehtracebacktable = {}
4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef wrap_frame(frame):
4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    fid = id(frame)
4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    frametable[fid] = frame
4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    return fid
4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef wrap_info(info):
4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    "replace info[2], a traceback instance, by its ID"
4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    if info is None:
4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return None
5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    else:
5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        traceback = info[2]
5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        assert isinstance(traceback, types.TracebackType)
5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        traceback_id = id(traceback)
5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        tracebacktable[traceback_id] = traceback
5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        modified_info = (info[0], info[1], traceback_id)
5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return modified_info
5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass GUIProxy:
5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __init__(self, conn, gui_adap_oid):
6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.conn = conn
6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.oid = gui_adap_oid
6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def interaction(self, message, frame, info=None):
6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # calls rpc.SocketIO.remotecall() via run.MyHandler instance
6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # pass frame and traceback object IDs instead of the objects themselves
6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.conn.remotecall(self.oid, "interaction",
6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                             (message, wrap_frame(frame), wrap_info(info)),
6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                             {})
7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass IdbAdapter:
7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __init__(self, idb):
7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.idb = idb
7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    #----------called by an IdbProxy----------
7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_step(self):
7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.idb.set_step()
8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_quit(self):
8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.idb.set_quit()
8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_continue(self):
8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.idb.set_continue()
8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_next(self, fid):
8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        frame = frametable[fid]
8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.idb.set_next(frame)
9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_return(self, fid):
9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        frame = frametable[fid]
9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.idb.set_return(frame)
9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def get_stack(self, fid, tbid):
9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ##print >>sys.__stderr__, "get_stack(%r, %r)" % (fid, tbid)
9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        frame = frametable[fid]
9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if tbid is None:
9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            tb = None
10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            tb = tracebacktable[tbid]
10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        stack, i = self.idb.get_stack(frame, tb)
10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ##print >>sys.__stderr__, "get_stack() ->", stack
10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        stack = [(wrap_frame(frame), k) for frame, k in stack]
10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ##print >>sys.__stderr__, "get_stack() ->", stack
10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return stack, i
10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def run(self, cmd):
10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        import __main__
11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.idb.run(cmd, __main__.__dict__)
11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_break(self, filename, lineno):
11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        msg = self.idb.set_break(filename, lineno)
11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return msg
11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def clear_break(self, filename, lineno):
11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        msg = self.idb.clear_break(filename, lineno)
11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return msg
11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def clear_all_file_breaks(self, filename):
12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        msg = self.idb.clear_all_file_breaks(filename)
12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return msg
12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    #----------called by a FrameProxy----------
12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def frame_attr(self, fid, name):
12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        frame = frametable[fid]
12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return getattr(frame, name)
12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def frame_globals(self, fid):
13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        frame = frametable[fid]
13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        dict = frame.f_globals
13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        did = id(dict)
13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        dicttable[did] = dict
13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return did
13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def frame_locals(self, fid):
13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        frame = frametable[fid]
13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        dict = frame.f_locals
14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        did = id(dict)
14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        dicttable[did] = dict
14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return did
14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
14483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def frame_code(self, fid):
14583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        frame = frametable[fid]
14683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        code = frame.f_code
14783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        cid = id(code)
14883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        codetable[cid] = code
14983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return cid
15083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
15183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    #----------called by a CodeProxy----------
15283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
15383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def code_name(self, cid):
15483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        code = codetable[cid]
15583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return code.co_name
15683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
15783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def code_filename(self, cid):
15883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        code = codetable[cid]
15983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return code.co_filename
16083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
16183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    #----------called by a DictProxy----------
16283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
16383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def dict_keys(self, did):
16483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        dict = dicttable[did]
16583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return dict.keys()
16683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
16783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def dict_item(self, did, key):
16883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        dict = dicttable[did]
16983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        value = dict[key]
17083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        value = repr(value)
17183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return value
17283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
17383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#----------end class IdbAdapter----------
17483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
17583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
17683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef start_debugger(rpchandler, gui_adap_oid):
17783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """Start the debugger and its RPC link in the Python subprocess
17883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
17983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    Start the subprocess side of the split debugger and set up that side of the
18083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    RPC link by instantiating the GUIProxy, Idb debugger, and IdbAdapter
18183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    objects and linking them together.  Register the IdbAdapter with the
18283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    RPCServer to handle RPC requests from the split debugger GUI via the
18383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    IdbProxy.
18483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
18583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """
18683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    gui_proxy = GUIProxy(rpchandler, gui_adap_oid)
18783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    idb = Debugger.Idb(gui_proxy)
18883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    idb_adap = IdbAdapter(idb)
18983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    rpchandler.register(idb_adap_oid, idb_adap)
19083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    return idb_adap_oid
19183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
19283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
19383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#=======================================
19483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
19583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# In the IDLE process:
19683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
19783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
19883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass FrameProxy:
19983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
20083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __init__(self, conn, fid):
20183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._conn = conn
20283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._fid = fid
20383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._oid = "idb_adapter"
20483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._dictcache = {}
20583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
20683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __getattr__(self, name):
20783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if name[:1] == "_":
20883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            raise AttributeError, name
20983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if name == "f_code":
21083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return self._get_f_code()
21183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if name == "f_globals":
21283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return self._get_f_globals()
21383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if name == "f_locals":
21483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return self._get_f_locals()
21583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return self._conn.remotecall(self._oid, "frame_attr",
21683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                     (self._fid, name), {})
21783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
21883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def _get_f_code(self):
21983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        cid = self._conn.remotecall(self._oid, "frame_code", (self._fid,), {})
22083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return CodeProxy(self._conn, self._oid, cid)
22183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
22283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def _get_f_globals(self):
22383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        did = self._conn.remotecall(self._oid, "frame_globals",
22483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                    (self._fid,), {})
22583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return self._get_dict_proxy(did)
22683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
22783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def _get_f_locals(self):
22883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        did = self._conn.remotecall(self._oid, "frame_locals",
22983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                    (self._fid,), {})
23083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return self._get_dict_proxy(did)
23183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
23283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def _get_dict_proxy(self, did):
23383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if did in self._dictcache:
23483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return self._dictcache[did]
23583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        dp = DictProxy(self._conn, self._oid, did)
23683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._dictcache[did] = dp
23783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return dp
23883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
23983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
24083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass CodeProxy:
24183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
24283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __init__(self, conn, oid, cid):
24383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._conn = conn
24483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._oid = oid
24583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._cid = cid
24683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
24783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __getattr__(self, name):
24883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if name == "co_name":
24983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return self._conn.remotecall(self._oid, "code_name",
25083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                         (self._cid,), {})
25183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if name == "co_filename":
25283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return self._conn.remotecall(self._oid, "code_filename",
25383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                         (self._cid,), {})
25483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
25583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
25683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass DictProxy:
25783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
25883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __init__(self, conn, oid, did):
25983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._conn = conn
26083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._oid = oid
26183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self._did = did
26283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
26383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def keys(self):
26483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return self._conn.remotecall(self._oid, "dict_keys", (self._did,), {})
26583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
26683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __getitem__(self, key):
26783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return self._conn.remotecall(self._oid, "dict_item",
26883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                     (self._did, key), {})
26983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
27083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __getattr__(self, name):
27183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ##print >>sys.__stderr__, "failed DictProxy.__getattr__:", name
27283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        raise AttributeError, name
27383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
27483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
27583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass GUIAdapter:
27683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
27783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __init__(self, conn, gui):
27883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.conn = conn
27983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.gui = gui
28083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
28183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def interaction(self, message, fid, modified_info):
28283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ##print "interaction: (%s, %s, %s)" % (message, fid, modified_info)
28383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        frame = FrameProxy(self.conn, fid)
28483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.gui.interaction(message, frame, modified_info)
28583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
28683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
28783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass IdbProxy:
28883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
28983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __init__(self, conn, shell, oid):
29083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.oid = oid
29183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.conn = conn
29283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.shell = shell
29383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
29483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def call(self, methodname, *args, **kwargs):
29583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ##print "**IdbProxy.call %s %s %s" % (methodname, args, kwargs)
29683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        value = self.conn.remotecall(self.oid, methodname, args, kwargs)
29783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        ##print "**IdbProxy.call %s returns %r" % (methodname, value)
29883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return value
29983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
30083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def run(self, cmd, locals):
30183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Ignores locals on purpose!
30283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        seq = self.conn.asyncqueue(self.oid, "run", (cmd,), {})
30383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.shell.interp.active_seq = seq
30483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
30583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def get_stack(self, frame, tbid):
30683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # passing frame and traceback IDs, not the objects themselves
30783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        stack, i = self.call("get_stack", frame._fid, tbid)
30883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        stack = [(FrameProxy(self.conn, fid), k) for fid, k in stack]
30983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return stack, i
31083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
31183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_continue(self):
31283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.call("set_continue")
31383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
31483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_step(self):
31583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.call("set_step")
31683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
31783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_next(self, frame):
31883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.call("set_next", frame._fid)
31983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
32083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_return(self, frame):
32183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.call("set_return", frame._fid)
32283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
32383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_quit(self):
32483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.call("set_quit")
32583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
32683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_break(self, filename, lineno):
32783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        msg = self.call("set_break", filename, lineno)
32883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return msg
32983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
33083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def clear_break(self, filename, lineno):
33183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        msg = self.call("clear_break", filename, lineno)
33283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return msg
33383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
33483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def clear_all_file_breaks(self, filename):
33583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        msg = self.call("clear_all_file_breaks", filename)
33683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return msg
33783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
33883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef start_remote_debugger(rpcclt, pyshell):
33983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """Start the subprocess debugger, initialize the debugger GUI and RPC link
34083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
34183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    Request the RPCServer start the Python subprocess debugger and link.  Set
34283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    up the Idle side of the split debugger by instantiating the IdbProxy,
34383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    debugger GUI, and debugger GUIAdapter objects and linking them together.
34483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
34583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    Register the GUIAdapter with the RPCClient to handle debugger GUI
34683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    interaction requests coming from the subprocess debugger via the GUIProxy.
34783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
34883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    The IdbAdapter will pass execution and environment requests coming from the
34983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    Idle debugger GUI to the subprocess debugger via the IdbProxy.
35083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
35183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """
35283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    global idb_adap_oid
35383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
35483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\
35583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                   (gui_adap_oid,), {})
35683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    idb_proxy = IdbProxy(rpcclt, pyshell, idb_adap_oid)
35783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    gui = Debugger.Debugger(pyshell, idb_proxy)
35883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    gui_adap = GUIAdapter(rpcclt, gui)
35983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    rpcclt.register(gui_adap_oid, gui_adap)
36083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    return gui
36183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
36283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef close_remote_debugger(rpcclt):
36383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """Shut down subprocess debugger and Idle side of debugger RPC link
36483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
36583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    Request that the RPCServer shut down the subprocess debugger and link.
36683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    Unregister the GUIAdapter, which will cause a GC on the Idle process
36783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    debugger and RPC link objects.  (The second reference to the debugger GUI
36883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    is deleted in PyShell.close_remote_debugger().)
36983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
37083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """
37183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    close_subprocess_debugger(rpcclt)
37283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    rpcclt.unregister(gui_adap_oid)
37383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
37483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef close_subprocess_debugger(rpcclt):
37583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    rpcclt.remotecall("exec", "stop_the_debugger", (idb_adap_oid,), {})
37683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
37783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef restart_subprocess_debugger(rpcclt):
37883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    idb_adap_oid_ret = rpcclt.remotecall("exec", "start_the_debugger",\
37983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                         (gui_adap_oid,), {})
38083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    assert idb_adap_oid_ret == idb_adap_oid, 'Idb restarted with different oid'
381