相关文章推荐

设置 /proc/sys/kernel/yama/ptrace_scope:

$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

运行 test.py:

$ python test.py & [ 1 ] 6489

通过 gdb python PID 来调试运行中的进程:

$ gdb python 6489 GNU gdb ( Ubuntu 7 .11.1-0ubuntu1~16.04 ) 7 .11.1 For help, type "help" . Type "apropos word" to search for commands related to "word" ... Reading symbols from python...Reading symbols from /usr/lib/debug/.build-id/90/d1300febaeb0a626baa2540d19df2416cd3361.debug...done. done . Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug//lib/i386-linux-gnu/ld-2.23.so...done. done . 0xb778fc31 in __kernel_vsyscall () ( gdb )

生成 core file

为了不影响运行中的进程,可以通过生成 core file 的方式来保存进程的当前信息:

( gdb ) generate-core-file warning: target file /proc/6489/cmdline contained unexpected null characters Saved corefile core.6489 ( gdb ) quit A debugging session is active. Inferior 1 [ process 6489 ] will be detached. Quit anyway? ( y or n ) y

可以通过 gdb python core.PID 的方式来读取 core file:

$ gdb python core.6489 GNU gdb ( Ubuntu 7 .11.1-0ubuntu1~16.04 ) 7 .11.1 Type "apropos word" to search for commands related to "word" ... Reading symbols from python...Reading symbols from /usr/lib/debug/.build-id/90/d1300febaeb0a626baa2540d19df2416cd3361.debug...done. done . warning: core file may not match specified executable file. [ New LWP 6489 ] [ Thread debugging using libthread_db enabled ] Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1" . Core was generated by ` python ' . #0 0xb778fc31 in __kernel_vsyscall () ( gdb )

可用的 python 相关的命令

可以通过输入 py 然后加 tab 键的方式来查看可用的命令:

( gdb ) py py-bt py-down py-locals py-up python-interactive py-bt-full py-list py-print python

可以通过 help cmd 查看各个命令的说明:

( gdb ) help py-bt Display the current python frame and all the frames within its call stack ( if any )

当前执行位置的源码

( gdb ) py-list 1 # -*- coding: utf-8 -*- 2 import time 5 def do ( x ) : >6 time.sleep ( 10 ) 9 def main () : 10 for x in range ( 10000 ) : 11 do ( x ) ( gdb )

可以看到当前正在执行 time.sleep(10)

当前位置的调用栈

( gdb ) py-bt Traceback ( most recent call first ) : <built-in function sleep> File "test.py" , line 6 , in do time.sleep ( 10 ) File "test.py" , line 11 , in main do ( x ) File "test.py" , line 15 , in <module> main () ( gdb )

可以看出来是 main() -> do(x) -> time.sleep(10)

查看变量的值

( gdb ) py-list 1 # -*- coding: utf-8 -*- 2 import time 5 def do ( x ) : >6 time.sleep ( 10 ) 9 def main () : 10 for x in range ( 10000 ) : 11 do ( x ) ( gdb ) py-print x local 'x' = 12 ( gdb ) ( gdb ) py-locals x = 12 ( gdb )

查看上层调用方的信息

( gdb ) py-up #9 Frame 0xb74c0994, for file test.py, line 11, in main (x=12) do ( x ) ( gdb ) py-list 6 time.sleep ( 10 ) 9 def main () : 10 for x in range ( 10000 ) : >11 do ( x ) 14 if __name__ == '__main__' : 15 main () ( gdb ) py-print x local 'x' = 12 ( gdb )

可以通过 py-down 回去:

( gdb ) py-down #6 Frame 0xb74926e4, for file test.py, line 6, in do (x=12) time.sleep ( 10 ) ( gdb ) py-list 1 # -*- coding: utf-8 -*- 2 import time 5 def do ( x ) : >6 time.sleep ( 10 ) 9 def main () : 10 for x in range ( 10000 ) : 11 do ( x ) ( gdb )

调试多线程程序

测试程序 test2.py:

# -*- coding: utf-8 -*-
from threading import Thread
import time
def do(x):
    x = x * 3
    time.sleep(x * 60)
def main():
    threads = []
    for x in range(1, 3):
        t = Thread(target=do, args=(x,))
        t.start()
    for x in threads:
        x.join()
if __name__ == '__main__':
    main()
$ python test2.py &
[2] 12281

查看所有线程

info threads

$ gdb python core.12281 (gdb) info threads Id Target Id Frame * 1 Thread 0xb74b9700 (LWP 11039) 0xb7711c31 in __kernel_vsyscall () 2 Thread 0xb73b8b40 (LWP 11040) 0xb7711c31 in __kernel_vsyscall () 3 Thread 0xb69ffb40 (LWP 11041) 0xb7711c31 in __kernel_vsyscall () (gdb)

可以看到这个程序当前有 3 个线程, 当前进入的是 1 号线程。

切换线程

thread ID

(gdb) thread 3
[Switching to thread 3 (Thread 0xb69ffb40 (LWP 11041))]
#0  0xb7711c31 in __kernel_vsyscall ()
(gdb) info threads
  Id   Target Id         Frame
  1    Thread 0xb74b9700 (LWP 11039) 0xb7711c31 in __kernel_vsyscall ()
  2    Thread 0xb73b8b40 (LWP 11040) 0xb7711c31 in __kernel_vsyscall ()
* 3    Thread 0xb69ffb40 (LWP 11041) 0xb7711c31 in __kernel_vsyscall ()
(gdb)

现在切换到了 3 号线程。

可以通过前面所说的 py- 命令来查看当前线程的其他信息:

[Current thread is 1 (Thread 0xb74b9700 (LWP 11039))]
(gdb) py-list
 335            waiter.acquire()
 336            self.__waiters.append(waiter)
 337            saved_state = self._release_save()
 338            try:    # restore state no matter what (e.g., KeyboardInterrupt)
 339                if timeout is None:
>340                    waiter.acquire()
 341                    if __debug__:
 342                        self._note("%s.wait(): got it", self)
 343                else:
 344                    # Balancing act:  We can't afford a pure busy loop, so we
 345                    # have to sleep; but if we sleep the whole timeout time,
(gdb) thread 2
[Switching to thread 2 (Thread 0xb73b8b40 (LWP 11040))]
#0  0xb7711c31 in __kernel_vsyscall ()
(gdb) py-list
   3    import time
   6    def do(x):
   7        x = x * 3
  >8        time.sleep(x * 60)
  11    def main():
  12        threads = []
  13        for x in range(1, 3):
(gdb)

同时操作所有线程

thread apply all CMDt a a CMD

(gdb) thread apply all py-list
Thread 3 (Thread 0xb69ffb40 (LWP 11041)):
   3    import time
   6    def do(x):
   7        x = x * 3
  >8        time.sleep(x * 60)
  11    def main():
  12        threads = []
  13        for x in range(1, 3):
Thread 2 (Thread 0xb73b8b40 (LWP 11040)):
   3    import time
   6    def do(x):
   7        x = x * 3
  >8        time.sleep(x * 60)
  11    def main():
  12        threads = []
  13        for x in range(1, 3):
---Type <return> to continue, or q <return> to quit---
Thread 1 (Thread 0xb74b9700 (LWP 11039)):
 335            waiter.acquire()
 336            self.__waiters.append(waiter)
 337            saved_state = self._release_save()
 338            try:    # restore state no matter what (e.g., KeyboardInterrupt)
 339                if timeout is None:
>340                    waiter.acquire()
 341                    if __debug__:
 342                        self._note("%s.wait(): got it", self)
 343                else:
 344                    # Balancing act:  We can't afford a pure busy loop, so we
 345                    # have to sleep; but if we sleep the whole timeout time,
(gdb)

常用的 gdb python 相关的操作就是这些, 同时也不要忘记原来的 gdb 命令都是可以使用的哦。

参考资料

  • DebuggingWithGdb - Python Wiki
  • Features/EasierPythonDebugging - FedoraProject
  • Debugging with GDB: Top
  • · Privacy

    Creative Commons License "mozillazg's Blog" by mozillazg is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License, except where indicated otherwise.

     
    推荐文章