C/C++ 디버깅을 위해 Memory Inspector 확장

Chrome 92에서는 선형 메모리 버퍼를 검사하는 도구인 Memory Inspector를 도입했습니다. 이 도움말에서는 C/C++ 디버깅을 위한 검사기를 어떻게 개선했는지와 그 과정에서 겪게 되는 기술적 문제에 관해 설명합니다.

다음은 C/C++ 디버깅 및 Memory Inspector를 처음 사용하는 경우 관련된 블로그 게시물입니다.

소개

Memory Inspector는 선형 메모리 버퍼를 위한 더 강력한 디버깅 옵션을 제공합니다. C/C++의 경우 WebAssembly 메모리에서 C/C++ 메모리 객체를 검사할 수 있습니다.

주변 WebAssembly 메모리에서 객체의 바이트를 인식하는 것이 어려운 일이었습니다. 객체의 크기와 객체를 시작할 때부터 바이트 수를 계산해야 합니다. 아래 스크린샷에서는 10개의 요소로 구성된 int32 배열의 첫 번째 바이트가 선택되었지만 어떤 바이트가 배열에 속하는지 즉시 명확하지는 않습니다. 객체에 속하는 모든 바이트를 즉시 인식할 수 있다면 정말 좋지 않을까요?

하나의 바이트가 강조표시된 원래 메모리 검사기의 스크린샷

Memory Inspector에서 객체 강조표시

Chrome 107부터 Memory Inspector는 C/C++ 메모리 객체의 모든 바이트를 강조표시합니다. 이를 통해 주변 기억과 구분할 수 있습니다.

생동감 있게 강조 표시된 배열이 있는 업데이트된 메모리 검사기 스크린샷

아래 동영상을 통해 메모리 검사기의 작동 방식을 확인하세요. Memory Inspector에서 x 배열을 확인하면 강조표시된 메모리가 바로 위에 새로운 칩과 함께 Memory Viewer에 표시됩니다. 이 칩을 통해 강조 표시된 메모리의 이름과 유형을 알려줍니다. 칩을 클릭하여 객체의 메모리로 이동합니다. 칩 위로 마우스를 가져가면 X표 아이콘이 표시됩니다. 이 아이콘을 클릭하면 강조표시가 삭제됩니다.

검사하는 객체 외부에서 한 바이트를 선택하면 주의를 분산시키지 않도록 하이라이트의 초점이 흐려집니다. 초점을 다시 맞추려면 객체의 바이트나 칩을 다시 클릭합니다.

객체 강조 표시 지원은 배열에만 국한되지 않습니다. 구조체, 객체, 포인터도 검사할 수 있습니다. 이러한 변경사항으로 그 어느 때보다도 쉽게 C/C++ 앱의 메모리를 탐색할 수 있습니다.

사용해 보시겠어요? 다음을 수행해야 합니다.

  • Chrome 107 이상을 실행합니다.
  • C/C++ DWARF 확장 프로그램을 설치합니다.
  • DevTools > 설정 페이지. 설정 > 실험 > WebAssemble Debugging: 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를 찾아 문제를 디버그합니다. 다음 데모도 참조하세요. 먼저 Memory Inspector에서 배열을 검사하고 numbers 배열에 예상대로 정수 1, 2, 3, 4만 포함되어 있음을 확인합니다.

검사된 int32 배열이 있는 열린 메모리 검사기 스크린샷 모든 배열 요소가 강조표시됩니다.

그런 다음 Scope 창에서 lastNumber 변수를 표시하고 포인터가 배열 외부의 정수를 가리키고 있음을 확인합니다. 이 지식을 토대로 프로그래머는 8번째 줄에서 포인터 오프셋을 잘못 계산했다는 사실을 알게 됩니다. ptr + arraySize - 1였어야 합니다.

&#39;lastNumber&#39;라는 포인터가 가리키는 강조 표시된 메모리를 보여주는 열린 메모리 검사기 스크린샷. 강조 표시된 메모리는 이전에 강조표시된 배열의 마지막 바이트 바로 뒤에 있습니다.

이 예시는 장난감 예시이지만 객체 강조표시가 메모리 객체의 크기와 위치를 효과적으로 전달하는 방법을 보여주므로 C/C++ 앱의 메모리 내에서 발생하는 상황을 더 잘 이해하는 데 도움이 됩니다.

DevTools가 강조 표시할 항목을 파악하는 방법

