Поделиться через


Отладка перемещения по времени — пошаговое руководство по приложению

Логотип отладки по времени с часовым отображением.

В этой лаборатории представлена отладка временных путешествий (TTD), используя небольшую примерную программу с недостатком кода. TTD используется для отладки, идентификации и первопричины проблемы. Хотя проблема в этой небольшой программе легко найти, общая процедура может использоваться в более сложном коде. Эта общая процедура может быть обобщена следующим образом.

  1. Захват трассировки путешествия по времени неудачной программы.
  2. Используйте команду dx (выражение объектной модели отладчика), чтобы найти событие исключения, хранящееся в записи.
  3. Используйте команду !tt (путешествие по времени) для перемещения в положение события исключения в трассировке.
  4. С этого момента один шаг трассировки выполняется обратно до тех пор, пока в области не появится код сбоя.
  5. При использовании кода сбоя в области просмотрите локальные значения и разработайте гипотезу переменной, которая может содержать неверное значение.
  6. Определите адрес памяти переменной с неправильным значением.
  7. Задайте точку останова доступа к памяти (ba) в адресе подозрительной переменной с помощью команды ba (Break on Access).
  8. Используйте g-, чтобы вернуться к последней точке доступа к памяти подозрительной переменной.
  9. Узнайте, является ли это расположение или несколько инструкций ранее, является точкой ошибки кода. Если да, то все готово. Если неверное значение произошло из другой переменной, задайте еще один разрыв для точки останова доступа во второй переменной.
  10. Используйте g-, чтобы вернуться к последней точке доступа к памяти во второй подозрительной переменной. Узнайте, содержит ли это расположение или несколько инструкций, прежде чем содержать ошибку кода. Если да, то все готово.
  11. Повторите этот процесс, пока не будет указан код, задающий неверное значение, вызвавшее ошибку.

Хотя общие методы, описанные в этой процедуре, применяются к широкому набору проблем кода, существуют уникальные проблемы кода, требующие уникального подхода. Методы, показанные в пошаговом руководстве, должны служить для расширения набора средств отладки и проиллюстрируют некоторые возможности трассировки TTD.

Цели лаборатории

После завершения этой лаборатории вы сможете использовать общую процедуру с трассировкой перемещения по времени для поиска проблем в коде.

Организация занятия

Для выполнения лаборатории потребуется следующее оборудование.

  • Ноутбук или настольный компьютер под управлением Windows 10 или Windows 11

Для выполнения лаборатории вам потребуется следующее программное обеспечение.

  • The WinDbg. Сведения об установке WinDbg см. в статье "Установка WinDbg"
  • Visual Studio для создания примера кода C++.

Лаборатория содержит следующие три раздела.

Раздел 1. Создание примера кода

В разделе 1 вы создадите пример кода с помощью Visual Studio.

Создание примера приложения в Visual Studio

  1. В Microsoft Visual Studio щелкните файл>нового>проекта или решения... и выберите шаблоны Visual C++.

    Выберите консольное приложение Win32.

    Укажите имя проекта DisplayGreeting и нажмите кнопку "ОК".

  2. Снимите флажок проверки жизненного цикла разработки безопасности (SDL).

    Параметры мастера приложений Win32 в Visual Studio.

  3. Нажмите кнопку "Готово".

  4. Вставьте следующий текст в область DisplayGreeting.cpp в Visual Studio.

    // DisplayGreeting.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <array>
    #include <stdio.h>
    #include <string.h>
    
    void GetCppConGreeting(wchar_t* buffer, size_t size)
    {
        wchar_t const* const message = L"HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL DEBUGGING!";
    
        wcscpy_s(buffer, size, message);
    }
    
    int main()
    {
         std::array <wchar_t, 50> greeting{};
         GetCppConGreeting(greeting.data(), sizeof(greeting));
    
         wprintf(L"%ls\n", greeting.data());
    
         return 0;
    }
    
  5. В Visual Studio щелкните свойства Project>DisplayGreeting. Затем щелкните C/C++ и создание кода.

    Задайте следующие свойства.

    Параметр Значение
    Проверка безопасности Отключение проверки безопасности (/GS-)
    Базовые проверки среды выполнения По умолчанию

    Примечание.

    Хотя эти параметры не рекомендуется, можно представить сценарий, в котором кто-то советует использовать эти параметры для ускорения написания кода или упрощения определенных сред тестирования.

  6. В Visual Studio щелкните "Сборка решения сборки>".

    Если все идет хорошо, окна сборки должны отображать сообщение, указывающее, что сборка выполнена успешно.

  7. Поиск созданных примеров файлов приложения

    В Обозреватель решений щелкните правой кнопкой мыши проект DisplayGreeting и выберите "Открыть папку" в проводнике.

    Перейдите в папку отладки, содержащую соответствующий файл exe и pdb символов для примера. Например, вы перейдете в папку C:\Projects\DisplayGreeting\Debug, если это папка, в которой хранятся проекты.

  8. Запуск примера приложения с ошибкой кода

    Дважды щелкните файл exe, чтобы запустить пример приложения.

    Снимок экрана: консоль с файлом DisplayGreeting.exe.

    Если откроется это диалоговое окно, нажмите кнопку "Закрыть программу"

    Снимок экрана диалогового окна с сообщением

    В следующем разделе пошагового руководства мы запишите выполнение примера приложения, чтобы узнать, можно ли определить, почему это исключение происходит.

Раздел 2. Запись трассировки примера DisplayGreeting

В разделе 2 вы запишите трассировку неправильного примера приложения DisplayGreeting

Чтобы запустить пример приложения и записать трассировку TTD, выполните следующие действия. Общие сведения о записях трассировок TTD см. в разделе "Отладка перемещения по времени" — запись трассировки

  1. Запустите WinDbg от имени администратора, чтобы иметь возможность записывать трассировки перемещения по времени.

  2. В WinDbg выберите "Запуск запуска>файла" для запуска исполняемого файла>(дополнительно).

  3. Введите путь к исполняемому файлу в пользовательском режиме, который вы хотите записать, или нажмите кнопку "Обзор ", чтобы перейти к исполняемому файлу. Сведения о работе с исполняемым меню запуска в WinDbg см. в разделе WinDbg — запуск сеанса пользовательского режима.

    Снимок экрана: WinDbg с флажком

  4. Установите флажок "Запись с отладчиком по времени", чтобы записать трассировку при запуске исполняемого файла.

  5. Нажмите кнопку "Настроить" и "Запись", чтобы начать запись .

  6. Когда появится диалоговое окно "Настройка записи", нажмите кнопку " Запись ", чтобы запустить исполняемый файл и начать запись.

    Снимок экрана: WinDbg, отображающий диалоговое окно

  7. Откроется диалоговое окно записи, показывающее, что трассировка записывается. Вскоре после этого приложение завершает работу.

  8. Нажмите кнопку "Закрыть программу", чтобы закрыть диалоговое окно "DisplayGreeting перестало работать".

    Диалоговое окно с приложением DisplayGreeting перестало работать.

  9. После сбоя программы файл трассировки будет закрыт и записан на диск.

    Снимок экрана: выходные данные WinDbg, отображающие индексированные ключевые кадры 1/1.

  10. Отладчик автоматически откроет файл трассировки и индексировать его. Индексирование — это процесс, который обеспечивает эффективную отладку файла трассировки. Этот процесс индексирования займет больше времени для больших файлов трассировки.

    (5120.2540): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: D:0 [Unindexed] Index
    !index
    Indexed 10/22 keyframes
    Indexed 20/22 keyframes
    Indexed 22/22 keyframes
    Successfully created the index in 755ms.
    

Примечание.

Ключевой кадр — это расположение трассировки, используемое для индексирования. Ключевые кадры создаются автоматически. Более крупные трассировки будут содержать дополнительные ключевые кадры.

  1. На этом этапе вы находитесь в начале файла трассировки и готовы к перемещению вперед и назад во времени.

    Теперь, когда вы записали трассировку TTD, вы можете воспроизвести трассировку обратно или работать с файлом трассировки, например совместно с ним. Дополнительные сведения о работе с файлами трассировки см. в статье "Отладка перемещения по времени" — работа с файлами трассировки

В следующем разделе этой лаборатории мы проанализируем файл трассировки, чтобы найти проблему с нашим кодом.

Раздел 3. Анализ записи файла трассировки для выявления проблемы с кодом

В разделе 3 вы проанализируете запись файла трассировки, чтобы определить проблему кода.

Настройка среды WinDbg

  1. Добавьте расположение локального символа в путь к символу и перезагрузите их, введя следующие команды.

    .sympath+ C:\MyProjects\DisplayGreeting\Debug
    .reload
    
  2. Добавьте расположение локального кода в исходный путь, введя следующую команду.

    .srcpath+ C:\MyProjects\DisplayGreeting\DisplayGreeting
    
  3. Чтобы просмотреть состояние стека и локальных переменных, на ленте WinDbg выберите "Вид" и "Локальные" и "Вид" и "Стек". Упорядочение окон для их просмотра, исходного кода и окон команд одновременно.

  4. На ленте WinDbg выберите "Исходный" и "Файл с открытым исходным кодом". Найдите файл DisplayGreeting.cpp и откройте его.

Проверка исключения

  1. Когда файл трассировки был загружен, он отображает сведения о возникновении исключения.

    2fa8.1fdc): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 15:0
    eax=68ef8100 ebx=00000000 ecx=77a266ac edx=69614afc esi=6961137c edi=004da000
    eip=77a266ac esp=0023f9b4 ebp=0023fc04 iopl=0         nv up ei pl nz na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
    ntdll!LdrpInitializeProcess+0x1d1c:
    77a266ac 83bdbcfeffff00  cmp     dword ptr [ebp-144h],0 ss:002b:0023fac0=00000000
    
  2. Используйте команду dx для перечисления всех событий записи. Событие исключения отображается в событиях.

    0:000> dx -r1 @$curprocess.TTD.Events
    ...
    [0x2c]           : Module Loaded at position: 9967:0
    [0x2d]           : Exception at 9BDC:0
    [0x2e]           : Thread terminated at 9C43:0
    ...
    
    

    Примечание.

    В этом пошаговом руководстве три периода используются для указания того, что лишние выходные данные были удалены.

  3. Щелкните событие исключения, чтобы отобразить сведения об этом событии TTD.

    0:000> dx -r1 @$curprocess.TTD.Events[17]
    @$curprocess.TTD.Events[17]                 : Exception at 68:0
        Type             : Exception
        Position         : 68:0 [Time Travel]
        Exception        : Exception of type Hardware at PC: 0X540020
    
  4. Щелкните поле "Исключение", чтобы продолжить детализацию данных исключений.

    0:000> dx -r1 @$curprocess.TTD.Events[17].Exception
    @$curprocess.TTD.Events[17].Exception                 : Exception of type Hardware at PC: 0X540020
        Position         : 68:0 [Time Travel]
        Type             : Hardware
        ProgramCounter   : 0x540020
        Code             : 0xc0000005
        Flags            : 0x0
        RecordAddress    : 0x0
    

    Данные исключения указывают на то, что это ошибка оборудования, вызываемая ЦП. Он также предоставляет код исключения 0xc0000005, указывающий, что это нарушение доступа. Обычно это означает, что мы пытались записать в память, к которому у нас нет доступа.

  5. Щелкните ссылку [Время перемещения] в событии исключения, чтобы перейти к этой позиции в трассировке.

    0:000> dx @$curprocess.TTD.Events[17].Exception.Position.SeekTo()
    Setting position: 68:0
    
    @$curprocess.TTD.Events[17].Exception.Position.SeekTo()
    (16c8.1f28): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 68:0
    eax=00000000 ebx=00cf8000 ecx=99da9203 edx=69cf1a6c esi=00191046 edi=00191046
    eip=00540020 esp=00effe4c ebp=00520055 iopl=0         nv up ei pl zr na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
    00540020 ??
    

    Обратите внимание, что в этом выходных данных стек и базовый указатель указывают на два очень разных адреса.

    esp=00effe4c ebp=00520055
    

    Это может указывать на повреждение стека, возможно, возвращенную функцию, а затем поврежденную стек. Чтобы проверить это, необходимо вернуться к состоянию ЦП и узнать, можно ли определить, когда произошла ошибка стека.

Проверьте локальные переменные и задайте точку останова кода

В точке сбоя трассировки обычно выполняется несколько шагов после истинной причины обработки ошибок. С путешествием по времени мы можем вернуть инструкцию за раз, чтобы найти истинную первопричину.

  1. На ленте "Главная" используйте команду "Шаг назад" для выполнения трех инструкций. По мере этого продолжайте изучать окна стека и памяти.

    В командном окне будут отображаться позиции перемещения по времени и регистры при шаге назад три инструкции.

    0:000> t-
    Time Travel Position: 67:40
    eax=00000000 ebx=00cf8000 ecx=99da9203 edx=69cf1a6c esi=00191046 edi=00191046
    eip=00540020 esp=00effe4c ebp=00520055 iopl=0         nv up ei pl zr na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
    00540020 ??              ???
    
    0:000> t-
    Time Travel Position: 67:3F
    eax=00000000 ebx=00cf8000 ecx=99da9203 edx=69cf1a6c esi=00191046 edi=00191046
    eip=0019193d esp=00effe48 ebp=00520055 iopl=0         nv up ei pl zr na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
    DisplayGreeting!main+0x4d:
    0019193d c3
    
    0:000> t-
    Time Travel Position: 67:39
    eax=0000004c ebx=00cf8000 ecx=99da9203 edx=69cf1a6c esi=00191046 edi=00191046
    eip=00191935 esp=00effd94 ebp=00effe44 iopl=0         nv up ei pl nz ac po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
    DisplayGreeting!main+0x45:
    

    Примечание.

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

  2. На этом этапе трассировки наш стек и базовый указатель имеют значения, которые имеют больше смысла, поэтому, по-видимому, мы приближаемся к точке в коде, где произошла коррупция.

    esp=00effd94 ebp=00effe44
    

    Кроме того, в окне локальных параметров содержатся значения из целевого приложения, а окно исходного кода выделяет строку кода, которая готова выполняться на этом этапе трассировки.

  3. Для дальнейшего изучения можно открыть окно памяти, чтобы просмотреть содержимое рядом с адресом памяти базового указателя 0x00effe44.

  4. Чтобы отобразить связанные символы ASCII, на ленте памяти выберите текст и ASCII.

    Снимок экрана: предварительная версия WinDbg, отображающая выходные данные ASCII памяти и окно исходного кода.

  5. Вместо базового указателя, указывающего на инструкцию, указывающую на текст сообщения. Так что что-то не так здесь, это может быть близко к моменту времени, что мы повреждены стек. Для дальнейшего изучения мы установим точку останова.

Примечание.

В этом очень маленьком примере было бы довольно легко просто выглядеть в коде, но если есть сотни строк кода и десятки вложенных шаблонов, описанные здесь, можно использовать для уменьшения времени, необходимого для поиска проблемы.

Точки останова и TTD

Использование точек останова — это распространенный подход для приостановки выполнения кода на каком-то событии, интересующем вас. TTD позволяет задать точку останова и вернуться назад до тех пор, пока эта точка останова не будет достигнута после записи трассировки. Возможность проверить состояние процесса после того, как возникла проблема, чтобы определить оптимальное расположение точки останова, позволяет дополнительным рабочим процессам отладки, уникальным для TTD.

