最好是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