我們在 Chrome 92 版中推出了記憶體檢查器,這項工具可用於檢查線性記憶體緩衝區。在本文中,我們將討論如何改善 C/C++ 偵錯檢查器,以及過程中遇到的技術難題。
如果您是第一次使用 C/C++ 偵錯和記憶體檢查器,以下是一些相關的網誌文章:
- 對深層記憶體偵錯感興趣嗎?請參閱「記憶體檢查器簡介」一文。
- 想要瞭解完整的 C/C++ 偵錯工具套件嗎?請參閱「使用新型工具對 WASM 進行偵錯」和「對 WebAssembly Faster」。
簡介
記憶體檢查器針對線性記憶體緩衝區提供更強大的偵錯選項。如果是 C/C++,您可以檢查 WebAssembly Memory 中的 C/C++ 記憶體物件。
從周圍的 WebAssembly 記憶體中辨識您物件的位元組是一項問題。您必須知道物件的大小和從物件的開頭開始計算位元組數量。在下方的螢幕截圖中,已選取 10 個元素 int32
陣列的第一個位元組,但使用者無法立即得知哪些位元組屬於陣列。如果能立即辨識屬於物件的所有位元組,那不是好事嗎?
記憶體檢查器中醒目顯示的物件
從 Chrome 107 開始,記憶體檢查器會醒目顯示 C/C++ 記憶體物件的所有位元組。以便區分相片和周圍的記憶。
請觀看下方影片,瞭解記憶體檢查器的實際運作情形。當您在記憶體檢查器中顯示陣列 x
時,記憶體檢視器中會顯示醒目顯示的記憶體,以及正上方的新方塊。這個方塊會提醒你醒目顯示回憶集錦的名稱和類型。按一下方塊即可跳至該物件的記憶體。將滑鼠遊標懸停在方塊上,畫面就會顯示打叉圖示,按一下即可移除醒目顯示。
當您選取要檢查的物件外的位元組時,系統會醒目顯示焦點,避免讓您分心。如要重新聚焦,請再按一下物件的任何位元組或方塊。
物件醒目顯示功能但不限於陣列。您也可以檢查結構、物件和指標,這些變更可讓您更輕鬆地探索 C/C++ 應用程式的記憶體!
想試試嗎?你需要完成下列事項:
- 使用 Chrome 107 以上版本。
- 安裝 C/C++ DWARF 擴充功能。
- 在「開發人員工具」DevTools >「設定」DevTools >「實驗」DevTools >「WebAssemble Debugging: Enable DWARF support」DevTools中啟用 DWARF 偵錯功能。
- 開啟這個示範頁面。
- 按照頁面上的指示操作。
偵錯範例
在本節中,讓我們看看一個玩具錯誤,瞭解如何使用記憶體檢查器執行 C/C++ 偵錯。在下方的程式碼範例中,程式設計師會建立整數陣列,並決定使用指標算術來選取最後一個元素。不幸的是,程式設計師在計算指標時出錯,現在程式不會輸出最後一個元素,而會輸出無意義的值。
#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;
}
程式設計師會改用「記憶體檢查器」來偵錯。您也可以觀看這個示範影片!他們會先檢查記憶體檢查器中的陣列,發現 numbers
陣列完全只包含整數 1
、2
、3
和 4
。
接著,他們會看到「Scope」(範圍) 窗格中的 lastNumber
變數,並注意到該指標指向陣列以外的整數!憑藉這些知識,程式設計師發現他們誤算第 8 行的指標偏移。應為 ptr + arraySize - 1
。
雖然這是玩具範例,但能說明物件醒目顯示如何有效傳達記憶體物件的大小和位置,協助您進一步瞭解 C/C++ 應用程式記憶體中的實際情況。
開發人員工具如何判斷應醒目顯示的內容
本節將說明啟用 C/C++ 偵錯工具的生態系統。具體來說,您將瞭解開發人員工具、V8、C/C++ DWARF 擴充功能和 Emscripten 如何在 Chrome 中實現 C/C++ 偵錯。
如要充分利用開發人員工具中的 C/C++ 偵錯功能,您需要執行以下兩項操作:
- 在 Chrome 中安裝的 C/C++ DWARF 擴充功能
- 如這篇網誌文章所述,使用最新的 Emscripten 編譯器編譯成 WebAssembly 的 C/C++ 來源檔案
但為什麼?V8 是 Chrome 的 JavaScript 和 WebAssembly 引擎,不知道如何執行 C 或 C++。有了 Emscripten (C/C++) 後,WebAssembly 編譯器的 C/C++ 能將以 C/C++ 建構的應用程式做為 WebAssembly 編譯,然後在瀏覽器中執行這些應用程式!
在編譯期間,emscripten 會將 DWARF 偵錯資料嵌入二進位檔。整體來說,這項資料可協助擴充功能找出哪些 WebAssembly 變數對應到 C/C++ 變數等等。這樣一來,即使 V8 實際執行 WebAssembly,開發人員工具也能顯示 C++ 變數。如果您有興趣,請參閱這篇網誌文章,取得 DWARF 偵錯資料示例。
那麼,揭露 lastNumber
時會發生什麼事?只要按一下記憶體圖示,開發人員工具就會立即檢查您要檢查的變數。接著,它會查詢 lastNumber
的資料類型和位置。只要擴充功能傳回相關資訊,記憶體檢查器就能顯示相關記憶體片段並瞭解其類型,也會顯示物件的大小。
查看先前範例中的 lastNumber
時,您可能會發現我們檢查了 lastNumber: int *
,但記憶體檢查器中的方塊顯示 *lastNumber: int
,有什麼好處?檢查器會使用 C++ 樣式指標去參照來指出向您顯示的物件類型!如果你檢查指標,檢查器會顯示指標指向的內容。
保留偵錯工具步驟的重點資訊
當您在記憶體檢查器中顯示物件並執行偵錯工具時,如果檢查器判定該物件仍適用,就會保留醒目標示。最初,我們尚未在藍圖中推出這項功能,但很快就發現這樣會��壞你的偵錯體驗。想像一下,每完成一個步驟後都要重新檢查陣列,如下方影片所示!
當偵錯工具觸發新的中斷點時,記憶體檢查器會再次查詢 V8 以及與先前醒目顯示的變數相關聯的變數擴充功能。接著比較物件的位置和類型。如果兩者相符,標示框就會維持原樣。在上面的影片中,會有一個迴圈寫入陣列 x
。這些作業不會變更陣列的類型或位置,因此會保持醒目顯示。
您可能會想知道這對指標有何影響。如果畫面上有醒目顯示的指標,並將其重新指派給其他物件,醒目顯示的物件的新位置和新位置就會不同,醒目顯示功能就會消失。由於新指向的物件可能位於 WebAssembly Memory 中的任何位置,且與之前的記憶體位置幾乎沒有關聯,因此移除醒目顯示即可比跳移至新的記憶體位置更清晰。如要再次醒目顯示指標,請在「Scope」窗格中按一下其記憶體圖示。
結論
本文將說明我們改善了 C/C++ 偵錯記憶體檢查器的改善項目。我們希望新功能可以簡化 C/C++ 應用程式的記憶體偵錯作業!如果你有改進建議,可以回報錯誤,讓我們瞭解你的想法!
後續步驟
詳情請參閱: