使用gdb调试android原生程序

        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 命令来单步调试了



你可能感兴趣的:(Android)