擴充記憶體檢查器以進行 C/C++ 偵錯

我們在 Chrome 92 版推出了記憶體檢查器,可用來檢查線性記憶體緩衝區。在本文中,我們將討論我們如何改善 C/C++ 偵錯的檢查器,並討論過程中遇到的技術問題。

如果您是 C/C++ 偵錯和記憶體檢查器的新手,請參閱下列相關網誌文章:

簡介

記憶體檢查器提供更強大的線性記憶體緩衝區偵錯選項。如果是 C/C++,您可以檢查 WebAssembly 記憶體中的 C/C++ 記憶體物件。

因為在周圍的 WebAssembly 記憶體中,辨識出物件位元組是一大難題。您必須知道物件的大小,並從物件開始計算位元組數。在下列螢幕截圖中,已選取 10 元素 int32 陣列的第一個位元組,但無法立即清除屬於陣列的其他位元組。如果您可以立即辨識屬於物件的所有位元組,那不是很棒嗎?

原始記憶體檢查器的螢幕截圖,有一個醒目顯示的單一位元組

記憶體檢查工具中的物件醒目顯示

從 Chrome 107 開始,記憶體檢查器會醒目顯示 C/C++ 記憶體物件的所有位元組。這有助於區分周圍的記憶體。

更新過的記憶體檢查器螢幕截圖,其中醒目顯示醒目顯示的陣列

請觀看以下影片,瞭解記憶體檢查器的實際運作情形。在記憶體檢查器中顯示陣列 x 時,醒目顯示的記憶體會顯示在記憶體檢視器中,上方也會新增方塊。這個方塊會顯示醒目顯示的記憶體名稱和類型。點按方塊即可跳至物件的記憶體。將滑鼠遊標懸停在方塊上,就會看到十字圖示,按一下該圖示即可移除醒目顯示範圍。

在要檢查的物件外選取位元組時,系統會對其進行醒目顯示,避免使用者分心。如要再次對焦,只要點選物件的位元組或方塊即可。

物件醒目顯示不一定只適用於陣列。您也可以檢查結構體、物件和指標。這些變更可讓您更輕鬆探索 C/C++ 應用程式的記憶體!

想試試嗎?您需要完成以下事項:

  • 使用 Chrome 107 以上版本。
  • 安裝 C/C++ DWARF 擴充功能。
  • 在「開發人員工具」DevTools中啟用 DWARF 偵錯功能 >。「設定」>實驗 >WebAssemble 偵錯:啟用 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 陣列如預期包含 1234 整數。

已開啟記憶體檢查器的螢幕截圖,其中含有已檢查的 int32 陣列。所有陣列元素都會醒目顯示。

接著,它們會顯示「Scope」窗格中的 lastNumber 變數,並發現指標指向陣列以外的整數!藉由掌握這項知識,程式設計師發現他們在第 8 行正確計算指標偏移值。目前應該是 ptr + arraySize - 1

已開啟記憶體檢查器的螢幕截圖,顯示以「lastNumber」指標指向的醒目顯示記憶體。醒目顯示的記憶體就位於先前醒目顯示陣列的最後一個位元組之後。

雖然這是玩具範例,但能說明物件醒目顯示功能如何有效傳達記憶體物件的大小和位置,協助您進一步瞭解 C/C++ 應用程式記憶體中的狀況。

開發人員工具如何判斷要醒目顯示的內容

在本節中,我們將介紹支援 C/C++ 偵錯的工俱生態系統。具體來說,您將瞭解開發人員工具、V8、C/C++ DWARF 擴充功能和 Emscripten 如何在 Chrome 中進行 C/C++ 偵錯。

如要充分運用開發人員工具中的 C/C++ 偵錯功能,需要有以下兩個條件:

  • 在 Chrome 中安裝的 C/C++ DWARF 擴充功能
  • 使用最新的 Emscripten 編譯器,將 C/C++ 來源檔案編譯成 WebAssembly,詳情請參閱這篇網誌文章

但為什麼?Chrome 的 JavaScript 和 WebAssembly 引擎 V8 不知道如何執行 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 記憶體中的任何位置,而且與先前的記憶體位置幾乎沒什麼關係,移除醒目提示的做法會比跳到新的記憶體位置更清晰。如要再次醒目顯示該指標,請在「Scope」窗格中按一下其記憶體圖示。

結論

本文說明 C/C++ 偵錯的記憶體檢查器改善了哪些內容。我們希望新功能可簡化 C/C++ 應用程式記憶體的偵錯程序!如果你有其他改進建議,歡迎回報錯誤來告訴我們!

後續步驟

詳情請參閱: