Einführung in Objekte zum Debuggen von Zeitreisen
In diesem Abschnitt wird beschrieben, wie das Datenmodell für die Abfrage von Ablaufverfolgungen für Zeitreisen verwendet werden kann. Dies kann ein nützliches Tool sein, um Fragen wie diesen zum Code zu beantworten, der in einer Zeitreiseablaufverfolgung erfasst wird.
- Welche Ausnahmen sind in der Ablaufverfolgung enthalten?
- Zu welchem Zeitpunkt in der Ablaufverfolgung wurde ein bestimmtes Code-Modul geladen?
- Wann wurden Threads in der Ablaufverfolgung erstellt/beendet?
- Welches sind die am längsten laufenden Threads in der Ablaufverfolgung?
Es gibt TTD-Erweiterungen, die Daten zu den Datenmodellobjekten Session und Process hinzufügen. Auf die TTD-Datenmodellobjekte kann über den Befehl dx (Display Debugger Object Model Expression), die Modellfenster von WinDbg, JavaScript und C++ zugegriffen werden. Die TTD-Erweiterungen werden beim Debuggen einer Ablaufverfolgung von Zeitreisen automatisch geladen.
Prozess-Objekte
Die primären Objekte, die zu Process-Objekten hinzugefügt werden, befinden sich im TTD-Namespace von jedem Process-Objekt. Beispiel: @$curprocess.TTD
.
0:000> dx @$curprocess.TTD
@$curprocess.TTD
Index
Threads
Events
DebugOutput
Lifetime : [2C8:0, 16EC:98A]
DefaultMemoryPolicy : InFragmentAggressive
SetPosition [Sets the debugger to point to the given position on this process.]
GatherMemoryUse [0]
RecordClients
PrevMemoryAccess [(accessMask, address, size [, address, size, ...]) - Find the previous matching memory access before current position.]
NextMemoryAccess [(accessMask, address, size [, address, size, ...]) - Find the next matching memory access after current position.]
Recorder
Allgemeine Informationen zur Arbeit mit LINQ-Abfragen und Debugger-Objekten finden Sie unter Verwendung von LINQ mit den Debugger-Objekten.
Eigenschaften
Object | Beschreibung |
---|---|
Lebensdauer | Ein TTD-Bereichsobjekt, das die Lebensdauer der gesamten Ablaufverfolgung beschreibt. |
Threads | Enthält eine Sammlung von TTD-Thread-Objekten, eines für jeden Thread während der gesamten Lebensdauer der Ablaufverfolgung. |
Ereignisse | Enthält eine Sammlung von TTD-Ereignisobjekten, eines für jedes Ereignis in der Ablaufverfolgung. |
Methoden
Methode | Beschreibung |
---|---|
SetPosition() | Nimmt eine Ganzzahl zwischen 0 und 100 oder eine Zeichenfolge im N:N-Format als Eingabe und springt in der Ablaufverfolgung an diese Stelle. Siehe !tt für weitere Informationen. |
Session-Objekte
Die primären Objekte, die zu Session-Objekten hinzugefügt werden, befinden sich im TTD-Namespace von jedem Session-Objekt. Beispiel: @$cursession.TTD
.
0:000> dx @$cursession.TTD
@$cursession.TTD
Calls [Returns call information from the trace for the specified set of methods: TTD.Calls("module!method1", "module!method2", ...) For example: dx @$cursession.TTD.Calls("user32!SendMessageA")]
Memory [Returns memory access information for specified address range: TTD.Memory(startAddress, endAddress [, "rwec"])]
MemoryForPositionRange [Returns memory access information for specified address range and position range: TTD.MemoryForPositionRange(startAddress, endAddress [, "rwec"], minPosition, maxPosition)]
PinObjectPosition [Pins an object to the given time position: TTD.PinObjectPosition(obj, pos)]
AsyncQueryEnabled : false
RichQueryTypesEnabled : true
DefaultParameterCount : 0x4
Data : Normalized data sources based on the contents of the time travel trace
Utility : Methods that can be useful when analyzing time travel traces
Analyzers : Methods that perform code analysis on the time travel trace
Bookmarks : Bookmark collection
Checkers : Checkers (scripts for detection of common issues recorded in a time travel trace)
Hinweis
Es gibt einige von TTDAnalyze hinzugefügte Objekte und Methoden, die für interne Funktionen der Erweiterung verwendet werden. Nicht alle Namespaces sind dokumentiert, und die aktuellen Namespaces werden sich im Laufe der Zeit weiterentwickeln.
Methoden
Methode | Beschreibung |
---|---|
Data.Heap() | Eine Sammlung von Heap-Objekten, die während der Ablaufverfolgung zugewiesen wurden. Beachten Sie, dass es sich um eine Funktion handelt, die Berechnungen durchführt und daher eine gewisse Zeit in Anspruch nimmt. |
Calls() | Gibt eine Sammlung von calls objects zurück, die mit der Eingabezeichenkette übereinstimmen. Die Eingabezeichenfolge kann Platzhalter enthalten. Beachten Sie, dass es sich um eine Funktion handelt, die Berechnungen durchführt und daher eine gewisse Zeit in Anspruch nimmt. |
Memory() | Diese Methode nimmt die Parameter beginAddress, endAddress und dataAccessMask entgegen und gibt eine Sammlung von Speicherobjekten zurück. Beachten Sie, dass es sich um eine Funktion handelt, die Berechnungen durchführt und daher eine gewisse Zeit in Anspruch nimmt. |
Sortieren der Abfrageausgabe
Verwenden Sie die Methode OrderBy(), um die von der Abfrage zurückgegebenen Zeilen nach einer oder mehreren Spalten zu sortieren. Dieses Beispiel sortiert nach TimeStart in aufsteigender Reihenfolge.
0:000> dx -r2 @$cursession.TTD.Calls("kernelbase!GetLastError").OrderBy(c => c.TimeStart)
@$cursession.TTD.Calls("kernelbase!GetLastError").OrderBy(c => c.TimeStart)
[0x0]
EventType : 0x0
ThreadId : 0x2d98
UniqueThreadId : 0x2
TimeStart : 718:7D7 [Time Travel]
TimeEnd : 718:7DA [Time Travel]
Function : KERNELBASE!GetLastError
FunctionAddress : 0x7ff996cf20f0
ReturnAddress : 0x7ff99855ac5a
ReturnValue : 0x0 [Type: unsigned long]
Parameters
SystemTimeStart : Friday, January 12, 2024 21:18:40.862
SystemTimeEnd : Friday, January 12, 2024 21:18:40.862
[0x1]
EventType : 0x0
ThreadId : 0x2d98
UniqueThreadId : 0x2
TimeStart : 72D:1B3 [Time Travel]
TimeEnd : 72D:1B6 [Time Travel]
Function : KERNELBASE!GetLastError
FunctionAddress : 0x7ff996cf20f0
ReturnAddress : 0x7ff9961538df
ReturnValue : 0x57 [Type: unsigned long]
Parameters
SystemTimeStart : Friday, January 12, 2024 21:18:40.862
SystemTimeEnd : Friday, January 12, 2024 21:18:40.862
...
Um eine zusätzliche Tiefe der Datenmodellobjekte anzuzeigen, wird die Option -r2 Rekursionsebene verwendet. Weitere Informationen zu den Optionen des dx-Befehls finden Sie unter dx (Display Debugger Object Model Expression).
Dieses Beispiel sortiert nach TimeStart in absteigender Reihenfolge.
0:000> dx -r2 @$cursession.TTD.Calls("kernelbase!GetLastError").OrderByDescending(c => c.TimeStart)
@$cursession.TTD.Calls("kernelbase!GetLastError").OrderByDescending(c => c.TimeStart)
[0x1896]
EventType : Call
ThreadId : 0x3a10
UniqueThreadId : 0x2
TimeStart : 464224:34 [Time Travel]
TimeEnd : 464224:37 [Time Travel]
Function : UnknownOrMissingSymbols
FunctionAddress : 0x7561ccc0
ReturnAddress : 0x7594781c
ReturnValue : 0x0
Parameters
[0x18a0]
EventType : Call
ThreadId : 0x3a10
UniqueThreadId : 0x2
TimeStart : 464223:21 [Time Travel]
TimeEnd : 464223:24 [Time Travel]
Function : UnknownOrMissingSymbols
FunctionAddress : 0x7561ccc0
ReturnAddress : 0x7594781c
ReturnValue : 0x0
Parameters
Angabe von Elementen in einer Abfrage
Um ein bestimmtes Element auszuwählen, können der Abfrage eine Reihe von Qualifizierern hinzugefügt werden. Die Abfrage zeigt zum Beispiel den ersten Aufruf an, der „kernelbase!GetLastError“ enthält.
0:000> dx @$cursession.TTD.Calls("kernelbase!GetLastError").First()
@$cursession.TTD.Calls("kernelbase!GetLastError").First()
EventType : 0x0
ThreadId : 0x2d98
UniqueThreadId : 0x2
TimeStart : 718:7D7 [Time Travel]
TimeEnd : 718:7DA [Time Travel]
Function : KERNELBASE!GetLastError
FunctionAddress : 0x7ff996cf20f0
ReturnAddress : 0x7ff99855ac5a
ReturnValue : 0x0 [Type: unsigned long]
Parameters
SystemTimeStart : Friday, January 12, 2024 21:18:40.862
SystemTimeEnd : Friday, January 12, 2024 21:18:40.862
Filterung in einer Abfrage
Verwenden Sie die Select()-Methode, um auszuwählen, welche Spalten angezeigt werden sollen, und um den Namen der Spaltenanzeige zu ändern.
Dieses Beispiel gibt Zeilen zurück, in denen ReturnValue ungleich Null ist, und wählt die Anzeige der Spalten TimeStart und ReturnValue mit den benutzerdefinierten Anzeigenamen Time und Error aus.
0:000> dx -r2 @$cursession.TTD.Calls("kernelbase!GetLastError").Where(c => c.ReturnValue != 0).Select(c => new { Time = c.TimeStart, Error = c.ReturnValue })
@$cursession.TTD.Calls("kernelbase!GetLastError").Where(c => c.ReturnValue != 0).Select(c => new { Time = c.TimeStart, Error = c.ReturnValue })
[0x1]
Time : 72D:1B3 [Time Travel]
Error : 0x57 [Type: unsigned long]
[0x2]
Time : 72D:1FC [Time Travel]
Error : 0x2af9 [Type: unsigned long]
[0x3]
Time : 72D:26E [Time Travel]
Error : 0x2af9 [Type: unsigned long]
Gruppierung
Verwenden Sie die Methode GroupBy(), um die von der Abfrage zurückgegebenen Daten zu gruppieren und so eine Analyse mit strukturierten Ergebnissen durchzuführen.
0:000> dx -r2 @$cursession.TTD.Calls("kernelbase!GetLastError").Where(c => c.ReturnValue != 0).Select(c => new { Time = c.TimeStart, Error = c.ReturnValue }).GroupBy(x => x.Error)
@$s = @$cursession.TTD.Calls("kernelbase!GetLastError").Where(c => c.ReturnValue != 0).Select(c => new { Time = c.TimeStart, Error = c.ReturnValue }).GroupBy(x => x.Error)
[0x36b7]
[0x0]
[0x1]
[0x2]
[0x3]
[...]
[0x3f0]
[0x0]
[0x1]
[0x2]
[0x3]
...
Zuweisung des Ergebnisses einer Abfrage an eine Variable
Verwenden Sie diese Syntax, um das Ergebnis einer Abfrage einer Variablen zuzuweisen dx @$var = <expression>
In diesem Beispiel werden die Ergebnisse einer Abfrage myResults zugewiesen
dx -r2 @$myResults = @$cursession.TTD.Calls("kernelbase!GetLastError").Where(c => c.ReturnValue != 0).Select(c => new { Time = c.TimeStart, Error = c.ReturnValue })
Verwenden Sie den Befehl dx, um die neu erstellte Variable mit der Option -g grid anzuzeigen. Weitere Informationen zu den Optionen des dx-Befehls finden Sie unter dx (Display Debugger Object Model Expression).
0:000> dx -g @$myResults
========================================
= = (+) Time = (+) Error =
========================================
= [0x13] - 3C64A:834 - 0x36b7 =
= [0x1c] - 3B3E7:D6 - 0x3f0 =
= [0x1d] - 3C666:857 - 0x36b7 =
= [0x20] - 3C67E:12D - 0x2 =
= [0x21] - 3C6F1:127 - 0x2 =
= [0x23] - 3A547:D6 - 0x3f0 =
= [0x24] - 3A59B:D0 - 0x3f0 =
Beispiele
Abfrage nach Ausnahmen
Diese LINQ-Abfrage verwendet das TTD.Event-Objekt, um alle Ausnahmen in der Ablaufverfolgung anzuzeigen.
0:000> dx @$curprocess.TTD.Events.Where(t => t.Type == "Exception").Select(e => e.Exception)
@$curprocess.TTD.Events.Where(t => t.Type == "Exception").Select(e => e.Exception)
[0x0] : Exception 0x000006BA of type Software at PC: 0X777F51D0
[0x1] : Exception 0x000006BA of type Software at PC: 0X777F51D0
[0x2] : Exception 0xE06D7363 of type CPlusPlus at PC: 0X777F51D0
Abfrage nach bestimmten API-Aufrufen
Verwenden Sie das Objekt TTD.Calls, um nach bestimmten API-Aufrufen zu suchen. In diesem Beispiel ist ein Fehler beim Aufruf von user32!MessageBoxW aufgetreten, der Windows-API zum Anzeigen einer Messagebox. Wir listen alle Aufrufe von MessageBoxW auf, ordnen sie nach der Startzeit der Funktion und wählen dann den letzten Aufruf aus.
0:000> dx @$cursession.TTD.Calls("user32!MessageBoxW").OrderBy(c => c.TimeStart).Last()
@$cursession.TTD.Calls("user32!MessageBoxW").OrderBy(c => c.TimeStart).Last()
EventType : Call
ThreadId : 0x3a10
UniqueThreadId : 0x2
TimeStart : 458310:539 [Time Travel]
TimeEnd : 45C648:61 [Time Travel]
Function : UnknownOrMissingSymbols
FunctionAddress : 0x750823a0
ReturnAddress : 0x40cb93
ReturnValue : 0x10a7000000000001
Parameters
Abfrage des Ladevorgangs für ein bestimmtes Modul
Verwenden Sie zunächst den Befehl lm (List Loaded Modules), um die geladenen Module anzuzeigen.
0:000> lm
start end module name
012b0000 012cf000 CDog_Console (deferred)
11570000 1158c000 VCRUNTIME140D (deferred)
11860000 119d1000 ucrtbased (deferred)
119e0000 11b63000 TTDRecordCPU (deferred)
11b70000 11cb1000 TTDWriter (deferred)
73770000 73803000 apphelp (deferred)
73ea0000 74062000 KERNELBASE (deferred)
75900000 759d0000 KERNEL32 (deferred)
77070000 771fe000 ntdll (private pdb symbols)
Verwenden Sie dann den folgenden dx-Befehl, um zu sehen, an welcher Position in der Ablaufverfolgung ein bestimmtes Modul geladen wurde, z. B. ntdll.
dx @$curprocess.TTD.Events.Where(t => t.Type == "ModuleLoaded").Where(t => t.Module.Name.Contains("ntdll.dll"))
@$curprocess.TTD.Events.Where(t => t.Type == "ModuleLoaded").Where(t => t.Module.Name.Contains("ntdll.dll"))
[0x0] : Module Loaded at position: A:0
Diese LINQ-Abfrage zeigt das/die Ladeereignis(e) eines bestimmten Moduls an.
0:000> dx @$curprocess.TTD.Events.Where(t => t.Type == "ModuleUnloaded").Where(t => t.Module.Name.Contains("ntdll.dll"))
@$curprocess.TTD.Events.Where(t => t.Type == "ModuleUnloaded").Where(t => t.Module.Name.Contains("ntdll.dll"))
[0x0] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0
Die Adresse FFFFFFFFFFFFFFFE:0 zeigt das Ende der Ablaufverfolgung an.
Abfrage nach allen Fehlerprüfungen in der Ablaufverfolgung
Verwenden Sie diesen Befehl, um alle Fehlerprüfungen in der Ablaufverfolgung nach Fehleranzahl zu sortieren.
0:000> dx -g @$cursession.TTD.Calls("kernelbase!GetLastError").Where( x=> x.ReturnValue != 0).GroupBy(x => x.ReturnValue).Select(x => new { ErrorNumber = x.First().ReturnValue, ErrorCount = x.Count()}).OrderByDescending(p => p.ErrorCount),d
==================================================
= = (+) ErrorNumber = ErrorCount =
==================================================
= [1008] - 1008 - 8668 =
= [14007] - 14007 - 4304 =
= [2] - 2 - 1710 =
= [6] - 6 - 1151 =
= [1400] - 1400 - 385 =
= [87] - 87 - 383 =
Abfrage der Zeitposition in der Ablaufverfolgung, zu der Threads erstellt wurden
Verwenden Sie diesen dx-Befehl, um alle Ereignisse der Ablaufverfolgung im Rasterformat (-g) anzuzeigen.
0:000> dx -g @$curprocess.TTD.Events
==================================================================================================================================================================================================
= = (+) Type = (+) Position = (+) Module = (+) Thread =
==================================================================================================================================================================================================
= [0x0] : Module Loaded at position: 2:0 - ModuleLoaded - 2:0 - Module C:\Users\USER1\Documents\Visual Studio 2015\Proje... - =
= [0x1] : Module Loaded at position: 3:0 - ModuleLoaded - 3:0 - Module C:\WINDOWS\SYSTEM32\VCRUNTIME140D.dll at address 0... - =
= [0x2] : Module Loaded at position: 4:0 - ModuleLoaded - 4:0 - Module C:\WINDOWS\SYSTEM32\ucrtbased.dll at address 0X118... - =
= [0x3] : Module Loaded at position: 5:0 - ModuleLoaded - 5:0 - Module C:\Users\USER1\AppData\Local\Dbg\UI\Fast.20170907... - =
= [0x4] : Module Loaded at position: 6:0 - ModuleLoaded - 6:0 - Module C:\Users\USER1\AppData\Local\Dbg\UI\Fast.20170907... - =
= [0x5] : Module Loaded at position: 7:0 - ModuleLoaded - 7:0 - Module C:\WINDOWS\SYSTEM32\apphelp.dll at address 0X73770... - =
= [0x6] : Module Loaded at position: 8:0 - ModuleLoaded - 8:0 - Module C:\WINDOWS\System32\KERNELBASE.dll at address 0X73... - =
= [0x7] : Module Loaded at position: 9:0 - ModuleLoaded - 9:0 - Module C:\WINDOWS\System32\KERNEL32.DLL at address 0X7590... - =
= [0x8] : Module Loaded at position: A:0 - ModuleLoaded - A:0 - Module C:\WINDOWS\SYSTEM32\ntdll.dll at address 0X7707000... - =
= [0x9] : Thread created at D:0 - ThreadCreated - D:0 - - UID: 2, TID: 0x4C2C =
= [0xa] : Thread terminated at 64:0 - ThreadTerminated - 64:0 - - UID: 2, TID: 0x4C2C =
= [0xb] : Thread created at 69:0 - ThreadCreated - 69:0 - - UID: 3, TID: 0x4CFC =
= [0xc] : Thread created at 6A:0 - ThreadCreated - 6A:0 - - UID: 4, TID: 0x27B0 =
= [0xd] : Thread terminated at 89:0 - ThreadTerminated - 89:0 - - UID: 4, TID: 0x27B0 =
= [0xe] : Thread terminated at 8A:0 - ThreadTerminated - 8A:0 - - UID: 3, TID: 0x4CFC =
= [0xf] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0 - ModuleUnloaded - FFFFFFFFFFFFFFFE:0 - Module C:\Users\USER1\Documents\Visual Studio 2015\Proje... - =
= [0x10] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0 - ModuleUnloaded - FFFFFFFFFFFFFFFE:0 - Module C:\Users\USER1\AppData\Local\Dbg\UI\Fast.20170907... - =
= [0x11] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0 - ModuleUnloaded - FFFFFFFFFFFFFFFE:0 - Module C:\WINDOWS\SYSTEM32\VCRUNTIME140D.dll at address 0... - =
= [0x12] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0 - ModuleUnloaded - FFFFFFFFFFFFFFFE:0 - Module C:\Users\USER1\AppData\Local\Dbg\UI\Fast.20170907... - =
= [0x13] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0 - ModuleUnloaded - FFFFFFFFFFFFFFFE:0 - Module C:\WINDOWS\SYSTEM32\ucrtbased.dll at address 0X118... - =
= [0x14] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0 - ModuleUnloaded - FFFFFFFFFFFFFFFE:0 - Module C:\WINDOWS\SYSTEM32\apphelp.dll at address 0X73770... - =
= [0x15] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0 - ModuleUnloaded - FFFFFFFFFFFFFFFE:0 - Module C:\WINDOWS\System32\KERNELBASE.dll at address 0X73... - =
= [0x16] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0 - ModuleUnloaded - FFFFFFFFFFFFFFFE:0 - Module C:\WINDOWS\System32\KERNEL32.DLL at address 0X7590... - =
= [0x17] : Module Unloaded at position: FFFFFFFFFFFFFFFE:0 - ModuleUnloaded - FFFFFFFFFFFFFFFE:0 - Module C:\WINDOWS\SYSTEM32\ntdll.dll at address 0X7707000... - =
==================================================================================================================================================================================================
Wählen Sie eine der Spalten mit einem +-Zeichen aus, um die Ausgabe zu sortieren.
Verwenden Sie diese LINQ-Abfrage, um im Rasterformat die Zeitposition in der Ablaufverfolgung anzuzeigen, zu der Threads erstellt wurden (Typ == „ThreadCreated“).
dx -g @$curprocess.TTD.Events.Where(t => t.Type == "ThreadCreated").Select(t => t.Thread)
===========================================================================================================
= = (+) UniqueId = (+) Id = (+) Lifetime = (+) ActiveTime =
===========================================================================================================
= [0x0] : UID: 2, TID: 0x4C2C - 0x2 - 0x4c2c - [0:0, FFFFFFFFFFFFFFFE:0] - [D:0, 64:0] =
= [0x1] : UID: 3, TID: 0x4CFC - 0x3 - 0x4cfc - [0:0, 8A:0] - [69:0, 8A:0] =
= [0x2] : UID: 4, TID: 0x27B0 - 0x4 - 0x27b0 - [0:0, 89:0] - [6A:0, 89:0] =
===========================================================================================================
Verwenden Sie diese LINQ-Abfrage, um im Rasterformat die Zeitpositionen in der Ablaufverfolgung anzuzeigen, an denen Threads beendet wurden (Typ == „ThreadTerminated“).
0:000> dx -g @$curprocess.TTD.Events.Where(t => t.Type == "ThreadTerminated").Select(t => t.Thread)
===========================================================================================================
= = (+) UniqueId = (+) Id = (+) Lifetime = (+) ActiveTime =
===========================================================================================================
= [0x0] : UID: 2, TID: 0x4C2C - 0x2 - 0x4c2c - [0:0, FFFFFFFFFFFFFFFE:0] - [D:0, 64:0] =
= [0x1] : UID: 4, TID: 0x27B0 - 0x4 - 0x27b0 - [0:0, 89:0] - [6A:0, 89:0] =
= [0x2] : UID: 3, TID: 0x4CFC - 0x3 - 0x4cfc - [0:0, 8A:0] - [69:0, 8A:0] =
===========================================================================================================
Sortieren der Ausgabe zur Ermittlung der am längsten laufenden Threads
Verwenden Sie diese LINQ-Abfrage, um im Rasterformat die ungefähr am längsten laufenden Threads in der Ablaufverfolgung anzuzeigen.
0:000> dx -g @$curprocess.TTD.Events.Where(e => e.Type == "ThreadTerminated").Select(e => new { Thread = e.Thread, ActiveTimeLength = e.Thread.ActiveTime.MaxPosition.Sequence - e.Thread.ActiveTime.MinPosition.Sequence }).OrderByDescending(t => t.ActiveTimeLength)
=========================================================
= = (+) Thread = ActiveTimeLength =
=========================================================
= [0x0] - UID: 2, TID: 0x1750 - 0x364030 =
= [0x1] - UID: 3, TID: 0x420C - 0x360fd4 =
= [0x2] - UID: 7, TID: 0x352C - 0x35da46 =
= [0x3] - UID: 9, TID: 0x39F4 - 0x34a5b5 =
= [0x4] - UID: 11, TID: 0x4288 - 0x326199 =
= [0x5] - UID: 13, TID: 0x21C8 - 0x2fa8d8 =
= [0x6] - UID: 14, TID: 0x2188 - 0x2a03e3 =
= [0x7] - UID: 15, TID: 0x40E8 - 0x29e7d0 =
= [0x8] - UID: 16, TID: 0x124 - 0x299677 =
= [0x9] - UID: 4, TID: 0x2D74 - 0x250f43 =
= [0xa] - UID: 5, TID: 0x2DC8 - 0x24f921 =
= [0xb] - UID: 6, TID: 0x3B1C - 0x24ec8e =
= [0xc] - UID: 10, TID: 0x3808 - 0xf916f =
= [0xd] - UID: 12, TID: 0x26B8 - 0x1ed3a =
= [0xe] - UID: 17, TID: 0x37D8 - 0xc65 =
= [0xf] - UID: 8, TID: 0x45F8 - 0x1a2 =
=========================================================
Abfrage nach Lesezugriffen auf einen Speicherbereich
Verwenden Sie das TTD.Memory Objekt zur Abfrage von Lesezugriffen auf einen Speicherbereich.
Der Thread Environment Block (TEB) ist eine Struktur, die alle Informationen über den Zustand eines Threads enthält, einschließlich des von GetLastError() zurückgegebenen Ergebnisses. Sie können diese Datenstruktur abfragen, indem Sie dx @$teb
für den aktuellen Thread ausführen. Eines der Mitglieder von TEB ist die 4 Byte große Variable LastErrorValue. Wir können das LastErrorValue-Mitglied in der TEB mit dieser Syntax referenzieren. dx &@$teb->LastErrorValue
.
Die Beispielabfrage zeigt, wie man alle Lesevorgänge in diesem Bereich im Speicher findet, alle Lesevorgänge auswählt, die vor der Erstellung des Dialogs stattgefunden haben, und dann das Ergebnis sortiert, um den letzten Lesevorgang zu finden.
0:000> dx @$cursession.TTD.Memory(&@$teb->LastErrorValue, &@$teb->LastErrorValue + 0x4, "r")
@$cursession.TTD.Memory(&@$teb->LastErrorValue, &@$teb->LastErrorValue + 0x4, "r")
[0x0]
[0x1]
[0x2]
[0x3]
Wenn in unserer Ablaufverfolgung ein „Dialog“-Ereignis stattgefunden hat, können wir eine Abfrage starten, um alle Lesevorgänge in diesem Bereich im Speicher zu finden, alle Lesevorgänge auswählen, die vor der Erstellung des Dialogs stattgefunden haben, und dann das Ergebnis sortieren, um den letzten Lesevorgang zu finden. Dann reist man zu diesem Zeitpunkt, indem man SeekTo() für die resultierende Zeitposition aufruft.
:000> dx @$cursession.TTD.Memory(&@$teb->LastErrorValue, &@$teb->LastErrorValue + 0x4, "r").Where(m => m.TimeStart < @$dialog).OrderBy(m => m.TimeStart).Last().TimeEnd.SeekTo()
Setting position: 458300:37
ModLoad: 6cee0000 6cf5b000 C:\WINDOWS\system32\uxtheme.dll
ModLoad: 75250000 752e6000 C:\WINDOWS\System32\OLEAUT32.dll
ModLoad: 76320000 7645d000 C:\WINDOWS\System32\MSCTF.dll
ModLoad: 76cc0000 76cce000 C:\WINDOWS\System32\MSASN1.dll
GitHub TTD Query Lab
Ein Lernprogramm zum Debuggen von C++-Code mithilfe einer Time Travel Debugging-Aufzeichnung mithilfe von Abfragen, um Informationen zur Ausführung des fraglichen problematischen Codes zu finden, finden Sie unter WinDbg-Samples - Time Travel Debugging und Abfragen.
Der gesamte im Lab verwendete Code ist hier verfügbar: https://github.com/Microsoft/WinDbg-Samples/tree/master/TTDQueries/app-sample.
Fehlersuche bei TTD-Abfragen
„UnknownOrMissingSymbols“ als Funktionsnamen
Die Datenmodellerweiterung benötigt vollständige Symbolinformationen, um Funktionsnamen, Parameterwerte usw. bereitstellen zu können. Wenn keine vollständigen Symbolinformationen verfügbar sind, verwendet der Debugger „UnknownOrMissingSymbols“ als Funktionsnamen.
- Wenn Sie über private Symbole verfügen, erhalten Sie den Funktionsnamen und die korrekte Liste der Parameter.
- Wenn Sie öffentliche Symbole haben, erhalten Sie den Funktionsnamen und einen Standardsatz von Parametern – vier vorzeichenlose 64-Bit-Ints.
- Wenn Sie keine Symbolinformationen für das abgefragte Modul haben, wird „UnknownOrMissingSymbols“ als Name verwendet.
TTD-Abfragen für Aufrufe
Es kann mehrere Gründe geben, warum eine Abfrage nichts für Aufrufe einer DLL zurückgibt.
- Die Syntax für den Aufruf ist nicht ganz richtig. Überprüfen Sie die Aufrufsyntax mithilfe von x (Prüfsymbole).
x <call>
Wenn der von x zurückgegebene Modulname in Großbuchstaben geschrieben ist, verwenden Sie diesen. - Die DLL ist noch nicht geladen und wird später in der Ablaufverfolgung geladen. Um dies zu umgehen, reisen Sie zu einem Zeitpunkt, nachdem die DLL geladen wurde, und wiederholen Sie die Abfrage.
- Der Aufruf ist inlined, was die Abfragesoftware nicht nachvollziehen kann.
- Das Abfragemuster verwendet Platzhalter, die zu viele Funktionen zurückgeben. Versuchen Sie, das Abfragemuster spezifischer zu gestalten, damit die Anzahl der übereinstimmenden Funktionen klein genug ist.
Weitere Informationen
Verwendung von LINQ mit den Debugger-Objekten
dx (Display Debugger Object Model Expression)
Zeitreise-Debugging – Überblick
Zeitreise-Debugging – JavaScript-Automatisierung