Com utilitzar gdbserver per a depuració remota a Linux

Darrera actualització: 14/01/2026
Autor: Isaac
  • gdbserver actua com a agent remot de GDB per controlar processos en una altra màquina via TCP o sèrie.
  • Per depurar en remot és clau compilar amb símbols, utilitzar el gdb adequat i configurar bé rutes de símbols i fonts.
  • gdbserver ofereix mode procés únic i mode multi, integrant-se també amb WinDbg i amb QEMU per depurar kernels.
  • Opcions com --debug, sysroot i límits de mida de valors ajuden a diagnosticar problemes i estabilitzar les sessions.

Depuració remota amb gdbserver

Si programes a C o C++ a Linux i mai no has tocat gdbserver, estàs deixant passar una de les eines més útils per a depurar processos en remot, ja sigui en un servidor, en un sistema embegut o fins i tot dins una màquina virtual o WSL. Lluny de ser “màgic” o reservat a experts, gdbserver és simplement un petit programa que s'encarrega de parlar amb gdb i controlar l'execució del procés objectiu.

La idea clau és molt senzilla: a la màquina on s'executa el binari que vols depurar (el target) arrenques gdbserver; al teu equip de treball (el host) arranques gdb o fins i tot WinDbg amb suport per al protocol gdb. Tots dos es connecten per TCP o per un port sèrie ia partir d'aquí podeu establir punts de ruptura, inspeccionar variables, veure la pila o seguir l'execució pas a pas com si el programa estigués corrent a la teva pròpia màquina.

Què és gdbserver i quan té sentit fer-lo servir

Què és gdbserver

gdbserver és un “agent” de depuració remota per al GNU gdb. La seva funció és molt concreta: s'executa a la màquina on corre el programa a analitzar, controla aquest procés (o processos) i es comunica amb un client gdb situat a una altra màquina (oa la mateixa) a través d'una connexió remota.

En el dia a dia, gdbserver es fa servir en dos escenaris típics: depurar programari que corre en entorns embeguts (routers, plaques amb Linux retallat, dispositius IO, etc.) i depurar processos en màquines Linux remotes, on no és còmode o directament no és possible tenir gdb “gros” amb totes les llibreries i símbols.

A nivell pràctic, gdbserver s'ocupa de tasques com llegir i escriure registres i memòria del procés, controlar l'execució (continuar, pausar, pas a pas), gestionar punts de ruptura i enviar totes aquestes dades a gdb mitjançant el protocol remot de GDB. Aquesta filosofia és molt semblant a la de ferramentes com OpenOCD, que fan de pont entre gdb i un maquinari extern, amb la diferència que gdbserver s'executa al propi sistema on corre el binari.

Si veniu d'entorns Windows també és interessant saber que depuradors com WinDbg poden parlar amb un gdbserver al Linux, de manera que pots depurar processos d'usuari al Linux des de WinDbg usant el suport de depuració remota via protocol gdb que Microsoft ha incorporat en versions recents.

Requisits bàsics per depurar amb gdb i gdbserver

Requisits per utilitzar gdbserver

Abans de llançar-te a depurar en remot necessites tenir clar el binomi host/target. El target és la màquina on corre el programa a depurar i on sexecutarà gdbserver; el host és la màquina des de la qual manejaràs gdb (o WinDbg) i on tindràs el codi font i, preferiblement, els símbols de depuració.

El punt de partida imprescindible és compilar el binari amb símbols. A GCC o g++ això s'aconsegueix amb el flag -g, i sol ser recomanable a més a més desactivar optimitzacions (per exemple amb -O0) perquè el depurador pugui mostrar variables, macros i estructura del codi de manera més fidel. Per a macros concretes pots utilitzar nivells de depuració més alts, com ara -g3.

Al costat del host necessitaràs una versió de gdb compatible amb l'arquitectura objectiu. Per depurar un sistema embegut MIPS, ARM o una altra arquitectura, cal utilitzar el gdb de la toolchain creuada corresponent (per exemple arm-none-eabi-gdb o gdb-multiarch) i, si cal, configurar l'arquitectura i endianness amb ordres com a set arch y set endian.

