如何在gdb

时间:2019-05-31 00:04:20

标签: python gdb

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

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

不幸的是,具有__slots__的类的实例没有__dict__,因此.get_attr_dict()返回None,因此Decimal实例的属性似乎没有无需费力即可检查。

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

如何完成这种手动检查?

1 个答案:

答案 0 :(得分:0)

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

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

带槽的属性实现为descriptors,并且_int属性的描述符存储在类型(在这种情况下为Decimal)字典中。幸运的是,libpython已经输出了python字典,因此我们不需要手动解释字典结构,而只需从输出中读取描述符的地址并将其保存到另一个便利变量中即可:

(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'