调试python脚本用到cpython_pythondocument/使用gdb调试CPython进程.md at master · hiddenJuliet/pythondocument · Git...

当Python程序员需要找到他们应用中的问题根源时,pdb一直是,而且很可能永远是他们的面包和黄油,因为它是一个内置的,并且易于使用的调试器。但也有些情况时pdb无法帮你的,例如,如果你的应用在某些地方卡住了,而你需要在不重启它的情况下,连接到正在运行的进程来找出原因。而这就是gdb让人眼前一亮的原因。

为嘛是gdb?

gdb是一个通用调试器,它主要是用于C和C++应用程序的调试(虽然它实际上支持阿Ada, Objective-C, Pascal等等)。

Python程序员对使用gdb进行调试感兴趣有多种原因:

gdb允许你在不以debug模式启动一个应用,或者以某些方式先修改该应用代码 (例如,把一些像import rpdb; rpdb.set_trace()之类的东西放到代码里)的情况下,连接到一个正在运行的进程。

gdb允许你获得一个进程的核心转储(core dump),以便稍后分析。当你不希望停止该进程的持续时间,或者当你正在审视它的状态,以及当你对一个已经失败(e.g. crashed with a segmentation fault)的程序进行事后剖析时,这是有用的。

Python大多数可用的调试器 (明显的例外是winpdb和pydevd)并不支持在被调试的应用线程之间进行切换。gdb允许这样,它还允许调试由非Python代码(例如,在一些使用的原生库中)创建的线程

解释型语言的调试

所以,当使用gdb时,是什么让Python与众不同呢?

不像诸如C或C++这样的编程语言,Python代码并不会被编译成目标平台的本地二进制文件。取而代之的是,有一个解释器 (例如,CPython,Python的参考实现),它执行编译的字节码。

这实际上意味着,当你用gdb连接到一个Python进程时,你会在解释器级别调试解释器实例和内省进程状态,而不是应用程序级别:即你会看到解释器的函数和变量,而不是你的应用程序。

给你举个例子,让我们来看看一个CPython(最流行 ​的Python解释器)进程的gdb回溯:

#0 0x00007fcce9b2faf3 in __epoll_wait_nocancel () at ../sysdeps/unix/syscall-template.S:81

#1 0x0000000000435ef8 in pyepoll_poll (self=0x7fccdf54f240, args=, kwds=) at ../Modules/selectmodule.c:1034

#2 0x000000000049968d in call_function (oparg=, pp_stack=0x7ffc20d7bfb0) at ../Python/ceval.c:4020

#3 PyEval_EvalFrameEx () at ../Python/ceval.c:2666

#4 0x0000000000499ef2 in fast_function () at ../Python/ceval.c:4106

#5 call_function () at ../Python/ceval.c:4041

#6 PyEval_EvalFrameEx () at ../Python/ceval.c:2666

以及一个通过traceback.extract_stack()工具获得的:

/usr/local/lib/python2.7/dist-packages/eventlet/greenpool.py:82 in _spawn_n_impl

`func(*args, **kwargs)`

/opt/stack/neutron/neutron/agent/l3/agent.py:461 in _process_router_update

`for rp, update in self._queue.each_update_to_next_router():`

/opt/stack/neutron/neutron/agent/l3/router_processing_queue.py:154 in each_update_to_next_router

`next_update = self._queue.get()`

/usr/local/lib/python2.7/dist-packages/eventlet/queue.py:313 in get

`return waiter.wait()`

/usr/local/lib/python2.7/dist-packages/eventlet/queue.py:141 in wait

`return get_hub().switch()`

/usr/local/lib/python2.7/dist-packages/eventlet/hubs/hub.py:294 in switch

`return self.greenlet.switch()`

照这样看,当你尝试找到你的Python代码中的错误时,前者没啥帮助,而你所看到的是解释器本身的当前状态。

然而,PyEval_EvalFrameEx看起来很有趣:这是CPython的一个函数,它执行Python应用级别的函数的字节码,因此,可以访问它们的状态 —— 那个我们通常感兴趣的非常态。

gdb和Python

"gdb debug python"的搜索结果可能会造成混淆。问题是,从gdb的版本7开始,使用Python代码扩展编译器成为了可能,例如,为了提供C++ STL类型的可视化,这用Python实现比在内置的macro语言实现容易得多。

为了能够调试CPython进程以及内省应用级别的状态,解释器开发者决定扩展gdb,为此编写一个script,当然,是用Python!

所有有两种不同,但是相关的事:

gdb版本7+ 是可以用Python模块扩展的

gdb有一个用于CPython进程调试的Python扩展

使用gdb 101调试Python

首先,你需要安装gdb:

# apt-get install gdb

或者

# yum install gdb

根据你正在使用的Linux不同发行版本。

下一步是为你的CPython安装调试符号 :

# apt-get install python-dbg

或者

# yum install python-debuginfo

一些Linux发行版本,例如CentOS或者RHEL分别从所有其他包自带了调试符号separately,推荐像这样安装

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值