Hibakeresés
gdb¶
Ahhoz, hogy kipróbálhassuk, hogyan is működik a gdb, tekintsük az alábbi példa kódot, amely egy szegmentációs hibát vét, és így a program végrehajtása megszakad.
1 2 3 4 5 6 7 8 9 10 11 12 | |
Program fordítás debug módban¶
A gdbhasználatához a programot debug szimbólumokkal kell lefordítani, hogy a forráskódra hivatkozhassunk.
Fordítsuk a terminálból a debuggolandó kódot a gcc pelda.c -o pelda -Wall -g utasítással.
A -g a debug ("hibakövetési") kapcsoló. Debug információk kerülnek a lefordított binárisba, így könnyebb lesz a debuggolás.
GDB elindítása és a cél program betöltése¶
gdb ./pelda
Ha nem -g kapcsolóval volt a program fordítva, akkor a betöltéskor kiírt logok között azt látjuk, hogy no debugging symbols found (amitől a debuggolás még elindítható, csak kevésbé lesz informatív)
Ezután a GDB interaktív módba lép, ahol különféle parancsokat adhatunk ki. Alap parancsok:
| Parancs | Jelentés |
|---|---|
run |
Elindítja a programot, de használható arra is, hogy az aktuális debug sessiont újraindítsuk |
break <függvény> vagy break <fájl>:<sor> |
Töréspontot (breakpoint) állít be |
info breakpoints |
breakpontok listázása |
next |
Következő sorra lép (függvényt átugrik) |
step |
Következő sorra lép (függvénybe belép) |
continue |
Futtatás folytatása a következő töréspontig |
print <változó> |
Változó aktuális értékének kiírása |
list |
A forráskód környezetének megjelenítése |
quit |
Kilépés a GDB-ből |
disassemble |
az aktuális függvény gépi kódja. Kis nyíl jelöli éppen melyik utasításnál lévő breakpointban vagyunk. |
| disassemble function | A kért függvény gépi kódjának megnézése |
disas /m funcname |
a C utasítások és a hozzájuk tartozó gépi utasítások együtt nézhetőek |
info functions [regexp] |
Opcionálisan megadható egy reguláris kifejezés a találatok szűrésére |
Breakpointok kezelése¶
-
bekapcsolás, kikapcsolás, törlés
-
disable N: adott sorszámú breakpoint kikapcsolása (dis N) -
enable N: adott sorszámú breakpoint visszakapcsolása (en N) -
clear function, clear linenum, clear filename:linenumbreakpoint törléshez -
delete: az összes breakpoint letörlése
-
-
Következő sor végrehajtása
-
step (s) -
next (n): a különbség, hogy nem lép bele függvényhívásokba -
s Nvagyn N: egyszerre N darab sort lépünk -
finish: az aktuális függvényből való visszatérés helyére ugrik. Ha volt visszatérési érték, akkor kiírja.
-
-
Következő gépi utasítás végrehajtása (ezekkel a parancsokkal assembly utasítás szintén tudunk lépdelni a kódban)
-
stepi (si) -
nexti (ni): a különbség, hogy nem lép bele függvényhívásokba
-
-
Breakpoint utáni újraindítás
-
continue (c) -
c N: ahol N megadja, hányszor ne álljon meg a gdb az aktuális breakpointnál
-
-
Backtrace (Breakpointnál vagy hiba (pl segmentation fault) esetén megnézhetjük hogyan jutott el a program az adott (hibás) sor lefutásához.)
-
backtrace (bt): az aktuális stack frame-től kezdve visszafelé haladva kiírja az összes frame-et, ami a stack-en van. Ha túl sokáig tart CTRL+C-vel le lehet állítani a kiíratást. -
bt n: csak az utolsó n darab frame-t írja ki -
bt -n: csak az első n darab frame-t írja ki -
bt full: a frame-k lokális változóit is kiíratja. Kombinálható az előző két utasítással.
-
Információk kiíratása¶
-
info registers -
layout regs info variables: globális és statikus változók értékeiinfo locals: lokális változók értékeiprint symbol: adott szimbólum értéke- röviden:
p symbol p valtozonevp fuggveny::valtozonevp $eax
- röviden:
info address symbol: adott szimbólum memóriacímeinfo frame: az aktuális frame adatai (argumentumok, lokális változók, ebp, eip értékei)x 0x080485e9: az x utasítással egy konkrét memóriacím tartalmát nézhetjük megx/16 address: 16 érték legyen megjelenítve az addresstől kezdve (növekvő memóriacímek irányába)x/-16 address: ugyanez, csak a 16 érték csökkenő memóriacímek irányába megy (gdb 8-tól működik)- Kiíratási módosítók megadása is lehetséges:
x/16x address: 16 hexadecimális érték kiíratásax/16xg address: 16 db 64 bites hexadecimális érték kiíratásax/16c address: 16 karakter kiíratásax/s address: C sztringként értelmezi az adott memóriaterületetx/d address: előjeles, decimális értékként való megjelenítésx/i address: utasításként próbálja értelmezni a memóriaterületet- Verem tetjének megtekintése:
x/20x $esp
Változáskövetés¶
watch symbol: változó, regiszter, memóriacím (vagy komplexebb kifejezés) értékének a váltazása esetén álljon meg a program futása (mint egy breakpoint érték változása alapján). Többszálú program esetén minden szálon van változásfigyelés.info watchpoints: listázásukrwatch symbol: megállítja a program futását, ha a szimbólumot olvastákawatch symbol: megállítja a program futását, ha a szimbólumot írták vagy olvasták
Feltételes breakpointok elhelyezése¶
Használhatjuk a célnyelv utasításait, szimbólumait, hogy a breakpointokat feltételekhez kössük! Meglévő breakpointhoz is tudunk az azonosító száma alapján utólag feltételt rakni (pl. info breakpoints-al kideríthető)
break file.c:20 if i == 112: breakpoint a 20-as soron, ha az i 112break file.c:17 if strcmp(input, "password") == 0: breakpoint a 17-es soron, ha a string értéke passwordcond 8 *p == 78: új feltétel a 8-as breakpointhozcond 8: a 8-as breakpoint feltételének törlése
Függvényhívás¶
Lehetőségünk van kézzel meghívni a célprogram valamely függvényét (pl. ha direkt írtunk egyet debug céllal) Paramétereket is adhatunk meg neki.
call segedfgv()
.gdbinit használata¶
GDB konfigurációs fájl, mely a gdb indításakor automatikusan betöltődik. Segítségével lehet kicsit automatizálni a debuggolást. Helyei lehetnek:
- /etc/gdbinit: rendszerszintű beállítások
- ~/.gdbinit: user szintű beállítások
- ./.gdbinit: csak az adott munkakönyvtárból futó gdb-re vonatkozik. A lokális gdbinit betöltése ki lehet kapcsolva, ekkor a megjelenő hibaüzenetek alapján lehet megoldást keresni (hozzáadni a biztonsági kivételt vagy teljesen kikapcsolni ezt az ellenőrzést)