Как вызвать конструктор в gdb для pretty-printers - PullRequest
8 голосов
/ 15 августа 2011

При отладке с помощью GDB я хотел бы установить вспомогательную переменную для вновь созданного значения.

Я программирую с использованием фреймворка Qt, поэтому я хотел бы создать QString, но это не имеет отношения к вопросу, поскольку я хотел бы знать, как это сделать с любым классом.

Я пытался

(gdb) set $str = 'QString::QString("abc")'
No symbol "QString::QString("abc")" in current context.

(gdb) set $str = QString::QString("abc")
Cannot resolve method QString::QString to any overloaded instance

(gdb) set $str = QString("abc")
A syntax error in expression, near `("abc")'.

затем я попытался использовать set overload-resolution off, что привело к следующему:

set $str = QString::QString("abc")
non-unique member `QString' requires type instantiation

set $str = 'QString::QString(const char*)'("abc")
Too few arguments in function call.

Итак, я предположил, что нужен этот указатель:

(gdb) set $str = 'QString::QString(const char*)'(malloc(sizeof(QString)), "abc")
(gdb) p $str
$8 = void

Хорошо, конструкторы возвращают void, это означает, что мне нужно где-то сохранить возвращаемое значение malloc:

(gdb) set $pointer = malloc(sizeof(QString))
(gdb) p $pointer
$9 = 6304560
(gdb) p/x $pointer
$10 = 0x603330
(gdb) set $str = 'QString::QString(const char*)'($pointer, "abc")
(gdb) p $str
$11 = void
(gdb) p $pointer
$12 = 6304560
(gdb) p *((QString*)$pointer)
$13 = "abc"

Хорошо, теперь это работает, как и ожидалось, однако я хочу использовать этот код в gdb.parse_and_eval () для симпатичного принтера на python. Теперь это будет вызывать malloc много раз, создавая утечку памяти. Так что просто позвоните бесплатно ()? Теперь происходит нечто неожиданное:

(gdb) call free($pointer)
$14 = 0
(gdb) p *((QString*)$pointer)
$15 = "abc"

Указатель все еще кажется действительным, что, конечно, может быть совершенно нормально, поскольку память не использовалась повторно. Однако я не уверен, что это нормально, потому что после выделения еще нескольких блоков памяти, которые вписываются ровно в одну строку QString, значение указателя все еще не используется malloc.

Создаю ли я большую утечку памяти, если использую ее в симпатичном принтере, которую можно часто вызывать во время сеанса отладки? Есть ли более простое решение для создания желаемого результата (т. Е. С помощью Python API)?

Также не имеет отношения к этому, почему free (3) возвращает мне значение 0, в то время как оно фактически аннулировано?

Ответы [ 2 ]

1 голос
/ 31 марта 2015

Я не знаю, как освободить указатель. Это кажется невозможным, но созданная утечка памяти должна быть довольно маленькой. Но я знаю, как убрать эффект, который вы описали как

Указатель все еще кажется действительным, что, конечно, может быть совершенно нормально, поскольку память не использовалась повторно. Однако я не уверен, все ли в порядке, потому что после выделения еще нескольких блоков памяти, вмещающих ровно одну строку QString, значение указателя все еще не используется malloc.

См. Этот код, который должен показать, как можно решить проблему (проверено только на GNU GDB (GDB) SUSE (7.5.1-2.1.1))

(gdb) call malloc(sizeof(std::string))
$1 = (void *) 0x64e4d0
(gdb) call ((std::string*)0x64e4d0)->basic_string()
(gdb) call ((std::string*)0x64e4d0)->assign("Hello World")
$2 = "Hello World"
(gdb) call ((std::string*)0x64e4d0)->'~basic_string'((std::string*)0x64e4d0)
warning: Using non-standard conversion to match method std::string::~basic_string to supplied arguments
(gdb) print ((std::string*)0x64e4d0)
$3 = (std::string *) 0x64e4d0
(gdb) print *((std::string*)0x64e4d0)
$4 = ""
(gdb) call free(0x64e4d0)
(gdb) print *((std::string*)0x64e4d0)
$5 = ""

Причина, по которой ваша версия не смогла освободить память, заключается в том, что ваша свободная команда должна влиять только на прямую зарезервированную память (например, указатели и основные типы, определенные классом), а не на созданный объект (имеется в виду память, зарезервированная конструктором). и методы объекта, который вы могли бы вызвать).

Нужно сначала вызвать деструктор созданного объекта, а затем освободить указатель (строка ниже $ 2 в моем коде).

Поскольку последние строки ($ 5) моего кода подразумевают, что симпатичный принтер gdb способен восстановить содержимое объекта, даже когда память объекта больше не занята процессом. Причина может заключаться в том, что принтер мог делать это почти с каждым адресом памяти, и когда никакой другой процесс не записал что-то в это место (что мы занимали несколько секунд назад), мы получили бы те же результаты, что и когда не вызывался free.

PS: формат деструктора и предупреждение должны показать вам, что немного сложно найти правильное выражение деструктора. У меня нет реального QT-проекта, чтобы попробовать это с QString, но он должен быть совсем рядом с тем, что я сделал.

1 голос
/ 20 августа 2011

Что вы пытаетесь сделать? Если вы хотите красиво распечатать QString с помощью gdb, используйте API-интерфейс симпатичного принтера gthon для Python. Подробнее см. http://sourceware.org/gdb/onlinedocs/gdb/Pretty-Printing.html. Вы можете использовать класс принтера Python, как показано ниже:

class QStringPrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        if self.val['d'] == self.val['shared_null'].address:
            return 0

        dataptr = self.val['d']['data'].cast(gdb.lookup_type('char').pointer())
        size = self.val['d']['size']

        if sys.byteorder == 'little':
            enc = 'utf_16_le'
        else:
            enc = 'utf_16_be'
        return dataptr.string(enc, 'ignore', size * 2)

    def display_hint(self):
        return 'string'
...