调试:使用 gdb 单步执行 Python 脚本?
问题描述
假设我们有以下超级简单的 Python 脚本:
Let's say we have the following mega-simple Python script:
print "Initializing"....
a=10
print "Variable value is %d" % (a)
print "All done!"
...然后说,我想通过在 a=10
行放置一个断点来调试此脚本,然后单步执行该脚本.
... and say, I'd like to debug this script by placing a breakpoint at line a=10
, and then stepping through the script.
现在,我想为此使用 gdb
,因为我想调试可能作为共享对象(.so
) 库 - 因此,理想情况下,我会在 Python 代码行上放置一个断点,然后进入"共享对象的 C 部分...(请注意,DebuggingWithGdb - PythonInfo Wiki 并没有明确说明这是可能的)
Now, I'd like to use gdb
for this, because I'd like to debug Python bindings that may come as a part of a shared object (.so
) library - hence, I'd ideally place a breakpoint on a Python code line, and then "step into" the C part of the shared object... (Note that DebuggingWithGdb - PythonInfo Wiki doesn't really explicitly state that this is possible)
问题是:gdb
本身无法真正识别断点,放置在 Python 脚本行:
The problem is: gdb
on its own cannot really recognize breakpoints, placed on a Python script line:
$ gdb python
GNU gdb (GDB) 7.3.50.20110806-cvs
...
Reading symbols from /usr/bin/python...(no debugging symbols found)...done.
(gdb) b test.py:3
No symbol table is loaded. Use the "file" command.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (test.py:3) pending.
(gdb) run test.py
Starting program: /usr/bin/python test.py
...
...虽然整个 Python 脚本确实在 gdb
中运行,但根本无法到达断点.
... and while the entire Python script does run within gdb
, the breakpoint is simply never reached.
所以 - 是我想要做的,完全可能使用 gdb
;如果没有,对于类似的东西,我还有什么其他选择?
So - is what I want to do, at all possible with gdb
; and if not, what other alternatives would I have for something similar?
解决方案
非常有趣的问题.这是我的方法.创建signal_test.py
:
Very interesting question. Here's my approach. Create signal_test.py
:
import os
import signal
PID = os.getpid()
def do_nothing(*args):
pass
def foo():
print "Initializing..."
a=10
os.kill(PID, signal.SIGUSR1)
print "Variable value is %d" % (a)
print "All done!"
signal.signal(signal.SIGUSR1, do_nothing)
foo()
然后就可以在gdb下运行了:
Then you can run it under gdb:
$ gdb --args python signal_test.py
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-37.el5_7.1)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /net/gs/vol3/software/modules-sw/python/2.7/Linux/RHEL5/x86_64/bin/python...done.
当你运行它时,它会一直运行到你调用 kill()
:
And when you run it, it will go until you reach the call to kill()
:
(gdb) run
Starting program: /net/gs/vol3/software/modules-sw/python/2.7/Linux/RHEL5/x86_64/bin/python signal_test.py
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000
[Thread debugging using libthread_db enabled]
Initializing...
Program received signal SIGUSR1, User defined signal 1.
0x0000003d340306f7 in kill () from /lib64/libc.so.6
然后您可以查看回溯:
(gdb) backtrace
#0 0x0000003d340306f7 in kill () from /lib64/libc.so.6
#1 0x00000000004d82dd in posix_kill (self=<value optimized out>, args=<value optimized out>)
at ./Modules/posixmodule.c:4047
#2 0x000000000049b574 in call_function (f=0x8aca30, throwflag=<value optimized out>)
at Python/ceval.c:4012
#3 PyEval_EvalFrameEx (f=0x8aca30, throwflag=<value optimized out>) at Python/ceval.c:2665
#4 0x000000000049c5cd in call_function (f=0x8ac560, throwflag=<value optimized out>)
at Python/ceval.c:4098
#5 PyEval_EvalFrameEx (f=0x8ac560, throwflag=<value optimized out>) at Python/ceval.c:2665
#6 0x000000000049d3bb in PyEval_EvalCodeEx (co=0x2aaaae224f30, globals=<value optimized out>,
locals=<value optimized out>, args=0x0, argcount=0, kws=0x0, kwcount=0, defs=0x0, defcount=0,
closure=0x0) at Python/ceval.c:3252
#7 0x000000000049d432 in PyEval_EvalCode (co=0x1a48, globals=0xa, locals=0x0) at Python/ceval.c:666
#8 0x00000000004bf321 in run_mod (fp=0x89ad60, filename=0x7fffffffb5b4 "signal_test.py",
start=<value optimized out>, globals=0x7e4680, locals=0x7e4680, closeit=1, flags=0x7fffffffaee0)
at Python/pythonrun.c:1346
#9 PyRun_FileExFlags (fp=0x89ad60, filename=0x7fffffffb5b4 "signal_test.py",
start=<value optimized out>, globals=0x7e4680, locals=0x7e4680, closeit=1, flags=0x7fffffffaee0)
at Python/pythonrun.c:1332
#10 0x00000000004bf5d8 in PyRun_SimpleFileExFlags (fp=<value optimized out>,
filename=0x7fffffffb5b4 "signal_test.py", closeit=1, flags=0x7fffffffaee0)
at Python/pythonrun.c:936
#11 0x00000000004148cc in Py_Main (argc=<value optimized out>, argv=<value optimized out>)
at Modules/main.c:599
#12 0x0000003d3401d994 in __libc_start_main () from /lib64/libc.so.6
#13 0x0000000000413b19 in _start ()
如果继续,程序的其余部分将正常运行.
If you continue on, the rest of the program will run normally.
(gdb) continue
Continuing.
Variable value is 10
All done!
Program exited normally.
相反,您可以在适当的框架中单步执行,直到找到您感兴趣的语句.您可能需要运行一个调试 Python 以使其更有意义.
You can, instead, step through in the appropriate frame until you reach the statement you're interested in. You're probably going to want to run a debugging Python for this to make much sense.
相关文章