1. 程式人生 > >重新編譯arm-linux-androideabi-gdb和gdbserver

重新編譯arm-linux-androideabi-gdb和gdbserver

一、引言

         Android應用程式在執行的時候,不管是dex還是native的so,都要載入到記憶體裡面,所以直接把與之對應的記憶體dump出來分析是一個不錯的主意,ndk給我們提供了可供開發者遠端除錯的gdb和gdbserver,但是一些功能比如gcore不能用,本文通過重新編譯gdb和gdbserver ,從而可以達到使用gcore把記憶體dump出來的目的。以下使用的android原始碼是android4.4.

二、開發環境

Ubuntu 12.04

android-ndk-r9

三、解決過程

首先編譯arm-linux-androideabi-gdb,android-ndk-r9中自帶了gdbserver和arm-linux-androideabi-gdb,但是使用gdbserver和arm-linux-androideabi-gdb除錯手機的時候,用gcore出現Command notimplemented for this target,

原因是ndk裡面自帶的arm-linux-androideabi-gdb把gcore移除了,所以需要自己編譯一個arm-linux-androideabi-gdb

以下是編譯過程:

首先下載原始碼

mkdir gdb_build
git clone https://android.googlesource.com/toolchain/build.git
git clone https://android.googlesource.com/toolchain/gdb.git

把build和gdb的原始碼下載完畢

執行

cd gdb_build
./configure --target=arm-linux-androideabi --prefix=gdb_build/gdb/gdb-7.6/arm-linux
make
make install

等待編譯完畢。

arm-linux-androideabi-gdb就在gdb_build/gdb/gdb-7.6/arm-linux下生成了

在遠端除錯的時候可能發現如下錯誤

remote g packet reply is too long

需要修改gdb-7.6/gdb/remote.c中把如下2行註釋掉

//if (buf_len > 2 * rsa->sizeof_g_packet)
//  error(_("Remote 'g' packet reply is too long: %s"), rs->buf);

修改成

if (buf_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 (rsa->regs[i].offset >= rsa->sizeof_g_packet)
        rsa->regs[i].in_g_packet = 0;
        else
        rsa->regs[i].in_g_packet = 1;
}

以上編譯的是gdb7.6,需要與之版本對應的gdbserver。

編譯gdbserver流程:

需要android原始碼,首先建立sysroot目錄,

cd gdb_build
./build/build-sysroot.sh ~/workspace/androidsrc/out/target/product/generic/ ./sysroot

然後修改~/workspace/androidsrc/ndk/build/tools/build-gdbserver.sh指令碼,

if [ "$NOTHREADS" !="yes" ] ; then
     # We're going to rebuild libthread_db.o fromits source
     #that is under sources/android/libthread_db and place its header
     # andobject file into the build sysroot.
    LIBTHREAD_DB_DIR=$ANDROID_NDK_ROOT/sources/android/libthread_db/gdb-$GDB_VERSION
     if[ ! -d "$LIBTHREAD_DB_DIR" ] ; then
        dump "ERROR: Missing directory: $LIBTHREAD_DB_DIR"
        exit 1
     fi
     #Small trick, to avoid calling ar, we store the single object file
     #with an .a suffix. The linker will handle that seamlessly.
     runcp $LIBTHREAD_DB_DIR/thread_db.h $BUILD_SYSROOT/usr/include/
     run$TOOLCHAIN_PREFIX-gcc --sysroot=$BUILD_SYSROOT -o$BUILD_SYSROOT/usr/lib/libthread_db.a -c $LIBTHREAD_DB_DIR/libthread_db.c
     if [$? != 0 ] ; then
        dump "ERROR: Could not compile libthread_db.c!"
        exit 1
     fi
 fi

修改為 

<<NOT_NEEDED
 # Removelibthread_db to ensure we use exactly the one we want.
 rm -f$BUILD_SYSROOT/usr/lib/libthread_db*
 rm -f$BUILD_SYSROOT/usr/include/thread_db.h
 
 if ["$NOTHREADS" != "yes" ] ; then
     #We're going to rebuild libthread_db.o from its source
     #that is under sources/android/libthread_db and place its header
     # andobject file into the build sysroot.
    LIBTHREAD_DB_DIR=$ANDROID_NDK_ROOT/sources/android/libthread_db/gdb-$GDB_VERSION
     if[ ! -d "$LIBTHREAD_DB_DIR" ] ; then
        dump "ERROR: Missing directory: $LIBTHREAD_DB_DIR"
        exit 1
     fi
     #Small trick, to avoid calling ar, we store the single object file
     #with an .a suffix. The linker will handle that seamlessly.
     runcp $LIBTHREAD_DB_DIR/thread_db.h $BUILD_SYSROOT/usr/include/
     run$TOOLCHAIN_PREFIX-gcc --sysroot=$BUILD_SYSROOT -o$BUILD_SYSROOT/usr/lib/libthread_db.a -c $LIBTHREAD_DB_DIR/libthread_db.c
     if [$? != 0 ] ; then
        dump "ERROR: Could not compile libthread_db.c!"
        exit 1
     fi
 fi
 NOT_NEEDED

修改~/workspace/androidsrc/ndk/build/tools/build-gdbserver.sh

get_toolchain_install ()
 {
     localNDK=”$1”
     shift
     echo"$ NDK/$(get_toolchain_install_subdir “%@”)”
 }

 修改為

 get_toolchain_install ()
 {
     echo"$1/prebuilts/gcc/$HOST_TAG/arm/$TOOLCHAIN"
 }

然後執行

sudo ~/workspace/androidsrc/ndk/build/tools/build-gdbserver.sh
~/workspace/gdb_build ~/workspace/androidsrcarm-linux-androideabi-4.6 --verbose --build-out=~/workspace/gdb_build/install--gdb-version=7.6 --sysroot=~/workspace/gdb_build/sysroot

編譯的時候可能會出現2個錯誤,

~/workspace/gdb_build/gdb/gdb-7.6/gdb/gdbserver/gdb_proc_service.h:79:1:error: unknown type name 'elf_gregset_t'
~/workspace/gdb_build/gdb/gdb-7.6/gdb/gdbserver/linux-low.c:113:3:error: conflicting types for 'Elf32_auxv_t'
~/workspace/gdb_build/install/sysroot/usr/include/elf.h:40:3:note: previous declaration of 'Elf32_auxv_t' was here
~/workspace/gdb_build/gdb/gdb-7.6/gdb/gdbserver/linux-low.c:128:3:error: conflicting types for 'Elf64_auxv_t'
~/workspace/gdb_build/install/sysroot/usr/include/elf.h:47:3:note: previous declaration of 'Elf64_auxv_t' was here

elf_gregset_t型別不識別,Elf32_auxv_t和Elf64_auxv_t定義衝突。

修改~/workspace/gdb_build/gdb/gdb-7.6/gdb/gdbserver/linux-low.c的結構體Elf32_auxv_t和Elf64_auxv_t,把他的名字改變。

修改

~/workspace/gdb_build/gdb/gdb-7.6/gdb/gdbserver/gdb_proc_service.h

#ifndef HAVE_PRGREGSET_T
typedef elf_gregset_t prgregset_t;
#endif

上面新增

typedef unsigned long elf_greg_t;
typedef elf_greg_t elf_gregset_t[35];
編譯好的gdbserver在~/workspace/gdb_build/install生成。