- gdbserver deluje kot oddaljeni agent GDB za nadzor procesov na drugem računalniku prek TCP ali serijskega vmesnika.
- Za oddaljeno odpravljanje napak je ključnega pomena prevajanje z simboliUporabite ustrezno gdb in pravilno konfigurirajte poti simbolov in pisav.
- gdbserver ponuja enoprocesni in večprocesni način, poleg tega pa se integrira z WinDbg in QEMU za odpravljanje napak v jedru.
- Možnosti, kot so --debug, sysroot in omejitve velikosti vrednosti, pomagajo pri diagnosticiranju težav in stabilizaciji sej.
Če programirate v jeziku C ali C++ Linux in se še nikoli nisi dotaknil gdbserverjaZamujate eno najbolj uporabnih orodij za oddaljeno odpravljanje napak v procesih, bodisi na strežniku, vgrajenem sistemu ali celo znotraj virtualnega stroja oziroma WSL. gdbserver še zdaleč ni nekaj "čarobnega" ali rezerviranega za strokovnjake, temveč je preprosto majhen program, ki komunicira z gdb in nadzoruje izvajanje ciljnega procesa.
Ključna ideja je zelo preprosta.: na računalniku, kjer se izvaja binarna datoteka, ki jo želite odpravljati napake (the ciljna) zaženete gdbserver; na vašem službenem računalniku ( gostiteljGdb ali celo WinDbg zaženete s podporo za protokol gdb. Oba se povežeta prek TCP ali serijskih vrat, od tam pa lahko nastavljate prekinitvene točke, pregledujete spremenljivke, si ogledujete sklad ali sledite izvajanju korak za korakom, kot če bi se program izvajal na vašem računalniku.
Kaj je gdbserver in kdaj ga je smiselno uporabljati?

gdbserver je oddaljeni "agent" za odpravljanje napak za GNU gdbNjegova funkcija je zelo specifična: teče na računalniku, kjer se izvaja program, ki ga je treba analizirati, nadzoruje ta proces (ali procese) in komunicira z odjemalcem gdb, ki se nahaja na drugem računalniku (ali na istem) prek oddaljene povezave.
V vsakodnevni uporabi se gdbserver uporablja v dveh tipičnih scenarijihProgramska oprema za odpravljanje napak, ki deluje v vgrajenih okoljih (usmerjevalniki, plošče z okrnjenim Linuxom, naprave) Internet stvariitd.) in procese odpravljanja napak na oddaljenih Linux računalnikih, kjer ni priročno ali preprosto ni mogoče imeti "debele" gdb z vsemi knjižnicami in simboli.
Na praktični ravni gdbserver obravnava naloge, kot so Branje in pisanje v procesne registre in pomnilnik, nadzor izvajanja (nadaljevanje, začasna ustavitev, prehod skozi korake), upravljanje prekinitvenih točk in pošiljanje vseh teh podatkov v gdb z uporabo oddaljenega protokola GDB. Ta filozofija je zelo podobna filozofiji orodij, kot je OpenOCD, ki delujejo kot most med gdb in strojna oprema zunanji, s to razliko, da se gdbserver izvaja na istem sistemu, kjer se izvaja binarna datoteka.
Če prihajate iz okolij Windows Zanimivo je tudi vedeti Razhroščevalniki, kot je WinDbg, lahko komunicirajo s strežnikom gdb v Linuxu, tako da lahko uporabniške procese v Linuxu odpravljate z uporabo podpore za oddaljeno odpravljanje napak prek protokola gdb, ki ga je Microsoft vključil v novejše različice.
Osnovne zahteve za odpravljanje napak z gdb in gdbserver

