使用 PDB 調試
python -m pdb 1.py
-m 的話,就會默認斷在第一行代碼
- h(elp),會打印當前版本Pdb可用的命令,如果要查詢某個命令,可以輸入 h [command],例如:“h l” — 查看list命令
- l(ist),可以列出當前將要運行的代碼塊
(Pdb) l
497 pdb.set_trace()
498 base_data = {}
499 new_data = {}
500 try:
501 execfile(base_file_name,{},base_data)
502 -> execfile(new_file_name,{},new_data)
503 except:
504 logger.writeLog(“error! load result log error!”)
505 print “load cmp logs error!”
506 raise Exception, “load cmp logs error!”
507
>斷點設置
(Pdb)b 10 #斷點設置在本py的第10行
或(Pdb)b ots.py:20 #斷點設置到 ots.py第20行
刪除斷點(Pdb)b #查看斷點編號
(Pdb)cl 2 #刪除第2個斷點
>運行
(Pdb)n #單步運行
(Pdb)s #細點運行 也就是會下到,方法
(Pdb)c #跳到下個斷點
>查看
(Pdb)p param #查看當前 變量值
(Pdb)l #查看運行到某處代碼
(Pdb)a #查看全部棧內變量
- b(reak), 設置斷點,例如 “b 77″,就是在當前腳本的77行打上斷點,還能輸入函數名作爲參數,斷點就打到具體的函數入口,如果只敲b,會顯示現有的全部斷點
(Pdb) b 504
Breakpoint 4 at /home/jchen/regression/regressionLogCMP.py:504
- condition bpnumber [condition],設置條件斷點,下面語句就是對第4個斷點加上條件“a==3”
(Pdb) condition 4 a==3
(Pdb) b
Num Type Disp Enb Where
4 breakpoint keep yes at /home/jchen/regression/regressionLogCMP.py:504
stop only if a==3
- cl(ear),如果後面帶有參數,就是清除指定的斷點(我在Python2.4上從來沒成功過!!!);如果不帶參數就是清除所有的斷點
(Pdb) cl
Clear all breaks? y
- disable/enable,禁用/激活斷點
(Pdb) disable 3
(Pdb) b
Num Type Disp Enb Where
3 breakpoint keep no at /home/jchen/regression/regressionLogCMP.py:505
- n(ext),讓程序運行下一行,如果當前語句有一個函數調用,用n是不會進入被調用的函數體中的
- s(tep),跟n相似,但是如果當前有一個函數調用,那麼s會進入被調用的函數體中
- c(ont(inue)),讓程序正常運行,直到遇到斷點
- j(ump),讓程序跳轉到指定的行數
(Pdb) j 497
> /home/jchen/regression/regressionLogCMP.py(497)compareLog()
-> pdb.set_trace()
- a(rgs),打印當前函數的參數
(Pdb) a
_logger =
_base = ./base/MRM-8137.log
_new = ./new/MRM-8137.log
_caseid = 5550001
_toStepNum = 10
_cmpMap = {‘_bcmpbinarylog’: ‘True’, ‘_bcmpLog’: ‘True’, ‘_bcmpresp’: ‘True’}
- p,最有用的命令之一,打印某個變量
(Pdb) p _new
u’./new/MRM-8137.log’
- !,感嘆號後面跟着語句,可以直接改變某個變量
- q(uit),退出調試
使用gdb調試Python進程
準備
1. 確認你的gdb版本是>=7,gdb從版本7開始支持對Python的debug。
2.確認gdb連接的Python是所要debug的Python,否則請重新編譯gdb。
方法:
1
2
3
4
5
6
7
|
$ gdb (gdb) python > import sys >print sys.version >end 2.4.3 ( #1, Sep 21 2011, 19:55:41) [GCC 4.1.2 20080704 (Red Hat 4.1.2-51)] |
在一些追求穩定的發行版(例如CentOS),Python的版本會較低,這時都會自己編譯一個Python使用。而從源裏安裝的gdb會連接源裏Python的版本。例如在CentOS 5.4,源裏的Python是2.4.3,從源安裝的gdb也會連接到Python 2.4.3。
使用 GDB
有兩種可行的方法:
- 一開始就使用
gdb
來啓動應用 - 連接到一個已經運行的 Python 進程
在 gdb
下面啓動 Python 同樣有兩種方式:
交互式:
$ gdb python
...
(gdb) run <programname>.py <arguments>
自動:
$ gdb -ex r --args python <programname>.py <arguments>
這樣的話,它會一直運行直到退出、段錯誤、或者人爲的停止(使用 Ctrl+C
)。
如果進程已經開始運行,你可以通過 PID 來接入它:
$ gdb python <pid of running process>
調試進程
如果你的程序段錯誤了, gdb
會自動暫停程序,這樣你可以切換到 gdb
命令行來檢查狀態。你也可以人爲地使用Ctrl+C
來暫停程序運行。
查看
EasierPythonDebugging獲得 gdb
裏面的 Python 命令列表。
查看 C 調用棧
如果你在 debug 段錯誤,你最想做的可能就是查看 C 調用棧。
在 gdb
的命令行裏面,只要運行一下命令:
(gdb) bt
#0 0x0000002a95b3b705 in raise () from /lib/libc.so.6
#1 0x0000002a95b3ce8e in abort () from /lib/libc.so.6
#2 0x00000000004c164f in posix_abort (self=0x0, noargs=0x0)
at ../Modules/posixmodule.c:7158
#3 0x0000000000489fac in call_function (pp_stack=0x7fbffff110, oparg=0)
at ../Python/ceval.c:3531
#4 0x0000000000485fc2 in PyEval_EvalFrame (f=0x66ccd8)
at ../Python/ceval.c:2163
...
運氣好的話,你可以直接看到問題出現在什麼地方。如果它提供的信息不能直接幫你解決問題,你可以嘗試繼續追蹤調用棧。調式的結果取決於 debug 信息的有效程度。
查看 Python 調用棧
如果你安裝了 Python 擴展,你可以使用
(gdb) py-bt
可以獲取熟悉的 Python 源代碼。
對掛住的進程開刀
如果一個進程看上去掛住了,他可能在等待什麼東西(比如鎖、IO 等等)。也有可能在拼命的跑循環。連接上這個進程,然後檢查調用棧也許可以幫上忙。
如果進程在瘋狂循環,你可以先讓它運行一會,使用 cont
命令,然後使用 Ctrl+C
來暫停,並且打印出調用棧。
如果一些線程卡住了,下面的命令可能會幫上忙:
(gdb) info threads
Id Target Id Frame
37 Thread 0xa29feb40 (LWP 17914) "NotificationThr" 0xb7fdd424 in __kernel_vsyscall ()
36 Thread 0xa03fcb40 (LWP 17913) "python2.7" 0xb7fdd424 in __kernel_vsyscall ()
35 Thread 0xa0bfdb40 (LWP 17911) "QProcessManager" 0xb7fdd424 in __kernel_vsyscall ()
34 Thread 0xa13feb40 (LWP 17910) "python2.7" 0xb7fdd424 in __kernel_vsyscall ()
33 Thread 0xa1bffb40 (LWP 17909) "python2.7" 0xb7fdd424 in __kernel_vsyscall ()
31 Thread 0xa31ffb40 (LWP 17907) "QFileInfoGather" 0xb7fdd424 in __kernel_vsyscall ()
30 Thread 0xa3fdfb40 (LWP 17906) "QInotifyFileSys" 0xb7fdd424 in __kernel_vsyscall ()
29 Thread 0xa481cb40 (LWP 17905) "QFileInfoGather" 0xb7fdd424 in __kernel_vsyscall ()
7 Thread 0xa508db40 (LWP 17883) "QThread" 0xb7fdd424 in __kernel_vsyscall ()
6 Thread 0xa5cebb40 (LWP 17882) "python2.7" 0xb7fdd424 in __kernel_vsyscall ()
5 Thread 0xa660cb40 (LWP 17881) "python2.7" 0xb7fdd424 in __kernel_vsyscall ()
3 Thread 0xabdffb40 (LWP 17876) "gdbus" 0xb7fdd424 in __kernel_vsyscall ()
2 Thread 0xac7b7b40 (LWP 17875) "dconf worker" 0xb7fdd424 in __kernel_vsyscall ()
* 1 Thread 0xb7d876c0 (LWP 17863) "python2.7" 0xb7fdd424 in __kernel_vsyscall ()
當前運行的線程被標記爲 *
,要查看 Python 代碼運行到哪裏,使用 py-list
查看:
(gdb) py-list
2025 # Open external files with our Mac app
2026 if sys.platform == "darwin" and 'Spyder.app' in __file__:
2027 main.connect(app, SIGNAL('open_external_file(QString)'),
2028 lambda fname: main.open_external_file(fname))
2029
>2030 app.exec_()
2031 return main
2032
2033
2034 def __remove_temp_session():
2035 if osp.isfile(TEMP_SESSION_PATH):
查看所有進程的 Python 代碼位置,可以使用:
(gdb) thread apply all py-list
...
200
201 def accept(self):
>202 sock, addr = self._sock.accept()
203 return _socketobject(_sock=sock), addr
204 accept.__doc__ = _realsocket.accept.__doc__
205
206 def dup(self):
207 """dup() -> socket object
Thread 35 (Thread 0xa0bfdb40 (LWP 17911)):
Unable to locate python frame
Thread 34 (Thread 0xa13feb40 (LWP 17910)):
197 for method in _delegate_methods:
198 setattr(self, method, dummy)
199 close.__doc__ = _realsocket.close.__doc__
200
201 def accept(self):
>202 sock, addr = self._sock.accept()
203 return _socketobject(_sock=sock), addr
...
引用
- http://fedoraproject.org/wiki/Features/EasierPythonDebugging
- https://code.google.com/p/spyderlib/wiki/HowToDebugDeadlock
老系統上的 GDB
有時候你需要在老系統上面安裝 gdb
,這時候你可能需要下列信息:
GDB Macros
一些隨着 Python 發佈的 GDB 腳本可以用來調試 Python 進程。你可以把 Python 源碼裏面的 Misc/gdbinit
拷貝到~/.gdbinit
,或者從Subversion來拷貝他們。請注意你的
Python,確保使用正確的代碼版本,否則有些功能可能無法工作。
請注意有些新的 GDB 命令只有在 debug 需要的庫存在才能正常工作。
這個腳本在 Ubuntu 上面的 gcc 4.5.2 工作時,會爆出錯誤No symbol "co" in current context.
,是因爲call_function
在PyEval_EvalFrameEx 和PyEval_EvalCodeEx
之間。重新使用make "CFLAGS=-g -fno-inline -fno-strict-aliasing"
編譯 Python 可以解決這個問題。
使用 Python Stack Traces GDB 腳本
在 gdb 命令行裏,可以這樣查看 Python stack trace:
(gdb) pystack
同樣的,可以獲取一列 stack frame 的 Python 變量:
(gdb) pystackv
更多 gdbinit 裏面沒定義的有用的腳本可以在這裏找到:
http://web.archive.org/web/20070915134837/http://www.mashebali.com/?Python_GDB_macros:The_Macros