Pel que fa a la connexió, gdbserver admet dos tipus principals: un enllaç sèrie (molt habitual en maquinari embegut, a través d'UART) i TCP/IP, que és el més còmode quan el target és a la mateixa xarxa o és una màquina Linux accessible per xarxa. En ambdós casos, des de gdb es fa servir l'ordre target remote per connectar-vos a l'endpoint exposat per gdbserver.

Formes d'arrencar gdbserver: procés únic i mode multi

Maneres d'execució de gdbserver

gdbserver pot funcionar de dues maneres principals quan parlem de depuració en mode usuari: associat directament a un sol procés o com un “servidor de processos” que permet llistar i adjuntar diferents processos del sistema.

En mode d'un sol procés llances gdbserver indicant el host:port i el programa a executar. En un exemple senzill en una màquina Linux descriptori podries fer una cosa així:

comando: gdbserver localhost:3333 foo

Amb aquesta comanda gdbserver arrenca el binari foo i es queda escoltant al port 3333. Fins que no es connecti un gdb remot, el programa roman detingut; quan gdb es connecta amb target remote localhost:3333, el procés comença a ser controlat pel depurador.

Al mode multiprocés (servidor de processos) s'utilitza l'opció --multi. En aquest cas, gdbserver no llança directament cap programa, sinó que es limita a escoltar connexions entrants i permet que el client (gdb o WinDbg) gestioni quin procés crear oa quin adjuntar-se:

  Google llança Gemini Code Assist: l'assistent gratuït de programació amb IA

comando: gdbserver --multi localhost:1234

Quan es treballa amb WinDbg a Linux, aquest mode multi és especialment interessant, perquè des del mateix WinDbg es pot llistar processos del sistema remot, veure PID, usuari i línia d'ordres, i adjuntar al que interessi, de manera semblant a com es fa amb el servidor de processos dbgsrv.exe a Windows.

Depuració remota amb gdbserver i gdb pas a pas

Baixarem això a terra amb un exemple molt típic: depurar una aplicació senzilla a la mateixa màquina (host i target coincideixen) usant gdbserver per simular l'escenari remot.

Primer escrius i compiles un petit programa, per exemple un bucle ximple que imprimeix un comptador:

comando: gcc -g foo.c -o foo

La clau aquí és el flag -g, que fica al binari la informació de depuració necessària perquè gdb pugui mostrar línies de codi, noms de variables, tipus, etc. En un entorn “real” de cross-compiling, aquesta compilació la faries amb la toolchain creuada i després copiaries tant el binari com les seves dependències al target.

El següent pas és arrencar gdbserver al target. Si host i target són la mateixa màquina, n'hi ha prou amb:

comando: gdbserver localhost:3333 foo

Veureu un missatge similar a "Process foo created; pid = XXXX; Listening on port 3333". Això indica que el gdbserver ha creat el procés i està esperant que el gdb es connecti. Si esteu en un sistema on es requereixen més privilegis (per exemple per adjuntar a processos del sistema), potser necessiteu llançar l'ordre amb sudo, però sempre convé ser prudent amb donar permisos de root al depurador.

Al host, inicies gdb indicant l'executable local (el mateix que s'està executant al target, o una còpia idèntica amb símbols):

comando: gdb foo

Ja dins de gdb, establiu la connexió remota amb:

comando: target remote localhost:3333

En aquest moment, gdb carrega els símbols del binari local, se sincronitza amb gdbserver i passa a controlar el procés que està realment corrent sota gdbserver. A partir d'aquí el flux és habitual: ordres com break per posar punts de ruptura, continue, step, next, print per inspeccionar variables, backtrace per veure la pila, etc.

Connexió a processos ja en execució amb gdbserver

No sempre vols llançar el programa des de zero; moltes vegades t'interessa adjuntar-te a un procés que ja està corrent (per exemple un httpd d'un enrutador, un dimoni del sistema o un servei en producció).

El patró típic és fer servir l'opció --attach de gdbserver, passant el port on escoltarà i el PID del procés objectiu. Per exemple, en un router on has copiat un gdbserver compilat per a la seva arquitectura podries fer:

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

Al costat del host usaràs una versió de gdb que suporti l'arquitectura del router, Per exemple gdb-multiarch, configurant abans l'arquitectura i l'endianness:

