Skip to main content

在 macOS 上调试

¥Debugging on macOS

如果你在 Electron 中遇到崩溃或问题,并且你认为不是由 JavaScript 应用引起的,而是由 Electron 本身引起的,那么调试可能会有点棘手,特别是对于不习惯原生/C++ 调试的开发者而言。但是,使用 lldb 和 Electron 源代码,你可以使用 Electron 源代码内的断点启用逐步调试。如果你喜欢图形界面,也可以使用 用于调试的 XCode

¥If you experience crashes or issues in Electron that you believe are not caused by your JavaScript application, but instead by Electron itself, debugging can be a little bit tricky especially for developers not used to native/C++ debugging. However, using lldb and the Electron source code, you can enable step-through debugging with breakpoints inside Electron's source code. You can also use XCode for debugging if you prefer a graphical interface.

要求

¥Requirements

  • Electron 的测试版本:最简单的方法通常是从源代码构建它,你可以按照 构建说明.h 中的说明进行操作。虽然你可以像直接下载一样附加到 Electron 并进行调试,但你会发现它经过了大量优化,使得调试变得更加困难。在这种情况下,调试器将无法显示所有变量的内容,并且由于内联、尾调用和其他编译器优化,执行路径可能看起来很奇怪。

    ¥A testing build of Electron: The easiest way is usually to build it from source, which you can do by following the instructions in the build instructions. While you can attach to and debug Electron as you can download it directly, you will find that it is heavily optimized, making debugging substantially more difficult. In this case the debugger will not be able to show you the content of all variables and the execution path can seem strange because of inlining, tail calls, and other compiler optimizations.

  • 代码:除了 Xcode 之外,你还应该安装 Xcode 命令行工具。其中包括 LLDB,macOS 上 Xcode 中的默认调试器。它支持在桌面、iOS 设备和模拟器上调试 C、Objective-C 和 C++。

    ¥Xcode: In addition to Xcode, you should also install the Xcode command line tools. They include LLDB, the default debugger in Xcode on macOS. It supports debugging C, Objective-C and C++ on the desktop and iOS devices and simulator.

  • .lldbinit:创建或编辑 ~/.lldbinit 以允许 Chromium 代码正确进行源映射。

    ¥.lldbinit: Create or edit ~/.lldbinit to allow Chromium code to be properly source-mapped.

    # e.g: ['~/electron/src/tools/lldb']
    script sys.path[:0] = ['<...path/to/electron/src/tools/lldb>']
    script import lldbinit

连接并调试 Electron

¥Attaching to and Debugging Electron

要启动调试会话,请打开终端并启动 lldb,传递 Electron 的非发布版本作为参数。

¥To start a debugging session, open up Terminal and start lldb, passing a non-release build of Electron as a parameter.

$ lldb ./out/Testing/Electron.app
(lldb) target create "./out/Testing/Electron.app"
Current executable set to './out/Testing/Electron.app' (x86_64).

设置断点

¥Setting Breakpoints

LLDB 是一个强大的工具,支持多种代码检查策略。对于这个基本介绍,我们假设你从 JavaScript 调用一个行为不正确的命令 - 所以你想在 Electron 源代码中中断该命令的 C++ 对应命令。

¥LLDB is a powerful tool and supports multiple strategies for code inspection. For this basic introduction, let's assume that you're calling a command from JavaScript that isn't behaving correctly - so you'd like to break on that command's C++ counterpart inside the Electron source.

相关代码文件可以在 ./shell/.h 中找到。

¥Relevant code files can be found in ./shell/.

假设你要调试 app.setName(),它在 browser.cc 中定义为 Browser::SetName()。使用 breakpoint 命令设置断点,指定要中断的文件和行:

¥Let's assume that you want to debug app.setName(), which is defined in browser.cc as Browser::SetName(). Set the breakpoint using the breakpoint command, specifying file and line to break on:

(lldb) breakpoint set --file browser.cc --line 117
Breakpoint 1: where = Electron Framework`atom::Browser::SetName(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 20 at browser.cc:118, address = 0x000000000015fdb4

然后,启动 Electron:

¥Then, start Electron:

(lldb) run

该应用将立即暂停,因为 Electron 在启动时设置了应用的名称:

¥The app will immediately be paused, since Electron sets the app's name on launch:

(lldb) run
Process 25244 launched: '/Users/fr/Code/electron/out/Testing/Electron.app/Contents/MacOS/Electron' (x86_64)
Process 25244 stopped

* thread #1: tid = 0x839a4c, 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118
115 }
116
117 void Browser::SetName(const std::string& name) {
-> 118 name_override_ = name;
119 }
120
121 int Browser::GetBadgeCount() {
(lldb)

要显示当前帧的参数和局部变量,请运行 frame variable(或 fr v),这将显示应用当前将名称设置为 "Electron"。

¥To show the arguments and local variables for the current frame, run frame variable (or fr v), which will show you that the app is currently setting the name to "Electron".

(lldb) frame variable
(atom::Browser *) this = 0x0000000108b14f20
(const string &) name = "Electron": {
[...]
}

要在当前选定的线程中执行源代码级单步,请执行 step(或 s)。这将带你进入 name_override_.empty()。要继续并跳过,请运行 next(或 n)。

¥To do a source level single step in the currently selected thread, execute step (or s). This would take you into name_override_.empty(). To proceed and do a step over, run next (or n).

(lldb) step
Process 25244 stopped

* thread #1: tid = 0x839a4c, 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119
116
117 void Browser::SetName(const std::string& name) {
118 name_override_ = name;
-> 119 }
120
121 int Browser::GetBadgeCount() {
122 return badge_count_;

注意:如果你认为应该看到源代码却没有看到,则可能没有添加上面的 ~/.lldbinit 文件。

¥NOTE: If you don't see source code when you think you should, you may not have added the ~/.lldbinit file above.

此时要完成调试,请运行 process continue。你还可以继续,直到命中该线程中的某一行(thread until 100)。该命令将在当前帧中运行线程,直到它到达该帧中的第 100 行,或者如果它离开当前帧则停止。

¥To finish debugging at this point, run process continue. You can also continue until a certain line is hit in this thread (thread until 100). This command will run the thread in the current frame till it reaches line 100 in this frame or stops if it leaves the current frame.

现在,如果你打开 Electron 的开发者工具并调用 setName,你将再次遇到断点。

¥Now, if you open up Electron's developer tools and call setName, you will once again hit the breakpoint.

进一步阅读

¥Further Reading

LLDB 是一个功能强大的工具,具有丰富的文档。要了解更多信息,请考虑 Apple 的调试文档,例如 LLDB 命令结构参考使用 LLDB 作为独立调试器 的介绍。

¥LLDB is a powerful tool with a great documentation. To learn more about it, consider Apple's debugging documentation, for instance the LLDB Command Structure Reference or the introduction to Using LLDB as a Standalone Debugger.

你还可以查看 LLDB 的精彩 手册和教程,它将解释更复杂的调试场景。

¥You can also check out LLDB's fantastic manual and tutorial, which will explain more complex debugging scenarios.