logo
Contato | Sobre...        
rebarba rebarba

WinDbg: Debugger de gente grande (parte 2)

Rebooting

No primeiro artigo da série descobrimos o que é o WinDbg, suas semelhanças e diferenças com o Visual Studio, comandos básicos para controlar o programa e para visualizar as variáveis. Agora continuaremos com o uso do WinDbg, para depois entrarmos na parte mais interessante: escarafunchar a memória.

Além de tudo que já vimos e veremos sobre as funcionalidades do WinDbg, eu gostaria de mencionar uma grande vantagem do WinDbg em relação ao debugger integrado do Visual Studio: o WinDbg é um debugger independente, que pode ser usado para verificar um problema na máquina de um usuário. Você pode gravar a pasta de instalação do WinDbg e os fontes do seu programa em um CD e levá-lo para o cliente. Chegando lá, configure o WinDbg dizendo que os fontes e os PDBs estão no CD, e pronto. Depois é só levar o CD embora (NÃO ESQUEÇA DISSO), sem ter que instalar milhares de ferramentas na máquina do cliente.

Ah, e não se esqueça: o WinDbg não está restrito somente a programas desenvolvidos em Visual C++. Ele pode fazer debug de programas gerados por qualquer ferramenta que gere informações de debug. Isso inclui o Visual Basic 6, Borland C++ Builder e o Delphi.

Breakpoints visuais

Vamos começar nossa sessão de debug, usando nosso programa de testes.

  • Usando o menu Open >> Open Executable, abra o executável que criamos.
  • Agora, abra o arquivo .CPP do programa, usando File >> Open Source File
  • Coloque um breakpoint (usando F9) na linha que tem a chamada para SHGetFolderPath
  • Pressione F5 e espere o programa parar nessa função

O WinDbg faz breakpoint diretamente nos fontes, como o Visual Studio. Não se esqueça que esse recurso não funciona para executáveis compilados em versão RELEASE, já que eles não tem informação de debug. Para efetuar o debug de um executável RELEASE, é necessário configurar o compilador para gerar os symbols (Debug Information no VS.NET).

Breakpoints em funções que não são suas

Uma das grandes vantagens do WinDbg é que ele possibilita que você coloque breakpoints em funções da Win32 API e de DLLs com a mesma facilidade que você coloca um breakpoint nas funções do seu executável.

No nosso programa de testes, nós usamos a função SHGetFolderPath para descobrir em qual pasta o Windows está instalado e encontrar o JPG que será colocado como fundo de tela. Se você conhece ao menos um pouco da arquitetura do Windows, você deve imaginar onde isso fica gravado. Se você falou “no registro, é claro”, ponto para você. A chamada dessa API garante que teremos ao menos uma chamada para as APIs de acesso ao registro.

(Na realidade, só o fato de chamar CoInitialize já faz que com que o programa acesse o registro zilhares de vezes, já que toda a configuração do COM também está no registro. E as funções do Shell também criam vários objetos COM)

O raciocínio do breakpoint

Checando a MSDN, encontramos duas funções que podem ser usadas para abrir uma chave de registro: RegOpenKeyEx e RegOpenKey. Qual será a função que o programa usa? Na dúvida podemos colocar um breakpoint nas duas, mas em 99% das vezes, a função correta é a com final Ex.

Quando uma função da API precisa ser modificada para receber mais parâmetros, o pessoal da Microsoft implementa a função com mais parâmetros e coloca Ex no final do nome da função. Depois disso, eles criam uma função stub com a assinatura da função antiga, que somente repassa os parâmetros para a função Ex, fornecendo os parâmetros que não existiam na função original. Ou seja: no final, a função Ex sempre será chamada, já que a função sem o Ex repassa a chamada para a Ex.

Sendo assim, colocaremos o breakpoint na função RegOpenKeyEx.

Já sei qual a função, mas em que DLL ela está?

