◀返回
使用 Python 辅助脚本调试本地可执行文件
除了 GDB 调试,您还可以使用 Python 辅助脚本 gdb-debughelpers.py 来调试 native-image
进程。GDB Python API 用于为调试原生可执行文件或共享库提供相当好的体验。它需要支持 Python 的 GDB。此调试扩展已针对 GDB 14.2 进行测试,并支持 GraalVM for JDK 17 及更高版本中引入的新调试信息生成。
注意:gdb-debughelpers.py 文件不适用于低于 14.2 版本的
gdb
或低于 GraalVM for JDK 17 的版本。
Python 脚本 gdb-debughelpers.py 可以在 <GRAALVM_HOME>/lib/svm/debug 目录中找到。如果启用了调试信息生成(请参阅构建包含调试信息的原生可执行文件),该脚本将复制到构建目录。native-image
工具会将调试部分 .debug_gdb_scripts
添加到调试信息文件,这使得 GDB 能够从当前工作目录自动加载 gdb-debughelpers.py。
出于安全原因,GDB 首次遇到请求加载特定 Python 文件的原生可执行文件或共享库时,将打印一条警告。
warning: File "<CWD>/gdb-debughelpers.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load". To enable execution of this file add add-auto-load-safe-path <CWD>/gdb-debughelpers.py line to your configuration file "<HOME>/.gdbinit". To completely disable this security protection add add-auto-load-safe-path / line to your configuration file "<HOME>/.gdbinit". For more information about this security protection see the "Auto-loading safe path" section in the GDB manual. E.g., run from the shell: info "(gdb)Auto-loading safe path"
要解决此问题,请将当前工作目录添加到 ~/.gdbinit,如下所示:
echo "add-auto-load-safe-path <CWD>/gdb-debughelpers.py" >> ~/.gdbinit
或者将路径作为命令行参数传递给 gdb
。
gdb -iex "set auto-load safe-path <CWD>/gdb-debughelpers.py" <binary-name>
这两种方法都使 GDB 能够从当前工作目录自动加载 gdb-debughelpers.py。
自动加载是向 GDB 提供脚本的推荐方式。但是,也可以通过以下方式从 GDB 手动显式加载脚本:
(gdb) source gdb-debughelpers.py
美观打印支持
加载 gdb-debughelpers.py 会向 GDB 注册一个新的美观打印器,这为调试原生可执行文件或共享库增加了额外的便利。此美观打印器处理 Java 对象、数组、字符串和枚举的打印,用于调试原生可执行文件或共享库。如果 Java 应用程序使用 @CStruct
和 @CPointer
注解来访问 C 数据结构,此美观打印器也将尝试像打印 Java 数据结构一样打印它们。如果 C 数据结构无法由美观打印器打印,则由 GDB 执行打印。
此美观打印器还会打印装箱原始类型(而不是 Java 对象)的原始值。
每当通过 print
命令的 p
别名进行打印时,美观打印器都会拦截该调用,以便对 Java 对象的相应运行时类型执行类型转换。这同样适用于使用 p
别名时的自动补全。这意味着,如果静态类型与运行时类型不同,print
命令将使用静态类型,这需要用户自行发现运行时类型并进行类型转换。此外,p
别名还支持 Java 对象的字段和数组访问以及函数调用。
限制
print
命令仍使用其默认实现,因为没有办法在保留默认 print
命令功能的同时覆盖它。覆盖会导致非 Java 对象的打印无法正常工作。因此,只有 print
命令的 p
别名被美观打印器覆盖,以便用户仍然可以使用默认的 GDB print
命令。
控制美观打印器行为的选项
除了增强的 p
别名,gdb-debughelpers.py 还引入了一些 GDB 参数来定制美观打印器的行为。GDB 中的参数可以通过 set <param> <value>
和 show <param>
命令进行控制,从而与 GDB 的定制选项集成。
-
svm-print 开/关
使用此命令启用/禁用美观打印器。这也会将 print
命令的别名 p
重置为其默认行为。另外,可以通过 GDB print
命令的 raw
打印选项来抑制美观打印。
(gdb) show svm-print
The current value of 'svm-print' is "on".
(gdb) print str
$1 = "string"
(gdb) print/r str
$2 = (java.lang.String *) 0x7ffff689d2d0
(gdb) set svm-print off
1 printer disabled
1 of 2 printers enabled
(gdb) print str
$3 = (java.lang.String *) 0x7ffff689d2d0
-
svm-print-string-limit <整数>
自定义美观打印 Java 字符串的最大长度。默认值为 200
。设置为 -1
或 unlimited
以无限打印 Java 字符串。这不会更改 C 字符串的限制,C 字符串的限制可以通过 GDB 的 set print characters
命令控制。
-
svm-print-element-limit <整数>
自定义美观打印 Java 数组、ArrayList 和 HashMap 的最大元素数量。默认值为 10
。设置为 -1
或 unlimited
以打印无限数量的元素。这不会更改 C 数组的限制,C 数组的限制可以通过 GDB 的 set print elements
命令控制。但是,GDB 的参数 print elements
是 svm-print-element-limit
的上限。
-
svm-print-field-limit <整数>
自定义美观打印 Java 对象字段的最大元素数量。默认值为 50
。设置为 -1
或 unlimited
以打印无限数量的字段。GDB 的参数 print elements
是 svm-print-field-limit
的上限。
-
svm-print-depth-limit <整数>
自定义递归美观打印的最大深度。默认值为 1
。将打印直接子级的子级(一个合理的默认值,使装箱值的内容可见)。设置为 -1
或 unlimited
以打印无限深度。GDB 的参数 print max-depth
是 svm-print-depth-limit
的上限。
-
svm-use-hlrep 开/关
启用/禁用高级表示形式的美观打印。它提供了一种更数据导向的方式来查看一些具有已知内部结构的 Java 数据结构,例如列表或映射。目前支持 ArrayList 和 HashMap。
-
svm-infer-generics <整数>
自定义在推断高级表示形式的泛型类型时考虑的元素数量。默认值为 10
。设置为 0
表示不推断泛型类型,设置为 -1
或 unlimited
表示推断所有元素的泛型类型。
-
svm-print-address 绝对/开/关
除了常规美观打印外,启用/禁用地址的打印。当使用 absolute
模式时,即使是压缩引用也显示为绝对地址。默认情况下禁用地址打印。
-
svm-print-static-fields 开/关
启用/禁用 Java 对象的静态字段打印。默认情况下禁用静态字段打印。
-
svm-complete-static-variables 开/关
启用/禁用增强型 p
别名的静态字段成员自动补全。默认情况下启用静态字段自动补全。
-
svm-selfref-check 开/关
启用/禁用数据结构的自引用检查。美观打印器会检测自引用数据结构,并阻止进一步展开以避免无限递归。默认情况下启用自引用检查。为了测试,可以暂时禁用此功能(通常您不会这样做)。