@ -39,12 +39,15 @@ class StartEvent(object):
def __init__ ( self ) :
self . registered = list ( )
self . running = False
def connect ( self , function ) :
if function not in self . registered :
self . registered . append ( function )
def disconnect ( self , function ) :
if function in self . registered :
self . registered . remove ( function )
def on_new_objfile ( self ) :
if self . running or not gdb . selected_thread ( ) :
return
@ -62,8 +65,46 @@ class StartEvent(object):
def on_stop ( self ) :
self . on_new_objfile ( )
gdb . events . start = StartEvent ( )
class EventWrapper ( object ) :
"""
Wraper for GDB events which may not exist on older GDB versions but we still can
fire them manually ( to invoke them you have to call ` invoke_callbacks ` ) .
"""
def __init__ ( self , name ) :
self . name = name
self . _event = getattr ( gdb . events , self . name , None )
self . _is_real_event = self . _event is not None
def connect ( self , func ) :
if self . _event is not None :
self . _event . connect ( func )
def disconnect ( self , func ) :
if self . _event is not None :
self . _event . disconnect ( func )
@property
def is_real_event ( self ) :
return self . _is_real_event
def invoke_callbacks ( self ) :
"""
As an optimization please don ' t call this if your GDB has this event (check `.is_real_event`).
"""
for f in registered [ self ] :
f ( )
# Old GDBs doesn't have gdb.events.before_prompt, so we will emulate it using gdb.prompt_hook
before_prompt_event = EventWrapper ( ' before_prompt ' )
gdb . events . before_prompt = before_prompt_event
# In order to support reloading, we must be able to re-fire
# all 'objfile' and 'stop' events.
registered = {
@ -72,7 +113,7 @@ registered = {
gdb . events . new_objfile : [ ] ,
gdb . events . stop : [ ] ,
gdb . events . start : [ ] ,
gdb . events . before_prompt : [ ]
gdb . events . before_prompt : [ ] # The real event might not exist, but we wrap it
}
# GDB 7.9 and above only
@ -82,20 +123,24 @@ try:
except ( NameError , AttributeError ) :
pass
class Pause ( object ) :
def __enter__ ( self , * a , * * kw ) :
global pause
pause + = 1
def __exit__ ( self , * a , * * kw ) :
global pause
pause - = 1
# When performing remote debugging, gdbserver is very noisy about which
# objects are loaded. This greatly slows down the debugging session.
# In order to combat this, we keep track of which objfiles have been loaded
# this session, and only emit objfile events for each *new* file.
objfile_cache = set ( )
def connect ( func , event_handler , name = ' ' ) :
if debug :
print ( " Connecting " , func . __name__ , event_handler )
@ -130,25 +175,31 @@ def connect(func, event_handler, name=''):
event_handler . connect ( caller )
return func
def exit ( func ) : return connect ( func , gdb . events . exited , ' exit ' )
def cont ( func ) : return connect ( func , gdb . events . cont , ' cont ' )
def new_objfile ( func ) : return connect ( func , gdb . events . new_objfile , ' obj ' )
def stop ( func ) : return connect ( func , gdb . events . stop , ' stop ' )
def start ( func ) : return connect ( func , gdb . events . start , ' start ' )
before_prompt = partial ( connect , event_handler = gdb . events . before_prompt , name = ' before_prompt ' )
def reg_changed ( func ) :
try :
return connect ( func , gdb . events . register_changed , ' reg_changed ' )
except Exception :
except AttributeError :
return func
def mem_changed ( func ) :
try :
return connect ( func , gdb . events . memory_changed , ' mem_changed ' )
except Exception :
except AttributeError :
return func
def log_objfiles ( ofile = None ) :
if not ( debug and ofile ) :
return
@ -158,8 +209,10 @@ def log_objfiles(ofile=None):
print ( " objfile: %r " % name )
gdb . execute ( ' info sharedlibrary ' )
gdb . events . new_objfile . connect ( log_objfiles )
def after_reload ( start = True ) :
if gdb . selected_inferior ( ) . pid :
for f in registered [ gdb . events . stop ] :
@ -168,6 +221,9 @@ def after_reload(start=True):
if start : f ( )
for f in registered [ gdb . events . new_objfile ] :
f ( )
for f in registered [ gdb . events . before_prompt ] :
f ( )
def on_reload ( ) :
for event , functions in registered . items ( ) :
@ -175,18 +231,22 @@ def on_reload():
event . disconnect ( function )
registered [ event ] = [ ]
@new_objfile
def _start_newobjfile ( ) :
gdb . events . start . on_new_objfile ( )
@exit
def _start_exit ( ) :
gdb . events . start . on_exited ( )
@stop
def _start_stop ( ) :
gdb . events . start . on_stop ( )
@exit
def _reset_objfiles ( ) :
global objfile_cache