Agora precisamos descobrir em que DLL está a função RegOpenKeyEx. Como eu já disse no artigo anterior, é possível colocar o breakpoint com o comando “BP RegOpenKeyEx”, mas isso faria com que o WinDbg procurasse esse função em todas as DLLs. Além disso, nós preferimos o modo elegante... :-)

Para procurar as funções e variáveis de um módulo (executável ou DLL), usamos o comando “X”, no seguinte formato:

x [Options] Module!Symbol

Sendo que em Module e em Symbol podemos usar o curinga “*”. Segue aqui a saída de comando da nossa busca pela função RegOpenKeyEx:

0:000> x *!RegOpenKeyEx

Não encontramos nada... Será que a função não existe? Vamos tentar colocar um coringa no final:

0:000> x *!RegOpenKeyEx*
77dd1a8b ADVAPI32!RegOpenKeyExW 
77dd229a ADVAPI32!RegOpenKeyExA

(Além disso, você pode ver mensagens de erro como "Symbol file could not be found". Por enquanto vamos ignorar esse erro. Rodando o comando de procura pela segunda vez faz com que essa mensagem não apareça mais. Arrumaremos o problema dos symbols mais tarde)

Encontramos a função com a letra A e a letra W no final. Mais uma vez devemos escolher qual a função certa.

Unicode e ANSI

A letra A é adicionada no nome das funções que suportam caracteres ANSI, e a letra W nas funções que aceitam caracteres UNICODE (o W vem de “wide char”). Como estamos usando Windows 2000/XP/2003 (você está, não está?), a função correta é a que tem W no final.

Os caracteres UNICODE ocupam 2 bytes, o que permite que um caractere UNICODE possa representar até 65536 letras ou símbolos diferentes (em oposição ao ANSI/ASCII, que suportam somente 255), o que permite conter confortavelmente todos os caracteres e símbolos de todas as línguas e dialetos existentes no nosso planeta. Isso acaba com aquela história de MODE CON CODEPAGE PREPARE (lembra?) para ficarmos mudando a página de caracteres dependendo do idioma escolhido.

Quando o Windows NT foi projetado (nos ido de 1989), foi feita a decisão pelo UNICODE, para facilitar a internacionalização do Windows e dos softwares que nele rodam. O mesmo não aconteceu com o Windows 95/98/Me, que herda muita coisa do Windows 3.1, baseado em ANSI.

Como estamos no Windows NT, colocaremos o breakpoint na função ADVAPI32!RegOpenKeyExW. Lembrando que caso um programa use as versões ANSI das funções e chame ADVAPI32!RegOpenKeyExA, essa função é um stub que converte as strings para UNICODE e repassa a chamada para ADVAPI32!RegOpenKeyExW.

Coloquemos então o breakpoint:

0:000> bp ADVAPI32!RegOpenKeyExW

Agora é só pressionar F5 (ou usar o comando G) e esperar que o programa pare.

Chegando lá

Logo depois de mandar o programa seguir, teremos uma saída parecida com essa:

Breakpoint 1 hit
eax=0012ee18 ebx=00000057 ecx=0012edf0 edx=00000002 esi=00000000 edi=775a8afc
eip=77dd1a8b esp=0012e990 ebp=0012ebbc iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000202
ADVAPI32!RegOpenKeyExW:
77dd1a8b 55               push    ebp

Como não temos os fontes do Windows, temos que nos contentar com o assembly, menu View >> Disassembly. Você pode perguntar do que nos adianta ver o assembly de uma função do Windows. Dou-lhe então dois motivos: descobrir como a função funciona e verificar os parâmetros que foram passados para a função. Para fazer as duas coisas você precisa conhecer assembly. Não é necessário ser mestre em assembly, mas todo programador que se preze deve saber ao menos ler código assembly.

Futuramente faremos um log das chamadas da API usando o WinDbg, onde o disassembly será muito útil.

Completando