comando: set arch mips
set endian big

Després indiqueu el fitxer local que conté els símbols del binari remot (per exemple file httpd) i, si cal, li dius a gdb on s'executa realment el binari al target amb set remote exec-file /usr/bin/httpd. Finalment, igual que abans, connectes amb:

comando: target remote 192.168.0.1:3333

Un cop adjuntat, pots posar punts de ruptura en funcions concretes (per exemple break checkFirmware), continuar lexecució i deixar que el flux normal del programa (pujar un microprogramari des de la interfície web, per exemple) dispari el punt de ruptura.

Ús de gdbserver amb WinDbg a Linux

En els darrers anys Microsoft ha afegit suport per a depuració de processos Linux a WinDbg usant precisament gdbserver com a backend. Aquesta funcionalitat està pensada per a escenaris on treballes a Windows però el codi corre a Linux (incloent WSL).

Per depurar un procés Linux concret amb WinDbg usant gdbserver, el flux seria una cosa així: primer localitzes el procés objectiu a la màquina Linux amb una ordre com ps -A (per exemple un python3 que està corrent), després llances gdbserver al target:

comando: gdbserver localhost:1234 python3

Si l'entorn ho requereix, potser haureu d'usar sudo gdbserver ..., amb les mateixes precaucions de seguretat de sempre. Quan gdbserver indica que està “Listening on port 1234”, a WinDbg vas a “Fitxer / Connectar al depurador remot” i especifiques una cadena de connexió de tipus:

comando: gdb:server=localhost,port=1234

WinDbg utilitza un petit “driver” de protocol gdb per parlar amb gdbserver i, una vegada establerta la connexió, es queda detingut al punt de arrencada del procés. Des d'aquí pots fer servir les finestres de pila, mòduls, memòria, punts de ruptura, així com ordres com k per veure la pila o lm per llistar mòduls (tenint en compte que algunes ordres esperen format PE i no ELF, per la qual cosa poden mostrar dades estranyes en certs casos).

Servidor de processos gdbserver i WinDbg

A més del cas de procés únic, WinDbg pot connectar-se a un gdbserver que actuï com a servidor de processos per treballar de forma més semblant a com ho fa amb processos Windows remots. En aquest mode, gdbserver es llança amb --multi i sense procés associat:

  La millor manera d'activar el mode de baix consum a l'iPhone

comando: sudo gdbserver --multi localhost:1234

Des de WinDbg tries “Fitxer / Connectar al servidor de processos” i tornes a fer servir la cadena de connexió gdb:server=localhost,port=1234. Quan la connexió està activa, pots llistar els processos Linux disponibles i adjuntar-te al que vulguis o fins i tot llançar un procés nou.

Cal tenir present un detall subtil: WinDbg distingeix entre “servidor de processos” i “destinació única” en funció de si gdbserver està ja associat a un procés quan es connecta. Si vas deixar gdbserver adjuntat a un procés, vas tancar WinDbg i després intentes reconnectar, és possible que no el detecti com a servidor de processos i hagis de reiniciar gdbserver.

Per finalitzar una sessió servidors de processos, n'hi ha prou amb prémer CTRL+D a la consola on corre gdbserver i aturar la depuració des de WinDbg. En alguns casos extrems, si hi ha problemes de sincronització, cal tancar completament el depurador i rellançar gdbserver des de zero.

Gestió de símbols i codi font en depuració remota

Una de les claus perquè la depuració remota sigui còmoda és tenir ben resolta la part de símbols i fonts. Sense símbols, navegar per la pila o posar punts de ruptura en funcions concretes es converteix en una tortura.

En escenaris gdb + gdbserver clàssics, l'ideal és conservar a l'amfitrió una còpia de l'executable amb símbols (no strippeado) i l'arbre de fonts. gdb no necessita que el binari remot contingui els símbols; només cal que l'arxiu local que carreguis amb file coincideixi amb lexecutable remot a nivell doffsets.

