Hur man använder gdbserver för fjärrfelsökning på Linux

Senaste uppdateringen: 14/01/2026
Författare: Isaac
  • gdbserver fungerar som en fjärragent för GDB för att styra processer på en annan maskin via TCP eller seriell kod.
  • För att felsöka på distans är det viktigt att kompilera med symbolerAnvänd lämplig gdb och konfigurera sökvägar för symboler och teckensnitt korrekt.
  • gdbserver erbjuder enprocessläge och flerprocessläge, och integrerar även med WinDbg och QEMU för kärnfelsökning.
  • Alternativ som --debug, sysroot och value size limits hjälper till att diagnostisera problem och stabilisera sessioner.

Fjärrfelsökning med gdbserver

Om du programmerar i C eller C++ Linux och du har aldrig rört gdbserverDu går miste om ett av de mest användbara verktygen för att felsöka processer på distans, oavsett om det är på en server, ett inbäddat system eller till och med i en virtuell maskin eller WSL. Långt ifrån att vara något "magiskt" eller reserverat för experter, är gdbserver helt enkelt ett litet program som kommunicerar med gdb och styr körningen av målprocessen.

Huvudidén är mycket enkel.: på maskinen där den binärfil du vill felsöka körs (den mål) du startar gdbserver; på din arbetsdator (den värdDu startar gdb eller till och med WinDbg med stöd för gdb-protokollet. Båda ansluter via TCP eller en seriell port, och därifrån kan du sätta brytpunkter, inspektera variabler, visa stacken eller följa exekveringen steg för steg som om programmet kördes på din egen maskin.

Vad är gdbserver och när är det vettigt att använda det?

Vad är gdbserver?

gdbserver är en fjärrfelsöknings-"agent" för GNU gdbDess funktion är mycket specifik: den körs på den maskin där programmet som ska analyseras körs, styr den processen (eller processerna) och kommunicerar med en gdb-klient som finns på en annan maskin (eller på samma) via en fjärranslutning.

I dagligt bruk används gdbserver i två typiska scenarierFelsökningsprogramvara som körs i inbäddade miljöer (routrar, kort med avskalad Linux, enheter) IoTetc.) och felsöka processer på fjärranslutna Linux-maskiner, där det inte är bekvämt eller helt enkelt inte möjligt att ha en "fet" gdb med alla bibliotek och symboler.

På en praktisk nivå hanterar gdbserver uppgifter som Läsa och skriva processregister och minne, kontrollera exekvering (fortsätta, pausa, stega igenom), hantera brytpunkter och skicka all denna data till gdb med hjälp av GDB-fjärrprotokollet. Denna filosofi är mycket lik den hos verktyg som OpenOCD, som fungerar som en brygga mellan gdb och en hårdvara extern, med skillnaden att gdbserver körs på samma system som binärfilen körs.

Om du kommer från miljöer Windows Det är också intressant att veta Felsökare som WinDbg kan kommunicera med en gdbserver på Linux, så du kan felsöka användarprocesser på Linux från WinDbg med hjälp av stödet för fjärrfelsökning via gdb-protokollet som Microsoft har införlivat i senare versioner.

Grundläggande krav för felsökning med gdb och gdbserver

Krav för att använda gdbserver

Innan du börjar felsöka på distans måste du förstå värd/mål-relationen.. Den mål Det är maskinen där programmet som ska felsökas körs och där gdbserver kommer att köras; värd Det här är maskinen från vilken du ska köra gdb (eller WinDbg) och där du kommer att ha källkoden och, helst, felsökningssymbolerna.

Den viktigaste utgångspunkten är att kompilera binärfilen med symbolerI GCC eller g++ uppnås detta med flaggan -goch det är vanligtvis lämpligt att även inaktivera optimeringar (till exempel med -O0Detta gör att felsökaren kan visa variabler, makron och kodstruktur mer exakt. För specifika makron kan du använda högre felsökningsnivåer, till exempel -g3.

På värdsidan behöver du en kompatibel version av gdb med målarkitekturen. För att felsöka ett MIPS-, ARM- eller annan arkitekturbaserad inbäddad system måste du använda gdb:n för motsvarande verktygskedja (till exempel) arm-none-eabi-gdb o gdb-multiarch) och, om nödvändigt, konfigurera arkitekturen och endianness med kommandon som set arch y set endian.

