Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Автоматизация JavaScript позволяет работать с трассировками TTD несколькими способами, например автоматизацией команд или запросами для поиска данных событий из файла трассировки.
Общие сведения о работе с JavaScript см. в скриптах отладчика JavaScript. Также существуют примеры скриптов отладчика JavaScript.
Автоматизация команд JavaScript TTD
Одним из способов использования JavaScript для автоматизации TTD является отправка команд для автоматизации работы с файлами трассировки времени.
Перемещение в файл трассировки
В этом JavaScript показано, как перейти к началу трассировки перемещения по времени с помощью команды !tt .
var dbgControl = host.namespace.Debugger.Utility.Control;
dbgControl.ExecuteCommand("!tt 0",false);
host.diagnostics.debugLog(">>> Sent command to move to the start of the TTD file \n");
Мы можем сделать это в функцию ResetTrace и сохранить ее как MyTraceUtils.js с помощью пользовательского интерфейса JavaScript в WinDbg.
// My Trace Utils
// WinDbg TTD JavaScript MyTraceUtilsCmd Sample
"use strict";
function MyTraceUtilsCmd()
{
var dbgControl = host.namespace.Debugger.Utility.Control;
dbgControl.ExecuteCommand("!tt 0",false);
host.diagnostics.debugLog(">>> Sent command to move to the start of the TTD file \n");
}
После загрузки файла TTD в WinDbg вызовите функцию ResetTraceCmd() с помощью команды DX в окне команды отладчика.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.ResetTraceCmd()
>>> Sent command to move to the start of the TTD file
Debugger.State.Scripts.MyTraceUtils.Contents.ResetTraceCmd()
Ограничения отправки команд
Но для всех, кроме самых простых ситуаций, подход отправки команд имеет недостатки. Он зависит от использования текстовых выходных данных. И анализ выходных данных приводит к тому, что код является хрупким и трудным для поддержания. Лучший подход — использовать объекты TTD напрямую.
В следующем примере показано, как использовать объекты непосредственно для выполнения той же задачи с помощью объектов напрямую.
// My Trace Utils
// WinDbg TTD JavaScript ResetTrace Sample
"use strict";
function ResetTrace()
{
host.currentProcess.TTD.SetPosition(0);
host.diagnostics.debugLog(">>> Set position to the start of the TTD file \n");
}
При выполнении этого кода показано, что мы можем перейти к началу файла трассировки.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.ResetTrace()
(948.148c): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: F:0
>>> Set position to the start of the TTD file
В этом примере функция ResetTraceEnd устанавливается в конец трассировки, а текущее и новое положение отображается с помощью объекта currentThread.TTD Position.
// WinDbg TTD JavaScript Sample to Reset Trace using objects directly
// and display current and new position
function ResetTraceEnd()
{
var PositionOutputStart = host.currentThread.TTD.Position;
host.diagnostics.debugLog(">>> Current position in trace file: "+ PositionOutputStart +"\n");
host.currentProcess.TTD.SetPosition(100);
var PositionOutputNew = host.currentThread.TTD.Position;
host.diagnostics.debugLog(">>> New position in trace file: "+ PositionOutputNew +"\n");
}
При выполнении этого кода отображается текущая и новая позиция.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.ResetTraceEnd()
>>> Current position in trace file: F:0
(948.148c): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: D3:1
>>> New position in trace file: D3:1
В этом развернутом примере значения начальной и конечной позиции сравниваются, если позиция в трассировке изменилась.
// WinDbg TTD JavaScript ResetTraceEx Sample
"use strict";
function ResetTraceEx()
{
const PositionOutputStart = host.currentThread.TTD.Position;
host.diagnostics.debugLog(">>> Current position in trace file: "+ PositionOutputStart +"\n");
host.currentProcess.TTD.SetPosition(0);
const PositionOutputNew = host.currentThread.TTD.Position;
host.diagnostics.debugLog(">>> New position in trace file: "+ PositionOutputNew +"\n");
if (parseInt(PositionOutputStart,16) != parseInt(PositionOutputNew,16))
{
host.diagnostics.debugLog(">>> Set position to the start of the TTD file \n");
}
else
{
host.diagnostics.debugLog(">>> Position was already set to the start of the TTD file \n");
}
}
В этом примере отображается сообщение о том, что все готово в начале файла трассировки.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.ResetTraceEx()
>>> Current position in trace file: F:0
(948.148c): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: F:0
>>> New position in trace file: F:0
>>> Position was already set to the start of the TTD file
Чтобы протестировать скрипт, используйте команду !tt для перехода по полпути в файле трассировки.
0:000> !tt 50
Setting position to 50% into the trace
Setting position: 71:0
Теперь при выполнении скрипта отображается соответствующее сообщение, указывающее, что позиция была задана в начале трассировки TTD.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.ResetTraceEx()
>>> Current position in trace file: 71:0
(948.148c): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: F:0
>>> New position in trace file: F:0
>>> Set position to the start of the TTD file
Индексирование файла трассировки перемещения по времени
Если только файл трассировки копируется на другой компьютер, он должен быть переиндексирован. Дополнительные сведения см. в статье "Отладка перемещения по времени" — работа с файлами трассировки.
В этом коде показан пример функции IndexTrace, которая показывает, сколько времени требуется для повторного индексирования файла трассировки.
function IndexTrace()
{
var timeS = (new Date()).getTime();
var output = host.currentProcess.TTD.Index.ForceBuildIndex();
var timeE = (new Date()).getTime();
host.diagnostics.debugLog("\n>>> Trace was indexed in " + (timeE - timeS) + " ms\n");
}
Ниже приведены выходные данные из небольшого файла трассировки.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.IndexTrace()
>>> Trace was indexed in 2 ms
Добавление инструкции try catch
Чтобы проверить, возникают ли ошибки при запуске индексирования, заключите код индексирования в инструкцию try catch.
function IndexTraceTry()
{
var timeS = (new Date()).getTime();
try
{
var IndexOutput = host.currentProcess.TTD.Index.ForceBuildIndex();
host.diagnostics.debugLog("\n>>> Index Return Value: " + IndexOutput + "\n");
var timeE = (new Date()).getTime();
host.diagnostics.debugLog("\n>>> Trace was successfully indexed in " + (timeE - timeS) + " ms\n");
}
catch(err)
{
host.diagnostics.debugLog("\n>>> Index Failed! \n");
host.diagnostics.debugLog("\n>>> Index Return Value: " + IndexOutput + "\n");
host.diagnostics.debugLog("\n>>> Returned error: " + err.name + "\n");
}
}
Ниже приведены выходные данные скрипта, если индексирование выполнено успешно.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.IndexTraceTry()
>>> Index Return Value: Loaded
>>> Trace was successfully indexed in 1 ms
Если трассировка не может быть индексирована, например если трассировка не загружена в отладчик, выполняется код цикла catch.
0:007> dx Debugger.State.Scripts.MyTraceUtils.Contents.IndexTraceTry()
>>> Index Failed!
>>> Index Return Value: undefined
>>> Returned error: TypeError
Запросы объектов JavaScript TTD
Более расширенное использование JavaScript и TTD — запрос объектов перемещения по времени для поиска определенных вызовов или событий, произошедших в трассировке. Дополнительные сведения о объектах TTD см. в следующих статье:
Общие сведения о объектах отладки временных путешествий
Собственные объекты отладчика в расширениях JavaScript — сведения об объекте отладчика
Команда dx отображает сведения из модели данных отладчика и поддерживает запросы с помощью синтаксиса LINQ. Dx очень полезно запрашивать объекты в режиме реального времени. Это позволяет создать прототип требуемого запроса, который затем можно автоматизировать с помощью JavaScript. Команда dx предоставляет завершение вкладки, которое может быть полезно при изучении объектной модели. Общие сведения о работе с запросами LINQ и объектами отладчика см. в разделе "Использование LINQ С объектами отладчика".
Эта команда dx подсчитывает все вызовы определенного API в этом примере GetLastError.
0:000> dx @$cursession.TTD.Calls("kernelbase!GetLastError").Count()
@$cursession.TTD.Calls("kernelbase! GetLastError").Count() : 0x12
Эта команда выглядит во всей трассировке перемещения по времени, чтобы увидеть, когда был вызван GetLastError.
0:000> dx @$cursession.TTD.Calls("kernelbase!GetLastError").Where(c => c.ReturnValue != 0)
@$cursession.TTD.Calls("kernelbase!GetLastError").Where(c => c.ReturnValue != 0)
[0x0]
[0x1]
[0x2]
[0x3]
Сравнение строк для TTD. Вызовы объекта для поиска вызовов
В этом примере команды показано, как использовать сравнения строк для поиска конкретных вызовов. В этом примере запрос ищет строку OLE в параметре lpFileName функции CreateFileW.
dx -r2 @$cursession.TTD.Calls("kernelbase!CreateFileW").Where(x => x.Parameters.lpFileName.ToDisplayString("su").Contains("OLE"))
Добавьте . Оператор Select для печати timestart и значения параметра lpFileName .
dx -r2 @$cursession.TTD.Calls("kernelbase!CreateFileW").Where(x => x.Parameters.lpFileName.ToDisplayString("su").Contains("OLE")).Select(x => new { TimeStart = x.TimeStart, lpFileName = x.Parameters.lpFileName })
Это создает выходные данные, если TTD. Объект вызовов найден, содержащий целевую информацию.
[0x0]
TimeStart : 6E37:590
lpFileName : 0x346a78be90 : "C:\WINDOWS\SYSTEM32\OLEACCRC.DLL" [Type: wchar_t *]
Отображение количества вызовов в трассировке
После использования команды dx для изучения объектов, с которыми вы хотите работать, вы можете автоматизировать их использование с JavaScript. В этом простом примере TTD. Объект "Вызовы" используется для подсчета вызовов к базе ядра! GetLastError.
function CountLastErrorCalls()
{
var LastErrorCalls = host.currentSession.TTD.Calls("kernelbase!GetLastError");
host.diagnostics.debugLog(">>> GetLastError calls in this TTD recording: " + LastErrorCalls.Count() +" \n");
}
Сохраните скрипт в файле TTDUtils.js и вызовите его с помощью команды dx, чтобы отобразить количество ядровой базы! GetLastError в файле трассировки.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.CountLastErrorCalls()
>>> GetLastError calls in this TTD recording: 18
Отображение кадров в стеке
Для отображения кадров в стеке используется массив.
function DisplayStack()
{
// Create an array of stack frames in the current thread
const Frames = Array.from(host.currentThread.Stack.Frames);
host.diagnostics.debugLog(">>> Printing stack \n");
// Print out all of the frame entries in the array
for(const [Idx, Frame] of Frames.entries())
{
host.diagnostics.debugLog(">>> Stack Entry -> " + Idx + ": "+ Frame + " \n");
}
}
В этом примере трассировки отображается одна запись стека.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.DisplayStack()
>>> Printing stack
>>> Stack Entry -> 0: ntdll!LdrInitializeThunk + 0x21
Поиск события и отображение стека
В этом коде находятся все события исключений, а цикл используется для перемещения к каждому из них. Затем currentThread.ID объектов потока TTD используется для отображения идентификатора потока и currentThread.Stack для отображения всех кадров в стеке.
function HardwareExceptionDisplayStack()
{
var exceptionEvents = host.currentProcess.TTD.Events.Where(t => t.Type == "Exception");
for (var curEvent of exceptionEvents)
{
// Move to the current event position
curEvent.Position.SeekTo();
host.diagnostics.debugLog(">>> The Thread ID (TID) is : " + host.currentThread.Id + "\n");
// Create an array of stack frames in the current thread
const Frames = Array.from(host.currentThread.Stack.Frames);
host.diagnostics.debugLog(">>> Printing stack \n");
// Print out all of the frame entries in the array
for(const [Idx, Frame] of Frames.entries()) {
host.diagnostics.debugLog(">>> Stack Entry -> " + Idx + ": "+ Frame + " \n");
}
host.diagnostics.debugLog("\n");
}
}
Выходные данные показывают расположение события исключения, TID и кадров стека.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.HardwareExceptionDisplayStack()
(948.148c): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: 91:0
>>> The Thread ID (TID) is : 5260
>>> Printing stack
>>> Stack Entry -> 0: 0x540020
>>> Stack Entry -> 1: 0x4d0049
>>> Stack Entry -> 2: DisplayGreeting!__CheckForDebuggerJustMyCode + 0x16d
>>> Stack Entry -> 3: DisplayGreeting!mainCRTStartup + 0x8
>>> Stack Entry -> 4: KERNEL32!BaseThreadInitThunk + 0x19
>>> Stack Entry -> 5: ntdll!__RtlUserThreadStart + 0x2f
>>> Stack Entry -> 6: ntdll!_RtlUserThreadStart + 0x1b
Поиск события и отправка двух команд
При необходимости можно объединить запросы к объектам TTD и отправлять команды. Этот пример находит каждое событие в трассировке TTD типа ThreadCreated, перемещается в эту позицию и отправляет команды ~Thread Status и !runaway для отображения состояния потока.
function ThreadCreateThreadStatus()
{
var threadEvents = host.currentProcess.TTD.Events.Where(t => t.Type == "ThreadCreated");
for (var curEvent of threadEvents)
{
// Move to the current event position
curEvent.Position.SeekTo();
// Display Information about threads
host.namespace.Debugger.Utility.Control.ExecuteCommand("~", false);
host.namespace.Debugger.Utility.Control.ExecuteCommand("!runaway 7", false);
}
}
При выполнении кода отображается состояние потока в момент возникновения исключения.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.ThreadCreateThreadStatus()
(948.148c): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: F:0
. 0 Id: 948.148c Suspend: 4096 Teb: 00a33000 Unfrozen
User Mode Time
Thread Time
0:148c 0 days 0:00:00.000
Kernel Mode Time
Thread Time
0:148c 0 days 0:00:00.000
Elapsed Time
Thread Time
0:148c 3474 days 2:27:43.000
Объединение функций служебной программы
В этом последнем примере можно вызвать функции служебной программы, созданные ранее. Сначала мы индексируем трассировку с помощью IndexTraceTry , а затем вызовем ThreadCreateThreadStatus. Затем мы используем ResetTrace для перехода к началу трассировки и последнего вызова HardwareExceptionDisplayStack.
function ProcessTTDFiles()
{
try
{
IndexTraceTry()
ThreadCreateThreadStatus()
ResetTrace()
HardwareExceptionDisplayStack()
}
catch(err)
{
host.diagnostics.debugLog("\n >>> Processing of TTD file failed \n");
}
}
Выполнение этого скрипта в файле трассировки, содержащего исключение оборудования, создает эти выходные данные.
0:000> dx Debugger.State.Scripts.MyTraceUtils.Contents.ProcessTTDFiles()
>>> Index Return Value: Loaded
>>> Trace was successfully indexed in 0 ms
(948.148c): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: F:0
. 0 Id: 948.148c Suspend: 4096 Teb: 00a33000 Unfrozen
User Mode Time
Thread Time
0:148c 0 days 0:00:00.000
Kernel Mode Time
Thread Time
0:148c 0 days 0:00:00.000
Elapsed Time
Thread Time
0:148c 3474 days 2:27:43.000
>>> Printing stack
>>> Stack Entry -> 0: ntdll!LdrInitializeThunk
>>> Current position in trace file: F:0
(948.148c): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: F:0
>>> New position in trace file: F:0
(948.148c): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: 91:0
>>> The Thread ID (TID) is : 5260
>>> Printing stack
>>> Stack Entry -> 0: 0x540020
>>> Stack Entry -> 1: 0x4d0049
>>> Stack Entry -> 2: DisplayGreeting!__CheckForDebuggerJustMyCode + 0x16d
>>> Stack Entry -> 3: DisplayGreeting!mainCRTStartup + 0x8
>>> Stack Entry -> 4: KERNEL32!BaseThreadInitThunk + 0x19
>>> Stack Entry -> 5: ntdll!__RtlUserThreadStart + 0x2f
>>> Stack Entry -> 6: ntdll!_RtlUserThreadStart + 0x1b
См. также
Отладка временных путешествий — обзор
Общие сведения о объектах отладки временных путешествий
Собственные объекты отладчика в расширениях JavaScript — сведения об объекте отладчика