Debugování v C/C++
Co musíme však nejdříve udělat? Přeložit program s debug informacemi Umožníme přidáním volby –g do překladače POZOR!!! Pokud se program skládá z více modulů (.o souborů) je potřeba přidat volbu –g při tvorbě každého takového modulu
Co by jsme naopak dělat neměli Debugovat programy které jsme prohnali přes optimalizující překladač Tj. pokud budu debugovat tak nepřidávám volbu –o ( a už vůbec ne -o2 -o3 ) Pokud tak učiníme tak debugovaný program bude odlišný od toho který máme před sebou ve zdrojovém textu
Rozdíl debbugování v C oproti C++ C++ umožňuje používat šablony. Tj. při pádu programu přidává i názvy šablon C++ umožňuje dědičnost a špatně se dohledává pokud je chyba ve virtuální destruktoru některé z nadřezených tříd Debuggování v C++ je tudíž trošku těžší a někdy velice nepřehledné
Jaké máme možnosti ? Debugovat ze souboru vzniklých při pádu programu Debugovat přímo spuštěný program
Debugování z core-dumpu 1 Musíme nejdříve donutit OS tvořit core- dumpy - Zvládneme pomocí příkazu “ulimit –c unlimited“ - Příkaz “ulimit“ má spoustu dalších užitečných vlastností ( změna počtu vláken, max. procesorového času apod.)
Debugování z core-dumpu 2 Po spadnutí programu se nám nyní vytvoří soubor core( číslo procesu ) Tento soubor můžeme nyní předhodit debbugeru a podívat se kde se stala chyba Provedeme pomocí: gdb ( název programu ) ( coredump )
Debugování z core-dumpu 3 Nyní když jsme v debbugeru tak vidíme řádek na kterém se stala chyba Zadáme teda příkaz “bt“ ať vídíme kde přesně se stala chyba a jaké volání funkcí jí předcházelo
Debugování z core-dumpu 4 Další příkazy které se mohou hodit ptype ( typ proměnné ) print ( název proměnné nebo výraz ) set print pretty print struktura->jmeno p list
Debugování z core-dumpu 5 Pozitiva + Nezdržujeme běh programu debbugerem +Debbugujeme až když skutečně víme, že něco spadlo Negativa - Né každý pád programu tvoří coredump ( např. signál pipe ) - Z coredumpu debbuger nikdy nezíská tolik informací jako přímo při běhu programu
Debugování za běhu 1 Můžeme používat přímo a nepotřebujeme k němu žádný coredump Musíme však počítat s někdy mnohonásobně větší zátěží při běhu programu
Debugování za běhu 2 - GDB Možnost číslo 1 – použijeme gdb Tuto možnost velice nedoporučuju. Osobně používám na debugování gdb v “bojových situacích“ Podíváme se teda na pár užitečnách příkazů které můžou pomoc
Debugování za běhu 3 - GDB Nejdříve spustíme program pod gdb gdb ( název programu) Takto spuštěný program je zatím zastavený. Spustíme ho tedy příkazem run ( argumenty z příkazové řádky )
Debugování za běhu 4 - GDB Breakpointy break ( číslo řádky ) break ( název funkce ) clear ( číslo řádky / název funkce ) Info breakpoints Krokování next continue
Debugování za běhu 5 - strace Strace je prográmek který nám sobrazuje veškeré systémové volání Hodí se tedy pokud chceme vyzkoumat co program volal a s jakými argumenty a nebo kvůli čemu a kde dostal signál Pokud tušíme, že nám program zhodil nějáký signál je toto nejlepší program na nalezení problému
Debugování za běhu 6 Všechny předchozí programy jsou užitečné ale nezobrazují všechny užitečné informace. Např. Nevíme kde jsme uvolnili proměnnou do které jsem se pak pokusili něco napsat Nekontolují memory-leaky apod.
Debugování za běhu 6 - strace Použití strace ( název programu ) Na obrazovce pak uvidíme postupně všechna volání i s parametry
Debugování za běhu 7 - valgrind Valgrind je užitečný prográmek který kontroluje veškeré operace s pamětí Odborně – Program na kontrolu konzistence heapu Asi nejlepší ze všech programů na debugování Bohužel zatím použitelný jen pod Linuxem
Debugování za běhu 7 - valgrind Program není ve standratní knihovně a porot ho musíme stáhnout z internetu Např z. apt-get install valgrind ( Debian ) yum install valgrind ( Red Hat )
Debugování za běhu 8 - valgrind Program se skládá z několika částí kde každá se soustředí na jiný druh problémů Nejvíce používané jsou error-check leak-check
Debugování za běhu 9 - valgrind Pokud valgrind spustíme bez jakýchkoliv parametrů tak použijeme modul pro kontrolu chyb Použití valgrind ( název programu )
Debugování za běhu 10 - valgrind Ve výpise se nám pak zobrazí chyby Proměnné bez defaultních hodnot Dvojí uvolnění paměti Zápis mimo paměť Přepis paměti Zápis do paměti kterou jsme nealokovali
Debugování za běhu 10 - valgrind Nejlepší je, že valgrind nám i ukáže proč k chybě došlo! Například pokud zapisujeme do předtím uvolněné paměti tak nám i ukáže místo kde jsme jí uvolnili Pokud zapisujeme mimo alokovanou oblast tak nám ukáže o kolik jsme se přepsali a kde máme zaalokovat více místa
Debugování za běhu 11 - valgrind Dalším skvělým modulem je kontrola memory-leaků Stačí spusti valgrind s jinou volbou valgrind --leak-check=full ( název programu ) Valgrind nám nyní ukáže všechnu paměť kterou jsme alokovali ale neuvolnili a taky paměť na kterou se již nemůžeme dostat
Debugování za běhu 12 Pozitiva + Máme mnohem více informací +Můžeme ovlivňovat chování programu +Valgrind ;) Negativa - Běh s debbugerem je mnohonásboně náročnější než bez debbugeru
IDE Další věc která se pro debugování hodí jsou různá IDE Z vlastní zkušeností můžu doporučit Eclipse s pluginem pro C/C++ Další skvělý nástroj je KDevelop který v sobě integruje strace/GDB/valgrind a spoustu dalších užitečných věcí
Shrnutí Pokud jsem si jistý, že v programu už nemám chybu tak mi stačí ladění z coredumpu Pokud potřebuju ladit intenzivně tak nechám běžet program pod debbugerem
Děkuji za pozornost