YangMing +

android的NDK调试常见问题

遇到的问题

https://developer.android.com/tools/sdk/ndk/index.html#Installing

用GDB进行so调试

编译

  1. 要有没有strip的so strip命令位置: toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/arm-linux-androideabi/bin/strip 注意strip前要保留原来的so文件,以后调试时需要使用
  2. 其他: 用nm命令 可以列出so内的符号,可以用于查看so是否有符号,如 nm xx.so

GDB 调试so

需要的文件: gdbserver 位置:android-ndk-r8b/prebuilt/android-arm/gdbserver/gdbserver gdb 位置:android-ndk-r8b/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb 步骤:

  1. apk 打开调试开关, AndroidManifest.xml 中, application节点 加入 android:debuggable="true",
  2. 如果是root的机器,apk没有打开调试开关也可以进行调试,如果是已经root的机器,把gdbserver放到系统(手机)的目录下(可以随意放置,一般放到system/bin目录下方便输入命令)
  3. 如果是没有root的机器,需要把gdbserver打到apk的包里(放到lib目录下),这样安装apk的的时候会把gdbserver拷贝到/data/data/app名称/lib/gdbserver
  4. 启动apk,可以直接启动
  5. 用 adb shell 进行控制台,用ps命令查看app的进程id
  6. 如果是root机器,可以su后,直接用gdbserver attach ,命令行是 gdbserver :端口号 --attach pid 如 : su gdbserver :2345 --attach pid
  7. 如果是未root机器,只能用以下方式 run-as app名称 lib/gdbserver :端口号 --attach pid
  8. 在pc上运行adb forward tcp:端口号(指PC上的端口) tcp:端口号(手机上的端口) 建立端口映射
  9. 把/system/bin/app_process /system/bin/linker, /system/lib/libc.so 从手机上拷贝出来(可以用adb pull 命令),其他so文件也拷贝出来也行,我们假定拷贝的目录为$lib
  10. 运行arm-linux-androideabi-gdb ,输入以下命令序列 file $lib/app_process $lib目录中有从手机拷贝出来的app_process,linker和libc.so这些文件 ,如我放到了/home/qrf/android_ndk_debug/mydev目录下

    set solib-absolute-prefix $nostriplib_dir $nostriplib_dir是存放了没有strip的so的目录,如 set solib-absolute-prefix /home/qrf/code/cmso

    set solib-search-path $lib:$nostriplib_dir 如set solib-search-path /home/qrf/android_ndk_debug/mydev:/home/qrf/code/cmso

    target remote :端口号 连上gdbserver

    dir source 指定源码路径 后面就是gdb调试的问题了,进入gdb调试界面可以用ctrl x + a 来切换到文本模式(可以查看源码), 如果要配合ddd前端, 用apt-get install ddd ,然后 用ddd --debugger arm-linux-androideabi-gdb 使用,但是ddd有时会不太灵光,还是直接使用gdb比较方便

附一些常用的gdb命令:

backtrace/bt    //列出当前线程堆栈

thread apply all bt //列出所有线程调用堆栈

thread 线程号//切换线程上下文

ctrl x+a //切换到源码浏览窗口 ,再按ctrl x+a 切换回去

ctrl c //中断当前运行

c/continue //继续运行

info sharedlibrary //列出so加载列表

info threads //列出线程列表

info locals //列出当前堆栈上的局部变量

info breakpoints //列出断点

print 变量名 //列出变量内容 

print 变量名= //修改变量名的值

b/break 源码文件名:行号 //下断点

d/delete 断点id //删除断点

f/frame 栈帧序号 //切换到指定的栈帧 如 f 0 顶层

s/step //下一步,有函数调用会进入

n/next //下一步,有函数调用不会进入

fin/finish //返回到上层函数调用

disable 断点id  //禁用断点

enable 断点id  //启用断点

disassemble/disas //查看汇编代码
评论:

Blog

Opinion

Project