腳本使用方法
- gdb_native.sh 228 adb1
- gdb_native.sh 228
- 其中228代表要調試進程的pid,必須指定;
- adb1 指定你想使用的adb工具,也可以不指定adb。
#!/bin/bash
PROJECT_ROOT=$(dirname $_)
#set -x
BIN_BIT=64 # BIN_BIT=64 when bin is 64bit version
GDB=$PROJECT_ROOT/prebuilts/gdb/linux-x86/bin/gdb
# GDB=$PROJECT_ROOT/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-gdb
# maybe gdbserver64, if process is 64bit version
GDB_SERVER=gdbserver$BIN_BIT
OUT=$PROJECT_ROOT/out/target/product/flounder
usage () {
echo -e "\033[;35m Usage : $0 228\033[0m"
echo -e "\033[;35m Usage : $0 228 adb1 \033[0m"
}
if [ -n "$2" ] ;then
aadb=$2
else
aadb=/usr/bin/adb
fi
if [ -n "$1" ] ;then
process_pid=$1
else
process_pid=0
fi
ADB=$aadb
GDB_PORT=5028
# 0: setenforce 0
$ADB root
$ADB remount
$ADB shell setenforce 0
sleep 1
if [[ $process_pid = 0 ]]; then
echo -e "\033[;31merror: Process id must designated!!!\033[0m"
usage
exit 0
else
process_name=$($ADB shell ps $process_pid | grep $process_pid | awk -F '\/' '{print $4}')
fi
TARGET_NAME=$process_name # process name
TARGET_PID=$process_pid # process id
GDB_PARAMETER=/tmp/gdbinit.`whoami`
echo -e "\033[;33m check target name($TARGET_NAME) pid($TARGET_PID) \033[0m"
# kill old gdbserver
oldgdbserver=`$ADB shell ps | grep "gdbserver" | awk '{ print $2 }'`
if [[ 0$oldgdbserver != 0 ]]; then
$ADB shell kill -9 $oldgdbserver
fi
# 1: bringup gdbserver and attach to host process for wait clent to connet me
echo "1: $ADB shell $GDB_SERVER :$GDB_PORT --attach $TARGET_PID"
$ADB shell $GDB_SERVER :$GDB_PORT --attach $TARGET_PID &
# 2: 設置端口轉發
# 表示通過adb映射tcp端口1234,命令中前面的是local的端口,后面的是remote的端口。
echo "2: $ADB forward tcp:$GDB_PORT tcp:$GDB_PORT"
$ADB forward tcp:$GDB_PORT tcp:$GDB_PORT
sleep 3
# 3: 啟動gdb,并傳入參數
# echo "target remote:$GDB_PORT" > $GDB_PARAMETER
# echo "file $OUT/system/bin/$TARGET_NAME" >> $GDB_PARAMETER
# echo "set sysroot $OUT/symbols/" >> $GDB_PARAMETER
# echo "set dir $PROJECT_ROOT" >> $GDB_PARAMETER
echo "set solib-absolute-prefix $OUT/symbols/system/lib$BIN_BIT" > $GDB_PARAMETER
echo "set sysroot $OUT/symbols/" >> $GDB_PARAMETER
echo "set solib-search-path $OUT/symbols/system/lib$BIN_BIT/" >> $GDB_PARAMETER
echo "target extended-remote :$GDB_PORT" >> $GDB_PARAMETER
echo "3: $GDB -x $GDB_PARAMETER $OUT/symbols/system/bin/$TARGET_NAME"
$GDB -x $GDB_PARAMETER $OUT/symbols/system/bin/$TARGET_NAME
擴展功能
到這里對于剛接觸gdb調試同學也有了入門的知識,對于gdb老手估計是要玩飛的節奏
但是這里要說一下,如果要調試的是framework相關的進程的native代碼,可能會受到system server的watchdog的影響,1分鐘沒有及時響應操作就會觸發watchdog而kill到system server進程,zygote也會跟著掛掉,這里有個小技巧可以用一下,就是在調試的過程中,如果需要耗時查看一些運行時狀態,可以先執行
adb shell am hang
防止超時重啟,查看完畢想要繼續執行,就Ctrl+c終止掉am hang即可繼續執行,后面就重復這個過程即可。
另外還有一種方式就是用Android Studio在線調試,把斷點加在watchdog里面,配置gdb native調試。
gdb命令說明
- 顯示gdb命令幫助信息
help 顯示gdb命令種類
help subcommand 顯示subcommand的幫助信息
apropos word 搜索與word相關的命令
- 顯示調試界面
ctrl + X + A
- 設置斷點
b(break) 在函數或某一行處設置斷點
如果只記得部分函的前綴,可以這樣:(gdb) b make_ <按TAB鍵>。
break filename:linenum 在源文件filename的linenum行處停住
break filename:function 在源文件filename的function函數的入口處停住
break *address 在程序運行的內存地址處停住
break break命令沒有參數時,指在下一條指令處停住
break … If … 在條件成立時程序停住
break thread threadnum 定義在線程threadnum上的斷點,如break BootAnimation.cpp:364 thread 28 if bartab > lim
- 設置觀察點
watch expr 設置觀察點,當表達式expr的值變化時,程序停住
rwatch expr 設置觀察點,當表達式expr的值被讀時,程序停住
awatch expr 設置觀察點,當表達式expr的值被讀或寫時,程序停住
- 設置捕捉點
catch 設置被調試程序捕捉點,當event發生時,程序停住
catch catch [args] 捕捉一個C++捕捉到的異常
catch throw [args] 捕捉一個C++拋出的異常
catch syscall [args] 捕捉系統調用
- 維護被調試程序斷點
condition N COND 修改斷點號為N的停止條件為COND
ignore N COUNT 忽略斷點號為N的停止條件COUNT次
clear [linenum|funname|*] 清除指定的行或函數斷點
d(delete) [breakpoints][range] 清除指定的斷點
disable [breakpoints] [range…] 禁用指定的斷點
enable [breakpoints] [range…] 啟用指定的斷點
- 為停止點設定運行命令
commands N 調試程序在斷點號為N的斷點處停止后,執行命令
執行命令
end
- 顯示被調試程序的信息
info subcommand 顯示被調試程序的某些信息,可用help info查看子命令。如:
info breakpoints [n] 顯示所有斷點(或斷點n)信息
info watchpoints [n] 顯示所有觀察點(或觀察點n)信息
info program 查看被調試程序的執行狀態
info args 打印出當前函數的參數名及其值
info locals 打印出當前函數中所有局部變量及其值
info display 查看display設置的自動顯示的信息
info frame 查看棧幀信息,包括程序語言
- 運行及查看被調試信息
r(run) 運行被調試程序
c(continue) 從斷點出開始繼續執行直到結束或下一個斷點
s(step) 單步跟蹤,如果有函數調用,他會進入該函數。進入函數的前提是此函數被編譯有debug信息
n(next) 單步跟蹤,如果有函數調用,他不會進入該函數
p(print) 打印表達式的值
可以查看全局變量(所有文件可見)、靜態全局變量(當前文件可見)、局部變量(當前Scope可見)
p file::var 查看文件file中的變量var
p func::var 查看函數file中的變量var
p start@len 查看一段連續的內存空間的值,“@”的左邊是第一個內存的地址的值,“@”的右邊則你你想查看內存的長度,如:
int array = (int ) malloc (len * sizeof (int));
p *array@len
p/format expr 按指定的格式顯示表達式expr(format:x, d, f, c, u, o, t, a)
display[/fmt] expr 程序停下來后就會顯示expr的值
undisplay/delete displaynum/disable displaynum/enable displaynum
bt 查看當前函數調用堆棧信息
f(frame) 查看當前棧層信息,包括棧的層編號、當前的函數名、函數參數值、函數所在文件及行號和函數執行到的語句
finish 運行程序,直到當前函數完成返回
u(until) 運行程序直到退出循環體
- 顯示源代碼
l(list) 列出具體的函數或代碼行
list 顯示當前行后面的源程序
list - 顯示當前行前面的源程序
list + 顯示當前行后面的源程序
list linenum 顯示程序第linenum行的周圍的源程序
list file:filenum 顯示文件file中的filenum行
list file:func 顯示文件file中的函數func
list funcname 顯示函數名為function的函數的源程序,如list android::BootAnimation::movie
- 搜索源代碼
forward-search reg 利用正則表達式前向搜索源碼
search reg 利用正則表達式前向搜索源碼
reverse-search reg 利用正則表達式在全部源碼中進行搜索
- 設置被調試程序參數/gdb配置
set subcommand 設置gdb環境變量,可以使用help set查看set子命令。如:
set args 設置被調試程序運行參數
set directories 設置源文件搜索路徑,多個使用“:”分割
set solib-search-path 設置符號表搜索路徑
set environment varname [=value] 設置環境變量。如:set env USER=llj
set listsize num 設置一次顯示源代碼的行數
set step-mode on 打開step-mode模式,于是,在進行單步跟蹤時,程序不會因為沒有debug信息而不停住。這個參數有很利于查看機器碼
set print address on 打開地址輸出, 當程序顯示函數信息時,GDB會顯出函數的參數地址
set print array on 打開數組顯示,打開后當數組顯示時,每個元素占一行,如果不打開的話,每個元素則以逗號分隔
set print elements num 設置顯示數組元素的最大個數
set print null-stop on/off 如果打開了這個選項,那么當顯示字符串時,遇到結束符則停止顯示
set print pretty on/off 打開后gdb顯示結構體時會比較漂亮
set print sevenbit-strings 設置字符顯示,是否按“/nnn”的格式顯示
set print union on/off 設置顯示結構體時,是否顯式其內的聯合體數據
show subcommand 顯示調試器的信息,使用help show查看子命令。如:
show environment [varname] 查看環境變量
show listsize 顯示當前listsize的設置
show directories 顯示定義了的源文件搜索路徑
show language 查看gdb當前的語言環境
- 其他
q(quit) 退出gdb
handle 處理信號
- shell命令
此外gdb中可以執行shell命令,使用SHELL環境變量定義的可執行程序來執行shell命令,常用的命令如下:
show environment SHELL 查看shell執行程序
make 重新編譯程序,相當于shell make
cd 必變工作目錄,相當于shell cd
pwd 查看當前工具目錄,相當于shell pwd
-
調整程序線路
一旦使用GDB掛上被調試程序,當程序運行起來后,你可以根據自己的調試思路來動態地在GDB中更改當前被調試程序的運行線路或是其變量的值,這個強大的功能能夠讓你更好的調試你的程序,比如,你可以在程序的一次運行中走遍程序的所有分支。
修改變量的值
print x = 4 C/C++語法,把變量x的值修改為4
set var width=10 用gdb命令將參數width值修改為10
- 跳轉執行
jump +num 當前運行點向下偏移num行開始執行
jump linenum 從當前調試文件的linenum行開始執行
jump file:linenum 從file的linenum行開始執行
-產生信號量
singal SIGNAL 發送信號SINGAL給被調試程序
-強制函數返回
return 強制函數返回,忽略未執行的語句
return result 強制函數返回結果result,忽略未執行的語句
-強制調用函數
call func 調用當前程序中的函數
print func 調用當前程序中的函數