Depurando um bug que só acontece em uma máquina sem Visual Studio

Um bug reproduz no servidor de teste e não no seu notebook. O servidor de teste não tem Visual Studio, e instalar uma IDE inteira ali só para colocar um breakpoint não é uma opção. A depuração remota existe para esse caso. Um programa pequeno e independente roda na máquina alvo, seu Visual Studio local se conecta a ele pela rede, e você ganha breakpoints e inspeção de variáveis em um processo que não está rodando nem perto da sua mesa.

São três etapas: rodar o depurador remoto no alvo, anexar a partir do Visual Studio, carregar os símbolos certos. Cada uma falha de um jeito próprio. Depois delas vêm os dois alvos remotos que você tem mais chance de encontrar na prática: um processo dentro de um container Docker e uma aplicação no Azure App Service.

Como instalar e rodar o depurador remoto do Visual Studio (msvsmon)

O programa é o msvsmon.exe, o Visual Studio Remote Debugger. Você consegue colocá-lo na máquina alvo de duas formas.

Se o alvo já tem o Visual Studio Community, Professional ou Enterprise instalado, o msvsmon.exe já está lá, em <pasta de instalação do Visual Studio>\Common7\IDE\Remote Debugger\x64\ (ou x86\, de acordo com a arquitetura que você está depurando). Rode-o direto.

Caso contrário, baixe o pacote standalone de remote tools na página de remote tools da Microsoft para a sua versão do Visual Studio, e pegue a atualização mais recente dele. A compatibilidade só funciona em uma direção: remote tools mais novas funcionam com um Visual Studio mais antigo, mas remote tools antigas podem recusar um Visual Studio mais novo. Escolha a arquitetura do sistema operacional alvo (x86, x64 ou ARM64), não a da aplicação que você está depurando.

A primeira execução abre um assistente de configuração que adiciona uma regra ao Firewall do Windows para o tipo de rede em que você está (domínio, privada ou pública). Quando ele termina, a janela do Remote Debugger mostra um nome de servidor e uma porta. Esse é o endereço que você vai digitar no Visual Studio. Deixe a janela aberta; fechá-la (File > Exit) encerra a sessão.

Portas e autenticação do depurador remoto: o que bloqueia a conexão

A regra de firewall do assistente só abre a porta TCP de entrada, e essa porta muda conforme a versão do Visual Studio. É a 4026 no Visual Studio 2022; versões mais antigas usam números diferentes. Se o alvo estiver atrás de um firewall que o assistente não configurou, como um appliance corporativo ou um security group na nuvem, abra essa porta específica você mesmo. Chutar “a porta do depurador” sem checar sua versão é perda de tempo.

A porta UDP 3702 de saída é opcional. Ela permite que o alvo apareça no seletor Find do Visual Studio. Sem ela você ainda consegue se conectar; só precisa digitar o endereço manualmente.

O modo de autenticação precisa bater dos dois lados. Por padrão o depurador remoto usa Windows Authentication, então a conta do Windows que está rodando o Visual Studio precisa de permissão no depurador remoto. Conceda isso em Tools > Permissions, na janela do Remote Debugger (exige direitos de administrador), ou inicie o msvsmon pela linha de comando já com a conta liberada:

1
msvsmon /allow user@computer

Trocar para No Authentication (Tools > Options na janela do Remote Debugger) pula tudo isso, e numa VM descartável a tentação é grande. Faça isso só numa rede em que você confia totalmente. Qualquer um que alcance essa porta consegue anexar a qualquer processo rodando sob a mesma conta: sem prompt, sem senha.

Como anexar a um processo remoto pelo Visual Studio

Com o depurador remoto rodando e acessível:

  1. No Visual Studio, abra Debug > Attach to Process (Ctrl+Alt+P).
  2. Configure Connection type como Remote (Windows).
  3. Em Connection target, digite o endereço no formato que a própria janela do depurador remoto mostra, geralmente <nome-da-máquina>:<porta>. Se o nome da máquina não resolver, use o IP: 10.0.0.15:4026.
  4. Clique em Refresh para puxar a lista de processos da máquina remota, depois encontre e selecione seu processo. Se ele não estiver rodando sob sua conta, marque Show processes from all users. O Visual Studio mostra um aviso de segurança antes de anexar a um processo de outra pessoa; leia-o em vez de descartá-lo.
  5. Deixe Code type em Automatic. A exceção é um processo de código misto em que o attach falha silenciosamente para uma das linguagens: escolha essa linguagem explicitamente e anexe de novo, e você recebe um erro específico em vez de nada.
  6. Clique em Attach.

