1. 程式人生 > >使用gdb除錯android原生程式

使用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<gdbarch_num_regs (gdbarch);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 命令來單步除錯了