Использование помощников отладчика
Библиотека помощника отладчика с C++
При отладке Qt Creator динамически загружает вспомогательную библиотеку в вашу программу. Эта вспомогательная библиотека обеспечивает Qt Creator красивое отображение типов Qt и STL. Пакет Qt SDK уже содержит заранее скомпилированную библиотеку помощника отладчика. Чтобы создать собственную библиотеку помощника отладчика, выберите Инструменты > Параметры... > Qt4 > Профили Qt. Так как внутренние структуры данных Qt могут меняться для разных версий, библиотека помощника отладчика собирается для каждой версии Qt.
Библиотека помощника отладчика с Python
С gdb с поддержкой Python вы можете использовать помощники отладчика и для определённых пользователем типов. Чтобы сделать это, определите одну функцию на Python для каждого определённого пользователем типа в .gdbinit.
Имя функции должно быть вида qdump__NS__Foo где NS::Foo это класс или шаблон класса для просмотра. Можно использовать вложенные пространства имён.
Подключаемый модуль отладчика вызывает эту функцию для отображения объекта этого типа. Этой функции передаются следующие параметры:
- d типа Dumper
- item типа Item
Функция должна наполнить объект Dumper определённой информацией, которая будет использована для построения вида Переменные этого объекта и его потомков.
Пример:
def qdump__QVector(d, item):
d_ptr = item.value["d"]
p_ptr = item.value["p"]
alloc = d_ptr["alloc"]
size = d_ptr["size"]
check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
check(d_ptr["ref"]["_q_value"] > 0)
innerType = item.value.type.template_argument(0)
d.putItemCount(size)
d.putNumChild(size)
if d.isExpanded(item):
p = gdb.Value(p_ptr["array"]).cast(innerType.pointer())
with Children(d, [size, 2000], innerType)
for i in d.childRange():
d.putItem(Item(p.dereference(), item.iname, i))
p += 1
Класс элемента
Класс Python Item это небольшая обёртка вокруг значений, соответствующих одной строке вида Переменные. У класса Item есть следующие члены:
- __init__(self, value, parentiname, iname, name = None) - Конструктор. Внутреннее имя объекта создаётся объединением parentiname и iname. Если None передаётся в качестве аргумента для name, то используется серийный номер.
- value - объект типа gdb.Value, представляющий отображаемое значение.
- iname - внутреннее имя объекта, состоящее из разделённого точками списка идентификаторов, соответствующее положению представления в виде.
- name - Дополнительное имя. Если оно задано, то будет использовано в столбце Имя вида. Если не задано, то вместо него будет использовано простое число в скобках.
Класс Dumper
Для каждой строки в виде Переменные должна быть создана и соединена с подключаемым модулем отладки строка примерно следующего содержания.
"{iname='некоторое внутреннее имя',
addr='адрес объекта в памяти',
name='содержимое столбца Имя',
value='содержимое столбца Значение',
type='содержимое столбца Тип',
numchild='число потомков',
childtype='тип потомка по умолчанию',
childnumchild='число внуков по умолчанию',
children=[
{iname='внутреннее имя первого потомка',
... },
{iname='внутреннее имя второго потомка',
... },
...
]}"
Хотя, в принципе, вы можете собрать всю строку выше вручную, гораздо проще для этой цели использовать класс Python Dumper. Класс Python Dumper содержит полный каркас для обработки полей iname и addr, для обработки потомков простых типов, ссылок, указателей, перечислений, известных и неизвестных структур, а также некоторые вспомогательные методы для обработки общих ситуаций.
У класса Dumper есть следующие члены:
- __init__(self) - Инициализирует выход пустой строкой и очищает стек потомков.
- put(self, value) - низкоуровневый метод для прямого добавления в выходную строку.
- putCommaIfNeeded(self) - добавляет запятую если текущий выход заканчивается '}', '"' или ']' .
- putField(self, name, value) - добавляет при необходимости запятую и поле name='value'.
- beginItem(self, name) - Начинает поле с записи name='.
- endItem(self) - Заканчивает запись поля с помощью '.
- endChildren(self) - Заканчивает запись списка потомков.
- childRange(self) - Возвращает ряд потомков, указанных в текущем пространстве Children.
- putItemCount(self, count) - Добавляет в выход поле value='<%d items'.
- putEllipsis(self) - Добавляет поле '{name="<incomplete>",value="",type="",numchild="0"}'. Это автоматически делается endChildren если число потомков для вывода меньше чем текущее число потомков.
- putName(self, name) - Добавляет поле name='...'.
- putType(self, type) - Добавляет поле type='...' если type не совпадает с типом потомка родителя по умолчанию.
- putNumChild(self, numchild) - Добавляет поле numchild='...' если numchild не совпадает со значением потомка родителя numchild по умолчанию.
- putValue(self, value, encoding = None) - Добавляет поле value='...' с необязательным полем valueencoding='...'. Значение value должно быть преобразуемым в строку полностью состоящую из числовых и буквенных значений. Параметр encoding может быть использован для указания способа кодирования в случае если настоящее значение должно быть закодировано каким-либо образом для выполнения требования о содержании только числовых и буквенных значений. В настоящий момент поддерживаются следующие способы кодирования:
- 0: незашифрованные 8-ми битные данные, интерпретируемые как Latin1.
- 1: зашифрованные с помощью base64 8-ми битные данные, используемые для QByteArray, будут добавлены двойные кавычки.
- 2: зашифрованные с помощью base64 16-ти битные данные, используемые для QString, будут добавлены двойные кавычки.
- 3: зашифрованные с помощью base64 32-х битные данные, будут добавлены двойные кавычки.
- 4: зашифрованные с помощью base64 16-ти битные данные, без кавычек (смотрите 2).
- 5: зашифрованные с помощью base64 8-ми битные данные, без кавычек (смотрите 1).
- 6: зашифрованные в виде %02x 8-ми битные данные (как с помощью QByteArray::toHex), будут добавлены двойные кавычки.
- 7: зашифрованные в виде %04x 16-ти битные данные (как с помощью QByteArray::toHex), будут добавлены двойные кавычки.
- putStringValue(self, value) - Кодирует QString и вызывает putValue с соответствующим способом кодирования encoding.
- putByteArrayValue(self, value) - Кодирует QByteArray и вызывает putValue с соответствующим способом кодирования encoding.
- isExpanded(self, item) - Проверяет раскрывается ли элемент с внутренним именем item.iname в виде.
- isExpandedIName(self, iname) - Проверяет раскрывается ли элемент с внутренним именем iname в виде.
- putIntItem(self, name, value) - Эквивалентно:
self.beginHash()
self.putName(name)
self.putValue(value)
self.putType("int")
self.putNumChild(0)
self.endHash()
- putBoolItem(self, name, value) - Эквивалентно:
self.beginHash()
self.putName(name)
self.putValue(value)
self.putType("bool")
self.putNumChild(0)
self.endHash()
- pushOutput(self) - Перемещает выходную строку в безопасное место, откуда она будет отправлена подключаемому модулю отладчика даже если дальнейшие операции вызовут исключение.
- putCallItem(self, name, item, func) - Использует gdb для вызова функции func для значения, указанного в item.value, и выводит результат. Эта функция не доступна при отладке дампов ядра и не доступна для платформы Symbian из-за ограничений, накладываемых AppTRK.
- putItemHelper(self, item) - "Главная функция", сразу обрабатывающая базовые типы, ссылки, указатели и перечисления, проход по всем потомкам и членам классов составных типов и вызов подходящих функций qdump__*.
- putItem(self, item) - Эквивалентно:
with SubItem(self):
self.putItemHelper(item)
Возникающие в последующих вызовах функций исключения ловятся, а весь вывод putItemHelper заменяется выводом:
...
except RuntimeError:
d.put('value="<invalid>",type="<unknown>",numchild="0",')
Класс потомков и подэлементов
Попытка создать дочерние элементы может привести к ошибкам если данные не инициализированы или повреждены. Для успешного восстановления в таких ситуациях используйте Children и SubItem для создания вложенных элементов.
Конструктор Children __init__(self, dumper, numChild = 1, childType = None, childNumChild = None) использует один обязательный и три необязательных аргумента. Обязательный аргумент ссылается на текущий объект Dumper. Необязательные аргументы могут быть использованы для указания числа потомков numChild с типом childType_ числом потомков childNumChild_ у каждого. Если numChild_ это список из двух целых чисел, то первое будет указывать текущее число потомков, а второе - максимальное число потомков для вывода.
Аналогично, использование класса SubItem
помогает защитить отдельные элементы.
Пример:
d.putNumChild(2)
if d.isExpanded(item):
with Children(d):
with SubItem(d):
d.putName("key")
d.putItemHelper(Item(key, item.iname, "key"))
with SubItem(d):
d.putName("value")
d.putItemHelper(Item(value, item.iname, "value"))