Imagine you just created a nice GObject with a so called “priv thing” in it. Yes, “thing” is a good name for now. In your code you access that “priv thing” using the G_TYPE_INSTANCE_GET_PRIVATE GType “stuff”. Most of the time you are a happy hacker with a “priv thing”. Then suddenly you have a bug somewhere in client code of that GObject type of yours (by client code I mean: code that is using an instance of your type, like calling API on it).
You’ll most likely want to peek at that “priv thing”? Doesn’t sound very unusual, right?
Well it’s actually quite simple:
We have a GtkTreeModel, which is a GTypeInterface implemented as TnyGtkHeaderListModel. The instance of that TnyGtkHeaderListModel is called “self”. The instance (which in this debugging session plays the role of the client code for a TnyFolder instance) will do some stuff with another instance stored at self->folder. With some casting voodoo magic we can easily get the “folder” instance out of that. Nothing difficult here.
Let’s do this step by step …
(gdb) print self
$17 = (GtkTreeModel *) 0x82f8090
(gdb) print *self
$18 = <incomplete type>
(gdb) print ((TnyGtkHeaderListModel*)self)->folder
$19 = (TnyFolder *) 0x8253ba8
(gdb) print *((TnyGtkHeaderListModel*)self)->folder
$20 = <incomplete type>
(gdb)
We are after the “priv thing” of that folder instance: we’re not there yet. But let’s dig a little bit deeper!
(gdb) print * (TnyCamelFolder*) ((TnyGtkHeaderListModel*)self)->folder
$21 = {parent = {g_type_instance = {g_class = 0x80e0b98}, ref_count = 2, qdata = 0x0}}
(gdb)
We’re still not there, and we still haven’t even seen a sign of that “priv thing”. That’s because it’s somewhere deep inside the “crazyness” of the glib GType stuff. Don’t worry, we have yet another gdb trick as tool in our pocket. We can actually launch some of our own code. Including code from the glib library.
(gdb) print g_type_instance_get_private (((TnyGtkHeaderListModel*)self)->folder, tny_camel_folder_get_type())
$22 = 136657848
(gdb)
Okay, let’s not care about the number and just use that $22 label.
(gdb) print *$22
$23 = 1
(gdb)
Well…of course! Our beloved debugger doesn’t know how that pointer looks like! Let’s tell it. Because “we” .. know, right?
(gdb) print *(TnyCamelFolderPriv*)$22
$24 = {loaded = 1, headers_list_type = 0, folder_changed_id = 132, headers_managed = 1898, folder_lock = 0x826af80, folder = 0x81f7868,
folder_name = 0x826afb0 "INBOX/30000", account = 0x80e58f8, store = 0x80e5a08, cached_length = 1898, unread_length = 49, unread_sync = 0,
local_size = 258652, subscribed = 1, has_summary_cap = 1, iter = 0x81f6800, iter_parented = 1, cached_name = 0x826afc0 "30000",
cached_folder_type = TNY_FOLDER_TYPE_NORMAL, remove_strat = 0x820a8b0, receive_strat = 0x820a6a0, observers = 0x8259fb0,
sobservers = 0x8259fc8, self = 0x8253ba8, want_changes = 1, dont_fkill = 0, parent = 0x81f3ee0}
(gdb)
Maybe we should make some gdb-shortcuts and do some integration with gdb and glib? I do like things like refdbg and I like all those other tools too. Yet I still have to fall back to using gdb most of the times.
Let’s play some more, digging deeper:
(gdb) print ((TnyCamelFolderPriv*)$22)->folder
$25 = (CamelFolder *) 0x81f7868
(gdb) print *((TnyCamelFolderPriv*)$22)->folder
$26 = {parent_object = {klass = 0x82a9130, hooks = 0x82f9190, ref_count = 1, flags = 0}, priv = 0x8216e00, name = 0x82f75f0 "30000",
full_name = 0x825d4f0 "INBOX/30000", description = 0x0, parent_store = 0x80e5a08, summary = 0x80b8368, folder_flags = 3,
permanent_flags = 8194079}
(gdb)
(gdb) print *((TnyCamelFolderPriv*)$22)->folder->parent_store
$31 = {parent_object = {parent_object = {klass = 0x80de0e0, hooks = 0x80bca80, ref_count = 7, flags = 0}, priv = 0x80e55e0,
session = 0x80b9c00, provider = 0xb6233da0, status = CAMEL_SERVICE_CONNECTED, connect_op = 0x0, url = 0x80e6230, data = 0x80e5ba0},
priv = 0x80e5778, folders = 0x80e57a8, flags = 11, mode = 3}
(gdb)