2014-09-10 91 views
2

我试图调试代码,其中python使用ctypes调用C函数。我感兴趣的python代码中的代码如下所示:Ctypes - 从使用ctypes的python代码获取C backtrace

returnValue = cfunction() 

其中cfunction是C函数。我想知道函数返回的函数在哪里。我怎样才能做到这一点?

看起来我可以在python中使用gdb,但我不确定正确的方式来使用gdb,所以我可以在上面的行设置一个断点并显示C代码返回的C函数的位置。当然,我有用-g编译的C代码。

只要我可以在Linux中使用一些免费的(如啤酒或语音)工具,就不需要使用gdb。

(我运行蟒蛇2.7.6,GDB 7.7和C代码与GCC 4.8.2编译。)

回答

1

如果任何合理的调试器(包括GDB)下运行python,无论是通过启动通过这种方式或通过附加它,它可以在C代码中创建断点,无论是Python的一部分,作为扩展模块加载,通过`ctypes或其他方式加载。而且,做完这些之后,您可以打印出回溯,逐行或进出,等等,您想要的任何其他内容。这只是一个普通的调试器会话。 (当然,你可能没有在你的Python中有调试符号,但只要你已经为你的.so提供了这些,那就是你所关心的,对吧?)

例如(使用lldb,但我想我已经坚持完全兼容gdb的命令的子集...):

$ lldb python3 
Current executable set to 'python3' (x86_64). 
(lldb) run 
Process 6828 launched: '/Library/Frameworks/Python.framework/Versions/3.4/bin/python3' (x86_64) 
Process 6828 stopped 
* thread #1: tid = 0x8cf0d1, 0x00007fff5fc01028 dyld`_dyld_start, stop reason = exec 
    frame #0: 0x00007fff5fc01028 dyld`_dyld_start 
dyld`_dyld_start: 
-> 0x7fff5fc01028: popq %rdi 
    0x7fff5fc01029: pushq $0x0 
    0x7fff5fc0102b: movq %rsp, %rbp 
    0x7fff5fc0102e: andq $-0x10, %rsp 
(lldb) c 
Process 6828 resuming 
Python 3.4.1 (v3.4.1:c0e311e010fc, May 18 2014, 00:54:21) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import ctypes 
>>> libc = ctypes.CDLL('/usr/lib/libc.dylib') 
Process 6828 stopped 
* thread #1: tid = 0x8cf0d1, 0x00007fff8a7149aa libsystem_kernel.dylib`__select + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP 
    frame #0: 0x00007fff8a7149aa libsystem_kernel.dylib`__select + 10 
libsystem_kernel.dylib`__select + 10: 
-> 0x7fff8a7149aa: jae 0x7fff8a7149b4   ; __select + 20 
    0x7fff8a7149ac: movq %rax, %rdi 
    0x7fff8a7149af: jmpq 0x7fff8a71119a   ; cerror 
    0x7fff8a7149b4: ret 
(lldb) b printf 
Breakpoint 1: where = libsystem_c.dylib`printf, address = 0x00007fff875cf8a8 
(lldb) c 
Process 6828 resuming 
>>> libc.printf('spam') 
Process 6828 stopped 
* thread #1: tid = 0x8cf0d1, 0x00007fff875cf8a8 libsystem_c.dylib`printf, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 
    frame #0: 0x00007fff875cf8a8 libsystem_c.dylib`printf 
libsystem_c.dylib`printf: 
-> 0x7fff875cf8a8: pushq %rbp 
    0x7fff875cf8a9: movq %rsp, %rbp 
    0x7fff875cf8ac: pushq %r15 
    0x7fff875cf8ae: pushq %r14 
(lldb) bt 
* thread #1: tid = 0x8cf0d1, 0x00007fff875cf8a8 libsystem_c.dylib`printf, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 
    * frame #0: 0x00007fff875cf8a8 libsystem_c.dylib`printf 
    frame #1: 0x0000000101a545e7 _ctypes.so`ffi_call_unix64 + 79 
    frame #2: 0x0000000101a5549f _ctypes.so`ffi_call + 575 
    frame #3: 0x0000000101a4f81f _ctypes.so`_ctypes_callproc + 879 
    frame #4: 0x0000000101a4772a _ctypes.so`PyCFuncPtr_call + 314 
    frame #5: 0x000000010000da08 Python`PyObject_Call + 104 
    frame #6: 0x00000001000e1c3f Python`PyEval_EvalFrameEx + 16975 
    frame #7: 0x00000001000e665d Python`PyEval_EvalCodeEx + 2349 
    frame #8: 0x00000001000e671f Python`PyEval_EvalCode + 63 
    frame #9: 0x000000010010f5ba Python`PyRun_InteractiveOneObject + 474 
    frame #10: 0x000000010010f93e Python`PyRun_InteractiveLoopFlags + 110 
    frame #11: 0x00000001001113e1 Python`PyRun_AnyFileExFlags + 161 
    frame #12: 0x000000010012867f Python`Py_Main + 3535 
    frame #13: 0x0000000100000e32 Python 
    frame #14: 0x0000000100000c84 Python 
(lldb) 
+0

对不起。我想我明白你在做什么,但我仍然不确定如何在python脚本中放置断点。我怀疑我对如何使用调试器知之甚少,因此我需要做更多的工作,然后才能在SO上合法地提出这个问题。 – raoulcousins 2014-09-10 23:09:08

+0

@raoulcousins:你想在Python代码或C代码中使用断点吗?对于前者,您希望使用'pdb',而不是C级调试器。对于后者,您需要阅读关于'gdb'或其他任何其他调试器的教程,或者找到一个很好的GUI IDE来包装它,以便您可以单击代码行旁边的代码并添加断点......但基本思想是'b printf'。如果在我的程序中有一个名为'printf'的明确的C函数,那么该函数在该函数的开始处设置一个断点。 – abarnert 2014-09-10 23:13:14

+0

@raoulcousins:事情可能会变得更复杂一些,但对于简单的情况......如果你可以通过编写'mylib.cfunction()'从'ctypes'调用函数,那么通常可以从'gdb'断点函数只需编写'b cfunction'即可。 – abarnert 2014-09-10 23:16:09