休息了將近半年後,貓開始上班了,又開始忙碌的生活。
最近正在玩Android,被指派了解如何利用GDB來對Android device來除錯。網路上可以找到一些資訊,不過實地操作起來,仍不免有狀況。尤其是如何用arm-eabi-gcc成功編譯程式,簡單的Hello world執行檔放上Andriod device後執行為什麼會segmentation fault,google找解答看得我眼花撩亂。
這裡特地放上我怎麼在Andriod上使用GDB,並且附上參考聯結。
1 ADB全稱Android Debug Bridge,是android sdk裡的工具,可以直接操作管理android模擬器或者真實的android設備。通過adb我們可以在Eclipse中方面通過DDMS來調試Android程序,說白了就是debug工具。
adb的工作方式比較特殊採用監聽Socket TCP 5554等端口的方式讓IDE和Qemu通訊,默認情況下adb會daemon相關的網絡端口,所以當我們運行Eclipse時adb進程就會自動運行。
ADB是採Client-Server架構,client端是使用者在操作的電腦,server端則是android device。Client包含在SDK裡,device上不需安裝只需要在手機中打開選項Menu->Settings->Application->Development->USB debugging.
1.1 主要功能有
1.1.1 進行設備的shell
adb shell就可以進入模擬器的shell環境中。也可以執行各種Linux的命令,其命令格式為:adb shell command
範例:
adb shell dir 就是列舉目錄,在Linux中根目錄為/而不是Windows上的C磁碟、D磁碟
adb shell dmesg 會列印出Linux的debug訊息。
1.1.2 管理模擬器或設備的port映射(端口轉發?)
adb forward tcp:5555 tcp:1234 將delault的 tcp 5555 轉發到1234
1.1.3 計算機和設備之間上傳/下載文件
使用adb push android123.txt /tmp/android123.txt命令可以把SDK\Tools下的android123.txt文件傳輸到模擬器的/tmp/文件夾中,需要注意的是/tmp/文件夾中內容會在Android模擬器重新啟動時清空。通過adb pull /tmp/android123.txt android123.txt命令就會把模擬器的tmp文件夾下android123.txt文件回傳到電腦SDK\Tools目錄下。
1.1.4 將local apk軟體安裝置模擬器或android設備
adb install android123.apk,這樣名為android123的安裝包就會安裝到Android模擬器中,前提是android123.apk文件需要放到SDK\Tools目錄下。
1.2 Froyo的adb位置在out/host/linux-x86/bin
1.2.1 Cd out/host/linux-x86/bin
1.2.2 ./adb shell (也可以直接設定
export PATH=$PATH:/home/builder/project/Froyo/out/host/linux-x86/bin )
1.2.2.1.1 可能會出現
*daemon not running. Starting it now *
*daemon started successfully *
Error: device offline
1.2.2.1.2 執行
telnet localhost 5554
來進入emulator control console
(http://developer.android.com/guide/developing/tools/emulator.html#console)
telnet localhost 5554
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Android Console: type 'help' for a list of commands
OK
1.2.2.1.3 Exit 離開emulator control console後再執行adb shell可成功
1.3 參考資料
1.3.1 http://stenlyho.blogspot.com/2008/11/androidadb.html
1.3.2 http://blog.ben.idv.tw/2007/12/android-debug-bridge.html
1.3.3 http://www.cublog.cn/u3/97568/showart_1977014.html
1.3.4 http://developer.android.com/guide/developing/debug-tasks.html
2 GDB可以透過網路對target端的程式進行除錯,需要在target端(device)執行gdbserver以及在host端(local PC)執行控制gdbserver的gdb。Gdbserver 的source code較原來的gdb簡單,比較容易被porting到target上。現在Gdbserver已經包含在android source code中,就在prebuilt目錄下。
3 Android 的Gdbserver其二進位檔就在prebuilt/android-arm/gdbserver/下,只需把gdbserver這個可執行檔放在模擬器上即可
3.1 adb push /home/builder/project/Froyo/prebuilt/android-arm/gdbserver/gdbserver /system/bin
3.2 如果告知 Read-only file system的話,執行adb remount,因為default是用read-only
3.3 以Froyo來說,整包編譯完後,gdbserver就已經被放置在 out/target/product/generic/system/bin/,當emulator起來後,可以直接執行。
4 編譯測試程式
4.1 我們需要一個能夠在target端編譯的程式,因此要用cross-compiler。Android預設的cross compiler位置可以從envsetup.mk 檔中找到如下:
ABP:=$(ABP):$(PWD)/prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-eabi-4.4.0/bin
4.2 Froyo是使用arm-eabi-4.4.0,如果cross-compiler選用錯誤,會造成檔案被放上emulator後無法執行或執行過程segmentation fault。
4.3 在使用arm-eabi-gcc編譯前,要把toolchain加入path
export PATH=$PATH:/home/builder/project/Froyo/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin
4.4 假設寫一個測試程式Hello.c用arm-eabi-gcc來編譯,要編譯過至少要有以下的flag
arm-eabi-gcc -g -o Hello Hello.c -Wl,-rpath-link=/home/builder/project/Froyo/out/target/product/generic/obj/lib,-dynamic-linker=/system/bin/linker -I/home/builder/project/Froyo/ndk/build/platforms/android-5/arch-arm/usr/include -L/home/builder/project/Froyo/out/target/product/generic/obj/lib -nostdlib /home/builder/project/Froyo/out/target/product/generic/obj/lib/crtbegin_dynamic.o –lc
4.5 如果沒有加上-dynamic-linker=/system/bin/linker,編譯完後的執行檔放到emulator上後執行,會出現”not found”的錯誤訊息。
4.6 如果沒有-I,則編譯時可能會出現”error: stdio.h: No such file or directory”
4.7 因為要加入debug information讓gdb可以使用,compiler option上要加上-g。如果是編譯Android source,可以修改Android.mk,增加 ”LOCAL_CPPFLAGS+=-g” 或 ”LOCAL_CFLAGS+=-g”。如果沒有-g,使用break 指令時會看到 ” No symbol table is loaded. Use the "file" command.”
4.8 參考資料
4.8.1 編譯android原始碼到模擬器上執行 http://www.dotblogs.com.tw/neil/archive/2009/04/03/7838.aspx
4.8.2 Android 3D : use OpenGL ES 2.0 and NEON compiler options http://developer.qualcomm.com/blog/android-3d-use-opengl-es-20-and-neon-compiler-options
4.8.3 Android NDK http://developer.android.com/sdk/ndk/index.html
4.8.4 Hello World C program using Android Toolchain http://android-tricks.blogspot.com/2009/02/hello-world-c-program-on-using-android.html
4.8.5 Dynamically linked "Hello, world!" for Android http://honeypod.blogspot.com/2007/12/dynamically-linked-hello-world-for.html
4.8.6 [SOLVED] Need some help compiling http://forum.xda-developers.com/archive/index.php/t-680200.html
4.8.7
5 在emulator上啟動gdbserver
5.1 啟動emulator
5.2 在emulator上啟動gdbserver
5.2.1 從target的adb client端輸入adb shell (參考1.2)
5.2.2 在target端用gdbserver開啟要除錯的程式,並監聽某一個port,等待host端的gdb連線進來
5.2.2.1 gdbserver 10.0.2.2:1234 testprog
5.2.2.1.1 10.10.2.2是host端的IP,default 是10.0.2.2,1234是gdbserver監聽的port
5.2.2.1.2 如果啟動成功,會出現
Process /system/bin/libomstts created; pid = 1025
Listening on port 1234
5.2.2.1.3 如果testprog 有argument ,直接寫在test prog後面,例如:
#gdbserver 10.3.5.123:2345 testprog -o -v 123
5.2.2.2 如果要接觸一個已經存在的process,可以用
gdbserver 10.10.2.2:1234 –-attach your-desired-pid
5.3 為了讓gdb能連接到emulator gdbserver
5.3.1 從target的adb client端輸入
telnet localhost 5554
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Android Console: type 'help' for a list of commands
OK
redir add tcp:1234:1234
OK
exit
5.3.2 5554是emulator gdbserver的監聽port,以上命令是將所有到localhost:1234的數據轉發到emulator的1234 port。
5.3.3 如果沒有做redir,host在做 target remot時會出現” localhost:1234: Connection refused.”
6 最後在本機端(host)啟動gdb client
6.1 因為gdbserver只負責控制程式,但是關於程式碼內容和執行程式本身的資訊都還是由GDB負責,所以要先用GDB引入測試程式testprog。Arm-eabi-gdb是Android Froyo toolchain裡的gdb。
prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-gdb testprog
或者是
export PATH=$PATH:/home/builder/project/Froyo/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/
arm-eabi-gdb testprog
6.2 告訴gdb shard libraries的路徑,最好是絕對路徑
(gdb) set solib-search-path /home/builder/project/Froyo/out/target/product/generic/symbols/system/lib/
6.3 接著要連接到target,target remote target_IP:gdbserver_port
6.4 (gdb)Target remote localhost:1234
Remote debugging using localhost:1234
6.5 接下來就可以直接使用gdb的指令了
在一般的gdb中,執行程式用 ”r” (run),不過在這裡,由於已經利用trget remote連上gdbserver執行程式了,所以使用 “c” (contunue)指令,可以得到
(gdb) c
Continuing.
Error while mapping shared library sections:
/system/bin/linker: No such file or directory.
[New Thread 311]
[Switching to Thread 311]
Breakpoint 1, main () at Hello.c:4
4 printf("\n Hello!!!!\n");
(gdb)
7 參考資料
7.1 Debugging with GDB http://source.android.com/porting/debugging_gdb.html
7.2 Debug Native C/C++ Application for Android http://www.cppblog.com/luonjtu/archive/2009/02/19/74310.html
7.3 How to use gdbserver on android http://jovechia.blogspot.com/2009/04/how-to-use-gdbserver-on-android.html
7.4 Lab 5 debugger 和 Software emulator http://opencsl.openfoundry.org/Lab05_debugger.rst.html
7.5 Use gdbserver and gdb - remote debugging http://checko.blogspot.com/2006/05/use-gdbserver-and-gdb-remote-debugging.html
7.6 Debuggin Segmentation Faults and Pointer Problems http://www.cprogramming.com/debugging/segfaults.html
7.7 Gdbserver on android http://sunsetyang.eduol.cn/archives/2010/995588.html
7.8 GDB簡介
http://tetralet.luna.com.tw/index.php?op=ViewArticle&articleId=187&blogId=1
7.9 Android系統中調試動態連接庫so文件的步驟 http://blog.wjmjimmie.cn/2010/08/02/android%E7%B3%BB%E7%BB%9F%E4%B8%AD%E8%B0%83%E8%AF%95%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93so%E6%96%87%E4%BB%B6%E7%9A%84%E6%AD%A5%E9%AA%A4/
8 Note:
8.1 /home/builder/project/Froyo/是我Android source的根目錄,請更換成使用者自己跟目錄的路徑
留言列表