I spent a few hours hacking something out as a proof of concept; I'd appreciate some opinions from those that know better. Before long, any development project generates complex data structures. Most of the time, gdb does a good job displaying even pretty complicated ones, and gives lots of options for customizing the output, such as turning off printing of static class members. When you need more customization, there is some rudimentary scripting support, but it tends to be slow and there are lots of cases where it doesn't work so well. I noticed one of my clients has a custom plugin for Visual Studio's debugger to view their string class (everyone rolls their own string class!), and I thought having that for GDB would be nice, too. So I've implemented a plugin system for gdb that allows people to override the "print" command for specific data types. The gist is this: you write some code to view the contents of some object and put it in a shared library. Then you punch "dataplugin SHAREDLIBRARYNAME.so" into gdb's console. GDB will look for a specific entry point in the library and call it, which lets the library register itself for certain data types. Then when the user attempts to view such a data type, control is handed to the library. GDB supplies a handful of functions that the library can call to get the job done: access to warning(), target_read_memory(), etc. Here is an example of what I mean, in Hello World form: You have a class Hello... class Hello { public: char *name; int times; }; ...and a program that uses it... int main(void) { int i; Hello hello; hello.name = (char *) "bob"; hello.times = 4; for (i = 0; i < hello.times; i++) printf("Hello, %s!\n", hello.name); return 0; } If we were to set a breakpoint on the for loop and type "p hello", we'd get this: $1 = {name = 0x4006b8 "bob", times = 4} But if you were to build this data plugin and load it ... http://hg.icculus.org/icculus/gdb-dataplugins/raw-file/1eb478462c3f/dataplugin_tests/hello/viewhello.cpp ...then "p hello" would report: This Hello says heya to bob, 4 times! Okay, that is not an upgrade. But it's a Hello World thing! Here are some more practical examples. 1) std::string (or insert your favorite string class here). std::string x("Hello, world!"); "p x" in gdb will give you something like this: $1 = {static npos = 18446744073709551615, _M_dataplus = {> = {<__gnu_cxx::new_allocator> = {}, }, _M_p = 0x602028 "Hello, world!"}} We are fortunate that the actual string data is visible here. I've seen string classes where it isn't. Also, you could try this with a std::wstring... std::wstring z(L"This is a wide string."); $2 = {static npos = 18446744073709551615, _M_dataplus = {> = {<__gnu_cxx::new_allocator> = {}, }, _M_p = 0x602088}} ...uhoh. But using a data plugin for these two types... http://hg.icculus.org/icculus/gdb-dataplugins/raw-file/1eb478462c3f/dataplugin_tests/std_str/viewstdstr.cpp (gdb) p x (std::string) "Hello, world!" (gdb) p z (std::wstring) L"This is a wide string." 2) wchar_t strings As we just saw with the std::wstring, wide character strings can be problematic in gdb...there's a FIXME in the source about it. But gcc introduces an extra complication with -fshort-wchar ... now the size of wchar_t may vary. Here's a plugin that handles both forms, by querying gdb for the sizeof (wchar_t) when loaded: http://hg.icculus.org/icculus/gdb-dataplugins/raw-file/1eb478462c3f/dataplugin_tests/wchar_t/viewwchar.c Breakpoint 1, main () at wchar.c:5 5 wchar_t *x = L"Hello, world!"; (gdb) p x $1 = (wchar_t *) 0x400558 (gdb) dataplugin ./viewwchar.so Loading data plugin "./viewwchar.so" ... Added data plugin viewer for 'wchar_t *' Data plugin added 1 viewers. (gdb) p x (wchar_t *) L"Hello, world!" 3) Linked lists. Let's say you had a simple linked list for storing people and office numbers... class LinkedList { public: const char *first; const char *last; int office_number; LinkedList *next; }; ...and some code to populate it... // this inserts a new item at the start of a global "list" AddToList("Ryan", "Gordon", 4923); AddToList("Greg", "Read", 227); AddToList("Linus", "Torvalds", 732); AddToList("Bill", "Gates", 666); // I kid! I kid! AddToList("Richard", "Stallman", 1135); AddToList("Andrew", "Tannenbaum", 9986); ...and wanted to view this in gdb... (gdb) p *list $2 = {first = 0x601270 "Andrew", last = 0x601290 "Tannenbaum", office_number = 9986, next = 0x6011d0} (gdb) p *list->next $3 = {first = 0x601200 "Richard", last = 0x601220 "Stallman", office_number = 1135, next = 0x601160} (gdb) p *list->next->next $4 = {first = 0x601190 "Bill", last = 0x6011b0 "Gates", office_number = 666, next = 0x6010f0} (gdb) p *list->next->next->mext There is no member named mext. Sooner or later, you get sick of adding on more "->next". (gdb) dataplugin ./viewlinkedlist.so Loading data plugin "./viewlinkedlist.so" ... Added data plugin viewer for 'LinkedList' Data plugin added 1 viewers. (gdb) p *list item (0x601240) { "Andrew", "Tannenbaum", 9986 }, item (0x6011d0) { "Richard", "Stallman", 1135 }, item (0x601160) { "Bill", "Gates", 666 }, item (0x6010f0) { "Linus", "Torvalds", 732 }, item (0x601080) { "Greg", "Read", 227 }, item (0x601010) { "Ryan", "Gordon", 4923 } (gdb) http://hg.icculus.org/icculus/gdb-dataplugins/raw-file/1eb478462c3f/dataplugin_tests/linked_list/viewlinkedlist.cpp It tightens down the output to what we care about, and walks the list for us. A linked list is trivial enough for an example, but there are plenty of common data structures that could benefit from a data plugin much more. Hash tables come to mind immediately, as do binary trees. 4) Not-human readable data. There are lots of things that are valid data that will never be comprehensible no matter what you pass to printf(). Images, mp3 data, 3d meshes, a million other things. Here's a plugin that will handle a "surface," the pixels that make up a bitmapped image, in the SDL multimedia library ( http://libsdl.org/ ). http://hg.icculus.org/icculus/gdb-dataplugins/file/1eb478462c3f/dataplugin_tests/sdl/viewsdl.c At runtime, if you try to "print" an SDL_Surface, the plugin will create an X11 window with the current pixel content, so you can see if your data is actually sane. Debugging continues when you close the window. Many many times I've stepped through these in gdb like this... (gdb) p/x ((unsigned int *) surface->pixels)[0] $1 = 0x0 (gdb) p/x ((unsigned int *) surface->pixels)[1] $2 = 0x0 (gdb) p/x ((unsigned int *) surface->pixels)[2] $3 = 0x0 ...and after 499 iterations think the entire bitmap is black, not realizing that it's only the top row having a black border and I'm still 301 pixels from the second row of the image. Having this data plugin would tell me if the whole image is black in under a second. Now, granted, some of these examples may not follow best practices for gdb, and some of them might be solvable with a little scripting in your ~/.gdbinit file. But these are meant to be simple, general-use examples. I could envision lots of projects maintaining their own plugins that are built with everything else, having the benefit of access to the same data headers as the code they are debugging. Some organizations will use this in-house, and some projects--Gnome, Python, KDE and Mozilla all come to mind--may wrap some common but complex data structures in plugins with the expectation that they will be useful to outside contributors that just want to step through a piece of code without steeping in the particular religion of the project: just load viewgnome.so and some things are easier to digest as an outsider! I have only tested this on GNU/Linux. It should, in theory, work on anything that has dlopen(). There are a few FIXMEs (such as the dlopen() requirement), there's isn't proper documentation, and the code is not up to quality standards...it's definitely usable and useful now, though. If this is something that could be accepted into gdb, I would welcome comments and guidance on cleaning it up for inclusion in CVS. I'm happy to walk anyone through the finer points of the patch, as well, if anything isn't clear. Attached is the current patch against the latest CVS. Thanks, --ryan.