import os
import sys
import vsi.tools.vdb as vdb
from functools import partial
import rpdb2
[docs]def dbstop_if_error(_rpdb2_pwd='vsi', fAllowUnencrypted=True,
fAllowRemote=False, timeout=0, source_provider=None,
fDebug=False, depth=0):
''' Run this to auto start the debugger on an exception.
Parameters
----------
_rpdb2_pwd : str
The Remote Python Debugger Password
fAllowUnencrypted : bool
True if unencrypted is allowed. False if not.
fAllowRemote : bool
True if a remote is allowed. False if not. Default: False
timeout : int
The timeout period in seconds.
source_provider : str
The Source Provider
fDebug : bool
The Debug Output
depth : int
The Depth of the frame. Default: 0
I THINK rpdb2 does not use the same traceback or the frame/stack objects
as pdb. So there is no way to just hand the debugger a traceback (yet).
So by starting the debugger, all exceptions will be cause, and just
attach to the debugger and type "analyze" to start debugging the last
exception.
Of course, this means that if the debugger slows down execution, it will
have to slow down all of the execution, instead of being loaded "just in
time"
'''
rpdb2.start_embedded_debugger(_rpdb2_pwd, fAllowUnencrypted, fAllowRemote,
timeout, source_provider, fDebug, depth)
#I'm not even going to attempt a DbStopIfError class, since this profiler does
#not have a Post Mortem equivalent... yet. Need to find a way to push the pm
#data into whatever the analyze command uses, so that it can be faked out
""" I can't get this working yet either. rpdb uses the profiler to catch
exceptions, NOT excepthook
#old_excepthook = rpdb2.__excepthook
#rpdb2.__excepthook = partial(rpdb_exception_hook, old_excepthook)
#sys.excepthook = rpdb_exception_hook
def rpdb_exception_hook(old_excepthook, type, value, tb, next_excepthook, index):
#def rpdb_exception_hook(type, value, tb):
traceback.print_exception(type, value, tb)
print('Starting rpdb2 for post_mortem... Remember to type analyze in the debugger')
#import sys
#sys.stdout.flush()
#print(sys.excepthook)
#rpdb2.start_embedded_debugger('vsi', timeout=0)
#rpdb2.m_current_ctx.m_core._break(rpdb2.m_current_ctx, tb.tb_frame, 'return', None)
old_excepthook(type, value, traceback, next_excepthook, index)
# I can't get this working yet...
sys.excepthook = partial(rpdb_dbstop_exception_hook, _rpdb2_pwd=_rpdb2_pwd, *args, **kwargs)
rpdb2.set_excepthook()
def rpdb_post_mortem(tb=None, _rpdb2_pwd='vsi', **kwargs):
#NO idea how to do this right right now...
#This isn't perfect... but should help
###rpdb_set_trace(*args, **kwargs)
#print('rpdb start')
#rpdb2.start_embedded_debugger(_rpdb2_pwd, timeout=5*60, **kwargs)
'''print('rpdb settrace')
rpdb2.settrace(f=tb.tb_frame)
ctx = rpdb2.g_debugger.get_ctx(rpdb2.thread.get_ident())
ctx.m_fUnhandledException = True
print('rpdb setbreak')
rpdb2.setbreak()
print('rpdb broke''')
def rpdb_dbstop_exception_hook(type, value, tb, _rpdb2_pwd='vsi', *args, **kwargs):
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
sys.__excepthook__(type, value, tb)
else:
import traceback
traceback.print_exception(type, value, tb)
rpdb_post_mortem(tb, _rpdb2_pwd, *args, **kwargs) # more "modern"
"""
[docs]def set_trace(_rpdb2_pwd='vsi', fAllowUnencrypted=True,
fAllowRemote=False, timeout=5*60, source_provider=None,
fDebug=False, depth=1):
''' Works, but without the other parts, it's far from auto
Parameters
----------
_rpdb2_pwd : str
The Remote Python Debugger Password
fAllowUnencrypted : bool
True if unencrypted is allowed. False if not.
fAllowRemote : bool
True if a remote is allowed. False if not. Default: False
timeout : int
The timeout period in seconds.
source_provider : str
The Source Provider
fDebug : bool
The Debug Output
depth : int
The Depth of the frame. Default: 0
'''
print('Starting rpdb2...')
rpdb2.start_embedded_debugger(_rpdb2_pwd, fAllowUnencrypted, fAllowRemote,
timeout, source_provider, fDebug, depth)
#else:#This does NOT work, as far as I know. It doesn't get the depth right, so....
# __start_embedded_debugger(_rpdb2_pwd, fAllowUnencrypted, fAllowRemote,
# timeout, source_provider, fDebug, depth, frame)
#rpdb2.g_debugger.settrace(frame, timeout=timeout)
#rpdb2.g_debugger.m_current_ctx._break(rpdb2.g_debugger.m_current_ctx, frame, 'return', None)
# sm = rpdb2.CSessionManager(_rpdb2_pwd, *args, **kwargs)
#
# sm.start()
# #set timeout 0
# frame = find_frame(frame, depth)
# rpdb2.g_debugger.settrace(frame)
[docs]def attach(pid, ip='127.0.0.1', password='vsi', gui=False, break_exit=False):
''' Parameters
----------
pid : int
The Process ID
ip : str
The IP Address
password : str
The Password
gui : bool
If true use winpbd GUI
break_exit : bool
If break_exit is true, it set's a breakpoint when the program extis.
'''
vdb.attach(pid)
import sys
old_args = sys.argv
#attach must come last for some STUPID reason. Dumb parser
sys.argv = ['', '--pwd=%s' % password, '--host=%s' % ip, '--attach', str(pid)]
if gui:
import winpdb
winpdb.main()
else:
rpdb2.main()
# Debuggee breaks (pauses) here
# before program termination.
#
# You can step to debug any exit handlers.
#
if break_exit:
rpdb2.setbreak()
sys.argv = old_args
[docs]def set_attach(_rpdb2_pwd='vsi', *args, **kwargs):
''' Parameters
----------
_rpdb2_pwd : str
The Remote Python Debugger Password
*args
Variable length argument list.
**kwargs
Arbitrary keyword arguments.
'''
vdb.set_attach(partial(set_trace, *args, **kwargs))
[docs]class CDebuggerCoreThread2(rpdb2.CDebuggerCoreThread):
''' I just wanted to add some output on exception!!!'''
[docs] def profile(self, frame, event, arg):
#print_debug('profile: %s, %s, %s, %s, %s' % (repr(frame), event, frame.f_code.co_name, frame.f_code.co_filename, repr(arg)[:40]))
if event == 'return':
self.m_depth -= 1
if sys.excepthook != rpdb2.g_excepthook:
rpdb2.set_excepthook()
self.m_frame = frame.f_back
try:
self.m_code_context = self.m_core.m_code_contexts[self.m_frame.f_code]
except AttributeError:
if self.m_event != 'return' and self.m_core.m_ftrap:
#
# An exception is raised from the outer-most frame.
# This means an unhandled exception.
#
self.m_frame = frame
self.m_event = 'exception'
self.m_uef_lineno = self.m_ue_lineno
self.m_fUnhandledException = True
print("Exception detected. Attach with rpdb2 pid {}\n"
"Don't forget to type 'analyze'".format(os.getpid()))
self.m_core._break(self, frame, event, arg)
self.m_uef_lineno = None
if frame in self.m_locals_copy:
self.update_locals()
self.m_frame = None
self.m_core.remove_thread(self.m_thread_id)
sys.setprofile(None)
sys.settrace(self.m_core.trace_dispatch_init)
if self.m_frame_external_references == 0:
return
try:
self.m_frame_lock.acquire()
while self.m_frame_external_references != 0:
rpdb2.safe_wait(self.m_frame_lock, 1.0)
finally:
self.m_frame_lock.release()
rpdb2.CDebuggerCoreThread = CDebuggerCoreThread2
#This is a crappy patch. Then again, rpdb2 could use a re-write. Then again,
#rpdb2 IS NOT A DEBUGGER! It's a profiler acting as a debugger.