筆記:gdb透過網路debug目標裝置


1. 於目標裝置置入gdbserver

以AOSP為例, 在prebuilts目錄下有已經編譯好的gdbserver版本(64-bit要找gdbserver64),
$ find -name gdbserver
prebuilts/misc/android-arm/gdbserver
prebuilts/misc/android-arm/gdbserver/gdbserver
...
我手邊裝置是arm,從本機用adb push把gdbserver置入目標裝置中即可
adb push prebuilts/misc/android-arm/gdbserver/gdbserver /system/bin/
如果push不上去,應該是read-only狀態,需要先adb remount後再adb push上去

2. 啟動目標裝置上的gdbserver

啟動gdbserver有兩種不太一樣的debug模式如下:

Debug情境1. debug已在跑的Process

例如:假設已用ps確認要debug已在跑的程式recorder之PID為2947。
# ps | grep recorder
root      2947  2939  40352  11380 hrtimer_na b2656f50 S recorder
在目標裝置上執行gdbserver在port 9999等待gdb連線,並附掛上指定PID為2947之程式
# gdbserver :9999 --attach 2947
Attached; pid = 2947
Listening on port 9999

Debug情境2. 從啟動程式開始debug

例如:在目標裝置上用gdbserver直接啟動待debug的程式recorder,並帶入啟動參數http://www.google.com, 在port 9999等待gdb連線近來
# gdbserver :9999 recorder http://www.google.com
Process recorder created; pid = 3039
Listening on port 9999

注意:程式啟動參數無法從本機電腦端(gdb)給予,請記得在目標裝置端(gdbserver)給定

3. 於本機電腦安裝套件gdb-multiarch

如果你的裝置和本機電腦的架構是相同,兩者同為arm或是x86, 應是不需要額外裝套件,可跳過此步驟。

我手邊裝置的cpu架構是arm
$ cat /proc/cpuinfo
processor : 0
Processor : ARMv7 Processor rev 4 (v7l)
...

若是架構不同,你會需要在gdb端安裝gdb-multiarch
$ sudo apt-get install gdb-multiarch 

否則從本機電腦連接目標裝置時會出現像下面紅色標示問題
(gdb) target remote 10.0.0.200:9999
Remote debugging using 10.0.0.200:9999
warning: while parsing target description (at line 10): Target description specified unknown architecture "arm"
warning: Could not load XML target description; ignoring
Reading /system/bin/recorder from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /system/bin/recorder from remote target...
Reading symbols from target:/system/bin/recorder...(no debugging symbols found)...done.
Remote 'g' packet reply is too long: 7c358abe74358abe00000000ffffffff0100000000000000a8398abea2000000153c8abe00000000b8398abecc3a8abee83a8abe70358abefdb863b24c6f65b2100....

ref: https://stackoverflow.com/questions/53524546/

4. 使用gdb-multiarch從本機電腦連接目標裝置

啟動gdb-multiarch並輸入目標裝置IP,這裡以10.0.0.200為例,9999是前面步驟gdbserver時指定的port號

$ gdb-multiarch 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
...
Type "apropos word" to search for commands related to "word".
(gdb) target remote 10.0.0.200:9999
Remote debugging using 10.0.0.200:9999
Reading /system/bin/recorder from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /system/bin/recorder from remote target...
Reading symbols from target:/system/bin/recorder...done.
Reading /system/bin/linker from remote target...
...

設置local目錄加速載入

上面藍色標示是gdb自動從目標裝置取得debug所需的相關library和symbol資料,網路不夠快的話效率會很差,如果不想等待傳輸,建議是設定本機電腦上的目錄,讓gdb載入so和symbol資料。以AOSP來說,假設workspace建置出來的輸出目錄在/data/out中,該裝置的產品名是myprod。則請在gdb中設定solib-absolute-prefix和solib-search-path為

(gdb) set solib-absolute-prefix /data/out/target/product/myprod/symbols
(gdb) set solib-search-path /data/out/target/product/myprod/symbols/system/lib

Debug情境2. 從啟動程式開始debug

這個情境下要注意的是gdbserver一開始只會載入linker部份,不會完全啟動指定的程式,就像下面這樣:

(gdb) target remote 10.0.0.200:9999
Remote debugging using 10.0.0.200:9999
Reading /system/bin/recorder from remote target...
Reading symbols from target:/system/bin/recorder...done.
Reading /system/bin/linker from remote target...
Reading symbols from target:/system/bin/linker...(no debugging symbols found)...done.
0xb6f9977c in __dl__start () from target:/system/bin/linker
(gdb) i threads 
  Id   Target Id         Frame
* 1    Thread 2947.2947 "recorder" 0xb6f9977c in __dl__start () from target:/system/bin/linker
(gdb) i locals 
No symbol table info available.

建議這時候先設定一些中斷點,再按下c/continue開始運行程式。(遠端debug按r是沒有用的喔!)
(gdb) c
Continuing.
Reading /system/lib/liblog.so from remote target...
.....

5. 開始debug

這部份沒什麼好說的,就是和本機電腦debug一樣,指令都一樣,只是顯示library和程式的位址會寫target:開頭

(gdb) i s
#0  0xb3df08fc in sleep () from target:/system/lib/libc.so
#1  0x85162d42 in main (argc=, argv=) at packages/mytest/./recorder.c:175

(gdb) i threads 
  Id   Target Id         Frame
* 1    Thread 2947.2947 "recorder" 0xab1f8f4c in nanosleep () from target:/system/lib/libc.so
  2    Thread 2947.3015 "recorder" 0xab1c6454 in syscall () from target:/system/lib/libc.so
  3    Thread 2947.3016 "recorder" 0xab1f8f4c in nanosleep () from target:/system/lib/libc.so
...

(gdb) i shared
From        To          Syms Read   Shared Object Library
0xabbe5480  0xabc32c8c  Yes (*)     target:/system/bin/linker
0xaac7b840  0xaac83d80  Yes (*)    target:/system/lib/liblog.so
...

6. 離開debug

跟平常本機的debug一樣,用attach就detach

Debug情境1. debug已在跑的Process

(gdb) detach

Debug情境2. 從啟動程式開始debug

(gdb) kill

7. 重複使用gdb時的問題

本機debug時只要用r就可以重新再跑一次,
但是遠端debug不能這樣做,得再次target remote並給遠端位址,以上面為例:
(gdb) target remote 10.0.0.200:9999

然後,有時候會載入不了symbol,這時候其實程式是沒有正常被處理的,想要debug也沒有資料,所以只要遭遇程式的symbol載入不了,建議是載入symbol失敗就再執行一次相同target remote指令。

參考:
https://developers.redhat.com/blog/2015/04/28/remote-debugging-with-gdb/

留言