Расширение инспектора памяти для отладки C/C++

В Chrome 92 мы представили Memory Inspector — инструмент для проверки линейных буферов памяти. В этой статье мы обсудим, как мы улучшили Инспектор для отладки C/C++, а также технические проблемы, возникшие при этом.

Вот несколько важных сообщений в блоге, если вы новичок в отладке C/C++ и инспекторе памяти :

Введение

Инспектор памяти предоставляет вам более мощные возможности отладки для линейных буферов памяти. В случае C/C++ вы можете проверять объекты памяти C/C++ в памяти WebAssembly.

Распознавание байтов вашего объекта среди окружающей памяти WebAssembly было болезненной проблемой. Вы должны знать размер объекта и считать байты с начала объекта. На снимке экрана ниже выбран первый байт массива int32 из 10 элементов, но не сразу понятно, какие еще байты принадлежат этому массиву. Было бы здорово, если бы вы могли мгновенно распознавать все байты, принадлежащие объекту, не правда ли?

Снимок экрана исходного инспектора памяти с одним выделенным байтом

Подсветка объектов в инспекторе памяти

Начиная с Chrome 107, инспектор памяти выделяет все байты объекта памяти C/C++. Это поможет вам отличить их от окружающих воспоминаний.

Скриншот обновленного инспектора памяти с ярко выделенным массивом

Посмотрите видео ниже, чтобы увидеть инспектор памяти в действии. Когда вы открываете массив x в инспекторе памяти, в средстве просмотра памяти появляется выделенная память вместе с новым чипом прямо над ней. Этот чип напоминает название и тип выделенной памяти. Нажмите на чип, чтобы перейти в память объекта. Если навести курсор на фишку, появится значок крестика — нажмите на него, чтобы убрать подсветку.

Когда вы выбираете байт за пределами проверяемого объекта, подсветка расфокусируется, чтобы вас не отвлекать. Чтобы снова сфокусировать его, снова щелкните любой из байтов объекта или чипа.

Поддержка выделения объектов не ограничивается массивами. Вы также можете проверять структуры, объекты и указатели. Эти изменения упрощают изучение памяти ваших приложений C/C++!

Хотите попробовать? Вам нужно будет:

  • У вас Chrome 107 или новее.
  • Установите расширение C/C++ DWARF.
  • Включить отладку DWARF в DevTools > Настройки. Настройки > Эксперименты > Отладка 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 содержит только целые числа 1 , 2 , 3 и 4 , как и ожидалось.

Скриншот открытого инспектора памяти с проверенным массивом int32. Все элементы массива выделены.

Затем они открывают переменную lastNumber на панели «Область» и замечают, что указатель указывает на целое число за пределами массива! Обладая этими знаниями, программист понимает, что они неправильно посчитали смещение указателя в строке 8. Оно должно было быть ptr + arraySize - 1 .

Снимок экрана открытого инспектора памяти, показывающий выделенную память, на которую указывает указатель с именем «lastNumber». Выделенная память находится сразу после последнего байта ранее выделенного массива.

Хотя это игрушечный пример, он иллюстрирует, как подсветка объектов эффективно передает размер и положение объектов памяти, что может помочь вам лучше понять, что происходит внутри памяти вашего приложения C/C++.

Как DevTools определяет, что выделить

В этом разделе мы рассмотрим экосистему инструментов, обеспечивающих отладку C/C++. В частности, вы узнаете, как DevTools, V8, расширение C/C++ DWARF и Emscripten делают возможной отладку C/C++ в Chrome.

Чтобы раскрыть всю мощь отладки C/C++ в DevTools, вам нужны две вещи:

  • Расширение C/C++ DWARF, установленное в Chrome
  • Исходные файлы C/C++, скомпилированные в WebAssembly с помощью новейшего компилятора Emscripten, как описано в этом сообщении блога.

Но почему? V8 , движок JavaScript и WebAssembly Chrome, не знает, как выполнять C или C++. Благодаря Emscripten , компилятору C/C++ в WebAssembly, вы можете компилировать приложения, созданные на C или C++, как WebAssembly и выполнять их в браузере!

Во время компиляции emscripten встроит данные отладки DWARF в ваш двоичный файл. На высоком уровне эти данные помогают расширению выяснить, какие переменные WebAssembly соответствуют вашим переменным C/C++ и многое другое. Таким образом, DevTools сможет показать вам переменные C++, несмотря на то, что в V8 на самом деле работает WebAssembly. Если вам интересно, ознакомьтесь с этой публикацией в блоге , где приведен пример отладочных данных DWARF.

Так что же на самом деле происходит, когда вы раскрываете lastNumber ? Как только вы нажмете на значок памяти, DevTools проверит, какую переменную вы хотите проверить. Затем он запрашивает расширение по типу данных и местоположению lastNumber . Как только расширение ответит этой информацией, инспектор памяти сможет отобразить соответствующий фрагмент памяти и, зная его тип, также может показать вам размер объекта.

Если вы посмотрите на lastNumber в предыдущем примере, вы можете заметить, что мы проверили lastNumber: int * , но чип в инспекторе памяти говорит *lastNumber: int , что это дает? Инспектор использует разыменование указателя в стиле C++, чтобы указать тип отображаемого вам объекта! Если вы проверите указатель, инспектор покажет вам, на что он указывает.

Сохраняющиеся выделения на этапах отладчика.

Когда вы открываете объект в инспекторе памяти и переходите к отладчику, инспектор сохраняет выделение, если считает, что оно все еще применимо. Изначально эта функция не была включена в наш план действий, но мы быстро поняли, что это ставит под угрозу ваш опыт отладки. Представьте себе, что вам придется повторно проверять массив после каждого шага, как показано в видео ниже!

Когда отладчик достигает новой точки останова, инспектор памяти снова запрашивает V8 и расширение переменной, связанной с предыдущим выделением. Затем он сравнивает расположение и типы объектов. Если они совпадают, выделение сохраняется. В видео выше есть запись цикла for в массив x . Эти операции не меняют тип или положение массива, поэтому он остается выделенным.

Вы можете задаться вопросом, как это влияет на указатели. Если у вас есть выделенный указатель и вы повторно назначили его другому объекту, старое и новое положение выделенных объектов различаются, и выделение исчезает. Поскольку новый объект, на который указывает курсор, может находиться где угодно в памяти WebAssembly и, скорее всего, будет иметь мало отношения к предыдущей ячейке памяти, удаление выделения будет более очевидным, чем переход к новой ячейке памяти. Вы можете снова выделить указатель, щелкнув его значок памяти на панели «Область» .

Заключение

В этой статье описаны наши улучшения инспектора памяти для отладки C/C++. Мы надеемся, что новые функции упростят отладку памяти ваших приложений C/C++! Если у вас есть предложения по дальнейшему улучшению, дайте нам знать, сообщив об ошибке !

Что дальше

Чтобы узнать больше, см.: