GNU Debugger (gdb) je neocenitelný nástroj pro kontrolu běžících procesů a řešení problémů při vývoji programů.
Můžete nastavit zarážky na konkrétních místech (podle názvu funkce, čísla řádku atd.), povolit a zakázat tyto zarážky, zobrazovat a měnit hodnoty proměnných a provádět všechny standardní věci, které byste očekávali od jakéhokoli ladicího programu. Má však mnoho dalších funkcí, se kterými jste možná neexperimentovali. Zde je pět, které můžete vyzkoušet.
Podmíněné zarážky
Nastavení bodu přerušení je jednou z prvních věcí, které se naučíte dělat s GNU Debuggerem. Program se zastaví, když dosáhne bodu přerušení, a můžete spustit příkazy gdb k jeho kontrole nebo změně proměnných, než umožníte programu pokračovat.
Můžete například vědět, že často zvaná funkce někdy selže, ale pouze tehdy, když získá určitou hodnotu parametru. Na začátku této funkce můžete nastavit bod přerušení a spustit program. Parametry funkce se zobrazí pokaždé, když dosáhne bodu přerušení, a pokud není zadána hodnota parametru, která spouští selhání, můžete pokračovat, dokud nebude funkce znovu volána. Když problémový parametr spustí selhání, můžete projít kód a zjistit, co je špatně.
(gdb) break občas_crashs
Bod 1 na 0x40110e:soubor prog.c, řádek 5.
(gdb) spustit
[...]
Bod 1, občas_crashes (f=0x7ffffffffd1bc) na prog.c:5
5 fprintf(stderr,
(gdb) pokračovat
Bod 1, někdy_chyby (f=0x7ffffffffd1bc) na prog.c:5
5 fprintf(stderr,
(gdb) pokračovat
Aby to bylo opakovatelnější, můžete spočítat, kolikrát je funkce volána před konkrétním voláním, které vás zajímá, a nastavit počítadlo na tento bod přerušení (například „pokračovat 30“, aby ignorovala dalších 29 případů, kdy dosáhne bod přerušení).
Kde jsou ale body přerušení opravdu mocné, je jejich schopnost vyhodnocovat výrazy za běhu, což vám umožňuje automatizovat tento druh testování. Zadejte:podmíněné zarážky.
přerušení [UMÍSTĚNÍ], pokud PODMÍNKA
(gdb) přerušení občas_zhroucení, pokud !f
Bod přerušení 1 na 0x401132:soubor prog.c, řádek 5.
(gdb) spustit
[...]
Bod zlomu 1, občas_crash (f=0x0) na prog.c:5
5 fprintf(stderr,
(gdb)
Místo toho, aby se gdb ptal, co má dělat při každém volání funkce, podmíněný bod přerušení vám umožní zastavit gdb na tomto místě pouze tehdy, když se konkrétní výraz vyhodnotí jako pravdivý. Pokud provedení dosáhne umístění podmíněného bodu přerušení, ale výraz se vyhodnotí jako nepravda,
Další zdroje pro Linux
- Cheat pro příkazy Linuxu
- Cheat sheet pro pokročilé příkazy systému Linux
- Bezplatný online kurz:Technický přehled RHEL
- Síťový cheat pro Linux
- Cheat sheet SELinux
- Cheat pro běžné příkazy pro Linux
- Co jsou kontejnery systému Linux?
- Naše nejnovější články o Linuxu
debugger automaticky nechá program pokračovat, aniž by se uživatel zeptal, co má dělat.
Příkazy bodu přerušení
Ještě sofistikovanější funkcí bodů přerušení v GNU Debuggeru je schopnost skriptovat odpověď na dosažení bodu přerušení. Příkazy bodu přerušení vám umožňují napsat seznam příkazů GNU Debuggeru, které se mají spustit, kdykoli dosáhne bodu přerušení.
Můžeme to použít k vyřešení chyby, o které již víme v sometimes_crashes funkce a přimět ji k neškodnému návratu z této funkce, když poskytuje nulový ukazatel.
Můžeme použít tichý jako první řádek, abyste získali větší kontrolu nad výstupem. Bez toho se rámec zásobníku zobrazí pokaždé, když je dosaženo bodu přerušení, dokonce ještě před spuštěním našich příkazů pro bod přerušení.
(gdb) break občas_crashes
Bod přerušení 1 na 0x401132:soubor prog.c, řádek 5.
(gdb) příkazy 1
Zadejte příkazy pro bod přerušení 1, jeden na řádek .
Konec řádkem s nápisem „konec“.
>tiché
>if !f
>rámec
>printf „Přeskočení hovoru\n“
>návrat 0
>pokračovat
>konec
>printf "Pokračování\n"
>pokračovat
>konec
(gdb) spustit
Spouštěcí program:/home/twaugh/Documents/GDB/prog
varování:Načítatelná sekce ".note.gnu.property" mimo segmenty ELF
Pokračování
Pokračování
Pokračování
#0 sometimes_crashes (f=0x0) na prog.c:5
5 fprintf(stderr,
Přeskočení hovoru
[Inferior 1 (proces 9373) ukončeno normálně]
(gdb)
Vypsat binární paměť
GNU Debugger má vestavěnou podporu pro zkoumání paměti pomocí x příkaz v různých formátech, včetně osmičkové, šestnáctkové a tak dále. Ale rád vidím dva formáty vedle sebe:šestnáctkové bajty vlevo a znaky ASCII reprezentované stejnými bajty vpravo.
Když chci zobrazit obsah souboru bajt po bajtu, často používám hexdump -C (hexdump pochází z balíčku util-linux). Zde je x gdb příkaz zobrazující hexadecimální bajty:
(GDB) x / 33xb MyData
0x404040:0x02 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x01
0x04048:0x01 0x47 0x00 0x12 0x61 0x74 0x74 0x72
0x404050:0x69 0x62 0x75 0x74 0x65 0x73 0x2d 0x63
0x404058:0x68 0x61 0x72 0x73 0x65 0x75 0x00 0x05
0x404060:0x00
Co kdybyste mohli naučit gdb zobrazovat paměť stejně jako hexdump? Tuto metodu můžete a ve skutečnosti můžete použít pro jakýkoli formát, který preferujete.
Kombinací skládky příkaz k uložení bajtů do souboru, shell příkaz ke spuštění hexdump na souboru a define příkaz, můžeme vytvořit vlastní nový hexdump příkaz k použití hexdump k zobrazení obsahu paměti.
(gdb) definujte hexdump
Zadejte příkazy pro definici "hexdump".
Konec řádkem, který říká "end".
>vypíše binární paměť /tmp/dump.bin $ arg0 $arg0+$arg1
>hexdump shellu -C /tmp/dump.bin
>end
Tyto příkazy lze dokonce zadat do ~/.gdbinit soubor k trvalému definování příkazu hexdump. Tady je v akci:
(gdb) hexdump mydata sizeof(mydata)
00000000 02 01 00 02 00 00 00 01 01 47 00 12 61 74 74 72 |.........G..attr|
00000010 69 62 75 74 65 73 2D 63 68 61 72 73 65 75 00 05 | Ibutes-charseu .. |
0000000020 00 |. |
00000021
Inline demontáž
Někdy chcete více porozumět tomu, co se stalo před havárií, a zdrojový kód nestačí. Chcete vidět, co se děje na úrovni instrukcí CPU.
Demontáž příkaz vám umožní zobrazit instrukce CPU, které implementují funkci. Ale někdy může být obtížné sledovat výstup. Obvykle chci vidět, jaké instrukce odpovídají určité části zdrojového kódu ve funkci. Chcete-li toho dosáhnout, použijte /s modifikátor pro zahrnutí řádků zdrojového kódu do rozebrání.
(gdb) disassemble/s main
Výpis kódu assembleru pro funkci main:
prog.c:
11 {
0x0000000000401158 <+0>: push %rbp
0x0000000000401159 <+1>: mov %rsp,%rbp
0x000000000040115c <+4>:0 sub 0 0 x 10 % n 0 0 0 0 0 0 0 0 0 0 0 0 % n <+8>: movl $ 0x0,-0x4 (% rbp)
13 občas_krashes(&n);
0x0000000000401167 <+15>: < lea -0x4 br /> 0x000000000040116b <+19>: mov %rax,%rdi
0x000000000040116e <+22>: callq 0x401126: callq 0x401126Toto spolu s informačními registry zobrazit aktuální hodnoty všech registrů CPU a příkazů, jako je stepi krokování jedné instrukce po druhé vám umožní mnohem podrobněji porozumět programu.
Zpětné ladění
Někdy si přejete vrátit čas. Představte si, že jste narazili na kontrolní bod proměnnou. Watchpoint je jako bod přerušení, ale místo toho, aby byl nastaven na místo v programu, je nastaven na výraz (pomocí watch příkaz). Kdykoli se změní hodnota výrazu, provádění se zastaví a řízení převezme ladicí program.
Představte si tedy, že jste narazili na tento sledovací bod a paměť používaná proměnnou změnila hodnotu. To se může ukázat jako způsobeno něčím, co se stalo mnohem dříve; například byla uvolněna paměť a nyní je znovu používána. Ale kdy a proč bylo osvobozeno?
GNU Debugger dokáže vyřešit i tento problém, protože svůj program můžete spustit i obráceně!
Dosahuje toho pečlivým zaznamenáváním stavu programu v každém kroku, aby mohl obnovit dříve zaznamenané stavy, což vytváří iluzi času plynoucího pozpátku.
Chcete-li povolit záznam tohoto stavu, použijte cílový záznam-plný příkaz. Pak můžete použít nemožně znějící příkazy, jako například:
- obrácený krok , který se vrátí na předchozí zdrojový řádek
- reverse-next , který se vrátí na předchozí zdrojový řádek a překročí volání funkcí
- zpětné dokončení , který se přetočí do bodu, kdy se chystala zavolat aktuální funkce
- reverse-continue , který se vrátí do předchozího stavu v programu, který by (nyní) spustil bod přerušení (nebo cokoliv jiného, co způsobí jeho zastavení)
Zde je příklad zpětného ladění v akci:
(gdb) b main
Bod 1 na 0x401160:soubor prog.c, řádek 12.
(gdb) r
Spouštěcí program:/home/twaugh/Documents/GDB/prog
[...]
Bod zlomu 1, hlavní () na prog.c:12
12 int n =0;
(gdb) cílový záznam plný
(gdb) c
Pokračování.
Program přijatý signál SIGSEGV, chyba segmentace.
0x0000000000401154 v občasných pádech (f=0x0) v prog.c:7
7 return *f;
(gdb) reverse-finish
Vraťte se k volání čísla 0 0x0000000000401154 při občasných selháních (f=0x0)
na prog.c:7
0x0000000000401190 v main () na prog.c:16
16 some_crashes(0);
Toto je jen hrstka užitečných věcí, které GNU Debugger umí. Existuje mnoho dalších k objevování. Která skrytá, málo známá nebo prostě úžasná funkce gdb je vaše oblíbená? Podělte se o to v komentářích.