Meu intuito com essa série não é escrever um tratado detalhado sobre WinDbg, isso me levaria a escrever até a parte 50. Minha intenção foi mostrar essa ferramenta poderosa e desconhecida da maioria do programadores. Caso você precise de mais detalhes e informações, você pode seguir esses caminhos:

  • Existe um newsgroup da Microsoft somente para WinDbg. Você acessá-lo via web ou usando seu cliente de news preferido (em nntp://msnews.microsoft.com). Em inglês, é claro.
  • Leia a documentação que vem junto com o WinDbg, ela é bem interessante e explica vários conceitos. Existe uma parte do help que explica como identificar código assembly gerado por um compilador C/C++. Usando o comando ".hh <algum comando>", o help se abre com o <algum comando> já digitado no Índice do HTML Help, o que facilita a procura por tópicos específicos
  • Google (precisa falar?)

E leia os próximos artigos da série!

Veja também
WinDbg: Debugger de gente grande (parte 1)

  
 
 
Comentários
Fabio | e-mail | em 28/10/2004 | #
Quando vc vai fazer a terceira parte. Tô me fudendo pra fazer meu trabalho heheh bem que vc podia me dar umas dicas... lol
Rodrigo Strauss | website | em 25/11/2004 | #
Quando eu vou fazer a terceira parte? Essa é uma pergunta que nem eu sei responder. Mas com certeza eu farei... :-)
Breno | em 26/05/2005 | #
hum...
muito legal esta mostra do windbg que voce deu. aposto que a maioria das pessoas que necessitam de um debugger, ou para trabalho ou para diversao, nao sabem nem da existencia deste programa. procuram conhecimento apenas ao lado do softice, o que, por exepriencia propria, é um grande atraso de vida, pois como voce disse, custa mais que um rim no mercado negro. Ainda que tente encontra-lo pela internet, provavelmente virá com um "bonus kit" cheiio de virus(ah vida cruel!). estou com uma duvida : no tutorial diz que o windbg foi projetado para funcionar em dois computadores conectados, mas existe algum meio para faze-lo rodar em apenas uma maquina? caso sim, por favor dá-me uma ajudinha, isso quebraria muito meu galho, já que tenho apenas um computer.
no mais peco que capriche na parte 3, e torco para que o windbg nao consiga paralizar seu bom humor!
Rodrigo Strauss | website | em 27/05/2005 | #
Não é possível fazer debug com uma máquina só usando o WinDbg, PARA DEBUG KERNEL MODE (drivers). Nesse caso eu costumo usar VMWare, que resolve muito bem o problema.

Para debug de aplicativos, ele funciona igual ao debugger do VC, uma máquina só

A parte 3 já está pronta, em http://www.1bit.com.br/content.1bit/windbg3
CARLOS CESAR CAMPOS | e-mail | em 21/04/2006 | #
estou tentanto instalar o NFSMW, mas sempre dá um erro de KERNEL DEBUGGER, e realmente não sei como resolver isso. Pesquisei e não ententi nada. Exite algum programa para corrigir isto ?
obrigado
Rodrigo Strauss | website | em 22/04/2006 | #
Se você tiver o SoftIce instalado, desinstale. Se no arquivo c:\boot.ini tiver uma flag /DEBUG, tire. Se isso não resolver, sugiro que você faça essa pergunta em um forum de games.
Romero Gonçalves | em 10/12/2006 | #
como desativa kernel debugger??
Algo a dizer?
Nome:


Site:


E-mail:


Escreva o número vinte e seis:


 Não mostre meu e-mail no site, não serve pra nada mesmo...

Comentário





Os comentários devem ser sobre assuntos relativos ao post, eu provavelmente apagarei comentários totalmente offtopic. Se quiser me enviar uma mensagem, use o formulário de contato. E não esqueça: isso é um site pessoal e eu me reservo o direito de apagar qualquer comentário ofensivo ou inapropriado.
rebarba rebarba
  ::::