gdb

gdb: examining complex c++ objects

I've been doing quite a bit of C++ programming (and, alas, debugging) for a project lately. One endless source of annoyance in C++ (at least in Linux) is the impedance mismatch between the compiler (gcc) and the debugger (gdb). C++ is notoriously hard to compile (and even just parse). gdb does a bit of name-demangling, but quickly finds itself out of its depth for complex C++ features (like heavy template usage). This is, after all, an old problem — even with C programs, debugging macro-ladden code is painful.

But I'm not going to get into the details of that; today I'm going to show you how to deal with a lesser annoyance, namely examining STL objects. For example, if you use the gdb's standard print (or p) command, strings look like a mess, and long ones are truncated:

#include <string>
#include <vector>
#include <iostream>
using namespace std;
int main () {
  string s = "";
  for (int i = 0; i < 5; i++)
    s += "This is a very, very long line.\n";
  s = s + s;
  cout 
~$ gdb testprog
(gdb) b 12
Breakpoint 1 at 0x8048c18: file testprog.cc, line 12.
(gdb) r
Breakpoint 1, main () at x.cc:12
12	  cout << s;
(gdb) p s
$1 = {static npos = 4294967295, 
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> =
    {<No data fields>}, <No data fields>}, 
    _M_p = 0x804b3ac "This is a very, very long line.\nTh"...}}

(ok, I had to truncate the string manually here for readability purposes — but the exact value of the maximum width isn't the issue here.) A much better way to examine strings is to use gdb's printf command on the appropriate member of the STL object:

(gdb) printf "%s\n" s._M_dataplus

This displays the actual string, without encoding newlines as \n. An even better way is to define a printstr command that you can reuse in future gdb sessions; create or edit the file ~/.gdbinit and add the following snippet:

define printstr
  printf "`%s'\n", $arg0._M_dataplus._M_p
end

This will allow you to simply say printstr s whenever you need to examine a string. Of course, this definition relies upon GCC's internal representation of a std::string, which may change from time to time.

After developing this gdb macro, I discovered Dan Marinescu's excellent STL Views gdb scripts, which adds support for examining vectors, maps, sets (and, yes, strings). The ideea is the same. If you spend any significant time inside gdb, this is an invaluable tool.

It's probably a good ideea to take this further and create similar printer functions for all complex (and frequently examined) classes in C++ projects. GDB's user-defined commands are extensively documented in the manual. You don't need to put such commands in ~/.gdbinit; you can create a separate script and load it using source scriptname.gdb when needed.

Tags: