Trasování a ladění v Linuxu: jazyk používaný SystemTapem

23. 6. 2016
Doba čtení: 17 minut

Sdílet

Pátá část miniseriálu o problematice trasování a ladění nativních aplikací je věnována popisu dalších možností programovacího jazyka vestavěného do nástroje SystemTap.

Obsah

1. Trasování a ladění nativních aplikací v Linuxu: jazyk používaný SystemTapem

2. Globální a lokální proměnné

3. Automatické vytištění obsahu globálních proměnných

4. Demonstrační příklad – automatické vytištění počtu přečtených a zapsaných bajtů

5. Zápis uživatelských funkcí

6. Demonstrační příklad: použití uživatelských funkcí

7. Operátory a funkce pro práci s histogramem a statistickými veličinami

8. Demonstrační příklad: vytvoření histogramu čtení a zápisu do souborů

9. Výsledky demonstračního příkladu

10. Základní funkce pro získání statistických informací

11. Demonstrační příklad: získání statistických informací o čtení a zápisech do souborů

12. Odkazy na Internetu

1. Trasování a ladění nativních aplikací v Linuxu: jazyk používaný SystemTapem

V páté části (mini)seriálu o trasování a ladění nativních aplikací v Linuxu se podrobněji seznámíme s možnostmi programovacího jazyka, v němž se popisuje chování takzvaných „sond“ (probes) používaných nástrojem SystemTap. Tento programovací jazyk je sice odvozen od klasického céčka (podobně jako jazyk D používaný v konkurenčním nástroji DTrace), ovšem některé jeho vlastnosti se od známého a široce používaného jazyka C odlišují. Jedná se především o rozdílný způsob práce s proměnnými (statické versus dynamické určování typů, …), dále o podporu asociativních polí a taktéž podporu pro tvorbu histogramů a zjišťování dalších statistických veličin. Právě práce s histogramem a výpočty sumy, průměru, maximální či minimální hodnoty atd. jsou při ladění aplikací či při sledování chování systému velmi často používány. V případě potřeby je dokonce možné zkombinovat programovací jazyk SystemTapu s funkcemi zapsanými v céčku. V tomto případě ovšem přijdeme o některé kontroly zdrojového kódu, které se jinak provádějí automaticky.

Kombinace obou jazyků může vypadat takto (podrobnosti si řekneme příště):

%{
#include <linux/in.h>
#include <linux/ip.h>
%} /* <-- top level */
 
/* Reads the char value stored at a given address: */
function __read_char:long(addr:long) %{ /* pure */
         STAP_RETURN(kderef(sizeof(char), STAP_ARG_addr));
         CATCH_DEREF_FAULT ();
%} /* <-- function body */
 
/* Determines whether an IP packet is TCP, based on the iphdr: */
function is_tcp_packet:long(iphdr) {
         protocol = @cast(iphdr, "iphdr")->protocol
         return (protocol == %{ IPPROTO_TCP %}) /* <-- expression */
}

2. Globální a lokální proměnné

V jazyce využívaném nástrojem SystemTap pro popis chování jednotlivých sond je možné používat jak globální, tak i lokální proměnné. To pravděpodobně není pro většinu čtenářů příliš překvapivé, ovšem zajímavé jsou vlastnosti těchto proměnných. Globální proměnné musí být deklarovány klíčovým slovem global, za nímž se uvede jméno proměnné a popř. i výraz, jehož výsledek je použit pro inicializaci proměnné. Nikde se však neuvádí typ proměnné, neboť ten je v případě potřeby zjišťován dynamicky. Zatímco globální proměnné je nutné deklarovat, u lokálních proměnných je tomu přesně naopak – žádná deklarace se neuvádí, protože při prvním použití nové proměnné se tato proměnná vytvoří automaticky, samozřejmě jako proměnná lokální (už z tohoto popisu je zřejmé, že ani u lokálních proměnných se explicitně neuvádí jejich typ). Podívejme se na velmi jednoduchý příklad, v němž se používají jak globální proměnné, tak i proměnné lokální:

global read_count=0
global write_count=0
 
probe begin(1) {
    cnt=0
    for (i = 0; i < 50; i++)
        if (isprime (i)) {
            cnt++
            printf("Prime number #%-2d is %2d\n", cnt, i)
        }
}

Ve skriptu jsou deklarovány a současně i inicializovány dvě globální proměnné nazvané read_count a write_count. Používají se zde i dvě proměnné lokální. První lokální proměnná pojmenovaná cnt je platná pro celou sondu, zatímco druhá proměnná nazvaná i je platná pouze uvnitř své smyčky typu for (platnost proměnných odpovídá jejich viditelnosti).

Poznámka: i přesto, že se u deklarací proměnných neuvádí jejich typ, se jedná o silně typovaný jazyk. V případě potřeby lze typ uvést, což platí i pro argumenty funkcí či návratové hodnoty funkcí.

Poznámka: výjimka platí pro pole, která mohou být pouze globální, nikoli lokální. Toto omezení pravděpodobně souvisí se způsobem správy paměti v nástroji SystemTap. Pro adresaci prvků v polích se používají jak celočíselné indexy, tak i jiné hodnoty (podporovány jsou tedy asociativní pole).

3. Automatické vytištění obsahu globálních proměnných

Globální proměnné mají ještě dvě zajímavé a mnohdy velmi užitečné vlastnosti. Pokud se globální proměnná nikde ve skriptu nevyužívá (pouze se deklaruje na jeho začátku), je o tomto potenciálním problému uživatel informován ihned při spuštění nástroje SystemTap v průběhu analýzy a překladu skriptu. V tomto případě se ovšem jedná pouze o varování (Warning), nikoli o zásadní chybu, která by ihned ukončila práci skriptu.

Zajímavější je však fakt, že hodnoty těch globálních proměnných, do nichž se pouze provádí zápis, jsou automaticky vypsány na standardní výstup při ukončování skriptu. To je velmi užitečná vlastnost, protože je tímto způsobem snadné do skriptu přidat další sledovanou veličinu, aniž by bylo nutné jakýmkoli způsobem upravovat sondu typu end, v níž se typicky provádí závěrečné vyhodnocení chování sledované aplikace či sledovaného systému. Úprava je samozřejmě nutná tehdy, pokud nám styl výchozího formátování nevyhovuje (hexadecimální hodnoty atd.)

Jednoduchá sonda, která po svém ukončení vypíše počet volání systémové funkce sys_sync, tedy může vypadat následovně:

global count=0
 
probe kernel.function("sys_sync") {
    count++
}

Nástroj sám rozpozná, že se globální proměnná používá pouze pro zápis nových hodnot a tudíž její výsledek vypíše při ukončování skriptu na standardní výstup.

Poznámka: z proměnné se ve skutečnosti čte, protože count++ lze napsat jako count = count + 1, ovšem žádné další operace se s hodnotou proměnné neprovádí.

4. Demonstrační příklad – automatické vytištění počtu přečtených a zapsaných bajtů

Podívejme se nyní na jednoduchý demonstrační příklad, v němž jsou použity globální proměnné, do nichž se ve skriptu pouze zapisuje (nejsou například vypisovány příkazem printf/println atd.). Ve skriptu se do proměnných read_count a write_count průběžně zapisuje počet operací čtení či zápisu do souboru (přesněji řečeno do file deskriptoru), zatímco v proměnných read_bytes a write_bytes se počítá objem čtených a zapisovaných dat (pro celý systém!). Pátá globální proměnná není nikde využita, takže se při spuštění skriptu vypíše varování o potenciálním problému, který SystemTap nalezl:

global read_count=0
global write_count=0
global read_bytes=0
global write_bytes=0
global unused_variable=0
 
probe begin
{
    println("STAP prepared");
}
 
probe process("ls").begin
{
    printf("ls with PID=%d started\n", pid());
}
 
probe process("ls").end
{
    printf("ls with PID=%d finished\n", pid());
}
 
probe syscall.open
{
    filename = user_string($filename);
    printf("ls opened file %s\n", filename);
}
 
probe syscall.read
{
    bytes=$count
    into=$fd
    read_bytes += bytes
    printf("read %d bytes from file descriptor %d\n", bytes, into);
    read_count++
    if (read_count>10000) exit()
}
 
probe syscall.write
{
    bytes=$count
    into=$fd
    write_bytes += bytes
    printf("write %d bytes to file descriptor %d\n", bytes, into);
    write_count++
    if (write_count>10000) exit()
}

Poznámky:

  1. Ve skutečnosti může při déletrvajícím běhu skriptu dojít k přetečení hodnot globálních proměnných read_bytes a write_bytes, podobně jako v programovacím jazyku C.
  2. Povšimněte si použití „céčkových“ operátorů typu ++ a +=. Ty jsou v nástroji SystemTap samozřejmě podporovány, stejně jako ostatní podobné operátory (--, -=, *= atd.).
  3. I přesto, že se volá funkce exit() po provedení 10000 zápisů či čtení, je před ukončením SystemTapu zavolána sonda end, pokud samozřejmě existuje. Exit tedy v tomto ohledu není destruktivní a ihned provedenou operací.

5. Zápis uživatelských funkcí

Kromě sond se programové skripty používané nástrojem SystemTap mohou skládat z uživatelských funkcí. Deklarace těchto funkcí začíná klíčovým slovem function, za nímž následuje jméno funkce a v kulatých závorkách pak jména parametrů (pokud funkce nějaké parametry akceptuje). Případné návratové hodnoty se vrací příkazem return, stejně jako v céčku:

function count_add(arg1, arg2) {
    return arg1 + arg2
}

V případě potřeby lze explicitně uvést i typ návratové hodnoty, popř. typy parametrů, a to tímto stylem:

function concatenate:string(arg1:long, arg2) {
    return sprintf("%d%s", arg1, arg2)
}

Jak jsme si již řekli v předchozích kapitolách, každé jméno proměnné, které neodpovídá proměnné globální, povede k automatickému vzniku lokální proměnné. Podívejme se na příklad s lokální proměnnou pojmenovanou i platnou pouze uvnitř počítané programové smyčky for (v kódu je vidět i použití příkazu break pro okamžité ukončení smyčky):

function isprime (x) {
    if (x < 2) return 0
    for (i = 2; i < x; i++) {
        if (x % i == 0)
            return 0
        if (i * i > x)
            break
    }
    return 1
}

Použít je možné i rekurzi, samozřejmě se všemi důsledky, které to přináší (problémy s kapacitou zásobníku v případě hluboké či dokonce nekonečné rekurze atd.):

function fibonacci(i) {
    if (i < 1)
        error("bad number")
    if (i == 1)
        return 1
    if (i == 2)
        return 2
    return fibonacci (i-1) + fibonacci (i-2)
}

6. Demonstrační příklad: použití uživatelských funkcí

Dvojici uživatelských funkcí nazvaných isprime a fibonacci, s nimiž jsme se seznámili v předchozí kapitole, použijeme v dalším demonstračním příkladu, v němž se nachází dvojice sond begin (o pořadových číslech jsme si řekli základní informace minule). Po spuštění tohoto skriptu se pouze vypíšou všechna prvočísla od 2 do 50 a následně prvních deset prvků Fibonacciho řady. Posléze je skript ukončen zavoláním funkce exit():

function isprime (x) {
    if (x < 2) return 0
    for (i = 2; i < x; i++) {
        if (x % i == 0)
            return 0
        if (i * i > x)
            break
    }
    return 1
}
 
probe begin(1) {
    cnt=0
    for (i = 0; i < 50; i++)
        if (isprime (i)) {
            cnt++
            printf("Prime number #%-2d is %2d\n", cnt, i)
        }
}
 
function fibonacci(i) {
    if (i < 1)
        error ("bad number")
    if (i == 1)
        return 1
    if (i == 2)
        return 2
    return fibonacci (i-1) + fibonacci (i-2)
}
 
probe begin(2) {
    for (i = 1; i <= 10; i++)
        printf ("Fibonacci number #%-2d is %2d\n", i, fibonacci(i))
    exit ()
}

Po spuštění příkazem stap by se na standardní výstup měly vypsat následující řádky s výsledky výpočtů:

Prime number #1  is  2
Prime number #2  is  3
Prime number #3  is  5
Prime number #4  is  7
Prime number #5  is 11
Prime number #6  is 13
Prime number #7  is 17
Prime number #8  is 19
Prime number #9  is 23
Prime number #10 is 29
Prime number #11 is 31
Prime number #12 is 37
Prime number #13 is 41
Prime number #14 is 43
Prime number #15 is 47
Fibonacci number #1  is  1
Fibonacci number #2  is  2
Fibonacci number #3  is  3
Fibonacci number #4  is  5
Fibonacci number #5  is  8
Fibonacci number #6  is 13
Fibonacci number #7  is 21
Fibonacci number #8  is 34
Fibonacci number #9  is 55
Fibonacci number #10 is 89

7. Operátory a funkce pro práci s histogramem a statistickými veličinami

Programovací jazyk využívaný nástrojem SystemTap obsahuje užitečný operátor zapisovaný následovně: <<<. Jedná se o binární operátor (s dvojicí operandů), přičemž levým operandem musí být pole, což je – jak již víme z předchozího textu – globální proměnná (pole totiž nemohou být lokálními proměnnými) a pravým operandem je libovolný výraz, jehož výsledkem je číselná hodnota (nikoli řetězec či nějaké pole). Pomocí tohoto operátoru se do pole na levé straně operátoru přidává další hodnota, což má ten význam, že se následně může celé pole k tomu připravenými funkcemi zpracovat a získat z něho histogram či různé statistické veličiny typu suma, průměr, maximální hodnota a minimální hodnota. Podívejme se na jednoduchý příklad (používaný mj. i v dokumentaci), v němž se zjišťuje objem dat tekoucích přes síťové rozhraní:

global histogram
 
probe begin {
    printf("Capturing...\n")
}
 
probe netdev.transmit {
    histogram <<< length
}
 
probe netdev.receive {
    histogram <<< length
}
 
probe end {
    printf( "\n" )
    print( @hist_log(histogram) )
}

Při ukončení SystemTapu se zavolá sonda end, která z pole hodnot získá histogram s logaritmickým měřítkem.

Další příklad je již složitější a zaslouží si stručný popis:

global receive_stats
global transmit_stats
 
probe begin {
    printf("Starting network capture (Ctl-C to end)\n")
}
 
probe netdev.receive {
    receive_stats[dev_name, pid(), execname()] <<< length
}
 
probe netdev.transmit {
   transmit_stats[dev_name, pid(), execname()] <<< length
}
 
probe end {
    printf("\nEnd Capture\n\n")
     
    printf("Iface Process........ PID.. RcvPktCnt XmtPktCnt\n")
     
    foreach ([dev, pid, name] in receive_stats) {
        recvcount = @count(receive_stats[dev, pid, name])
        xmitcount = @count(transmit_stats[dev, pid, name])
        printf( "%5s %-15s %-5d %9d %9d\n", dev, name, pid, recvcount, xmitcount )
    }
 
    delete receive_stats
    delete transmit_stats
}

Opět zde nalezneme dvojici globálních proměnných, tentokrát se ovšem jedná o asociativní pole, v němž jsou prvky „indexovány“ jménem síťového rozhraní, PID aktivního procesu a současně jménem procesu. Do těchto polí se ukládají délky bloků dat přenášených přes dané rozhraní a na konci běhu skriptu se v sondě end vypíše celkový počet přenosů, a to jednotlivě pro zařízení, PID procesu a jména procesu.

8. Demonstrační příklad: vytvoření histogramu čtení a zápisu do souborů

V dnešním třetím demonstračním příkladu rozšíříme možnosti skriptu, s nímž jsme se již seznámili minule. Budeme sledovat čtení a zápisy do souborů. Počet zapsaných či přečtených bajtů se ukládá do globálních polí pojmenovaných reads a writes. Z těchto dat se posléze vytvoří histogram funkcí @hist_linear. Této funkci je nutné předat čtyři hodnoty: vlastní pole, minimální hodnotu na ose, maximální hodnotu na ose a šířku intervalu (čím je šířka intervalu menší, tím více hodnot se v histogramu zobrazí):

global reads
global writes
global read_write_count=0
 
probe begin
{
    println("STAP prepared");
}
 
probe process("ls").begin
{
    printf("ls with PID=%d started\n", pid());
}
 
probe process("ls").end
{
    printf("ls with PID=%d finished\n", pid());
}
 
probe syscall.open
{
    filename = user_string($filename);
    printf("ls opened file %s\n", filename);
}
 
probe syscall.read
{
    bytes=$count
    into=$fd
    reads <<< bytes
    printf("read %d bytes from file descriptor %d\n", bytes, into);
    read_write_count++
    if (read_write_count>10000) exit()
}
 
probe syscall.write
{
    bytes=$count
    into=$fd
    writes <<< bytes
    printf("write %d bytes to file descriptor %d\n", bytes, into);
    read_write_count++
    if (read_write_count>10000) exit()
}
 
probe end
{
    println("Reads:")
    print(@hist_linear(reads, 0, 1000, 100))
    println()
    println("Writes:")
    print(@hist_linear(writes, 0, 1000, 100))
}

9. Výsledky demonstračního příkladu

Pokud výše uvedený skript spustíme na středně vytíženém systému, můžeme získat například následující dva histogramy. Ty jsou samozřejmě vytištěny na standardní výstup, vystačíme si tedy s pouhým terminálem. Znaky ~ jsou použity pro vynechání „nezajímavých“ hodnot, znak > na začátku řádku zase říká, že maximální hodnota je příliš nízká:

Reads:
value |-------------------------------------------------- count
    0 |                                                       0
  100 |                                                       2
  200 |                                                       0
  300 |@                                                     10
      ~
  800 |                                                       0
  900 |                                                       0
 1000 |                                                       1
>1000 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  35621

Histogram zápisů vypadá zcela jinak a naznačuje, že některé procesy zapisují po jednotlivých znacích (možná na standardní výstup) či mají malý buffer:

Writes:
value |-------------------------------------------------- count
    0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  17940
  100 |@@@@@@@@@@@@@@@@@@@@@@@@@@                          9492
  200 |@                                                    468
  300 |@@                                                   873
  400 |@@                                                  1070
  500 |                                                     211
  600 |                                                      91
  700 |                                                      26
  800 |                                                      12
  900 |                                                       1
 1000 |                                                       5
>1000 |                                                     147

10. Základní funkce pro získání statistických informací

Na prvky (globálního) pole použitého pro tvorbu histogramu je možné aplikovat i některé další funkce vracející mnohdy užitečné statistické informace:

# Funkce Stručný popis
1 @count() počet prvků (vzorků)
2 @sum součet (suma) hodnot prvků
3 @min nalezení vzorku s minimální hodnotou
4 @max nalezení vzorku s maximální hodnotou
5 @avg výpočet průměrné hodnoty
6 @hist_linear normální histogram s lineární osou
7 @hist_log histogram s logaritmickou osou

Histogram s logaritmickou osou vypadá takto:

bitcoin_skoleni

value |-------------------------------------------------- count
    1 |                                                      0
    2 |                                                      0
    4 |                                                      0
    8 |                                                      0
   16 |                                                      0
   32 |                                                      0
   64 |                                                      0
  128 |                                                      0
  256 |                                                      0
  512 |                                                      0
 1024 |                                                      0
 2048 |                                                      0
 4096 |                                                      0

11. Demonstrační příklad: získání statistických informací o čtení a zápisech do souborů

Zmíněné funkce pro výpočet základních statistických veličin byly přidány do dalšího demonstračního příkladu, který opět sleduje čtení a zápisy do souborů. Při ukončení skriptu (stisk Ctrl+C popř. po dosažení 10000 čtení/zápisů) se v sondě end jednotlivé hodnoty vypočtou a následně zobrazí. Mimochodem, povšimněte si, že se funkce printf chová prakticky stejně jako v céčku (až na ten rozdíl, že v SystemTapu se lépe kontrolují typy parametrů):

global reads
global writes
global read_write_count=0
 
probe begin
{
    println("STAP prepared");
}
 
probe process("ls").begin
{
    printf("ls with PID=%d started\n", pid());
}
 
probe process("ls").end
{
    printf("ls with PID=%d finished\n", pid());
}
 
probe syscall.open
{
    filename = user_string($filename);
    printf("ls opened file %s\n", filename);
}
 
probe syscall.read
{
    bytes=$count
    into=$fd
    reads <<< bytes
    printf("read %d bytes from file descriptor %d\n", bytes, into);
    read_write_count++
    if (read_write_count>10000) exit()
}
 
probe syscall.write
{
    bytes=$count
    into=$fd
    writes <<< bytes
    printf("write %d bytes to file descriptor %d\n", bytes, into);
    read_write_count++
    if (read_write_count>10000) exit()
}
 
probe end
{
    println("Reads:")
    printf("Count: %d operations\n", @count(reads))
    printf("Total: %d bytes\n", @sum(reads))
    printf("Min:   %d bytes\n", @min(reads))
    printf("Max:   %d bytes\n", @max(reads))
    printf("Avg:   %d bytes/operation\n", @avg(reads))
 
    println()
    println("Writes:")
    printf("Count: %d operations\n", @count(writes))
    printf("Total: %d bytes\n", @sum(writes))
    printf("Min:   %d bytes\n", @min(writes))
    printf("Max:   %d bytes\n", @max(writes))
    printf("Avg:   %d bytes/operation\n", @avg(writes))
}

Výsledky demonstračního příkladu mohou vypadat následovně (čistě náhodou se počet čtení prakticky rovná počtu zápisů, vy však na svém systému můžete naměřit odlišné hodnoty):

Reads:
Count: 5003 operations
Total: 538640392 bytes
Min:   8196 bytes
Max:   131072 bytes
Avg:   107663 bytes/operation
 
Writes:
Count: 4999 operations
Total: 828740 bytes
Min:   40 bytes
Max:   2312 bytes
Avg:   165 bytes/operation

12. Odkazy na Internetu

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

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.