Silmor . de
Site Links:
Impressum / Publisher

A Printing routine for QString in GDB

GDB supports the command print to print out the content of variables. This works pretty well with all basic types, but becomes annoying at best with complex types like QString. GDB has its own macro language, so it is possible to write routines for printing these types.

When GDB starts it reads in the file $HOME/.gdbinit to load macros that should be available at runtime. In the following two sections I show a macro to print QString objects. If you copy this macro into your .gdbinit file it will be automatically available each time you call gdb.

Example session:

(gdb) print myString
$2 = {static null = {<No data fields>}, static shared_null = {ref = {atomic = 39},
    alloc = 0, size = 0, data = 0x82174ca, clean = 0, simpletext = 0, 
    righttoleft = 0, asciiCache = 0, reserved = 0, array = {0}}, 
    static shared_empty = {ref = {atomic = 1}, alloc = 0, size = 0, 
    data = 0xf5f71aca, clean = 0, simpletext = 0, righttoleft = 0,
    asciiCache = 0, reserved = 0, array = {0}}, d = 0x8260b48, 
    static codecForCStrings = 0x0}
(gdb) printqstring myString
(QString)0x8217658 (length=26): "this is an example QString"
(gdb)

As you see above, print myString prints the QString as an object. Since the actual data is hidden in the element "d" it is not immediately visible - even print myString.d would not be very satisfactory, since QString stores its data in unicode format.

The form printqstring myString prints out a more readable version.

Qt 3.x

This macro was posted by David Faure to the KDE maillist in 2001:

define printqstring
    set $i=0
    while $i < $arg0.d->len
        print $arg0.d->unicode[$i++].cl
    end
end

It already prints out each character of the QString onto a single line.

A much refined version was posted by Arnaud de Muyser to the qt-interest list the same year:

define pqs
    set $i=0
    set $unicode=$arg0.d->unicode

    printf "Getting QString...\n"
    while $i < $arg0.d->len
        set $c=$unicode[$i++].cl
        if $c < 32 
          printf "\\0%o", $c
        else
          if $c <= 127
            printf "%c", $c
          else 
            printf "\\0%o", $c
          end 
        end
    end
    echo \n
end

Qt 4.x

The internal representation of QString changed for Qt 4.x: the length is now stored in d->size and it uses UCS-16 instead of UTF-8 for internal storage. The fact that QStrings are now implicitly shared does not matter in this context though.

So this is my adapted version of the macro:

define printqstring
    printf "(QString)0x%x (length=%i): \"",&$arg0,$arg0.d->size
    set $i=0
    while $i < $arg0.d->size
        set $c=$arg0.d->data[$i++]
        if $c < 32 || $c > 127
                printf "\\u0x%04x", $c
        else
                printf "%c", (char)$c
        end
    end
    printf "\"\n"
end

KDE

For KDE there is a collection of macros here.

Qt5

The internal representation of QString changed again for Qt 5.x: it relies on QTypedArrayData to store its data. This is an internal class that allows to store shared array data very efficiently.

I made two adaptations of the macro:

define printqs5static
  set $d=$arg0.d
  printf "(Qt5 QString)0x%x length=%i: \"",&$arg0,$d->size
  set $i=0
  set $ca=(const ushort*)(((const char*)$d)+$d->offset)
  while $i < $d->size
    set $c=$ca[$i++]
    if $c < 32 || $c > 127
      printf "\\u%04x", $c
    else
      printf "%c" , (char)$c
    end
  end
  printf "\"\n"
end

define printqs5dynamic
  set $d=(QStringData*)$arg0.d
  printf "(Qt5 QString)0x%x length=%i: \"",&$arg0,$d->size
  set $i=0
  while $i < $d->size
    set $c=$d->data()[$i++]
    if $c < 32 || $c > 127
      printf "\\u%04x", $c
    else
      printf "%c" , (char)$c
    end
  end
  printf "\"\n"
end

The difference is in how they access the array data of the string. The static version uses the blue code to access the data directly. It relies on some implementation details of the QArrayData class, therefore it may fail if some of the semantics or implementation details ever change. On the other hand the static version still works with core dumps or after the program crashed to analyze the wreckage. The dynamic version on the other hand uses the red code and relies on the (semi-)official interface of the QArrayData class. The downside is that this requires a dynamic call into the Qt code, which may fail (for some odd stack configurations), crash (in case you are analyzing a situation that leads to a real crash in QString), or simply refuse to work (core dumps and after the program already crashed).

In any case a warning: both versions take their time while printing strings. GDB has to dive very deep into the internals of Qt in order to extract the data, so printing even a very simple QString takes about 10 seconds.


Webmaster: webmaster AT silmor DOT de