如何使用gdb调试python服务

Python051

如何使用gdb调试python服务,第1张

1.安装gdb

最好是gdb7.7版本

2.获取python源代码

3.编译python

*

./configure

--prefix=/home/admin/python

*

make

"CFLAGS=-g

-fno-inline

-fno-strict-aliasing"

*

make

install

4.复制python源代码中的Tools//gdb/libpython.py到目录

~/.gdbinit

5.修改.gdbinit中的代码

<<<<

if

$pc

>

PyEval_EvalFrameEx

&&

$pc

<

PyEval_EvalCodeEx

修改为

>>>>

if

$pc

>

PyEval_EvalFrameEx

&&

$pc

<

PyEval_EvalCodeEx

&&

$fp

!=

0

6.启动gdb

./gdb

python

可用命令有

./gdb

python

--pid=${pid}

./gdb

python

--core=${core_file}

7.引入libpython.py

(gdb)

python

>import

sys

>sys.path.insert(0,'/home/admin/')

>import

libpython

>end

(gdb)

8.然后可运行命令py-bt,py-list,pystack,pystackv

注:

1.libpython.py为python

debug扩展

2.gdbinit中包含扩展命令,pystack即在这里边定义

3.若运行pystack时出现错误

No

symbol

"co"

in

current

context.

则表示未执行以下两个步骤:

make

"CFLAGS=-g

-fno-inline

-fno-strict-aliasing"

修改.gdbinit中的代码(修改内容见上边的步骤5)

做这件事情的目的是为了在QtCreator里调试ARM Linux程序的时候,能看清楚QString、QList这些Qt特有的对象的内容,而不是一个完全看不懂的结构体。

目前(2014年8月)Linaro、CodeSourcery的GCC工具链里的GDB都不支持Python。想知道你用的GDB支持不支持,试一试就行,这样表示不支持:

(gdb) python

>print 'Hello GDB!'

>(按Ctrl+D)Python scripting is not supported in this copy of GDB.

这样表示支持:

(gdb) python

>print 'Hello GDB!'

>(按Ctrl+D)Hello GDB!

这件事情乍一看也很简单,只要把GDB源码下载下来,然后再配置,打开Python支持就行了。实际上会遇到的问题是,在MinGW下,又要与“\”和“:”这两个Windows路径里的刺头斗争了。我觉得我之前挺傻,编译MinGW下Qt的时候,就去硬磕源码和configure脚本去了。这次GDB的configure是自动生成的,不是给人看的,configure.ac看起来也很费劲,根本磕不下去,于是我换了个思路,在ubuntu下交叉编译吧,sudo apt-get install mingw32,这是Ubuntu下的MinGW交叉编译器。

然后是依赖,这样的GDB要依赖expat和python的开发版本。如果是ubuntu底下直接编译,apt-cache search一下他们的开发版本,然后sudo apt-get install一下就好了;给MinGW交叉编译就麻烦了。先说expat,这个好办,把http://downloads.sourceforge.net/project/expat/expat/2.1.0/expat-2.1.0.tar.gz下载下来,然后:

./configure --prefix=[安装目录,如/home/cdu/mingw-gdb/expat] --host=i586-mingw32msvc

make

make install

会提示一些警告,无视即可。

Python就无语了,目前的GDB貌似最高支持Python 2.7,而2.7版本的Python本身不支持MinGW…… 好在有高手做了Patch,也写了说明,可以参考这文章:http://mdqinc.com/blog/2011/10/cross-compiling-python-for-windows-with-mingw32/

但是,就算这样,编译也充满挑战,要修复很多问题,出来的Python还少“nt”模块。就在我觉得没办法的时候,突然发现Windows版Qt提供的MinGW居然内置了Python开发包,位置在Tools/mingw48_32/opt,赶紧把它拷贝到Linux下,比如/home/cdu/mingw-gdb/python。当然,你也必须确保ubuntu下有可用的python。

然后,给GDB打一个补丁:

--- gdb-7.8/gdb/configure 2014-07-29 20:37:42.000000000 +0800

+++ gdb-7.8-old/gdb/configure 2014-08-30 00:08:27.122042706 +0800

@@ -8263,21 +8263,22 @@

# We have a python program to use, but it may be too old.

# Don't flag an error for --with-python=auto (the default).

have_python_config=yes

-python_includes=`${python_prog} ${srcdir}/python/python-config.py --includes`

+python_config_tool=`echo ${python_prog} | sed "s#python.exe#python-config#g"`

+python_includes=`${python_config_tool} --includes`

if test $? != 0then

have_python_config=failed

if test "${with_python}" != autothen

as_fn_error "failure running python-config --includes" "$LINENO" 5

fi

fi

-python_libs=`${python_prog} ${srcdir}/python/python-config.py --ldflags`

+python_libs=`${python_config_tool} --ldflags`

if test $? != 0then

have_python_config=failed

if test "${with_python}" != autothen

as_fn_error "failure running python-config --ldflags" "$LINENO" 5

fi

fi

-python_prefix=`${python_prog} ${srcdir}/python/python-config.py --exec-prefix`

+python_prefix=`${python_config_tool} --exec-prefix`

if test $? != 0then

have_python_config=failed

if test "${with_python}" != autothen

@@ -8343,12 +8344,12 @@

return 0

}

_ACEOF

-if ac_fn_c_try_link "$LINENO"then :

+#if ac_fn_c_try_link "$LINENO"then :

have_libpython=${version}

