Syntax highlighting of Archiv/Ladění pod UNIXEM - gdb, mtrace

==Programy a chyby==
Téměř každý program má svoje chyby. Chyby mohou být jak v návrhu(program tak jak je naržen nefunguje správně),
tak v realizaci (chyby v kódu). Praktičtější je ovšem chyby rozdělit na chyby "aktivní" a pasivní. Do první 
skupiny patří chyby patrné na první pohled, tj. program nedělá to co má, nebo padá. Do druhé skupiny patří typicky
chyby v alokaci a uvolňování paměti. Druhou skupinu je výrazně obtížnější jak detekovat, tak odhalit.
===Fáze ladění kódu===
Vytváření a aldění nového software vpostatě probíhá podle následujícího shématu:
 DOPSAL JSEM SOFTWARE                                                                   
 TESTUJU HO                                                                             
 if (V PROGRAMU JE CHYBA) goto ZACATEK LADENI else goto KONEC                           
  ZACATEK LADENI                                                                       
  STABILIZUJ CHYBU //zajisteni aby se chyba opakovala                                  
  LOKALIZUJ CHYBU  //nalezeni příslušné knihovny, funkce, řádku, kde k chybam dochazi  
  OPRAV CHYBU                                                                          
 goto TESTUJ HO                                                                       
 KONEC //program je odladěný a můžeme začít s distribucí.

===Možnosti ladění kódu===
====Expertní čtení====
Nejjednosušší je tzv "expertní čtení", aneb "Strécu, ono to nefacha, tak se do toho hleď ještě mrknout.". Tohle je jistě
možnost, ale má nevýhodu zejména psychologickou, pokud jsme udělali logickou chybu v návrhu, je poměrně těžké ji 
odstranit jen čtením kódu, protože se ném kód zdá v pořádku. Je to (prý) poměrně funkční v případě, že kód po nás čte 
někdo jiný.
====Ladící výpisy====
Asi nejobecnější možnost ladění, funguje skoro vždy a skoro všude. Je dobré vypisovat na stderr, pač jinak pokud 
něco vypíšete na stdin a program pak "spadne", hláška se může v principu stratit (neměla by, ale experimentálně je 
tohle tvrzení ověřené).
Do programu je možné zařadit výpisy na místa, kde čekáme, že by mohlo dojít k chybě.
Docela rozumné může být využít makroprocesoru překladače, napřiklad konstrukcí 

 #ifdef DEBUG
   printf ("hodnota x je : %d\n", x);
 #endif

a makro DEBUG si definovat třeba při překladu

 $ cc -o sorter -DDEBUG main.c
A jinak v jazyce c/c++  jsou k dispozici makra
{| border=1 cellspacing=0 cellpadding=5
| __LINE__
| Číslo aktuální řádky
|-
| __FILE__
| Jméno souboru
|- 
| __DATE__
| datum, Řetězec formátu "Mmm dd yyyy"
|-
| __TIME__
| čas, Řetězec formátu "h h : mm : s s"
|-  
|}

====Ladící nástroje====
Jsou asi neúčinnější formou ladění, (pokud jsou dostupné), pod unixovými systémy je obvykle k dspozici pro ladění 
chyb, které se projevují db, který má pod linuxem obdobu gdb. Na skryté chyby, např v alokaci paměti jsou k dispozici
nástroje typu mtrace, nebo knihovna electric fence (možná pár slov na konci).
Program gdb nám umožňuje pozorovat co se děje v "programu vevnitř", popřípadě toto dokonce měnit.
==Ukázkový příklad 1.==
main.c

 #include <stdio.h>
 #include <stdlib.h>
 #include "qsort.h"
 int main(int argc, char ** argv){  
  int i;
  int cisla[] = {10, 12, 2, 4, 8,7, 1, 20, 3, 25};
  int *  cilsa;
  int arrsize = sizeof(cisla) / sizeof(int); 
  printf("\n\nhello, Im Program for sorting.. ");
  
  printf("\nthis is my input  :");
  for (i=0; i < arrsize; i++){
    printf("%d ",cisla[i] );
  }
  //tady se to celý děje.
  xquickSort(cilsa,  arrsize);
  
  printf("\nthis is my output :");
  
  for (i=0; i < arrsize; i++){
    printf("%d ",cisla[i] );
  }
  printf("\nDo you think it's OK?\n");
  return 0;
 }

