While the primary intention of this pretty printing implementation is to provide what Qt Creator needs, it can be used in a plain commandline GDB session, too. With python sys.path.insert(1, '/share/qtcreator/debugger/') python from gdbbridge import * in .gdbinit there is a new "GDB command", called "pp". With code like int main(int argc, char *argv[]) { QString ss = "Hello"; QApplication app(argc, argv); app.setObjectName(ss); // break here } the "pp" command can be used as follows: (gdb) pp app app = [ = {"Hello"} staticMetaObject = = {""} [parent] = = {"0x0"} [children] = = {"<3 items>"} [properties] = "<>0 items>" [methods] = "<6 items>" [signals] = "<1 items>" ], = {"Hello"} (gdb) pp app [properties],[children] app = [ = {"Hello"} staticMetaObject = = {""} [parent] = = {"0x0"} [children] = [ = {""} = {""} = {"fusion"} ], = {"<3 items>"} [properties] = [ windowIcon = = {""} cursorFlashTime = = {"1000"} doubleClickInterval = = {"400"} keyboardInputInterval = = {"400"} wheelScrollLines = = {"3"} globalStrut = = {"(0, 0)"} startDragTime = = {"500"} startDragDistance = = {"10"} styleSheet = = {""} autoSipEnabled = = {"true"} ],"<10 items>" [methods] = "<6 items>" [signals] = "<1 items>" ], = {"Hello"} (gdb) pp ss ss = = {"Hello"} In order to hook a new debugger backend into this "common pretty printing system", the backend should expose a Python API containing at least the following: class Value: name() -> string # Name of this thing or None type() -> Type # Type of this value asBytes() -> bytes # Memory contents of this object, or None address() -> int # Address of this object, or None dereference() -> Value # Dereference if value is pointer, # remove reference if value is reference. hasChildren() -> bool # Whether this object has subobjects. expand() -> bool # Make sure that children are accessible. nativeDebuggerValue() -> string # Dumper value returned from the debugger childFromName(string name) -> Value # (optional) childFromField(Field field) -> Value # (optional) childFromIndex(int position) -> Value # (optional) class Type: name() -> string # Full name of this type bitsize() -> int # Size of type in bits code() -> TypeCodeTypedef | TypeCodeStruct | TypeCodeVoid | TypeCodeIntegral | TypeCodeFloat | TypeCodeEnum | TypeCodePointer | TypeCodeArray | TypeCodeComplex | TypeCodeReference | TypeCodeFunction | TypeCodeMemberPointer | TypeCodeUnresolvable unqualified() -> Type # Type without const/volatile target() -> Type # Type dereferenced if it is a pointer type, element if array etc stripTypedef() -> Type # Type with typedefs removed fields() -> [ Fields ] # List of fields (member and base classes) of this type templateArgument(int pos, bool numeric) -> Type or int # (optional) class Field: name() -> string # Name of member, None for anonymous items isBaseClass() -> bool # Whether this is a base class or normal member type() -> Type # Type of this member parentType() -> Type # Type of class this member belongs to bitsize() -> int # Size of member in bits bitpos() -> int # Offset of member in parent type in bits parseAndEvaluate(string: expr) -> Value # or None if not possible. lookupType(string: name) -> Type # or None if not possible. listOfLocals() -> [ Value ] # List of items currently in scope. readRawMemory(ULONG64 address, ULONG size) -> bytes # Read a block of data from the virtual address space