Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Este laboratório introduz a Depuração de Viagem no Tempo (TTD), usando um pequeno programa de exemplo com uma falha de código. TTD é usado para depurar, identificar e determinar a causa raiz do problema. Embora o problema neste pequeno programa seja fácil de encontrar, o procedimento geral pode ser usado em códigos mais complexos. Este procedimento geral pode ser resumido da seguinte forma.
- Capture um traço de viagem no tempo do programa falhado.
- Use o comando dx (Display Debugger Object Model Expression) para localizar o evento de exceção armazenado na gravação.
- Use o comando !tt (viagem no tempo) para viajar até a posição do evento de exceção no rastreamento.
- A partir desse ponto no rastreamento, um único passo para trás até que o código de falha em questão entre em escopo.
- Com o código de falha no escopo, observe os valores locais e desenvolva uma hipótese de uma variável que pode conter um valor incorreto.
- Determine o endereço de memória da variável com o valor incorreto.
- Defina um ponto de interrupção de acesso à memória (ba) no endereço da variável suspeita usando o comando ba (Break on Access).
- Use g- para voltar ao último ponto de acesso à memória da variável suspeita.
- Veja se esse local, ou algumas instruções antes, é o ponto da falha do código. Se sim, está feito. Se o valor incorreto veio de alguma outra variável, defina outra quebra no ponto de interrupção de acesso na segunda variável.
- Use g- para voltar ao último ponto de acesso à memória na segunda variável suspeita. Veja se esse local ou algumas instruções antes contém a falha de código. Se for o caso, já está.
- Repita esse processo retrocedendo até que o código que definiu o valor incorreto que causou o erro seja localizado.
Embora as técnicas gerais descritas neste procedimento se apliquem a um amplo conjunto de problemas de código, há problemas de código exclusivos que exigirão uma abordagem exclusiva. As técnicas ilustradas no guia passo a passo deverão servir para expandir o seu conjunto de ferramentas de depuração e ilustrarão algumas das possibilidades com um rastro TTD.
Objetivos do laboratório
Depois de concluires este laboratório, serás capaz de usar o procedimento geral com um traço de viagem no tempo para localizar problemas no código.
Configuração do laboratório
Você precisará do seguinte hardware para poder concluir o laboratório.
- Um laptop ou computador desktop (host) executando o Windows 10 ou Windows 11
Você precisará do seguinte software para poder concluir o laboratório.
- O WinDbg. Para obter informações sobre como instalar o WinDbg, consulte WinDbg - Installation
- Visual Studio para criar o código C++ de exemplo.
O laboratório tem as seguintes três seções.
- Seção 1: Criar o código de exemplo
- Seção 2: Gravar um rastreamento do exemplo "DisplayGreeting"
- Seção 3: Analise a gravação do arquivo de rastreamento para identificar o problema de código
Seção 1: Criar o código de exemplo
Na Seção 1, você criará o código de exemplo usando o Visual Studio.
Criar o aplicativo de exemplo no Visual Studio
No Microsoft Visual Studio, clique em Arquivo>Novo>Projeto/Solução... e clique nos modelos do Visual C++.
Selecione o aplicativo de console Win32.
Indique o nome do projeto como DisplayGreeting e clique em OK.
Desmarque as verificações do Ciclo de Vida de Desenvolvimento de Segurança (SDL).
Clique em Concluir.
Cole o texto a seguir no painel DisplayGreeting.cpp no 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; }No Visual Studio, clique em Project>propriedades DisplayGreeting. Em seguida, clique em C/C++ e Code Generation.
Defina as seguintes propriedades.
Configurações Valor Verificação de segurança Desativar verificação de segurança (/GS-) Verificações básicas de tempo de execução Predefinido Observação
Embora essas configurações não sejam recomendadas, é possível imaginar um cenário em que alguém aconselharia o uso dessas configurações para agilizar a codificação ou facilitar determinados ambientes de teste.
No Visual Studio, clique em Build>Build Solution.
Se tudo correr bem, as janelas de compilação devem exibir uma mensagem indicando que a compilação foi bem-sucedida.
Localize os arquivos de aplicativo de exemplo criados
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto DisplayGreeting e selecione Abrir Pasta no Explorador de Arquivos.
Navegue até à pasta Debug que contém o ficheiro exe compilado e o ficheiro de símbolos pdb para o exemplo. Por exemplo, você navegaria até C:\Projects\DisplayGreeting\Debug, se essa for a pasta na qual seus projetos estão armazenados.
Execute o aplicativo de exemplo com a falha de código
Clique duas vezes no arquivo exe para executar o aplicativo de exemplo.
Se essa caixa de diálogo for exibida, selecione Fechar programa
Na próxima seção do passo a passo, registraremos a execução do aplicativo de exemplo para ver se podemos determinar por que essa exceção está ocorrendo.
Seção 2: Gravar um rastreamento do exemplo "DisplayGreeting"
Na Seção 2, você gravará um traço do exemplo de comportamento incorreto do aplicativo "DisplayGreeting"
Para iniciar o aplicativo de exemplo e registrar um rastreamento TTD, siga estas etapas. Para obter informações gerais sobre como gravar rastreamentos TTD, consulte Depuração de viagem no tempo - Gravar um rastreamento
Execute o WinDbg como administrador, para poder gravar rastreamentos de viagem no tempo.
No WinDbg, selecione Arquivo>Iniciar depuração>Executável (avançado) Iniciar.
Digite o caminho para o executável no modo utilizador que pretende gravar ou selecione Pesquisar para navegar até ao executável. Para obter informações sobre como trabalhar com o menu executável de inicialização no WinDbg, consulte WinDbg - Iniciar uma sessão de modo de usuário.
Marque a caixa Registro com Depuração de Viagem no Tempo para gravar um rastreamento quando o executável for lançado.
Clique Configurar e gravar para iniciar a gravação.
Quando a caixa de diálogo "Configurar gravação" aparecer, clique em gravar para iniciar o executável e iniciar a gravação.
A caixa de diálogo de gravação é exibida indicando que o traço está a ser gravado. Pouco tempo depois, o aplicativo trava.
Clique em Fechar programa para descartar a caixa de diálogo "DisplayGreeting parou de funcionar".
Quando o programa falha, o arquivo de rastreamento será fechado e gravado no disco.
O depurador abrirá automaticamente o arquivo de rastreamento e o indexará. A indexação é um processo que permite a depuração eficiente do arquivo de rastreamento. Esse processo de indexação levará mais tempo para arquivos de rastreamento maiores.
(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.
Observação
Um quadro-chave é um local em um traço usado para indexação. Os quadros-chave são gerados automaticamente. Rastreamentos maiores conterão mais quadros-chave.
Neste ponto, você está no início do arquivo de rastreamento e está pronto para avançar e retroceder no tempo.
Agora que você gravou um rastreamento TTD, pode reproduzir o rastreamento ou trabalhar com o arquivo de rastreamento, por exemplo, compartilhá-lo com um colega de trabalho. Para obter mais informações sobre como trabalhar com arquivos de rastreamento, consulte Depuração de viagem no tempo - Trabalhando com arquivos de rastreamento
Na próxima seção deste laboratório, analisaremos o arquivo de rastreamento para localizar o problema com nosso código.
Seção 3: Analisar a gravação do arquivo de rastreamento para identificar o problema de código
Na Seção 3, você analisará a gravação do arquivo de rastreamento para identificar o problema de código.
Configurar o ambiente WinDbg
Adicione a localização do símbolo local ao caminho do símbolo e recarregue os símbolos, digitando os seguintes comandos.
.sympath+ C:\MyProjects\DisplayGreeting\Debug .reloadAdicione o seu código local ao caminho de origem inserindo o seguinte comando.
.srcpath+ C:\MyProjects\DisplayGreeting\DisplayGreetingPara visualizar o estado da pilha e das variáveis locais, na faixa de opções do WinDbg, selecione Visualizar e Locais e Visualizar e Pilha. Organize as janelas para permitir que você as visualize, o código-fonte e as janelas de comando ao mesmo tempo.
Na faixa de opções do WinDbg, selecione de origem e Arquivo de código-fonte aberto . Localize o arquivo DisplayGreeting.cpp e abra-o.
Examinar a exceção
Quando o arquivo de rastreamento foi carregado, ele exibe informações de que ocorreu uma exceção.
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=00000000Use o comando dx para listar todos os eventos na gravação. O evento de exceção é listado nos eventos.
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 ...Observação
Neste passo a passo, três períodos são usados para indicar que a saída estranha foi removida.
Clique no evento Exception para exibir informações sobre esse evento 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: 0X540020Clique no campo Exceção para detalhar melhor os dados da exceção.
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 : 0x0Os dados de exceção indicam que esta é uma falha de hardware lançada pela CPU. Ele também fornece o código de exceção de 0xc0000005 que indica que esta é uma violação de acesso. Isso normalmente indica que estávamos tentando gravar na memória à qual não temos acesso.
Clique no link [Viagem no tempo] no evento de exceção para passar para essa posição no rastreamento.
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 ??É importante notar nesta saída que a pilha e o ponteiro base estão a apontar para endereços muito diferentes.
esp=00effe4c ebp=00520055Isso pode indicar corrupção da pilha, possivelmente uma função retornou e, em seguida, corrompeu a pilha. Para validar isso, precisamos voltar atrás no tempo para antes de o estado da CPU ter sido corrompido e ver se conseguimos determinar quando a corrupção da pilha ocorreu.
Examine as variáveis locais e defina um ponto de interrupção de código
No ponto de falha no rastreamento, é comum acabar alguns passos após a verdadeira causa no código de manipulação de erros. Com a viagem no tempo, podemos voltar uma instrução de cada vez, para localizar a verdadeira causa raiz.
Na faixa de opções do Home, use o comando Step Into Back para retroceder três instruções. Ao fazer isso, continue a examinar as janelas da pilha e da memória.
A janela de comando exibirá a posição da viagem no tempo e os registros à medida que você recua três instruções.
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:Observação
Neste passo a passo, a saída do comando mostra os comandos que podem ser usados em vez das opções do Menu da interface do usuário para permitir que os usuários com uma preferência de uso da linha de comando usem comandos de linha de comando.
Neste ponto do rastreamento, nossa pilha e ponteiro base têm valores que fazem mais sentido, então parece que estamos nos aproximando do ponto no código onde a corrupção ocorreu.
esp=00effd94 ebp=00effe44Também é interessante que a janela locais contém valores do nosso aplicativo de destino e a janela do código-fonte está destacando a linha de código que está pronta para ser executada neste ponto do rastreamento.
Para investigar melhor, podemos abrir uma janela de memória para visualizar o conteúdo perto do endereço de memória do ponteiro base de 0x00effe44.
Para exibir os caracteres ASCII associados, na faixa de opções Memória, selecione Texto e depois ASCII.
Em vez de o ponteiro base apontar para uma instrução, ele está apontando para o texto da mensagem. Portanto, algo não está bem aqui, isto pode estar perto do momento em que corrompemos a pilha. Para investigar mais a fundo, vamos definir um ponto de interrupção.
Observação
Neste exemplo muito pequeno, seria muito fácil apenas olhar no código, mas se houver centenas de linhas de código e dezenas de sub-rotinas, as técnicas descritas aqui podem ser usadas para diminuir o tempo necessário para localizar o problema.
TTD e pontos de interrupção
O uso de pontos de interrupção é uma abordagem comum para pausar a execução de código em algum evento de interesse. O TTD permite que você defina um ponto de interrupção e viaje de volta no tempo até que esse ponto de interrupção seja atingido após o rastreamento ter sido registrado. A capacidade de examinar o estado do processo após a ocorrência de um problema, para determinar o melhor local para um ponto de interrupção, permite fluxos de trabalho de depuração adicionais exclusivos do TTD.
Pontos de interrupção de acesso à memória
Você pode definir pontos de interrupção que são acionados quando um local de memória é acessado. Use o comando ba (break on access), com a sintaxe a seguir.
ba <access> <size> <address> {options}
| Opção | Descrição |
|---|---|
| e | executar (quando a CPU executa uma instrução a partir do endereço) |
| r | leitura/gravação (quando a CPU lê ou grava no endereço) |
| w | escrever (quando a CPU grava no endereço) |
Observe que você só pode definir quatro pontos de interrupção de dados a qualquer momento e cabe a você certificar-se de que está alinhando seus dados corretamente ou não acionará o ponto de interrupção (as palavras devem terminar em endereços divisíveis por 2, dwords devem ser divisíveis por 4 e quadwords por 0 ou 8).
Defina o ponto de paragem no acesso à memória para o ponteiro base
Neste ponto da análise, pretendemos definir um ponto de interrupção no acesso à memória de escrita para o ponteiro base, ebp, que no nosso exemplo é 00effe44. Para fazer isso, use o comando ba usando o endereço que queremos monitorar. Queremos monitorizar gravações para quatro bytes, por isso especificamos w4.
0:000> ba w4 00effe44Selecione Exibir e, em seguida, Pontos de interrupção para confirmar que eles estão definidos como pretendido.
No menu Início, selecione Voltar para viajar no tempo até que o ponto de interrupção seja atingido.
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=ccccccccSelecione Exibir e, em seguida, Locais. Na janela locais, podemos ver que a variável de destino tem apenas parte da mensagem, enquanto a de origem contém todo o texto. Essas informações suportam a ideia de que a pilha foi corrompida.
Neste ponto, podemos examinar a pilha de programas para ver qual código está ativo. Na faixa de opções Vista, selecione Empilhar.
Como é muito improvável que a função wscpy_s() fornecida pela Microsoft tenha um bug de código como este, olhamos mais longe na pilha. A pilha mostra que Greeting!main chama Greeting!GetCppConGreeting. Em nosso exemplo de código muito pequeno, poderíamos simplesmente abrir o código neste ponto e provavelmente encontrar o erro com bastante facilidade. Mas para ilustrar as técnicas que podem ser usadas com programas maiores e mais complexos, vamos definir um novo ponto de interrupção para investigar mais.
Defina a quebra no ponto de interrupção de acesso para a função GetCppConGreeting
Use a janela de pontos de interrupção para limpar o ponto de interrupção existente clicando com o botão direito do mouse no ponto de interrupção existente e selecionando Remover.
Determine o endereço do DisplayGreeting! GetCppConGreeting função usando o comando dx.
0:000> dx &DisplayGreeting!GetCppConGreeting &DisplayGreeting!GetCppConGreeting : 0xb61720 [Type: void (__cdecl*)(wchar_t *,unsigned int)] [Type: void __cdecl(wchar_t *,unsigned int)]Use o comando ba para definir um ponto de interrupção no acesso à memória. Como a função será apenas lida da memória para execução, precisamos definir um ponto de interrupção r - read.
0:000> ba r4 b61720Confirme se um ponto de interrupção de leitura de hardware está ativo na janela de pontos de interrupção.
Como estamos nos perguntando sobre o tamanho da string de saudação, vamos definir uma janela de monitorização para exibir o valor de sizeof(greeting). Na faixa de opções Exibir, selecione Watch e insira sizeof(saudação). Se o valor não estiver no escopo, a janela de observação será exibida - Não é possível vincular o nome 'saudação'.
No menu Viagem no Tempo, use Viagem no Tempo para iniciar ou use o comando
!tt 0para mover-se para o início do rastreio.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=00000000No menu Página Inicial, selecione Ir ou use o comando
gpara avançar no código até que o ponto de interrupção seja atingido.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,espNo menu Página Inicial, selecione *Step Out Back* ou utilize o comando
g-upara voltar um passo.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)Parece que encontramos a causa raiz. A array de saudação que declaramos tem 50 caracteres de comprimento, enquanto o sizeof(saudação) que passamos para GetCppConGreeting é 0x64, 100.
À medida que analisamos a questão do tamanho, também notamos que a mensagem tem 75 caracteres de comprimento e 76 quando se inclui o final do caractere de cadeia de caracteres.
HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL DEBUGGING!Uma maneira de corrigir o código seria expandir o tamanho da matriz de caracteres para 100.
std::array <wchar_t, 100> greeting{};E também precisamos mudar sizeof(greeting) para size(greeting) nesta linha de código.
GetCppConGreeting(greeting.data(), size(greeting));Para validar essas correções, podemos recompilar o código e confirmar que ele é executado sem erros.
Definindo um ponto de interrupção usando a janela de origem
Uma maneira alternativa de realizar essa investigação seria definir um ponto de interrupção clicando em qualquer linha de código. Por exemplo, clicar no lado direito da linha de definição std:array na janela de origem definirá um ponto de interrupção lá.
No menu Viagem no Tempo, use Time Travel para iniciar o comando para mover para o início da trilha.
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=00000000Na Faixa de Opções Principal, clique em Ir para retroceder até que o breakpoint seja alcançado.
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
Configurar o ponto de break no acesso para a variável de saudação
Outra maneira alternativa de realizar essa investigação seria definir um ponto de interrupção em variáveis suspeitas e examinar qual código está alterando-as. Por exemplo, para definir um ponto de interrupção na variável de saudação no método GetCppConGreeting, use este procedimento.
Esta parte do passo a passo pressupõe que você ainda esteja localizado no ponto de interrupção da seção anterior.
A partir de Ver e, em seguida, Locais. Na janela de locais, saudação está disponível no contexto atual, para que possamos determinar o seu local de memória.
Utilize o comando dx para examinar a matriz de saudações .
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]Neste rastreamento, saudação está localizado na memória em ddf800.
Use a janela de pontos de interrupção para limpar qualquer ponto de interrupção existente clicando com o botão direito do mouse no ponto de interrupção existente e selecionando Remover.
Defina o ponto de interrupção com o comando ba usando o endereço de memória que queremos monitorar para acesso de gravação.
ba w4 ddf800No menu Viagem no Tempo, use Viagem no tempo para iniciar comando para mover para o início do rastreamento.
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=00000000No menu Início, selecione Ir para deslocar-se até o primeiro ponto de acesso à memória do array de saudação.
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=ccccccccComo alternativa, poderíamos ter percorrido até ao final do rastreamento e analisado o código em sentido inverso para encontrar o último ponto no rastreamento onde o endereço de memória do array foi gravado.
Use o TTD. Objetos de memória para visualizar o acesso à memória
Outra maneira de determinar em que pontos no rastreamento a memória foi acessada é usar os objetos TTD.Memory e o comando dx.
Use o comando dx para examinar o array greeting.
0:000> dx &greeting &greeting : 0xddf800 [Type: std::array<wchar_t,50> *] [+0x000] _Elems : "꽘棶檙瞝???" [Type: wchar_t [50]]Neste rastreamento, a saudação está localizada na memória em ddf800.
Use o comando dx para examinar os quatro bytes na memória a partir desse endereço com acesso de leitura e escrita.
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] ...Clique em qualquer uma das ocorrências para exibir mais informações sobre essa ocorrência de acesso à memória.
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.400Clique em [Viagem no tempo] para que o TimeStart posicione o rastreamento no momento desejado.
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 ecxSe estivermos interessados na última ocorrência de acesso à memória de leitura/gravação no rastreamento, podemos clicar no último item da lista ou adicionar a função .Last() ao final do comando 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.859Poderíamos então clicar em [Viagem no Tempo] para passar para essa posição no rastreamento e olhar mais para a execução do código naquele ponto, usando as técnicas descritas anteriormente neste laboratório.
Para mais informações sobre os objetos de memória TTD, consulte TTD. Objeto de memória.
Resumo
Neste exemplo muito pequeno, o problema poderia ter sido determinado olhando para as poucas linhas de código, mas em programas maiores as técnicas apresentadas aqui podem ser usadas para diminuir o tempo necessário para localizar um problema.
Depois que um rastreamento é registrado, as etapas de rastreamento e reprodução podem ser compartilhadas e o problema será reproduzível em qualquer PC.
Ver também
Depuração de viagem no tempo - Visão geral
Depuração de "Viagem no Tempo" - Gravação
Depuração de Viagem no Tempo - Reproduzir rastreamento
Depuração de Viagem no Tempo - Trabalhando com arquivos de rastreamento