qsort.c
 void xq_sort(int numbers[], int left, int right){
  int pivot, l_hold, r_hold;
  l_hold = left;
  r_hold = right;
  pivot = numbers[left];
  while (left < right)
  {
    while ((numbers[right] >= pivot) && (left < right))
      right--;
    if (left != right)
    {
      numbers[left] = numbers[right];
      left++;
    }
    while ((numbers[left] <= pivot) && (left < right))
      left++;
    if (left != right)
    {
      numbers[right] = numbers[left];
      right--;
    }
  }
  numbers[left] = pivot;
  pivot = left;
  left = l_hold;
  right = r_hold;
  if (left < pivot)
    xq_sort(numbers, left, pivot-1);
  if (right > pivot)
    xq_sort(numbers, pivot+1, right);
 
 }

qsort.h

 extern void xquickSort(int numbers[], int array_size);
Makefile

 EXECUTABLE	        = sorter 
 SOURCES		= main.c qsort.c
 HEADERS		= qsort.h
 OBJECTS		= $(SOURCES:.c=.o)
 CC		        = gcc
 CFLAGS		        = -ggdb -Wall
 LDFLAGS		= -o 
 all: $(EXECUTABLE) 
 clean:
       rm *.o $(EXECUTABLE) 
 $(EXECUTABLE): $(OBJECTS)
       $(CC) $(LDFLAGS) $@ $^
 $(OBJECTS): $(SOURCES) $(HEADERS)


==Překlad programu==
Program se nám přeloží bez chyb nebo varování. Je dobré poznamenat,že program je dobé přeložit s parametrem 
 -g, 
nebo pro gdb ještě lépe 
 -ggdb nebo -ggdb3
. Ty volby se liší ve formátu ladících informací vkládaných do souboru.  Do programu takto budou vkládat i některé informace "navíc",které ladícímu prostředku umožní sledovat hromadu věcí, jako jsou třeba jména proměnných a podobně
Mimo jiné by šlo ještě poznamenat, že pokud program nechodí tak jak má je dobré ho přeložit s volbou 
 -Wall -pedantic -ansi
, které nám mohou pomoci odhalit i některé neobyklé konstrukce, často chyby.

== Nástroj gdb ==
gdb je program pro ladění jiných programů. Programy jdou spustit jakoby "v něm". Někdo tvrdí, že je gdb 
nepřekonatelné... Já bych byl střízlivšjší, pro člověka, který není líný se něco naučit, a je schopen
překonat deprese z příkazové řádky je to mocný nástroj.
=== Co umožňuje gbd ===
Ladit přeložené programy, zkoumat core-dumpy a připojovat se k běžícím programům. Poslední možnost je docela praktická zvlástě pokud chceme ladit třeba serverové aplikace.

=== Co se děje při startu gdb ===
Než začnu rozebírat přikazy pro gdb, pár slov k tomu, co se děje při startu gdb.
#1gdb se rozběhne v příslušném módu (třeba s gui, nebo v módu silent).. (o gui nic netuším ,ale je to v manuálu)přečte si konfigurák v $HOME
#2zpracuje argumenty příkazové žádky
#přečte si konfigurák v aktuálním adresáři
#načte histotii příkazů pokud ji máme zapnutou

=== Konfigurační soubor ===
A teď k tomu konfiguráku: na linuxu se jemnuje vždycky stejně, .gdbinit a dá se do něj nacpat spoooousta zajímavejch věcí.
No třeba ta historie :

 set history filename ./.gdb_history
 set history save on 

Docela dobry je si do konfiguraku v daném adresáři dát který soubor bude laděn
 file ./sorter

Nebo preloudované knihovny
 set env LD_PRELOAD=/usr/lib/libefence.so

Nebo breakpointy
 b main

Dají se tem taky definovat makra, ale to je jiná kapitola.
Komentáře jsou jako ve skriptech - uvozené #

