gdb和gdbserver除錯android應用與可執行
學習android5.0以後的ART虛擬機器,看了看原始碼,比較頭疼,決定通過動態除錯的方式去學習。
Art虛擬機器有一個dex2oat的可執行程式。就想到了通過gdb和gdbserver來debug這個dex2oat。
記錄一下除錯方法:
gdb執行在本地系統(windows/linux)
gdbserver執行在android真機/模擬器上(adb shell ls /system/bin檢視是否有gdbserver,如果沒有,可以從原始碼prebuild資料夾中獲取,也可以從ndk的檔案中獲取)
Ps:gdb和gdbserver的版本要一致,不然會出錯的
一:“
1,準備工作:
1-1,在prebuild資料夾中找到gdb和gdbserver的可執行檔案(ndk中也有)
1-2,把gdbserver 通過adb shell push進system/bin
1-3,把dex2oat需要的hello.jar給push到/data/test/中
2,通過adb在android模擬器中通過gdbserver關聯相關的程序或者啟動相關程序
2-1,gdbserver關聯相關的程序 : adb shell gdbserver :埠號1234--attach 程序pid
(程序pid可以通過adb shell ps檢視,除錯應用可以attach system_process(沒有測試))
2-2,gdbserver啟動相關的程序: adb shell gdbserver :埠號1234
file=/data/test/hello.jar --oat-file=/data/test/hello.dex
3,埠對映:
在本地命令列:adb forward tcp:1234 tcp:1234
4,進行gdb所在目錄,啟動gdb
4-1,cd /home/zero/android-5.0.0_r3.0.1/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin
4-2,./arm-linux-androideabi-gdb
5,進入了GDB以後:
5-1,(gdb)target remote localhost:1234 (連線目標)
5-2,(gdb)file /home/zero/android-5.0.0_r3.0.1/out/target/product/generic/symbols/system/bin/dex2oat (找到可執行檔案dex2oat,都是在android原始碼的這個bin目錄下的,一般的使用者程序使用app_process)
5-3,(gdb)set solib-absolute-prefix /home/zero/android-5.0.0_r3.0.1/out/target/product/generic/symbols (不懂為什麼要有這句)
5-4,(gdb)set solib-search-path /home/zero/android-5.0.0_r3.0.1/out/target/product/generic/symbols/system/lib (設定可函式路徑??)
6,設定斷點 ,開始執行
6-1,(gdb)b main
6-2,(gdb) c
二:gdbclient與gdb1,在原始碼目錄執行:
1-1,source build/envsetup.sh
1-2,lunch full-eng
2,類似上面的gdbserver的啟動和adb forward的埠對映
3,啟動gdbclient
gdbclient dex2oat :1234
4,設定斷點,開始除錯
envsetup.sh中關於gdbclient的原始碼
<span style="font-size:18px;"># gdbclient now determines whether the user wants to debug a 32-bit or 64-bit
# executable, set up the approriate gdbserver, then invokes the proper host
# gdb.
function gdbclient()
{
local OUT_ROOT=$(get_abs_build_var PRODUCT_OUT)
local OUT_SYMBOLS=$(get_abs_build_var TARGET_OUT_UNSTRIPPED)
local OUT_SO_SYMBOLS=$(get_abs_build_var TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED)
local OUT_VENDOR_SO_SYMBOLS=$(get_abs_build_var TARGET_OUT_VENDOR_SHARED_LIBRARIES_UNSTRIPPED)
local OUT_EXE_SYMBOLS=$(get_symbols_directory)
local PREBUILTS=$(get_abs_build_var ANDROID_PREBUILTS)
local ARCH=$(get_build_var TARGET_ARCH)
local GDB
case "$ARCH" in
arm) GDB=arm-linux-androideabi-gdb;;
arm64) GDB=arm-linux-androideabi-gdb; GDB64=aarch64-linux-android-gdb;;
mips|mips64) GDB=mips64el-linux-android-gdb;;
x86) GDB=x86_64-linux-android-gdb;;
x86_64) GDB=x86_64-linux-android-gdb;;
*) echo "Unknown arch $ARCH"; return 1;;
esac
#引數1<span style="white-space:pre"> </span>
if [ "$OUT_ROOT" -a "$PREBUILTS" ]; then
local EXE="$1"
if [ "$EXE" ] ; then
EXE=$1
if [[ $EXE =~ ^[^/].* ]] ; then
EXE="system/bin/"$EXE
fi
else
EXE="app_process"
fi
#引數2<span style="white-space:pre"> </span>
local PORT="$2"
if [ "$PORT" ] ; then
PORT=$2
else
PORT=":5039"
fi
local PID="$3"
if [ "$PID" ] ; then
if [[ ! "$PID" =~ ^[0-9]+$ ]] ; then
PID=`pid $3`
if [[ ! "$PID" =~ ^[0-9]+$ ]] ; then
# that likely didn't work because of returning multiple processes
# try again, filtering by root processes (don't contain colon)
PID=`adb shell ps | \grep $3 | \grep -v ":" | awk '{print $2}'`
if [[ ! "$PID" =~ ^[0-9]+$ ]]
then
echo "Couldn't resolve '$3' to single PID"
return 1
else
echo ""
echo "WARNING: multiple processes matching '$3' observed, using root process"
echo ""
fi
fi
fi
adb forward "tcp$PORT" "tcp$PORT"
local USE64BIT="$(is64bit $PID)"
adb shell gdbserver$USE64BIT $PORT --attach $PID &
sleep 2
else
echo ""
echo "If you haven't done so already, do this first on the device:"
echo " gdbserver $PORT /system/bin/$EXE"
echo " or"
echo " gdbserver $PORT --attach <PID>"
echo ""
fi
OUT_SO_SYMBOLS=$OUT_SO_SYMBOLS$USE64BIT
OUT_VENDOR_SO_SYMBOLS=$OUT_VENDOR_SO_SYMBOLS$USE64BIT
echo >|"$OUT_ROOT/gdbclient.cmds" "set solib-absolute-prefix $OUT_SYMBOLS"
echo >>"$OUT_ROOT/gdbclient.cmds" "set solib-search-path $OUT_SO_SYMBOLS:$OUT_SO_SYMBOLS/hw:$OUT_SO_SYMBOLS/ssl/engines:$OUT_SO_SYMBOLS/drm:$OUT_SO_SYMBOLS/egl:$OUT_SO_SYMBOLS/soundfx:$OUT_VENDOR_SO_SYMBOLS:$OUT_VENDOR_SO_SYMBOLS/hw:$OUT_VENDOR_SO_SYMBOLS/egl"
echo >>"$OUT_ROOT/gdbclient.cmds" "source $ANDROID_BUILD_TOP/development/scripts/gdb/dalvik.gdb"
echo >>"$OUT_ROOT/gdbclient.cmds" "target remote $PORT"
# Enable special debugging for ART processes.
if [[ $EXE =~ (^|/)(app_process|dalvikvm)(|32|64)$ ]]; then
echo >> "$OUT_ROOT/gdbclient.cmds" "art-on"
fi
echo >>"$OUT_ROOT/gdbclient.cmds" ""
local WHICH_GDB=
# 64-bit exe found
if [ "$USE64BIT" != "" ] ; then
WHICH_GDB=$ANDROID_TOOLCHAIN/$GDB64
# 32-bit exe / 32-bit platform
elif [ "$(get_build_var TARGET_2ND_ARCH)" = "" ]; then
WHICH_GDB=$ANDROID_TOOLCHAIN/$GDB
# 32-bit exe / 64-bit platform
else
WHICH_GDB=$ANDROID_TOOLCHAIN_2ND_ARCH/$GDB
fi
gdbwrapper $WHICH_GDB "$OUT_ROOT/gdbclient.cmds" "$OUT_EXE_SYMBOLS/$EXE"
else
echo "Unable to determine build system output dir."
fi
}
</span>
Ps,1,通過指令碼方便除錯:
source XXXX
XXXX:
define envset
target remote localhost:1234
file /home/zero/aa/android-5.0.0_r3.0.1/out/target/product/generic/symbols/system/bin/dex2oat
set solib-absolute-prefix /home/zero/aa/android-5.0.0_r3.0.1/out/target/product/generic/symbols
set solib-search-path /home/zero/aa/android-5.0.0_r3.0.1/out/target/product/generic/symbols/system/lib
set breakpoint pending on
end
define argsSet
set args --runtime-arg -classpath --runtime-arg hello.jar --instruction-set=arm --runtime-arg -Xrelocate --host --boot-image=/home/zero/aa/android-5.0.0_r3.0.1/out/target/product/generic/system/framework/boot.art --dex-file=hello.jar --oat-file=/home/zero/aa/android-5.0.0_r3.0.1/out/oatfiles/arm/hello.oat
end
define bb1
b frontend.cc:625 if method_idx==3
end
3,通過shell指令碼(.sh)定義環境變數,然後使用gdb除錯:
#!/bin/sh
CWD=`pwd`
export ANDROID_DATA="${CWD}/out/host/datadir/dalvik-cache/x86_64"
export ANDROID_ROOT="${CWD}/out/host/linux-x86"
BOOT_IMAGE="${CWD}/out/target/product/generic/system/framework/boot.art"
OUTPUT="${CWD}/out/oatfiles/arm"
#read x
#mkdir -p $OUTPUT
#mkdir -p $ANDROID_DATA
#exec gdb
exec gdb out/host/linux-x86/bin/dex2oat