|
|
|
@ -9,15 +9,49 @@ import traceback
|
|
|
|
import gdb
|
|
|
|
import gdb
|
|
|
|
import sys
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
debug = True
|
|
|
|
debug = False
|
|
|
|
pause = 0
|
|
|
|
pause = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# There is no GDB way to get a notification when the binary itself
|
|
|
|
|
|
|
|
# is loaded from disk, by the operating system, before absolutely
|
|
|
|
|
|
|
|
# anything happens
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# However, we get an Objfile event when the binary is loaded, before
|
|
|
|
|
|
|
|
# its entry point is invoked.
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# We also get an Objfile event when we load up GDB, so we need
|
|
|
|
|
|
|
|
# to detect when the binary is running or not.
|
|
|
|
|
|
|
|
class StartEvent(object):
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
|
|
self.registered = set()
|
|
|
|
|
|
|
|
self.running = False
|
|
|
|
|
|
|
|
def connect(self, function):
|
|
|
|
|
|
|
|
self.registered.add(function)
|
|
|
|
|
|
|
|
def disconnect(self, function):
|
|
|
|
|
|
|
|
if function in self.registered:
|
|
|
|
|
|
|
|
self.registered.remove(function)
|
|
|
|
|
|
|
|
def on_new_objfile(self, o):
|
|
|
|
|
|
|
|
if self.running or not gdb.selected_thread():
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.running = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for function in self.registered:
|
|
|
|
|
|
|
|
function(o)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_stop(self, e):
|
|
|
|
|
|
|
|
self.running = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gdb.events.start = StartEvent()
|
|
|
|
|
|
|
|
|
|
|
|
# In order to support reloading, we must be able to re-fire
|
|
|
|
# In order to support reloading, we must be able to re-fire
|
|
|
|
# all 'objfile' and 'stop' events.
|
|
|
|
# all 'objfile' and 'stop' events.
|
|
|
|
registered = {gdb.events.exited: [],
|
|
|
|
registered = {gdb.events.exited: [],
|
|
|
|
gdb.events.cont: [],
|
|
|
|
gdb.events.cont: [],
|
|
|
|
gdb.events.new_objfile: [],
|
|
|
|
gdb.events.new_objfile: [],
|
|
|
|
gdb.events.stop: []}
|
|
|
|
gdb.events.stop: [],
|
|
|
|
|
|
|
|
gdb.events.start: []}
|
|
|
|
|
|
|
|
|
|
|
|
class Pause(object):
|
|
|
|
class Pause(object):
|
|
|
|
def __enter__(self, *a, **kw):
|
|
|
|
def __enter__(self, *a, **kw):
|
|
|
|
@ -28,6 +62,9 @@ class Pause(object):
|
|
|
|
pause -= 1
|
|
|
|
pause -= 1
|
|
|
|
|
|
|
|
|
|
|
|
def connect(func, event_handler, name=''):
|
|
|
|
def connect(func, event_handler, name=''):
|
|
|
|
|
|
|
|
if debug:
|
|
|
|
|
|
|
|
print("Connecting", func.__name__, event_handler)
|
|
|
|
|
|
|
|
|
|
|
|
def caller(*a):
|
|
|
|
def caller(*a):
|
|
|
|
func.__doc__
|
|
|
|
func.__doc__
|
|
|
|
if debug: sys.stdout.write('%r %s.%s %r\n' % (name, func.__module__, func.__name__, a))
|
|
|
|
if debug: sys.stdout.write('%r %s.%s %r\n' % (name, func.__module__, func.__name__, a))
|
|
|
|
@ -37,9 +74,10 @@ def connect(func, event_handler, name=''):
|
|
|
|
except Exception as e:
|
|
|
|
except Exception as e:
|
|
|
|
if debug: print(traceback.format_exc())
|
|
|
|
if debug: print(traceback.format_exc())
|
|
|
|
raise e
|
|
|
|
raise e
|
|
|
|
if debug: sys.stdout.write('DONE %r %s.%s %r\n' % (name, func.__module__, func.__name__, a))
|
|
|
|
|
|
|
|
registered[event_handler].append(caller)
|
|
|
|
registered[event_handler].append(caller)
|
|
|
|
caller.name = func.__name__
|
|
|
|
caller.name = func.__name__
|
|
|
|
|
|
|
|
caller.__name__ = func.__name__
|
|
|
|
event_handler.connect(caller)
|
|
|
|
event_handler.connect(caller)
|
|
|
|
return func
|
|
|
|
return func
|
|
|
|
|
|
|
|
|
|
|
|
@ -47,6 +85,7 @@ def exit(func): return connect(func, gdb.events.exited, 'exit')
|
|
|
|
def cont(func): return connect(func, gdb.events.cont, 'cont')
|
|
|
|
def cont(func): return connect(func, gdb.events.cont, 'cont')
|
|
|
|
def new_objfile(func): return connect(func, gdb.events.new_objfile, 'obj')
|
|
|
|
def new_objfile(func): return connect(func, gdb.events.new_objfile, 'obj')
|
|
|
|
def stop(func): return connect(func, gdb.events.stop, 'stop')
|
|
|
|
def stop(func): return connect(func, gdb.events.stop, 'stop')
|
|
|
|
|
|
|
|
def start(func): return connect(func, gdb.events.start, 'start')
|
|
|
|
|
|
|
|
|
|
|
|
def after_reload():
|
|
|
|
def after_reload():
|
|
|
|
return
|
|
|
|
return
|
|
|
|
@ -56,9 +95,16 @@ def after_reload():
|
|
|
|
# for f in registered[gdb.events.stop]:
|
|
|
|
# for f in registered[gdb.events.stop]:
|
|
|
|
# f()
|
|
|
|
# f()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_reload():
|
|
|
|
def on_reload():
|
|
|
|
for event, functions in registered.items():
|
|
|
|
for event, functions in registered.items():
|
|
|
|
for function in functions:
|
|
|
|
for function in functions:
|
|
|
|
event.disconnect(function)
|
|
|
|
event.disconnect(function)
|
|
|
|
registered[event] = []
|
|
|
|
registered[event] = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@new_objfile
|
|
|
|
|
|
|
|
def _start_newobjfile(o=None):
|
|
|
|
|
|
|
|
gdb.events.start.on_new_objfile(o)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@stop
|
|
|
|
|
|
|
|
def _start_stop(o=None):
|
|
|
|
|
|
|
|
gdb.events.start.on_stop(o)
|
|
|
|
|