Como usar o gdbserver para depuração remota no Linux

Última atualização: 14/01/2026
autor: Isaac
  • O gdbserver atua como um agente remoto do GDB para controlar processos em outra máquina via TCP ou serial.
  • Para depurar remotamente, é fundamental compilar com símbolosUtilize o gdb apropriado e configure corretamente os caminhos dos símbolos e das fontes.
  • O gdbserver oferece modo de processo único e modo multiprocesso, integrando-se também com o WinDbg e o QEMU para depuração do kernel.
  • Opções como --debug, sysroot e limites de tamanho de valor ajudam a diagnosticar problemas e estabilizar as sessões.

Depuração remota com gdbserver

Se você programa em C ou C++ em Linux e você nunca mexeu com o gdbserverVocê está perdendo uma das ferramentas mais úteis para depurar processos remotamente, seja em um servidor, um sistema embarcado ou até mesmo dentro de uma máquina virtual ou WSL. Longe de ser algo "mágico" ou reservado para especialistas, o gdbserver é simplesmente um pequeno programa que se comunica com o gdb e controla a execução do processo alvo.

A ideia principal é muito simples.: na máquina onde o binário que você deseja depurar está sendo executado (o alvo) você inicia o gdbserver; no seu computador de trabalho (o hospedeiroVocê inicia o gdb ou até mesmo o WinDbg com suporte ao protocolo gdb. Ambos se conectam via TCP ou porta serial, e a partir daí você pode definir pontos de interrupção, inspecionar variáveis, visualizar a pilha de chamadas ou acompanhar a execução passo a passo como se o programa estivesse rodando em sua própria máquina.

O que é o gdbserver e quando faz sentido usá-lo?

O que é gdbserver?

O gdbserver é um "agente" de depuração remota para o GNU gdb.Sua função é muito específica: ele é executado na máquina onde o programa a ser analisado está sendo executado, controla esse processo (ou processos) e se comunica com um cliente gdb localizado em outra máquina (ou na mesma) por meio de uma conexão remota.

No uso diário, o gdbserver é utilizado em dois cenários típicos.Depuração de software que roda em ambientes embarcados (roteadores, placas com Linux simplificado, dispositivos) IoTetc.) e depurar processos em máquinas Linux remotas, onde não é conveniente ou simplesmente não é possível ter um gdb "completo" com todas as bibliotecas e símbolos.

Em termos práticos, o gdbserver lida com tarefas como: Lê e escreve registros e memória do processo, controla a execução (continuar, pausar, executar passo a passo), gerencia pontos de interrupção e envia todos esses dados para o gdb usando o protocolo remoto do GDB. Essa filosofia é muito semelhante à de ferramentas como o OpenOCD, que atuam como uma ponte entre o gdb e um sistema operacional. Hardwares externo, com a diferença de que o gdbserver é executado no mesmo sistema em que o binário é executado.

Se você vem de ambientes Windows Também é interessante saber Depuradores como o WinDbg podem se comunicar com um servidor gdb no Linux, permitindo depurar processos de usuário no Linux a partir do WinDbg, utilizando o suporte à depuração remota via protocolo gdb que a Microsoft incorporou em versões recentes.

Requisitos básicos para depuração com gdb e gdbserver

Requisitos para usar o gdbserver

Antes de começar a depurar remotamente, você precisa entender a relação entre o host e o alvo.. O alvo É a máquina onde o programa a ser depurado é executado e onde o gdbserver será executado; o hospedeiro Esta é a máquina a partir da qual você executará o gdb (ou WinDbg) e onde você terá o código-fonte e, de preferência, os símbolos de depuração.

O ponto de partida essencial é compilar o binário com símbolos.Em GCC ou g++ isso é conseguido com a flag -ge geralmente também é aconselhável desativar as otimizações (por exemplo, com -O0Isso permite que o depurador exiba variáveis, macros e a estrutura do código com mais precisão. Para macros específicas, você pode usar níveis de depuração mais altos, como -g3.

No lado do host, você precisará de uma versão compatível do gdb. com a arquitetura de destino. Para depurar um sistema embarcado MIPS, ARM ou de outra arquitetura, você deve usar o gdb da cadeia de ferramentas cruzada correspondente (por exemplo). arm-none-eabi-gdb o gdb-multiarch) e, se necessário, configure a arquitetura e a ordem dos bytes (endianness) com comandos como set arch y set endian.

Em relação à conexão, o gdbserver suporta dois tipos principais.Uma conexão serial (muito comum em hardware embarcado, via UART) e TCP/IP, que é mais conveniente quando o alvo está na mesma rede ou é uma máquina Linux acessível pela rede. Em ambos os casos, o comando é usado a partir do gdb. target remote Para conectar-se ao endpoint exposto pelo gdbserver.

Formas de iniciar o gdbserver: modo de processo único e modo multiprocesso

modos de execução do gdbserver

O gdbserver pode funcionar de duas maneiras principais. Quando falamos de depuração em modo de usuário: diretamente associada a um único processo ou como um "servidor de processos" que permite listar e conectar-se a diferentes processos do sistema.

No modo de processo único Você inicia o gdbserver, especificando o host:porta e o programa a ser executado. Em um exemplo simples em uma máquina desktop Linux, você poderia fazer algo assim:

Comando: gdbserver localhost:3333 foo

Com esse comando, o gdbserver inicia o binário. foo e ele permanece escutando no porto 3333.Até que um gdb remoto se conecte, o programa permanece parado; quando o gdb se conecta com target remote localhost:3333, o processo começa a ser controlado pelo destriturador.

No modo multiprocesso (servidor de processos), a opção é utilizada. --multiNeste caso, o gdbserver não inicia diretamente nenhum programa, mas simplesmente fica à escuta de conexões de entrada e permite que o cliente (gdb ou WinDbg) gerencie qual processo criar ou ao qual se conectar:

  Google lança Gemini Code Assist: o assistente de programação gratuito com tecnologia de IA

Comando: gdbserver --multi localhost:1234

Ao trabalhar com o WinDbg no Linux, esse modo múltiplo é especialmente interessante.Porque a partir do próprio WinDbg você pode listar os processos no sistema remoto, ver o PID, o usuário e a linha de comando, e conectar-se ao processo de seu interesse, de forma semelhante ao que é feito com o servidor de processos. dbgsrv.exe no Windows.

Depuração remota com gdbserver e gdb passo a passo

Vamos trazer isso para a realidade com um exemplo bem típico.Depure um aplicativo simples na mesma máquina (host e destino coincidem) usando o gdbserver para simular o cenário remoto.

Primeiro você escreve e compila um pequeno programa.Por exemplo, um loop simples que imprime um contador:

Comando: gcc -g foo.c -o foo

A chave aqui é a bandeira. -gIsso adiciona as informações de depuração necessárias ao binário para que o gdb possa exibir linhas de código, nomes de variáveis, tipos, etc. Em um ambiente de compilação cruzada "real", você faria essa compilação com a cadeia de ferramentas cruzada e, em seguida, copiaria o binário e suas dependências para o destino.

O próximo passo é iniciar o gdbserver no alvo.Se o host e o alvo forem a mesma máquina, então:

Comando: gdbserver localhost:3333 foo

Você verá uma mensagem semelhante a “Processo foo criado; pid = XXXX; Ouvindo na porta 3333”. Isso indica que o gdbserver criou o processo e está aguardando a conexão do gdb. Se você estiver em um sistema que exige mais privilégios (por exemplo, para se conectar a processos do sistema), talvez seja necessário executar o comando com sudoMas é sempre prudente ser cauteloso ao conceder permissão. raiz ao dessulfurizador.

No host, você inicia o gdb especificando o executável local. (o mesmo que está sendo executado no alvo, ou uma cópia idêntica com símbolos):

Comando: gdb foo

Uma vez dentro do gdb, você estabelece a conexão remota com:

Comando: target remote localhost:3333

Nesse ponto, o gdb carrega os símbolos do binário local.Ele sincroniza com o gdbserver e assume o controle do processo que está sendo executado no gdbserver. A partir daí, o fluxo é o usual: comandos como break definir pontos de ruptura, continue, step, next, print para inspecionar variáveis, backtrace para ver a bateria, etc.

Conectando-se a processos em execução com o gdbserver

Nem sempre é desejável iniciar o programa do zero.Muitas vezes, você tem interesse em participar de um processo que já está em andamento (por exemplo, um httpd um roteadorum daemon do sistema ou um serviço de produção).

O padrão típico é usar a opção --attach do gdbserverpassando a porta em que ficará em escuta e o PID do processo alvo. Por exemplo, em um roteador onde você copiou um gdbserver compilado para sua arquitetura, você poderia fazer o seguinte:

Comando: gdbserver localhost:3333 --attach <pid_de_httpd>

No lado do host, você usará uma versão do gdb que suporte a arquitetura do roteador., por exemplo gdb-multiarchConfigurar a arquitetura e a ordem dos bytes (endianness) antecipadamente:

Comando: set arch mips
set endian big

Em seguida, você especifica o arquivo local que contém os símbolos. do binário remoto (por exemplo file httpd) e, se necessário, você informa ao gdb onde o binário está sendo executado no alvo com set remote exec-file /usr/bin/httpdFinalmente, assim como antes, você se conecta com:

Comando: target remote 192.168.0.1:3333

Uma vez anexadoVocê pode definir pontos de interrupção em funções específicas (por exemplo, break checkFirmware), continue a execução e deixe que o fluxo normal do programa (carregar o firmware a partir da interface web, por exemplo) acione o ponto de interrupção.

Utilizando o gdbserver com o WinDbg no Linux

Nos últimos anos, a Microsoft adicionou suporte para depuração de processos Linux no WinDbg. Utilizando o gdbserver como backend. Esta funcionalidade destina-se a cenários em que você trabalha no Windows, mas o código é executado no Linux (incluindo o WSL).

Para depurar um processo específico do Linux com o WinDbg usando o gdbserverO fluxo seria algo assim: primeiro você localiza o processo alvo na máquina Linux com um comando como ps -A (por exemplo um python3 que está em execução), então você inicia o gdbserver no alvo:

Comando: gdbserver localhost:1234 python3

Se o ambiente assim o exigir, poderá ser necessário usar sudo gdbserver ...Com as mesmas precauções de segurança de sempre. Assim que o gdbserver indicar que está "Escutando na porta 1234", no WinDbg vá em "Arquivo / Conectar ao depurador remoto" e especifique uma string de conexão do seguinte tipo:

Comando: gdb:server=localhost,port=1234

O WinDbg utiliza um pequeno "driver" de protocolo gdb para se comunicar com o servidor gdb. e, uma vez estabelecida a conexão, ela permanece interrompida no ponto de Bota do processo. A partir daí, você pode usar suas janelas de pilha, módulos, memória, pontos de interrupção, bem como comandos como k para ver a bateria ou lm Para listar os módulos (lembrando que alguns comandos esperam o formato PE e não o ELF, portanto, podem exibir dados estranhos em certos casos).

gdbserver e servidor de processos WinDbg

Além do caso de processo único, o WinDbg pode se conectar a um servidor gdb que atua como um servidor de processos. para funcionar de forma mais semelhante ao funcionamento com processos remotos do Windows. Nesse modo, o gdbserver é iniciado com --multi e sem um processo associado:

  A melhor maneira de ativar o modo de baixo consumo de energia no iPhone

Comando: sudo gdbserver --multi localhost:1234

No WinDbg, escolha “Arquivo / Conectar ao servidor de processos”. e você reutiliza a string de conexão. gdb:server=localhost,port=1234Quando a conexão estiver ativa, você poderá listar os processos Linux disponíveis e conectar-se ao que desejar ou até mesmo iniciar um novo processo.

Um detalhe sutil deve ser levado em consideração.O WinDbg distingue entre "servidor de processos" e "alvo único" dependendo se o gdbserver já está anexado a um processo no momento da conexão. Se você deixou o gdbserver anexado a um processo, fechou o WinDbg e tentou se reconectar, ele pode não ser detectado como um servidor de processos, e talvez seja necessário reiniciar o gdbserver.

Para encerrar uma sessão do oficial de justiça.Normalmente, basta pressionar CTRL+D no console onde o gdbserver está em execução e interromper a depuração no WinDbg. Em alguns casos extremos, se houver problemas de sincronização, pode ser necessário fechar completamente o depurador e reiniciar o gdbserver do zero.

Gerenciamento de símbolos e código-fonte na depuração remota

Uma das chaves para tornar a depuração remota conveniente é ter a parte de símbolos e fontes bem resolvida.Sem símbolos, navegar pela pilha de chamadas ou definir pontos de interrupção em funções específicas torna-se uma tortura.

Em cenários clássicos de gdb + gdbserver, o ideal é manter uma cópia do executável com os símbolos no host. (sem remoção de símbolos) e a árvore de origem. O gdb não exige que o binário remoto contenha os símbolos; basta que o arquivo local que você carrega com file corresponder ao executável remoto no nível de deslocamento.

No mundo do WinDbg e da depuração no Linux, também surgiram serviços como o DebugInfoD.que expõem símbolos e fontes via HTTP. O WinDbg pode usar caminhos especiais do tipo DebugInfoD*https://debuginfod.elfutils.org tanto .sympath como em .srcpath Para baixar símbolos DWARF e código-fonte binário ELF do Linux sob demanda.

Em um exemplo específico com WSL, onde o código do usuário está em C:\Users\Bob\Você poderia dizer ao WinDbg:

Comando: .sympath C:\Users\Bob\
.srcpath C:\Users\Bob\

E se você também quiser usar o DebugInfoD para binários do sistema:

Comando: .sympath+ DebugInfoD*https://debuginfod.elfutils.org
.srcpath+ DebugInfoD*https://debuginfod.elfutils.org

Com essa configuração, ao inspecionar a pilha ou entrar em funções da libc,O WinDbg pode tentar baixar os símbolos DWARF correspondentes e, se o servidor também expuser o código, exibir a fonte com detalhes consideráveis, embora internamente o conjunto de ferramentas do Windows não lide com ELF e DWARF de forma tão "nativa" quanto PE e PDB.

Exemplo prático: depurando um programa em C++ com gdbserver e WinDbg

Um exemplo ilustrativo é um pequeno aplicativo em C++ que escreve uma saudação na tela., compilado no WSL com símbolos de depuração. Imagine um programa que reserva um std::array<wchar_t, 50> e copia uma mensagem mais longa para dentro dela, fazendo com que o texto seja truncado e caracteres apareçam. ???? ao final.

Após compilar com algo como:

Comando: g++ DisplayGreeting.cpp -g -o DisplayGreeting

Você inicia o gdbserver contra esse binário.:

Comando: gdbserver localhost:1234 DisplayGreeting

No WinDbg, você se conecta com a string gdb:server=localhost,port=1234 E, uma vez que a sessão esteja estabelecida e os caminhos dos símbolos e fontes estejam configurados, você define um ponto de interrupção em DisplayGreeting!main, você pode usar dx greeting Inspecione a matriz local e veja seu tamanho (50 posições), e verifique visualmente na aba de memória ou na visualização de variáveis ​​como a saudação é cortada.

A beleza deste exemplo reside em demonstrar que, mesmo sem suporte completo para todos os formatos ELF/DWARF no WinDbgVocê pode percorrer pilhas de execução, inspecionar tipos, definir pontos de interrupção por nome de função e navegar pelo código C++ de forma razoavelmente confortável usando o gdbserver como um backend remoto.

Depurando o kernel do Linux com qemu e gdb

O gdbserver não é usado apenas no modo usuário; existem também cenários muito poderosos no modo kernel.especialmente quando se combina o QEMU com suporte para depuração. Embora aqui a função de "gdbserver" seja desempenhada pela própria opção do QEMU, a abordagem é idêntica: uma extremidade executa o sistema a ser depurado e abre uma porta gdb; a outra extremidade é o gdb ou um depurador que se comunica pelo protocolo remoto.

