android ndk代码的调试本身还是有点麻烦的,因为本身google android的sdk
主要是面向广大的java程序员的,所以后来发布的 ADT 集成开发环境对java的代码调试
支持还是很好的,但是对于 ndk编写的so代码就没有那么直观的图形界面的调试工具了。
相信将来google肯定要开发出来 调试c/c++代码的图形调试工具,但是目前大多数刚开始
用ndk编写c或者c++代码的程序员调试的时候一般还是打log,然后再根据log来进行分析。
这种方法虽然简单,但是缺点也是很明显的,很多详细的信息不能调试,为了解决这个问题,
我写了这篇 android gdb 调试本地so的实例演示,以供大家参考。
做任何事情都是有代价的,用log调试的方法简单方便,用android gdb调试就需要记下一些
命令,并且做一些前期的准备工作了。
前期准备工作:
1 gdbserver 这个是需要放在android 手机里面的,一般放在 /system/bin/目录即可。
注意:直接从android源码编译出来的 gdbserver 放到android 手机中运行一般会crash的
官方的说法是 bionic 库不匹配导致,所以建议重新编译一个gdbserver。具体如何
编译 gdbserver 见我的另外一篇博客
http://sunzeduo.blog.51cto.com/2758509/1381552
2 对应版本的 androidgdb
比如我的gdbserver是
shell@android:/ # gdbserver --version GNU gdbserver (GDB) 7.3.1-gg2 Copyright (C) 2011 Free Software Foundation, Inc. gdbserver is free software, covered by the GNU General Public License. This gdbserver was configured as "arm-eabi-linux"
而使用的 android gdb应该是
root@ubuntu:~/Desktop# ./androidgdb --version 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://source.android.com/source/report-bugs.html>.
注意版本一致,而./androidgdb 需要你下载一个ndk里面有
我使用的在
/root/android/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gdb
这个路径里面
3 会使用常用gdb命令,具体命令的介绍,见我的另外一篇博文
http://sunzeduo.blog.51cto.com/2758509/1387538
4 一个自己写好的demo程序,这个我会放在附件中的,后面的调试都是以这个demo例子来进行的
这里先大概介绍一下 这个demo程序中 jni的文件,一共有三个文件,如下图
target.c 是一个服务器代码,随着代码启动而启动运行
socketclient.c 是个客户端代码,给java层提供jni接口
socketback.c 打酱油的不用管他
开始调试
前期准备的工作做好以后,可以开始调试了。
1 首先启动要调试的程序,ps 获取其进程号 (手机界面操作即可)
shell@android:/ # ps | busybox grep socketcomm u0_a66 26175 125 494016 50792 ffffffff 40090a40 S com.example.socketcomm root 27938 27933 860 336 c04fbc9c 4004a5f4 S /data/data/com.example.socketcomm/files/target
2 启动gdbserver attach到目标进程 (手机shell中操作)
shell@android:/ # gdbserver remote:1234 --attach 26175 Attached; pid = 26175 Listening on port 1234
其中 remote:1234 表示映射成tcp的1234端口,这个时候重新打开一个 adb shell 在ps com.example.socketcomm
发现
shell@android:/ # ps | busybox grep example u0_a66 26175 125 494016 50792 ffffffff 40090a40 t com.example.socketcomm root 27938 27933 860 336 c04fbc9c 4004a5f4 S /data/data/com.example.socketcomm/files/target
进程状态已经变成 t了,表示 attach已经成功了
3 启动gdb 来进行调试 (pc环境中操作,我用的是ubuntu系统)
root@ubuntu:~/Desktop# adb forward tcp:1234 tcp:1234
首先端口映射,映射成 1234 端口号
root@ubuntu:~/Desktop# ./androidgdb 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://source.android.com/source/report-bugs.html>. (gdb) target remote:1234 Remote debugging using :1234 0x40090a40 in ?? () (gdb)
这个时候已经进入 gdb了,当然现在还没有加载symbols 所以gdb的很多调试还不能用 输入 list
bt 这些命令还是不太直观或者不能使用
这里使用 file命令将symbols文件加载进来。因为我们有源代码,而本身android 源码ndk编译的时候
默认是加 -g选项的,没有被 strip的so库在
/root/android/temp/socketcomm/obj/local/armeabi
这个目录下,而在libs下的so是被 strip过的版本(strip剥光,表示去掉了symbols符号表的版本)
如下图:
(gdb) set solib-search-path /root/android/temp/socketcomm/obj/local/armeabi
这个命令将so 的路径设置一下
设置完成以后
(gdb) list socketclient.c:97 92 LOGI("read data fail !"); 93 return NULL; 94 } 95 96 97 buffer[recbytes]=‘\0‘; 98 LOGI("recv buff %s",buffer); 99 100 close(cfd);
发现已经有代码显示了
(gdb) b socketclient.c:97 Breakpoint 1 at 0x56dd7044: file jni/socketclient.c, line 97.
具体代码看 socketclient.c 这两行是接收到服务器打代码,然后通过logcat 打印出来的
我们在这里设置断点
(gdb) b socketclient.c:97 Breakpoint 1 at 0x56dd7044: file jni/socketclient.c, line 97.
继续执行
(gdb) c Continuing. [New Thread 26648] [Switching to Thread 26648] Breakpoint 1, Java_com_example_socketcomm_JniSocketClient_cliensocket ( env=0x56d7e870, thiz=<optimized out>, jstr=<optimized out>) at jni/socketclient.c:97 97 buffer[recbytes]=‘\0‘; (gdb) print buffer $1 = "server back buff 64", ‘\000‘ <repeats 1004 times> (gdb) bt #0 Java_com_example_socketcomm_JniSocketClient_cliensocket (env=0x56d7e870, thiz=<optimized out>, jstr=<optimized out>) at jni/socketclient.c:97 #1 0x4074de34 in ?? () #2 0x4074de34 in ?? () Backtrace stopped: previous frame identical to this frame (corrupt stack?)
ok 在断点处停止了,然后值也打出来了
更多调试技巧,需要看gdb的命令,demo程序见附件。