Точки останова доступа к памяти

Точки останова можно задать при доступе к расположению памяти. Используйте команду ba (break on access) со следующим синтаксисом.

ba <access> <size> <address> {options}
Вариант Описание
e выполнение (при получении инструкции из адреса ЦП)
r чтение и запись (при чтении или записи ЦП в адрес)
w запись (когда ЦП записывает в адрес)

Обратите внимание, что вы можете задать только четыре точки останова данных в любой момент времени, и вам нужно убедиться, что вы правильно выравниваете данные или не активируете точку останова (слова должны заканчиваться адресами, делимыми на 2, dwords должны быть делимыми на 4, а квадроты на 0 или 8).

Настройка точки останова доступа к памяти для базового указателя

  1. На этом этапе трассировки мы хотели бы задать точку останова для доступа к памяти записи к базовому указателю - ebp, который в нашем примере равен 000effe444. Для этого используйте команду ba с помощью адреса, который мы хотим отслеживать. Мы хотим отслеживать записи для четырех байтов, поэтому мы указываем w4.

    0:000> ba w4 00effe44
    
  2. Выберите "Вид ", а затем точки останова, чтобы убедиться, что они заданы как предполагаемые.

    Снимок экрана: окно точек останова WinDbg, отображающее одну точку останова.

  3. В меню "Главная" выберите "Вернуться назад", пока точка останова не будет достигнута.

    0:000> g-
    Breakpoint 0 hit
    Time Travel Position: 5B:92
    eax=0000000f ebx=003db000 ecx=00000000 edx=00cc1a6c esi=00d41046 edi=0053fde8
    eip=00d4174a esp=0053fcf8 ebp=0053fde8 iopl=0         nv up ei pl nz ac pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
    DisplayGreeting!DisplayGreeting+0x3a:
    00d4174a c745e000000000  mov     dword ptr [ebp-20h],0 ss:002b:0053fdc8=cccccccc
    
  4. Выберите "Вид" и "Локальные". В окне локальных параметров видно, что целевая переменная имеет только часть сообщения, в то время как источник содержит весь текст. Эта информация поддерживает идею повреждения стека.

    Снимок экрана: WinDbg с окном

  5. На этом этапе мы можем проверить стек программ, чтобы узнать, какой код активен. На ленте "Вид" выберите "Стек".

    Снимок экрана: WinDbg, отображающий окно стека.

Так как маловероятно, что у предоставленной корпорацией Майкрософт функции wscpy_s() будет ошибка кода, как в этом случае, мы ищем дополнительные сведения в стеке. В стеке показано, что приветствие!main вызывает Приветствие! GetCppConGreeting. В нашем очень маленьком примере кода мы могли просто открыть код на этом этапе и, скорее всего, найти ошибку довольно легко. Но чтобы проиллюстрировать методы, которые можно использовать с более крупной, более сложной программой, мы установим новую точку останова для дальнейшего изучения.

