import os
import sys
from functools import partial
import traceback
import socket
import rpdb
import vsi.tools.vdb as vdb
DEFAULT_IP = '127.0.0.1'
DEFAULT_PORT = 4444
[docs]class RpdbPostMortemHook(vdb.PostMortemHook):
[docs] @staticmethod
def set_post_mortem(interactive=False, ip=DEFAULT_IP, port=DEFAULT_PORT):
sys.excepthook = partial(vdb.dbstop_exception_hook,
interactive=interactive,
post_mortem=partial(post_mortem,
ip=ip, port=port))
[docs]def dbclear_if_error():
RpdbPostMortemHook.dbclear_if_error()
[docs]def dbstop_if_error(interactive=False, ip=DEFAULT_IP, port=DEFAULT_PORT):
''' Run this to auto start the debugger on an exception.
Optional arguments
Parameters
----------
interactive : bool
see vsi.tools.vdb.dbstop_if_error
ip : str
Default 127.0.0.1 - Ip to bind to for remote debugger
port : int
Default 4444 - Port to bind to for remote debugger
'''
RpdbPostMortemHook.dbstop_if_error(interactive=interactive,
ip=ip, port=port)
[docs]def post_mortem(tb=None, ip=DEFAULT_IP, port=DEFAULT_PORT):
''' Parameters
---------
tb : str
The Traceback
ip : str
The IP Address
port : int
The Port
Raises
------
ValueError
Passes a valied traceback
'''
if tb is None:
# sys.exc_info() returns (type, value, traceback) if an exception is
# being handled, otherwise it returns None
tb = sys.exc_info()[2]
if tb is None:
raise ValueError("A valid traceback must be passed if no "
"exception is being handled")
r = rpdb.Rpdb(addr=ip, port=port)
r.reset()
r.interaction(None, tb)
[docs]class DbStopIfError(vdb.DbStopIfErrorGeneric):
[docs] def get_post_mortem(self):
return post_mortem
[docs] def get_post_mortem_class(self):
return RpdbPostMortemHook
[docs]def set_trace(frame=None, depth=None, ip=DEFAULT_IP, port=DEFAULT_PORT):
''' Wrapper function to keep the same import x; x.set_trace() interface.
We catch all the possible exceptions from pdb and cleanup.
Parameters
----------
frame : str
The Frame
depth : int
The Depth
ip : str
The IP Address
port : int
The Port
'''
frame = vdb.find_frame(frame, depth if depth is not None else 2 if frame is None else 0)
try:
debugger = rpdb.Rpdb(addr=ip, port=port)
except socket.error:
if rpdb.OCCUPIED.is_claimed(port, sys.stdout):
# rpdb is already on this port - good enough, let it go on:
sys.stdout.write("(Recurrent rpdb invocation ignored)\n")
return
else:
# Port occupied by something else.
raise
try:
debugger.set_trace(frame)
except Exception:
import traceback
traceback.print_exc()
[docs]def attach(pid, ip=DEFAULT_IP, port=DEFAULT_PORT):
''' NOT IMPLEMENTED! Needs a telnet client
Parameters
----------
pid : str
The Process ID
ip : str
The IP Address
port : str
The Port
'''
vdb.attach(pid)
assert(False)
[docs]def set_attach(ip=DEFAULT_IP, port=DEFAULT_PORT):
''' Parameters
----------
ip : str
The IP Address
port : str
The Port
'''
vdb.set_attach(db_cmd=partial(set_trace, ip=ip, port=port))