Как вызвать конструктор в gdb для симпатичных принтеров

При отладке с помощью 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 повторно.

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

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


person ar31    schedule 14.08.2011    source источник


Ответы (2)


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

Указатель все еще кажется действительным, что, конечно, может быть совершенно нормально, поскольку память не использовалась повторно. Однако я не уверен, что это нормально, потому что после выделения еще нескольких блоков памяти, которые соответствуют ровно одной 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, но он должен быть очень близок к тому, что я сделал.

person msebas    schedule 31.03.2015

Что ты пытаешься сделать? Если вы хотите красиво напечатать QString с помощью gdb, используйте API-интерфейс gdb для печати 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'
person emkey08    schedule 20.08.2011