Angående anslutningen stöder gdbserver två huvudtyperEn seriell länk (mycket vanligt i inbyggd hårdvara, via UART) och TCP/IP, vilket är mest praktiskt när målet är på samma nätverk eller är en Linux-maskin tillgänglig över nätverket. I båda fallen används kommandot från gdb. target remote för att ansluta till slutpunkten som exponerats av gdbserver.

Sätt att starta gdbserver: enkelprocess- och flerprocessläge

gdbserver-körningslägen

gdbserver kan fungera på två huvudsakliga sätt När vi pratar om felsökning i användarläge: direkt associerad med en enskild process eller som en "processerver" som tillåter listning och anslutning till olika systemprocesser.

I enprocessläge Du startar gdbserver och anger host:port och det program som ska köras. I ett enkelt exempel på en Linux-skrivbordsdator kan du göra något liknande:

kommando: gdbserver localhost:3333 foo

Med det kommandot startar gdbserver binärfilen. foo och han fortsätter att lyssna på port 3333Tills en fjärransluten gdb ansluter förblir programmet stoppat; när gdb ansluter till target remote localhost:3333, processen börjar styras av avkrustaren.

I flerprocessläge (processerver) används alternativet --multiI det här fallet startar inte gdbserver direkt något program, utan lyssnar helt enkelt efter inkommande anslutningar och låter klienten (gdb eller WinDbg) hantera vilken process som ska skapas eller anslutas till:

  Google lanserar Gemini Code Assist: den kostnadsfria AI-drivna programmeringsassistenten

kommando: gdbserver --multi localhost:1234

När man arbetar med WinDbg på Linux är detta multiläge särskilt intressant.För från WinDbg kan du lista processer på fjärrsystemet, se PID, användare och kommandorad, och koppla till den du är intresserad av, på ett liknande sätt som det görs med processervern. dbgsrv.exe på Windows.

Fjärrfelsökning med gdbserver och gdb steg för steg

Låt oss förenkla detta med ett mycket typiskt exempel.Felsök en enkel applikation på samma maskin (värd och mål matchar) med hjälp av gdbserver för att simulera fjärrscenariot.

Först skriver och kompilerar du ett litet programTill exempel, en fånig loop som skriver ut en räknare:

kommando: gcc -g foo.c -o foo

Nyckeln här är flaggan -gDetta lägger till nödvändig felsökningsinformation till binärfilen så att gdb kan visa kodrader, variabelnamn, typer etc. I en "riktig" korskompileringsmiljö skulle du göra denna kompilering med cross-toolchain och sedan kopiera både binärfilen och dess beroenden till målet.

Nästa steg är att starta gdbserver på måletOm värd och mål är samma maskin, då:

kommando: gdbserver localhost:3333 foo

Du kommer att se ett meddelande som liknar ”Process foo created; pid = XXXX; Listening on port 3333”. Detta indikerar att gdbserver har skapat processen och väntar på att gdb ska ansluta. Om du använder ett system där fler behörigheter krävs (till exempel för att ansluta till systemprocesser) kan du behöva köra kommandot med sudoMen det är alltid klokt att vara försiktig när man beviljar tillstånd. rot till avsvavlaren.

På värden startar du gdb genom att ange den lokala körbara filen (samma som körs på målet, eller en identisk kopia med symboler):

kommando: gdb foo

Väl inne i gdb upprättar du fjärranslutningen med:

kommando: target remote localhost:3333

Vid den tidpunkten laddar gdb symbolerna från den lokala binärfilen.Den synkroniserar med gdbserver och tar kontroll över processen som faktiskt körs under gdbserver. Därifrån är flödet det vanliga: kommandon som break att sätta brytpunkter, continue, step, next, print att inspektera variabler, backtrace för att se batteriet osv.

Ansluta till körande processer med gdbserver

Du vill inte alltid starta programmet från grunden.Ofta är du intresserad av att delta i en process som redan pågår (till exempel en httpd en routeren systemdaemon eller en produktionstjänst).

Det typiska mönstret är att använda alternativet --attach från gdbserverskickar porten där den ska lyssna och PID för målprocessen. Till exempel, på en router där du har kopierat en gdbserver kompilerad för dess arkitektur, kan du göra:

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

