Chrome 92 では、リニアメモリ バッファを検査するためのツールである メモリ インスペクタを導入しました。この記事では、C/C++ デバッグ用インスペクタの改善方法と、その過程で直面した技術的な課題について説明します。
C/C++ デバッグと Memory Inspector を初めて使用する場合は、以下の関連するブログ投稿をご覧ください。
- 詳細なメモリ デバッグに関心をお持ちですか?Memory Inspector の概要をご覧ください。
- C/C++ デバッグ ツールスイートの概要については、最新のツールで WASM をデバッグすると WebAssembly をより速くデバッグするをご覧ください。
はじめに
メモリ インスペクタには、リニアメモリ バッファ用のより強力なデバッグ オプションが用意されています。C/C++ の場合は、WebAssembly メモリで C/C++ メモリ オブジェクトを検査できます。
周囲の WebAssembly メモリからオブジェクトのバイトを見つけることが課題でした。オブジェクトのサイズを把握し、オブジェクトの先頭からバイト数をカウントする必要があります。次のスクリーンショットでは、10 要素の int32
配列の最初のバイトが選択されていますが、他のバイトが配列に属していることはすぐにはわかりません。オブジェクトに属するすべてのバイトを即座に認識できたら便利だと思いませんか?
Memory Inspector でのオブジェクトのハイライト表示
Chrome 107 以降、メモリ インスペクタで C/C++ メモリ オブジェクトのすべてのバイトがハイライト表示されます。これにより、周囲のメモリと区別しやすくなります。
Memory Inspector の動作については、以下の動画をご覧ください。Memory Inspector で配列 x
を表示すると、Memory Viewer にハイライト表示されたメモリと、そのすぐ上に新しいチップが表示されます。このチップには、ハイライト表示されたメモリの名前とタイプが表示されます。チップをクリックすると、オブジェクトのメモリに移動します。チップにカーソルを合わせると、× アイコンが表示されます。このアイコンをクリックすると、ハイライトが解除されます。
検査対象のオブジェクトの外側のバイトを選択すると、注意が散漫にならないようにハイライトがぼかされます。再びフォーカスを合わせるには、オブジェクトのバイトまたはチップをもう一度クリックします。
オブジェクトのハイライト表示は、配列に限定されません。構造体、オブジェクト、ポインタを調べることもできます。これらの変更により、C/C++ アプリのメモリをこれまで以上に簡単に探索できるようになりました。
試してみたい場合は、そこで次の作業が必要になります。
- Chrome 107 以降を使用している。
- C/C++ DWARF 拡張機能をインストールします。
- DevTools > [設定] > [試験運用版] > [WebAssemble デバッグ: DWARF サポートを有効にする] で DWARF デバッグを有効にします。
- こちらのデモページを開きます。
- ページに記載されている手順に沿って操作します。
デバッグの例
このセクションでは、サンプルバグを使用して、C/C++ デバッグに Memory Inspector を使用する方法を説明します。次のコードサンプルでは、プログラマが整数配列を作成し、ポインタ演算を使用して最後の要素を選択することにしました。残念ながら、プログラマはポインタの計算でミスを犯し、最後の要素を出力する代わりに、意味不明な値を出力するプログラムになりました。
#include <iostream>
int main()
{
int numbers[] = {1, 2, 3, 4};
int *ptr = numbers;
int arraySize = sizeof(numbers)/sizeof(int);
int* lastNumber = ptr + arraySize; // Can you notice the bug here?
std::cout <<../ *lastNumber <<../ '\n';
return 0;
}
プログラマは Memory Inspector を使用して問題をデバッグします。こちらのデモで確認できます。まず、メモリ インスペクタで配列を調べ、numbers
配列に整数 1
、2
、3
、4
のみが含まれていることを確認します。
次に、[スコープ] ペインで lastNumber
変数を開き、ポインタが配列外の整数を参照していることを確認します。この知識を得たプログラマは、8 行目でポインタ オフセットを間違ってカウントしたことに気付きます。ptr + arraySize - 1
にする必要があります。
これは単なる例ですが、オブジェクトのハイライト表示によってメモリ オブジェクトのサイズと位置を効果的に伝える方法を示しています。これにより、C/C++ アプリのメモリ内で何が起こっているかをよりよく把握できます。
DevTools がハイライト表示する内容を判断する方法
このセクションでは、C/C++ デバッグを可能にするツールのエコシステムについて説明します。具体的には、DevTools、V8、C/C++ DWARF 拡張機能、Emscripten を使用して Chrome で C/C++ デバッグを可能にする方法について説明します。
DevTools で C/C++ デバッグを最大限に活用するには、次の 2 つが必要です。
- Chrome にインストールされている C/C++ DWARF 拡張機能
- こちらのブログ投稿の手順に沿って、最新の Emscripten コンパイラで WebAssembly にコンパイルされた C/C++ ソースファイル
しかし、なぜこうなってしまったのでしょう。Chrome の JavaScript および WebAssembly エンジンである V8 は、C または C++ を実行できません。C/C++ から WebAssembly へのコンパイラである Emscripten を使用すると、C または C++ でビルドされたアプリを WebAssembly としてコンパイルし、ブラウザで実行できます。
コンパイル時に、emscripten は DWARF デバッグデータをバイナリに埋め込みます。概要レベルでは、このデータは、拡張機能が C/C++ 変数に対応する WebAssembly 変数などを特定するのに役立ちます。これにより、V8 が実際に WebAssembly を実行しているにもかかわらず、DevTools で C++ 変数を表示できます。DWARF デバッグデータの例については、こちらのブログ投稿をご覧ください。
lastNumber
を公開すると、実際にはどのような処理が行われるのでしょうか?メモリ アイコンをクリックすると、検査する変数がチェックされます。次に、lastNumber
のデータ型と場所について拡張機能にクエリを実行します。拡張機能がその情報で応答するとすぐに、Memory Inspector は関連するメモリスライスを表示し、そのタイプを把握してオブジェクトのサイズも表示できます。
前の例の lastNumber
を見ると、lastNumber: int *
を検査したはずなのに、メモリ インスペクタのチップに *lastNumber: int
と表示されています。これはなぜでしょうか。インスペクタは、C++ スタイルのポインタ デリファレンスを使用して、表示されるオブジェクトのタイプを示します。ポインタをインスペクトすると、ポインタが指している内容が表示されます。
デバッガのステップでハイライトを保持する
Memory Inspector でオブジェクトを表示し、デバッガでステップすると、Inspector は、ハイライトが引き続き適用可能であると判断した場合は、ハイライトを保持します。当初、この機能はロードマップにはありませんでしたが、デバッグ体験が損なわれることにすぐに気付きました。以下の動画のように、各ステップの後に配列を再検査しなければならないとしたらどうでしょう。
デバッガが新しいブレークポイントに到達すると、Memory Inspector は、以前のハイライトに関連付けられた変数について、V8 と拡張機能に対して再度クエリを実行します。次に、オブジェクトの位置とタイプを比較します。一致する場合、ハイライトは保持されます。上の動画では、配列 x
に書き込む for ループがあります。これらのオペレーションでは配列の型や位置は変更されないため、配列はハイライト表示されたままになります。
ポインタにどのような影響があるか疑問に思われるかもしれません。ハイライト表示されたポインタを別のオブジェクトに再割り当てすると、ハイライト表示されたオブジェクトの古い位置と新しい位置が異なるため、ハイライト表示が消えます。新しく参照されるオブジェクトは WebAssembly メモリのどこにでも存在し、以前のメモリ位置とほとんど関係がない可能性があるため、新しいメモリ位置にジャンプするよりもハイライトを削除するほうが明確です。ポインタを再度ハイライト表示するには、[スコープ] ペインでポインタのメモリ アイコンをクリックします。
まとめ
この記事では、C/C++ デバッグ用の Memory Inspector の改善点について説明しました。これらの新機能が、C/C++ アプリのメモリのデバッグ作業を簡素化することを願っています。改善のアイデアがございましたら、バグを報告してご連絡ください。
次のステップ
詳しくは、次をご覧ください。