ndk-gdb

NDK 包含一个名为 ndk-gdb 的 Shell 脚本,可以启动命令行原生调试会话。喜欢使用 GUI 的用户应改为阅读在 Android Studio 中调试这篇文档。

要求

要运行命令行原生调试,必须满足以下要求:

  • 使用 ndk-build 脚本编译您的应用。ndk-gdb 脚本不支持使用旧的 make APP=<name> 方法进行编译。
  • 添加可将 android:debuggable 属性设为 true<application> 元素,从而在 AndroidManifest.xml 文件中启用应用调试。
  • 编译可在 Android 2.2(Android API 级别 8)或更高版本上运行的应用。
  • 在运行 Android 2.2 或更高版本的设备或模拟器上进行调试。在 AndroidManifest.xml 文件中声明的目标 API 级别对于调试而言并不重要。
  • 在 Unix shell 中开发您的应用。在 Windows 上,请使用 Cygwin 或实验性 ndk-gdb-py Python 实现。
  • 使用 GNU Make 3.81 或更高版本。

用法

要调用 ndk-gdb 脚本,请切换到应用目录或该目录下的任何目录。例如:

    cd $PROJECT
    $NDK/ndk-gdb
    

此处,$PROJECT 指向您项目的根目录,而 $NDK 则指向 NDK 安装路径。

调用 ndk-gdb 时,它会配置此会话以查找您的源文件和所生成的原生库的符号/调试版本。成功附加到您的应用进程后,ndk-gdb 会输出一长串错误消息,表示无法找到各种系统库。这很正常,因为您的主机不包含这些库在您目标设备上的符号/调试版本。您可以放心地忽略这些消息。

接下来,ndk-gdb 会显示一个正常的 GDB 提示。

请使用与 GNU GDB 进行交互的方式与 ndk-gdb 进行交互。例如,您可以使用 b <location> 设置断点,使用 c(表示“continue”)继续执行。有关完整的命令列表,请参阅 GDB 手册

请注意,如果您退出 GDB 提示,那么您正在调试的应用进程将停止。此行为是 gdb 的一个局限。

ndk-gdb 可处理许多错误情况,并在发现问题时显示可提供有用信息的错误消息。这些检查包括确保符合以下条件:

  • 确保 ADB 位于您的路径中。
  • 确保您的应用已在其清单中声明为可调试。
  • 确保设备上安装的具有相同软件包名称的应用同样可调试。

默认情况下,ndk-gdb 会搜索已在运行的应用进程;如果没有搜索到,则显示相应的错误。不过,您可以使用 --start--launch=<name> 选项在调试会话前自动启动您的 Activity。有关详情,请参阅选项

选项

要查看完整的选项列表,请在命令行中输入 ndk-gdb --help。表 1 显示了许多比较常用的选项及其简要说明。

表 1. 常用 ndk-gdb 选项及其说明。

通过这个指定的选项启动 ndk-gdb 将会启动应用清单中列出的第一个可启动 Activity。使用 --launch=<name> 可启动下一个可启动的 Activity。要转储可启动 Activity 的列表,请从命令行运行 --launch-list

选项 说明>
--verbose

此选项指示编译系统打印有关原生调试会话设置的详细信息。仅在调试程序无法连接到应用且 ndk-gdb 显示的错误消息不充分时,才需要用它调试问题。

--force 默认情况下,如果 ndk-gdb 发现另一个原生调试会话已在相同设备上运行,它将会中止运行。此选项将终止另一个会话,并将其替换为新的会话。请注意,此选项不会终止正在调试的实际应用,您必须单独终止它。
--start

您启动 ndk-gdb 时,默认情况下,它会尝试附加到您的应用当前在目标设备上运行的实例。您可以替换此默认行为,只需在调试会话前使用 --start 在目标设备上明确启动应用即可。

--launch=<name>

此选项类似于 --start,不过它允许您从应用中启动特定 Activity。仅当您的清单定义多个可启动 Activity 时,才会用到该功能。

--launch-list

这个便捷选项会打印在您的应用清单中找到的所有可启动 Activity 名称的列表。--start 会使用第一个 Activity 名称。

--project=<path> 此选项可指定应用项目目录。如果您想不必先切换到项目目录就可启动脚本,则该选项会很有用。
--port=<port>

默认情况下,ndk-gdb 会使用本地 TCP 端口 5039 与它在目标设备上调试的应用进行通信。对于在连接至相同主机的不同设备或模拟器上运行的程序,您可以使用不同的端口对其进行本地调试。

--adb=<file>

此选项可指定 adb 工具可执行文件。只有在您未设置包括该可执行文件的路径时才需要使用此选项。

  • -d
  • -e
  • -s <serial>
  • 这些标记与具有相同名称的 adb 命令类似。如果您有多个已连接至主机的设备或模拟器,请设置这些标记。其含义如下所示:

    -d
    连接至单个物理设备。
    -e
    连接至单个模拟器设备。
    -s <serial>
    连接至特定设备或模拟器。在这种情况下,<serial> 是设备的名称(如通过 adb devices 命令所列出的那样)。

    此外,您还可以定义 ADB_SERIAL 环境变量来列出特定的设备,而无需指定具体选项。

  • --exec=<file>
  • -x <file>
  • 此选项可指示 ndk-gdb 在连接至它正在调试的进程后运行在 <file> 中找到的 GDB 初始化命令。如果您要重复执行某些操作(如设置断点列表,然后继续自动执行),该功能就非常实用。

    --nowait

    解除 Java 代码的暂停状态,直到连上 GDB。传递此选项可能会导致调试程序错过早期的断点。

    --tui -t

    启用文本界面(如果可用)。

    --gnumake-flag=<flag>

    此选项是在查询 ndk-build 系统以获取项目信息时要传递到该系统的一个(或多个)额外标记。您可以在同一个命令中使用此选项的多个实例。

    注意:此表中的最后三个选项仅适用于 ndk-gdb 的 Python 版本。

    线程支持

    如果您的应用在 Android 2.3(API 级别 9)之前的版本上运行,则 ndk-gdb 无法正确调试原生线程。调试程序只能调试主线程,abd 会完全忽略其他线程的执行。

    如果您在非主线程上执行的函数上放置一个断点,则程序将退出,GDB 将显示以下消息:

        Program terminated with signal SIGTRAP, Trace/breakpoint trap.
              The program no longer exists.