Using Debugging Helpers

Structured data, such as objects of class, struct, or union types, is displayed in the Locals and Expressions view as part of a tree. To access sub-structures of the objects, expand the tree nodes. The sub-structures are presented in their in-memory order, unless the Sort Members of Classes and Structs Alphabetically option from the context menu is selected.

Similarly, pointers are displayed as a tree item with a single child item representing the target of the pointer. In case the context menu item Dereference Pointers Automatically is selected, the pointer and the target are combined into a single entry, showing the name and the type of the pointer and the value of the target.

This standard representation is good enough for the examination of simple structures, but it does usually not give enough insight into more complex structures, such as QObjects or associative containers. These items are internally represented by a complex arrangement of pointers, often highly optimized, with part of the data not directly accessible through either sub-structures or pointers.

To give the user simple access also to these items, Qt Creator employs so-called debugging helpers. Debugging helpers come in two varieties, a compiled one, for use with the CDB backend, and a set of Python scripts for use with the GDB and LLDB backends.

Debugging helpers are always automatically used. To force a plain C-like display of structures, select Tools > Options > Debugger > Locals & Expressions, and then deselect the Use Debugging Helper check box. For GDB and LLDB this will still use the Python scripts, but generate more basic output. To force plain display for a single object or for all objects of a given type, select the corresponding option from the context menu.

Qt Creator ships with debugging helpers for more than 130 of the most popular Qt classes, Standard C++ containers and smart pointers, covering the usual needs of a C++ application developer out-of-the-box.

Extending GDB and LLDB Debugging Helpers

When using either GDB or LLDB as the debugging backend, Qt Creator uses Python scripts to display information in the Locals and Expressions view.

You can easily extend these scripts to cover your own types, using the same code for both the GDB and the LLDB backend. No compilation is required, just adding a few lines of Python. The scripts can address multiple versions of Qt, or of your own library, at the same time.

To extend the shipped Python based debugging helpers for custom types, add debugging helper implementations to the GDB startup file ~/.gdbinit, or specify them directly in the Additional Startup Commands in Tools > Options > Debugger > GDB.

The implementation of a debugging helper typically consists of a single Python function, which needs to be named qdump__NS__Foo, where NS::Foo is the class or class template to be examined. Note that the :: scope resolution operator is replaced by double underscores __. Nested namespaces are possible.

The debugger plugin calls this function whenever you want to display an object of this type. The function is passed the following parameters:

  • d of type Dumper, an object containing current settings and providing facilities to build up an object representing part of the Locals and Expressions view,
  • value of type Value, wrapping either a gdb.Value or an lldb.SBValue.

The qdump__* function has to feed the Dumper object with certain information which is used to build up the object and its children's display in the Locals and Expressions view.

Example:

def qdump__QFiniteStack(d, value):
    alloc = int(value["_alloc"])
    size = int(value["_size"])
    d.putItemCount(size)
    d.putNumChild(size)
    if d.isExpanded():
        innerType = d.templateArgument(value.type, 0)
        d.putArrayData(innerType, value["_array"], size)

Note: To create dumper functions usable with both LLDB and GDB backends, avoid direct access to the gdb.* and lldb.* namespaces and use functions of the Dumper class instead.

Dumper Class

For each line in the Locals and Expressions view, a string like the following needs to be created and channeled to the debugger plugin.

 {iname='some internal name',           # optional
  addr='object address in memory',      # optional
  name='contents of the name column',   # optional
  value='contents of the value column',
  type='contents of the type column',
  numchild='number of children',        # zero/nonzero is sufficient
  childtype='default type of children', # optional
  childnumchild='default number of grandchildren', # optional
  children=[              # only needed if item is expanded in view
     {iname='internal name of first child',
       },
     {iname='internal name of second child',
       },

  ]}

The value of the iname field is the internal name of the object, constituting a dot-separated list of identifiers, corresponding to the position of the object's representation in the view. If it is not present, is it generated by concatenating the parent object's iname, a dot, and a sequential number.

The value of the name field is displayed in the Name column of the view. If it is not specified, a simple number in brackets is used instead.

While in theory you can build up the entire string above manually, it is easier to employ the Dumper Python class for that purpose. The Dumper Python class contains a complete framework to take care of the iname and addr fields, to handle children of simple types, references, pointers, enums, known and unknown structs as well as some convenience functions to handle common situations.

