QStrings don't use standard C arrays for strings
QT QStrings don't use standard C arrays for strings so gdb (the gnu debugger) isn't able to use its usual routines to display the string. About all you can do is display one character at a time, which isn't a very fast way to see what your string contains. You still have to know where the QString class stores this information.

Fortunately gdb has some scripting support to automate the process of ripping the string apart to display. After some searching I found this version. (Minor conversion to kde 2.3.2, the .cl in unicode[$i++].cl is changed to .ucs for later versions of qt). The script can be found on the kde web site kde-devel-gdb along with some other qt related gdb scripts.

Note: When using the scripts make sure the really long string constant is all on one line without any whitespace. Web browsers don't wrap long words so I manually put in some line breaks. The scripts can be downloaded as a text file kde_gdb.txt and my_gdb.txt. Move the file to .gdbinit in your home directory for gdb to read the function each time you start gdb.

kde version of the gdb script


define printqstring
       set $i=0
       set $out="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
       set $cur=0
       set $s = $arg0
       while $i < $s.d->len
         set $out[$cur++] = (char)($s.d->unicode[$i++].cl & 0xff)
         if $cur >= 40
           p $out
           set $cur = 0
           set $out="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
         end
       end
       if $cur < 40
         p $out
       end
end

I have in my notes that I was viewing a 4536 character string, the important thing is it is somewhat long. The above version took 54 seconds to display the string. It would visibly pause between each line of output, I did say that gdb had scripting, I didn't say that it was fast. This is the first time I had really played with gdb scripts, and I was determined to optimize things a little.

My version of the script

define printqstring
        set $i=0
        set $length=60
        # hold up to 80 characters at a time
        set $out="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
        set $a = &$arg0.d->unicode[0].cl
        set $stop = $arg0.d->len
        # find a multiple of $length to print
        set $whole = $arg0.d->len/$length
        set $whole *= $length
        set $cur = 0
        set $incur = 0
        # take care of multiples of $length
        while $incur < $whole
                set $cur = 0
                while $cur < $length
                        set $out[$cur++] = $a[$incur++ <<1]
                end
                output $out
        end
        set $out="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
        set $cur = 0
        while $incur < $stop
                set $out[$cur++] = $a[$incur++ <<1]
        end
        if $out[0]
                printf "\n"
                output $out
        end
        printf "\n"
end

My script is longer, has a nested loop, and another loop while the original script only had one loop, but mine is faster, much. My script takes some work setting up variables, but the critical section of my script has less statements to execute, only two vs three, and each statement is less complicated because there are less checks and less work to do in that section.

At time time it was taking something like 12 seconds to print the same 4536 character string. That comes out to about 4.5 times faster. More recently I did some more time tests between both scripts.

new code 5.7 seconds for 4K
old code 16 seconds for 4K

New code 55 seconds for a 40K string.
Old code 152 seconds for 40K string.

I'm now running gdb version 5.2.90_2002-11-20-cvs-debian, I don't know what version I was running at the time, but it looks like they must have improved script performance, between two and three times faster. My version of the script might not be as portable since I made some more assumptions than the original script, but it works for me and is much faster.

One note of caution that holds for both strings, gdb allocates memory for each array assigned in the scripts from the program's memory space and never gives it back, it is just a memory leak. The same holds for malloc and free. You can call the malloc and free functions from the scripts, but from my tests free doesn't do anything, or at least it doesn't return the memory to the program which to me means it doesn't do anything, so I'm just assigning the array. Maybe I should use this opportunity to note that my version of the script only allocates two arrays each time it is run where as the original script allocates an array per line of output.


Written by David Fries <david@fries.net>

Valid HTML 4.0! Valid HTML 4.0!
My pgp key is available and the fingerprint follows. See
http://www.gnupg.org/ for details.
pub 1024D/CB1EE8F0 2001-08-21 David D. Fries <david@fries.net>
Key fingerprint = 7079 F7EA D7EA 8E93 5B84 1900 008F 39D9 CB1E E8F0
sub 1024g/D9B8B029 2001-08-21