自己动手写ndk-gdb

做NDK开发,经常会用到ndk-gdb,但ndk-gdb的启动规则比较严格,甚至需要检查工程文件,在一些手机上往往无法启动;所以,研究了一下ndk-gdb的代码,实现了一个简单的版本,基本的原理如下:

1. 首先进入android工程目录,该目录下包含了jni, obj, bin工程相关的子目录;


2. 使用awk找到package进程对应的PID(具体实现参考后面的代码)

    如果PID为0, 说明程序没有运行,需要强制启动

     adb shell am start -n $package/$ActivityName

     如:adb shell am start -n  com.xxx.yyy/com.xxx.main.xxxx

     其中,ActivityName 可以在android的工程配置文件 AndroidManefest.xml中找到;

     强制启动后,再通过awk找到$package进程对应的PID;


3.  通过run-as命令在非root权限下,启动package中的gdbserver, 并且attach到$PID进程。

      adb shell run-as $packagelib/gdbserver +debug-socket --attach $PID


4. 端口映射, 将本地端口5039映射到Android上的域套接字对应的端口

    adb forward tcp:5039 localfilesystem:/data/data/$package/debug-socket


5. Pull调试相关的filesobj/local/armeabi目录

    包括:/system/bin/app_process,/system/bin/linker, /system/lib/libc.so


6. 将GDB启动后需要进行的操作添加到obj/local/armeabi/gdb.setup文件

    其中gdb.setup是在编译阶段生成的(android-ndk-r8d/build/core/setup-toolchain.mk)gdb.setup默认有两个命令:

    set solib-search-path./obj/local/armeabi

    directory src-dir1src-dir2 ... src-dirN

    需要自己添加的操作包括:

    file./obj/local/armeabi/app_process

    target remove :5039

    set print object on

    可以根据需要,再添加其他命令,比如启动的是gdbtui,可以添加:

    winheight src 25

    focus cmd


7. 以gdb.setup为配置文件启动gdb

    arm-linux-androideabi-gdb/gdbtui-x ./obj/local/armeabi/gdb.setup

以下是一个例子,其中Activity可以在工程配置文件AndroidManifest.xml文件中找到,改成对应的名字即可:

#!/bin/sh 
#Author: Kyle(justbitguy@gmail.com)
#Date:2013-10-12

VERSION="4.0"

pid_for_package ()
{
   pack_name=$1
   _pid=`adb shell ps | awk -v PACKAGE="$pack_name" '
   BEGIN {
       FS=" "
   
       if (PACKAGE == "") {
           PACKAGE="com.google.android.apps.maps"
       }
   
       PID=0
       PID_COLUMN=2
    }

    {
       gsub("\r","",$NF)
       if (NR == 1) {
           for (n = 1; n <= NF; n++) {
               if ($n == "PID") {
                   PID_COLUMN=n;
               }
           }
       } else {
       if ($NF == PACKAGE) {
           PID=$PID_COLUMN
           }
       }
    }

   END {
       print PID 
   }
   '` 
   echo $_pid
}

#start of this script
###########################################

USAGE="usage: `basename $0` package"

if [ $# -lt 1 ]; then
   echo $USAGE 
   exit
fi

package=$1

if [ -z $package ]; then 
   echo $USAGE
   exit 13   
fi 

ARM_TYPE=armeabi 

APP_OUT=./obj/local/$ARM_TYPE
APP_PROCESS=$APP_OUT/app_process

DEBUGGER=`basename $0`
DEBUGGER_PATH=`which $DEBUGGER`
DEBUGGER_DIR=`dirname $DEBUGGER_PATH`
echo "debugger dir is $DEBUGGER_DIR"

GDBSERVER_PID=`pid_for_package lib/gdbserver`
echo "gdbserver pid is $GDBSERVER_PID"

if [ "$GDBSERVER_PID" != "0" ]; then 
    adb shell kill -9 $GDBSERVER_PID
fi

PID=`pid_for_package $package`

if [ "$PID" -eq "0" ]; then
## COMMAND: adb_cmd shell am start -n $package/$Activity
#Starting: Intent { cmp=$package/$Activity}
## COMMAND: adb_cmd shell sleep 2
    adb shell am start -n $package/$Activity
    adb shell sleep 5
    PID=`pid_for_package $package`
fi 

echo "$packge pid is $PID"


adb forward tcp:5039 localfilesystem:/data/data/$package/debug-socket
echo adb shell run-as $package lib/gdbserver +debug-socket --attach $PID
adb shell run-as $package lib/gdbserver +debug-socket --attach $PID > ~/.gdb.log &


#pull files from devices
#####################################
adb pull /system/bin/app_process $APP_OUT/app_process
echo "Pulled app_process from device/emulator."

adb pull /system/bin/linker $APP_OUT/linker
echo "Pulled linker form device/emulator."

adb pull /system/lib/libc.so $APP_OUT/libc.so
echo "Pulled libc.so from device/emulator."

#start gdb client
GDB_PREFIX=arm-linux-androideabi-
GDBCMD=${GDB_PREFIX}gdb
GDBSETUP=$APP_OUT/gdb.setup

cp -f ./libs/$ARM_TYPE/gdb.setup $GDBSETUP -v
echo "file $APP_PROCESS" >> $GDBSETUP
echo "target remote :5039" >> $GDBSETUP
echo "set print object on" >> $GDBSETUP

GDBCLIENT=$GDBCMD   
$GDBCLIENT -x $GDBSETUP






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值