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

Chrome 92에서는 선형 메모리 버퍼를 검사하는 도구인 Memory Inspector를 도입했습니다. 이 도움말에서는 C/C++ 디버깅용 검사기를 개선한 방법과 그 과정에서 발생한 기술적 문제에 대해 설명합니다.

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

소개

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

주변 WebAssembly 메모리에서 객체의 바이트를 인식하는 것이 골치 아픈 문제였습니다. 객체의 크기를 알아야 하며 객체 시작 시점부터 바이트 수를 계산해야 합니다. 아래 스크린샷에서는 요소가 10개인 int32 배열의 첫 번째 바이트가 선택되었지만 배열에 속하는 다른 바이트가 즉시 명확하지는 않습니다. 객체에 속하는 모든 바이트를 즉시 인식할 수 있다면 좋지 않을까요?

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

메모리 검사기에서 객체 강조표시

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

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

아래 동영상에서 Memory Inspector의 작동 모습을 확인하세요. Memory Inspector에 배열 x가 표시되면 강조표시된 메모리가 바로 위에 새 칩과 함께 Memory Viewer에 표시됩니다. 이 칩을 통해 강조표시된 추억의 이름과 유형을 알 수 있습니다. 칩을 클릭하여 객체의 메모리로 이동합니다. 칩 위로 마우스를 가져가면 X 표시 아이콘이 나타납니다. 이 아이콘을 클릭하면 강조표시가 삭제됩니다.

검사한 객체 밖의 바이트를 선택하면 강조 표시가 분산되어 주의가 산만해지지 않습니다. 다시 포커스를 맞추려면 객체의 바이트나 칩을 다시 클릭합니다.

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

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

  • Chrome 107 이상을 사용해야 합니다.
  • C/C++ DWARF 확장 프로그램을 설치합니다.
  • DevTools에서 DWARF 디버깅 사용 설정 > 설정을 탭합니다. 설정 > 실험 > WebAssemble 디버깅: 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의 JavaScript 및 WebAssembly 엔진인 V8은 C 또는 C++를 실행하는 방법을 모릅니다. C/C++에서 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에서 객체를 표시하고 디버거를 실행해도 Inspector는 여전히 적용 가능하다고 판단되면 강조 표시를 유지합니다. 초기에는 로드맵에 이 기능이 없었지만 이 기능으로 인해 디버깅 환경이 손상된다는 사실을 금세 깨달았습니다. 아래 동영상과 같이 모든 단계를 실행한 후 배열을 다시 검사해야 한다고 상상해 보세요.

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

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

결론

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

다음 단계

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