http://blog.sina.com.cn/s/blog_602f87700101c4r5.html
作者: Sam (甄峰) sam_code@hotmail.com
在嵌入式系统应用程序开发中,常见的调试方法就是print缩小差错范围,然后一步步找到出错点。这显然效率太低,所以不少人尝试使用GDBServer的方式调试。Sam之前也短暂使用过,但过后很多信息忘记了,现记录如下。
GDBServer+ 交叉编译-GDB 调试的主要思路是:
GDBServer运行在开发板上(目标机,目标平台)。 而 嵌入式GDB(如: arm-linux-gdb)则运行在开发机(宿主机)上。
如果目标机上没有GDBServer, 则需要下载GDBServer程序交叉编译。(Sam之前的Blog有过描述)我们现在把目标集中到Android开发平台上,据说在Android早期版本上,没有GDBServer。但在Sam手头的Android2.2上,已经有了GDBServer,呵呵,那就直接用吧。
例1:在Android平台使用GDBServer调试简单的应用程序:
Debug时,需要二进制文件中包含Debug信息,如符号Talbe, 调试段等。这就需要增加 -g 编译选项。且最好使用 -O0 (不做任何优化)。
1.1: 确保Debug信息齐全。
在Application.mk中:
APP_OPTIM := debug
此时编译:
/opt/Android_NDK/android-ndk-r8c/ndk-build -B V=1
这时,发现编译中,使用 -g 。 且最终使用 -O0。符合我们要求。
但请一定注意:ndk-build 将目标文件放到:/obj/local/armeabi-v7a/
然后copy了一份到lib/armeabi-v7a. 但又使用strip 去掉了这份二进制的调试信息,以减小其大小。
(strip 命令从 XCOFF 对象文件中有选择地除去行号信息、重定位信息、调试段、typchk 段、注释段、文件头以及所有或部分符号表)
所以,不能使用 lib/armeabi-v7a的库和可执行程序debug. 否则必然会报找不到符号表。
WARNING: no debugging symbols found in xxxx
可以通过objdump -t 来查看elf文件中是否包含Symbol Table.
1.2: 正式使用GDBServer调试:
首先说明Sam开发环境配置:
开发机是Fedora17-64. IP: 10.0.0.19
目标机是:Hi3716C. IP: 10.0.0.13
1.2.1:
首先在目标机上运行:
#gdbserver 10.0.0.19:1234 Test_Debug
解释如下:#gdbserver 开发机IP:监听Port 应用程序名
此时,目标机上显示:
Process Test_Debug created; pid = 3409
Listening on port 1234
1.2.2:
在开发机上进入obj/local/armeabi-v7a/目录,其中包含二进制文件,运行:
#/opt/Android_NDK/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb
Test_Debug
即使用Android NDK 所带的gdb 来调试Test_Debug.
因为当前二进制文件中包含符号列表,所以显示:
Reading symbols from /home/sam/work/current/Source/Test_Debug/obj/local/armeabi-v7a/Test_Debug...done.
(gdb)
这里则表明进入(gdb)模式。
此时,需要将开发机与目标机联起来调试。
(gdb) target remote 10.0.0.13:1234
解释:target remote 开发机IP:port
则显示:
Remote debugging using 10.0.0.13:1234
warning: Unable to find dynamic linker breakpoint function.
GDB will retry eventurally.
Meanwhile, it is likely
that GDB is unable to debug shared library initializers
or resolve pending breakpoints after dlopen().
0xb0001000 in ?? ()
(gdb)
此时:开发机上也显示
Remote debugging from host 10.0.0.19
gdb: Unable to get location for thread creation breakpoint: requested event is not supported
表明顺利连接。
下一步,基本所有动作都在开发机上完成。
(gdb) l
//列出代码
(gdb) b 20
//在20行加断点
(gdb) c
// 开始调试
(gdb) info break
//显示断点
(gdb) p i
//打印i 的内容
例2:调试动态库内容:
Debug时,需要二进制文件中包含Debug信息,如符号Talbe, 调试段等。这就需要增加 -g 编译选项。且最好使用 -O0 (不做任何优化)。
1.1: 确保Debug信息齐全。
在Application.mk中:
APP_OPTIM := debug
此时编译:
/opt/Android_NDK/android-ndk-r8c/ndk-build -B V=1
这时,发现编译中,使用 -g 。 且最终使用 -O0。符合我们要求。
1.2: 正式开始调试:
在目标机:
#gdbserver 10.0.0.19:1234 Test_Input_Event
显示:
Process Test_Input_Event created; pid = 2458
Listening on port 1234
在开发机:
#/opt/Android_NDK/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb Test_Input_Event
GNU gdb (GDB) 7.3.1-gg2
Copyright (C) 2011 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-linux-android".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/sam/work/current/Source/Test_Debug/obj/local/armeabi-v7a/Test_Input_Event...done.
此时,打开的符号Table是应用程序Test_Debug的.
(gdb)l
都显示的是主程序main.cpp的代码。
若想要打开动态库的,该怎么处理呢?
(gdb)
sharedlibrary
(gdb) file libInput_Event.so
Load new symbol table from "/home/sam/work/current/Source/Test_Debug/obj/local/armeabi-v7a/libInput_Event.so"? (y or n) y
Reading symbols from /home/sam/work/current/Source/Test_Debug/obj/local/armeabi-v7a/libInput_Event.so...done.
显示加载符号Table成功。
首先查看是什么.cpp文件内:
(gdb)info FUNCTION
All defined functions:
File /home/sam/work/current/Source/Test_Debug/jni/
Input_Event.cpp:
Input_Event_Rel Input_Event_Destroy();
Input_Event_Rel Input_Event_Init();
ssize_t Input_Event_ReadData(void*, Input_Event_Rel*);
void *thread_Input_Read_Data(void*);
(gdb)l
则开始显示动态库 Input_Event.cpp的代码。
(gdb) b 247
Breakpoint 1 at 0xd58: file /home/sam/work/current/Source/Test_Debug/jni/Input_Event.cpp, line 247.
在动态库中增加断电。显示成功。
但是有时候并不成功。则可以做以下动作:
(gdb) b 247
Cannot access memory at address 0x0
Cannot access memory at address 0xcc8
(gdb) b Input_Event.cpp 247
Function "Input_Event.cpp 247" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (Input_Event.cpp 247) pending.
这样则成功了。
调试动态库时,常常会调试不通。需要注意的是:
1.主机的目录结构和目标机尽量相同。
2.主机和目标机上的目录最好为777。
3.如果在动态库cpp中设置断点后无法c. 则可以先在main.cpp中设置断点,用c 启动后,再file library.
然后设置断点。
3. 一些奇怪问题的查找:
在Android Native C程序下,一些Signal 如段错误,浮点错误等有时候只是卡死,程序并不退出,所以也就无从谈起Core文件。
Sam有曾使用这个办法解决之:
程序使用gdbserver 和 arm-xxx-gdb 启动。
如果挂死,则使用bt 查看
调用栈帧, 看看调用顺序。
然后使用:
cat /proc/pid/maps 大致看看是在哪个函数里错误的。
或者:(gdb) info FUNCTION
看看对应函数是什么。
路径:
开发机是Fedora17-64. IP: 10.0.0.19
目标机是:Hi3716C. IP: 10.0.0.13
1.2.1:
首先在目标机上运行:
#gdbserver 10.0.0.19:1234 Test_Debug
解释如下:#gdbserver 开发机IP:监听Port 应用程序名
此时,目标机上显示:
Process Test_Debug created; pid = 3409
Listening on port 1234
1.2.2:
在开发机上进入obj/local/armeabi-v7a/目录,其中包含二进制文件,运行:
#/opt/Android_NDK/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb
Test_Debug
即使用Android NDK 所带的gdb 来调试Test_Debug.
因为当前二进制文件中包含符号列表,所以显示:
Reading symbols from /home/sam/work/current/Source/Test_Debug/obj/local/armeabi-v7a/Test_Debug...done.
(gdb)
这里则表明进入(gdb)模式。
此时,需要将开发机与目标机联起来调试。
(gdb) target remote 10.0.0.13:1234
解释:target remote 开发机IP:port
则显示:
Remote debugging using 10.0.0.13:1234
warning: Unable to find dynamic linker breakpoint function.
GDB will retry eventurally.
Meanwhile, it is likely
that GDB is unable to debug shared library initializers
or resolve pending breakpoints after dlopen().
0xb0001000 in ?? ()
(gdb)
此时:开发机上也显示
Remote debugging from host 10.0.0.19
gdb: Unable to get location for thread creation breakpoint: requested event is not supported
表明顺利连接。
下一步,基本所有动作都在开发机上完成。
(gdb)
set solib-search-path /opt/Android_NDK/android-ndk-r8c/platforms/android-8/arch-arm/usr/lib/
(gdb) c
直到出错,则看bt.