使用GDB进行Android Native调试

时间:2024-04-01 22:31:25

使用脚本工具快速进行Android Native调试。

安装android_gdbserver_attach脚本

使用GDB远程调试指定Android进程的时候,经常要查询pid,然后再attach。为了简化步骤,就写了个脚本。
file name: android_gdbserver_attach

#!/usr/bin/env bash
gdbServerPid=`adb shell ps | grep gdbserver | awk '{print $2}'`

if [[ "" != ${gdbServerPid} ]]; then
    adb shell su -c "kill ${gdbServerPid}"
fi

adb forward tcp:1234 tcp:1234

if [[ `adb shell whoami` == 'root'  ]]; then
    is_root=true
fi

if [[ -n $1 ]]; then
    OLDIFS=$IFS
    IFS='
'
	grepPsResult=(`adb shell ps | grep $1 | awk '{print $1"\t"$2"\t"$9}'`)
    IFS=$OLDIFS
    NUMPIDS=${#grepPsResult[@]}
    declare -a appPid
    for (( x=0; x < $NUMPIDS; x++ )); do
	    appPid[x]=`echo ${grepPsResult[x]} | awk '{print $2}'`
    done
    selectedPid=0
    if [[ 0 -eq "$NUMPIDS" ]]; then
	    echo "No this process name - nothing to do."
	    exit 0;
    elif [[ 1 -eq "$NUMPIDS" ]]; then
	    # Just one process
        selectedPid=${appPid[0]}
    else
        # Select one process
        echo "Multiple processes detected, please select one"
        for (( x=0; x < $NUMPIDS; x++ )); do
            echo -e "$[x+1]: ${grepPsResult[x]}"
        done
        echo -n "> "
        read USER_CHOICE

        # Validate user entered a number
        if [[ $USER_CHOICE =~ ^[0-9]+$ ]]; then
            echo "Selected Process : ${grepPsResult[$USER_CHOICE-1]}"
            selectedPid=${appPid[$USER_CHOICE-1]}
        else
            echo "You must enter a number"
            exit 0;
        fi
    fi
    adb forward tcp:12345 jdwp:${selectedPid}

	if [[ $is_root == true  ]]; then
        adb shell gdbserver :1234 --attach ${selectedPid}
    else
        adb shell su -c "gdbserver :1234 --attach ${selectedPid} "
    fi
else
	echo "Please input the name of the process to be debugged (app's process name is the package name)。Example: $0 <process name>"
fi

GDB调试正在运行的App进程

  1. 使用脚本attach到指定的进程
    脚本后面输入进程名,如果发现多个匹配,就会出现选择列表,输入数字选择即可
    $ android_gdbserver_attach gms
    Multiple processes detected, please select one
    1: u0_a40	1584	com.google.android.gms.persistent
    2: u0_a40	2039	com.google.android.gms
    3: u0_a40	3244	com.google.android.gms.unstable
    4: u0_a40	25548	com.google.android.gms.ui
    > 2
    Selected Process : u0_a40	2039	com.google.android.gms
    Attached; pid = 2039
    Listening on port 1234
    
  2. 使用gdb或者clion remote gdb 连接本地端口1234即可

GDB在App启动阶段进行调试

  1. 以等待调试的方式启动App

    adb shell am force-stop <包名> && adb shell am start -n
    “<包名>/<启动的Activity名>” -a android.intent.action.MAIN -c
    android.intent.category.LAUNCHER -D

    例如

    $ adb shell am force-stop com.kevin.jni.jniworld && adb shell am start -n "com.kevin.jni.jniworld/com.kevin.jni.jniworld.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -D
    

    出现如下图对话框
    使用GDB进行Android Native调试

  2. 使用android_gdbserver_attach脚本attach到改进程

    $ android_gdbserver_attach com.kevin.jni.jniworld                                                                                                                                                                             
    Attached; pid = 7578
    Listening on port 1234
    
  3. 使用gdb或者CLion remote gdb 连接本地端口1234即可
    这里以CLion GDB Remote 配置截图
    使用GDB进行Android Native调试
    连接成功如下图所示
    使用GDB进行Android Native调试

  4. 通过jdb attach进程
    为了让App继续运行,结束Waiting。需要通过jdb attach 该进程。jdwp端口转发已经在脚本中执行了(第50行)。所以这里直接attach即可

    $ jdb -attach localhost:12345
    Set uncaught java.lang.Throwable
    Set deferred uncaught java.lang.Throwable
    Initializing jdb ...
    > 
    
  5. 程序就会在断点处停下来,现在就可以开始愉快的调试了
    使用GDB进行Android Native调试