På värdsidan kommer du att använda en version av gdb som stöder routerns arkitektur., till exempel gdb-multiarchkonfigurera arkitekturen och endianness i förväg:

kommando: set arch mips
set endian big

Sedan anger du den lokala filen som innehåller symbolerna. av den fjärrbinära filen (till exempel file httpd) och, om nödvändigt, berättar du för gdb var binärfilen faktiskt körs på målet med set remote exec-file /usr/bin/httpdSlutligen, precis som tidigare, ansluter du till:

kommando: target remote 192.168.0.1:3333

När den väl är fästDu kan ställa in brytpunkter för specifika funktioner (till exempel break checkFirmware), fortsätta körningen och låt programmets normala flöde (till exempel uppladdning av firmware från webbgränssnittet) utlösa brytpunkten.

Använda gdbserver med WinDbg på Linux

Under senare år har Microsoft lagt till stöd för felsökning av Linux-processer i WinDbg. Använder gdbserver som backend. Den här funktionen är avsedd för scenarier där du arbetar i Windows men koden körs på Linux (inklusive WSL).

För att felsöka en specifik Linux-process med WinDbg med hjälp av gdbserverFlödet skulle se ut ungefär så här: först lokaliserar du målprocessen på Linux-maskinen med ett kommando som ps -A (till exempel en python3 som körs), sedan startar du gdbserver på målet:

kommando: gdbserver localhost:1234 python3

Om miljön kräver det kan du behöva använda sudo gdbserver ...med samma säkerhetsåtgärder som alltid. När gdbserver indikerar att den "Lyssnar på port 1234", gå till "Arkiv / Anslut till fjärrfelsökare" i WinDbg och ange en anslutningssträng av följande typ:

kommando: gdb:server=localhost,port=1234

WinDbg använder en liten gdb-protokolldrivrutin för att kommunicera med gdbserver. och när anslutningen väl är upprättad förblir den stoppad vid den punkt där boot av processen. Därifrån kan du använda dess stackfönster, moduler, minne, brytpunkter, såväl som kommandon som k för att se batteriet eller lm för att lista moduler (med tanke på att vissa kommandon förväntar sig PE-format och inte ELF, så de kan visa konstig data i vissa fall).

gdbserver och WinDbg-processerver

Förutom fallet med en enda process kan WinDbg ansluta till en gdbserver som fungerar som en processserver. att fungera mer likt hur det fungerar med fjärrstyrda Windows-processer. I det här läget startas gdbserver med --multi och utan en associerad process:

  Det bästa sättet att aktivera lågenergiläge på iPhone

kommando: sudo gdbserver --multi localhost:1234

Från WinDbg, välj "Arkiv / Anslut till processerver" och du återanvänder anslutningssträngen gdb:server=localhost,port=1234När anslutningen är aktiv kan du lista tillgängliga Linux-processer och koppla till den du vill ha eller till och med starta en ny process.

En subtil detalj måste man ha i åtanke.WinDbg skiljer mellan "processerver" och "enkelt mål" beroende på om gdbserver redan är ansluten till en process när den ansluter. Om du lämnade gdbserver ansluten till en process, stängde WinDbg och sedan försökte återansluta, kanske den inte upptäcks som en processerver och du kan behöva starta om gdbserver.

Så här avslutar du en processserversessionVanligtvis räcker det med att helt enkelt trycka CTRL+D i konsolen där gdbserver körs och stoppa felsökningen från WinDbg. I vissa extrema fall, om det finns synkroniseringsproblem, kan det vara nödvändigt att stänga felsökaren helt och starta om gdbserver från början.

Symbol- och källkodshantering vid fjärrfelsökning

En av nycklarna till att göra fjärrfelsökning bekväm är att ha symbol- och teckensnittsdelen väl upplöst.Utan symboler blir det tortyr att navigera i stacken eller sätta brytpunkter för specifika funktioner.

I klassiska gdb + gdbserver-scenarier är det idealiskt att behålla en kopia av den körbara filen med symboler på värden. (ostrippad) och källkodsträdet. gdb kräver inte att den fjärrbinära filen innehåller symbolerna; det räcker att den lokala filen du laddar med file matcha den fjärrkörbara filen på offset-nivå.

