在 Chrome 92 中,我們推出了記憶體檢查器,這是用於檢查線性記憶體緩衝區的工具。本文將說明我們如何改善 C/C++ 偵錯工具的檢查器,以及過程中遇到的技術挑戰。
如果您是 C/C++ 偵錯和記憶體檢查器的新手,請參閱以下幾篇相關的部落格文章:
- 想瞭解深入記憶體偵錯嗎?請參閱「記憶體檢查工具簡介」。
- 想瞭解完整的 C/C++ 偵錯工具套件嗎?請參閱「使用新式工具偵錯 WASM」和「加快 WebAssembly 偵錯速度」。
簡介
Memory Inspector 提供更強大的線性記憶體緩衝區偵錯選項。在 C/C++ 的情況下,您可以在 WebAssembly 記憶體中檢查 C/C++ 記憶體物件。
在周圍的 WebAssembly 記憶體中辨識物件的位元組是個難題。您必須知道物件的大小,並從物件的開頭開始計算位元組。在下方螢幕截圖中,系統已選取 10 個元素 int32
陣列的第一個位元組,但無法立即判斷其他位元組屬於哪個陣列。如果您能立即辨識屬於物件的所有位元組,那該有多好?
記憶體檢查工具中的物件醒目顯示
從 Chrome 107 開始,記憶體檢查器會醒目顯示 C/C++ 記憶體物件的所有位元組。這有助於您區分記憶體與周遭記憶體。
請觀看以下影片,瞭解記憶體檢查器的運作方式。在「記憶體檢查器」中顯示陣列 x
時,記憶體檢視器會顯示醒目顯示的記憶體,以及位於其上方的新方塊。這個方塊會提醒您醒目顯示的記憶體名稱和類型。按一下晶片即可跳至物件的記憶體。將滑鼠游標懸停在方塊上,畫面上會顯示一個叉號圖示,按一下即可移除醒目顯示。
當您選取要檢查的物件以外的位元組時,系統會將醒目顯示設為模糊,以免分散您的注意力。如要再次聚焦,請再次點選物件的任何位元或方塊。
物件醒目顯示功能不限於陣列。您也可以檢查結構體、物件和指標。這些變更可讓您更輕鬆地探索 C/C++ 應用程式的記憶體!
想試試看嗎?你必須:
- 使用 Chrome 107 以上版本。
- 安裝 C/C++ DWARF 擴充功能。
- 依序前往「開發人員工具」 >「設定」 >「實驗」 >「WebAssemble 偵錯:啟用 DWARF 支援」,啟用 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 編譯器將 C/C++ 來源檔案編譯為 WebAssembly
但為什麼呢?V8 是 Chrome 的 JavaScript 和 WebAssembly 引擎,但不支援執行 C 或 C++。多虧了 Emscripten (C/C++ 到 WebAssembly 的編譯器),您可以將以 C 或 C++ 建構的應用程式編譯為 WebAssembly,並在瀏覽器中執行!
在編譯期間,emscripten 會將 DWARF 偵錯資料嵌入二進位檔。從高層面來說,這類資料可協助擴充功能找出哪些 WebAssembly 變數對應至 C/C++ 變數,以及其他資訊。這樣一來,即使 V8 實際執行的是 WebAssembly,開發人員工具仍可顯示 C++ 變數。如有興趣,請參閱這篇網誌文章,瞭解 DWARF 偵錯資料的範例。
那麼,當您揭露 lastNumber
時,實際上會發生什麼事?只要按一下記憶體圖示,開發人員工具就會檢查要檢查的變數。接著,系統會針對 lastNumber
的資料類型和位置,查詢擴充資料。擴充功能一回應這項資訊,記憶體檢查器就會顯示相關的記憶體切片,並顯示其類型,還會顯示物件的大小。
如果您查看前述範例中的 lastNumber
,可能會發現我們檢查的是 lastNumber: int *
,但記憶體檢查器中的晶片卻顯示 *lastNumber: int
,這是為什麼?檢查器會使用 C++ 風格的指標解參照,指出要顯示的物件類型!如果您檢查指標,檢查器會顯示指標指向的項目。
在偵錯工具步驟中保留醒目顯示
在記憶體檢查工具中顯示物件,並透過偵錯工具執行步驟時,如果檢查工具認為仍適用,就會保留醒目顯示。我們一開始並未將這項功能納入路線圖,但很快就意識到這會影響您的偵錯體驗。想像一下,如果您必須在每個步驟後重新檢查陣列,就像下方影片中的情況一樣!
當偵錯工具命中新的中斷點時,記憶體檢查器會再次查詢 V8 和與先前醒目顯示項目相關聯的變數擴充功能。然後比較物件的地點和類型。如果相符,則會持續顯示醒目顯示。在上方的影片中,有一個 for 迴圈會寫入陣列 x
。這些作業不會變更陣列的類型或位置,因此會持續醒目顯示。
您可能會想知道這會對指標造成什麼影響。如果您有醒目提示指標,並將其重新指派給其他物件,醒目提示物件的舊位置和新位置會不同,醒目提示也會消失。由於新指向的物件可位於 WebAssembly 記憶體中的任何位置,且可能與先前的記憶體位置幾乎無關,因此移除醒目顯示會比跳到新的記憶體位置更清楚。您可以點選「範圍」窗格中的記憶體圖示,再次醒目顯示指標。
結論
本文說明我們針對 C/C++ 偵錯功能改善記憶體檢查器。我們希望新功能能簡化 C/C++ 應用程式的記憶體偵錯作業!如有進一步改善建議,歡迎回報錯誤!
後續步驟
詳情請參閱: