2
# vim:fileencoding=utf-8
3
from __future__ import (unicode_literals, division, absolute_import,
7
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
9
import pdb, socket, inspect, sys, select, os, atexit, time
11
from calibre import prints
12
from calibre.utils.ipc import eintr_retry_call
13
from calibre.constants import cache_dir
16
QUESTION = b'\x00\x01\x02'
18
class RemotePdb(pdb.Pdb):
20
def __init__(self, addr="127.0.0.1", port=4444, skip=None):
22
prints("pdb is running on %s:%d" % (addr, port), file=sys.stderr)
26
# Open a reusable socket to allow for reloads
27
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
28
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
29
self.sock.bind((addr, port))
31
clientsocket, address = self.sock.accept()
32
self.handle = clientsocket.makefile('rw')
33
pdb.Pdb.__init__(self, completekey='tab', stdin=self.handle, stdout=self.handle, skip=skip)
36
def prints(self, *args, **kwargs):
37
kwargs['file'] = self.handle
38
prints(*args, **kwargs)
40
def ask_question(self, query):
41
self.handle.write(QUESTION)
42
self.prints(query, end='')
43
self.handle.write(PROMPT)
45
return self.handle.readline()
47
def end_session(self, *args):
48
self.clear_all_breaks()
52
self.sock.shutdown(socket.SHUT_RDWR)
56
return pdb.Pdb.do_continue(self, None)
58
def do_clear(self, arg):
60
ans = self.ask_question("Clear all breaks? [y/n]: ")
61
if ans.strip().lower() in {b'y', b'yes'}:
62
self.clear_all_breaks()
63
self.prints('All breaks cleared')
65
return pdb.Pdb.do_clear(self, arg)
68
def do_continue(self, arg):
70
ans = self.ask_question(
71
'There are no breakpoints set. Continuing will terminate this debug session. Are you sure? [y/n]: ')
72
if ans.strip().lower() in {b'y', b'yes'}:
73
return self.end_session()
75
return pdb.Pdb.do_continue(self, arg)
76
do_c = do_cont = do_continue
78
do_EOF = do_quit = do_exit = do_q = end_session
80
def set_trace(port=4444, skip=None):
81
frame = inspect.currentframe().f_back
84
debugger = RemotePdb(port=port, skip=skip)
85
debugger.set_trace(frame)
86
except KeyboardInterrupt:
87
prints('Debugging aborted by keyboard interrupt')
89
prints('Failed to run debugger')
94
prints('Connecting to remote debugger on port %d...' % port)
95
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
98
sock.connect(('127.0.0.1', port))
105
sock.connect(('127.0.0.1', port))
106
except socket.error as err:
107
prints('Failed to connect to remote debugger:', err, file=sys.stderr)
109
prints('Connected to remote process')
111
histfile = os.path.join(cache_dir(), 'rpdb.history')
113
readline.read_history_file(histfile)
116
atexit.register(readline.write_history_file, histfile)
118
readline.set_completer(p.complete)
119
readline.parse_and_bind("tab: complete")
124
while not recvd.endswith(PROMPT) or select.select([sock], [], [], 0) == ([sock], [], []):
125
buf = eintr_retry_call(sock.recv, 16 * 1024)
129
recvd = recvd[:-len(PROMPT)]
130
if recvd.startswith(QUESTION):
131
recvd = recvd[len(QUESTION):]
132
sys.stdout.write(recvd)
133
raw = sys.stdin.readline() or b'n'
135
sys.stdout.write(recvd)
138
raw = raw_input(PROMPT) + b'\n'
139
except (EOFError, KeyboardInterrupt):
143
eintr_retry_call(sock.send, raw)
144
except KeyboardInterrupt:
147
if __name__ == '__main__':