Hlavní navigace

Trasování a ladění nativních aplikací v Linuxu: použití GDB a jeho nadstaveb

24. 5. 2016
Doba čtení: 22 minut

Sdílet

 Autor: Shutterstock.com
Dnes se seznámíme s některými možnostmi GNU Debuggeru (GDB). Nad tímto všestranně nástrojem vzniklo i mnoho různých nadstaveb s TUI a samozřejmě i s GUI. O některých se stručně zmíníme.

Obsah

1. Trasování a ladění nativních aplikací v Linuxu: použití GDB a jeho nadstaveb

2. GNU Debugger

3. Orientace v laděném kódu

4. Spuštění programu, nastavení breakpointů a krokování

5. Parametry breakpointů

6. Výpis obsahu zásobníkových rámců

7. Ladění aplikací, které zhavarovaly

8. Demonstrační příklady použité v dnešním článku

9. Nadstavby na GNU Debuggerem

10. cgdb

11. Data Display Debugger – DDD

12. Nemiver

13. KDbg

14. Emacs

15. Odkazy na Internetu

1. Trasování a ladění nativních aplikací v Linuxu: použití GDB a jeho nadstaveb

V první části článku o nástrojích, které je možné použít pro trasování a popř. i pro plnohodnotné ladění nativních aplikací běžících v Linuxu, jsme se seznámili s jednoduše použitelnými nástroji nazvanými ltrace a strace. Připomeňme si, že nástroj ltrace slouží k trasování volání knihovních funkcí (s různými možnostmi filtrace, měření atd.) a strace se naopak používá pro trasování volání funkcí jádra (syscalls). Kromě toho jsme si řekli základní informace o pokročilém (a již složitěji ovládaném) nástroji nazvaném SystemTap, s jehož možnostmi se blíže seznámíme v následujícím článku. Připomeňme si též, jak může vypadat použití jednotlivých nástrojů na celém „stacku“, tj. od trasování/ladění samotné uživatelské aplikace až přes řešení problémů přímo v jádře operačního systému:

+----------+
|          |..... gdb
| aplikace |
|          |..... SystemTap
+----------+
     |
     |
     |...... ltrace
     |
     v
+----------+
|          |..... gdb
|  glibc   |
|          |..... SystemTap
+----------+
     |
     |
     |...... strace
     |
     v
+----------+
|          |..... SystemTap
|  jádro   |
|          |..... KGDB
+----------+

Vidíme, že dnes popisovaný GNU Debugger je možné použít jak na úrovni ladění aplikace, tak i knihoven. Kromě toho ho lze využít i pro „pitvu“ těch nativních aplikací, které byly kvůli nějakému problému zabity jádrem systému a byl pro ně vygenerován takzvaný „core dump“.

2. GNU Debugger

Nástroj GNU Debugger, který je taktéž někdy podle své spustitelné (binární) části pojmenováván gdb, primárně používá ke komunikaci s uživatelem příkazový řádek, ale alternativně lze použít i jednoduché TUI (textové uživatelské rozhraní) či protokol pro nepřímé ovládání debuggeru a v případě potřeby je možné k laděné aplikaci přidat relativně krátký „stub“ sloužící pro přímé ladění takové aplikace (touto nepochybně zajímavou problematikou se však dnes nebudeme zabývat). Většina často používaných příkazů zapisovaných na příkazový řádek má i svoji zkrácenou podobu (bt=backtrace, c=continue, f=frame) a navíc je možné používat klávesu [Tab] pro automatické doplnění celého jména příkazu či jeho parametru (doplňování je kontextové). Pokud je správně nastavený terminál, bude fungovat i historie příkazového řádku, a to stejným způsobem, jaký známe ze shellu. Alternativně je možné využít gdbtui s celoobrazovkovým výstupem a alespoň částečně se tak přiblížit možnostem debuggerů s plnohodnotným grafickým uživatelským rozhraním.

Podívejme se nyní na způsob spuštění GNU Debuggeru a práce s ním. Nejprve si připravíme testovací aplikaci, kterou pro jednoduchost naprogramujeme v céčku (a nikoli v C++ – to kvůli jménům funkcí):

#include <stdio.h>
 
void print_hello()
{
    puts("Hello world!");
}
 
int main(int argc, char **argv)
{
    print_hello();
    return 0;
}

Zdrojový kód uložíme do souboru nazvaného hello.c a přeložíme s volbou -g, která zajistí vložení potřebných ladicích symbolů do výsledného binárního (spustitelného) souboru:

gcc -g -ansi -pedantic -Wall -o hello hello.c

Následně již můžeme spustit GNU Debugger:

gdb hello
 
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 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-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello...done.

Povšimněte si především posledního řádku, ve kterém debugger potvrzuje načtení ladicích symbolů. Pokud se v tomto řádku zobrazí text:

(no debugging symbols found)

znamená to, že jste pravděpodobně při překladu zapomněli použít volbu -g, popř. se na již přeložený soubor použila utilita strip, která symboly odstranila.

GNU Debugger obsahuje i poměrně rozsáhlý systém nápovědy, který si můžeme vyzkoušet:

(gdb) help
List of classes of commands:
 
aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands
 
Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous.

Ukončení GNU Debuggeru zajišťuje příkaz quit zkracovaný na pouhé q:

(gdb) q

Pro úplnost se ještě podívejme, jak vypadá TUI (textové uživatelské rozhraní) zabudované do GNU Debuggeru:

gdbtui hello
 
 
 
   +--hello.c-----------------------------------------------------------------------------+
   |1       #include <stdio.h>                                                            |
   |2                                                                                     |
   |3       void print_hello()                                                            |
   |4       {                                                                             |
   |5           puts("Hello world!");                                                     |
   |6       }                                                                             |
   |7                                                                                     |
   |8       int main(int argc, char **argv)                                               |
   |9       {                                                                             |
   |10          print_hello();                                                            |
   |11          return 0;                                                                 |
   |12      }                                                                             |
   |13                                                                                    |
   |14                                                                                    |
   |15                                                                                    |
   |16                                                                                    |
   +--------------------------------------------------------------------------------------+
exec No process In:                                                      Line: ??   PC: ??
<http://www.gnu.org/software/gdb/documentation/>
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello...done.

V základním nastavení je terminál rozdělen do dvou oken – první okno obsahuje zdrojový kód, druhé pak klasické rozhraní příkazového řádku. Ve skutečnosti je však možné zobrazit i další okna, například speciální okno s registry atd. V okně se zdrojovým kódem se navíc zobrazují breakpointy a další důležité informace, takže „režim TUI“ může být pro mnohé vývojáře velmi užitečný (dokonce si dovolím říct, že je časově výhodnější se naučit pracovat v tomto režimu, než řešit problémy s různými GUI nadstavbami).

3. Orientace v laděném kódu

Pokud jsou do binárního souboru laděné aplikace přiloženy i ladicí symboly, lze v GNU Debuggeru relativně snadno pracovat přímo se zdrojovým kódem a využívat jména funkcí, jména proměnných atd. Základním příkazem, který se může hodit například při nastavování breakpointů, je příkaz info functions, který vypíše jak všechny funkce z aplikace, tak i přímo či nepřímo volané funkce (pro zápis tohoto příkazu použijte klávesu [Tab] pro kontextové doplňování):

(gdb) info functions
All defined functions:
 
File hello.c:
int main(int, char **);
void print_hello();
 
Non-debugging symbols:
0x00000000004003e0  _init
0x0000000000400410  puts@plt
0x0000000000400420  __libc_start_main@plt
0x0000000000400430  __gmon_start__@plt
0x0000000000400440  _start
0x0000000000400470  deregister_tm_clones
0x00000000004004a0  register_tm_clones
0x00000000004004e0  __do_global_dtors_aux
0x0000000000400500  frame_dummy
0x0000000000400560  __libc_csu_init
0x00000000004005d0  __libc_csu_fini
0x00000000004005d4  _fini

Dalším užitečným příkazem je příkaz list, který vypíše deset řádků zdrojového kódu. Opakováním příkazu (či pouhým stlačením klávesy Enter, což má stejný význam, jako explicitní opakování posledního příkazu) se zobrazí dalších deset řádků atd.:

