Peek and Poke, Vol. 2

NOTE: Some of the commands shown below have changed in more recent versions of Qt CreatorPlease check the Qt Creator documentation for details. Self-compiling gdb is rarely needed nowadays (2012).

Remember the day when you were asked to remember the days when all the tools at hand looked like a Basic interpreter with 30 commands, the most usable being PEEK, POKE and PRINT?

That’s been almost half a year now, and the tale is ready to get a new chapter.

The latest and greatest in the World of the GNU Project debugger (also known as gdb) is Python scripting, -- and it is really awesome. I certainly don't tend to exaggerate on the positive side, but this is close to sliced bread with chocolate and beer. Erm... well, you get the idea ;-)

The feature has been in the works for a while (the initial commit to the gdb CVS repository was in August 2008) and was officially released with gdb 7.0 in October 2009. So in theory it is now in a usable state and accessible on a broad range of platforms.

Unfortunately, outside the Ivory Tower usability is a bit hampered by the fact that gdb 7.0 likes to divide by zero every now and then, and the ``broad range of platforms'' excludes Mac (Apple's gdb for Mac is based on FSF gdb 6.3, and FSF gdb does not work there), Symbian (best bet so far is based on FSF gdb 6.4), and, of course, MSVC compiled binaries on Windows (no gdb at all).

But a few Gaul villages are still standing: It does work on Linux, and after tickling the gdb sources a bit it even works well, so well in fact that the next release of Qt Creator will use gdb's Python scripting to build up the "Locals and Watchers" view.

This also lets us nicely address one of the most prominent feature requests: To "provide hooks so that users could write their own display classes for custom data types to totally do away with the need for printf-style debugging", or "an easy to use plugin interface for the display of custom object", or "a nice custom data type display interface would be for the user to implement" (see comments of Ben, Abdel, and spinynorman), or a few similar ones on qt-creator@qt-project.org

Here is how:

  1. Get a Python enabled gdb by either
    • downloading a pre-build binary from here
    • --or--

    • building one yourself:
      • get build prerequisites including Python development packages (on Ubuntu e.g. python2.6-dev)
      • get gdb sources from the archer-tromey-python branch:
           git clone git://sourceware.org/git/archer.git
        cd archer
        git checkout -b archer-tromey-python origin/archer-tromey-python
      • patch sources to work around that division by zero:
           --- a/gdb/value.c
        +++ b/gdb/value.c
        @@ -1920,7 +1920,8 @@ value_primitive_field (struct value *arg1, int offset,
        v = allocate_value_lazy (type);
        v->bitsize = TYPE_FIELD_BITSIZE (arg_type, fieldno);
        - if ((bitpos % container_bitsize) + v->bitsize bitsize < = container_bitsize
        && TYPE_LENGTH (type) bitpos = bitpos % container_bitsize;
        else
      • configure and build it:
           ./configure --with-python --disable-werror
        make

        Your new gdb will emerge as gdb/gdb. It will identify itself as gdb-6.8.50.something-cvs. That is fine.

  2. Get a recent checkout of Qt Creator master branch and build it:
       git clone git://gitorious.org/qt-creator/qt-creator.git
    cd qt-creator
    qmake -r
    make
  3. Point Qt Creator's gdb path (Options -> Debugger -> Gdb -> Gdb Location) to your archer gdb or set the QTC_DEBUGGER_PATH environment variable before starting Qt Creator.
  4. Start debugging as usual.

That gives you the kind of display of QStringList, std::map etc use are used to from the old C++ based debugging helpers. You might notice that it's even a bit quicker. Nothing to be scared about, though.

But now, time for your own debugging helpers. Assuming you have the following class template in your code:

  template <typename T> class Vector
{
public:
explicit Vector(int size) : m_size(size), m_data(new T[size]) {}
~Vector() { delete [] m_data; }
//...
private:
int m_size;
T *m_data;
};

all you need is to

  1. write the following into some file, say vector.py:
        def qdump__Vector(d, value):
    data = value["m_data"] # extract the 'm_data' member from the object
    size = value["m_size"] # extract the 'm_size' member from the object
    d.putItemCount(size) # set the 'value' field to ''
    d.putNumChild(size) # announce 'size' children
    if d.isExpanded(): # check whether the children should be shown, too
    with Children(d, size): # if so:
    for i in d.childRange(): # iterate over the specified range
    d.putSubItem(i, data.dereference()) # show value btained from dereferencing the data pointer
    data += 1 # advance the data pointer by one
  2. make it accessible to gdb by putting
    python execfile('/path/to/your/vector.py')

    into the Additional Startup Commands settting

  3. start debugging as usual - i.e. hit F5

Qt Creator's default helpers are defined in share/qtcreator/dumper/qttypes.py. For a description of the two parameters 'd' and 'value' (of type 'Dumper' and 'gdb.Value' respectively), refer to the Qt Creator documentation.

Have fun!
André


Blog Topics:

Comments