Ladění programu pomocí gdb: Porovnání verzí
m (→Práce s core: fix) |
m (→Práce s core: fix) |
||
Řádka 135: | Řádka 135: | ||
10 (gdb) '''backtrace''' | 10 (gdb) '''backtrace''' | ||
11 #0 0x0000000000400500 in main () at sigsegv.c:8 | 11 #0 0x0000000000400500 in main () at sigsegv.c:8 | ||
− | 12 (gdb) '''quit''' | + | 12 (gdb) '''quit''' |
Na řádku 1 je povolen zápis neomezeně velkého souboru core (obraz paměti v okamžiku pádu programu) do aktuálního adresáře. Na řádku 4 je spuštěn debugger s parametrem pro načtení core, po kterém debugger informuje o zjištěné příčině pádu programu a řádku, na kterém k tomu došlo (starší verze debuggeru vyžadují použití příkazu ''backtrace''). Soubor ''core'' má jako příponu číslo havarovaného procesu, takže nový výpis nepřepíše ten starší. | Na řádku 1 je povolen zápis neomezeně velkého souboru core (obraz paměti v okamžiku pádu programu) do aktuálního adresáře. Na řádku 4 je spuštěn debugger s parametrem pro načtení core, po kterém debugger informuje o zjištěné příčině pádu programu a řádku, na kterém k tomu došlo (starší verze debuggeru vyžadují použití příkazu ''backtrace''). Soubor ''core'' má jako příponu číslo havarovaného procesu, takže nový výpis nepřepíše ten starší. |
Verze z 7. 4. 2014, 18:59
Ladění programu pomocí gdb je vhodné pro práci v příkazovém řádku. Debugger gdb slouží pro krokování programu, inspekci proměnných, ale i analýzu core (soubory s obrazem paměti po pádu programu). Existují nadstavby jak pro textové rozhraní (např. cgdb), tak pro grafické rozhraní (např. ddd) nebo je možné ladit program přímo v integrovaném vývojovém prostředí (Eclipse). Text se bude dále zabývat použitím debuggeru přímo na příkazovém řádku.
Obsah
Ladění programu
Program, který chceme ladit pomocí gdb, je nutné přeložit s přepínačem -g
. Program natáhneme do debuggeru příkazem gdb vypocet
, načež je zobrazena licence a aktivuje se interní řádkové rozhraní debuggeru (v následujícím příkladu je vstup uživatel vyznačen tučně):
$ gdb vypocet GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5_5.2) Copyright (C) 2009 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-redhat-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/kerslage/vyuka/pre/vypocet...done. (gdb)
Pokud by program gdb vypíše hlášení no debugging symbols found, je potřeba zkontrolovat zadání parametru -g
při překladu jako parametr (pro překladač gcc
). V interním řádkovém rozhraní je možné zadávat příkazy, kterými je gdb řízen (viz dále).
Krokování programu
- list
- Příkaz list vypíše zdrojový kód programu včetně čísel řádků. Parametrem může být číslo řádku, jméno funkce, dvojice soubor:jménofunkce nebo rozsah řádků oddělený čárkou.
- break
- Příkaz break slouží k vytvoření bodu přerušení v programu (též zarážka). Parametrem může být číslo řádku nebo název funkce a oboje může být podobně jako u příkazu list upřesněno názvem souboru s dvojtečkou. Za parametr může být doplněno klíčové slovo if, za kterým je možné předepsat podmínku pro přerušení (např.
x>5
). - watch
- Příkaz watch definuje výraz, při jehož splnění je program pozastaven (např.
x>5
). - clear
- Příkaz clear slouží ke zrušení bodu přerušení definovaného příkazem break.
- next
- Příkaz next spustí program až do začátku následujícího příkazu ve zdrojovém kódu. Pokud je na aktuálním řádku volání funkce, je tato provedena celá.
- step
- Příkaz step udělá v programu jeden krok (tj. jeden příkaz). Pokud je na aktuálním řádku volání funkce, vstoupí se do ní a provádění se zastaví (bude možné funkci krokovat).
- until
- Příkaz unitl spustí program až do specifikovaného místa (číslo řádku, název funkce).
- finish
- Příkaz finish způsobí, že aktuální funkce je dokončena.
- continue
- Pokračování běhu programu (až do dalšího bodu přerušení).
- run
- Příkaz run slouží ke spuštění programu, který je do gdb natažen. Případné parametry uvedené za příkazem run jsou programu předány, jako by byl s nimi spuštěn z příkazového řádku.
- record
- Příkaz record umožňuje registrovat změny, které umožní vracet se v programu zpět. Příkaz zadejte ihned po příkazu run. Pak je možné použít příkazy
reverse-next
,reverse-step
a další.
Inspekce proměnných a paměti
- Příkaz print slouží k vypsání obsahu proměnné, která je zadána jako parametr. Předřazením znaku & je vypsána adresa, na které je proměnná umístěna (spolu s datovým typem).
- info locals
- Příkaz info locals vypíše všechny lokální proměnné v aktuálním kontextu programu.
- info proc mappings
- Příkaz info proc mappings vypíše mapu paměti procesu.
- x
- Příkaz x slouží k inspekci obsahu paměti. Parametrem může být adresa v paměti, název funkce nebo znak & následovaný jménem proměnné (vypíše adresu paměti a její obsah). Modifikátory umožňují různý výpis obsahu paměti (čísla, strojové instrukce, znaky) – např.
x/5c 0x400500
vypíše 5 znaků z udané hexadecimální adresy. - backtrace
- Příkaz backtrace vypíše obsah zásobníku ve smyslu seznamu aktuálního stavu volání funkcí (tj. všechna volání funkcí, resp. návratů z funkcí). Při zpracování core zobrazí číslo řádku v kódu, na kterém došlo k chybě.
Ostatní
- quit
- Příkaz quit slouží k ukončení činnosti gdb.
- kill
- Příkaz kill ukončí běh právě zpracovávaného programu.
- help
- Příkaz help vypíše nápovědu. Parametrem může být libovolný příkaz.
- info
- Příkaz info vypisuje různé informace o stavu debuggeru. Parametrem může být například args (argumenty programu z příkazového řádku), breakpoints (výpis bodů přerušení), watchpoints (dtto), registers (obsah registrů procesoru), threads (spuštěné thready), set (interní nstavení gdb).
Příklady ladění programu
Pro ladění je možné použít pohodlnější grafickou nadstavbu debuggeru, například ddd
(data display debugger) nebo nějaké vývojové prostředí (např. Eclipse).
Krokování a inspekce proměnných
Mějme zdrojový kód programu v souboru vypocet.c
:
#include <stdio.h>
int main()
{
int a, x = 3;
a = x + 5;
printf("Vysledek: %d\n", a);
return 1;
}
Pak ho přeložíme spolu s ladícími informacemi (pomocí parametru -g
):
gcc -g -o vypocet vypocet.c
Dále je záznam práce s gdb, přičemž tučně jsou zvýrazněny vstupy uživatele. Komentář je pod příkladem (čísla řádků zcela vlevo jsou přidána dodatečně, aby bylo možné výpis komentovat):
1 $ gdb vypocet 2 Reading symbols from /home/ke/pokus/vypocet...done. 3 (gdb) break main 4 Breakpoint 1 at 0x4004cc: file vypocet.c, line 5. 5 (gdb) run 6 Starting program: /home/ke/pokus/vypocet 7 8 Breakpoint 1, main () at vypocet.c:5 9 5 int a, x = 3; 10 Missing separate debuginfos, use: debuginfo-install glibc-2.13-1.x86_64 11 (gdb) print a 12 $1 = 0 13 (gdb) print x 14 $2 = 0 15 (gdb) next 16 6 a = x + 5; 17 (gdb) print a 18 $3 = 0 19 (gdb) print x 20 $4 = 3 21 (gdb) next 22 7 printf("Vysledek: %d\n", a); 23 (gdb) print a 24 $5 = 8 25 (gdb) print x 26 $6 = 3 27 (gdb) continue 28 Continuing. 29 Vysledek: 8 30 31 Program exited with code 01. 32 (gdb) quit 33 $
Práce s core
Mějme chybný zdrojový kód programu v souboru sigsegv.c
, který způsobí pád programu na porušení ochrany paměti (SEGV, tj. segmentation fault):
#include <stdio.h>
int main()
{
char *adresa = "Ahoj";
// následuje zápis do text segmentu (paměť jen pro čtení) -> SEGV
strcpy(adresa, "BAF");
}
Pak ho přeložíme spolu s ladícími informacemi (pomocí parametru -g
):
gcc -g -o sigsegv sigsegv.c
Dále je záznam práce na příkazovém řádku, přičemž tučně jsou zvýrazněny vstupy uživatele. Komentář je pod příkladem (čísla řádků zcela vlevo jsou přidána dodatečně, aby bylo možné výpis komentovat):
1 $ ulimit -c unlimited 2 $ ./sigsegv 3 Neoprávněný přístup do paměti (SIGSEGV) (core dumped [obraz paměti uložen]) 4 $ gdb -c core.8847 sigsegv 5 Reading symbols from /home/ke/Dropbox/Dokumenty/Výuka/TUL/c/sigsegv...done. 6 [New LWP 8847] 7 Core was generated by `./sigsegv'. 8 Program terminated with signal SIGSEGV, Segmentation fault. 9 #0 0x0000000000400500 in main () at sigsegv.c:8 9 8 strcpy(adresa, "BAF"); 10 (gdb) backtrace 11 #0 0x0000000000400500 in main () at sigsegv.c:8 12 (gdb) quit
Na řádku 1 je povolen zápis neomezeně velkého souboru core (obraz paměti v okamžiku pádu programu) do aktuálního adresáře. Na řádku 4 je spuštěn debugger s parametrem pro načtení core, po kterém debugger informuje o zjištěné příčině pádu programu a řádku, na kterém k tomu došlo (starší verze debuggeru vyžadují použití příkazu backtrace). Soubor core má jako příponu číslo havarovaného procesu, takže nový výpis nepřepíše ten starší.