Peek and Poke, Vol. 2

Published Tuesday December 15th, 2009 | by

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é

Did you like this? Share it:

Posted in Qt, QtCreator

9 comments to Peek and Poke, Vol. 2

bobrik says:

no motivating screenshot? :-)

André says:

Would have been pretty much the same as the old ones at http://labs.trolltech.com/blogs/2009/06/22/peek-and-poke. I thought I could spend the rest of the day with something less challenging than fighting WordPress ;-}

Niko says:

Gdb 7.0 not only has introduced python scripting, but also pretty printing using python scripts:
http://sourceware.org/gdb/current/onlinedocs/gdb/Pretty-Printing.html

Advantage over your home grown solution:
* pretty printers work in cli gdb and any other gdb frontend
* libraries can ship their on pretty printers which gdb will automatically load

I even wrote such scripts for Qt ( http://nikosams.blogspot.com/2009/10/gdb-qt-pretty-printers.html )

So why do have you your own implementation?

bobrik says:

Thanks, now I see (I wasn’t aware of the previous post with screenshots).

crackedmind says:

awesome :)

André says:

@Niko: I am aware of gdb’s own pretty printer. It was a very conscious decision not to use them.

Users will not use the gdb/CLI for data display inside an IDE, and so far there are no libraries shipping usable pretty printers. So the advantages you cite are minor from a Qt Creator perspective, if they exist at all.

On the other hand, using them has some major drawbacks for me. They do not produce the output that I need, but on the other hand they produce also output that I don’t need. Worse, they force me to use MI variable objects, leading to extra roundtrips and bookkeeping for nested structures. While all those might be bearable on desktop machine, they are show stoppers on low bandwidth/high latency connections.

The nail in the coffin is another issue: The world is bigger than FSF gdb 7.0. First, there are a few people on Windows using MSVC. For good reasons even. They, unfortunately, cannot use gdb at all. Also, there are people on Mac and Symbian that cannot use gdb 7.0, and even on *nix it’s not uncommon to be stuck with old software. Even if You-Know-What IDE does not need to care for them, Qt Creator has to. So I have to maintain the Creator’s old C++ based pretty printing in parallel to the python based one, and keeping python and C++ code at least structurally the same helps with that a lot.

I am really, really happy that the python scripting allows me to use the architecture I find useful and produce the data I find interesting.

niko.sams says:

@André:
Performance shouldn’t be a problem – with varobjs gdb tells you what data changed, you don’t have to re-request everything. That should be a major advantage.

I understand the technical reason for your decision, but from the point of view from an user that want’s to write pretty printer for his own classes it’s not optimal. However it should be not to hard to port QtCreator pretty printers them to gdb pretty printers I guess.

Jeffrey Walton says:

> Unfortunately, outside the Ivory Tower usability is a bit hampered …, and
> the “broad range of platforms” excludes [Microsoft] MSVC compiled binaries
> on Windows (no gdb at all).
There’s no need for gdb on Windows – we have WinDbg and cdb, which are awesome tools. Perhaps the spare cycles (saved by not porting to Windows) can go to help Apple’s shitty assembler, or at least an upgrade to from at&t syntax to intel.

JW

Andre' says:

@Jeffrey Walton: There are quite a few features of gdb that are not available or not usable in cdb. Not having a “real” scripting language is one of them, and the whole “pretty printing” stuff mentioned in the blog is only possible because of having that available.

I am aware of what VS can do using autoexp.dat. But this is (a) not available in cdb as far as I know, and (b) not sufficient anyway. Also, writing Extension DLLs is neither trivial nor appealing in cross-platform development (“cross-platform” is not “runs on both XP _and_ Vista”)

cdb is also really, really slow when calling into user code, and it is way less capable in passing function parameters and evaluating expressions compared to gdb.

In addition, cdb cannot be fixed or extended to compensate for the missing features.

So, no, sorry, cdb is not a full replacement for gdb, but unfortunately the best we can get right now for debugging MSVC compiled binaries.

Re ‘AT&T’ vs ‘Intel’ syntax. I pretty much prefer Intel, too. That’s why I put ‘set disassembly-flavor intel’ into my .gdbinit.

Commenting closed.