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 --versionGNU gdbserver (GDB) 7.3.1-gg2Copyright (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 --versionGNU gdb (GDB) 7.3.1-gg2Copyright (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.socketcommroot 27938 27933 860 336 c04fbc9c 4004a5f4 S /data/data/com.example.socketcomm/files/target


2 启动gdbserver attach到目标进程 (手机shell中操作)


shell@android:/ # gdbserver remote:1234 --attach 26175Attached; pid = 26175Listening on port 1234


其中 remote:1234 表示映射成tcp的1234端口,这个时候重新打开一个 adb shell 在ps com.example.socketcomm
发现


shell@android:/ # ps | busybox grep exampleu0_a66 26175 125 494016 50792 ffffffff 40090a40 t com.example.socketcommroot 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# ./androidgdbGNU gdb (GDB) 7.3.1-gg2Copyright (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:1234Remote debugging using :12340x40090a40 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:9792 LOGI("read data fail !");93 return NULL;94 }959697 buffer[recbytes]='\0';98 LOGI("recv buff %s",buffer);99100 close(cfd);

发现已经有代码显示了


(gdb) b socketclient.c:97Breakpoint 1 at 0x56dd7044: file jni/socketclient.c, line 97.


具体代码看 socketclient.c 这两行是接收到服务器打代码,然后通过logcat 打印出来的

我们在这里设置断点

(gdb) b socketclient.c:97Breakpoint 1 at 0x56dd7044: file jni/socketclient.c, line 97.

继续执行

(gdb) cContinuing.[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:9797 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程序见附件。



附件:http://down.51cto.com/data/2364249