使用ndk-gdb调试android native程序

《使用ndk-gdb调试android native程序》
作者: 游蓝海
文章链接: http://blog.csdn.net/you_lan_hai/article/details/50993437
转载请注明出处

虽然Eclipse可以调试android native程序,但是Eclipse启动和监测的线程太多(感觉都上百个了),导致数据同步很慢,还没走几步就卡崩了。
网上也有很多人向google反馈过调试太慢的问题,但是google给的回复是,他们没觉得native调试太慢,是被Eclipse搞慢的,他们建议使用ndk-gdb进行调试。
我以前没用过gdb调试,感觉很低效,比起Xcode的调试功能,android真是太落后了,没有合适的native调试工具。无奈代码在ios上运行正确,在android上就崩了,该面对的还是要面对。遂作此文,记录下调试过程。
我使用的操作系统是OSX,Windows系统上的操作类似,但需要安装Cygwin。

1.配置目标程序

  1. C++代码必须使用ndk-build编译,传入参数NDK_DEBUG=1。编译完成后,会在lib目录下生成gdbserver,供后续调试使用。
  2. 设置AndroidManifest.xml,在application项下面设置android:debuggable="true"
    <application
        android:debuggable="true">
        ...
    </application>

注意:是application项下面,别写到其他地方去了,我就被坑过。
3. 打包生成apk,然后安装到手机上。

2.启动ndk-gdb

  1. 在手机上启动上一步骤安装的程序,准备让ndk-gdb挂接。注意:手机需要root,否则ndk-gdb可能没有相关权限启动gdbserver。
  2. 进入工程目录,执行$NDK_PATH/ndk-gdb。ndk-gdb会分析当前目录下的AndroidManifest.xml文件,提取包名,并且判断是否是debuggable模式,然后自动连接包名对应的程序上。
    你的工程可能还需要提供参数NDK_MODULE_PATH=your_module_path
    如果启动失败,设置上参数--verbose,可以看到更详细的log。
    如果log显示ERROR: The device does not support the application's targetted CPU ABIs!,这是ndk-gdb脚本的bug,提取COMPAT_ABI失败了,换成python脚本$NDK_PATH/ndk-gdb.py重新执行。
  3. 如果启动成功,程序会被中断,在控制台上就可以输入gdb的命令了。
  4. ndk-gdb的部分参数说明
参数 说明
--verbose 开启verbose模式,可以看到ndk-gdb输出的详细调试信息。如果gdb总是启动失败,可以加上该参数,查看错误的原因。
--force 强制结束掉已经存在的调试连接。
--nowait app直接启动,不用等待调试器。默认情况下,app启动之后,会等待调试器挂接(attach)。该参数可与–delay配合使用。
--delay=<secs> 延迟若干秒之后,再挂接调试器。如果希望程序完全运行起来之后再挂接调试器,可以设置上--nowait参数,并且--delay设置上希望延迟的时间。
--start 重新启动app用于调试。默认情况下,gdb会挂接到已经启动了的app上。但是,直接挂接已经启动了的app可能会失败。
--launch=<name> --start功能相似。不同之处在于,--launch可以指定Android Activity。如果你的app存在多个Activity,该参数就比较合适。某些情况下,--start会获取到错误的Activity名称,也会导致启动失败。

3.使用gdb调试命令

ndk-gdb启动成功后,可能会频繁的出现SIG33中断,这个中断不是异常,使用下面的命令忽略掉就可以了。

(gdb) handle SIG33 nostop
(gdb) handle SIG33 noprint

某些情况下,在启动的时候,会一直报段错误(SIGSEGV),并且没有调用堆栈。此时可以一直使用命令c跳过,直到执行正常。
常用命令说明

命令名称 命令 说明
查看调用堆栈 backtrace 简写bt。如果程序中断或者崩溃,可以使用该命令查看当前的函数调用堆栈。然后结合frame参数,定位到对应的层次中。
跳转到堆栈 frame frame-number 简写f。如果想查看某层堆栈的变量,可以用该命令跳转到相应的层。
设置断点 break file:line file为文件名称,可以不含路径。line为行号
列出断点 info breakpoints 列出所有的断点,每个断点对应一个编号。可以使用delete命令删除编号对应的断点。
删除断点 delete breakpoint-number breakpoint-number为断点编号。
单步进入 step 简写s。逐个命令执行。
单步执行 next 简写n。逐行执行。
跳出当前函数 finish
继续执行 continue 简写c。程序恢复执行,直到遇到下个断点或者异常。
查看变量 print variable 简写p。打印变量值、地址、寄存器等,也可以执行函数,变量赋值等。
设置变量 set var name=value

更多gdb用法,可以参考文章尾部的链接[2]

参考链接:

  1. nkd-gdb官网:http://developer.android.com/ndk/guides/ndk-gdb.html
  2. gdb常用命令:http://elinux.org/GDB
原文地址:https://www.cnblogs.com/ygxsk/p/7693977.html