Skip to main content

能够附加到进程的 Python 调试器

项目描述

**免责声明:这不是谷歌官方项目,这只是我在谷歌时写的。**

Pyringe
=======

这是什么
------------

Pyringe 是一个python调试器能够附加到正在运行的进程,检查它们的状态,甚至在它们运行时将python代码注入它们。使用 pyringe,您可以列出线程、获取回溯、检查正在运行的函数的本地/全局/内置,所有这些都无需为它准备程序。

这不是什么
----------------

一个“谷歌项目”。开源的是我的实习项目。对困惑感到抱歉。

我需要什么?
---------------

Pyringe 内部使用 gdb 来完成很多繁重的工作,因此您需要一个相当新的 gdb 构建(版本 7.4 及更高版本,并且仅当 gdb 配置了 `--with-python` 时)。您还需要用于您正在运行的任何 python 版本的符号。
在 Fedora 上,您要查找的软件包是 `python-debuginfo`,在 Debian 上它称为 `python2.7-dbg`(根据版本进行调整)。Arch Linux 用户:参见 [issue #5][]。
拥有 [Colorama](https://pypi.python.org/pypi/colorama) 将使您以粗体字输出,但它是可选的。

[问题 #5]:https://github.com/google/pyringe/issues/5

我如何得到它?
----------------

从 [Github repo][]、[PyPI][] 或通过 pip (`pip install pyringe`) 获取它。

[Github 仓库]:https://github.com/google/pyringe
[PyPI]:https

://pypi.python.org/pypi/pyringe 这对 Python3 友好吗?
-------------------------

简短回答:**不,抱歉。** 详细回答:
这里有三个可能不同的 python 版本:
1. 运行 pyringe
的版本 2. 正在调试
的版本 3. 您的 gdb 构建的 `libpythonXX.so` 版本​​与

`2` 相关联目前是这里的交易破坏者。与此同时,Cpython 发生了一些变化[1],在调试 python3 的同时使所有功能正常工作,现在必须退居二线,直到更明显的问题得到解决。
至于`1`和`3`,`2to3`工具或许可以自动处理。但是,只要没有处理“2”,这首先就不是一个真正的用例。

[1] - 例如,`pendingbusy`(用于注入)已被重命名为 `busy`,并被赋予了函数本地范围,使得通过 gdb 进行交互变得更加困难。

这适用于 PyPy 吗?
-------------------------

不幸的是,没有。由于这使用了一些 CPython 内部和实现细节,因此仅支持 CPython。如果你不知道 PyPy 或 CPython 是什么,你可能会没事的。

为什么不是 PDB?
------------

PDB很棒。在适用的地方使用它!但有时并非如此。
就像 python 本身崩溃,卡在某个 C 扩展中,或者你想在不停止程序的情况下检查数据时一样。在这种情况下,PDB(以及在解释器本身中运行的所有其他调试器)几乎是无用的,如果没有 pyringe,您将不得不使用 `print` 语句进行调试。Pyringe 在这些情况下非常方便。


我将本地 var 的更改注入到函数中,但它没有显示出来!
-------------------------------------------------- -------------------------

这是一个已知的限制。像 `inject('var = 2')` 这样的东西不会起作用,但是 `inject('var[1] = 1337')` 应该。这是因为大多数时候,python 在内部使用快速路径来查找局部变量,而该路径实际上并没有在 `locals()` 中执行字典查找。通常,使用 pyringe 注入进程的代码与普通的 python 函数调用非常不同。

我该如何使用它?
----------------

你可以通过执行`python -m pyringe`来启动调试器。或者:


```python
import pyringe
pyringe.interact()
```

如果这让你想起了代码模块,很好;这是故意的。
启动调试器后,您会看到其行为几乎类似于常规 python REPL。
尝试以下操作:


```python
==> pid:[None] #threads:[0] current thread:[None]
>>> help()
可用命令:
attach:使用给定的 pid 附加到进程。
bt:获取当前位置的回溯。
[...]
==> pid:[None] #threads:[0] 当前线程:[None]
>>> attach(12679)
==> pid:[12679] #threads:[11] 当前线程:[ 140108099462912]
>>> threads()
[140108099462912, 140108107855616, 140108116248323, 140108124641024, 140108133033728, 140108224739072, 140108233131776, 140108141426432, 140108241524480, 140108249917184, 140108269324032]
```

The IDs you see here correspond to what `threading.current_thread().ident `会告诉你。
所有调试器函数都只是暴露给 REPL 的常规 python 函数,因此您可以执行以下操作。

```python
==> pid:[12679] #threads:[11] current thread:[140108099462912]
>>> for tid in threads():
... if not tid % 10:
... thread(tid)
... bt()
...
Traceback(最近一次调用最后):
文件“/usr/lib/python2.7/threading.py”,第 524 行,在 __bootstrap
self.__bootstrap_inner()
文件“/usr/lib/ python2.7/threading.py”,第 551 行,在 __bootstrap_inner
self.run()
文件“/usr/lib/python2.7/threading.py”,第 504 行,运行
self.__target(*self.__args, * *self.__kwargs)
文件 "./test.py",
Thread_2_Func(1)
File "./test.py", line 40, in Wait time.sleep
(n)
==> pid:[12679] #threads:[11] current thread:[140108241524480]
>>>
```

您可以访问下级的本地变量并像这样检查它们:

```python
==> pid:[12679] #threads:[11] current thread:[140108241524480]
>>> inflocals()
{'a': <proxy of A object at remote 0x1d9b290>, 'LOL': 'success!', 'b': <proxy of B object at remote 0x1d988c0>, 'n': 1}
==> pid:[12679] #threads:[11]当前线程:[140108241524480]
>>> p('a')
<proxy of A object at remote 0x1d9b290>
==> pid:[12679] #threads:[11] 当前线程:[140108241524480]
>>> p('a').attr
'Some_magic_string'
==> pid:[12679] #threads:[11] current thread:[140108241524480]
>>>
```

果然,`a`的类的定义是:

```python
class Example(object) :
cl_attr = False
def __init__(self):
self.attr = 'Some_magic_string'
```

这种对象代理的范围是有限制的,所有不重要的数据都将显示为字符串(如 `'<function在远程 0x1d957d0>'`)。
您可以将 python 代码注入正在运行的程序中。当然,有一些警告,但是......你自己看看:

```python
==> pid:[12679] #threads:[11] current thread:[140108241524480]
>>> inject('import threading')
==> pid:[12679] #threads:[11] 当前线程:[140108241524480]
>>> inject('print threading.current_thread().ident')
==> pid:[12679] #threads:[11]当前线程:[140108241524480]
>>>
```

在这种情况下,我的程序的输出为:

```
140108241524480
```

如果您需要额外的指针,只需尝试使用 python 的帮助(调试器中的 `pyhelp()`)关于调试器命令。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

pyringe-1.0.2.tar.gz (42.8 kB 查看哈希)

已上传 source