Produkty Novinky Články Návody Kontakty

Vzdálené ladění

V předchozím textu jsme se naučili ladit aplikaci za běhu a dokonce i se k ní připojit v situaci, kdy začala během své činnosti vykazovat chyby. Jenže jak se ladí aplikace, která běží v cílovém zařízení?
obrázek ladeni-aplikace-vzdalene
Obrázek 1.6 Ladění aplikace - vzdáleně
Je jasné, že variantu, kdy v cílovém zařízení kromě samotné aplikace běží i gdb, budeme s ohledem na omezené systémové prostředky většiny embedded zařízení považovat za nepoužitelnou. Zbývá nám tedy klasická ”embedded” varianta, kdy v našem počítači běží křížový debugger, zatímco v cílovém zařízení laděná aplikace. Aha! Ale jak gbd ovládá aplikaci, když běží jinde? Odpovědí na vznesenou otázku je slovo gdbserver.

gdbserver

Gdbserver je malý program, který běží na cílovém zařízení spolu s aplikací a řídí její běh. Sám o sobě ovšem neumí nic jiného než jen přijímat a odesílat data a vykonávat příkazy gdb, který běží na hostitelském počítači. Je tedy jen jakási prodloužená ruka gdb, jakýsi vykonavatel příkazů, prostředník mezi gdb a aplikací. Výhoda je zřejmá. Gdb (cross varianta) běží na výkonném počítači například i s nějakou grafickou nadstavbou, zatímco gdbserver běží na cílovém zařízení spolu s aplikací. Díky jednoduchosti je portace gdbserveru na nové platformy relativně snadnou a rychlou záležitostí. Situaci zachycuje obrázek 1.6.
Komunikace probíhá přes rozhranní ethernet pomocí TCP/IP spojení nebo případně přes sériový port. Komunikační protokol mezi gdb a gdbserverem je interní záležitostí gdb a je popsán v jeho dokumentaci.
Je zřejmé, že gdb které poběží na hostitelském počítači, musí být v křížové variantě, tzn. že běží zpravidla na platformě x86, ale rozumí spustitelnému souboru zkompilovanému pro cílovou platformu. Naproti tomu gdbserver je nativní aplikace zkompilovaná pro cílové zařízení. Obvykle je součástí vývojového prostředí a v cílovém zařízení je vhodné ji umístit do nějakého standardně prohledávaného adresáře pro spustitelné soubory (např. /usr/bin, /usr/local/bin).

Příprava aplikace pro vzdálené ladění

Jak už víme, aplikaci lze na úrovni zdrojového kódu ladit jen tehdy, jestliže spustitelný soubor aplikace obsahuje ladící informace (volba -g při kompilaci). Jenže tyto ladící informace a další symboly značně zvětšují výslednou velikost spustitelného souboru. Což může být v případě velmi omezených systémových prostředků cílového zařízení problém.
Proto se pro cílové zařízení připraví pomocí utility stripInformationhttp://en.wikipedia.org/wiki/Strip_(Unix) kopie spustitelného souboru, v které se odstraní všechna nepotřebná data (ladící informace, symboly, komentáře apod.) a ponechá se jen to nezbytné.
Tato zmenšená kopie se pak nahraje do cílového zařízení, zatímco v hostitelském počítači, kde běží cross-debugger, zůstane originál spustitelného souboru se všemi ladícími informacemi.
Ukažme si jak utilitou stripInformationSamozřejmě musíme použít křížovou variantu utility strip! zmenšit ukázkovou aplikace Obsah (kód viz výpis 3):
$ arm-none-linux-gnueabi-strip -s -R .comment -o obsah-stripped obsah 
Výsledný binární soubor obsah-stripped nebude obsahovat žádné symboly ani ladící informace (volba -s) a ani žádné komentáře (volba -R .comment).
Je důležité si pamatovat, že pokud není zadán výstupní soubor (volba -o), tak utilita strip automaticky přepíše původní (vstupní) soubor!
Srovnáním velikosti původního a zmenšeného souboru zjistíme, že zatímco původní soubor měl velikost 7075B, tak odstraněním všech nepotřebných dat, jsme se dostali až na 3168B. To představuje úsporu 56%!

Vzdálené ladění přes TCP/IP spojení

Vzdálené ladění na cílovém zařízení si ukážeme na aplikaci obsah (zdrojový kód viz výpis 3). Cílové zařízení bude mít IP adresu 192.168.1.12, hostitelský počítač (vývojářské PC) pak 192.168.1.10. Gdbserver bude poslouchat na portu 2001.
Příprava:
  1. Aplikaci obsah zkompilujeme křížovým kompilátorem pro cílové zařízení.
  2. Vytvoříme zmenšenou kopii spustitelného souboru a nahrajeme ji do cílového zařízení.
  3. Do cílového zařízení nahrajeme také gdbserver.
  4. Hostitelský počítač a cílové zařízení propojíme přes ethernet.
  5. Ověříme, že mezi nimi funguje TCP/IP spojení (např. pomocí příkazu ping).
