メインコンテンツへ飛ぶ

macOS におけるデバッグ

JavaScript アプリケーションに起因しないと思われるクラッシュや問題が Electron 上で起こった場合、特にネイティブ/C++ デバッグの経験がない開発者にとって少しトリッキーなデバッグになります。 しかし、lldb と Electron のソースコードを使用することで、Electron のソースコード内でブレークポイントを使用したステップ実行デバッグを有効にできます。 You can also use XCode for debugging if you prefer a graphical interface.

要件

  • 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. 直接ダウンロードした Electron をアタッチしてデバッグすることも可能ですが、非常に最適化されているため、デバッグが大幅に難しいでしょう。 この場合、デバッガはすべての変数の内容を表示することができず、インライン化、テールコール、その他のコンパイラの最適化により、実行経路がおかしく見えることがあります。

  • Xcode: 加えて Xcode では、Xcode コマンドラインツールもインストールする必要があります。 macOS の XCode には、デフォルトのデバッガの LLDB が入っています。 C、Objective-C、C++ のデバッグを、デスクトップ、iOS デバイス、シミュレータ上でサポートします。

  • .lldbinit: ~/.lldbinit を以下のように作成及び編集し、Chromium コードを適切にソースマップできるようにします。

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

Electronへの接続とデバッグ

デバッグセッションを始めるには、ターミナルを開いて Electron のリリースでないビルドを引数として渡して lldb を実行します。

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

ブレークポイントの設定

LLDBは強力なツールであり、コード検査のための複数の計画をサポートします。 この基本的な導入では、正しく動作していないコマンドを JavaScript から呼び出していると仮定しましょう。Electron ソース内に対応するコマンドの C++をブレークしたいとします。

関連コードファイルは ./shell/ にあります。

browser.cc 内に Browser::SetName() として定義されている app.setName() をデバッグしたいと仮定しましょう。 breakpoint コマンドを用いて、以下のようにブレークするファイルと行を指定してブレークポイントを設定します。

(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 を実行します。

(lldb) run

Electron は起動時にアプリの名前を設定するため、アプリはすぐに一時停止されます。

(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" にセットされているのが表示されるでしょう。

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

現在のスレッド内でソースレベルステップ実行するには、step (または s) を実行します。 これにより、name_override_.empty() に飛びます。 処理してステップオーバーするには、next (または 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 ファイルを追加していない可能性があります。

このポイントでのデバッグが完了したら、process continue を実行します。 このスレッドで特定の行がヒットするまで (thread until 100) 続行することもできます。 このコマンドは、このフレームの100行目に達するまで、現在のフレーム内のスレッドを実行し、現在のフレームを終了すると停止します。

今、Electron の開発者ツールを開いて setName を呼び出すと、もう一度ブレークポイントにヒットします。

参考リンク

LLDB は素晴らしいドキュメントを備えた強力なツールです。 詳細については、LLDB コマンド構造リファレンスLLDB をスタンドアロンデバッガとして使用する方法 などの Apple のデバッグドキュメントを参照してください。

LLDB の素晴らしい マニュアルとチュートリアル もご参考ください。さらに複雑なデバッグシナリオについて説明されています。