(gdb) list
1       #include <stdio.h>
2
3       void print_hello()
4       {
5           puts("Hello world!");
6       }
7
8       int main(int argc, char **argv)
9       {
10          print_hello();

K příkazu list je možné explicitně přidat i číslo prvního a posledního vypisovaného řádku, což je výhodné v případě, že z nějakého chybového hlášení víte, na kterém řádku k chybě došlo:

(gdb) list 1,12
1       #include <stdio.h>
2
3       void print_hello()
4       {
5           puts("Hello world!");
6       }
7
8       int main(int argc, char **argv)
9       {
10          print_hello();
11          return 0;
12      }

Užitečnější je však použití příkazu list společně se jménem funkce, protože nemusíte složitě zjišťovat, na jakém řádku je hledaná funkce zapsána (ani v jakém je souboru):

(gdb) list main
4       {
5           puts("Hello world!");
6       }
7
8       int main(int argc, char **argv)
9       {
10          print_hello();
11          return 0;
12      }
13

Pokud chcete jméno funkce vybrat ze seznamu, stačí napsat jen příkaz list, mezeru a potom stlačit klávesu [Tab]:

_IO_stdin_used
__JCR_END__
__JCR_LIST__
__libc_csu_fini
__libc_csu_init
__libc_start_main
__libc_start_main@got.plt
__libc_start_main@plt
long int
long unsigned int
main
print_hello
puts
puts@got.plt
puts@plt
register_tm_clones
short int
short unsigned int
signed char
sizetype
_start
__TMC_END__
unsigned char
unsigned int
(gdb) list 

Samozřejmě funguje i vyhledávání na základě částečně zapsaného jména funkce:

__libc_csu_fini            __libc_start_main@got.plt
__libc_csu_init            __libc_start_main@plt
__libc_start_main
(gdb) list __libc_

Užitečné mohou být i další varianty příkazu info:

(gdb) info sources
Source files for which symbols have been read in:
 
/home/tester/temp/presentations/tracing/hello.c
 
Source files for which symbols will be read in on demand:
(gdb) info sharedlibrary 
From                To                  Syms Read   Shared Object Library
0x00007ffff7ddaae0  0x00007ffff7df54e0  Yes (*)     /lib64/ld-linux-x86-64.so.2
(*): Shared library is missing debugging information.

4. Spuštění programu, nastavení breakpointů a krokování

Nyní se podíváme na způsob spuštění laděné aplikace přímo v GNU Debuggeru. To je ve skutečnosti velmi jednoduché a přímočaré, protože postačuje zadat příkaz run či jen r:

(gdb) run
Starting program: /home/tester/temp/presentations/tracing/hello
Hello world!
[Inferior 1 (process 6977) exited normally]

Na libovolnou funkci, řádek či dokonce jednotlivou strojovou instrukci je možné zaregistrovat breakpoint. Pokud se běh programu dostane na breakpoint, je jeho běh přerušen a řízení se vrátí zpět uživateli do debuggeru. Nejjednodušeji se nastavuje breakpoint na vstupním bodě funkce. V tomto případě postačuje zadat příkaz break se jménem funkce:

(gdb) break main
Breakpoint 1 at 0x40054c: file hello.c, line 10.

Pokud nyní program znovu spustíme, zastaví se na právě nastaveném breakpointu:

(gdb) run
Starting program: /home/tester/temp/presentations/tracing/hello
 
Breakpoint 1, main (argc=1, argv=0x7fffffffe158) at hello.c:10
10          print_hello();

Nyní máme možnost pokračovat v běhu (c/continue), ale zajímavější je použít příkaz n/next, který vykoná pouze jediný programový řádek a posléze se běh programu opět zastaví:

(gdb) n
Hello world!
11          return 0;
(gdb) c
Continuing.
[Inferior 1 (process 7040) exited normally]

O tom, že GNU Debugger není žádné ořezávátko, možná svědčí i to, že se v průběhu ladění může použít mj. i příkaz print akceptující různé typy výrazů, lokální i globální proměnné, formátování atd.:

(gdb) print(i)
$1 = 30
 
(gdb) print(argc>0)
$2 = 1
 
(gdb) print(atoi("42"))
$3 = 42
 
(gdb) print(isdigit('4'))
$4 = 2048
 
(gdb) print(isdigit('a'))
$5 = 0

Všechny doposud popsané příkazy si otestujme na jiném (nepatrně složitějším) zdrojovém kódu, v němž se nachází funkce pro výpočet faktoriálu:

#include <stdio.h>
 
short factorial(short n)
{
    if (n==0 || n==1) return 1;
    return n*factorial(n-1);
}
 
int main(int argc, char **argv)
{
    printf("%d\n", factorial(8));
    return 0;
}

Výpis části zdrojového kódu:

(gdb) list
2
3       short factorial(short n)
4       {
5           if (n==0 || n==1) return 1;
6           return n*factorial(n-1);
7       }
8
9       int main(int argc, char **argv)
10      {
11          printf("%d\n", factorial(8));

Nastavení breakpointu:

(gdb) break factorial
Breakpoint 1 at 0x40053b: file factorial.c, line 5.

Spuštění programu a výpis parametru funkce po zastavení na breakpointu:

(gdb) run
Starting program: /home/tester/temp/presentations/tracing/factorial
 
Breakpoint 1, factorial (n=8) at factorial.c:5
5           if (n==0 || n==1) return 1;
(gdb) print(n)
$1 = 8

Pokračování v běhu programu a opětovný výpis parametru funkce:

(gdb) continue
Continuing.
 
Breakpoint 1, factorial (n=7) at factorial.c:5
5           if (n==0 || n==1) return 1;
(gdb) print(n)
$2 = 7

Odstranění breakpointu:

(gdb) clear main
Deleted breakpoint 1
(gdb) run
Starting program: /home/tester/temp/presentations/tracing/a.out
Hello world!
[Inferior 1 (process 7876) exited normally]

5. Parametry breakpointů

U breakpointů je možné nastavovat různé parametry a především podmínky ovlivňující, za jakých okolností se breakpoint projeví a za jakých nikoli. Nejprve si opět nastavme breakpoint na vstupní bod funkce nazvané factorial:

(gdb) break factorial
Breakpoint 1 at 0x40053b: file factorial.c, line 5.

Informaci o všech breakpointech získáme příkazem info breakpoints:

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000040053b in factorial at factorial.c:5

Vidíme, že náš breakpoint je uložen na indexu 1. Nastavme nyní tento breakpoint takovým způsobem, aby ignoroval prvních pět průchodů, tedy část „winding“ fáze rekurzivní funkce factorial:

(gdb) ignore 1 5
Will ignore next 5 crossings of breakpoint 1.
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000040053b in factorial at factorial.c:5
        ignore next 5 hits

Pozor: pokud se breakpoint zobrazil pod jiným číslem, je nutné příkaz ignore n 5 upravit tak, aby se použilo správné n.

Pokud aplikaci nyní spustíme, bude se chovat odlišně, protože se zastaví až ve chvíli, kdy je hodnota n rovna třem a nikoli osmi:

(gdb) r
Starting program: /home/tester/temp/presentations/tracing/factorial
 
Breakpoint 1, factorial (n=3) at factorial.c:5
5           if (n==0 || n==1) return 1;

6. Výpis obsahu zásobníkových rámců

V tomto okamžiku si můžeme vypsat historii volání, a to příkazem backtrace popř. jeho zkrácenou variantou bt:

(gdb) bt
#0  factorial (n=3) at factorial.c:5
#1  0x000000000040055f in factorial (n=4) at factorial.c:6
#2  0x000000000040055f in factorial (n=5) at factorial.c:6
#3  0x000000000040055f in factorial (n=6) at factorial.c:6
#4  0x000000000040055f in factorial (n=7) at factorial.c:6
#5  0x000000000040055f in factorial (n=8) at factorial.c:6
#6  0x0000000000400583 in main (argc=1, argv=0x7fffffffe158) at factorial.c:11

Vidíme, že se skutečně ještě nacházíme ve „winding“ fázi funkce factorial. Historii je nutné číst odspodu, což je logické, protože bt získává informace z obsahu zásobníkových rámců vytvářených pro každou volanou funkci.

Pokud nepotřebujete zobrazit celou historii, ale jen posledních n volání, stačí zadat bt s požadovaným počtem řádků:

(gdb) bt 4
#0  factorial (n=3) at factorial.c:5
#1  0x000000000040055f in factorial (n=4) at factorial.c:6
#2  0x000000000040055f in factorial (n=5) at factorial.c:6
#3  0x000000000040055f in factorial (n=6) at factorial.c:6
(More stack frames follow...)

Začátek historie se naopak zobrazí po zadání záporného čísla:

(gdb) bt -4
#3  0x000000000040055f in factorial (n=6) at factorial.c:6
#4  0x000000000040055f in factorial (n=7) at factorial.c:6
#5  0x000000000040055f in factorial (n=8) at factorial.c:6
#6  0x0000000000400583 in main (argc=1, argv=0x7fffffffe1c8) at factorial.c:11

Pro zobrazení zásobníkových rámců společně s lokálními proměnnými použijte bt full (to však u naší jednoduchoučké funkce postrádá význam).

7. Ladění aplikací, které zhavarovaly

GNU Debugger může být velmi užitečný i v těch případech, kdy je zapotřebí zjistit příčinu havárie nějakého programu. Jádro operačního systému totiž může ještě před úplným ukončením procesu uložit do speciálního souboru nazvaného core dump jak obsah paměti přiřazené procesu, tak i další údaje související s jeho aktuálním stavem – obsahy pracovních registrů, stav otevřených souborů apod. (tyto informace jsou do značné míry závislé na architektuře i na použitém operačním systému). Mimochodem termín „core dump“ vznikl v dobách používání feritových pamětí, protože jadérka v těchto pamětech si pamatovala svůj obsah tak dlouho, že po pádu aplikace (žádný skutečný operační systém ještě neexistoval, většinou se jednalo o pouhý loader uživatelského kódu) bylo možné její obsah v klidu prozkoumat. Nicméně se vraťme k současným core dumpům. Jeden si vytvoříme, a to tímto jednoduchým (zabugovaným) prográmkem:

void set_mem(int *address, int value)
{
    *address = value;
}
 
int main(int argc, char **argv)
{
    set_mem((int*)0, 42);
    return 0;
}

Program přeložíme běžným způsobem:

gcc -g -Wall -ansi -pedantic npe.c

A pokusíme se ho spustit běžným způsobem z příkazové řádky:

./npe 
Segmentation fault

Pokud se vypíše pouze „Segmentation fault“, znamená to, že se core dump ve skutečnosti nevytvořil. Zkusíme tedy systému pomoci povolením vytváření core dumpů o neomezené velikosti:

ulimit -c unlimited
./npe 
Segmentation fault (core dumped)

Teď už je to lepší (viz text v závorce) – vytvořil se core dump, který můžeme prozkoumat. GNU Debugger je nutné spustit takovým způsobem, že se specifikuje jak jméno spustitelného souboru, tak i jméno souboru s core dumpem (v uvedeném pořadí):

gdb npe core

Zajímavé je, že se při spouštění GNU Debuggeru vypíšou odlišné informace, které však poměrně přesně říkají, co se stalo. Proč se to stalo, to je již otázkou na samotného programátora:

Reading symbols from npe...done.
[New LWP 7703]
Core was generated by `./npe'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00000000004004ff in set_mem (address=0x0, value=42) at npe.c:3
3           *address = value;

GNU Debugger se nyní chová, jakoby byl program již spuštěný (což není náhoda), takže si můžeme nechat vypsat obsah zásobníkových rámců:

(gdb) bt
#0  0x00000000004004ff in set_mem (address=0x0, value=42) at npe.c:3
#1  0x0000000000400521 in main (argc=1, argv=0x7fff07ba7798) at npe.c:8

Můžeme nastavit breakpoint na začátek té funkce, v níž došlo k pádu. Jedná se o funkci nazvanou set_mem:

(gdb) b set_mem
Breakpoint 1 at 0x4004f8: file npe.c, line 3.

A program můžeme znovu spustit:

(gdb) r
Starting program: /home/tester/temp/presentations/tracing/npe

Běh laděné aplikace se podle očekávání zastaví na breakpointu:

Breakpoint 1, set_mem (address=0x0, value=42) at npe.c:3
3           *address = value;

Takže znovu prozkoumáme obsah zásobníkových rámců:

(gdb) bt
#0  set_mem (address=0x0, value=42) at npe.c:3
#1  0x0000000000400521 in main (argc=1, argv=0x7fffffffe168) at npe.c:8

Aha, adresa je nastavená nějak divně – zápis na adresu 0 skutečně povede k pádu (to je většinou ošetřeno na hardwarové úrovni, například nastavením práv k celé první stránce paměti přidělené aplikaci atd.):

(gdb) print address
$1 = (int *) 0x0

Skutečně, nyní již víme (což bylo v tomto případě velmi jednoduché), že chyba je ve funkci main, resp. v předání špatné adresy. Bez opuštění debuggeru si můžeme kód prohlédnout (osmý řádek):

(gdb) list main
2       {
3           *address = value;
4       }
5
6       int main(int argc, char **argv)
7       {
8           set_mem((int*)0, 42);
9           return 0;
10      }
11

Poznámka: ke složitějším situacím, stejně jako k ladění programů napsaných v C++ (kde je někdy nutné se zabývat překladem jmen funkcí a metod), se dostaneme příště.

8. Demonstrační příklady použité v dnešním článku

Všechny tři demonstrační příklady, které jsme používali při popisu GNU Debuggeru, byly opět uloženy do GIT repositáře nazvaného https://github.com/tisnik/pre­sentations:

9. Nadstavby na GNU Debuggerem

Práce s příkazovým řádkem GNU Debuggeru sice programátorům přináší velkou flexibilitu (a to jsme se prozatím seznámili pouze s nepatrnou částí celkové funkcionality), ovšem je pochopitelné, že některým uživatelům příkazová řádka nemusí vyhovovat. To však – alespoň teoreticky – nemusí být nepřekonatelným problémem, protože GDB je navržen takovým způsobem, aby se nad ním daly vytvářet různé nadstavby vybavené více či méně konformním textovým či grafickým uživatelským rozhraním. O nadstavbách vytvořených nad GNU Debuggerem jsem již napsal krátký seriál na „konkurenčním“ webu http://www.mojefedora.cz, takže si dnes o každé nadstavbě řekneme pouze základní informace (nejdůležitější informací je v době Googlu samozřejmě jméno nadstavby :-), zbytek se již dá dohledat na stránkách vývojářů toho kterého nástroje).

Obrázek 1: V minulosti velmi populární nástroj Turbo Debugger je vybaven celoobrazovkovým textovým uživatelským rozhraním (TUI) připomínajícím další produkty vytvořené společností Borland. Rozhraní a možnosti Turbo Debuggeru je stále možné považovat za etalon toho, jak by mohl vypadat moderní debugger s TUI či GUI.

10. cgdb

Nástroj nazvaný cgdb, o němž jsem se zmínil zde, je založený na knihovně curses resp. ncurses, tudíž ho je možné využít v terminálu, na stroji připojeném přes SSH atd. Ve svém základním nastavení nástroj cgdb rozděluje okno terminálu (konzole) na dvě části. V horní části je zobrazen zdrojový kód laděné aplikace a v části dolní pak rozhraní samotného GNU Debuggeru, které již známe. Mezi oběma částmi je možné se s využitím několika klávesových zkratek přepínat, přičemž je nutné poznamenat, že většinu složitějších příkazů je možné zadávat jen v rozhraní GNU Debuggeru. Horní část slouží zejména pro dobrou orientaci v laděném programu, pro zobrazení nastavených breakpointů (v základním nastavení je použita červená barva) a taktéž pro zobrazení místa, v němž se právě nachází laděný program (v základním nastavení je tento řádek zobrazen zeleně).

Obrázek 2: Ladění programu v cgdb. Na řádku 21 je nastaven breakpoint, proto je tento řádek zvýrazněn červeně. Řízení programu přešlo na řádek číslo 23 (zvýrazněno zeleně) a v dolní části si vývojář s využitím příkazu print vypsal obsah dvou lokálních proměnných.

11. Data Display Debugger – DDD

O nástroji nazvaném Data Display Debugger, který je známý i pod svojí zkratkou DDD, vznikl článek na serveru mojefedora.cz, takže si zde pouze ve stručnosti řekněme, že Data Display Debugger je nadstavbou nad GNU Debuggerem, která nabízí uživatelům při ladění aplikací plnohodnotné grafické uživatelské rozhraní, jehož jednotlivé ovládací prvky a jejich chování sice mohou působit zastarale (což je způsobeno použitou GUI knihovnou), ve skutečnosti je však celé uživatelské rozhraní Data Display Debuggeru velmi flexibilní, což vynikne především při použití dvou a více monitorů (to je dnes pro vývojáře asi standardní konfigurace). Příkladem flexibility GUI jsou například „odtrhávací“ menu (tear off menu), které je možné velmi snadno změnit na nemodální dialogy s nabídkou příkazů. Data Display Debugger lze využít i pro komunikaci s dalšími debuggery, například s debuggerem jazyka Perl, debuggerem skriptů psaných v BASHi a v neposlední řadě taktéž pro ovládání pydb, což je jeden z debuggerů používaných vývojáři používajícími programovací jazyk Python

Obrázek 3: Ukázka grafického uživatelského rozhraní programu Data Display Debugger. V horní části můžeme vidět okno se zdrojovým kódem, v prostřední části pak výpis odpovídajícího strojového kódu a spodní třetina GUI obsahuje klasický příkazový řádek GNU Debuggeru. K dispozici je i dialogové okno se základními a často používanými příkazy.

12. Nemiver

I o dalším nástroji pojmenovaném Nemiver již vyšel samostatný článek. Tento nástroj opět komunikuje s GNU Debuggerem, ovšem na rozdíl od DDD postaveného nad postarší GUI knihovnou je Nemiver primárně určený pro desktopové prostředí GNOME se všemi přednostmi a zápory, které to přináší. Nemiver tak uživatelům nabízí přehledné prostředí, které ovšem není tak flexibilní jako DDD a taktéž například možnosti zobrazení složitějších datových struktur (různých lineárně vázaných seznamů, stromů či obecnějších grafových struktur) jsou v Nemiveru omezené. Pokud ale někdo pouze potřebuje odkrokovat několik funkcí a neprovádět žádné složitější operace, může být tento nástroj pro takového uživatele dobrým řešením.

Obrázek 4: Ukázka grafického uživatelského rozhraní nástroje Nemiver při ladění uživatelské aplikace. V dolní části si povšimněte „oušek“ jednotlivých podoken.

13. KDbg

Pro „konkurenční“ desktopové prostředí KDE vznikl projekt nazvaný KDbg, který byl podrobněji zmíněn v tomto článku. KDbg vývojářům nabízí prakticky veškeré základní funkce, které jsou od debuggerů očekávány: nastavování breakpointů, nastavování watchpointů, krokování po jednotlivých příkazech, vstup do volaných funkcí, prohlížení obsahu operační paměti, prohlížení složitějších datových struktur apod. KDbg je ve skutečnosti opět nadstavbou nad klasickým GNU Debuggerem, což mj. znamená, že KDbg je možné v současné verzi použít pro ladění nativních aplikací naprogramovaných v jazycích Ada, C, C++, Go, Objective-C, D, Fortran, Modula-2, Pascal a Java (zde ovšem pouze při překladu do nativního strojového kódu). Nejpoužívanějšími jazyky laděných aplikací pravděpodobně zůstanou C a C++.

Obrázek 5: Ukázka grafického uživatelského rozhraní nástroje KDbg, opět při ladění uživatelské aplikace. Obsah levého spodního podokna je opět volitelný.

14. Emacs

Rozhraní pro GNU Debugger může být zabudováno i do různých pokročilejších programátorských editorů. Pravděpodobně nejlepší propojení s debuggerem nabízí textový editor Emacs. Používá se v něm knihovna Grand Unified Debugger, která mj. zajišťuje i propojení mezi textovým editorem GNU Emacs a debuggerem GNU Debugger. V tomto režimu je možné si v okně Emacsu zobrazit zdrojový kód a současně i několik bufferů obsahujících jak textové uživatelské rozhraní debuggeru (konzoli, která je aktivní, tj. lze do ní zapisovat příkazy), tak i speciální buffer s hodnotami pracovních registrů procesoru, další buffer se seznamem breakpointů, buffer se seznamem vláken atd. Kromě toho je možné (minimálně ve chvíli, kdy je Emacs spuštěn v prostředí grafického desktopu) otevřít další specializovaná okna, zejména okno s výpisem obsahu vybraných proměnných, obsahem bloku paměti, disassemblovaným kódem apod.

Obrázek 6: Nám již známý program nazvaný npe v průběhu jeho krokování a ladění v Emacsu (v režimu GNU Debuggeru).

15. Odkazy na Internetu

  1. Debuggery a jejich nadstavby v Linuxu
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/
  2. Debuggery a jejich nadstavby v Linuxu (2. část)
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/
  3. Debuggery a jejich nadstavby v Linuxu (3): Nemiver
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/
  4. Debuggery a jejich nadstavby v Linuxu (4): KDbg
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/
  5. Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/
  6. Tracing (software)
    https://en.wikipedia.org/wi­ki/Tracing_%28software%29
  7. ltrace(1) – Linux man page
    http://linux.die.net/man/1/ltrace
  8. ltrace (Wikipedia)
    https://en.wikipedia.org/wiki/Ltrace
  9. strace(1) – Linux man page
    http://linux.die.net/man/1/strace
  10. strace (stránka projektu na SourceForge)
    https://sourceforge.net/pro­jects/strace/
  11. strace (Wikipedia)
    https://en.wikipedia.org/wiki/Strace
  12. SystemTap (stránka projektu)
    https://sourceware.org/systemtap/
  13. SystemTap (Wiki projektu)
    https://sourceware.org/systemtap/wiki
  14. SystemTap (Wikipedia)
    https://en.wikipedia.org/wi­ki/SystemTap
  15. Dynamic Tracing with DTrace & SystemTap
    http://myaut.github.io/dtrace-stap-book/
  16. DTrace (Wikipedia)
    https://en.wikipedia.org/wiki/DTrace
  17. GDB – Dokumentace
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/
  18. GDB – Supported Languages
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/Suppor­ted-Languages.html#Supported-Languages
  19. GNU Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Debugger
  20. The LLDB Debugger
    http://lldb.llvm.org/
  21. Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/Debugger
  22. 13 Linux Debuggers for C++ Reviewed
    http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817
  23. Getting started with ltrace: how does it do that?
    https://www.ellexus.com/getting-started-with-ltrace-how-does-it-do-that/
  24. Reverse Engineering Tools in Linux – strings, nm, ltrace, strace, LD_PRELOAD
    http://www.thegeekstuff.com/2012/03/re­verse-engineering-tools/
  25. 7 Strace Examples to Debug the Execution of a Program in Linux
    http://www.thegeekstuff.com/2011/11/stra­ce-examples/
  26. Oracle® Solaris 11.3 DTrace (Dynamic Tracing) Guide
    http://docs.oracle.com/cd/E53394_01/html/E­53395/gkwpo.html#scrolltoc
  27. An Introduction To Using GDB Under Emacs
    http://tedlab.mit.edu/~dr/gdbin­tro.html
  28. GNU Emacs
    https://www.gnu.org/softwa­re/emacs/emacs.html
  29. The Emacs Editor
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­macs/index.html
  30. Emacs Lisp
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/index.html
  31. An Introduction to Programming in Emacs Lisp
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­intr/index.html
  32. 27.6 Running Debuggers Under Emacs
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­macs/Debuggers.html
  33. GdbMode
    http://www.emacswiki.org/e­macs/GdbMode
  34. Emacs (Wikipedia)
    https://en.wikipedia.org/wiki/Emacs
  35. Emacs Lisp (Wikipedia)
    https://en.wikipedia.org/wi­ki/Emacs_Lisp
  36. Pyclewn installation notes
    http://pyclewn.sourceforge­.net/install.html
  37. pip Installation
    https://pip.pypa.io/en/la­test/installing.html
  38. Clewn
    http://clewn.sourceforge.net/
  39. Clewn installation
    http://clewn.sourceforge.net/in­stall.html
  40. Clewn – soubory
    http://sourceforge.net/pro­jects/clewn/files/OldFiles/
  41. KDbg: úvodní stránka
    http://www.kdbg.org/
  42. Nemiver (stránky projektu)
    https://wiki.gnome.org/Apps/Nemiver
  43. Nemiver FAQ
    https://wiki.gnome.org/Ap­ps/Nemiver/FAQ
  44. Nemiver (Wikipedia)
    https://en.wikipedia.org/wiki/Nemiver
  45. Data Display Debugger
    https://www.gnu.org/software/ddd/
  46. GDB – Dokumentace
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/
  47. BASH Debugger
    http://bashdb.sourceforge.net/
  48. The Perl Debugger(s)
    http://debugger.perl.org/
  49. Visual Debugging with DDD
    http://www.drdobbs.com/tools/visual-debugging-with-ddd/184404519
  50. Pydb – Extended Python Debugger
    http://bashdb.sourceforge.net/pydb/
  51. Insight
    http://www.sourceware.org/insight/
  52. Supported Languages (GNU Debugger)
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/Suppor­ted-Languages.html#Supported-Languages
  53. GNU Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Debugger
  54. The LLDB Debugger
    http://lldb.llvm.org/
  55. Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/Debugger
  56. 13 Linux Debuggers for C++ Reviewed
    http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817
  57. Clewn
    http://clewn.sourceforge.net/
  58. Clewn installation
    http://clewn.sourceforge.net/in­stall.html
  59. Clewn – soubory ke stažení
    http://sourceforge.net/pro­jects/clewn/files/OldFiles/
  60. Pyclewn installation notes
    http://pyclewn.sourceforge­.net/install.html
  61. Debugging
    http://janus.uclan.ac.uk/pa­gray/labs/debug.htm

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.