Spuštění ladění:
  1. Otevřeme si terminálové spojení s cílovým zařízením (přes telnet či sériový port), tak abychom mohli zadávat příkazy a sledovat výstupy aplikace na standardní výstup.
  2. Na cílovém zařízení spustíme gdbserver (viz obrázek 1.7) s parametry síťového rozhraní (IP adresa a port), kde se bude čekat na spojení od gdb, a s názvem aplikace, kterou hodláme ladit. Za názvem aplikace můžeme přidat také parametry, které budou aplikaci předány (nelze je předat příkazem set args jako v případě lokálního ladění):
    # gdbserver :2001 obsah-stripped 2 3
    
    Poznámka: Pokud IP adresu neuvedeme (náš případ), tak gdbserver čeká na spojení na všech dostupných síťových rozhraních.
    obrázek vzdalene-ladeni-gdbserver
    Obrázek 1.7 Vzdálené ladění - gdbserver
  3. Po svém spuštění gdbserver oznámí, že vytvořil nový podřízený proces (naši aplikaci), a uvede port na kterém čeká na příchozí spojení od gdb. Aplikace je nyní připravena k běhu s parametry předanými jakoby z příkazové řádky.
  4. Na hostitelském počítači spustíme křížovou variantu gdb s odkazem na původní (nezmenšený) spustitelný soubor aplikace:
    $ arm-none-linux-gnueabi-gdb -q obsah
    
    obrázek vzdalene-ladeni-gdb
    Obrázek 1.8 Vzdálené ladění - gdb
  5. Gdb se spustí a oznámí nám, že načetl symboly (ladící informace) z daného souboru.
  6. Přikážeme gdb, aby se vzdáleně připojit ke gdbserveru (viz obrázek 1.8). Zároveň zadáme IP adresu cílového zařízení a port, kde gdbserver čeká na příchozí spojení:
    (gdb) target remote 192.168.1.12:2001
    
  7. Úspěšné navázání spojení ze strany gdb oznámí gdbserver hlášením s IP adresou hostitelského počítače: ”Remote debugging from host 192.168.1.10”.
  8. Podobně gdb oznámí úspěšné spojení s gdbserverem na zadané adrese: ”Remote debugging using 192.168.1.12:2001”.
  9. Gdb si postěžuje, že nebyl schopen najít dynamický linker atd. To je dáno tím, že nezná cestu k dynamickému zavaděči/linkeru a dalším standardním knihovnám, které jsou v cílovém zařízení. To snadno napravíme nastavením proměnné sysrootInformationNebo lze místo toho nastavit proměnou solib-search-path, např. když máme knihovny ve více adresářích. Ke zjištění aktuálních hodnot se používá příkaz show, např. show sysroot. na cestu, kde se nachází knihovny a další soubory, které tvoří linuxovou distribuci cílového zařízeníInformationV případě prostředí SourceryG++ je to pro architekturu ARMv5TE adresář /instalacniAdresar/arm-none-linux-gnueabi/libc.
    (gdb) set sysroot /usr/local/SourceryG++/arm-none-linux-gnueabi/arm-none-linux-gnueabi/libc
    
  10. Nyní můžeme aplikaci ladit stejně, jako kdyby byla debuggerem řízena lokálně. Vyjímkou je příkaz run, který nelze u vzdáleného ladění použít. Místo něj se používá příkaz continue. Jen dodávám, že výstupy aplikace na standarní výstup nejsou přesměrovávány do gdb, takže je možné je sledovat jen v okně terminálu připojeného k cílovému zařízení.
Ukončení ladění:
Způsobů jak ukončit vzdálené ladění je několik:
  • Necháme běžet aplikaci až do konce. Jakmile apliakce doběhne do konce, tak se ukončí gdbserver a gdb uzavře spojení.
  • Nebo příkazem detach odpojíme gdb od gdbserveru. Gdbserver se ukončí a aplikace v cílovém zařízení bude pokračovat dál bez kontroly běhu gdbserverem.
  • Nebo příkazem disconnect ukončíme spojení s gdbserverem. Gdbserver ovšem běží dál a čeká na nové příchozí spojení. Zároveň stále řídí běh aplikace, kterou ponechává ve stejném stavu, v jakém bylo ukončeno spojení s gdb (například čekání na breakpointu). Je možné se znovu připojit a pokračovat v ladění.
Poznámka: Spuštěný gdbserver nelze ukončit klasickým CTRL+C, protože všechny signály (tedy i SIGINT od této kombinace kláves) jsou předávány laděné aplikaci. Jedinou možností je otevřít si nové terminálové spojení a ukončit gdbserver příkazem:
# killall gdbserver
Aplikace pak poběží dál bez kontroly gdbserveru.

Vzdálené ladění přes sériový port

Postup je podobný jako v případě ladění přes TCP/IP spojení. Jediné, co musíme dodržet je, že použijeme sériový port, který není používán žádným jiným programem nebo ovladačem, např. ovladačem systémové konzole. Z toho obvykle plyne, že v cílovém zařízení musíme mít dva sériové porty nebo zakázat systémovou konzoli či ji přesměrovat.
Způsob jak spustit gdbserver, tak aby komunikoval s gdb přes sériový port je patrný z obrázku 1.9.
obrázek vzdalene-ladeni-serial
Obrázek 1.9 Vzdálené ladění přes sériový port

Vzdálené ladění běžícího programu

S pomocí gdbserveru jsme schopni se připojit vzdáleně také k programu, který běží na cílovém zařízení a který vyžaduje naši pozornost kvůli nevhodnému chování. Musíme ovšem nejprve spustit gdbserver a přinutit jej, aby se ke sledovanému programu (určeném PIDem) připojil:
# gdbserver :2001 --attach PID
Pak už stačí pustit gdb a připojit se ke gdbserveru.