Para uma aplicação ASP.NET hospedada no IIS, o processo que você quer é o w3wp.exe. Para uma aplicação .NET rodando seu próprio servidor Kestrel, é o dotnet.exe ou o nome do executável da própria aplicação. O IIS costuma rodar vários w3wp.exe idênticos lado a lado. A coluna Command Line na lista de processos é o que diferencia um do outro.

Corrigindo “no symbols loaded” na depuração remota

Anexar não significa que você já consegue depurar. Abra Debug > Windows > Modules e olhe a coluna Symbol Status do seu binário. Um círculo de breakpoint vermelho vazio em vez de um preenchido diz a mesma coisa do lado do editor: o depurador não tem símbolos para mapear aquele breakpoint.

Três status aparecem na prática:

StatusO que significaCorreção
Skipped loading symbolsO carregamento de símbolos está filtrado pelas suas configuraçõesConfira Debug > Options > Symbols por uma regra de include/exclude bloqueando esse módulo
Cannot find or open the PDB fileNenhum .pdb correspondente está acessívelCopie o .pdb exato do build que gerou o binário implantado para a máquina remota, ou aponte o Visual Studio para ele
Sem entrada / só hex de aparência nativaO módulo não tem nenhuma informação de debugFoi compilado em Release sem .pdb, ou é uma DLL do sistema que você não precisa depurar

A maior parte do tempo perdido aqui vem de uma regra só: o depurador só aceita um .pdb que bate exatamente com o binário. Não “a mesma versão”. O arquivo daquele build específico. Se a máquina remota foi reimplantada depois do seu último build local, seu .pdb local não bate mais. Quando o carregamento automático não encontra o arquivo certo, clique com o botão direito no módulo dentro da janela Modules, escolha Load Symbols e navegue até a pasta de saída do próprio deploy.

O hábito que evita tudo isso: publique o .pdb junto com o binário em todo deploy que você possa precisar depurar. Reconstruir um que bate depois do fato raramente funciona.

Como depurar um processo em um container Docker

Tudo acima presume uma máquina Windows em que você pode instalar software. Um container é diferente. Você não coloca o msvsmon numa imagem de produção, e dependendo da configuração da rede Docker, o container pode nem estar acessível a partir do seu host pelo nome.

Se o projeto tem suporte a Docker ativado (Add > Docker Support, ou um projeto já criado com um Dockerfile), o tooling de container do Visual Studio faz o trabalho: F5 constrói uma imagem configurada para debug, inicia o container e anexa. Para um container que você não iniciou pelo Visual Studio, abra Debug > Attach to Process, configure Connection type como Docker (Linux Container) ou Docker (Windows Container) de acordo com a imagem, e escolha o container na lista. O Visual Studio passa pelo daemon do Docker e coloca seu próprio depurador dentro do container em execução, então você nunca precisa adicionar um à imagem.

Como depurar remotamente uma aplicação no Azure App Service

Para uma aplicação implantada no Azure App Service, pule a configuração manual do depurador remoto. Clique com o botão direito no projeto no Solution Explorer, escolha Publish, depois no menu … do publish profile selecione Attach Debugger. O Visual Studio ativa o endpoint de depuração remota na instância do App Service e cuida da conexão e da autenticação para você. Depois de anexado, as regras de símbolos das seções anteriores continuam valendo. Confira a janela Modules antes de confiar em um breakpoint.

Depurador remoto ou git bisect: qual usar primeiro

Um depurador remoto mostra o que uma linha específica está fazendo agora, numa máquina específica. Ele não consegue dizer qual commit introduziu o problema. O git bisect responde isso, com uma busca binária pelo histórico em vez de uma busca pela sua memória.

Para uma regressão, siga essa ordem. Se você ainda não sabe qual commit quebrou as coisas, faça o bisect primeiro. Quando tiver o commit e uma máquina em que o bug reproduz, configure o depurador remoto ali e descubra o porquê.

Artigos relacionados