There have been many new Python scripting features added to gdb since my last post on the topic. The one I want to focus on today is event generation.
I wrote a little about events in gdb-python post #9 — but a lot has changed since then. A Google SoC student, Oguz Kayral, wrote better support for events in 2009. Then, Sami Wagiaalla substantially rewrote it and put it into gdb.
In the new approach, gdb provides a number of event registries. An event registry is just an object with
disconnect methods. Your code can use
connect to register a callback with a registry; the callback is just any callable object. The event is passed to the callable as an argument.
Each registry emits specific events — “emitting” an event just means calling all the callables that were connected to the registry. For example, the
gdb.events.stop registry emits events when an inferior or thread has stopped for some reason. The event describes the reason for the stop — e.g., a breakpoint was hit, or a signal was delivered.
Here’s a script showing this feature in action. It arranges for a notification to pop up if your program stops unexpectedly — if your program exits normally, nothing is done. Something like this could be handy for automating testing under gdb; you could augment it by having gdb automatically exit if
gdb.events.exited fires. You could also augment it by setting a conditional breakpoint to catch a rarely-seen condition; then just wait for the notification to appear.
To try this out, just “
source” it into gdb. Then, run your program in various ways.
import gdb, threading, Queue, gtk, glib, os, pynotify (read_pipe, write_pipe) = os.pipe() event_queue = Queue.Queue() def send_to_gtk(func): event_queue.put(func) os.write(write_pipe, 'x') def on_stop_event(event): n = pynotify.Notification('Your program stopped in gdb') n.show() class GtkThread(threading.Thread): def handle_queue(self, source, condition): global event_queue os.read(source, 1) func = event_queue.get() func() def run(self): global read_pipe glib.io_add_watch(read_pipe, glib.IO_IN, self.handle_queue) gtk.main() gdb.events.stop.connect(on_stop_event) gtk.gdk.threads_init() pynotify.init('gdb') t = GtkThread() t.setDaemon(True) t.start()