- gdbserver funguje jako vzdálený agent GDB pro řízení procesů na jiném počítači přes TCP nebo sériové rozhraní.
- Pro vzdálené ladění je klíčové kompilovat s symbolyPoužijte vhodnou gdb a správně nakonfigurujte cesty k symbolům a písmům.
- gdbserver nabízí jednoprocesový i víceprocesový režim a také se integruje s WinDbg a QEMU pro ladění jádra.
- Možnosti jako --debug, sysroot a limity velikosti hodnot pomáhají diagnostikovat problémy a stabilizovat relace.
Pokud programujete v jazyce C nebo C++ Linux a nikdy jsi se gdbserveru nedotklPřicházíte o jeden z nejužitečnějších nástrojů pro vzdálené ladění procesů, ať už na serveru, vestavěném systému nebo dokonce ve virtuálním počítači či WSL. gdbserver zdaleka není něco „magického“ nebo vyhrazeného pro experty, je to jednoduše malý program, který komunikuje s gdb a řídí provádění cílového procesu.
Klíčová myšlenka je velmi jednoduchá.: na počítači, kde běží binární soubor, který chcete ladit ( cíl) spustíte gdbserver; na svém pracovním počítači ( hostitelSpustíte gdb nebo dokonce WinDbg s podporou protokolu gdb. Oba se připojují přes TCP nebo sériový port a odtud můžete nastavovat zarážky, kontrolovat proměnné, prohlížet zásobník nebo sledovat provádění krok za krokem, jako by program běžel na vašem vlastním počítači.
Co je gdbserver a kdy má smysl ho používat?

gdbserver je „agent“ pro vzdálené ladění pro GNU gdbJeho funkce je velmi specifická: běží na počítači, kde běží analyzovaný program, řídí tento proces (nebo procesy) a komunikuje s klientem gdb umístěným na jiném počítači (nebo na stejném) prostřednictvím vzdáleného připojení.
V každodenním používání se gdbserver používá ve dvou typických scénářích.Ladicí software, který běží ve vestavěných prostředích (routery, desky s ořezaným Linuxem, zařízení) IoTatd.) a ladění procesů na vzdálených linuxových počítačích, kde není pohodlné nebo jednoduše není možné mít „tlustou“ gdb se všemi knihovnami a symboly.
V praxi gdbserver zvládá úkoly jako například Čtení a zápis do registrů procesů a paměti, řízení provádění (pokračování, pozastavení, krokování), správa zarážek a odesílání všech těchto dat do gdb pomocí vzdáleného protokolu GDB. Tato filozofie je velmi podobná filozofii nástrojů jako OpenOCD, které fungují jako most mezi gdb a... technické vybavení externí, s tím rozdílem, že gdbserver běží na stejném systému, kde běží binární soubor.
Pokud pocházíte z prostředí Windows Je také zajímavé vědět Debuggery jako WinDbg mohou komunikovat s gdbserverem v Linuxu, takže můžete ladit uživatelské procesy v Linuxu z WinDbg pomocí podpory vzdáleného ladění prostřednictvím protokolu gdb, který Microsoft začlenil do posledních verzí.
Základní požadavky pro ladění s gdb a gdbserver

Než začnete s laděním na dálku, musíte pochopit vztah hostitel/cíl.. cíl Je to počítač, na kterém běží laděný program a kde bude spuštěn gdbserver; hostitel Toto je počítač, ze kterého budete spouštět gdb (nebo WinDbg) a kde budete mít zdrojový kód a nejlépe i ladicí symboly.
Základním výchozím bodem je kompilace binárního souboru se symbolyV GCC nebo g++ se toho dosáhne pomocí příznaku -ga obvykle je vhodné také zakázat optimalizace (například pomocí -O0To umožňuje ladicímu programu přesněji zobrazit proměnné, makra a strukturu kódu. Pro specifická makra můžete použít vyšší úrovně ladění, například -g3.
Na straně hostitele budete potřebovat kompatibilní verzi gdb. s cílovou architekturou. Pro ladění vestavěného systému s architekturou MIPS, ARM nebo jinou je nutné použít gdb odpovídajícího cross-toolchainu (například) arm-none-eabi-gdb o gdb-multiarch) a v případě potřeby nakonfigurujte architekturu a endianness pomocí příkazy jak set arch y set endian.
Pokud jde o připojení, gdbserver podporuje dva hlavní typySériové připojení (velmi běžné u embedded hardwaru, přes UART) a TCP/IP, což je nejpohodlnější, když je cíl ve stejné síti nebo se jedná o počítač s Linuxem přístupný přes síť. V obou případech se příkaz používá z gdb. target remote pro připojení ke koncovému bodu zpřístupněnému gdbserverem.
Způsoby spuštění gdbserveru: režim jednoho procesu a více procesů

