How does Qt Creator interact with debugger GDB?

You may never notice the interaction between Qt Creator and the GDB debugger in the past. The communication between Qt Creator and GDB is hidden well. You are supposed to only use the variable/watch window during the debug. But sooner or later, you’ll find problems you cannot solve with the debug windows Qt Creator presents to you. For example, you may encounter the problem that Qt Creator cannot launch the debugger engine. Without seeing the logs Qt Creator communicates with the debugger, you’ll never know what’s happening.

There does exist a debugger log window. As I said, it is hidden well. If you are lucky, you may see this windows appears in a short time then disappears again when the debugged program exits. It is also impossible for a newbie to dig the debugger window out. In fact, you can let Qt Creator show the debugger log window only when you are debugging a program and by clicking Window/Views/Debugger Log menu item.

Now you will see the debugger log window which has a left panel and a right panel.

From the debugger log window, you can see a lot of interaction messages between Qt Creator and GDB. These are the commands Qt Creator sends to GDB and the results Qt Creator gets from GDB. I hear you are saying “wait a minute, do you mean those lines like 640-exec-continue 641-thread-info are the commands sent by Qt Creator to GDB and executed by GDB? I never used those commands. I only used commands like br, list, run, continue, print, etc to debug a program in GDB.” Yes, you are right, those are not ordinary GDB CLI commands you are using in your daily debugging work, but GDB MI(Machine oriented text Interface) commands.  When you start GDB with the -i mi option, as Qt Creator does, you’ll get the commands available for you.

gdb -i mi test.exe

The printed messages in the MI mode are very messy because they are not for human readers but for machine parsers. How to decode those inputs and outputs in the debugger log window? Well, the left panel of the debugger log window contains mainly the commands Qt Creator sends to GDB, while the right panel contains both the commands sent and the messages received from GDB. There is a line edit at the bottom of the left panel where you can input debug command(one per time) manually. The MI commands have the form of token-command where token is usually a number. The output of the command will also include the number so the result can be associated with the command easily. But the token can be omitted, for example, -exec-run, -thread-info are both legal GDB MI commands. Most of the common MI commands have their CLI counterparts. For example, -exec-run corresponds to run, -exec-continue corresponds to continue. You can also input ordinary CLI commands in MI mode.

(gdb)
next
&"next\n"
^running
*running,thread-id="all"
(gdb)

The output of a CLI command will include a line beginning with “&” which is followed by the command you enter. The output in MI mode has special character such as &, ^, *, ~ at the beginning of each line which means the line is from specific output channel. The line beginning with ^ is the final status of the command, i.e., done, or error. There may be other outputs between the enter of the command and the final status, even after the final status line. These are called out-of-band messages.

The mainly communications between Qt Creator and GDB are not done by calling GDB MI commands, but through GDB Python API. The python code is mainly in gdbbridge.py and dumper.py which are in c:\Qt5.12.1\Tools\QtCreator\share\qtcreator\debugger\. Qt Creator will import the gdbbridge python module in GdbEngine::setupEngine() in src\plugins\debugger\gdb\gdbengine.cpp then get the theDumper(of class Dumper) object. With the theDumper python object, Qt Creator can retrieve much information from GDB with the python api. In the setupEngine function, you can also find the commands Qt Creator asks GDB to execute to set the debugger up.

show version
show debug-file-directory
set print object on
set breakpoint pending on
set print elements 10000
set unwindonsignal on
set width 0
set height 0
set substitute-path
directory 
set sysroot 
set detach-on-fork off
python sys.path.insert(1,"xxxxxx")
python sys.path.append('xxxxx')
python from gdbbridge import *

After the last line, theDumper is available and the first thing Qt Creator uses it to do is to load the pretty printers.

As I said before, the most used debugger windows are the local and the watcher window. If they are not appeared, you can call them out by clicking Window/Views/Locals(Expressions).

The Locals window shows the values of local variables/parameters of a function when execution stops in the function. The watcher window displays the variables you added to watch their values. After breaking on some line in a function, Qt Creator will call theDumper.fetchVariables to retrieve the values of both the local variables and the watched variables in single shot. Here is an example:

<682python theDumper.fetchVariables({"autoderef":1,"context":"","displaystringlimit":"100","dyntype":1,"expanded":["inspect","local","watch","return"],"fancy":1,"formats":{},"nativemixed":0,"partialvar":"","passexceptions":0,"qobjectnames":1,"resultvarname":"","stringcutoff":"10000","token":682,"typeformats":{},"watchers":[{"exp":"6d7977837273696f6e","iname":"watch.0"}]})

The results are parsed and displayed in the Locals window and the Expressions window, respectively.

Qt Creator calls theDumper.fetchVariables frequently. Even your mouse pointer floats over a variable name in the source code, Qt Creator will call it to retrieve the value of the variable and display it in the popup tool-tip.

Posted in

Leave a Reply