Начните с некоторого значения для проверки.Для этого примера мы рассмотрим self._int
.Начните с получения адреса self
и сохранения его в вспомогательной переменной:
(gdb) py-locals
self = <Decimal at remote 0x7f2d6cbc0280>
[...]
(gdb) set $self = (PyObject*)0x7f2d6cbc0280
Временные атрибуты реализованы как дескрипторы , а дескриптор для атрибута _int
имеет видхранится в словаре типов (в данном случае Decimal
).К счастью, libpython уже печатает python dicts, поэтому нам не нужно вручную интерпретировать структуру словаря, мы можем просто прочитать адрес дескриптора из выходных данных и сохранить его в другой вспомогательной переменной:
(gdb) p $self->ob_type->tp_dict
$5 = {[...] '_int': <member_descriptor at remote 0x7f2d8e527320>, [...]}
(gdb) set $int = (PyMemberDescrObject *)0x7f2d8e527320
Slotted attributeхранятся с некоторым смещением от указателя объекта ($self
), и мы можем получить это смещение следующим образом:
(gdb) p *$int->d_member
$9 = {name = 0x7f2d931d3774 "_int", type = 16, offset = 24, flags = 0, doc = 0x0}
Чтобы интерпретировать значение, мы также должны принять к сведению тип.Реализация PyMember_GetOne
показывает, как значение должно быть приведено в соответствии с типом, и мы можем видеть в structmember.h , что тип 16 сверху соответствует T_OBJECT_EX
.Теперь мы добавляем offset
из дескриптора к $self
, приводим его соответствующим образом и печатаем результат:
(gdb) p *(PyObject**)((char *)$self+24)
$14 = '600'
И вот у вас это есть: self._int
is '600'
.