I WinDbg- och Linux-felsökningens värld har även tjänster som DebugInfoD dykt upp.som exponerar symboler och teckensnitt över HTTP. WinDbg kan använda speciella sökvägar av typen DebugInfoD*https://debuginfod.elfutils.org båda i .sympath som i .srcpath för att ladda ner DWARF-symboler och källkod för Linux ELF-binärer på begäran.

I ett specifikt exempel med WSL, där användarkoden finns under C:\Users\Bob\Du kan säga till WinDbg:

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

Och om du också vill använda DebugInfoD för systembinärfiler:

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

Med den här konfigurationen, när du inspekterar stacken eller anger libc-funktionerWinDbg kan försöka ladda ner motsvarande DWARF-symboler och, om servern också exponerar koden, visa källkoden i stor detalj, även om Windows-verktygskedjan internt inte hanterar ELF och DWARF lika "nativt" som PE och PDB.

Praktiskt exempel: felsökning av ett C++-program med gdbserver och WinDbg

Ett illustrativt exempel är ett litet C++-program som skriver en hälsning till skärmen., kompilerad i WSL med felsökningssymboler. Tänk dig ett program som reserverar en std::array<wchar_t, 50> och kopierar ett längre meddelande till det, vilket gör att texten avkortas och tecken visas ???? i slutet

Efter att ha kompilerat med något liknande:

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

Du startar gdbserver mot den binärfilen:

kommando: gdbserver localhost:1234 DisplayGreeting

I WinDbg ansluter du med strängen gdb:server=localhost,port=1234 Och när sessionen är upprättad och symbol- och teckensnittssökvägar är konfigurerade, anger du en brytpunkt i DisplayGreeting!maindu kan använda dx greeting för att inspektera den lokala arrayen och se dess storlek (50 positioner), och visuellt kontrollera i minnesfliken eller i variabelvyn hur hälsningen avbryts.

Det fina med detta exempel är att det visar att även utan fullt stöd för alla ELF/DWARF-format i WinDbgDu kan navigera stackar, inspektera typer, ställa in brytpunkter efter funktionsnamn och navigera genom C++-kod relativt bekvämt med hjälp av gdbserver som en fjärrstyrd backend.

Felsöka Linuxkärnan med qemu och gdb

gdbserver används inte bara i användarläge; det finns också mycket kraftfulla scenarier i kernelläge.särskilt när man kombinerar QEMU med felsökningsstöd. Även om rollen som "gdbserver" här uppfylls av QEMUs eget alternativ, är tillvägagångssättet identiskt: ena änden kör systemet som ska felsökas och öppnar en gdb-port; den andra änden är antingen gdb eller en felsökare som talar fjärrprotokollet.

