Android 系统中使用GDB调试C程序
Android 系统中使用GDB调试C程序
调试环境说明:
操作系统:Ubuntu 11.10 32bit
Android源码版本:Android 4.0.3 r1
Emulator:Android4.0.3
注:本文以调试Android源码自带的memtest程序做为例子,调试前已经编译过一次Android源码,编译目标是full-eng,如何编译源码,如何使用编译得到的镜像启动模拟器这里就略过了
1. 准备工作:
启动模拟器
#emulator –system ~/system.img –data ~/userdate.img –ramdisk ~/ramdisk.img –kernel ~/kernel-qeum-armv7
2. 安装没有被strip的memtest到模拟器
使用gdb调试程序,则被调试程序必须带有调试信息,Android编译源码时默认带有调试信息,,但是最后生成的系统文件中的程序和库还是会被strip,但是out目录里面还是存放了带有调试信息的程序,下面会介绍。
这里假设你已经执行了一次源码编译,那么源码自带的memtest程序也会被编译
Memtest的源码存放路径为:
~/source_code/system/extras/tests/memtest
编译后没有strip的可执行程序路径一般为:
~/source_code/out/target/product/generic/obj/EXECUTABLES/memtest_intermediates/LINKED/
进入到上述目录,将memtest程序push到模拟器/data/bin下(事先在data下建立bin目录)
#adb push memtest /data/bin
3. 启动gdbserver
我们编译出来的系统都已经自带了gdbserver,如果没有,例如真机,可以在prebuilt里面找到编译好的安装上去
这里我们直接在adb shell中启动gdbserver
#gdbserver :1234 /data/bin/memtest
正常的话应该显示:
Process /data/bin/memtest created; pid = 571
Listening on port 1234
4. 启动arm-eabi-gdb进行调试
然后在另一个终端里面启动gdb客户端
A.首先设置模拟器端口转发:
#adb forward tcp:1234 tcp:1234
B. 启动arm-eabi-gdb:
在Android源码的prebuilt/linux-86/toolchain/arm-eabi-4.4.3/bin下面有这个程序,当然你也可以选择其他版本的gdb,argc为程序参数
# ~/source_code/prebuilt/linux-86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-gdb ~/source_code/out/target/product/generic/obj/EXECUTABLES/memtest_intermediates/LINKED/memtest [args]
正常启动后会显示:
GNU gdb (GDB) 7.1-android-gg2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-elf-linux".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /work_dir/android4.0.3/out/target/product/generic/obj/EXECUTABLES/memtest_intermediates/LINKED/memtest...done.
(gdb)
C. 执行set solib-xxx 这两个命令,建立符号链接
(gdb) set solib-absolute-prefix ~ /out/target/product/generic/symbols/
(gdb) set solib-search-path ~/out/target/product/generic/symbols/system/lib/
D.连接gdbserver进行调试:
(gdb) target remote :1234
成功的话显示:
Remote debugging using :1234
Reading symbols from /work_dir/android4.0.3/out/target/product/generic/symbols/system/bin/linker...done.
Loaded symbols for /work_dir/android4.0.3/out/target/product/generic/symbols/system/bin/linker
__dl__start () at bionic/linker/arch/arm/begin.S:35
35 mov r0, sp
(gdb)
另一个控制台会显示:Remote debugging form host 127.0.0.1
如果没执行set solib-×××的两个命令会显示如下信息:
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
0xb0000100 in ?? ()
5. 最后终于可以进行gdb调试了
Gdb调试工具是基于命令行的,调试命令可以参考如下连接:
http://blog.csdn.net/dadalan/article/details/3758025
设置断点命令:breakpoint n或b n,n为程序行号或是函数名称,例如在main函数出打上断点
(gdb) b main
Breakpoint 1 at 0xa504: file system/extras/tests/memtest/memtest.cpp, line 107.
从断点开始继续执行:continue 或c,例如:
(gdb) c
Continuing.
Breakpoint 1, main (argc=1, argv=0xbea51c84)
at system/extras/tests/memtest/memtest.cpp:107
107 if (argc == 1) {
单步执行:next 或 n ,例如:
(gdb) n
106 {
(gdb) n
107 if (argc == 1) {
(gdb) n
108 usage(argv[0]);
(gdb) n
109 return 0;
打印变量值:print param 或 p param,param为变量名,例如打印argc的值:
(gdb) p argc
$1 = 1
含有很多有用的命令,查看当前运行程序的源码:list或l,查看函数堆栈:bt,查看断点信息:info break,设置观察点:watch,退出gdb:q,终止程序:kill。
程序调试运行完后,启动gdbserver的客户端会打印程序的运行结果,并停止server,如果要重新开始调试,不要忘了先启动gdbserver,再启动gdbclient。
这里只介绍了Android gdb简单的使用方法,还有很多东西可以研究,例如调试动态库so,当然gdb本身还是有很多研究的地方的,甚至有着图形化工具不能完成的功能。有机会继续研究~