이 섹션에서는 C/C++ 디버깅을 사용 설정하는 도구 생태계를 살펴봅니다. 특히 DevTools, V8, C/C++ DWARF 확장 프로그램, Emscripten을 통해 어떻게 Chrome에서 C/C++ 디버깅을 가능하게 하는지 알아봅니다.

DevTools에서 C/C++ 디버깅의 모든 기능을 활용하려면 다음 두 가지가 필요합니다.

  • Chrome에 설치된 C/C++ DWARF 확장 프로그램
  • 이 블로그 게시물의 안내에 따라 최신 Emscripten 컴파일러를 사용하여 WebAssembly에 컴파일된 C/C++ 소스 파일

그런데 왜일까요? Chrome의 자바스크립트 및 WebAssembly 엔진인 V8은 C 또는 C++를 실행하는 방법을 모릅니다. C/C++ to WebAssembly 컴파일러인 Emscripten을 사용하면 C 또는 C++에서 빌드된 앱을 WebAssembly로 컴파일하여 브라우저에서 실행할 수 있습니다.

컴파일하는 동안 emscripten은 DWARF 디버그 데이터를 바이너리에 삽입합니다. 개략적으로 이 데이터는 확장 프로그램이 C/C++ 변수에 해당하는 WebAssembly 변수 등을 파악하는 데 도움이 됩니다. 이렇게 하면 V8이 실제로 WebAssembly를 실행 중이더라도 DevTools에서 C++ 변수를 표시할 수 있습니다. 궁금한 점이 있으면 이 블로그 게시물에서 DWARF 디버그 데이터의 예시를 확인하세요.

그렇다면 lastNumber를 공개하면 실제로 어떻게 될까요? 메모리 아이콘을 클릭하는 즉시 DevTools가 검사하려는 변수를 확인합니다. 그런 다음 lastNumber의 데이터 유형과 위치에 관한 확장 프로그램을 쿼리합니다. 확장 프로그램이 이 정보로 응답하면 Memory Inspector는 관련 메모리 슬라이스를 표시하고 유형을 파악하며 객체의 크기도 표시할 수 있습니다.

앞의 예에서 lastNumber를 살펴보면 lastNumber: int *를 검사했지만 Memory Inspector의 칩에는 *lastNumber: int이라고 표시됩니다. 어떻게 된 건가요? 검사기는 C++ 스타일의 포인터 역참조를 사용하여 표시되는 객체의 유형을 나타냅니다. 포인터를 검사하면 검사기에서 포인터가 가리키는 대상을 표시합니다.

디버거 단계 주요 사항 유지

Memory Inspector에서 객체를 표시하고 디버거로 단계를 진행할 때 검사기는 여전히 적용 가능하다고 판단하는 경우 강조표시를 유지합니다. 처음에는 이 기능이 로드맵에 포함되어 있지 않았지만 곧 디버깅 환경이 저하된다는 것을 깨달았습니다. 아래 동영상과 같이 모든 단계를 실행한 후 배열을 다시 검사해야 한다고 상상해 보세요.

디버거가 새 중단점에 도달하면 Memory Inspector는 V8 및 이전 강조표시와 연결된 변수의 확장자를 쿼리합니다. 그런 다음 객체의 위치와 유형을 비교합니다. 일치하는 경우 강조표시가 계속됩니다. 위 동영상에는 x 배열에 쓰는 for 루프가 있습니다. 이 작업은 배열의 유형이나 위치를 변경하지 않으므로 배열이 강조 표시됩니다.

이것이 포인터에 어떤 영향을 미치는지 궁금할 수 있습니다. 강조 표시된 포인터를 다른 객체에 다시 할당하면 강조표시된 객체의 이전 위치와 새 위치가 달라서 강조표시가 사라집니다. 새로 가리키는 객체는 WebAssembly Memory의 어디에나 있을 수 있고 이전 메모리 위치와 거의 관련이 없을 가능성이 높으므로 강조 표시를 제거하는 것이 새 메모리 위치로 이동하는 것보다 더 명확합니다. Scope 창에서 메모리 아이콘을 클릭하여 포인터를 다시 강조표시할 수 있습니다.

결론

이 도움말에서는 C/C++ 디버깅을 위한 Memory Inspector 개선사항을 설명했습니다. 새로운 기능을 통해 C/C++ 앱의 메모리 디버깅을 간소화할 수 있기를 바랍니다. 더 개선할 수 있는 제안사항이 있으면 버그를 신고하여 알려주시기 바랍니다.

다음 단계

자세한 내용은 다음을 참고하세요.