archer gdb macros for glib

The Archer project is working on  modernizing gdb. One aspec of this is support for scripting gdb using python. Today I landed some python macros for gdb that makes debugger integration with glib/gobject much nicer.

This is best shown by a “screencast” showing the new features. If you’ve ever debugged a glib program, read the below carefully. If not, it won’t make much sense to you, sorry.

(gdb) # Welcome to the glib macros demo
(gdb) # We support pretty printing of lists:
(gdb) l toplevel_list
296    static GtkKeyHash *gtk_window_get_key_hash        (GtkWindow   *window);
297    static void        gtk_window_free_key_hash       (GtkWindow   *window);
298    static void       gtk_window_on_composited_changed (GdkScreen *screen,
299                                 GtkWindow *window);
300
301    static GSList      *toplevel_list = NULL;
302    static guint        window_signals[LAST_SIGNAL] = { 0 };
303    static GList       *default_icon_list = NULL;
304    static gchar       *default_icon_name = NULL;
305    static guint        default_icon_serial = 0;
(gdb) p toplevel_list
$1 = 0x84d7218 = {0x842f468, 0x842f3b8, 0x842f308, 0x842f258, 0x842f1a8, 0x842f0f8,
 0x842f048, 0x8370710, 0x8370660, 0x83705b0, 0x8370500, 0x8370450, 0x83703a0, 
0x83702f0, 0x8370240, 0x8370190, 0x83700e0, 0x8370030, 0x8349088}
(gdb) # And hashtables:
(gdb) l g_quark_ht
88    G_LOCK_DEFINE_STATIC (g_dataset_global);
89    static GHashTable   *g_dataset_location_ht = NULL;
90    static GDataset     *g_dataset_cached = NULL; /* should this be
91                             threadspecific? */
92    G_LOCK_DEFINE_STATIC (g_quark_global);
93    static GHashTable   *g_quark_ht = NULL;
94    static gchar       **g_quarks = NULL;
95    static GQuark        g_quark_seq_id = 0;
96
97    /* --- functions --- */
(gdb) p g_quark_ht
$2 = 0x8220a30 = {
 [0x824db08 "draw-border"] = 0x97,
 [0x83bdc38 "<Actions>/IconViewActions/Sort by Size"] = 0x962,
 [0x3970905 "custom-success"] = 0x414,
 [0x83c0878 "<Actions>/DirViewActions/OpenFolderWindow"] = 0x8df,
 [0x2a9d6bb "tooltip-text"] = 0x107,
 [0x82c0648 "audio_%d"] = 0x50c,
 [0x83af728 "zoom_level_changed"] = 0x7e6,
 [0x83c1210 "Empty Trash"] = 0x8e6,
 [0x83584a0 "GdkPixmap"] = 0x76c,
 [0x83298d0 "soup"] = 0x61f,
 [0x82e4a58 "gio"] = 0x568,
 [0x83c2600 "<Actions>/DirViewActions/Create Link"] = 0x8f9,
 [0x835bca0 "MimeTypes"] = 0x6ed,
 [0x81c221d "NautilusIconInfo"] = 0x7bb,
 [0x2b2ff13 "gtk-file-chooser-backend"] = 0x84,
 [0x82edee8 "audio/x-shorten"] = 0x5a6,
 [0x82b9e08 "GstAllocTraceFlags"] = 0x498,
 [0x8307798 "videotestsrc"] = 0x5ee,
 [0x82cc6c0 "tcp"] = 0x529,
 [0x81a3dda "NautilusBookmarkList"] = 0x733,
 [0xc76e26 "dirname"] = 0x350,
 [0x2b1f004 "gtk-menu-bar-accel"] = 0x66,
 [0x8267da8 "GstObjectFlags"] = 0x461,
 [0x82bea88 "http://farsight.sf.net"] = 0x500,
 [0x835bbf8 "FileSystems"] = 0x6ec,
 [0x82b8bd0 "GstDebugColorFlags"] = 0x481,
 [0x81c564d "EggSMClient"] = 0x2b3,
 [0x83b6528 "band-select-ended"] = 0x84f,
 [0xc685fd "GFile"] = 0x318,
 [0x83bcb80 "row-reordered"] = 0x8ac,
 [0x8320628 "liveadder"] = 0x60f,
 [0x825c870 "drag_failed"] = 0x171,
 [0x825d8e0 "gnome_disable_sound_events"] = 0xd6,
 [0x2b4f420 "grab-focus"] = 0x129,
 [0x83c4c20 "<Actions>/DirViewActions/Self Format Volume"] = 0x91d,
 [0x2b3889d "x"] = 0x817,
 [0x2a92cc0 "y"] = 0x818,
 [0x2b2a535 "color-hash"] = 0x83,
 [0x2b3c0e6 "mask"] = 0x76f,
 [0x8343360 "<Actions>/ShellActions/Zoom Normal"] = 0x711,
 [0x83cd8b0 "<Actions>/IconViewActions/Tighter Layout"] = 0x956,
 [0x2b4f28a "gtk-pango-context"] = 0xea,
 [0x82ec370 "application/x-gzip"] = 0x58f,
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) # We also have a cool gforeach command:
(gdb) gforeach i in toplevel_list: print ((GtkWindow *)$i)
$3 = 0x842f468 [GtkWindow]
$4 = 0x842f3b8 [GtkWindow]
$5 = 0x842f308 [GtkWindow]
$6 = 0x842f258 [GtkWindow]
$7 = 0x842f1a8 [GtkWindow]
$8 = 0x842f0f8 [GtkWindow]
$9 = 0x842f048 [GtkWindow]
$10 = 0x8370710 [GtkWindow]
$11 = 0x8370660 [GtkWindow]
$12 = 0x83705b0 [GtkWindow]
$13 = 0x8370500 [GtkWindow]
$14 = 0x8370450 [GtkWindow]
$15 = 0x83703a0 [GtkWindow]
$16 = 0x83702f0 [GtkWindow]
$17 = 0x8370240 [GtkWindow]
$18 = 0x8370190 [GtkWindow]
$19 = 0x83700e0 [GtkWindow]
$20 = 0x8370030 [GtkWindow]
$21 = 0x8349088 [NautilusSpatialWindow]
(gdb) gforeach i in toplevel_list: print ((GtkWindow *)$i)->title
$22 = (gchar *) 0x0
$23 = (gchar *) 0x0
$24 = (gchar *) 0x0
$25 = (gchar *) 0x0
$26 = (gchar *) 0x0
$27 = (gchar *) 0x0
$28 = (gchar *) 0x0
$29 = (gchar *) 0x0
$30 = (gchar *) 0x0
$31 = (gchar *) 0x0
$32 = (gchar *) 0x0
$33 = (gchar *) 0x0
$34 = (gchar *) 0x0
$35 = (gchar *) 0x0
$36 = (gchar *) 0x0
$37 = (gchar *) 0x0
$38 = (gchar *) 0x0
$39 = (gchar *) 0x0
$40 = (gchar *) 0x83d0200 "alex"
(gdb) # There is also some nice GObject integration features:
(gdb) break gtk_widget_size_allocate
Breakpoint 1 at 0x29ff265: file gtkwidget.c, line 3821.
(gdb) c
Continuing.
[Thread 0xb71ffb70 (LWP 2599) exited]
Breakpoint 1, IA__gtk_widget_size_allocate (widget=0x8349088 [NautilusSpatialWindow], allocation=0xbfffe914) at gtkwidget.c:3821
3821    {
(gdb) # Notice the runtime detected type of the instance
(gdb) c
Continuing.
Breakpoint 1, IA__gtk_widget_size_allocate (widget=0x8313d38 [GtkTable], allocation=0xbfffe460) at gtkwidget.c:3821
3821    {
(gdb) c
Continuing.
Breakpoint 1, IA__gtk_widget_size_allocate (widget=0x8365c70 [GtkVBox], allocation=0xbfffe048) at gtkwidget.c:3821
3821    {
(gdb) c
Continuing.
Breakpoint 1, IA__gtk_widget_size_allocate (widget=0x8365d20 [GtkVBox], allocation=0xbfffdc08) at gtkwidget.c:3821
3821    {
(gdb) # This is gonna be a long hairy backtrace, right? NO!
(gdb) new-backtrace
#0  gtk_widget_size_allocate (widget=0x8365d20 [GtkVBox], allocation=0xbfffdc08) at gtkwidget.c:3821
#1  0x027dcb19 in gtk_box_size_allocate (widget=<value optimized out>, allocation=<value optimized out>) at gtkbox.c:500
#2  0x00a180ac in g_cclosure_marshal_VOID__BOXED (closure=0x8249ad0, return_value=0x0, n_param_values=2, param_values=
 0x8535e78, invocation_hint=0xbfffddc0, marshal_data=0x27dc850) at gmarshal.c:566
#3  <...>
#4  <...>
#5  <...>
#6  <...>
#7  <emit signal size-allocate on instance 0x8365c70 [GtkVBox]>
#8  0x029ff3da in gtk_widget_size_allocate (widget=<value optimized out>, allocation=<value optimized out>) at gtkwidget.c:3887
#9  0x0295b625 in gtk_table_size_allocate_pass2 (table=<value optimized out>) at gtktable.c:1610
#10 0x0295b625 in gtk_table_size_allocate (table=<value optimized out>) at gtktable.c:849
#11 0x00a180ac in g_cclosure_marshal_VOID__BOXED (closure=0x8249ad0, return_value=0x0, n_param_values=2, param_values=
 0x85956f0, invocation_hint=0xbfffe200, marshal_data=0x295abd0) at gmarshal.c:566
#12 <...>
#13 <...>
#14 <...>
#15 <...>
#16 <emit signal size-allocate on instance 0x8313d38 [GtkTable]>
#17 0x029ff3da in gtk_widget_size_allocate (widget=<value optimized out>, allocation=<value optimized out>) at gtkwidget.c:3887
#18 0x02a14b39 in gtk_window_size_allocate (widget=<value optimized out>, allocation=<value optimized out>) at gtkwindow.c:4941
#19 0x00a180ac in g_cclosure_marshal_VOID__BOXED (closure=0x8249ad0, return_value=0x0, n_param_values=2, param_values=
 0x859bc28, invocation_hint=0xbfffe610, marshal_data=0x2a149f0) at gmarshal.c:566
#20 <...>
#21 <...>
#22 <...>
#23 <...>
#24 <emit signal size-allocate on instance 0x8349088 [NautilusSpatialWindow]>
#25 0x029ff3da in gtk_widget_size_allocate (widget=<value optimized out>, allocation=<value optimized out>) at gtkwidget.c:3887
#26 0x02a15044 in gtk_window_move_resize (window=<value optimized out>) at gtkwindow.c:6186
#27 0x02a15044 in gtk_window_check_resize (window=<value optimized out>) at gtkwindow.c:5358
#28 0x00a17994 in g_cclosure_marshal_VOID__VOID (closure=0x8262b68, return_value=0x0, n_param_values=1, param_values=
 0x8535700, invocation_hint=0xbfffeae0, marshal_data=0x2a14b50) at gmarshal.c:77
#29 <...>
#30 <...>
#31 <...>
#32 <...>
#33 <emit signal check-resize on instance 0x8349088 [NautilusSpatialWindow]>
#34 0x028176ba in gtk_container_check_resize (container=<value optimized out>) at gtkcontainer.c:1424
#35 0x028179f2 in gtk_container_idle_sizer (data=<value optimized out>) at gtkcontainer.c:1350
#36 0x002c3588 in gdk_threads_dispatch (data=<value optimized out>) at gdk.c:506
#37 0x00929382 in g_idle_dispatch (source=0x8557f20, callback=0x8365d20, user_data=0x83548c0) at gmain.c:4065
#38 0x0092b198 in g_main_dispatch (context=<value optimized out>) at gmain.c:1960
#39 0x0092b198 in g_main_context_dispatch (context=<value optimized out>) at gmain.c:2513
#40 0x0092eac8 in g_main_context_iterate (context=0x8247f90, block=<value optimized out>, dispatch=1, self=
 0x821f018) at gmain.c:2591
#41 0x0092ef3f in g_main_loop_run (loop=0x8291758) at gmain.c:2799
#42 0x028b7129 in gtk_main () at gtkmain.c:1205
#43 0x0807e923 in g_themed_icon_append_name () at gthemedicon.c:378
#44 0x0071ab36 in __libc_start_main (main=0x807e2c0 <g_themed_icon_append_name+86084>, argc=1, ubp_av=0xbffff154, init=
 0x81a3180, fini=0x81a3170, rtld_fini=0x6efd00 <_dl_fini>, stack_end=0xbffff14c) at libc-start.c:220
#45 0x080692b1 in g_themed_icon_append_name () at gthemedicon.c:378

The above was recorded using a stock rawhide (to be Fedora 12) gdb and glib (including debuginfo packages), with just the python macros added. It also works with the gdb shipping in Fedora 11, but there is some issue there that makes the gforeach macro crash gdb. Additionally, the VTA work that landed in the GCC in Fedora 12 makes what gdb reports much more reliable wrt optimizations, which is very nice for e.g. the backtrace filtering.

3 Responses to “archer gdb macros for glib”

  1. Snark says:

    It definitely looks interesting!

  2. Danni says:

    Where do we get this!

  3. alexl says:

    Danni: Its in glib git