Android NDK目录下的gdb虽然可以调试android程序,但是这个不包含符号信息,调试时需要设置Android系统动态链接库的符号加载路径,并且只能调试拥有调试信息的原生程序,而一般情况下,使用 Android NDK编译的原生程序都不包含调试信息,因此无发使用官方的gdb
我们可以手动编译一个静态版本的gdb调试器,首先到gdb的官方下载gdb的源代码,我们这里下载的版本为7.3.1,下载地址为:ftp://sourceware.org/pub/gdb/gdb-7.3.1.tar.gz,
下载后解压源代码,在终端下使用命令安装编译gdb所需的软件包。
sudo apt-get install bison flex libncurses5-dev texinfo gawk libtool
编译gdb时不要使用自带的多线程库thread_db.c,应使用Android NDK中的修改版本,位于Android NDk 的sources/android/libthread_db/gdb-7.3.x/libthread_db.c,为了避免兼容性的问题,将其编译成静态库,配置gdb编译脚本如下
export TOOLCHAIN_PATH=/home/android/tools/android/android-ndk-r8b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86
export PATH=$TOOLCHAIN_PATH/bin:$PATH
export SYSROOT=/home/android/tools/android/android-ndk-r8b/platforms/android-14/arch-arm
export TOOLCHAIN_PREFIX=$TOOLCHAIN_PATH/bin/arm-linux-androideabi
export CC="$TOOLCHAIN_PREFIX-gcc --sysroot=$SYSROOT"
export AR="$TOOLCHAIN_PREFIX-ar"
$CC -o $SYSROOT/usr/lib/libthread_db.o -c /home/android/tools/android/android-nkd-r8b/sources/android/libthread_db/gdb-7.3.x/libthread_db.c
$AR -r $SYSROOT/usr/lib/ibthread_db.a $SYSROOT/usr/lib/libthread_db.o
#配置gdb编译脚本
./configure --target=arm-elf-linux --enable-static --disable-stripping -with-libthread-db=$SYSROOT/usr/lib/libthread_db.a
"--target=arm-elf-linux" 指定了被调试的程序运行的系统平台,“--enable-static”指定了静态编译,“--disable-stripping”指定禁止剥离符号信息,“--with-libthread-db”手动指定多线程库文件,在终端上依次执行以上命令会声称makefile 我呢间,接下来还需要手动修改gdb-7.3.1/gdb目录下的remote.c文件,找到process_G_packet()函数的代码,将一下的内容
if(but_len>2*rsa->sizeof_g_packet)
error(_("Remote 'g' packet reply is too long:%s"),rs->but);
修改为
if(but_len>2*rsa->sizeof_g_packet)
{
rsa->sizeof_g_packet=buf_len;
for(i=0;i { if(rsa->regs[i].pnum==-1) continue; if(rya->regs[i].offset>=rsa->sizeof_g_packet) rsa->regs[i].in_g_packet=0; else rsa->regs[i].in_g_packet=1; } } 修改保存后,在终端上执行make编译gdb 单独使用gdb还不能调试android原生程序 还需要编译gdbserver,这个的源代码在 gdb-7.3.1/gdb/gdbserver 目录下,在终端下执行一下命令配置gdbserver编译脚本 export CC="$TOOLCHAIN_PREFIX-gcc --sysroot=$SYSROOT" export CFLAGS="-02 -D__ANDROID__ -DANDROID -DSTDC_HEADERS -D__GLIBC__" ./configure --host=arm-linux-androideabi --with-libthread-db=$SYSROOT/usr/lib/libthread_db.a 命令执行完成后会在gdb-7.3.1/gdb/gdbserver 目录下声称makefile文件,打开该文件找到 WERROR_CFLAGS的定义,将它的值清空,然后打开config.h文件,将“/*#undef HAVE_LWPID_T */”改为“#define HAVE_LWPID_T 1”,修改后保存,然后在终端下执行make编译gdbserver. 下面介绍如何调试,首先准备一个android app,这个用一个名为testapp的程序,在终端下执行以下两个命令将testapp与gdbserver复制到android石碑的/data/local/tmp目录 adb push test app /data/local/tmp dab push gdbserver /data/local/tmp 执行以下两行命令给两个文件加上可执行权限 adb shell chmod 755 /data/local/tmp/testapp adb shell chnod 755 /data/local/tmp/gdbserver 接着执行 “adb shell /data/local/tmp/gdbserver:12345 /data/local/tmp/testapp”,启动dgb调试服务器,会输入如下信息 Process /data/local/tmp/testapp create; pid=292 Listening on port 12345 程序其实调试服务器已经启动,并且监听了12345号端口,打开另一个终端窗口执行以下命令开启端口转发 dab forward tcp:12345 tcp:12345 在pc 端的终端下执行./gdb启动gdb调试器,然后执行以下命令连接gdb调试服务器 target remote localhost:12345 命令执行后会输出 (gdb) target remote localhost:12345 Remote debugging using localhost:12345 warning: Can not parse XML target description; XML support was disabled at compile time 0xb000100 in ?? () (gdb) 使用 ida pro 或者objdump 找到程序main()函数地址,例如 0x8580,在gdb Shell 环境下执行命令“b *0x8580” 在main()函数的第一行上设置断点,输出信息如下 (gdb) b *0x8580 Breakpoint 1 at 0x8580 (gdb) 断点设置完成后输入continue 让程序继续执行,输出信息如下 (gdb)continue Continuing. Program received signal SIGSEGV,Segmentation fault. 0x00008584 in ??() 执行"set disassemble-next on "设置反汇编显示代码,然后执行“dosas 0x8580,+20”显示0x8580以下20各字符的反汇编代码,输出信息如下 (gdb)disas 0x8580,+20 Dump of assembler code from 0x8580 to 0x8594 0x00008580:ldr r0,[pc,#16] ;0x8598 => 0x00008584:push {r4,lr} 0x00008588:add r0,pc,r0 0x0000858c:bl 0x84f8 0x00008590:mov r0,#0 End of assembler dump. (gdb) 接下来可以输入si或者ni 命令来单步调试了