Al món WinDbg i depuració de Linux han aparegut a més serveis com DebugInfoD, que exposen símbols i fonts a través de HTTP. WinDbg pot utilitzar rutes especials del tipus DebugInfoD*https://debuginfod.elfutils.org tant en .sympath com a .srcpath per descarregar sota demanda símbols DWARF i codi font de binaris ELF de Linux.

En un exemple concret amb WSL, on el codi d'usuari és baix C:\Users\Bob\, podries dir-li a WinDbg:

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

I si a més vols estirar DebugInfoD per a binaris del sistema:

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

Amb aquesta configuració, quan inspeccions la pila o entris en funcions de la libc, WinDbg podrà intentar descarregar els símbols DWARF corresponents i, si el servidor també exposa el codi, mostrar la font amb força detall, encara que internament la cadena d'eines de Windows no tracti ELF i DWARF de forma tan “nativa” com PE i PDB.

Exemple pràctic: depurar un programa C++ amb gdbserver i WinDbg

Un exemple il·lustratiu és una petita aplicació C++ que escriu una salutació a la pantalla, compilada amb WSL amb símbols de depuració. Imagina un programa que reserva un std::array<wchar_t, 50> i copia en ell un missatge més llarg, provocant que el text es trunqui i apareguin caràcters ???? a al final.

Després de compilar amb alguna cosa com:

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

Arrenques gdbserver contra aquest binari:

comando: gdbserver localhost:1234 DisplayGreeting

A WinDbg et connectes amb la cadena gdb:server=localhost,port=1234 i, una vegada establerta la sessió i configurades rutes de símbols i fonts, estableixes un punt de ruptura a DisplayGreeting!main, Pots utilitzar dx greeting per inspeccionar l'array local i veure'n la mida (50 posicions), i comprovar visualment a la pestanya de memòria oa la vista de variables com la salutació es queda tallada.

La gràcia d'aquest exemple és que demostra que, fins i tot sense un suport complet de tots els formats ELF/DWARF a WinDbg, es poden recórrer piles, inspeccionar tipus, posar breakpoints per nom de funció i navegar pel codi C++ de forma raonablement còmoda usant gdbserver com a backend remot.

Depuració del nucli de Linux amb qemu i gdb

gdbserver no només es fa servir en mode usuari; també hi ha escenaris molt potents en mode kernel, especialment quan combines QEMU amb suport de depuració. Encara que aquí el paper de gdbserver ho fa la pròpia opció de QEMU, l'enfocament és idèntic: un extrem executa el sistema a depurar i obre un port gdb; l'altre extrem és el gdb o un depurador que parli el protocol remot.

Per poder depurar el nucli cal compilar-lo amb opcions específiques de depuració: activar la generació d'informació de depuració (CONFIG_DEBUG_INFO), els scripts de GDB per a kernel (CONFIG_GDB_SCRIPTS) i el propi mode de depuració de kernel (CONFIG_DEBUG_KERNEL). També és important desactivar opcions que eliminin símbols a l'enllaç, com “Strip assembler-generated symbols during link”.

Després de compilar obtindràs un binari vmlinux “not stripped”, que és el que utilitzaràs des de gdb. A més, necessites un initramfs bàsic, que pots generar amb una ordre tipus:

comando: mkinitramfs -o ramdisk.img

Després arrenques QEMU amb paràmetres de depuració. Un exemple típic inclou lopció -gdb tcp::1234 per obrir un endpoint remot compatible amb gdb, i -S perquè la màquina virtual arrenqui pausada des del principi. També indiques el kernel amb -kernel vmlinux, el -initrd ramdisk.img, la memòria amb -m 512 i sols redirigir la consola a ttyS0 per manejar tot des del terminal.

  Com actualitzar Edge a la darrera versió a Windows 11: guia completa pas a pas

Amb QEMU detingut esperant gdb, des de la màquina host arranques gdb apuntant a vmlinux i connectes amb target remote localhost:1234. A partir d'aquí pots posar primerencs breakpoints, per exemple un hb start_kernel, i controlar l'execució amb ordres com c (continuar) i CTRL+C per pausar de nou.

Canvis recents i matisos a gdb i gdbserver

En distribucions modernes com Red Hat Enterprise Linux 8 hi ha una sèrie de canvis en gdb i gdbserver que convé tenir al cap, sobretot si vens de versions anteriors o tens scripts que analitzen la sortida del depurador.