Настройка точки останова доступа для функции GetCppConGreeting

  1. Используйте окно точек останова, чтобы очистить существующую точку останова, щелкнув правой кнопкой мыши существующую точку останова и выбрав "Удалить".

  2. Определите адрес DisplayGreeting! Функция GetCppConGreeting с помощью команды DX .

    0:000> dx &DisplayGreeting!GetCppConGreeting
    &DisplayGreeting!GetCppConGreeting                 : 0xb61720 [Type: void (__cdecl*)(wchar_t *,unsigned int)]
        [Type: void __cdecl(wchar_t *,unsigned int)]
    
  3. Используйте команду ba, чтобы задать точку останова для доступа к памяти. Так как функция будет только считываться из памяти для выполнения, нам нужно задать точку останова r - чтение.

    0:000> ba r4 b61720
    
  4. Убедитесь, что точка останова "Аппаратное чтение" активна в окне точек останова.

    Снимок экрана: окно точек останова WinDbg с одной аппаратной точкой останова.

  5. Так как мы задаемся вопросом о размере строки приветствия, мы зададим окно просмотра, чтобы отобразить значение sizeof(приветствие). На ленте "Вид" выберите "Смотреть" и укажите sizeof(приветствие). Если значение не находится в области, откроется окно наблюдения. Не удается привязать имя "приветствие".

    Снимок экрана: WinDbg с окном

  6. В меню "Путешествие по времени" используйте время для запуска или использования !tt 0команды, чтобы перейти к началу трассировки.

    0:000> !tt 0
    Setting position to the beginning of the trace
    Setting position: 15:0
    (1e5c.710): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 15:0
    eax=68e28100 ebx=00000000 ecx=77a266ac edx=69e34afc esi=69e3137c edi=00fa2000
    eip=77a266ac esp=00ddf3b8 ebp=00ddf608 iopl=0         nv up ei pl nz na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
    ntdll!LdrpInitializeProcess+0x1d1c:
    77a266ac 83bdbcfeffff00  cmp     dword ptr [ebp-144h],0 ss:002b:00ddf4c4=00000000
    
  7. В меню "Главная" выберите "Перейти " или используйте g команду, чтобы перейти вперед в коде до тех пор, пока точка останова не будет достигнута.

    0:000> g
    Breakpoint 2 hit
    Time Travel Position: 4B:1AD
    eax=00ddf800 ebx=00fa2000 ecx=00ddf800 edx=00b61046 esi=00b61046 edi=00b61046
    eip=00b61721 esp=00ddf7a4 ebp=00ddf864 iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
    DisplayGreeting!GetCppConGreeting+0x1:
    00b61721 8bec            mov     ebp,esp
    
  8. В меню "Главная" выберите "Шаг назад" или используйте g-u команду, чтобы вернуть один шаг.

    0:000> g-u
    Time Travel Position: 4B:1AA
    eax=00ddf800 ebx=00fa2000 ecx=00ddf800 edx=00b61046 esi=00b61046 edi=00b61046
    eip=00b61917 esp=00ddf7ac ebp=00ddf864 iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
    DisplayGreeting!main+0x27:
    00b61917 e8def7ffff      call    DisplayGreeting!ILT+245(?GetCppConGreetingYAXPA_WIZ) (00b610fa)
    
  9. Похоже, мы нашли первопричину. Массив приветствий , объявленный нами, составляет 50 символов в длину, а размер (приветствие), который мы передаваем в GetCppConGreeting, 0x64, 100.

    Снимок экрана: WinDbg, отображающий код DisplayGreeting с окном

    Как мы рассмотрим проблему размера, мы также замечаем, что сообщение имеет длину 75 символов и равно 76 при включении конца строкового символа.

    HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL DEBUGGING!
    
  10. Одним из способов исправления кода будет расширение размера массива символов до 100.

    std::array <wchar_t, 100> greeting{};
    

    Кроме того, необходимо изменить sizeof(greeting) на size(greeting) в этой строке кода.

     GetCppConGreeting(greeting.data(), size(greeting));
    
  11. Чтобы проверить эти исправления, мы можем перекомпилировать код и убедиться, что он выполняется без ошибок.

Настройка точки останова с помощью исходного окна

  1. Альтернативным способом выполнения этого исследования будет установка точки останова, щелкнув любую строку кода. Например, щелкнув справа от строки определения std:array в окне источника, установите точку останова.

    Снимок экрана: окно источника в WinDbg с точкой останова, установленной в std::array.

  2. В меню "Путешествие по времени" используйте команду "Время" для запуска команды, чтобы перейти к началу трассировки.

    0:000> !tt 0
    Setting position to the beginning of the trace
    Setting position: 15:0
    (1e5c.710): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 15:0
    eax=68e28100 ebx=00000000 ecx=77a266ac edx=69e34afc esi=69e3137c edi=00fa2000
    eip=77a266ac esp=00ddf3b8 ebp=00ddf608 iopl=0         nv up ei pl nz na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
    ntdll!LdrpInitializeProcess+0x1d1c:
    77a266ac 83bdbcfeffff00  cmp     dword ptr [ebp-144h],0 ss:002b:00ddf4c4=00000000
    
  3. На домашней ленте нажмите кнопку "Перейти ", чтобы вернуться, пока точка останова не будет достигнута.

    Breakpoint 0 hit
    Time Travel Position: 5B:AF
    eax=0000000f ebx=00c20000 ecx=00000000 edx=00000000 esi=013a1046 edi=00effa60
    eip=013a17c1 esp=00eff970 ebp=00effa60 iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
    DisplayGreeting!DisplayGreeting+0x41:
    013a17c1 8bf4            mov     esi,esp
    

Установка точки останова для точки останова доступа для переменной приветствия

Другим альтернативным способом выполнения этого исследования будет установка точки останова на подозрительных переменных и изучение того, какой код изменяет их. Например, чтобы задать точку останова в переменной приветствия в методе GetCppConGreeting, используйте эту процедуру.

В этом пошаговом руководстве предполагается, что вы все еще находитесь в точке останова из предыдущего раздела.

  1. В представлении , а затем в локальном режиме. В окне локальных параметров приветствие доступно в текущем контексте, поэтому мы сможем определить расположение памяти.

  2. Используйте команду DX для проверки массива приветствия.

    0:000> dx &greeting
    &greeting                 : ddf800 : { size=50 } [Type: std::array<wchar_t,50> *]
       [<Raw View>]     [Type: std::array<wchar_t,50>]
       [0]              : 3 [Type: wchar_t]
       [1]              : 0 [Type: wchar_t]
    

    В этой трассировке приветствие находится в памяти в ddf800.

  3. Используйте окно точек останова, чтобы очистить любую существующую точку останова, щелкнув правой кнопкой мыши существующую точку останова и выбрав "Удалить".

  4. Задайте точку останова с помощью команды ba с помощью адреса памяти, который мы хотим отслеживать для доступа на запись.

    ba w4 ddf800
    
  5. В меню "Путешествие по времени" используйте команду "Время" для запуска команды, чтобы перейти к началу трассировки.

    0:000> !tt 0
    Setting position to the beginning of the trace
    Setting position: 15:0
    (1e5c.710): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 15:0
    eax=68e28100 ebx=00000000 ecx=77a266ac edx=69e34afc esi=69e3137c edi=00fa2000
    eip=77a266ac esp=00ddf3b8 ebp=00ddf608 iopl=0         nv up ei pl nz na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
    ntdll!LdrpInitializeProcess+0x1d1c:
    77a266ac 83bdbcfeffff00  cmp     dword ptr [ebp-144h],0 ss:002b:00ddf4c4=00000000
    
  6. В меню "Главная" выберите перейти к первой точке доступа к памяти массива приветствий.

    0:000> g-
    Breakpoint 0 hit
    Time Travel Position: 5B:9C
    eax=cccccccc ebx=002b1000 ecx=00000000 edx=68d51a6c esi=013a1046 edi=001bf7d8
    eip=013a1735 esp=001bf6b8 ebp=001bf7d8 iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
    DisplayGreeting!GetCppConGreeting+0x25:
    013a1735 c745ec04000000  mov     dword ptr [ebp-14h],4 ss:002b:001bf7c4=cccccccc
    

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

Используйте TTD. Объекты памяти для просмотра доступа к памяти

Другой способ определить, к каким точкам в памяти трассировки был доступ, — использовать TTD. Объекты памяти и команда DX.

  1. Используйте команду DX для проверки массива приветствия.

    0:000> dx &greeting
    &greeting                 : 0xddf800 [Type: std::array<wchar_t,50> *]
       [+0x000] _Elems           : "꽘棶檙瞝???" [Type: wchar_t [50]]
    

    В этой трассировке приветствие находится в памяти в ddf800.

  2. Используйте команду DX, чтобы просмотреть четыре байта в памяти, начиная с этого адреса с доступом на чтение записи.

    0:000> dx -r1 @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")
    @$cursession.TTD.Memory(0x1bf7d0,0x1bf7d4, "rw")                
        [0x0]           
        [0x1]           
        [0x2]           
        [0x3]           
        [0x4]           
        [0x5]           
        [0x6]           
        [0x7]           
        [0x8]           
        [0x9]           
        [0xa]           
        ...         
    
  3. Щелкните любой из вхождения, чтобы отобразить дополнительные сведения об этом вхождения доступа к памяти.

    0:000> dx -r1 @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")[5]
    @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")[5]                
        EventType        : MemoryAccess
        ThreadId         : 0x710
        UniqueThreadId   : 0x2
        TimeStart        : 27:3C1 [Time Travel]
        TimeEnd          : 27:3C1 [Time Travel]
        AccessType       : Write
        IP               : 0x6900432f
        Address          : 0xddf800
        Size             : 0x4
        Value            : 0xddf818
        OverwrittenValue : 0x0
        SystemTimeStart  : Monday, November 18, 2024 23:01:43.400
        SystemTimeEnd    : Monday, November 18, 2024 23:01:43.400
    
  4. Щелкните [Время перемещения] для timeStart, чтобы разместить трассировку в момент времени.

    0:000> dx @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")[5].TimeStart.SeekTo()
    @$cursession.TTD.Memory(0xddf800,0xddf804, "rw")[5].TimeStart.SeekTo()
    (1e5c.710): Break instruction exception - code 80000003 (first/second chance not available)
    Time Travel Position: 27:3C1
    eax=00ddf81c ebx=00fa2000 ecx=00ddf818 edx=ffffffff esi=00000000 edi=00b61046
    eip=6900432f esp=00ddf804 ebp=00ddf810 iopl=0         nv up ei pl nz ac po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
    ucrtbased!_register_onexit_function+0xf:
    6900432f 51              push    ecx
    
  5. Если мы заинтересованы в последнем вхождения доступа к памяти чтения и записи в трассировке, мы можем щелкнуть последний элемент в списке или добавить его. Функция Last() до конца команды DX.

    0:000> dx -r1 @$cursession.TTD.Memory(0xddf800,0xddf804, "rw").Last()
    @$cursession.TTD.Memory(0xddf800,0xddf804, "rw").Last()                
        EventType        : MemoryAccess
        ThreadId         : 0x710
        UniqueThreadId   : 0x2
        TimeStart        : 53:100E [Time Travel]
        TimeEnd          : 53:100E [Time Travel]
        AccessType       : Read
        IP               : 0x690338e4
        Address          : 0xddf802
        Size             : 0x2
        Value            : 0x45
        SystemTimeStart  : Monday, November 18, 2024 23:01:43.859
        SystemTimeEnd    : Monday, November 18, 2024 23:01:43.859
    
  6. Затем мы можем щелкнуть [Время путешествия], чтобы перейти к этой позиции в трассировке и узнать больше о выполнении кода на этом этапе, используя методы, описанные ранее в этой лаборатории.

Дополнительные сведения о TTD. Объекты памяти см. в разделе TTD. Объект памяти.

Итоги

В этом очень маленьком примере проблема могла быть определена путем просмотра нескольких строк кода, но в более крупных программах методы, представленные здесь, можно использовать для уменьшения времени, необходимого для поиска проблемы.

После записи трассировки можно совместно использовать шаги трассировки и повтора, и проблема будет воспроизведена на любом компьютере.

См. также

Отладка временных путешествий — обзор

Отладка перемещения по времени — запись

Отладка перемещения по времени — воспроизведение трассировки

Отладка перемещения по времени — работа с файлами трассировки