首页 > 系统相关 >使用 gdb 调试运行中的 Python 进程(转)

使用 gdb 调试运行中的 Python 进程(转)

时间:2024-01-22 18:25:03浏览次数:36  
标签:__ do Python py gdb time main 调试

add by zhj: 虽然本文是以Ubuntu Python2.7为例,但基本也适用于Ubuntu Python3,但有两点不同

1. apt intall python<3.x>-dbg,这里的3.x是你要调试的Python程序使用的Python版本。如果你有两个Python程序需要调试,一个使用Python3.7,另一个使用Python3.9,那需要安装python3.7-dbg和python3.9-dbg

2. 不需要设置/proc/sys/kernel/yama/ptrace_scope,而是修改~/.gdbinit,如果该文件不存在,那创建即可。写入内容如下。对于多个python版本,路径之间用分号;分隔

add-auto-load-safe-path <你的Python程序使用的可执行文件"python"的全路径>

 

原文:https://mozillazg.com/2017/07/debug-running-python-process-with-gdb.html

作者:mozillazg

假设一个服务器上运行了下面这样的 test.py 程序,我们怎样才能知道程序是否在正常运行,运行到哪一步了呢?

import time


def do(x):
    time.sleep(10)


def main():
    for x in range(10000):
        do(x)


if __name__ == '__main__':
    main()

这个程序既没有日志也没有 print 输出,通过查看日志文件/标准输出/标准错误是没有办法确认程序状况的。 一种可行的办法就是使用 gdb 来查看程序当前的运行状况。

测试环境

  • 系统: Ubuntu 16.04.1 LTS
  • Python: 2.7.12

准备工作

安装 gdb 和 python2.7-dbg:

sudo apt-get install gdb python2.7-dbg

设置 /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
   3
   4
   5    def do(x):
  >6        time.sleep(10)
   7
   8
   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
   3
   4
   5    def do(x):
  >6        time.sleep(10)
   7
   8
   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)
   7
   8
   9    def main():
  10        for x in range(10000):
 >11            do(x)
  12
  13
  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
   3
   4
   5    def do(x):
  >6        time.sleep(10)
   7
   8
   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 号线程。

切换线程

# 线程序号即info threads的Id列
thread <线程序号>

如下

(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
   4
   5
   6    def do(x):
   7        x = x * 3
  >8        time.sleep(x * 60)
   9
  10
  11    def main():
  12        threads = []
  13        for x in range(1, 3):
(gdb)

同时操作所有线程

thread apply all CMD 或 t a a CMD

如下

(gdb) thread apply all py-list

Thread 3 (Thread 0xb69ffb40 (LWP 11041)):
   3    import time
   4
   5
   6    def do(x):
   7        x = x * 3
  >8        time.sleep(x * 60)
   9
  10
  11    def main():
  12        threads = []
  13        for x in range(1, 3):

Thread 2 (Thread 0xb73b8b40 (LWP 11040)):
   3    import time
   4
   5
   6    def do(x):
   7        x = x * 3
  >8        time.sleep(x * 60)
   9
  10
  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 命令都是可以使用的哦。

参考资料

 

标签:__,do,Python,py,gdb,time,main,调试
From: https://www.cnblogs.com/ajianbeyourself/p/17980687

相关文章

  • 想在IDEA中调试API?试试这款,堪比postman
    Postman是大家最常用的API调试工具,那么有没有一种方法可以不用手动写入接口到Postman,即可进行接口调试操作?今天给大家推荐一款IDEA插件:ApipostHelper,写完代码就可以调试接口并一键生成接口文档!而且还可以根据已有的方法帮助您快速生成url和params。更重要的是他完全免费!Apipos......
  • python学习笔记10(循环结构2)
    一)循环结构21、扩展模式语法:for循环变量in遍历对象:语句块1else:语句块2说明:else在循环结束后执行,通常和break和continue结合使用2、无限循环whilewhile表达式:语句块例子:answer=input('今天要上课么?y/n')whileanswer=='y':print('好好学习,天天向上')answer=input('今......
  • 快乐学Python,如何使用Python处理文件(csv、Excel、html)数据?
    在前面的文章中,我们了解了Python爬虫的一些内容。截止到现在,我们已经可以将需要的数据通过爬虫获取,并保存到CSV文件中。在有了数据集后,接下来我们就开始了解如何将数据集的内容加载到Python中。虽然在之前也有了解简单的读取csv数据。但是存在两个问题:只能读取csv文件,但数据分析......
  • python自动化测试学习路线(从入门到精通)
    python自动化测试学习路线(从入门到精通)一、Python的应用场景Python用于简单脚本编程,如编写2048小游戏或12306的自动抢票软件;Python用于系统编程,如开发系统应用;Python用于开发网络爬虫;网络爬虫的用途是进行数据采集,也就是将互联网中的数据采集过来。网络爬虫的难点其......
  • 测试开发技术:Python测试框架Pytest的基础入门
    测试开发技术:Python测试框架Pytest的基础入门  Pytest简介Pytestisamaturefull-featuredPythontestingtoolthathelpsyouwritebetterprograms.Thepytestframeworkmakesiteasytowritesmalltests,yetscalestosupportcomplexfunctionaltesting......
  • 如何从 0 开始学 Python 自动化测试开发(一)
    如何从0开始学Python自动化测试开发(一)Python:「TIOBE’s2018年度编程语言」Python作为大数据工程和AI的主流开发语言,近年来一直保持强劲的上升趋势。即使目前AI领域还没有大量的成功商业案例(盈利的)出现,Python语言就已经空前火爆了。2019新年伊始,Python果然......
  • Python 自动化测试开发
     测试开发WebUI测试自动化splinter-webUI测试工具,基于selnium封装。链接selenium-webUI自动化测试。链接--推荐文档参考mechanize-Python中有状态的程序化Web浏览。链接selene-使用Python+Ajax支持+PageObjects+Widgets进行简明UI测试链......
  • 基于python3 flet库的证书查看工具
    前言基于python3flet库实现了证书信息的提取,留作自用,如有错误欢迎指正。正文程序架构:主程序main.py证书解析程序certHandle.py运行pythonmain.pymain.py#-*-coding:utf-8-*-importbase64importtracebackimportjsonimportfletasftfromcertHandleimp......
  • Python web crawler(4)图片的下载
    下载图片(单线程)importos.pathimportrequests#异步加载数据的接口url=''headers={'User-Agent':'****************************','Cookie':'********************************','Referer':'......
  • 【Python进阶】Python设计模式
    设计模式介绍什么是设计模式设计模式是面对各种问题进行提炼和抽象而形成的解决方案。这些设计方案是前人不断试验,考虑了封装性、复用性、效率、可修改、可移植等各种因素的高度总结。它不限于一种特定的语言,它是一种解决问题的思想和方法为什么要用设计模式按照设计模式编写......