使用 GDB 调试 Firefox¶
此页面详细介绍了如何更轻松地使用 gdb 调试 Firefox。 rr 通常是调试问题的更好选择,但有时无法使用它,例如尝试重现竞争条件或当性能对于重现问题很重要时。 rr
混乱模式允许重现许多问题,并且应该尝试。
在哪里可以找到通用的 gdb 文档?¶
使用 GDB 超出了本文档的范围。如果您已安装 GDB,则系统上可能提供了文档,形式为 **info**、**man** 页面或 gnome 帮助浏览器。此外,您可以使用 GDB 的图形前端,例如 ddd 或 insight。有关更多信息,请参阅 https://sourceware.org/gdb/current/onlinedocs/gdb/
如何使用 gdb 调试 Firefox?¶
Firefox 是一款多进程应用程序,包含一个父进程和多个子进程,每个子进程都具有不同的专业化和沙箱。
$ ./mach run --debugger=gdb
允许在 gdb 中运行 Firefox 并调试父进程。您可以用其他操作替换 run
,例如 test
、mochitest
、xpcshell-test
等。
可以通过附加调试器来调试子进程。
$ gdb --pid <pid>
有多种方法可以找到进程的 PID:将鼠标悬停在选项卡上以查看内容进程、打开 about:processes
、在命令行上使用 ps ... | grep firefox
等。
有时,希望在启动时附加到子进程,以诊断非常接近进程开始的内容。设置环境变量 MOZ_DEBUG_CHILD_PROCESS=10
将使每个新进程打印几行信息,包括进程类型及其 PID。然后,进程将休眠几秒钟(等于环境变量的值),以便附加调试器。
$ MOZ_DEBUG_CHILD_PROCESS=10 ./mach run
...
...
...
CHILDCHILDCHILDCHILD (process type tab)
debug me @ 65230
...
...
...
附加 gdb 到 Firefox 可能会在启用常见内核加固功能(例如 Yama 安全模块)的 Linux 发行版上失败。如果您在附加时遇到以下错误:
$ gdb --pid <pid>
...
...
Attaching to process <pid>
ptrace: Operation not permitted.
检查 /proc/sys/kernel/yama/ptrace_scope 的内容。如果它设置为 1,则您将无法附加到进程,请从 root shell 将其设置为 0
\# echo 0 > /proc/sys/kernel/yama/ptrace_scope
如果您仍然无法附加,请仔细检查您的设置。在任何情况下,都不要以 root 身份运行 gdb。由于 gdb 可以执行任意代码并生成 shell,因此在具有 root 权限的情况下使用它非常危险。
高级 gdb 配置¶
首选方法是使用 Mach 命令行工具运行调试器,它可以绕过几个可选的默认值。使用“mach help run”获取更多详细信息。如果在源代码目录中,您将使用“./mach”。请注意,mach 了解 mozconfigs。
$ ./mach run --debug [arguments to pass to firefox]
如果您需要将参数传递给 gdb,可以通过命令行解析器使用“--debugger-args”选项,注意遵守 shell 分割规则。例如,如果您想在 gdb 启动时运行命令“show args”,则可以使用
$ ./mach run --debug --debugger-args "-ex 'show args'"
或者,您可以直接对 Firefox 运行 gdb。但是,您将无法通过这种方式获得一些更有用的功能。例如,mach 设置一个环境变量(见下文),以阻止 JS 引擎生成合成段错误以支持较慢的脚本对话框机制。
(gdb) $OBJDIR/dist/bin/firefox
如何在现场调试 Firefox(未在主机上编译)¶
如果您需要附加到机器上的 Firefox 进程,并且此 Firefox 由 Mozilla 或某些 Linux 发行版构建,则可以使用 Mozilla 符号服务器获取符号和源代码,请参阅 此部分 获取设置说明,这只是在 .gdbinit
中获取 python 脚本的问题。
调试工作方式与往常一样,只是构建可能具有非常高的优化级别。
如何在 prun 中传递参数?¶
在调用 prun 之前在 GDB 中设置参数。以下是如何执行此操作的示例
(gdb) set args https://www.mozilla.org
(gdb) prun
为什么断点似乎没有命中?¶
最可能的原因是 gdb 未附加到运行要诊断的代码的进程。启用相关的 MOZ_LOG 模块可以提供帮助,因为默认情况下它会打印所有日志语句的进程类型和 pid。
break list 将显示断点列表,以及它们是否已启用。需要完全指定 C++ 命名空间,并且有时难以在 lambda 中中断。按行号中断是一种替代策略,在这种情况下通常有效。
如何显示 nsString?¶
(gdb) p ToNewCString(string);
这会泄漏一些内存,但这并不重要。
如何确定接口指针指向的对象的具体类型?¶
您可以通过查看对象 vtable 的符号的 mangled 名称来确定任何对象(由 XPCOM 接口指针指向)的具体类型
(gdb) p aKidFrame
$1 = (nsIFrame *) 0x85058d4
(gdb) x/wa *(void**)aKidFrame
0x4210d380 <__vt_14nsRootBoxFrame>: 0x0
(gdb) p *(nsRootBoxFrame*)aKidFrame
[ all the member variables of aKidFrame ]
或使用 gdb 命令 set print object on
。
如何从 gdb 调试 JavaScript?¶
如果堆栈上有 JavaScript 引擎代码,您可能希望除了 C++ 堆栈之外还需要 JS 堆栈。
(gdb) call DumpJSStack()
请注意,如果 gdb 已附加到进程,则堆栈可能会在启动 Firefox 的终端窗口中打印。
有关更多 JS 调试技巧,请参阅 此 MDN 页面。
如何调试竞争条件¶
即使在未附加 gdb 时没有崩溃,我仍然在 JS/JIT 代码下收到 SIGSYS 或 SIGSEGV。如何解决?¶
允许 gdb 读取 mozilla-central 的 .gdbinit,位于 build/.gdbinit。在您自己的 .gdbinit 中,添加以下行:
add-auto-load-safe-path /path/to/mozilla-central
如何在系统库内部获取有用的堆栈跟踪?¶
许多 Linux 发行版提供单独的软件包,其中包含系统库(例如 gdb、Valgrind、性能分析工具等)的调试信息,以便通过系统库提供有用的堆栈跟踪。
现代方法是启用 debuginfod
。这可以通过添加以下内容来实现:
set debuginfod enabled on
在您的 .gdbinit
中,但可能存在特定于发行版说明。或者,您可以安装包含要调试的库的调试符号的软件包。
使用 debuginfod
时,将在需要时自动下载正确的信息(并随后缓存)。
如果您不确定使用什么,则有一个联合 debuginfod 服务器,它为大多数主流发行版提供调试信息。您可以通过将以下行添加到 .gdbinit
文件中来使用它:
set debuginfod urls "https://debuginfod.elfutils.org/"
请记住,第一次下载调试信息可能需要一段时间。这会依次查询多个发行版的服务器,并且调试信息往往很大。但它将被缓存以供下次运行使用。
Fedora¶
在 Fedora 上,您需要启用 debuginfo 存储库,因为软件包位于单独的存储库中。永久启用它们,以便在您获取更新时也获取这些软件包的安全更新。一种方法是编辑 /etc/yum.repos.d/fedora.repo
和 fedora-updates.repo
以将 debuginfo 部分中的 enabled=0
行更改为 enabled=1
。这可能会在升级到新的发行版时导致冲突。您将需要再次执行此编辑。
您现在可以使用 yum 或其他软件包管理工具安装 debuginfo 软件包。最好的方法是安装 yum-utils
软件包,然后使用 debuginfo-install
命令安装所有 debuginfo
$ yum install yum-utils
$ debuginfo-install firefox
这可以通过手动方式完成,使用
$ yum install GConf2-debuginfo ORBit2-debuginfo atk-debuginfo \
cairo-debuginfo dbus-debuginfo expat-debuginfo \
fontconfig-debuginfo freetype-debuginfo gcc-debuginfo glib2-debuginfo \
glibc-debuginfo gnome-vfs2-debuginfo gtk2-debuginfo gtk2-engines-debuginfo \
hal-debuginfo libX11-debuginfo libXcursor-debuginfo libXext-debuginfo \
libXfixes-debuginfo libXft-debuginfo libXi-debuginfo libXinerama-debuginfo \
libXrender-debuginfo libbonobo-debuginfo libgnome-debuginfo \
libselinux-debuginfo pango-debuginfo popt-debuginfo scim-bridge-debuginfo
禁用多进程¶
mach run
和 mach test
都接受 --disable-e10s
参数。某些调试器在没有它的情况下无法捕获子进程崩溃。这有时是附加的替代方案,但如今它改变了很多东西,因此并不总是可用的选项。
另请参阅¶
使用 gdb 的乐趣,作者:Steve Fink