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 gdb
haszná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:linenum
breakpoint 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 N
vagyn 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 valtozonev
p fuggveny::valtozonev
p $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)