Introdução à Depuração de objetos de viagem no tempo
Esta seção explica como usar o modelo de dados para consultar rastreamentos de viagem no tempo. Essa pode ser uma ferramenta útil para responder a perguntas como essas sobre o código capturado em um rastreamento de viagem no tempo.
- Quais são as exceções que estão no rastreamento?
- Em que ponto do rastreamento um módulo de código específico foi carregado?
- Em que ponto do rastreamento os threads foram criados/encerrados?
- Quais são os threads mais longos do rastreamento?
Há extensões TTD que adicionam dados aos objetos de modelo de dados Session e Process. Os objetos de modelo de dados TTD podem ser acessados através do comando dx (Display Debugger Object Model Expression), janelas do modelo WinDbg, JavaScript e C++. As extensões TTD são carregadas automaticamente na depuração de um rastreamento de viagem no tempo.
Processar objetos
Os objetos principais adicionados a objetos Process podem ser encontrados no namespace TTD de qualquer objeto Process. Por exemplo, @$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
Para obter informações gerais sobre como trabalhar com consultas LINQ e objetos do depurador, consulte Usando LINQ com os objetos do depurador.
Propriedades
Objeto | Descrição |
---|---|
Vida útil | Um objeto de intervalo TTD que descreve o tempo de vida de todo o rastreamento. |
Threads | Contém uma coleção de objetos de thread TTD, um para cada thread durante toda a vida útil do rastreamento. |
Eventos | Contém uma coleção de Objetos de evento TTD, um para cada evento no rastreamento. |
Métodos
Método | Descrição |
---|---|
SetPosition() | Pega um inteiro entre 0 e 100 ou uma cadeia de caracteres no formato N:N como entrada e salta o rastreamento para esse local. Consulte !tt para mais informações. |
Objetos de sessão
Os objetos principais adicionados a objetos Session podem ser encontrados no namespace TTD de qualquer objeto Session. Por exemplo, @$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)
Observação
Há alguns objetos e métodos adicionados pelo TTDAnalyze que são usados para funções internas da extensão. Nem todos os namespaces são documentados, e os namespaces atuais evoluirão com o tempo.
Métodos
Método | Descrição |
---|---|
Data.Heap() | Uma coleção de objetos de heap que foram alocados durante o rastreamento. Observe que essa é uma função que faz computação, de modo que leva um tempo para ser executada. |
Calls() | Retorna uma coleção de objetos de chamadas que correspondem à cadeia de caracteres de entrada. A cadeia de caracteres da entrada pode conter curingas. Observe que essa é uma função que faz computação, de modo que leva um tempo para ser executada. |
Memory() | Esse é um método que usa os parâmetros beginAddress, endAddress e dataAccessMask e retorna uma coleção de objetos de memória. Observe que essa é uma função que faz computação, de modo que leva um tempo para ser executada. |
Como classificar a saída da consulta
Use o método OrderBy() para classificar as linhas que retornarem da consulta por uma ou mais colunas. Este exemplo classifica por TimeStart na ordem crescente.
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
...
Para mostrar profundidade adicional dos objetos de modelo de dados, é usada a opção de nível de recursão -r2. Para obter mais informações sobre as opções de comando dx, consulte dx (expressão para exibir modelo de objeto de depurador).
Este exemplo classifica por TimeStart na ordem decrescente.
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
Como especificar elementos em uma consulta
Para selecionar um elemento específico, diversos qualificadores podem ser anexados à consulta. Por exemplo, a consulta mostra a primeira chamada que contém "kernelbase!GetLastError".
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
Como filtrar em uma consulta
Use o método Select() para escolher quais colunas ver e modificar o nome de exibição da coluna.
Este exemplo retorna linhas onde ReturnValue não é zero e seleciona exibir as colunas TimeStart e ReturnValue com nomes de exibição personalizados de Hora e Erro.
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]
Agrupamento
Use o método GroupBy() para agrupar dados retornados pela consulta para executar análises com resultados estruturados. Este exemplo agrupa os locais de hora por número de erro.
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]
...
Como atribuir o resultado de uma consulta a uma variável
Use esta sintaxe para atribuir o resultado de uma consulta a uma variável dx @$var = <expression>
Este exemplo atribui os resultados de uma consulta ao myResults
dx -r2 @$myResults = @$cursession.TTD.Calls("kernelbase!GetLastError").Where(c => c.ReturnValue != 0).Select(c => new { Time = c.TimeStart, Error = c.ReturnValue })
Use o comando dx para ver a variável recém-criada usando a opção de grade -g. Para obter mais informações das opções de comando dx, consulte dx (expressão para exibir modelo de objeto de depurador).
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 =
Exemplos
Consulta para exceções
Esta consulta LINQ usa o objeto TTD.Event para exibir todas as exceções no rastreamento.
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
Consulta para chamadas de API específicas
Use o objeto TTD.Calls para consultar chamadas de API específicas. Neste exemplo, ocorreu um erro ao chamar user32!MessageBoxW, a API do Windows para mostrar uma caixa de mensagem. Listamos todas as chamadas a MessageBoxW, ordenamos pela hora de início da função e, depois, escolhemos a última chamada.
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
Consultar para o evento de carregamento de um módulo específico
Primeiro, use o comando lm (List Loaded Modules) para ver os módulos carregados.
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)
Depois, use o seguinte comando dx para ver em que posição no rastreamento um módulo específico foi carregado, como 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
Esta consulta LINQ mostra o(s) evento(s) de carregamento de um módulo específico.
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
O endereço de FFFFFFFFFFFFFFFE:0 indica o fim do rastreamento.
Consultar todas as verificações de erro no rastreamento
Use este comando para classificar todas as verificações de erros no rastreamento pela contagem de erros.
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 =
Consultar a posição no tempo no rastreamento quando os threads foram criados
Use este comando dx para mostrar todos os eventos no rastreamento no formato de grade (-g).
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... - =
==================================================================================================================================================================================================
Selecione qualquer colunas que tenha um sinal de + para classificar a saída.
Use esta consulta LINQ para ver em formato de grade, a posição no tempo no rastreamento quando os threads foram criados (Type == "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] =
===========================================================================================================
Use esta consulta LINQ para ver em formato de grade, as posições no tempo no rastreamento quando os threads foram encerrados (Type == "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] =
===========================================================================================================
Classificar a saída para determinar os threads de execução mais longa
Use esta consulta LINQ para exibir, em formato de grade, os threads aproximados de execução mais longa no rastreamento.
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 =
=========================================================
Consultar acessos de leitura a um intervalo de memória
Use o objeto TTD.Memory para consultar acessos de leitura a um intervalo de memória.
O Bloco de ambiente de thread (TEB) é uma estrutura que contém todas as informações sobre o estado de um thread, incluindo o resultado retornado por GetLastError(). Consulte essa estrutura de dados executando dx @$teb
para o thread atual. Um dos membros do TEB é uma variável LastErrorValue, de 4 bytes. Podemos fazer referência ao membro LastErrorValue no TEB com essa sintaxe. dx &@$teb->LastErrorValue
.
O exemplo de consulta mostra como encontrar cada operação de leitura feita nesse intervalo na memória, selecionar todas as leituras que ocorrem antes de criar uma caixa de diálogo e, depois, classificar o resultado para encontrar a última operação de leitura.
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]
Se tiver ocorrido um evento "dialog" em nosso rastreamento, podemos executar uma consulta para encontrar todas as operações de leitura feitas naquele intervalo na memória, selecionar todas as leituras que ocorrem antes da criação do diálogo e classificar o resultado para encontrar a última operação de leitura. Depois, viaje no tempo até esse ponto no tempo chamando SeekTo() na posição de tempo resultante.
: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
Laboratório de consulta TTD do GitHub
Para obter um tutorial sobre como depurar código C++ usando uma gravação de Depuração de Viagem no Tempo usando consultas para encontrar informações sobre a execução do código problemático em questão, consulte WinDbg-Samples – Depuração e Consultas de Viagem no Tempo.
Todo o código usado no laboratório pode ser encontrado aqui: https://github.com/Microsoft/WinDbg-Samples/tree/master/TTDQueries/app-sample.
Solucionando consultas TTD
"UnknownOrMissingSymbols" como nomes das funções
A extensão do modelo de dados precisa ter informações completas de símbolo para dar os nomes de função, os valores de parâmetro, etc. Quando as informações completas do símbolo não estão disponíveis, o depurador usa "UnknownOrMissingSymbols" como nome da função.
- Se tiver símbolos privados, você irá receber o nome da função e a lista correta de parâmetros.
- Se tiver símbolos públicos, você receberá o nome da função e um conjunto padrão de parâmetros; quatro inteiros de 64 bits não assinados.
- Se não tiver nenhuma informação de símbolo para o módulo que você está consultando, o nome usado será "UnknownOrMissingSymbols".
Consultas TTD para chamadas
Pode haver vários motivos pelos quais uma consulta não retorna nada para chamadas para uma DLL.
- A sintaxe para a chamada não está correta. Tente verificar a sintaxe da chamada usando o x (Examinar símbolos)
x <call>
. Se o nome do módulo retornado por x estiver em maiúsculas, use esse nome. - A DLL ainda não foi carregada; ela será carregada depois no rastreamento. Para contornar essa viagem a um ponto no tempo depois que a DLL é carregada e refazer a consulta.
- A chamada está embutida, de modo que o mecanismo de consulta não consegue rastrear.
- O padrão da consulta usa curingas que retornam um excesso de funções. Tente especificar mais o padrão de consulta para que o número de funções correspondentes seja pequeno o suficiente.
Confira também
Usando LINQ com os objetos do depurador
dx (expressão para exibir modelo de objeto de depurador)
Depuração de viagem no tempo – Visão geral
Depuração de viagem no tempo - Automação JavaScript