The member functions of the Dumper class are the following:

  • __init__(self) - Initializes the output to an empty string and empties the child stack. This should not be used in user code.
  • put(self, value) - Low level function to directly append to the output string. That is also the fastest way to append output.
  • putField(self, name, value) - Appends a name='value' field.
  • childRange(self) - Returns the range of children specified in the current Children scope.
  • putItemCount(self, count) - Appends a field value='<%d items' to the output.
  • putName(self, name) - Appends a name='' field.
  • putType(self, type, priority=0) - Appends a field type='' unless the type coincides with the parent's default child type or putType was already called for the current item with a higher value of priority.
  • putBetterType(self, type) - Overrides the last recorded type.
  • putNumChild(self, numchild) - Appends a field numchild='' unless the numchild coincides with the parent's default child numchild value.
  • putValue(self, value, encoding = None) - Append a file value='', optionally followed by a field valueencoding=''. The value needs to be convertible to a string entirely consisting of alphanumerical values. The encoding parameter can be used to specify the encoding in case the real value had to be encoded in some way to meet the alphanumerical-only requirement. Currently the following encodings are supported:
    • 0: unencoded 8 bit data, interpreted as Latin1.
    • 1: base64 encoded 8 bit data, used for QByteArray, double quotes are added.
    • 2: base64 encoded 16 bit data, used for QString, double quotes are added.
    • 3: base64 encoded 32 bit data, double quotes are added.
    • 4: base64 encoded 16 bit data, without quotes (see 2)
    • 5: base64 encoded 8 bit data, without quotes (see 1)
    • 6: %02x encoded 8 bit data (as with QByteArray::toHex), double quotes are added.
    • 7: %04x encoded 16 bit data (as with QByteArray::toHex), double quotes are added.
  • putStringValue(self, value) - Encodes a QString and calls putValue with the correct encoding setting.
  • putByteArrayValue(self, value) - Encodes a QByteArray and calls putValue with the correct encoding setting.
  • isExpanded() - Checks whether the current item is expanded in the view.
  • putIntItem(self, name, value) - Equivalent to:
            with SubItem(self, name):
                self.putValue(value)
                self.putAddress(value.address)
                self.putType("int")
                self.putNumChild(0)
  • putBoolItem(self, name, value) - Equivalent to:
            with SubItem(self, name):
                self.putValue(value)
                self.putType("bool")
                self.putNumChild(0)
  • putCallItem(self, name, value, func, *args) - Uses GDB to call the function func on the value specified by value and output the resulting item. Use putCallItem only if there is no other way to access the data. Calls cannot be executed when inspecting a core file, they are expensive to execute and have the potential to change the state of the debugged program.
  • putArrayData(self, type, address, size) - Creates size children of type type of an array-like object located at address.
  • putItem(self, value) - The "master function", handling basic types, references, pointers and enums directly, iterates over base classes and class members of compound types and calls qdump__* functions whenever appropriate.
  • putSubItem(self, component, value) - Equivalent to:
            with SubItem(self, component):
                self.putItem(value)

    Exceptions raised by nested function calls are caught and all output produced by putItem is replaced by the output of:

           except RuntimeError:
                d.put('value="<invalid>",type="<unknown>",numchild="0",')

Children and SubItem Class

The attempt to create child items might lead to errors if data is uninitialized or corrupted. To gracefully recover in such situations, use Children and SubItem Context Managers to create the nested items.

The Children constructor __init__(self, dumper, numChild = 1, childType = None, childNumChild = None, maxNumChild = None, addrBase = None, addrStep = None) uses one mandatory argument and several optional arguments. The mandatory argument refers to the current Dumper object. The optional arguments can be used to specify the number numChild of children, with type childType_ and childNumChild_ grandchildren each. If maxNumChild is specified, only that many children are displayed. This should be used when dumping container contents that might take overly long otherwise. The parameters addrBase and addrStep can be used to reduce the amount of data produced by the child dumpers. Address printing for the nth child item will be suppressed if its address equals with addrBase + n * addrStep.

Example:

d.putNumChild(2)  # Annouce children to make the item expandable in the view.
if d.isExpanded():
    with Children(d):
        with SubItem(d):
            d.putName("key")
            d.putItem(key)
        with SubItem(d):
            d.putName("value")
            d.putItem(value)

Note that this can be written more conveniently as:

d.putNumChild(2)
if d.isExpanded():
    with Children(d):
        d.putSubItem("key", key)
        d.putSubItem("value", value)

© 2015 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.