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

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

如果您是第一次使用 C/C++ 偵錯和記憶體檢查器,以下是一些相關的網誌文章:

簡介

記憶體檢查器針對線性記憶體緩衝區提供更強大的偵錯選項。如果是 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 陣列完全只包含整數 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 編譯器編譯成 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++ 應用程式的記憶體偵錯作業!如果你有改進建議,可以回報錯誤,讓我們瞭解你的想法!

後續步驟

詳情請參閱: