Compartilhar via


WinDbg: Linhas do tempo

Logotipo WinDbg com lupa inspecionando bits.

A TTD (Depuração Temporal) permite que os usuários registrem rastros, que são gravações da execução de um programa. Linhas do tempo são uma representação visual de eventos que ocorrem durante a execução. Esses eventos podem ser locais de pontos de interrupção, leituras/gravações de memória, chamadas e retornos de função e exceções.

Captura de tela das linhas do tempo no depurador exibindo exceções, acesso à memória, pontos de interrupção e chamadas de função.

Use a janela Linhas do Tempo para exibir eventos importantes, entender sua posição relativa e ir facilmente para o local em seu arquivo de rastreamento TTD. Use várias linhas do tempo para explorar visualmente eventos no rastreamento de viagem no tempo e descobrir a correlação de eventos.

A janela Linhas do Tempo é exibida quando você abre um arquivo de rastreamento TTD. Ele mostra os principais eventos sem que você precise criar consultas de modelo de dados manualmente. Ao mesmo tempo, todos os objetos de viagem no tempo estão disponíveis para permitir consultas de dados mais complexas.

Para obter mais informações sobre como criar e trabalhar com arquivos de rastreamento de viagem no tempo, consulte Depuração de Viagem no Tempo: Visão geral.

Tipos de linhas do tempo

A janela Linhas do Tempo mostra eventos nas seguintes linhas do tempo:

  • Exceções: você pode filtrar em um código de exceção específico.
  • Pontos de interrupção: você pode ver quando pontos de interrupção atingem uma linha do tempo.
  • Acessos de memória: você pode ler, gravar e executar entre dois endereços de memória.
  • Chamadas de função: você pode pesquisar na forma de module!function.

Passe o mouse sobre cada evento para obter mais informações por meio da dica de ferramenta. Selecionar um evento executa a consulta do evento e exibe mais informações. Clicar duas vezes em um evento salta para esse local no arquivo de rastreamento TTD.

Exceções

Quando você carrega um arquivo de rastreamento e a linha do tempo está ativa, ele exibe todas as exceções na gravação automaticamente.

Quando você passa o mouse sobre um ponto de interrupção, informações como o tipo de exceção e o código de exceção são exibidas.

Captura de tela de uma linha do tempo no depurador exibindo exceções com informações sobre um código de exceção específico.

Você pode filtrar ainda mais em um código de exceção específico usando o campo Código de Exceção opcional.

Captura de tela de uma caixa de diálogo de exceção do depurador de linha do tempo com o Tipo de Linha do Tempo definido como Exceções e Código de Exceção definido como 0xC0000004.

Você também pode adicionar uma nova linha do tempo para um tipo de exceção específico.

Pontos de interrupção

Depois de adicionar um ponto de interrupção, as posições na linha do tempo mostram quando esse ponto de interrupção é atingido. Por exemplo, você pode usar o comando bp Set Breakpoint. Quando você passa o mouse sobre um ponto de interrupção, o endereço e o ponteiro de instrução associados ao ponto de interrupção são exibidos.

Captura de tela de uma linha do tempo no depurador exibindo aproximadamente 30 indicadores de ponto de interrupção.

Quando o ponto de interrupção é limpo, a linha do tempo do ponto de interrupção associada é removida automaticamente.

Chamadas de função

Você pode ver as posições das chamadas de função na linha do tempo. Para fazer essa etapa, forneça a pesquisa na forma de module!function. Um exemplo é TimelineTestCode!multiplyTwo. Você também pode especificar 'wildcards', por exemplo, TimelineTestCode!m*.

Captura de tela da adição de uma linha do tempo no depurador com um nome de chamada de função inserido.

Quando você passa o mouse sobre uma chamada de função, o nome da função, os parâmetros de entrada, seus valores e o valor retornado são exibidos. Este exemplo mostra o buffer e o tamanho porque eles são os parâmetros para DisplayGreeting!GetCppConGreeting.

Captura de tela de uma linha do tempo no depurador exibindo chamadas de função e a janela Registros.

Acesso à memória

Use a linha do tempo de Acessos de Memória para ver quando um intervalo específico de memória foi lido ou gravado ou em que local ocorreu a execução do código. Os endereços iniciar e parar são usados para definir um intervalo entre dois endereços de memória.

Captura de tela da adição de uma caixa de diálogo Acessos à Memória com a opção Gravar selecionada.

Quando você passa o mouse sobre um item de acesso à memória, o valor e o ponteiro de instrução são exibidos.

Captura de tela de uma linha do tempo no depurador exibindo eventos de acesso à memória.

Trabalhar com linhas do tempo

Uma linha cinza vertical segue o cursor quando você passa o mouse sobre a linha do tempo. A linha azul vertical indica a posição atual no rastreamento.

Selecione os ícones de lupa para ampliar e reduzir a linha do tempo.

Na área de controle superior da linha do tempo, use o retângulo para mover a visão da linha do tempo. Arraste os delimitadores externos do retângulo para redimensionar a exibição da linha do tempo atual.

Captura de tela de uma linha do tempo no depurador mostrando a área superior usada para selecionar o modo de exibição ativo.

Movimentos do mouse

Para ampliar e reduzir, selecione Ctrl e use a roda de rolagem.

Para mover lateralmente, selecione a tecla Shift e use a roda de rolagem.

Técnicas de depuração da linha do tempo

Para demonstrar técnicas de depuração com linha do tempo, o passo a passo de Depuração de Viagem no Tempo é reutilizado aqui. Essa demonstração pressupõe que você concluiu as duas primeiras etapas para criar o código de exemplo e criou a gravação TTD usando as duas primeiras etapas descritas lá.

Nesse cenário, a primeira etapa é encontrar a exceção no rastreio de viagem no tempo. Clique duas vezes na única exceção que você vê na linha do tempo.

Na janela Comando , você pode ver que o comando a seguir foi emitido quando você selecionou a exceção.

(2dcc.6600): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: CC:0
@$curprocess.TTD.Events.Where(t => t.Type == "Exception")[0x0].Position.SeekTo()

Selecione Exibir>Registros para exibir os registros neste ponto na linha do tempo para iniciar sua investigação.

Captura de tela de uma linha do tempo no depurador exibindo a exceção do laboratório de demonstração e a janela Registros.

Na saída do comando, a pilha (esp) e o ponteiro base (ebp) estão apontando para endereços diferentes. Essa discrepância pode indicar corrupção na pilha. Possivelmente, uma função retornou e corrompeu a pilha. Para validar esse problema, volte para um momento antes do estado da CPU ser corrompido e verifique se é possível determinar quando a corrupção da pilha ocorreu.

Ao fazer esse processo, examine os valores das variáveis locais e da pilha:

  • Selecione Exibir>Locais para exibir os valores locais.
  • Selecione Exibir>Pilha para exibir a pilha de execução de código.

No momento da falha, é comum que o rastreamento termine algumas etapas depois da verdadeira causa no código de tratamento de erros. Utilizando a viagem no tempo, você pode voltar uma instrução de cada vez para identificar a verdadeira causa raiz.

Na faixa de opções Página Inicial , use o comando Step Into Back para recuar três instruções. À medida que você faz esse processo, continue examinando as janelas Stack, Locals e Registers.

A janela Comando exibe a posição da viagem no tempo e os registros à medida que você retrocede três instruções anteriores.

0:000> t-
Time Travel Position: CB:41
eax=00000000 ebx=00564000 ecx=c0d21d62 edx=7a1e4a6c esi=00061299 edi=00061299
eip=00540020 esp=003cf7d0 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: CB:40
eax=00000000 ebx=00564000 ecx=c0d21d62 edx=7a1e4a6c esi=00061299 edi=00061299
eip=00061767 esp=003cf7cc 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+0x57:
00061767 c3              ret
0:000> t-
Time Travel Position: CB:3A
eax=0000004c ebx=00564000 ecx=c0d21d62 edx=7a1e4a6c esi=00061299 edi=00061299
eip=0006175f esp=003cf718 ebp=003cf7c8 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
DisplayGreeting!main+0x4f:
0006175f 33c0            xor     eax,eax

Neste ponto do rastreamento, sua pilha e o ponteiro base têm valores que fazem mais sentido. Parece que você está se aproximando do ponto no código em que a corrupção ocorreu.

esp=003cf718 ebp=003cf7c8

A janela Locals contém valores de seu aplicativo de destino. A janela código-fonte realça a linha de código que está pronta para ser executada no código-fonte neste ponto do rastreamento.

Para investigar mais a fundo, abra uma janela Memória para visualizar o conteúdo próximo ao endereço de memória do ponteiro de pilha (esp). Neste exemplo, ele tem um valor de 003cf7c8. Selecione Memória>Texto>ASCII para exibir o texto ASCII armazenado nesse endereço.

Captura de tela do depurador exibindo as janelas Registros, Pilha e Memória.

Linha do tempo de acesso à memória

Depois que um local de interesse de memória for identificado, use esse valor para adicionar uma linha do tempo de acesso à memória. Selecione + Adicionar linha do tempo e preencha o endereço inicial. Examine 4 bytes para que, ao adicioná-los ao valor de Endereço Inicial, 003cf7c8você tenha um valor de Endereço Final.003cf7cb O padrão é examinar todas as gravações de memória, mas você também pode examinar apenas gravações ou execução de código nesse endereço.

Captura de tela da adição de uma caixa de diálogo de acesso à memória da linha do tempo com a opção de gravação selecionada e um valor inicial de 003cf7c8.

Agora você pode percorrer a linha do tempo ao contrário para examinar em que ponto neste rastreamento de viagem de tempo esse local de memória foi gravado para ver o que você pode encontrar. Ao selecionar essa posição na linha do tempo, você pode ver que os locais valorizam valores diferentes para a cadeia de caracteres que está sendo copiada. O valor de destino parece estar incompleto, como se o comprimento da cadeia de caracteres não estivesse correto.

Captura de tela da linha do tempo de acesso à memória e da janela Locais exibindo valores locais com valores de origem e destino diferentes.

Linha do tempo do ponto de interrupção

Usar pontos de interrupção é uma abordagem comum para pausar a execução de código em algum evento de interesse. Com o TTD, você pode definir um ponto de interrupção e retornar no tempo até que esse ponto de interrupção seja alcançado após o rastreamento ser gravado. A capacidade de examinar o estado do processo após um problema, determinar o melhor local para um ponto de interrupção, permite mais fluxos de trabalho de depuração exclusivos para TTD.

Para explorar uma técnica alternativa de depuração da linha do tempo, selecione a exceção na linha do tempo e, mais uma vez, retorne três etapas usando o comando Step Into Back na faixa de opções Home .

Neste pequeno exemplo, é fácil procurar no código. Se você tiver centenas de linhas de código e dezenas de sub-rotinas, use as técnicas descritas aqui para diminuir o tempo necessário para localizar o problema.

Conforme mencionado anteriormente, o ponteiro base (esp) aponta para o texto da mensagem em vez de apontar para uma instrução.

Use o ba comando para definir um ponto de interrupção no acesso à memória. Você define um w - ponto de interrupção de gravação para ver quando essa área de memória é gravada.

0:000> ba w4 003cf7c8

Embora você use um ponto de interrupção de acesso à memória simples, você pode construir pontos de interrupção para serem instruções condicionais mais complexas. Para obter mais informações, consulte bp, bu, bm (Definir ponto de interrupção).

No menu Página Inicial , selecione Voltar para viajar de volta no tempo até que o ponto de interrupção seja atingido.

Neste ponto, você pode examinar a pilha de programas para ver qual código está ativo.

Captura de tela de uma linha do tempo no depurador exibindo linhas do tempo de acesso à memória e janelas stack.

Como é improvável que a função fornecida pela wscpy_s() Microsoft possa ter um bug de código como este, verifique mais detalhadamente a pilha de chamadas. A pilha mostra que Greeting!main chama Greeting!GetCppConGreeting. No seu pequeno exemplo de código, você pode abrir o código neste momento e provavelmente encontrar o erro facilmente. Mas para ilustrar as técnicas que você pode usar com um programa maior e mais complexo, adicione uma linha do tempo de chamada de função.

Linha do tempo da chamada de função

Selecione + Adicionar linha do tempo e preencha DisplayGreeting!GetCppConGreeting a cadeia de caracteres de pesquisa de função.

Os checkboxes Local de Início e Local de Término indicam o início e o fim de uma chamada de função no rastreamento.

Você pode usar o dx comando para exibir o objeto de chamada de função para ver os campos associados TimeStart e TimeEnd que correspondem ao local de início e ao local de término da chamada de função.

dx @$cursession.TTD.Calls("DisplayGreeting!GetCppConGreeting")[0x0]
    EventType        : 0x0
    ThreadId         : 0x6600
    UniqueThreadId   : 0x2
    TimeStart        : 6D:BD [Time Travel]
    SystemTimeStart  : Thursday, October 31, 2019 23:36:05
    TimeEnd          : 6D:742 [Time Travel]
    SystemTimeEnd    : Thursday, October 31, 2019 23:36:05
    Function         : DisplayGreeting!GetCppConGreeting
    FunctionAddress  : 0x615a0
    ReturnAddress    : 0x61746
    Parameters  

Uma das caixas de seleção Local de Início ou Local de Término ou ambas as caixas de seleção Local de Início e Local de Término devem ser selecionadas.

Captura de tela da caixa de diálogo Adicionar novo cronograma exibindo a adição de um cronograma de Chamadas de Função com uma string de busca de funções do DisplayGreeting!GetCppConGreeting.

Seu código não é recursivo ou reentrante, portanto, é fácil localizar quando o método GetCppConGreeting é chamado na linha do tempo. A chamada para GetCppConGreeting também ocorre ao mesmo tempo que o seu ponto de interrupção e o evento de acesso à memória que você definiu. Portanto, parece que você restringiu uma área de código para examinar cuidadosamente a causa raiz da falha do aplicativo.

Captura de tela de uma linha do tempo no depurador exibindo a linha do tempo de acesso à memória e a janela Locais com uma mensagem e um buffer contendo valores de cadeia de caracteres diferentes.

Explorar a execução de código exibindo várias linhas do tempo

Embora nosso exemplo de código seja pequeno, a técnica de usar várias linhas do tempo permite a exploração visual de um rastreamento de viagem no tempo. Você pode procurar o arquivo de rastreamento para fazer perguntas, como "Quando uma área de memória é acessada antes de um ponto de interrupção ser atingido?".

Captura de tela de um cronograma no depurador exibindo um cronograma de Acessos de Memória e a janela Locais.

A capacidade de ver mais correlações e encontrar coisas inesperadas diferencia a ferramenta de linha do tempo de interagir com o rastreamento de viagem no tempo usando comandos de linha de comando.

Marcadores de cronograma

Marque posições importantes de viagem pelo tempo no WinDbg ao invés de copiar e colar manualmente a posição no Bloco de Notas. Os marcadores facilitam a visualização rápida de diferentes posições no rastreamento em relação a outros eventos e a sua anotação.

Você pode dar um nome descritivo para marcadores.

Captura de tela da caixa de diálogo Novo Marcador mostrando um nome de exemplo para a primeira chamada à API no aplicativo Display Greeting.

Selecione Exibir>Linha do Tempo para abrir a janela Linha do Tempo para que você possa acessar a linha do tempo dos Indicadores . Quando você passa o cursor sobre um favorito, o nome do favorito é exibido.

Captura de tela da linha do tempo exibindo três marcadores com o cursor pairando sobre um para revelar o nome do marcador.

Clique com o botão direito do mouse no marcador para ir para a posição do marcador, renomear o marcador ou excluí-lo.

Captura de tela do menu pop-up de clique com o botão direito do mouse em Favoritos exibindo opções para ir para a posição, editar e remover.

Observação

O recurso de marcador não está disponível na versão 1.2402.24001.0 do WinDbg.