gdbserver může fungovat dvěma hlavními způsoby Když mluvíme o ladění v uživatelském režimu: přímo spojené s jedním procesem nebo jako „procesový server“, který umožňuje výpis a připojení k různým systémovým procesům.
V režimu jednoho procesu Spustíte gdbserver, zadáte host:port a program, který se má spustit. V jednoduchém příkladu na desktopovém počítači s Linuxem byste mohli udělat něco jako toto:
Příkaz: gdbserver localhost:3333 foo
Tímto příkazem gdbserver spustí binární soubor. foo a on poslouchá na portu 3333Dokud se nepřipojí vzdálená gdb, program zůstane zastavený; když se gdb připojí k target remote localhost:3333, proces začíná být řízen descrusherem.
V multiprocesovém režimu (procesový server) se tato možnost používá --multiV tomto případě gdbserver přímo nespustí žádný program, ale pouze naslouchá příchozím připojením a umožňuje klientovi (gdb nebo WinDbg) spravovat, který proces vytvořit nebo ke kterému se připojit:
Příkaz: gdbserver --multi localhost:1234
Při práci s WinDbg v Linuxu je tento multimód obzvláště zajímavý.Protože ze samotného WinDbg můžete zobrazit seznam procesů na vzdáleném systému, zobrazit PID, uživatele a příkazový řádek a připojit se k tomu, který vás zajímá, podobným způsobem, jako se to dělá s procesním serverem. dbgsrv.exe na Windows.
Vzdálené ladění pomocí gdbserver a gdb krok za krokem
Pojďme si to přiblížit na velmi typickém příkladu.Ladění jednoduché aplikace na stejném počítači (hostitel a cíl se shodují) pomocí gdbserver k simulaci vzdáleného scénáře.
Nejprve napíšete a zkompilujete malý programNapříklad hloupá smyčka, která vypíše čítač:
Příkaz: gcc -g foo.c -o foo
Klíčem je zde vlajka -gTím se do binárního souboru přidají potřebné ladicí informace, aby gdb mohl zobrazit řádky kódu, názvy proměnných, typy atd. V „skutečném“ prostředí křížové kompilace byste tuto kompilaci provedli s cross-toolchainem a poté byste zkopírovali binární soubor i jeho závislosti do cíle.
Dalším krokem je spuštění gdbserveru na cílovém serveru.Pokud jsou hostitelský a cílový počítač stejný, pak:
Příkaz: gdbserver localhost:3333 foo
Zobrazí se vám zpráva podobná té „Proces foo vytvořen; pid = XXXX; Naslouchá na portu 3333“. To znamená, že gdbserver vytvořil proces a čeká na připojení gdb. Pokud se nacházíte v systému, kde jsou vyžadována další oprávnění (například pro připojení k systémovým procesům), může být nutné spustit příkaz s sudoAle při udělování povolení je vždy moudré být opatrný. kořen do odsiřovače.
Na hostiteli spustíte gdb s uvedením lokálního spustitelného souboru (stejný, který běží na cíli, nebo identická kopie se symboly):
Příkaz: gdb foo
Jakmile jste uvnitř gdb, navážete vzdálené připojení pomocí:
Příkaz: target remote localhost:3333
V tomto okamžiku gdb načte symboly z lokálního binárního souboru.Synchronizuje se s gdbserverem a přebírá kontrolu nad procesem, který ve skutečnosti běží pod gdbserverem. Odtud je postup obvyklý: příkazy jako break stanovit body zlomu, continue, step, next, print kontrolovat proměnné, backtrace vidět baterii atd.
Připojení k spuštěným procesům pomocí gdbserveru
Ne vždycky chcete program spouštět od nuly.Často máte zájem zapojit se do procesu, který již probíhá (například httpd ale tzv. routersystémový démon nebo produkční služba).
Typickým postupem je použití možnosti --attach z gdbserverupředáním portu, na kterém bude naslouchat, a PID cílového procesu. Například na routeru, kam jste zkopírovali gdbserver zkompilovaný pro jeho architekturu, byste mohli udělat:
Příkaz: gdbserver localhost:3333 --attach <pid_de_httpd>
Na straně hostitele budete používat verzi gdb, která podporuje architekturu routeru.například gdb-multiarchpředem nakonfigurujte architekturu a endianness:
Příkaz: set arch mips
set endian big
Pak zadáte lokální soubor, který obsahuje symboly. vzdáleného binárního souboru (například file httpd) a v případě potřeby sdělíte gdb, kde binární soubor na cíli skutečně běží pomocí set remote exec-file /usr/bin/httpdNakonec, stejně jako předtím, se spojíte s:
Příkaz: target remote 192.168.0.1:3333
Po připojeníZarážky můžete nastavit na konkrétních funkcích (například break checkFirmware), pokračovat v provádění a nechat normální tok programu (například nahrávání firmwaru z webového rozhraní) spustit zarážku.
Používání gdbserveru s WinDbg v Linuxu
V posledních letech společnost Microsoft přidala podporu pro ladění linuxových procesů ve WinDbg. Použití gdbserveru jako backendu. Tato funkce je určena pro scénáře, kde pracujete ve Windows, ale kód běží na Linuxu (včetně WSL).
Ladění konkrétního linuxového procesu pomocí WinDbg a gdbserveruPostup by byl nějak takový: nejprve vyhledáte cílový proces na počítači s Linuxem pomocí příkazu jako ps -A (například python3 (který běží), pak spustíte gdbserver na cíli:
Příkaz: gdbserver localhost:1234 python3
Pokud to prostředí vyžaduje, může být nutné použít sudo gdbserver ...se stejnými bezpečnostními opatřeními jako vždy. Jakmile gdbserver indikuje, že „Naslouchá na portu 1234“, přejděte ve WinDbg do „Soubor / Připojit ke vzdálenému debuggeru“ a zadejte připojovací řetězec následujícího typu:
Příkaz: gdb:server=localhost,port=1234
WinDbg používá malý ovladač protokolu gdb pro komunikaci s gdbserverem. a jakmile je spojení navázáno, zůstane zastaveno v bodě bota procesu. Odtud můžete použít jeho okna zásobníku, moduly, paměť, zarážky a také příkazy jako k vidět baterii nebo lm pro výpis modulů (s ohledem na to, že některé příkazy očekávají formát PE a nikoli ELF, takže v určitých případech mohou zobrazovat podivná data).
gdbserver a procesní server WinDbg
Kromě případu s jedním procesem se WinDbg může připojit k gdbserveru, který funguje jako procesní server. aby fungoval podobněji, jako když pracuje se vzdálenými procesy Windows. V tomto režimu se gdbserver spouští pomocí --multi a bez přidruženého procesu:
Příkaz: sudo gdbserver --multi localhost:1234
Ve WinDbg vyberte „Soubor / Připojit k procesnímu serveru“ a znovu použijete připojovací řetězec gdb:server=localhost,port=1234Když je připojení aktivní, můžete zobrazit seznam dostupných procesů Linuxu a připojit se k požadovanému, nebo dokonce spustit nový proces.
Je třeba mít na paměti jeden jemný detail.WinDbg rozlišuje mezi „procesovým serverem“ a „jediným cílem“ v závislosti na tom, zda je gdbserver již připojen k procesu v okamžiku připojení. Pokud jste nechali gdbserver připojený k procesu, zavřeli WinDbg a poté se pokusili znovu připojit, nemusí být detekován jako procesový server a může být nutné gdbserver restartovat.
Ukončení relace procesního serveruObvykle stačí stisknout CTRL+D v konzoli, kde běží gdbserver, a zastavit ladění z WinDbg. V některých extrémních případech, pokud se vyskytnou problémy se synchronizací, může být nutné ladicí program úplně zavřít a gdbserver restartovat od začátku.
Správa symbolů a zdrojového kódu při vzdáleném ladění
Jedním z klíčů k pohodlnému vzdálenému ladění je dobře rozlišené symboly a písma.Bez symbolů se navigace v zásobníku nebo nastavování zarážek u konkrétních funkcí stává mučením.
V klasických scénářích gdb + gdbserver je ideální uchovávat kopii spustitelného souboru se symboly na hostiteli. (neodebrán) a strom zdrojového kódu. gdb nevyžaduje, aby vzdálený binární soubor obsahoval symboly; stačí, aby lokální soubor, který načítáte pomocí file shoduje se vzdáleným spustitelným souborem na úrovni offsetu.
Ve světě ladění WinDbg a Linuxu se objevily také služby jako DebugInfoD.které zpřístupňují symboly a fonty přes HTTP. WinDbg může používat speciální cesty typu DebugInfoD*https://debuginfod.elfutils.org oba .sympath jako v .srcpath ke stažení zdrojového kódu symbolů DWARF a binárních souborů ELF pro Linux na vyžádání.
V konkrétním příkladu s WSL, kde je uživatelský kód pod C:\Users\Bob\Můžete říct WinDbg:
Příkaz: .sympath C:\Users\Bob\
.srcpath C:\Users\Bob\
A pokud chcete také použít DebugInfoD pro systémové binární soubory:
Příkaz: .sympath+ DebugInfoD*https://debuginfod.elfutils.org
.srcpath+ DebugInfoD*https://debuginfod.elfutils.org
S touto konfigurací, když prohlížíte zásobník nebo zadáváte funkce libcWinDbg se může pokusit stáhnout odpovídající symboly DWARF a pokud server také zpřístupní kód, zobrazit zdrojový kód s dostatečnými detaily, ačkoli interně nástrojová sada Windows nezpracovává ELF a DWARF tak „nativně“ jako PE a PDB.
Praktický příklad: ladění programu v C++ pomocí gdbserver a WinDbg
Ilustrativním příkladem je malá aplikace v C++, která vypíše pozdrav na obrazovku., zkompilovaný v WSL s ladicími symboly. Představte si program, který si rezervuje std::array<wchar_t, 50> a zkopíruje do něj delší zprávu, což způsobí zkrácení textu a zobrazení znaků ???? na konci
Po kompilaci s něčím podobným:
Příkaz: g++ DisplayGreeting.cpp -g -o DisplayGreeting
Spustíte gdbserver proti tomuto binárnímu souboru.:
Příkaz: gdbserver localhost:1234 DisplayGreeting
Ve WinDbg se připojíte k řetězci gdb:server=localhost,port=1234 A jakmile je relace navázána a cesty k symbolům a písmům jsou nakonfigurovány, nastavíte zarážku v DisplayGreeting!mainmůžete použít dx greeting prohlédnout si lokální pole a zjistit jeho velikost (50 pozic) a vizuálně zkontrolovat na kartě paměti nebo v zobrazení proměnných, jak je pozdrav oříznut.
Krása tohoto příkladu spočívá v tom, že ukazuje, že i bez plné podpory všech formátů ELF/DWARF ve WinDbgS gdbserverem jako vzdáleným backendem můžete poměrně pohodlně procházet zásobníky, kontrolovat typy, nastavovat zarážky podle názvu funkce a procházet kódem C++.
Ladění linuxového jádra pomocí qemu a gdb
gdbserver se nepoužívá pouze v uživatelském režimu; existují také velmi výkonné scénáře v režimu jádra.zejména když kombinujete QEMU s podporou ladění. Ačkoli zde roli „gdbserveru“ plní vlastní volba QEMU, přístup je identický: jeden konec spouští systém, který má být laděn, a otevírá port gdb; druhý konec je buď gdb, nebo debugger, který hovoří vzdáleným protokolem.
Pro ladění jádra je nutné jej zkompilovat se specifickými ladicími možnostmi.: aktivovat generování ladicích informací (CONFIG_DEBUG_INFO), skripty jádra GDB (CONFIG_GDB_SCRIPTS) a vlastní ladicí režim jádra (CONFIG_DEBUG_KERNELJe také důležité zakázat možnosti, které během linkování odstraňují symboly, například „Odstraňovat symboly generované assemblerem během linkování“.
Po kompilaci získáte binární soubor vmlinux „není svlékl“který použijete z gdb. Také budete potřebovat základní initramfs, který můžete vygenerovat příkazem jako:
Příkaz: mkinitramfs -o ramdisk.img
Pak spustíte QEMU s ladicími parametryTypický příklad zahrnuje možnost -gdb tcp::1234 otevřít vzdálený koncový bod kompatibilní s gdb a -S takže virtuální stroj se pozastaví od začátku. Také určíte jádro pomocí -kernel vmlinuxse -initrd ramdisk.img, paměť s -m 512 a obvykle přesměrujete konzoli na ttyS0 spravovat vše od terminál.
S QEMU zadrženou a čekající na gdbZ hostitelského počítače spustíte gdb ukazující na vmlinux a spojíte se s target remote localhost:1234Odtud můžete nastavit časné zarážky, například hb start_kernela řídit provádění pomocí příkazů, jako například c (pokračovat) a CTRL+C pro opětovné pozastavení.
Nedávné změny a nuance v gdb a gdbserver
V moderních distribucích, jako je Red Hat Enterprise Linux 8, existuje řada změn v gdb a gdbserver, které stojí za to mít na paměti.zvláště pokud používáte předchozí verze nebo máte skripty, které analyzují výstup ladicího programu.
Na jedné straně nyní gdbserver spouští „nižší“ procesy pomocí shelluStejně jako gdb umožňuje rozšiřování a substituce proměnných na příkazovém řádku. Pokud z jakéhokoli důvodu potřebujete toto chování zakázat, v RHEL 8 jsou zdokumentována specifická nastavení pro návrat do předchozího režimu.
Několik věcí bylo také odstraněno nebo změněno: podpora ladění programů v Javě kompilovaných s gcj, režim kompatibility HP-UX XDB, příkazy jako například set remotebaud (nahrazeno set serial baud) nebo kompatibilitu s určitým starším formátem stabsČíslování závitů navíc již není globální, ale podle „nižšího“ závitu, a zobrazuje se jako inferior_num.thread_nums novými proměnnými pro pohodlí, jako například $_gthread odkazovat na globální identifikátor.
Další důležitou novou funkcí je úprava max-value-sizeToto omezuje množství paměti, kterou může gdb alokovat k zobrazení obsahu hodnoty. Výchozí hodnota je 64 KiB, takže pokusy o výpis velkých polí nebo masivních struktur mohou vést k varování „hodnota je příliš velká“ namísto zobrazení veškeré dostupné paměti.
Také byl upraven způsob, jakým gdb zpracovává sysrootVýchozí hodnota je nyní target:To znamená, že u vzdálených procesů se nejprve pokusí najít knihovny a symboly v cílovém systému. Pokud chcete, aby upřednostňoval lokální symboly, měli byste spustit příkaz set sysroot s trasou, která vás zajímá, než se vydáte target remote.
Pokud jde o historii příkazů, nyní používaná proměnná prostředí je GDBHISTSIZE místo HISTSIZETo vám umožňuje jemně doladit, jak dlouho chcete uchovávat příkazy zadané v ladicích relacích, aniž byste ovlivnili chování ostatních aplikací, které používají knihovnu pro čtení řádků.
Tipy pro pracovní postupy a řešení problémů s gdbserverem
Pro pohodlný pracovní postup existují určité vzory, které obvykle fungují velmi dobře. Při vývoji pro vestavěné systémy nebo vzdálené servery je prvním krokem co nejvíce automatizovat kompilaci symbolů a nasazení binárních souborů na cíl. Tímto způsobem vždy víte, která verze spustitelného souboru běží, a máte kopii symbolů snadno dostupnou na hostiteli.
V prostředích s mnoha jádry způsobujícími pády se vyplatí naučit se používat gdb v dávkovém režimu.s vlajkami jako --batch, --ex y -x automaticky spouštět příkazy na seznamu jader a zpracovávat jejich zpětné trasy ze skriptů (například v PYTHONTo umožňuje rychle filtrovat opakované problémy, seskupovat selhání podle trasování zásobníku atd.
Pokud se něco pokazí se vzdáleným připojením, možnost --debug gdbserver je tvůj nejlepší přítelPokud například spustíte procesní server s:
Příkaz: gdbserver --debug --multi localhost:1234
Konzole gdbserveru zobrazí podrobné záznamy o tom, co se děje. Na úrovni vzdáleného protokolu to zahrnuje příchozí pakety, chyby formátování, problémy s odpojením atd. To je velmi užitečné, když se váš gdb server náhle odpojí, proces se zhroutí, jakmile je nastaven zarážka, nebo vaše ladicí grafické rozhraní odešle něco, čemu gdbserver nerozumí.
V kontextech, jako je router TP-Link, kde připojujete gdbserver ke kritickému procesu, jako je httpdJe poměrně běžné, že určité zarážky vytvářejí závodní podmínky nebo watchdogy, které ukončí proces, když se v ladicím programu příliš dlouho „zasekne“. V těchto situacích může být nutné upravit, které signály jsou blokovány, která vlákna jsou řízena a případně upravit samotnou konfiguraci systému (časové limity, hardwarové watchdogy), aby se umožnily delší ladicí relace.
Správné používání gdbserveru zahrnuje kombinování několika částíZkompilujte s vhodnými symboly, vyberte správnou gdb pro danou architekturu, nakonfigurujte cesty k symbolům a zdrojovým kódům, pochopte dva hlavní režimy gdbserveru (jednoprocesový a víceprocesový) a nebojte se z těchto režimů stahovat. --debug když se připojení nechová podle očekávání. S tímto základem se ladění aplikací běžících na vzdáleném systému Linux, routeru nebo virtuálním počítači s vlastním jádrem z vašeho počítače stává poměrně rutinní a především neuvěřitelně užitečným.
Vášnivý spisovatel o světě bytů a technologií obecně. Rád sdílím své znalosti prostřednictvím psaní, a to je to, co budu dělat v tomto blogu, ukážu vám všechny nejzajímavější věci o gadgetech, softwaru, hardwaru, technologických trendech a dalších. Mým cílem je pomoci vám orientovat se v digitálním světě jednoduchým a zábavným způsobem.