Как читать атрибуты объекта Python с __slots__ в GDB - PullRequest
1 голос
/ 31 мая 2019

У меня есть дамп ядра процесса Python, который я пытаюсь проверить.В частности, меня интересует значение конкретного Decimal экземпляра.

Я загрузил расширения Python в gdb, в частности, я использую libpython.py, распространяемый с Python 2.7..И это обеспечивает некоторую степень проверки состояния языка Python внутри GDB.В частности, проверка основана на воссоздании «прокси-объекта» для объектов из подчиненного процесса, и эти прокси-объекты создаются путем копирования __dict__ проверяемого объекта.

К сожалению, экземпляры классас __slots__ не имеют __dict__, и поэтому .get_attr_dict() возвращает None, и, таким образом, атрибуты экземпляра Decimal не кажутся проверяемыми без каких-либо усилий.

Кроме того, поскольку это дамп ядра, а не живой процесс, я не могу просто позвонить PyObject_GenericGetAttr.Кажется, мой единственный вариант - обходить структуры вручную в GDB до тех пор, пока я не достигну значения.

Как можно выполнить такую ​​ручную проверку?

1 Ответ

0 голосов
/ 03 июня 2019

Начните с некоторого значения для проверки.Для этого примера мы рассмотрим 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'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...