found_usable_python=yes

PYTHON_CPPFLAGS=$new_CPPFLAGS

PYTHON_LIBS=$new_LIBS

-fi

+#fi

rm -f core conftest.err conftest.$ac_objext \

conftest$ac_exeext conftest.$ac_ext

CPPFLAGS=$save_CPPFLAGS

这个补丁的目的是强制为检测到python。

然后给拷贝到Linux下的python开发包打一个补丁:

--- python-old/bin/python-config 2013-04-18 02:43:01.000000000 +0800

+++ python/bin/python-config 2014-08-30 00:53:16.630060288 +0800

@@ -1,4 +1,4 @@

-#!/temp/x32-480-posix-dwarf-r2/mingw32/opt/bin/python2.7.exe

+#!/usr/bin/python

import sys

import os

@@ -31,26 +31,23 @@

for opt in opt_flags:

if opt == '--prefix':

-print sysconfig.PREFIX

+print '../python'

elif opt == '--exec-prefix':

-print sysconfig.EXEC_PREFIX

+print '../python'

elif opt in ('--includes', '--cflags'):

-flags = ['-I' + sysconfig.get_python_inc(),

- '-I' + sysconfig.get_python_inc(plat_specific=True)]

+flags = ['-I' + os.path.split(os.path.realpath(__file__))[0] + '/../include/python2.7']

if opt == '--cflags':

-flags.extend(getvar('CFLAGS').split())

+flags += ['-fno-strict-aliasing -DMS_WIN32 -DMS_WINDOWS -DHAVE_USABLE_WCHAR_T -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes']

print ' '.join(flags)

elif opt in ('--libs', '--ldflags'):

-libs = getvar('LIBS').split() + getvar('SYSLIBS').split()

-libs.append('-lpython'+pyver)

+libs = ['-lm -lpython2.7 -Wl,--out-implib=libpython2.7.dll.a']

# add the prefix/lib/pythonX.Y/config dir, but only if there is no

# shared library in prefix/lib/.

if opt == '--ldflags':

if not getvar('Py_ENABLE_SHARED'):

-libs.insert(0, '-L' + getvar('LIBPL'))

-libs.extend(getvar('LINKFORSHARED').split())

+libs.insert(0, '-L' + os.path.split(os.path.realpath(__file__))[0] + '/../lib/python2.7/config')

print ' '.join(libs)

因为Linux下是无法运行开发包中的python.exe的,所以这个补丁借用了ubuntu的python。里面的cflags和ldflags都是在Windows底下运行原始python-config获得的。prefix和exec-prefix设成“../python”,可以在编译完以后,把python开发包拷贝到gdb安装目录里面的python子目录,这样运行GDB的时候就不需要设定PYTHONHOME环境变量了。

最后一个事情,确保你的Linux下有arm交叉编译器,我的是arm-linux-gnueabihf,是啥target就写啥。

准备工作做完了,开始配置和编译:

./configure --with-expat --host=i586-mingw32msvc --target=arm-linux-gnueabihf --with-libexpat-prefix=[expat安装位置] --with-python=[python开发包安装位置/bin/python.exe]

make

make DESTDIR=[GDB安装位置] install

然后把GDB安装位置下面的所有文件拷贝到Windows下,再把python开发包拷贝到同目录下的python子目录,大功告成。

如果提示没找到libpython2.7.dll,那就把GDB安装目录的python/bin下的拷贝到bin下。

如果发现生成的exe文件太大了,那就strip一下。

2015年9月12日追加:

在windows下调试时,一般会提示说加载不了共享库,让你用"set sysroot"或"set solib-search-path"之类设定路径的。这个问题可以通过.gdbinit文件,用上面这两条命令来设定路径解决,如果想一劳永逸,可以在编译的时候加上host_configargs环境变量来解决这个问题:

host_configargs=--with-sysroot=E:\MinGW\opt\sysroot-arm ./configure ...

或者

export host_configargs=--with-sysroot=E:\MinGW\opt\sysroot-arm

./configure ...

后面的路径是你放在windows下的sysroot的位置。

公司有个业务是使用python脚本调用.so文件,但是有时候so文件内部发生错误,python就直接崩溃了,无任何提示信息,所以很不方便找错误原因.

使用 gdb 可以看到更详细的一些信息,其使用方式如下:

ulimit -c 是查看创建的核心转储的最大大小,这里为0,是需要修改的,可以将其改成不限制大小的 unlimited .

cat /proc/sys/kernel/core_pattern 这一步我的理解是查看到时候生成的缓存文件存储名称,这里为 core ,表示其会在当前目录下生成一个名为core的缓存文件,但是为了使其更加通用,可以修改一下其路径和名称格式.

可以看到在 var/cores 目录下生成了一个 core.python.31796 文件,此时可以在刚才的运行目录下执行,下面的 which 前面是`符号,不是单引号

此时可以看到项目最终是在 #0 0x00007f89d8700960 in mkl_pds_lp64_ladj_mod_pardiso () from /usr/lib/libmkl_intel_thread.so 时发生了错误,这个时候可以输入 bt 查看更多,其从上到下是错误从底层到最外层的顺序.

若执行的时候没有 gdb ,可以执行 apt-get install gdb 安装.

还有就是,若查看的时候错误地方是 #0 0x00000000005406df in ?? () 这样的没有具体函数名的情况,这是因为so文件在编译时候没有链接符号到文件里面,需要在使用gcc编译的时候加上 -g