Peek and Poke, Vol. 3

With the feature work on Qt Creator 2.0 slowing down in anticipation of the beta release there is a bit of time to update the Tale of Debugging.

Executive Summary for the people not following the thread so far: Users of recent release of the GNU Project Debugger gdb can automate certain tasks using the Python scripting language. Qt Creator takes advantage of that to populate the Locals and Expressions view. While this could be done before using the gdb/MI protocol it is more robust and way more powerful nowadays. And, surprisingly, faster.

But let us start with a look at the outside world. Work is progressing nicely, albeit, unfortunately, not uniformly. The FSF gdb has seen two official releases (7.0.1 and 7.1) since December, and both releases decided to play nice with Qt Creator on Linux and Windows/MinGW. The Symbian folks managed to get hold of a pre-7.0 based port that's capable of handling Python, so they are on the lucky side now, too, and so is, in theory, Maemo.

The other factions have been less lucky. Of course, Apple's gdb is still fast and robust on Mac, but as it's 6.3 based, it does not have Python, and the Python-enabled FSF-7.x-for-Darwin port happily crashes when only looking at something linked with QtCore. And then there was some vain attempt to improve the sad gdb-on-Windows/MSVC story.


Anyway, back to the bright side:

Qt Creator's Python based 'helpers' to inspect objects of certain Qt and Standard data types now finally caught up with their older compiled cousins - and went a bit further. By now they cover:

QAtomicInt, QBasicAtomicInt, QByteArray, QChar, QAbstractItem, QAbstractItemModel, QModelIndex, QDateTime, QDir, QFile, QFileInfo, QFlags, QHash, QList, QImage, QLinkedList, QLocale, QMap, QMultiMap, QObject, QPixmap, QPoint, QPointF, QRect, QRectF, QSet, QSharedPointer, QSize, QSizeF, QStack, QString, QStringList, QTemporaryFile, QTextCodec, QUrl, QVariant, QVector, QWeakPointer, std::deque, std::list, std::map, std::set, std::string, std::vector, std::wstring, std::basic_string, gnu_cxx::hash_set, TBuf and TLitC.

Why QImage you may ask. Uuh... well. Later ; )

For the beginning some boring stuff, like making gdb play nicely with stuff you'll never need. Nested anonymous struct for instance. I never noticed this was a problem with the gdb/MI based versions until someone created a bug report for Qt Creator. The problem is exposed by the following code:

        union {
struct { int i; int b; };
struct { float f; };
double d;
} a = { 42, 43 };
a.i = 1;
a.i = 2;
a.i = 3;

Put a breakpoint on the a.i = 1 line and press F5. When the program stops, expand the a, #1 and #2 nodes:

Anonymous Structs 1

Everything there. You can even modify the data in that structure: Change a.i in Locals view to 0. This changes f, d but, as expected, not b:

Anonymous Structs 2


Bored? Perhaps less boring is that you can now use scripting on the IDE side to do some fancy stuff with watched expressions, i.e. expressions that are evaluated each time the process stops, like at a break point or after a single step.

Have you ever had a large array of structs that contain lots of data but for the time being you are really only interest in a couple of members? I.e. something like the following, only a bit bigger?

        struct S { int a; double b; } s[10];
for (int i = 0; i != 10; ++i)
s[i].b = s[i].a = i;

Now, what if you are only interested in the a members of items 2 through 4?

Filtering to the Rescue! Create a new entry in the Watchers view (by selecting "Add New Watcher" from the Watchers view's context menu or by "cloning" an expression from the Locals view or the main text editor) and edit it to

        ['s[2].a', 's[3].a', 's[4].a']

You can enter a Python list of strings there, and each will be evaluated as an expression by gdb in the context of the current stack frame. The result will show up as children of the list's own node in the Watchers view, and as we specified the a member in all cases, we get a flat list of three ints.
Exactly what we were interested in.

But that's not all. The more daring can even use Python to create the list of expressions by using e.g.

        ['s[%d].a' % i for i in range(2, 5)]

Filtered Display

and one can even obtain the range indices from other variable values or arithmetic operations thereof etc.


Still bored by looking at black-on-white numbers and strings? What about watching an image being painted? With real colors ;-))?
Then try the following:

        QImage im(QSize(200, 200), QImage::Format_RGB32);
im.fill(QColor(200, 10, 30).rgba());
QPainter p;
p.setPen(QPen(Qt::black, 5.0, Qt::SolidLine, Qt::RoundCap));
p.drawEllipse(20, 20, 160, 160);
p.drawArc(70, 115, 60, 30, 200 * 16, 140 * 16);
p.drawEllipse(65, 70, 15, 15);
p.drawEllipse(120, 70, 15, 15);

Put a breakpoint on the first 'drawEllipse' line. Run and wait until the breakpoint is hit. Now go to the context menu of the im item in the Locals view and toggle between "Normal" and "Displayed" in the "Display of Type QImage" submenu.

Keep it at "Displayed", press F10 a few more times, and watch the contents of the extra window:

QImage 2  QImage 3  QImage 4  QImage 5


So many possibilities ; )


PS: A big "Thank you!" to everybody who was involved on making this possible by bringing Python scripting to gdb, especially to Thiago Jung Bauermann, Phil Muldoon and Tom Tromey.

Blog Topics: