GDB 获取python程序堆栈

Posted espzest

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GDB 获取python程序堆栈相关的知识,希望对你有一定的参考价值。

在调试python程序时,经常需要从gdb attach上去,跟踪stack信息。 虽然DebuggingWithGdb[https://wiki.python.org/moin/DebuggingWithGdb]提供了不错的方法,但是某些情况下还是需要gdb原始操作的。

typedef struct {
    PyObject_HEAD
    int co_argcount;        /* #arguments, except *args */
    int co_nlocals;     /* #local variables */
    int co_stacksize;       /* #entries needed for evaluation stack */
    int co_flags;       /* CO_..., see below */
    PyObject *co_code;      /* instruction opcodes */
    PyObject *co_consts;    /* list (constants used) */
    PyObject *co_names;     /* list of strings (names used) */
    PyObject *co_varnames;  /* tuple of strings (local variable names) */
    PyObject *co_freevars;  /* tuple of strings (free variable names) */
    PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
    /* The rest doesn't count for hash/cmp */
    PyObject *co_filename;  /* string (where it was loaded from) */
    PyObject *co_name;      /* string (name, for reference) */
    int co_firstlineno;     /* first source line number */
    PyObject *co_lnotab;    /* string (encoding addr<->lineno mapping) See
                   Objects/lnotab_notes.txt for details. */
    void *co_zombieframe;     /* for optimization only (see frameobject.c) */
    PyObject *co_weakreflist;   /* to support weakrefs to code objects */
} PyCodeObject;

其中重要的是:co_filename(文件名), co_firstlineno(首行), co_name(函数名)。

如果通过gdb拿到以下stack:

#0  0x000000395bee8f63 in epoll_wait () from /lib64/libc.so.6
#1  0x00007feb949885de in pyepoll_poll (self=0x7feb9c2acc00, args=<optimized out>, kwds=<optimized out>) at /n/filer3b/home/sqa/xuezhang/tickets/SCM-979/software-SCM-1280/Python-2.7.11/Modules/selectmodule.c:1034
#2  0x00000000004a2fc1 in call_function (pp_stack=<optimized out>, oparg=<optimized out>) at Python/ceval.c:4350
#3  0x00000000004a2fc1 in PyEval_EvalFrameEx (f=0x2b67fc0, throwflag=<optimized out>)
#4  0x00000000004a4890 in PyEval_EvalCodeEx (co=0x7feb94749630, globals=<optimized out>, locals=<optimized out>, args=0x7feb91a3f1d8, argcount=1, kws=0x7feb91a3f1e0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at Python/ceval.c:3582
#5  0x00000000004a2c0e in call_function (pp_stack=<optimized out>, oparg=<optimized out>) at Python/ceval.c:4445
#6  0x00000000004a2c0e in PyEval_EvalFrameEx (f=0x7feb91a3f050, throwflag=<optimized out>)
#7  0x00000000004a3857 in call_function (pp_stack=<optimized out>, oparg=<optimized out>) at Python/ceval.c:4436
#8  0x00000000004a3857 in PyEval_EvalFrameEx (f=0x7feb9c2c2050, throwflag=<optimized out>)
#9  0x00000000004a4890 in PyEval_EvalCodeEx (co=0x7feb9c0ab730, globals=<optimized out>, locals=<optimized out>, args=0x0, argcount=0, kws=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at Python/ceval.c:3582
#10 0x00000000004a4a12 in PyEval_EvalCode (co=0x5, globals=0x2d36f50, locals=0x3ff) at Python/ceval.c:669
#11 0x00000000004c9983 in run_pyc_file (fp=<optimized out>, filename=<optimized out>, globals=0x2d36f50, locals=0x3ff, flags=<optimized out>) at Python/pythonrun.c:1400
#12 0x00000000004c9983 in PyRun_SimpleFileExFlags (fp=0x2586930, filename=<optimized out>, closeit=<optimized out>, flags=0x7ffd20d1d21c)
#13 0x0000000000414dd6 in Py_Main (argc=<optimized out>, argv=0x7ffd20d1d3c8) at Modules/main.c:640
#14 0x000000395be1ed5d in __libc_start_main () from /lib64/libc.so.6
#15 0x00000000004141da in _start ()

PyEval_EvalCodeEx(PyCodeObject* co, ...), 第一个参数函数含有我们需要的信息。
p ((PyCodeObject*)0x7feb9c0ab730)->co_firstlineno    得到首行行号: 3
x /50sb (PyStringObject*)(((PyCodeObject*)0x7feb9c0ab730)->co_name)  打印一系列字符串, 可以得到函数名:  module
x /50sb (PyStringObject*)(((PyCodeObject*)0x7feb9c0ab730)->co_filename) 打印一系列字符串,可以得到文件名: ./backend/run.py

以上是关于GDB 获取python程序堆栈的主要内容,如果未能解决你的问题,请参考以下文章

从核心转储中获取堆栈跟踪

20145316GDB调试汇编堆栈

如何获取 gdb 调用堆栈跟踪?

GDB调试汇编堆栈过程分析

是啥导致我的堆栈中出现神秘的重复条目?

gdb:检查堆栈和小端澄清