我正在运行python 3.6.6-debug(通过pyenv安装),并且已将关联的libpython.py从cpython/Tools/gdb/libpython.py
复制到~/.config/gdb
(已检出v3.6.6标记)
在我的.gdbinit中,我有:
source ~/.config/gdb/libpython.py
对于简单的过程,我可以使用py-list
,py-bt
等,但是目前在py.test下测试的程序为所有python gdb helper命令提供了此错误:
(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对象没有目标 。根据{{3}}:
—功能:Type.target()
返回一个新的gdb.Type对象,该对象表示此类型的目标类型。
对于指针类型,目标类型是指向对象的类型。对于数组类型(意味着类似C的数组),目标类型是数组元素的类型。对于函数或方法类型,目标类型是返回值的类型。对于复杂类型,目标类型是元素的类型。对于typedef,目标类型是别名类型。
如果类型没有目标,则此方法将引发异常。
这肯定看起来像是个错误,尽管在网上,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的交互式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
毕竟,对于上述选项,我偶然发现了。设置默认情况下会打开堆栈跟踪打印,这将避免进行所有手动调试的需要。因此,事后看来,我做了 lot 不需要的额外工作:) (尽管我在此过程中学到了很多东西。)
我现在将其添加到我的gdbinit中,以备将来使用。
答案 0 :(得分:3)
我遇到了同样的问题,尝试过并简单地更改了线路
fields = gdb.lookup_type('PyUnicodeObject')。target()。fields()
到
fields = gdb.lookup_type('PyUnicodeObject')。fields()
然后它起作用。