För att felsöka kärnan måste du kompilera den med specifika felsökningsalternativ.aktivera generering av felsökningsinformation (CONFIG_DEBUG_INFO), GDB-kärnskripten (CONFIG_GDB_SCRIPTS) och kärnans eget felsökningsläge (CONFIG_DEBUG_KERNELDet är också viktigt att inaktivera alternativ som tar bort symboler under länkning, till exempel "Ta bort assemblergenererade symboler under länkning".

Efter kompilering får du en binär fil vmlinux "inte avskalad"vilket är den du kommer att använda från gdb. Du behöver också en grundläggande initramfs, som du kan generera med ett kommando som:

kommando: mkinitramfs -o ramdisk.img

Sedan startar du QEMU med felsökningsparametrarEtt typiskt exempel inkluderar alternativet -gdb tcp::1234 för att öppna en gdb-kompatibel fjärrslutpunkt, och -S så att den virtuella maskinen börjar pausad från början. Du anger också kärnan med -kernel vmlinux, The -initrd ramdisk.img, minnet med -m 512 och du omdirigerar vanligtvis konsolen till ttyS0 att hantera allt från terminala.

  Så här uppdaterar du Edge till den senaste versionen på Windows 11: en komplett steg-för-steg-guide

Med QEMU frihetsberövad i väntan på gdbFrån värdmaskinen börjar du med att gdb pekar mot vmlinux och du ansluter till target remote localhost:1234Därifrån kan du ställa in tidiga brytpunkter, till exempel en hb start_kerneloch styra körningen med kommandon som c (fortsätt) och CTRL+C för att pausa igen.

Senaste ändringar och nyanser i gdb och gdbserver

I moderna distributioner som Red Hat Enterprise Linux 8 finns det ett antal förändringar i gdb och gdbserver som är värda att ha i åtanke.särskilt om du kommer från tidigare versioner eller har skript som analyserar felsökarens utdata.

Å ena sidan startar gdbserver nu de "lägre" processerna med hjälp av ett skalPrecis som med gdb tillåter detta variabelexpansion och substitutioner på kommandoraden. Om du av någon anledning behöver inaktivera detta beteende finns det specifika inställningar dokumenterade i RHEL 8 för att återgå till föregående läge.

Flera saker har också tagits bort eller ändratsfelsökningsstöd för Java-program kompilerade med gcj, HP-UX XDB-kompatibilitetsläget, kommandon som set remotebaud (ersatt av set serial baud) eller kompatibilitet med ett visst äldre format av stabsDessutom är trådnumreringen inte längre global, utan efter "nedre" tråd, och visas som inferior_num.thread_num, med nya bekvämlighetsvariabler som $_gthread att referera till den globala identifieraren.

En annan relevant ny funktion är justeringen max-value-sizeDetta begränsar mängden minne som gdb kan allokera för att visa innehållet i ett värde. Standardvärdet är 64 KiB, så försök att skriva ut stora matriser eller massiva strukturer kan resultera i en varning om "värdet är för stort" istället för att visa allt tillgängligt minne.

Det har också justerats hur gdb hanterar sysrootStandardvärdet är nu target:Det betyder att för fjärrprocesser kommer den först att försöka hitta bibliotek och symboler på målsystemet. Om du vill att den ska prioritera lokala symboler bör du köra set sysroot med den rutt som intresserar dig innan du gör det target remote.

Angående kommandohistoriken är den miljövariabel som nu används GDBHISTSIZE istället för HISTSIZEDetta låter dig finjustera hur länge du vill behålla kommandon du har skrivit i felsökningssessioner utan att störa beteendet hos andra program som använder radläsningsbiblioteket.

Arbetsflödestips och felsökning med gdbserver

För att ha ett bekvämt arbetsflöde finns det några mönster som tenderar att fungera mycket bra. Vid utveckling för inbyggda system eller fjärrservrar är det första steget att automatisera symbolkompilering och binärdistribution till målet så mycket som möjligt. På så sätt vet du alltid vilken version av den körbara filen som körs och har symbolkopian lätt tillgänglig på värden.

I miljöer med många kraschkärnor är det värt att lära sig hur man använder gdb i batchläge., med flaggor som --batch, --ex y -x att automatiskt starta kommandon på en lista med kärnor och bearbeta deras bakåtspårningar från skript (till exempel i PythonDetta gör att du snabbt kan filtrera bort upprepade problem, gruppera fel efter stackspårning etc.

När något går fel med fjärranslutningen visas alternativet --debug gdbserver är din bästa vänOm du till exempel startar en processerver med:

kommando: gdbserver --debug --multi localhost:1234

gdbserver-konsolen visar detaljerade spår av vad som händer På fjärrprotokollnivå inkluderar detta inkommande paket, formateringsfel, frånkopplingsproblem etc. Detta är mycket användbart när din gdb-server plötsligt kopplas bort, en process kraschar så fort en brytpunkt är inställd, eller ditt felsökningsgränssnitt skickar något som gdbserver inte förstår.

I sammanhang som en TP-Link-router där du ansluter gdbserver till en kritisk process som httpdDet är relativt vanligt att vissa brytpunkter skapar kappvillkor eller watchdogs som stoppar processen när den "fastnar" för länge i felsökaren. I dessa situationer kan det vara nödvändigt att justera vilka signaler som blockeras, vilka trådar som styrs och, om tillämpligt, modifiera själva systemkonfigurationen (timeout-tider, hårdvaru-watchdogs) för att möjliggöra längre felsökningssessioner.

Att använda gdbserver på ett bra sätt innebär att kombinera flera delarKompilera med lämpliga symboler, välj rätt gdb för arkitekturen, konfigurera symbol- och källsökvägar, förstå de två huvudlägena för gdbserver (enkelprocess och flerprocess), och var inte rädd för att dra från läget. --debug när anslutningen inte beter sig som förväntat. Med den grunden blir felsökning av applikationer som körs på ett fjärrsystem i Linux, en router eller en virtuell maskin med en anpassad kärna från din dator ganska rutinmässig och framför allt otroligt användbar.