【问题标题】:How to read attributes of a python object with __slots__ in gdb如何在 gdb 中使用 __slots__ 读取 python 对象的属性
【发布时间】:2019-05-31 00:04:19
【问题描述】:

我有一个要检查的 Python 进程的核心转储。特别是,我对特定 Decimal 实例的值感兴趣。

我已将 Python 扩展加载到 gdb,特别是我正在使用 libpython.py distributed with Python 2.7。这提供了从 gdb 中对 Python 语言状态的某种程度的检查。值得注意的是,检查是基于为来自下级进程的对象重新创建一个“代理对象”,而这些代理对象是通过复制被检查对象的__dict__ 创建的。

不幸的是,带有__slots__ 的类的实例没有__dict__,因此.get_attr_dict() 返回None,因此Decimal 实例的属性似乎不费吹灰之力就可以检查。

此外,由于这是核心转储而不是实时进程,我不能简单地调用PyObject_GenericGetAttr。看来我唯一的选择是在 gdb 中手动遍历结构,直到获得值。

如何完成这样的人工检查?

【问题讨论】:

    标签: python gdb


    【解决方案1】:

    从要检查的一些值开始。对于此示例,我们将查看 self._int。首先获取self 的地址,并将其保存到一个便利变量中:

    (gdb) py-locals
    self = <Decimal at remote 0x7f2d6cbc0280>
    [...]
    (gdb) set $self = (PyObject*)0x7f2d6cbc0280
    

    插槽属性被实现为descriptors_int 属性的描述符存储在类型的(在本例中为Decimal)字典中。幸运的是 libpython 已经打印了 python dicts,所以我们不需要手动解释字典结构,而是可以从输出中读取描述符的地址并将其保存到另一个便利变量:

    (gdb) p $self->ob_type->tp_dict
    $5 = {[...] '_int': <member_descriptor at remote 0x7f2d8e527320>, [...]}
    (gdb) set $int = (PyMemberDescrObject *)0x7f2d8e527320
    

    开槽属性存储在距离对象指针 ($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'600'

    【讨论】:

      猜你喜欢
      • 2010-10-23
      • 1970-01-01
      • 2013-01-15
      • 1970-01-01
      • 2017-11-19
      • 2017-06-13
      • 1970-01-01
      • 2021-05-07
      相关资源
      最近更新 更多