=== Spuštění gdb ===
celá ta nádhera se spustí pomocí příkazu gdb. Volby jsou následující :
{| border=1 cellspacing=0 cellpadding=5
| -s file
|Ze souboru file se načte tabulka symbolů 
|-
| -e file
|Soubor file bude laděn , možno kombinovat se s.
|-
| -c N
|Gdb se připojí k již běžícímu procesu s PID N 
|-
| -c file
|Gdb načte core soubor file 
|-
| -x file
|Gdb vykoná gdb příkazy v souboru file, něco jako možnost skriptování 
|-
| -d dir
|K adresářům, v nichž gdb hledá zdrojové kódy přidá dir 
|-
| -m
|Načte symboly do souboru, který pak používá jako tabulku symbolů 
|-
| -r
|Načte všechny symboly okamžitě, místo čtení až v případě potřeby 
|-
| -n,-nx
|GDB nevykoná žádné příkazy z inicializačních souborů
|-
| -q
|Nevytiskne po spuštění úvodní text a informace o copyrightu 
|-
| -batch
|Po vykonání příkazů v souboru -x file vrátí 0, při chybě vrátí nenulové číslo 
|-
| -cd dir
|Změní aktuální adresář na dir 
|-
| -f
|Vypisuje plné jméno souboru a číslo řádky vždy při zastavení programu 
|-
| -b bps
|Nastaví rychlost seriového portu na bps pro vzdálené ladění 
|-
| -tty dev
|Přesměruje stdout a stdin laděného programu na dev 
|}
Kdo jste chodila na základy překladačů tak určitě víte co jsou to tabulky symbolů.
Je to taková ta chztrá věc, která pojí to jak se proměnná jmenuje, a to jakou má hodnotu.
Docela fajn věc pro takové ladění.

Jinak většinou budete startovat gdb příkazem
 gdb file
, kde file je jméno laděného programu.

=== Příkazy v gdb ===
No a teď zvesela na všechny možný příkazy a fíčury gdb.
příkazy se zadávají ručně a gdb si je kompletuje, tj, pokud stisknete 
 h
a 
 help 
je jediný příkaz začínající na h
tak to gdb pochopí. Pokud mu dáváte ještě vybrat,tj. je víc příkazu začínající danou sadou znaků, tak  gdb vypíše možnosti.

=== Příkaz help ===
První příkaz, který je dobrý znát je vyvolání helpu. 
help se vyvolá třeba 
 h
Tenhle příkaz vypíše seznam všech skupin do kterých jsou příkazy dělené. 
 h <skupina> 
zobrazí příkazy ve skupině.
 h <prikaz>  
zobrazí krátký popis příkazu.
Ukázka:
Chceme se dozvědět jak se nastavuje breakpoint na nějakou řádku.
 (gdb) h
 aliases -- Aliases of other commands
 breakpoints --
 ....
 (gdb) h breakpoints
 awatch -- Set a breakpoint for an expression
 break -- Set a breakpoint at specified line or function
 ....
 (gdb) h break
nám vrátí podrobný popis jak dát breakpoint na řádku

=== Příkazy k použití pro započetí ladění ===
Pokud už nám gdb běží (a nespustili jsme ho gdb file) tak musíme specifikovat co se vlastně bude ladit.

{| border=0 cellspacing=0 cellpadding=5
|exec-file file
|otevře file pro ladìní 
|-    
|core-file file
|otevře core file
|- 
|attach pid
|připojí se k procesu pid 
|}

Programu je možné nastavit argumenty a pracovní adresář.

{| border=0 cellspacing=0 cellpadding=5
|set arg
|nastaví argumenty programu
|- 
|show arg
|zobrazí argumenty programu
|- 
|set environment
|nastaví promìnné prostředí
|- 
|show environment
|zobrazí promìnné prostøedí 
|-
|cd dir
|nastaví adresář dir jako aktuální 
|-
|pwd
|zobrazí aktuální adresář
|}

A potom už mùžeme program vesele spustit, a ladit daný program.

{| border=0 cellspacing=0 cellpadding=5
|run
|spustí program 
|}


Ukázka:

 (gdb) exec-file sorter
 (gdb) set arg Evzen
 (gdb) cd ../
 (gdb) run   
Poznámka: když jsem tohle zkoušel tak se mi to jevilo, jako když gdb nenašel v souboru  ladící informace,pokud byl spuštìn bez argumentù a pak mu byl dán pøíkaz exec-file.Že by bug v debuggeru :-) ???

