NDK包含了一个辅助脚本ndk-gdb使你能够轻松地为你的 由NDK产生的机器码 启动一个调试会话。
要求
想要调试本地层代码,你必须遵循如下的要求:
- 使用ndk-build脚本编译你的app。ndk-gdb脚本不支持使用传统的make APP=<name>这种方法的编译。
- 在你的AndroidManifest.xml文件中,通过在<application>元素中包含android:debuggable属性并将该属性设置为true来启用app调试。
- 编译你的app来在Android 2.2 (Android API level 8)或更新的版本上运行。
- 在一个运行了Android 2.2或更高版本android的设备或模拟器上调试。对于调试,你的AndroidManifest.xml文件中声明的target API level并不重要。
- 在一个Unix shell中开发你的app。在Windows上,使用Cygwin或试验性的ndk-gdb-py Python实现。
- 使用GNU Make 3.81或更高的版本。
- 如果你是在Eclipse中编译你的app,则请使用本本0.9.7或更高版本的ADT插件来编译。
用法
要调用ndk-gdb脚本,首先切换至应用程序目录或它的任何子目录下。比如:
cd $PROJECT
$NDK/ndk-gdb
在这里,$PROJECT指向你的项目的根目录,而$NDK指向了你的NDK的安装路径。
当你调用ndk-gdb时,它会配置会话来查找你的源文件及你已经生成的native libraries的symbol/debug版本。在成功attaching到你的应用进程之后,ndk-gdb输出一长串错误消息,提示它找不到各种系统libraries。这是正常的,因为你的主机不包含你的目标设备上这些libraries的symbol/debug版本。你可以安全地忽略这些消息。
接下来,ndk-gdb显示一个普通的GDB提示符。
你可以与ndk-gdb进行交互,就像与GNU GDB那样。比如,你可以使用b <location>来设置断点,及c (for "continue")来恢复执行。GDB命令的完整列表,请参考GDB 手册。
注意当你退出GDB提示时,你正在调试的应用进程也会停止。这是一个gdb限制。
ndk-gdb处理非常多的错误情况,并在它发现了一个问题时显示一个有益的错误消息。这些检查包括确保满足下列的条件:
- 检查ADB在你的path里。
- 检查你的应用程序在它的manifest里声明了debuggable。
- 检查设备上已经安装且具有同样包名的应用程序是可调试的。
默认情况下,ndk-gdb搜索一个已经运行的应用进程,如果找不到就显示一个错误。然而,你可以使用--start 或 --launch=<name>选项在调试会话之前自动地启动你的activity。更多详细信息,请参考选项部分。
选项
要查看选项的完整列表,则在命令行输入ndk-gdb --help。表1展示许多常用的选项,并伴有清晰的描述。
表1. 常见ndk-gdb选项及它们的描述
使用这个选项启动ndk-gdb将启动你的应用manifest中首个可启动的activity。使用--launch=<name>来启动下一个可启动的activity。要dump可启动的activities的列表,则在命令行运行--launch-list。
Option | Description> |
---|---|
--verbose | 这个选项告诉构建系统打印关于native-debugging会话建立的详细信息。这个选项只有在只有在调试 调试器无法连接app的问题,或ndk-gdb显示的信息不够时才需要。 |
--force | 默认情况下,ndk-gdb在发现有另外一个native debugging会话已经在相同的设备上运行时会自动退出。这个选项杀死另一个会话,并用新的替换。注意这个选项不杀死被调试的实际app,你必须另外杀死它。 |
--start | 当你启动ndk-gdb时,默认情况下它会试着去attach到目标设备上你的app一个已经在运行的实例上。你可以通过使用--start覆盖这个默认行为来显式地在调试会话之前在目标设备上启动应用程序。 |
--launch=<name> | 这个选项与--start类似,除了它允许你启动你的应用程序中一个特定actvitiy外。这个功能只有在你的manifest中定义了多个可启动activities时才有用。 |
--launch-list | 这个便利选项打印在你的app manifest中发现的可启动的activity名字的列表。--start使用第一个activity名字。 |
--project=<path> | 这个选项制定app工程目录。如果你想要启动脚本而不必须先切换到项目目录中,则它很有用。 |
--port=<port> | 默认情况下,ndk-gdb使用本地的TCP端口5039来与目标设备上它调试的app通信。使用一个不同的端口使你能够本地地调试连接到相同主机的不同设备或模拟器上运行的程序。 |
--adb=<file> | 这个选项指定了可执行的adb工具。只有在你没有把adb的路径设置进path时这个选项才有必要。 |
-d -e -s <serial> | 这些flags与adb命令的同名flags非常相似。如果你有多个设备或模拟器连接到你的主机则设置这些flags。它们的含义如下: -d 连接一个单独的物理设备。 -e 连接一个单独的模拟器设备。 -s <serial> 连接到一个特定的设备或模拟器。这里,<serial>是设备的名字,如同adb devices命令列出的那样。 或者你可以定义ADB_SERIAL环境变量来列出一个特定的设备,而不需要一个特别的选项。 |
--exec=<file> -x <file> | 这个选项告诉ndk-gdb在连接上它调试的进程之后执行在<file>中找到的GDB初始化命令。如果你想要做一些重复性的事情的话它很有用,比如设置一个断点的列表,然后自动地恢复执行。 |
--nowait | 禁止中断Java code直到GDB连接上。传入这个参数可能导致调试器丢失早期的断点。 |
--tui -t | 如果可用的话就启用Text User Interface。 |
--gnumake-flag=<flag> | This option is an extra flag (or flags) to pass to the ndk-build system when querying it for project information. You can use multiple instances of this option in the same command. |
--stdcxx-py-pr={auto|none|gnustdcxx[-GCCVER]|stlport} | Use specified Python pretty-printers for displaying types in the Standard C++ Library. auto mode works by looking at the .so files for alibstdc++ library, and as such only works for a shared library. When linking statically to a libstdc++ library, you must specify the required printers. The default is none. |
注意:这个表中最后的三个选项只有Python版本的ndk-gdb可用。
线程支持
如果你的app运行在一个比Android 2.3 (API level 9)更老的平台上,则ndk-gdb不能适当地调试本地线程。调试器只能调试主线程,abd完全忽略其它线程的执行。
使用一个版本早于2.3的Android将导致ndk-gdb在显示GDB提示符之前先显示下面的消息:
Thread debugging is unsupported on this Android platform!
如果你在一个非主线程中执行的函数中放置了一个断点,则程序将退出,而GDB将显示下面的消息:
Program terminated with signal SIGTRAP, Trace/breakpoint trap.
The program no longer exists.
Done。