Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой лаборатории представляется отладка с возможностью перемотки времени (TTD), на примере небольшой демонстрационной программы с дефектом в коде. TTD используется для отладки, идентификации и первопричины проблемы. Хотя проблема в этой небольшой программе легко найти, общая процедура может использоваться в более сложном коде. Эта общая процедура может быть обобщена следующим образом.
- Захват следа путешествия во времени неудачной программы.
- Используйте команду dx (выражение объектной модели отладчика), чтобы найти событие исключения, хранящееся в записи.
- Используйте команду !tt (путешествие по времени) для перемещения в положение события исключения в трассировке.
- С этого момента выполните трассировку шаг за шагом в обратном направлении до тех пор, пока не удастся обнаружить код ошибки в процессе анализа.
- При анализе кода сбоя в контексте, рассмотрите локальные значения и предположите, какая переменная может содержать неверное значение.
- Определите адрес памяти переменной с неправильным значением.
- Задайте точку останова доступа к памяти (ba) в адресе подозрительной переменной с помощью команды ba (Break on Access).
- Используйте g-, чтобы вернуться к последней точке доступа к памяти подозрительной переменной.
- Узнайте, является ли данное место или несколько инструкций до него местом ошибки в коде. Если да, то все готово. Если неверное значение произошло из другой переменной, задайте еще один разрыв для точки останова доступа во второй переменной.
- Используйте g-, чтобы вернуться к последней точке доступа к памяти во второй подозрительной переменной. Проверьте, содержится ли ошибка кода в этом расположении или в нескольких предыдущих инструкциях. Если да, то все готово.
- Повторяйте этот процесс, возвращаясь назад, пока не найдете код, который задал неверное значение, вызвавшее ошибку.
Хотя общие методы, описанные в этой процедуре, применяются к широкому набору проблем кода, существуют уникальные проблемы кода, требующие уникального подхода. Методы, показанные в пошаговом руководстве, должны служить для расширения набора средств отладки и проиллюстрируют некоторые возможности трассировки TTD.
Цели лаборатории
После завершения этой лаборатории вы сможете использовать общую процедуру с трассировкой перемещения по времени для поиска проблем в коде.
Настройка лаборатории
Для выполнения лабораторной работы потребуется следующее оборудование.
- Ноутбук или настольный компьютер с установленной системой Windows 10 или Windows 11
Чтобы выполнить лабораторную работу, вам потребуется следующее программное обеспечение.
- The WinDbg. Сведения об установке WinDbg см. в статье "Установка WinDbg"
- Visual Studio для создания примера кода C++.
Лаборатория содержит следующие три раздела.
- Раздел 1. Создание примера кода
- Раздел 2. Запись трассировки примера DisplayGreeting
- Раздел 3. Анализ записи файла трассировки для выявления проблемы с кодом
Раздел 1. Создание примера кода
В разделе 1 вы создадите пример кода с помощью Visual Studio.
Создание примера приложения в Visual Studio
В Microsoft Visual Studio щелкните Файл>Создать>Проект/Решение... и выберите шаблоны Visual C++.
Выберите консольное приложение Win32.
Укажите имя проекта DisplayGreeting и нажмите кнопку "ОК".
Снимите флажок проверки жизненного цикла разработки безопасности (SDL).
Нажмите кнопку "Готово".
Вставьте следующий текст в область 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; }
В Visual Studio щелкните Проект>свойства DisplayGreeting. Затем щелкните C/C++ и Генерация кода.
Задайте следующие свойства.
Настройка Значение Проверка безопасности Отключение проверки безопасности (/GS-) Базовые проверки среды выполнения По умолчанию Примечание.
Хотя эти параметры не рекомендуется, можно представить сценарий, в котором кто-то советует использовать эти параметры для ускорения написания кода или упрощения определенных сред тестирования.
В Visual Studio щелкните Сборка>Собрать решение.
Если все идет хорошо, окна сборки должны отображать сообщение, указывающее, что сборка выполнена успешно.
Найдите созданные файлы примерного приложения
В Проводнике решений щелкните правой кнопкой мыши на проекте DisplayGreeting и выберите Открыть папку в Проводнике файлов.
Перейдите в папку Debug, содержащую собранный exe-файл и файл символов pdb для примера. Например, вы перейдете в папку C:\Projects\DisplayGreeting\Debug, если это папка, в которой хранятся проекты.
Запуск примера приложения с ошибкой кода
Дважды щелкните файл exe, чтобы запустить пример приложения.
Если откроется это диалоговое окно, нажмите кнопку "Закрыть программу"
В следующем разделе пошагового руководства мы запишите выполнение примера приложения, чтобы узнать, можно ли определить, почему это исключение происходит.
Раздел 2. Запись трассировки примера DisplayGreeting
В разделе 2 вы запишите трассировку примера приложения "DisplayGreeting", работающего с ошибками
Чтобы запустить пример приложения и записать трассировку TTD, выполните следующие действия. Общие сведения о записях трассировок TTD см. в разделе "Отладка перемещения по времени" — запись трассировки
Запустите WinDbg от имени администратора, чтобы иметь возможность записывать трассировки перемещения по времени.
В WinDbg выберите Файл>Начать отладку>Запустить исполняемый файл (расширенный).
Введите путь к исполняемому файлу в пользовательском режиме, который вы хотите записать, или нажмите кнопку "Обзор ", чтобы перейти к исполняемому файлу. Сведения о работе с исполняемым меню запуска в WinDbg см. в разделе WinDbg — запуск сеанса пользовательского режима.
Отметьте флажок "Запись с отладкой с функцией перемещения во времени", чтобы записать трассировку при запуске исполняемого файла.
Нажмите кнопку "Настроить" и "Запись", чтобы начать запись .
Когда появится диалоговое окно "Настройка записи", нажмите кнопку " Запись ", чтобы запустить исполняемый файл и начать запись.
Откроется диалоговое окно записи, показывающее, что трассировка записывается. Вскоре после этого приложение завершает работу.
Нажмите кнопку "Закрыть программу", чтобы закрыть диалоговое окно "DisplayGreeting перестало работать".
После сбоя программы файл трассировки будет закрыт и записан на диск.
Отладчик автоматически откроет файл трассировки и проиндексирует его. Индексирование — это процесс, который обеспечивает эффективную отладку файла трассировки. Этот процесс индексирования займет больше времени для больших файлов трассировки.
(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.
Примечание.
Ключевой кадр — это место в трассировке, используемое для индексирования. Ключевые кадры создаются автоматически. Более крупные трассировки будут содержать больше ключевых кадров.
На этом этапе вы находитесь в начале файла трассировки и готовы к перемещению вперед и назад во времени.
Теперь, когда вы записали трассировку TTD, вы можете просмотреть трассировку или работать с файлом трассировки, например поделиться им с коллегой. Дополнительные сведения о работе с файлами трассировки см. в статье "Отладка перемещения по времени" — работа с файлами трассировки
В следующем разделе этой лаборатории мы проанализируем файл трассировки, чтобы найти проблему с нашим кодом.
Раздел 3. Анализ записи файла трассировки для выявления проблемы с кодом
В разделе 3 вы проанализируете запись файла трассировки, чтобы определить проблему кода.
Настройка среды WinDbg
Добавьте местоположение локального символа в путь символов и перезагрузите символы, введя следующие команды.
.sympath+ C:\MyProjects\DisplayGreeting\Debug .reload
Добавьте расположение локального кода в исходный путь, введя следующую команду.
.srcpath+ C:\MyProjects\DisplayGreeting\DisplayGreeting
Чтобы просмотреть состояние стека и локальных переменных, на ленте WinDbg выберите Вид и Локальные, затем Вид и Стек. Организуйте окна так, чтобы вы могли одновременно просматривать их, исходный код и окна команд.
На ленте WinDbg выберите "Исходный" и "Файл с открытым исходным кодом". Найдите файл DisplayGreeting.cpp и откройте его.
Проверка исключения
Когда файл трассировки был загружен, он отображает сведения о возникновении исключения.
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
Используйте команду 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 ...
Примечание.
В этом пошаговом руководстве три периода используются для указания того, что лишние выходные данные были удалены.
Щелкните на событии типа "исключение", чтобы отобразить сведения об этом событии 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
Щелкните поле "Исключение", чтобы продолжить детализацию данных исключений.
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, указывающий, что это нарушение доступа. Обычно это означает, что мы пытаемся записать в память, к которой мы не имеем доступа.
Щелкните ссылку [Путешествие во времени] в событии исключения, чтобы перейти к этой позиции в трассировке.
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
Это может указывать на повреждение стека — возможно, функция вернулась, а затем стек был поврежден. Чтобы проверить это, нам нужно вернуться к моменту до повреждения состояния ЦП и проверить, можем ли мы определить, когда произошло повреждение стека.
Проверьте локальные переменные и задайте точку останова кода
В месте сбоя в трассировке обычно проходит несколько шагов после истинной причины в коде обработки ошибок. Используя путешествия во времени, мы можем возвращаться на одну инструкцию назад, чтобы найти истинную первопричину.
На ленте "Главная" используйте команду "Шаг назад", чтобы вернуться на три инструкции назад. Продолжайте изучать окна стека и памяти в процессе выполнения этого.
В командном окне будут отображаться позиции в перемещении во времени и регистры, когда вы отступите на три инструкции назад.
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:
Примечание.
В этом пошаговом руководстве выходные данные команды отображают команды, которые можно использовать вместо параметров меню пользовательского интерфейса, чтобы разрешить пользователям с предпочтениями использования командной строки использовать команды командной строки.
На этом этапе трассировки наш стек и базовый указатель имеют значения, которые имеют больше смысла, поэтому, по-видимому, мы приближаемся к точке в коде, где произошла коррупция.
esp=00effd94 ebp=00effe44
Кроме того, в окне локальных параметров содержатся значения из целевого приложения, а окно исходного кода выделяет строку кода, которая готова выполняться на этом этапе трассировки.
Для дальнейшего изучения можно открыть окно памяти, чтобы просмотреть содержимое рядом с адресом памяти базового указателя 0x00effe44.
Чтобы отобразить связанные символы ASCII, на ленте памяти выберите текст и ASCII.
Вместо того чтобы базовый указатель указывал на инструкцию, он указывает на текст нашего сообщения. Здесь что-то не так, возможно, это как раз тот момент времени, когда мы повредили стек. Для дальнейшего изучения мы установим точку останова.
Примечание.
В этом очень небольшом примере было бы довольно легко просто просмотреть код, но если есть сотни строк кода и десятки подпрограмм, можно использовать описанные здесь техники для уменьшения времени, необходимого для выявления проблемы.
TTD и точки останова
Использование точек останова — это распространенный подход для приостановки выполнения кода на каком-то событии, интересующем вас. TTD позволяет задать точку останова и вернуться назад до тех пор, пока эта точка останова не будет достигнута после записи трассировки. Возможность проверить состояние процесса после возникновения проблемы, чтобы определить оптимальное расположение точки останова, позволяет использовать дополнительные рабочие процессы отладки, характерные для TTD.
Точки останова доступа к памяти
Точки останова можно установить, чтобы срабатывать при доступе к участку памяти. Используйте команду ba (break on access) со следующим синтаксисом.
ba <access> <size> <address> {options}
Вариант | Описание |
---|---|
e | выполнение (когда процессор получает инструкцию по адресу) |
r | чтение и запись (при чтении или записи данных процессором в адрес) |
w | запись (когда процессор записывает на адрес) |
Обратите внимание, что вы можете задать только четыре точки останова данных в любой момент времени, и вам нужно убедиться, что вы правильно выравниваете данные или не активируете точку останова (слова должны заканчиваться адресами, делимыми на 2, dwords должны быть делимыми на 4, а квадроты на 0 или 8).
Настройка точки останова доступа к памяти для базового указателя
На этом этапе трассировки мы хотели бы задать точку останова для доступа к памяти записи к базовому указателю - ebp, который в нашем примере равен 00effe44. Для этого используйте команду ba с помощью адреса, который мы хотим отслеживать. Мы хотим отслеживать операции записи для четырех байтов, поэтому мы указываем параметр w4.
0:000> ba w4 00effe44
Выберите «Вид», а затем «Точки останова», чтобы убедиться, что они установлены правильно.
В меню "Главная" выберите "Вернуться назад", пока точка останова не будет достигнута.
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
Выберите "Вид" и "Локальные". В окне локальных параметров видно, что целевая переменная имеет только часть сообщения, в то время как источник содержит весь текст. Эта информация свидетельствует о том, что стек был повреждён.
На этом этапе мы можем проверить стек программ, чтобы узнать, какой код активен. На ленте "Вид" выберите "Стек".
Так как маловероятно, что у функции wscpy_s(), предоставленной корпорацией Майкрософт, будет подобная ошибка кода, мы исследуем стек дальше. В стеке показано, что приветствие!main вызывает Приветствие! GetCppConGreeting. В нашем очень маленьком примере кода мы могли просто открыть код на этом этапе и, скорее всего, найти ошибку довольно легко. Но чтобы проиллюстрировать методы, которые можно использовать с более крупной, более сложной программой, мы установим новую точку останова для дальнейшего изучения.
Настройка точки останова доступа для функции GetCppConGreeting
Используйте окно точек останова, чтобы очистить существующую точку останова, щелкнув правой кнопкой мыши существующую точку останова и выбрав "Удалить".
Определите адрес функции 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)]
Используйте команду ba, чтобы задать точку останова для доступа к памяти. Поскольку функция будет только считываться из памяти для выполнения, нам нужно установить точку останова на чтении (r - read breakpoint).
0:000> ba r4 b61720
Убедитесь, что точка останова для аппаратного чтения активна в окне точек останова.
Так как мы задаемся вопросом о размере строки приветствия, мы зададим окно просмотра, чтобы отобразить значение sizeof(приветствие). На ленте Вид выберите Смотреть и укажите sizeof(приветствие). Если значение не находится в области видимости, окно наблюдения отобразит: Не удается привязать имя 'greeting'.
В меню "Путешествие по времени" используйте перейти к началу или используйте команду
!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
В меню "Главная" выберите "Перейти " или используйте
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
В меню "Главная" выберите "Шаг назад" или используйте
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)
Похоже, мы нашли первопричину. Массив приветствий, как мы объявили, имеет длину 50 символов, а размер массива приветствий, который мы передаём в GetCppConGreeting, составляет 0x64, 100.
Как мы рассмотрим проблему размера, мы также замечаем, что сообщение имеет длину 75 символов и равно 76 при включении конца строкового символа.
HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL DEBUGGING!
Одним из способов исправления кода будет расширение размера массива символов до 100.
std::array <wchar_t, 100> greeting{};
Кроме того, необходимо изменить sizeof(greeting) на size(greeting) в этой строке кода.
GetCppConGreeting(greeting.data(), size(greeting));
Чтобы проверить эти исправления, мы можем перекомпилировать код и убедиться, что он выполняется без ошибок.
Настройка точки останова с помощью исходного окна
Альтернативным способом выполнения этого исследования будет установка точки останова, щелкнув любую строку кода. Например, щелкнув справа от строки определения std:array в окне источника, установите точку останова.
В меню "Путешествие по времени" используйте команду "Переместиться в начало", чтобы перейти к началу трассировки.
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
На домашней ленте нажмите кнопку "Перейти ", чтобы вернуться, пока точка останова не будет достигнута.
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, используйте эту процедуру.
В этом пошаговом руководстве предполагается, что вы все еще находитесь в точке останова из предыдущего раздела.
В представлении , а затем в локальном режиме. В окне локальных переменных приветствие доступно в текущем контексте, поэтому мы сможем определить его адрес в памяти.
Используйте команду 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.
Используйте окно точек останова, чтобы очистить любую существующую точку останова, щелкнув правой кнопкой мыши существующую точку останова и выбрав "Удалить".
Установите точку останова командой ba, используя адрес памяти, который мы хотим отслеживать для доступа на запись.
ba w4 ddf800
В меню "Путешествие во времени" используйте команду "Перейти к началу", чтобы перейти к началу трассировки.
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
В меню "Главная" выберите перейти к первой точке доступа к памяти массива приветствий.
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.Memory для просмотра доступа к памяти
Другой способ определить, в каких точках памяти трассировки был осуществлён доступ, — это использование объектов памяти TTD и команды dx.
Используйте команду DX для проверки массива приветствия.
0:000> dx &greeting &greeting : 0xddf800 [Type: std::array<wchar_t,50> *] [+0x000] _Elems : "꽘棶檙瞝???" [Type: wchar_t [50]]
В этой трассировке приветствие находится в памяти в ddf800.
Используйте команду 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] ...
Щелкните любое из вхождений, чтобы отобразить дополнительные сведения об этом вхождении доступа к памяти.
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
Щелкните [Путешествие во времени] для 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
Если мы заинтересованы в последнем вхождении доступа к памяти для чтения/записи в трассировке, мы можем щелкнуть на последний элемент в списке или добавить функцию .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
Затем мы могли бы щелкнуть [Time Travel], чтобы перейти к этой позиции в трассировке и узнать больше о выполнении кода на этом этапе, используя методы, описанные ранее в этой лаборатории.
Дополнительные сведения об объектах памяти TTD см. в разделе Объект памяти TTD.
Итоги
В этом очень маленьком примере проблема могла быть определена путем просмотра нескольких строк кода, но в более крупных программах методы, представленные здесь, можно использовать для уменьшения времени, необходимого для поиска проблемы.
После записи трассировки этими данными и шагами воспроизведения можно делиться, и проблема будет воспроизводиться на любом компьютере.
См. также
Отладка временных путешествий — обзор
Отладка перемещения по времени — запись
Отладка перемещения по времени — воспроизведение трассировки
Отладка перемещения по времени — работа с файлами трассировки