Para depurar o kernel, você precisa compilá-lo com opções de depuração específicas.: ativar a geração de informações de depuração (CONFIG_DEBUG_INFO), os scripts do kernel GDB (CONFIG_GDB_SCRIPTS) e o próprio modo de depuração do kernel (CONFIG_DEBUG_KERNELTambém é importante desativar opções que removem símbolos durante a vinculação, como "Remover símbolos gerados pelo montador durante a vinculação".

Após a compilação, você obterá um arquivo binário. vmlinux “não despido”que é o que você usará no gdb. Você também precisa de um initramfs básico, que pode ser gerado com um comando como:

Comando: mkinitramfs -o ramdisk.img

Em seguida, inicie o QEMU com parâmetros de depuração.Um exemplo típico inclui a opção -gdb tcp::1234 para abrir um endpoint remoto compatível com gdb, e -S para que a máquina virtual inicie pausada desde o início. Você também especifica o kernel com -kernel vmlinux, o -initrd ramdisk.img, a memória com -m 512 e você geralmente redireciona o console para ttyS0 para gerenciar tudo desde o terminal.

  Como atualizar o Edge para a versão mais recente no Windows 11: um guia completo passo a passo

Com o QEMU detido aguardando o gdbA partir da máquina host, inicie o gdb apontando para vmlinux e você se conecta com target remote localhost:1234A partir daí, você pode definir pontos de interrupção antecipados, por exemplo, um hb start_kernele controlar a execução com comandos como c (continuar) e CTRL+C para pausar novamente.

Mudanças e nuances recentes no gdb e gdbserver

Em distribuições modernas como o Red Hat Enterprise Linux 8, existem diversas mudanças no gdb e no gdbserver que vale a pena ter em mente.especialmente se você estiver vindo de versões anteriores ou tiver scripts que analisam a saída do depurador.

Por um lado, o gdbserver agora inicia os processos "inferiores" usando um shell.Assim como o gdb, isso permite a expansão e substituição de variáveis ​​na linha de comando. Se, por algum motivo, você precisar desativar esse comportamento, existem configurações específicas documentadas no RHEL 8 para reverter ao modo anterior.

Diversos itens também foram removidos ou alterados.Suporte à depuração para programas Java compilados com gcj, o modo de compatibilidade XDB do HP-UX, comandos como set remotebaud (substituído por set serial baud) ou compatibilidade com um determinado formato mais antigo de stabsAlém disso, a numeração de threads não é mais global, mas sim por thread "inferior", e aparece como inferior_num.thread_num, com novas variáveis ​​de conveniência, como $_gthread para se referir ao identificador global.

Outra nova funcionalidade relevante é o ajuste. max-value-sizeIsso limita a quantidade de memória que o gdb pode alocar para exibir o conteúdo de um valor. O padrão é 64 KiB, portanto, tentativas de imprimir arrays enormes ou estruturas massivas podem resultar em um aviso de "valor muito grande" em vez de exibir toda a memória disponível.

Também foi ajustado o modo como o gdb lida com o sysrootO valor padrão agora é target:Isso significa que, para processos remotos, ele primeiro tentará encontrar bibliotecas e símbolos no sistema de destino. Se você quiser que ele priorize símbolos locais, você deve executar set sysroot com o percurso que lhe interessa antes de fazer target remote.

Com relação ao histórico de comandos, a variável de ambiente atualmente em uso é GDBHISTSIZE em vez de HISTSIZEIsso permite ajustar com precisão por quanto tempo você deseja reter os comandos digitados em sessões de depuração, sem interferir no comportamento de outros aplicativos que usam a biblioteca de leitura de linhas.

Dicas de fluxo de trabalho e solução de problemas com o gdbserver

Para ter um fluxo de trabalho confortável, existem alguns padrões que tendem a funcionar muito bem. Ao desenvolver para sistemas embarcados ou servidores remotos, o primeiro passo é automatizar ao máximo a compilação de símbolos e a implantação de binários no destino. Dessa forma, você sempre sabe qual versão do executável está em execução e tem a cópia dos símbolos prontamente disponível no host.

Em ambientes com muitos núcleos de processamento que travam, vale a pena aprender a usar o gdb no modo em lote., com bandeiras como --batch, --ex y -x para executar comandos automaticamente em uma lista de núcleos e processar seus rastreamentos de pilha a partir de scripts (por exemplo, em PythonIsso permite filtrar rapidamente problemas recorrentes, agrupar falhas por rastreamento de pilha, etc.

Quando algo dá errado com a conexão remota, a opção --debug O gdbserver é seu melhor amigo.Se você iniciar, por exemplo, um servidor de processos com:

Comando: gdbserver --debug --multi localhost:1234

O console do gdbserver exibirá registros detalhados do que está acontecendo. No nível do protocolo remoto, isso inclui pacotes recebidos, erros de formatação, problemas de desconexão, etc. Isso é muito útil quando o servidor gdb se desconecta repentinamente, um processo trava assim que um ponto de interrupção é definido ou a interface gráfica de depuração envia algo que o servidor gdb não entende.

Em contextos como um roteador TP-Link, onde você conecta o gdbserver a um processo crítico como httpdÉ relativamente comum que certos pontos de interrupção criem condições de corrida ou mecanismos de monitoramento que encerram o processo quando ele permanece "travado" por muito tempo no depurador. Nessas situações, pode ser necessário ajustar quais sinais são bloqueados, quais threads são controladas e, se aplicável, modificar a própria configuração do sistema (tempos limite, mecanismos de monitoramento de hardware) para permitir sessões de depuração mais longas.

Utilizar o gdbserver corretamente envolve combinar várias peças.Compile com os símbolos apropriados, escolha o gdb correto para a arquitetura, configure os caminhos de símbolos e de origem, entenda os dois modos principais do gdbserver (processo único e multiprocesso) e não tenha medo de usar o modo de compilação. --debug quando a conexão não se comporta como esperado. Com essa base, depurar aplicativos em execução em um sistema Linux remoto, um roteador ou uma máquina virtual com um kernel personalizado a partir do seu PC torna-se bastante rotineiro e, acima de tudo, incrivelmente útil.