Preden začnete z oddaljenim odpravljanjem napak, morate razumeti odnos med gostiteljem in ciljem.. ciljna To je stroj, na katerem se izvaja program, ki ga je treba razhroščiti, in kjer se bo izvajal gdbserver; gostitelj To je računalnik, s katerega boste zagnali gdb (ali WinDbg) in kjer boste imeli izvorno kodo in po možnosti tudi simbole za odpravljanje napak.
Bistveno izhodišče je prevajanje binarne datoteke s simboliV GCC ali g++ se to doseže z zastavico -gin običajno je priporočljivo tudi onemogočiti optimizacije (na primer z -O0To omogoča razhroščevalniku natančnejši prikaz spremenljivk, makrov in strukture kode. Za določene makre lahko uporabite višje ravni razhroščevanja, kot so -g3.
Na strani gostitelja boste potrebovali združljivo različico gdb s ciljno arhitekturo. Za odpravljanje napak v vgrajenem sistemu MIPS, ARM ali drugi arhitekturi morate uporabiti gdb ustrezne navzkrižne orodne verige (na primer) arm-none-eabi-gdb o gdb-multiarch) in po potrebi konfigurirajte arhitekturo in endiannost z ukazi kot set arch y set endian.
Glede povezave gdbserver podpira dve glavni vrstiSerijska povezava (zelo pogosta v vgrajeni strojni opremi, prek UART-a) in TCP/IP, kar je najprimernejše, kadar je cilj v istem omrežju ali je računalnik z Linuxom dostopen prek omrežja. V obeh primerih se ukaz uporablja iz gdb. target remote za povezavo s končno točko, ki jo razkrije gdbserver.
Načini zagona gdbserverja: enoprocesni in večprocesni način