D'una banda, gdbserver arrenca ara els processos “inferiors” usant un shell, igual que fa gdb, el que permet expansió de variables i substitucions a la línia d'ordres. Si per qualsevol motiu necessites desactivar aquest comportament, hi ha ajustaments específics documentats a la versió de RHEL 8 per tornar al mode anterior.

S'han eliminat o canviat també diverses coses: el suport de depuració per a programes Java compilats amb gcj, el mode de compatibilitat HP-UX XDB, comandes com set remotebaud (substituïts per set serial baud) o la compatibilitat amb cert format antic de stabs. A més, la numeració de fils ja no és global, sinó per “inferior”, i apareix com inferior_num.thread_num, amb variables de conveniència noves com $_gthread per referir-se a l'identificador global.

Una altra novetat rellevant és l'ajust max-value-size, que limita la quantitat de memòria que el gdb pot reservar per mostrar el contingut d'un valor. Per defecte són 64 KiB, de manera que intents d'imprimir arrays enormes o estructures mastodòntiques poden donar com a resultat un avís de “valor massa gran” en lloc d'escopir tota la memòria a la pantalla.

També s'ha ajustat com maneja gdb el sysroot. Ara el valor per defecte és target:, el que significa que per a processos remots intentarà primer buscar biblioteques i símbols al sistema de destinació. Si vols que prioritzi els símbols locals, convé executar set sysroot amb la ruta que us interessa abans de fer target remote.

Pel que fa a l'historial de comandes, la variable d'entorn utilitzada ara és GDBHISTSIZE en lloc de HISTSIZE, de manera que pots afinar quant de temps vols que es conservin les ordres que has anat teclejant en sessions de depuració sense interferir amb el comportament de la resta d'aplicacions que usen la llibreria de lectura de línia.

Consells de flux de treball i resolució de problemes amb gdbserver

Amb vista a tenir un flux de treball còmode, hi ha alguns patrons que solen funcionar molt bé quan desenvolupes per a sistemes encastats o servidors remots. El primer és automatitzar al màxim la compilació amb símbols i el desplegament del binari al target, de manera que sempre sàpigues quina versió de l'executable s'està corrent i tinguis la còpia amb símbols a mà al host.

En entorns amb molts nuclis de crash, val la pena aprendre a fer servir gdb en mode batch, amb flags com --batch, --ex y -x per llançar ordres automàticament sobre una llista de cors i processar els seus backtraces des de scripts (per exemple a Pitó). Així pots filtrar ràpidament problemes repetits, agrupar errors per stack trace, etc.

Quan alguna cosa va malament amb la connexió remota, l'opció --debug de gdbserver és la teva millor amiga. Si arrenques, per exemple, un servidor de processos amb:

comando: gdbserver --debug --multi localhost:1234

La consola de gdbserver mostrarà traces detallades del que està passant a nivell del protocol remot, paquets que arriben, errors de format, problemes de desconnexió, etc. Això és molt útil quan el teu gdb es desconnecta de sobte, un procés es mor només posar un breakpoint o el teu GUI de depuració envia una cosa que gdbserver no entén bé.

En contextos com el d'un router TP-Link on adjunteu gdbserver a un procés crític com httpd, és relativament comú que en posar certs punts d'interrupció es produeixin condicions de carrera o watchdogs que matin el procés quan es queda “aturat” massa temps al depurador. En aquestes situacions pot ser necessari ajustar quins senyals s'aturen, quins fils es controlen i, si n'hi ha, tocar la configuració del propi sistema (temps de timeout, watchdogs de maquinari) per permetre sessions de depuració més llargues.

Usar gdbserver bé suposa combinar diverses peces: compilar amb símbols adequats, triar el gdb correcte per a l'arquitectura, configurar rutes de símbols i fonts, entendre les dues maneres principals de gdbserver (procés únic i multi) i no tenir por de tirar de la manera --debug quan la connexió no es comporta com esperes. Amb aquesta base, depurar des del teu PC aplicacions que corren en un Linux remot, un router o una màquina virtual amb kernel personalitzat es converteix en una cosa força rutinari i, sobretot, tremendament útil.