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 connect
and 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()
8 Comments
I think you meant to call send_to_gtk(gtk.main_quit) in on_stop_event().
Crud, you’re right, I messed that up.
The idea is that all Gtk code should run in its own thread. I don’t think this is enforced, though, hence my bug.
What I meant was something like (untested):
gdb.events.stop.connect(lambda(event): send_to_gtk(on_stop_event))
… but with on_stop_event suitably defined not to have arguments.
I am using python 2.6.5 under ubuntu 10.04
When I place a “gdb.events.exited.connect (exit_handler)” in my code
I get a
AttributeError: ‘module’ object has no attribute ‘events’
Error.
what am I missing?
Your gdb is probably too old. What version are you using?
I am using GNU gdb (GDB) 7.1-ubuntu
…
This GDB was configured as “i486-linux-gnu
Events didn’t go in until 7.3
Thanks TOM! works in 7.4
Another help needed. Can I use the following in python …
———–
gdb.execute(‘while (!$myFlagToQuit) \
python run_one_stepinto() \
end’,False, True)
———–
I am checking a python var (viz. myFlagToQuit) and want to run one python function (viz. run_one_stepinto) and end the loop.
I am setting the var “myFlagToQuit” within an exit handler.
Why not just put the entire loop in Python?