gdbserver lahko deluje na dva glavna načina Ko govorimo o odpravljanju napak v uporabniškem načinu: neposredno povezano z enim samim procesom ali kot "strežnik procesov", ki omogoča naštevanje in pripenjanje različnim sistemskim procesom.
V enoprocesnem načinu Zaženete gdbserver in določite gostiteljska vrata (host:port) ter program, ki ga želite zagnati. V preprostem primeru na namiznem računalniku z operacijskim sistemom Linux bi lahko naredili nekaj takega:
Ukaz: gdbserver localhost:3333 foo
S tem ukazom gdbserver zažene binarno datoteko. foo in posluša na vratih 3333Dokler se oddaljeni gdb ne poveže, program ostane ustavljen; ko se gdb poveže z target remote localhost:3333, postopek začne nadzorovati drobilnik.
V večprocesnem načinu (strežnik procesov) se uporablja možnost --multiV tem primeru gdbserver ne zažene neposredno nobenega programa, temveč preprosto posluša dohodne povezave in odjemalcu (gdb ali WinDbg) omogoča, da upravlja, kateri proces ustvari ali se mu priključi:
Ukaz: gdbserver --multi localhost:1234
Pri delu z WinDbg v Linuxu je ta večnačinnost še posebej zanimiva.Ker lahko iz samega WinDbg navedete procese na oddaljenem sistemu, vidite PID, uporabnika in ukazno vrstico ter se pripnete tistemu, ki vas zanima, podobno kot to storite s strežnikom procesov. dbgsrv.exe v operacijskem sistemu Windows.
Oddaljeno odpravljanje napak z gdbserverjem in gdb korak za korakom
Poglejmo si to z zelo tipičnim primerom.Odpravite napake v preprosti aplikaciji na istem računalniku (gostitelj in cilj se ujemata) z uporabo gdbserverja za simulacijo oddaljenega scenarija.
Najprej napišeš in prevedeš majhen programNa primer, neumna zanka, ki izpiše števec:
Ukaz: gcc -g foo.c -o foo
Ključna je tukaj zastava -gTo doda potrebne informacije za odpravljanje napak v binarno datoteko, tako da lahko gdb prikaže vrstice kode, imena spremenljivk, tipe itd. V "pravem" okolju navzkrižnega prevajanja bi to prevajanje izvedli z navzkrižnim orodjem in nato kopirali binarno datoteko in njene odvisnosti v cilj.
Naslednji korak je zagon gdbserverja na ciljnem strežnikuČe sta gostitelj in cilj isti stroj, potem:
Ukaz: gdbserver localhost:3333 foo
Videli boste sporočilo, podobno »Proces foo ustvarjen; pid = XXXX; Poslušanje na vratih 3333«. To pomeni, da je gdbserver ustvaril proces in čaka na povezavo z gdb. Če ste v sistemu, kjer je potrebnih več privilegijev (na primer za povezavo s sistemskimi procesi), boste morda morali zagnati ukaz z sudoVendar je pri dajanju dovoljenj vedno pametno biti previden. koren do razžvepljevalnika.
Na gostitelju zaženete gdb z določitvijo lokalne izvedljive datoteke (isti, ki se izvaja na cilju, ali identična kopija s simboli):
Ukaz: gdb foo
Ko ste enkrat znotraj gdb, vzpostavite oddaljeno povezavo z:
Ukaz: target remote localhost:3333
Na tej točki gdb naloži simbole iz lokalne binarne datoteke.Sinhronizira se z gdbserverjem in prevzame nadzor nad procesom, ki se dejansko izvaja pod gdbserverjem. Od tam naprej je potek običajen: ukazi, kot so break postaviti prelomne točke, continue, step, next, print za pregled spremenljivk, backtrace da vidim baterijo itd.
Povezovanje z delujočimi procesi z gdbserverjem
Programa ni vedno treba zagnati iz nič.Pogosto vas zanima pridružitev procesu, ki že poteka (na primer httpd po usmerjevalniksistemski demon ali produkcijska storitev).
Tipičen vzorec je uporaba možnosti --attach iz gdbserverjas podajanjem vrat, kjer bo poslušal, in PID-a ciljnega procesa. Na primer, na usmerjevalniku, kjer ste kopirali gdbserver, preveden za njegovo arhitekturo, lahko storite:
Ukaz: gdbserver localhost:3333 --attach <pid_de_httpd>
Na strani gostitelja boste uporabili različico gdb, ki podpira arhitekturo usmerjevalnika.na primer gdb-multiarchpredhodno konfiguriranje arhitekture in endiannosti:
Ukaz: set arch mips
set endian big
Nato določite lokalno datoteko, ki vsebuje simbole. oddaljenega binarnega programa (na primer file httpd) in po potrebi poveste gdb, kje na cilju se binarna datoteka dejansko izvaja z set remote exec-file /usr/bin/httpdKončno se, tako kot prej, povežete z:
Ukaz: target remote 192.168.0.1:3333
Ko je pritrjenPrekinitvene točke lahko nastavite na določenih funkcijah (na primer break checkFirmware), nadaljujte z izvajanjem in pustite, da normalen potek programa (na primer nalaganje vdelane programske opreme iz spletnega vmesnika) sproži prekinitveno točko.
Uporaba gdbserverja z WinDbg v Linuxu
V zadnjih letih je Microsoft v WinDbg dodal podporo za odpravljanje napak v procesih Linuxa. Uporaba gdbserverja kot zalednega sistema. Ta funkcionalnost je namenjena scenarijem, kjer delate v sistemu Windows, koda pa se izvaja v Linuxu (vključno z WSL).
Za odpravljanje napak v določenem Linux procesu z WinDbg in uporabo gdbserverjaPostopek bi bil nekako takšen: najprej poiščete ciljni proces na računalniku z Linuxom z ukazom, kot je ps -A (na primer a python3 (ki se izvaja), nato pa zaženete gdbserver na cilju:
Ukaz: gdbserver localhost:1234 python3
Če okolje to zahteva, boste morda morali uporabiti sudo gdbserver ...z enakimi varnostnimi ukrepi kot vedno. Ko gdbserver pokaže, da »posluša na vratih 1234«, v WinDbg pojdite na »Datoteka / Poveži se z oddaljenim razhroščevalnikom« in določite povezovalni niz naslednjega tipa:
Ukaz: gdb:server=localhost,port=1234
WinDbg uporablja majhen "gonilnik" protokola gdb za komunikacijo z gdbserverjem in ko je povezava vzpostavljena, ostane ustavljena na točki škorenj procesa. Od tam lahko uporabljate njegova okna sklada, module, pomnilnik, prekinitvene točke in ukaze, kot so k da vidim baterijo oz. lm za seznam modulov (upoštevajte, da nekateri ukazi pričakujejo format PE in ne ELF, zato lahko v nekaterih primerih prikažejo čudne podatke).
gdbserver in procesni strežnik WinDbg
Poleg primera z enim samim procesom se lahko WinDbg poveže s strežnikom gdb, ki deluje kot strežnik procesov. da deluje bolj podobno kot pri oddaljenih procesih sistema Windows. V tem načinu se gdbserver zažene z --multi in brez povezanega postopka:
Ukaz: sudo gdbserver --multi localhost:1234
V WinDbg izberite »Datoteka / Poveži se s procesnim strežnikom« in ponovno uporabite povezovalni niz gdb:server=localhost,port=1234Ko je povezava aktivna, lahko naštejete razpoložljive procese Linuxa in se povežete z želenim ali celo zaženete nov proces.
Upoštevati je treba eno subtilno podrobnost.WinDbg razlikuje med »strežnikom procesov« in »enim samim ciljem«, odvisno od tega, ali je gdbserver že priključen na proces, ko se poveže. Če ste gdbserver pustili priključen na proces, zaprli WinDbg in nato poskušali znova vzpostaviti povezavo, ga morda ne bo zaznal kot strežnik procesov in morda boste morali znova zagnati gdbserver.
Zaključek seje procesnega strežnikaObičajno zadostuje že pritisk tipke CTRL+D v konzoli, kjer se izvaja gdbserver, in zaustavitev odpravljanja napak iz WinDbg. V nekaterih skrajnih primerih, če pride do težav s sinhronizacijo, bo morda treba popolnoma zapreti odpravljalnik napak in znova zagnati gdbserver od začetka.
Upravljanje simbolov in izvorne kode pri oddaljenem odpravljanju napak
Eden od ključev za priročno oddaljeno odpravljanje napak je dobra razločitev simbolov in pisav.Brez simbolov postane navigacija po skladu ali nastavitev prekinitvenih točk na določenih funkcijah mučenje.
V klasičnih scenarijih gdb + gdbserver je idealno, da se kopija izvedljive datoteke s simboli hrani na gostitelju. (nerazstavljeno) in izvorno drevo. gdb ne zahteva, da oddaljena binarna datoteka vsebuje simbole; zadostuje, da lokalna datoteka, ki jo naložite z file ujema se z oddaljeno izvedljivo datoteko na ravni odmika.
V svetu odpravljanja napak v WinDbg in Linuxu so se pojavile tudi storitve, kot je DebugInfoD.ki prek HTTP-ja razkrivajo simbole in pisave. WinDbg lahko uporablja posebne poti tipa DebugInfoD*https://debuginfod.elfutils.org oboje .sympath kot v .srcpath za prenos simbolov DWARF na zahtevo in izvorne kode binarnih datotek Linux ELF.
V konkretnem primeru z WSL, kjer je uporabniška koda pod C:\Users\Bob\WinDbg-u bi lahko povedal:
Ukaz: .sympath C:\Users\Bob\
.srcpath C:\Users\Bob\
In če želite uporabiti tudi DebugInfoD za sistemske binarne datoteke:
Ukaz: .sympath+ DebugInfoD*https://debuginfod.elfutils.org
.srcpath+ DebugInfoD*https://debuginfod.elfutils.org
S to konfiguracijo, ko pregledate sklad ali vnesete funkcije libcWinDbg lahko poskusi prenesti ustrezne simbole DWARF in, če strežnik razkrije tudi kodo, prikaže izvorno kodo precej podrobno, čeprav orodjarna sistema Windows ne obravnava ELF in DWARF tako "izvorno" kot PE in PDB.
Praktičen primer: odpravljanje napak v programu C++ z gdbserverjem in WinDbg
Ilustrativen primer je majhna aplikacija v jeziku C++, ki na zaslon izpiše pozdrav., prevedeno v WSL z razhroščevalnimi simboli. Predstavljajte si program, ki rezervira std::array<wchar_t, 50> in vanj kopira daljše sporočilo, zaradi česar se besedilo skrajša in se pojavijo znaki ???? na koncu
Po prevajanju z nečim podobnim:
Ukaz: g++ DisplayGreeting.cpp -g -o DisplayGreeting
Zaženete gdbserver proti tej binarni datoteki:
Ukaz: gdbserver localhost:1234 DisplayGreeting
V WinDbg se povežete z nizom gdb:server=localhost,port=1234 Ko je seja vzpostavljena in so poti do simbolov in pisav konfigurirane, nastavite prekinitveno točko v DisplayGreeting!mainlahko uporabite dx greeting da pregledate lokalno tabelo in vidite njeno velikost (50 položajev) ter vizualno preverite na zavihku pomnilnika ali v pogledu spremenljivk, kako je pozdrav odrezan.
Lepota tega primera je v tem, da prikazuje, da tudi brez polne podpore za vse formate ELF/DWARF v WinDbgZ uporabo gdbserverja kot oddaljenega zalednega sistema lahko dokaj udobno prečkate sklade, pregledujete tipe, nastavljate prekinitvene točke po imenu funkcije in se pomikate po kodi C++.
Odpravljanje napak v jedru Linuxa s qemu in gdb
gdbserver se ne uporablja samo v uporabniškem načinu; obstajajo tudi zelo zmogljivi scenariji v načinu jedra.še posebej, če kombinirate QEMU s podporo za odpravljanje napak. Čeprav tukaj vlogo »gdbserverja« opravlja QEMU-jeva lastna možnost, je pristop enak: en konec zažene sistem, ki ga je treba odpravljati napake, in odpre vrata gdb; drugi konec je bodisi gdb bodisi razhroščevalnik, ki govori oddaljeni protokol.
Za odpravljanje napak v jedru ga morate prevesti s posebnimi možnostmi za odpravljanje napak.: aktiviranje generiranja informacij za odpravljanje napak (CONFIG_DEBUG_INFO), skripte jedra GDB (CONFIG_GDB_SCRIPTS) in način odpravljanja napak v jedru (CONFIG_DEBUG_KERNELPomembno je tudi onemogočiti možnosti, ki med povezovanjem odstranjujejo simbole, kot je na primer »Odstrani simbole, ki jih je ustvaril asembler, med povezovanjem«.
Po prevajanju boste dobili binarno datoteko vmlinux "Ni slečen"ki ga boste uporabili iz gdb. Potrebujete tudi osnovni initramfs, ki ga lahko ustvarite z ukazom, kot je:
Ukaz: mkinitramfs -o ramdisk.img
Nato zaženete QEMU z odhroščevalnimi parametriTipičen primer vključuje možnost -gdb tcp::1234 odpreti oddaljeno končno točko, združljivo z gdb, in -S tako da se virtualni stroj zažene od začetka in je začasno ustavljen. Določite tudi jedro z -kernel vmlinuxje -initrd ramdisk.img, spomin z -m 512 in konzolo običajno preusmerite na ttyS0 upravljati vse od terminal.
Z QEMU pridržanim čaka na gdbZ gostiteljskega računalnika zaženete gdb, ki kaže na vmlinux in se povežeš z target remote localhost:1234Od tam lahko nastavite zgodnje prelomne točke, na primer hb start_kernelin nadzorujte izvajanje z ukazi, kot so c (nadaljuj) in CTRL+C za ponovno premor.
Nedavne spremembe in nianse v gdb in gdbserver
V sodobnih distribucijah, kot je Red Hat Enterprise Linux 8, je v gdb in gdbserver veliko sprememb, ki jih je vredno upoštevati.še posebej, če prihajate iz prejšnjih različic ali imate skripte, ki analizirajo izhod razhroščevalnika.
Po eni strani gdbserver zdaj zažene "nižje" procese z uporabo lupineTako kot gdb tudi to omogoča razširitev spremenljivk in zamenjave v ukazni vrstici. Če iz kakršnega koli razloga morate to vedenje onemogočiti, so v RHEL 8 dokumentirane posebne nastavitve za vrnitev v prejšnji način.
Odstranjenih ali spremenjenih je bilo tudi več stvari.: podpora za odpravljanje napak v programih Java, prevedenih z gcj, način združljivosti HP-UX XDB, ukazi, kot so set remotebaud (nadomeščeno z set serial baud) ali združljivost z določeno starejšo obliko zapisa stabsPoleg tega oštevilčenje niti ni več globalno, temveč po "spodnjih" nitih, in se prikaže kot inferior_num.thread_num, z novimi priročnimi spremenljivkami, kot so $_gthread za sklicevanje na globalni identifikator.
Druga pomembna nova funkcija je prilagoditev max-value-sizeTo omejuje količino pomnilnika, ki ga lahko gdb dodeli za prikaz vsebine vrednosti. Privzeta vrednost je 64 KiB, zato lahko poskusi izpisa ogromnih polj ali masivnih struktur povzročijo opozorilo »vrednost je prevelika« namesto prikaza vsega razpoložljivega pomnilnika.
Prilagojen je bil tudi način, kako gdb obravnava sysrootPrivzeta vrednost je zdaj target:To pomeni, da bo za oddaljene procese najprej poskušal najti knjižnice in simbole v ciljnem sistemu. Če želite, da da prednost lokalnim simbolom, morate zagnati set sysroot s potjo, ki vas zanima, preden se odpravite target remote.
Glede zgodovine ukazov je trenutno uporabljena okoljska spremenljivka GDBHISTSIZE namesto HISTSIZETo vam omogoča natančno nastavitev, kako dolgo želite ohraniti ukaze, ki ste jih vnesli v sejah odpravljanja napak, ne da bi to vplivalo na delovanje drugih aplikacij, ki uporabljajo knjižnico za branje vrstic.
Nasveti za potek dela in odpravljanje težav z gdbserverjem
Za udoben potek dela obstaja nekaj vzorcev, ki običajno delujejo zelo dobro. Pri razvoju za vgrajene sisteme ali oddaljene strežnike je prvi korak čim večja avtomatizacija prevajanja simbolov in uvajanja binarnih datotek na cilj. Na ta način vedno veste, katera različica izvedljive datoteke se izvaja, in imate kopijo simbolov na voljo na gostitelju.
V okoljih z veliko jedri, ki povzročajo sesutje sistema, se je vredno naučiti uporabljati gdb v paketnem načinu., z zastavami, kot so --batch, --ex y -x za samodejno zaganjanje ukazov na seznamu jeder in obdelavo njihovih povratnih sledi iz skriptov (na primer v PythonTo vam omogoča hitro filtriranje ponavljajočih se težav, združevanje napak po sledenju sklada itd.
Ko gre kaj narobe z oddaljeno povezavo, je na voljo možnost --debug gdbserver je tvoj najboljši prijateljČe na primer zaženete procesni strežnik z:
Ukaz: gdbserver --debug --multi localhost:1234
Konzola gdbserver bo prikazala podrobne sledi dogajanja Na ravni oddaljenega protokola to vključuje dohodne pakete, napake pri oblikovanju, težave s prekinitvijo povezave itd. To je zelo uporabno, ko se vaš strežnik gdb nenadoma prekine, se proces sesuje takoj, ko je nastavljena prekinitvena točka, ali pa vaš grafični uporabniški vmesnik za odpravljanje napak pošlje nekaj, česar strežnik gdb ne razume.
V kontekstih, kot je usmerjevalnik TP-Link, kjer strežnik gdbserver priključite na kritičen proces, kot je httpdRelativno pogosto je, da določene prekinitvene točke ustvarijo tekmovalne pogoje ali nadzorne programe, ki ustavijo proces, ko ta predolgo ostane "zataknjen" v razhroščevalniku. V teh primerih bo morda treba prilagoditi, kateri signali so blokirani, katere niti so nadzorovane in, če je primerno, spremeniti samo konfiguracijo sistema (časovne omejitve, strojne nadzorne programe), da se omogočijo daljše seje odpravljanja napak.
Dobra uporaba gdbserverja vključuje kombiniranje več delovPrevedite z ustreznimi simboli, izberite pravilen gdb za arhitekturo, konfigurirajte poti do simbolov in izvornih kod, razumite dva glavna načina delovanja gdbserverja (enoprocesni in večprocesni) in se ne bojte črpati iz tega načina. --debug ko se povezava ne obnaša po pričakovanjih. S to osnovo postane odpravljanje napak v aplikacijah, ki se izvajajo na oddaljenem sistemu Linux, usmerjevalniku ali virtualnem stroju s prilagojenim jedrom iz vašega računalnika, precej rutinsko in predvsem neverjetno uporabno.
Strasten pisec o svetu bajtov in tehnologije nasploh. Rad delim svoje znanje s pisanjem in to je tisto, kar bom počel v tem blogu, saj vam bom pokazal vse najbolj zanimive stvari o pripomočkih, programski opremi, strojni opremi, tehnoloških trendih in še več. Moj cilj je, da vam pomagam krmariti po digitalnem svetu na preprost in zabaven način.