=== Breakpointy, watchpointy a jiné zastavování běhu programu ===
Preakpointy a watchpointy jsou místa, kde si přejeme program zastavit. 
Breakpointy jsou nastavení na nějakou funkci nebo řádek, zatímco watchpointy se vztahují k nějakým proměnným.
Co je zajímavý rozdíl, je jak je debugovaní pomocí watchpointù a breakpointů  realizované zevnitř. 
Obě skupiny mohou být realizovány hardwarově a softwarově. Hardwarové řešení vyžaduje podporu hardware, aproto není možné ho zapnout vždy.(softwarově znamená, že do programu je vložena nějaká instrukce, což samo o sobì mùže být značně nežádoucí )Pro hardwarové wp jsou
poměrně značné omezení, protože využívali registry, mohou být jen dva a to ještì stejného typu. 

==== Breakpointy ====
{| border=1 cellspacing=0 cellpadding=5
|break, b
|    nastaví bp na další řádku od aktuální v daném podprogramu (funkci) 
|-
|b funct
|    nastaví bp na funkci "funct" 
|-
|b N
|    nastaví bp na řádek N ve zdrojovém kódu 
|-
|b +N, -N
|    nastaví bp o N řádek dopředu / dozadu od aktuální řádky 
|-
|b file:funct
|    nastaví bp na funkci funct definovanou v souboru file 
|-
|b file:N
|    nastaví bp na řádek N v souboru file 
|-
|b *addr
|    nastaví bp na adresu addr (tohle ja praktické, zvlášť pokud Vás něco vede k ladění programu,přeloženého bez -g)
|-
|b if cond
|    nastaví podmíněný bp, tzn. bp zastaví běh programu, pouze je-li splněna podmínka cond
|-
|tbreak args
|    nastaví bp se stejnými argumenty jako výše, ale pouze na jedno použití, pak je bp vymazán 
|-
|hbreak args
|    nastaví hardwarový bp, hw bp musí být podporován hardwarem, oproti klasickému bp nemění 
instrukci, na které je nastaven
|- 
|thbreak args
|    hardwarový tbreak
|- 
|rbreak regex
|    nastaví bp na všechny funkce, které vyhovují výrazu regex, dodatečně je možno doplnit podmínky a příkazy
|- 
|info breake [n]
|    zobrazí všechny bp a jejich případné podmínky, je-li specifikováno číslo bp, zobrazí informace pouze o něm
|- 
|}

==== Watchpointy ====
K zastavení programu kdykoliv při změně nějaké proměnné je možno použít tzv. watchpointy.
{| border=1 cellspacing=0 cellpadding=5
|watch expr
|    vytvoří wp pro proměnnou expr; gdb zastaví program, kdykoli se obsah proměnné expr změní 
|-
|rwatch expr
|     program je zastaven, kdykoli je proměnná expr čtena 
|-
|awatch expr
|     program je zastaven při jakémkoli přístupu k proměnné (r/w) 
|-
|info watchpoints
|    zobrazí iformace o všech wp, je-li specifikováno číslo wp, vypíše informace pouze o něm 
|}
==== Vyjímky ====

Program je možno zastavit i při volání obsluhy výjimky
{| border=1 cellspacing=0 cellpadding=5
|catch exeptions
|    nastaví bp na aktivní obslužné rutiny výjimek, jejichž jména jsou v seznamu exeptions 
|-
|info catch
|    vypíše všechny aktivní obslužné rutiny vyjímek 
|}

=== Podmínky pro breakpointy, příkazy pro breakpointy ===
=== Zpráva breakpointů (vymazání, disalování) ===
=== Krokování programu ===
=== Zobrazení zdrojového kódu přímo v programu gdb ===
=== Zobrazování kódu programu v asembleru ===
=== Zkoumání obsahu paměti programu ===
==== Formát dat ====
==== Délky datové buňky ====
==== Zobrazování hodnot proměnných (print) ====
==== Automatické zobrazování hodnot proměnných (display) ====
==== Přímý přístup k datům (x, eXamine) ====
=== Práce s daty na zásobníku, trasování ===
=== Ladění proramu v asembleru -pro labužníky ===
=== Proměnné ===
=== Definování maker ===
=== Ukázka session -odladění vzorového příkladu ===