python-gdb 错误 : Python Exception <class 'RuntimeError' > Type does not have a target

标签 python python-3.x debugging gdb gdb-python

我正在运行 python 3.6.6-debug(通过 pyenv 安装)并且我已经从 cpython/Tools/gdb/libpython.py 复制了相关的 libpython.py至 ~/.config/gdb ( checkout v3.6.6 标签)。

在我的 .gdbinit 中我有:

source ~/.config/gdb/libpython.py

对于简单的流程,我可以使用 py-list , py-bt等没有问题,但是我目前正在 py.test 下测试的程序为任何 python gdb 帮助程序命令提供了这个错误:

(gdb) py-list
Python Exception <class 'RuntimeError'> Type does not have a target.:
Error occurred in Python command: Type does not have a target.

这个错误是什么意思,我该如何解决?

更新

我深入研究了 libpython.py 以了解 py-list 到底是如何工作的/py-bt做他们的事情,然后从 gdb 中手动运行相关的 gdb python 命令以重现问题并准确隔离 libpython.py 中发生问题的位置。在进行了下面的调试之后,我能够在 gdb 中获得更详细的回溯:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "~/git/cpython/Tools/gdb/libpython.py", line 916, in filename
  File "~/git/cpython/Tools/gdb/libpython.py", line 1158, in proxyval
RuntimeError: Type does not have a target.

问题是在 libpython.py 行 1158 触发的, 这是

fields = gdb.lookup_type('PyUnicodeObject').target().fields()

这澄清了一些事情:libpython.py 获取 PyUnicodeObject 的 Type 对象,然后尝试调用 target方法,但是 PyUnicodeObject 的 Type 对象没有目标。根据 gdb documentation :

— Function: Type.target ()

Return a new gdb.Type object which represents the target type of this type.

For a pointer type, the target type is the type of the pointed-to object. For an array type (meaning C-like arrays), the target type is the type of the elements of the array. For a function or method type, the target type is the type of the return value. For a complex type, the target type is the type of the elements. For a typedef, the target type is the aliased type.

If the type does not have a target, this method will throw an exception.

这看起来确实像一个错误,尽管我在网上、python 问题跟踪器或 python 提交历史记录中找不到任何关于此问题的提及。我将在 python 跟踪器上打开一个问题,看看维护者怎么说(除非有人之前遇到过这个问题并提交了答案)。

我是如何调试的

配置ptrace允许在没有 sudo 的情况下进行调试

$ sudo sh -c 'echo 0 > /proc/sys/kernel/yama/ptrace_scope

判断挂起(多进程)程序的父python进程

$ pstree -p -s 22391
systemd(1)───tmux(31719)───bash(5161)───py.test(22391)─┬─py.test(22478)
                                                       ├─py.test(24577)
                                                       ├─py.test(24578)
                                                       ├─python3.6(25427)
                                                       ├─python3.6(25545)
                                                       ├─python3.6(25546)
                                                       ├─python3.6(25547)
                                                       ├─python3.6(27376)───{python3.6}(27393)
                                                       ├─python3.6(30563)───{python3.6}(30580)
                                                       ├─{py.test}(27368)
                                                       ├─{py.test}(30562)
                                                       ├─{py.test}(629)
                                                       └─{py.test}(630)

(我只是在上面猜对了,对我的程序使用任何正在运行的 python 进程的 pid 都可以)

附加到父进程

$ gdb -p 22391

确定最近的python执行帧并切换到它

(gdb) bt 10
#0  0x00007fec7309a5d3 in select () at ../sysdeps/unix/syscall-template.S:84
#1  0x00007fec738692aa in pysleep (secs=50000000) at ./Modules/timemodule.c:1417
#2  0x00007fec738671a3 in time_sleep (self=0x7fec71a00458, obj=0x7fec6cf728b0) at ./Modules/timemodule.c:235
#3  0x00007fec7368513e in _PyCFunction_FastCallDict (func_obj=0x7fec719ff5f8, args=0x7fec406fac08, nargs=1, kwargs=0x0) at Objects/methodobject.c:209
#4  0x00007fec73685535 in _PyCFunction_FastCallKeywords (func=0x7fec719ff5f8, stack=0x7fec406fac08, nargs=1, kwnames=0x0) at Objects/methodobject.c:294
#5  0x00007fec7379ab0d in call_function (pp_stack=0x7ffc37032440, oparg=1, kwnames=0x0) at Python/ceval.c:4830
#6  0x00007fec737927ca in _PyEval_EvalFrameDefault (f=0x7fec406faa58, throwflag=0) at Python/ceval.c:3328
===> #7  0x00007fec7377eb3b in PyEval_EvalFrameEx (f=0x7fec406faa58, throwflag=0) at Python/ceval.c:754
#8  0x00007fec7363a208 in gen_send_ex (gen=0x7fec3d0b88d8, arg=0x0, exc=0, closing=0) at Objects/genobject.c:189
#9  0x00007fec7363bca6 in gen_iternext (gen=0x7fec3d0b88d8) at Objects/genobject.c:563
(More stack frames follow...)
(gdb) frame 7
#7  0x00007fec7377eb3b in PyEval_EvalFrameEx (f=0x7fec406faa58, throwflag=0) at Python/ceval.c:754
754     Python/ceval.c: No such file or directory.

添加python源目录并使用tui enable获取一些上下文

(gdb) dir ~/git/cpython
Source directories searched: /home/calid/git/cpython:$cdir:$cwd
(gdb) tui enable

gdb tui screenshot

启动gdb的交互式python解释器,手动输入libpython行获取当前python脚本/行号

(gdb) pi
>>> gdbframe = gdb.selected_frame()
>>> f = gdbframe.read_var('f')
>>> pyframe = PyFrameObjectPtr.from_pyobject_ptr(f)
>>> pyframe.filename()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "~/git/cpython/Tools/gdb/libpython.py", line 916, in filename
  File "~/git/cpython/Tools/gdb/libpython.py", line 1158, in proxyval
RuntimeError: Type does not have a target.

这重现了我在 py-list 中看到的异常和 py-bt , 但这次我也得到了一个非常有用的回溯。

默认开启 gdb python 堆栈跟踪

set python print-stack full

毕竟我偶然发现了documentation对于上面的选项。默认情况下打开堆栈跟踪打印的设置可以避免进行所有手动调试的需要......所以事后看来,我做了很多我不需要做的额外工作:) (虽然我在这个过程中确实学到了很多)。

我现在已将其添加到我的 gdbinit 中以备将来使用。

资源

最佳答案

我遇到了同样的问题,试过并简单地改变了线路

fields = gdb.lookup_type('PyUnicodeObject').target().fields()

fields = gdb.lookup_type('PyUnicodeObject').fields()

然后就可以了。

关于python-gdb 错误 : Python Exception <class 'RuntimeError' > Type does not have a target,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53084290/

相关文章:

debugging - 关闭调试堆有哪些负面后果? (_NO_DEBUG_HEAP==1)

没有堆栈跟踪的 Android "Shutting down VM"

python - 我如何在 numpy 中向量化这个 for 循环?

python-3.x - 提供随机种子时不起作用,并且某些函数不接受种子参数

python - urllib3 中没有默认密码属性?

python-3.x - 自动将旧的字符串格式设置样式转换为f字符串

list - 有极限的序列

python selenium 3.0 - 未识别安装在默认位置的 Firefox 47.0.1。 (壁虎司机)

python - Beautifulsoup soup.body 返回 None

Python 列表和字典理解