Debuggovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy

08.08.2008 20:11 | blackhole

Článok je prekladom dokumentu Peter's GDB Turorial, konkrétne tento diel je v Chapter 2. Je to najobsiahlejší tutoriál, aký na internete nájdete a v knihách debuggovanie rozoberú len na pár stránkach (riadkoch). Ďaľším komplexným zdrojom iformácií je GNU's GDB User's Manual, ale učiť sa z neho je ako učiť sa cudzí jazyk zo slovníka. Tento návod je určený pre tých, ktorí chcú vedieť spraviť viac než break 42;run;step;step. Jednej noci pred deadlajnom sa vám to možno bude hodiť.

Ak chcete efektívne používať GDB, musíťe pochopiť, čo sú to zásobníkove frejmy (stack frames). Pre pochopenie zásobníka si čosi povieme o rozvrstvení pamäte (memory layoute) bežiaceho programu. Táto časť bude z väčšej časti teoretická, ale aby to bolo zaújmavejšie, na konci som pridal príklady ukazujúce zásobník a zásobníkové frejmy v GDB.

Teóriu nevynechajte, pretože:

  1. Pochopenie zásobníka je absolutne nevyhnutné k používaniu symbolického debuggera ako je GDB.
  2. Znalosť rozvrstvenia pamäte procesu vám pomôže pochopiť, čo presne je segmentation fault (alebo segfault), a prečo nám občas killne program (alebo niekedy dôležitejšie - nekillne keď by mal). V skratke, segfaulty sú najbežnejšou príčinou okamžitého pádu aplikácie (pre PC je totaké, ako by ste ho kopli do hlavy).
  3. Tiež nám to umožní nájsť dobre skryté bugy bez použitia printf(), kompilátoru alebo dokonca GDB! (Ukážka [en]: Mark Kim mi našiel chybu v pomerne dlhom kóde bez debuggeru. Zabralo mu to len 5-10 minút.)

Virtuálna pamäť (VP)
Hocikedy sa vytvorí proces, kernel mu priradí kus fyzickej pamäte, ktorá môže mať ľubovolné umiestnenie. Vďaka mágii virtuálnej pamäte (VP) si však proces myslí, že mu patrí celá pamäť počítača. Možno ste už počuli pojem "virtuálna pamäť" v súvislosti s použitím harddisku ako pamäte, keď dojde RAMka. To je tiež virtuálna pamäť, ale prevažne nesúvisí s tým, o čom sa bavíme.
VP o ktorej hovoríme, funguje na základe týchto princípov:

  • Každý proces dostane pridelenú fyzickú pamäť, ktorú nazývame virtuálna pamäť.
  • Proces nevie o detailoch jeho fyzickej pamäte (napr. kde v pamäti je v skutočnosti umiestnený). Všetko čo proces vie, je aký veľký je jeho priestor a že začína na adrese 0.
  • Proces nevie nič o VP patriacej iným procesom.
  • Aj keby proces vedel o cudzej VP, je fyzicky zamedzený k tej pamäti pristupovať.

Zakaždým, keď chce proces čítať alebo zapisovať do pamäte, jeho požiadavka musí byť prevedená z adresy VP na adresu fyzickej pamäte. A naopak, keď kernel potrebuje prístup k VP procesu, musí previesť adresu fyzickej pamäte na adresu VP. S tým súvisia dva hlavné problémy:

  • Počítač neustále pristupuje k pamäti, takže prevody sú veľmi bežné; musia byť bleskovo rýchle.
  • Ako môže OS zaistiť že proces nebude zasahovať do VP iného procesu?

Odpoveď na obidve otázky spočíva vo fakte, že OS neriadi VP sám; dostáva sa mu pomoci od CPU. Večšina procesorov obsahuje zariadenie nazývané MMU - jednotka na správu pamäte (memory management unit). MMU a OS sú spoločne zodpovední za riadenie VP, prevody medzi adresami virtuálnej a fyzickej pamäte a sledovanie, ktorý proces má dovolené pristupovať ku ktorým miestam v pamäti a riadenie oprávnení na čítanie/zápis do VP, aj pre proces, ktorému daný kúsok VP patrí.

Kedysi mohol byť Linux portovaný iba na architektúry, ktoré mali MMU (takže Linux nebežal na, napríklad x286). Avšak v roku 1998 bol Linux portovaný na 68000, ktorá MMU nemala. To vytvorilo cestu pre embedded Linux a Linux na zariadeniach, ako je Palm Pilot.

Cvičenie

  1. Prečítajte si výcuc na Wikipédii: MMU [en]
  2. Dobrovoľné: Ak sa chcete o VP dozvedieť viac, prečítajte si link [en]. Je tam toho oveľa viac, než potrebujete vedieť.

Rozvrstvenie pamäte
Obvykle je VP každého procesu usporiadaná podobným a predvídateľným spôsobom:

  • Textový segment: obsahuje kód, ktorý sa bude spúšťať. Obvykle je zdieľaný, takže ho môže používať viecero instancí programu naraz a tak znížiť požiadavky na pamäť. Býva označený ako read-only, teda program nemôže modifikovať svoje vlastné inštrukcie.
  • Segment inicializovaných dát: obsahuje globálne premenné, ktoré boli inicializované programátorom.
  • Segment neinicializovaných dát: tiež nazývaný "bss" (block started by symbol) bol operátor pužívaný assemblerom. Tento segment obsahuje neinicializované globálne premenné. Všetky premenné v tomto segmente sú naplnené nulami alebo ukazovateľmi NULL predtým, než sa program rozbehne.
  • Zásobník: je kolekcia zásobníkových frejmov, ktoré budú podrobnejšie opísané v ďaľšej sekcii. Keď je pridaný nový frejm (ako výsledok práve zavolanej funkcie), zásobník rastie smerom nadol.
  • Heap: väčšina dynamickej pamäte (vyžiadaná buď pomocou malloc() & jeho kamošmi, alebo new v C++) je ťahaná z heapu. Z heapu bere dynamickú pamäť aj C knižnica pre jej vlastný pracovný priestor. Ako sa viac a viac pamäte žiada za behu, heap rastie smerom nahor.

Z objektového alebo spustitelného súboru môžeme zistiť veľkosť jednotlivých segmentov (uvedomte si, že nehovoríme o rozvrstvení pamäte; hovoríme o súbore na disku, ktorý bude eventuálne v pamäti). Stiahnite si súbor hello_world-1.c

1  // hello_world-1.c
2
3  #include <stdio.h>
4
5  int main(void)
6  {
7      printf("hello world\n");
8
9      return 0;
10  }

zkompilujte a zlinkujte ho samostatne pomocou:

  $ gcc -W -Wall -c hello_world-1.c
  $ gcc -o hello_world-1  hello_world-1.o

Na výpis veľkosti jednotlivých segmentov použijeme príkaz size.

  $ size hello_world-1 hello_world-1.o
  text  data  bss    dec  hex  filename
    916    256    4  1176  498  hello_world-1
    48      0    0    48    30  hello_world-1.o

Sekcia dát je kombináciou inicializovaného a neinicializovaného segmentu. Sekcie dec a hex sú veľkosti súboru v decimálnom a hexadecimálnom formáte.
Veľkosť segmentov objektového súboru môžete získať aj pomocou "objdump -h" alebo "objdump -x".

  $ objdump -h hello_world-1.o
  hello_world-1.o:    file format elf32-i386
  Sections:
  Idx Name          Size      VMA      LMA      File off  Algn
    0 .text        00000023  00000000  00000000  00000034  2**2
                    CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
    1 .data        00000000  00000000  00000000  00000058  2**2
                    CONTENTS, ALLOC, LOAD, DATA
    2 .bss          00000000  00000000  00000000  00000058  2**2
                    ALLOC
    3 .rodata      0000000d  00000000  00000000  00000058  2**0
                    CONTENTS, ALLOC, LOAD, READONLY, DATA
    4 .note.GNU-stack 00000000  00000000  00000000  00000065  2**0
                    CONTENTS, READONLY
    5 .comment      0000001b  00000000  00000000  00000065  2**0
                    CONTENTS, READONLY

Cvičenie

  1. Príkaz size nevypísal segment zásobníka a heapu. Prečo asi?
  2. V hello_world-1.c nie sú žiadne globálne premenné. Skús vysvetliť, prečo size tvrdí, že segment dát a bss segment majú nulovú dĺžku u objektového súboru, ale nenulovú u spustitelného súboru.
  3. Size a objdump ukazujú rôzne veľkosti u textového segmentu. Uhádneš kde sa berie ten rozdiel? Nápoveda: Aký veľký je rozdiel? Vidíte niečo takej veľkosti v zdrojovom kóde?
  4. Dobrovoľné: Prečítajte si o formátoch objektových súborov. [en]

Zásobníkové frejmy a zásobník
Už vieme, ako je rozvrstvená pamäť procesu. Jednen segment tohto rozmiestnenia sa nazýva zásobník, ktorý je súborom zásobníkových frejmov. Každý zásobníkový frejm reprezentuje volanie funkcie. Ako su funkcie volané, množstvo zásobníkových frejmov sa zvyšuje a zásobník sa zväčšuje. A naopak, ako funkcie vracajú výsledky tým, ktorí ich vyvolali, počet frejmov sa znižuje a zásobník sa zmenšuje. V tomto dieli sa naučíme, čo to vlasne zásobníkový frejm je. Veľmi detailné vysvetlenie je na wikipédii [en], ale my si rozoberieme iba veci, ktoré momentálne potrebujeme.

Program je tvorený jednou alebo viacerými funkciami, ktoré na seba vzájomné pôsobnia tým, že sa volajú. Zakaždým keď je funkcia volaná, vyhradí sa kúsok pamäte, nazývaný zásobníkový frejm. Tento kúsok pamäte obsahuje pár dôležitých informácií, ako:

  1. Úschovné miesto pre všetky lokálne premenné práve zavolanej funkcie.
  2. Číslo riadku volajúcej funkcie, aby sme sa tam mohli vrátiť, keď zavolaná funkcia vráti výsledok.
  3. Argumenty, alebo parametre, zavolanej funkcie

Každé volanie funkcie dostane vlastný zásobníkový frejm. Dokopy tvoria všetky frejmy zásobník volaní - call stack (alebo len 'zásobník'). V ďaľšej ukážke použijeme hello_world-2.c.

1  #include <stdio.h>
2  void first_function(void);
3  void second_function(int);
4
5  int main(void)
6  {
7      printf("hello world\n");
8      first_function();
9      printf("goodbye goodbye\n");
10
11    return 0;
12  }
13
14
15  void first_function(void)
16  {
17    int imidate = 3;
18    char broiled = 'c';
19    void *where_prohibited = NULL;
20
21    second_function(imidate);
22    imidate = 10;
23  }
24
25
26  void second_function(int a)
27  {
28    int b = a;
29  }

Keď sa spustí program, má jeden zásobníkový frejm, patriaci funkcii main(). Keďže main() nemá žiadne lokálne premenné, parametre ani funkciu, do ktorej by sa mohla vrátiť, tento frejm je pre nás nezaujímavý. Takto vyzerá zásobník tesne pred tým, než sa zavolá first_function()

Keď sa zavolá first_function(), nepoužívaná zásobníková pamäť sa použije na vytvorenie frejmu pre first_function(). Obsahuje 4 veci: úschovné miesto pre int, char a void *, a návratku do main() (číslo riadku, teda vlastne adresu v pamäti). Takto vyzerá zásobník než sa zavolá second_function().

Keď zavoláme second_function(), nepoužívaná zásobníková pamäť sa použije na vytvorenie frejmu pre first_function(). Takto vyzerá zásobník, než second_function() vráti výsledok.

Keď second_function() vráti výsledok, jej frejm je použitý na určenie, kam sa vrátiť (riadok 22 vo first_function()), potom sa de-alokuje a vráti zásobníku. Takto vyzerá zásobník, keď second_function() vráti výsledok:

Keď first_function() vráti výsledok, jej frejm je použitý na určenie, kam sa vrátiť (riadok 9 v main()) a potom sa de-alokuje. Takto vyzerá zásobník, keď first_function() vráti výsledok:

A keď sa vráti main(), program skončí.

Cvičenie

  1. Povedzme, že program spraví 5 funkčných volaní. Koľko frejmov by malo byť v zásobníku?
  2. Videli sme, že zásobník rastie nadol a keď sa funkcia vráti, posledný frejm sa de-alokuje a v zásobníku sa uvoľní miesto. Je možné, aby sa nejaký frejm de-alokoval v strede zásobníka? Keby áno, čo by to spôsobilo?
  3. Môže goto() spôsobiť, aby sa de-alokoval frejm v strede zásobníka? Odpoveď je nie, ale prečo?
  4. Môže longjmp() spôsobiť, aby sa de-alokoval frejm v strede zásobníka?

Tabuľka symbolov
Symbol je premenná alebo funkcia. Tabuľka symbolov je presne to, čo myslíte: tabuľka premenných a funkcií v spustiteľnom súbore. Normálne obsahuje len adresy symbolov v pamäti, keďže počítač nezaujíma, ako máme funkcie a premenné pomenované. Ale informácia, že máme chybu vo funkcii 0xbffff924, by nám bola na dve veci, takže gdb sa nejako tieto názvy musí dozvedieť. Musíme teda zkompilovať kód s informáciami pre debugger, ktoré povedia GDB 2 veci:

  1. Ako si spojiť adresu symbolu s jeho názvom v zdrojovom kóde.
  2. Ako si spojiť adresu strojového kódu s riadkom v zdrojovom kóde

Tabuľka symbolov s týmito extra informáciami pre debugger sa nazýva rozšírená tabuľka symbolov. Pretože gcc a GDB bežia na toľkých rôznych platformách, je veľa rôznych formátov, v ktorých sa informácie pre debugger môžu uložiť.

  • stabs: Formát používaný programom DBX na väčšine BSD systémoch.
  • coff: Formát používaný programom SDB na väčšine System V systémoch pred System V Release 4.
  • xcoff: Formát používaný programom DBX na IBM RS/6000 systémoch.
  • dwarf: Formát používaný programom SDB na väčšine System V Release 4 systémoch.
  • dwarf2: Formát používaný programom DBX na IRIX 6.
  • vms: Formát používaný programom DEBUG na VMS systémoch.

Okrem týchto formátov GDB ešte podporuje ich varianty, ktoré mu umožňujú používať GNU rozšírenia. Nenechajte sa týmito formátmi zmiasť, GDB automaticky vyberie najvhodnejší formát.

Príprava súboru na debuggovanie

Najprv musíme program zkompilovať s voľbou -g.

  gcc -g -o filename filename.c

Ako alternatívu k -g, môžete tiež použiť voľbu -ggdb,

  gcc -ggdb -o filename filename.c

ktorá použije rozšírenú GNU variantu. Túto voľbu by ste mali používať vo väčšine prípadov.

Ku -g a -ggdb môžete pridať číselný argument, 1 pre najmenšie množstvo informácii a 3 pre najväčšie. Default je 2. S použitím -g3 získate prístup ku makrám preprocesoru. Odporúčam vždy používať -ggdb3.

Informácie pre debugger sa neloadujú do pamäte (iba keď program spúšta GDB). To znamená, že programy skompilované s -g alebo -ggdb, nebudú o nič pomalšie a ani nebudú mať väčšie požiadavky na pamäť. Iba vám zaberú viac miesta na disku.

Posledná poznámka. Je možné program zoptimalizovať a debugovať (gcc -g -O9 hello_world-1.c), GDB je jeden z mála, ktorý to podporuje. Mali by ste sa tomu ale radšej vyhnúť, pretože to môže GDB občas zmiasť. Niektoré premenné sa optimalizácou zrušia, funkcie sa zmenia na "inline", atď.

Cvičenie

  1. Spustite "strip --strip-debug hello_world-1 a pozrite sa na veľkosť súboru. Teraz spustite strip --strip-all hello_world-1 a skontrolujte veľkosť. Viete uhádnuť, čo sa deje? Ak nie, vašim trestom je prečítať "man strip".
  2. Odstránili ste všetky zbytočné symboly. Skúste program spustiť. Spravte "strip --remove-section=.text hello_world-1" a pozrite veľkosť. Skúste program spustiť. Čo sa deje?
  3. Prečítajte toto link [en] o tabuľkách symbolov (je to krátke).
  4. Dobrovoľné: Prečítajte toto link [en] a formáte objektového súboru COFF.

Prieskum zásobníka pomocou GDB
Znovu sa pozrieme na zásobník, tentokrát pomocou GDB. Možno nebudete všetkéme chápať, kedže ešte nepoznáte breakpointy, ale malo by to byť intuitívne.
Zkompilujte a spustite try1.c

  1    #include <stdio.h>
  2    static void display(int i, int *ptr);
  3
  4    int main(void) {
  5      int x = 5;
  6      int *xptr = &x;
  7      printf("In main():\n");
  8      printf("  x is %d and is stored at %p.\n", x, &x);
  9      printf("  xptr points to %p which holds %d.\n", xptr, *xptr);
  10      display(x, xptr);
  11      return 0;
  12  }
  13
  14    void display(int z, int *zptr) {
  15    printf("In display():\n");
  16      printf("  z is %d and is stored at %p.\n", z, &z);
  17      printf("  zptr points to %p which holds %d.\n", zptr, *zptr);
  18  }

Uistite sa, že rozumiete výstupu. Toto vidím ja:

  $ ./try1
  In main():
      x is 5 and is stored at 0xbffff948.
      xptr points to 0xbffff948 which holds 5.
  In display():
      z is 5 and is stored at 0xbffff924.
      zptr points to 0xbffff948 which holds 5.

Spustite try1 v GDB pomocou "gdb try1". Uvidíte kecy o copyrighte:

  $ gdb try1
  GNU gdb 6.1-debian
  Copyright 2004 Free Software Foundation, Inc.
  GDB is free software, covered by the GNU General Public License, and you are
  welcome to change it and/or distribute copies of it under certain conditions.
  Type "show copying" to see the conditions.
  There is absolutely no warranty for GDB.  Type "show warranty" for details.
  (gdb)

Gdb teraz čaká na príkazy. Program momentálne nebeží; aby ste ho rozbehli, napíšte run.

  (gdb) run
  Starting program: try1
  In main():
      x is 5 and is stored at 0xbffffb34.
      xptr points to 0xbffffb34 which holds 5.
  In display():
      z is 5 and is stored at 0xbffffb10.
      zptr points to 0xbffffb34 which holds 5.
  Program exited normally.
  (gdb)

No, program bežal. Ale to isté sme mohli spraviť aj bez GDB. S pomocou GDB však môžeme program zastaviť v strede behu a pozrieť sa na zásobník. Program zastavíte breakpointami. Neskôr si o nich napíšeme viac, ale zatiaľ vám stačí vedieť, že keď GDB poviete break 5, zastaví program na 5. riadku. Možno sa pýtate: spustí sa riadok 5? Odpoveď je nie. Posledný sa spustí 4. riadok a na začiatku piateho program zastaví.
Nastavte breakpoint na riadok 10 a znovu spustite program:

  (gdb) break 10
  Breakpoint 1 at 0x8048445: file try1.c, line 10.
  (gdb) run
  Starting program: try1
  In main():
      x is 5 and is stored at 0xbffffb34.
      xptr holds 0xbffffb34 and points to 5.
  Breakpoint 1, main () at try1.c:10
  10        display(x, xptr);

Nastavili sme breakpoint na riadok 10 súboru try1.c. GDB nám povedal, že ten riadok súhlasí s adresou 0x8048445 v pamäti. Znovu sme spustili program a dostali prvé 2 riadky výstupu. Sme v main(), čakajúc na začiatku riadku 10. Na zásobník sa môžeme pozrieť príkazom backtrace

  (gdb) backtrace
  #0  main () at try1.c:10
  (gdb)

V zásobníku je jeden frejm s číslom #0 a patrí funkcii main(). Pokiaľ spustíme daľší riadok kódu, ocitneme sa vo funkcii display(). Ak ste čítali teóriu, mali by ste presne vedieť, čo sa stane so zásobníkom: na spodok zásobníka sa pridá ďaľší frejm. Pozrime sa na to. Ďaľší riadok spustíme príkazom step.

  (gdb) step
  display (z=5, zptr=0xbffffb34) at try1.c:15
  15              printf("In display():\n");
  (gdb)

Znovu sa pozrite na zásobník a uistite sa že všetkému rozumiete:

  (gdb) backtrace
  #0  display (z=5, zptr=0xbffffb34) at try1.c:15
  #1  0x08048455 in main () at try1.c:10

Pár postrehov:

  • Teraz máme dva frejmy, frejm #1 patriaci funkcii main() a frejm #0 patriaci funkcii display().
  • Osobne sa mi zdá číslovanie frejmov trochu mätúce. Preferoval by som, keby main() zostala frejmom #0 a ďaľšie frejmy dostávali vyššie čísla. Ale takto sa to zhoduje s predstavou, že zásobník rastie "nadol". Proste si pamätajte, že frejm s najnižším číslom patrí poslednej volanej funkcii.
  • Výpis zásobníka nám ukáže aj argumenty, ktoré funkcie zobrali. Vidíme, že main() nevzala žiadne, ale display() áno (a tiež sa nám zobrazia hodnoty týchto argumentov).
  • Tiež sa dozvieme, ktorý riadok sa v danom frejme práve spúšťa. Pozrite sa spät do zdrojového kódu a overte si, že rozumiete číslam riadkov, ktoré vám backtrace ukazuje.

Spustite ďalšie dva riadky:

  (gdb) step
  In display():
  16        printf("  z is %d and is stored at %p.\n", z, &z);
  (gdb) step
      z is 5 and is stored at 0xbffffb10.
  17        printf("  zptr holds %p and points to %d.\n", zptr, *zptr);

Spomeňte si, že vo frejme sa ukladajú lokálne premenné pre funkciu. Pokiaľ mu nepoviete inak, GDB je vždy v kontexte frejmu práve bežiacej funkcie. Keďže sme vo funkcii display(), GDB je v kontexte frejmu #0. Môžeme zistiť v kontexte ktorého frejmu sa nachádzame pomocou príkazu frame bez argumentov:

  (gdb) frame
  #0  display (z=5, zptr=0xbffffb34) at try1.c:17
  17        printf("  zptr holds %p and points to %d.\n", zptr, *zptr);

Zatiaľ som vám nevysvetlil čo znamená "kontext". Keďže GDB je v kontexte frejmu #0, máme prístup ku všetkým lokálnym premenným frejmu #0, ale nemáme prístup k premenným v iných frejmoch. Pozrime sa na to. Príkazom print môžeme získať hodnoty premenných v aktuálnom frejme. Keďže z a zptr sú premenné vo funkcii display() a GDB je práve vo frejme pre display(), môžeme zistiť ich hodnoty:

  (gdb) print z
  $1 = 5
  (gdb) print zptr
  $2 = (int *) 0xbffffb34

Ale nemáme prístup k lokálnym premenným v iných frejmoch. Skúste sa pozrieť na premenné vo funkcii main(), ktorej patrí frejm #1:

  (gdb) print x
  No symbol "x" in current context.
  (gdb) print xptr
  No symbol "xptr" in current context.

Môžeme však GDB povedať, aby skočilo z frejmu #0 do frejmu #1 pomocou príkazu frame s číslom frejmu ako argumetom. To nám umožní prístup k premenným vo frejme #1. Asi tušíte, že ale stratíme prístup k premenným vo frejme #0.

  (gdb) frame 1                          <--- switch to frame 1
  #1  0x08048455 in main () at try1.c:10
  10        display(x, xptr);
  (gdb) print x
  $5 = 5                                  <--- we have access to variables in frame 1
  (gdb) print xptr
  $6 = (int *) 0xbffffb34                <--- we have access to variables in frame 1
  (gdb) print z
  No symbol "z" in current context.      <--- we don't have access to variables in frame 0
  (gdb) print zptr
  No symbol "zptr" in current context.    <--- we don't have access to variables in frame 0

Btw. jednou z najťažších vecí pri používaní GDB je vidieť výstup programu:

  x is 5 and is stored at 0xbffffb34.
  xptr holds 0xbffffb34 and points to 5.

zmixovaný s výstupom GDB:

  Starting program: try1
  In main():
  ...
      Breakpoint 1, main () at try1.c:10
  10        display(x, xptr);

zmixovaný s inputom do GDB:

  (gdb) run

zmixovaný s inputom do programu. Spočiatku to mätie, ale čím viac GDB používate, tým viac si na to zvyknete. Ešte viac sa to domixuje, keď váš program používa ncurses alebo svga, ale dá sa to obísť.

Cvičenie

  1. Pokračujúc v predchádzajúcom príklade, skočte späť do frejmu funkcie display(). Overte, že máte prístup k premenným vo frejeme #0, ale nie v #1.
  2. Zistite, ako opustiť GDB. Funguje aj control-d, ale chcem aby ste si tipli.
  3. GDB má aj nápovedu. Ak napíšete help foo, GDB vám ukáže popis príkazu foo. Spustite GDB (bez argumentov) a prečítajte si nápovedu pre všetky príkazy, ktoré sme v tomto dieli použili.
  4. Znovu otvorte try1 v debuggeri, nastavte breakpoint hocikde do funkcie display() a spustite program. Zistite, ako zobraziť zásobník zároveň s hodnotami všetkých lokálnych premenných pre každý frejm. Hint: Ak ste čítali nápovedu pre každý príkaz, čo sme použili, mala by to byť hračka.
    • Re: Debugovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy 08.08.2008 | 22:18
      Avatar blackhole   Návštevník

      Robim rozsiahlejsi preklad prvy raz tak ma prosim nezastrelte. Tiez vecsinou tutorialy/knihy citam v EN tak som si neni ista ako su niektore pojmy poslovencene.
      Btw mohol by mi to niekto kto moze pouzivat full html editnut aby boli obrazky obtekane zlava? (okrem prveho)

      -----
      42

    • Re: Debuggovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy 09.08.2008 | 14:21
      Avatar blackhole_ventYl   Používateľ

      Pri obkece okolo utility size pouzivas slovo "sekcia" aj na oznacenie stlpca, aj na oznacenie segmentu binarky. To by dakoho mohlo zmiast. Inac vcelku expresny preklad, dufam, ze to nezabalis uprostred prekladu.

      Inac zrejme aj typek v tom ma bordel, pretoze to, co on oznacuje ako VM, sa obvykle v terminologii operacnych systemov oznacuje ako LAP (Linearny Adresovaci Priestor) a preklad sa deje do FAP (Fyzicky Adresovaci Priestor), co vykonava MMU pomocou pagingu. Pod (pripadne nad, proste na opacnej strane, ako FAP) LAP je este ALAP (mruh, preco slova logicky a linearny maju rovnake zaciatocne pismeno?; Aplikacny Logicky Adresovy Priestor), ale ten sa minimalne na Unixoidnych systemoch nevyuziva a od nastupu technologie NT uz to nepouziva asi ani Windows.
      ---
      Cuchat s nadchou, to je ako sniffovat bez promiscu.

      --- Cuchat s nadchou, to je ako sniffovat bez promiscu.
      • Re: Debuggovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy 09.08.2008 | 19:11
        Avatar blackhole   Návštevník

        Opravene (dufam, pozri sa ci je to zrozumitelnejsie).
        Ja sa v tom tiez nejako extremne nevyznam, iba sa ucim a zdalo sa mi ze by sa to chcel naucit aj niekto kto ma slabsiu anglictinu. Povedz mi co mam kde prepisat alebo to editni, nemam nic proti.
        A neboj, urcite neprestanem v strede prekladu, ratam este take 3-4 casti, podla toho ako to rozdelim.

        ----
        42

    • Re: Debuggovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy 11.08.2008 | 08:09
      Avatar blackhole   Návštevník

      mne sa to paci, len by som aj uvital odpovede na tie cvicenia :-)

    • Vypis pamate 15.08.2008 | 12:14
      Avatar blackhole   Návštevník

      Pekny clanok ale myslim ze by mohlo pomoct na lepsiu predstavu a pochopenie vypis pamate. Do tohoto vypisu by ste mohli farebne vyznacit miesta ako navratova adresa funkcie a pod. Je to mozne realizovat prakticky aspon v dalsom clanku?
      ---------------------------------------------------------------------------------------
      Dobrý vedec dokáže každú vec jednoducho vysvetliť aj blbcovi (nie úplnému :) .

    • v zasobnikovom frejme navratova adresa za premennou 15.08.2008 | 13:30
      Avatar blackhole   Návštevník

      Ak sa nemyslim tak by sa mala v obrazkoch so zasobnikom nachadzat najprv lokalna (e) premenna(e) a potom navratova adresa. Tak je to aj na obrazku na wiki:
      http://en.wikipedia.org/wiki/Stack_buffer_overflow
      (tu je na obrazku zasobnika ako prva navratova adresa a zanou az lokalne premenne).
      Jedine tak je mozne buffer overflow, ak prilis dlhy napr. textovy retazec zaplni lokalnu premennu a bude pokracovat v zapise aj za tuto oblast az prepise navratovu adresu funkcie.
      ---------------------------------------------------------------------------------------
      Dobrý vedec dokáže každú vec jednoducho vysvetliť aj blbcovi (nie úplnému :) .

      • Re: v zasobnikovom frejme navratova adresa za premennou 16.08.2008 | 10:10
        Avatar vid   Používateľ

        To je kozmeticka vec. Realne je ta navratova adresa na vyssej adrese ako lokalne data, kedze zasobnik sa naplna od vyssich adries k nizsim. Ale zvykne sa to kreslit tak ako je to v tomto clanku, ze vrchol zasobniku je "naspodu", a aj mne to prijde rozumnejsie.

        Keby to dal tak ako hovoris, potom by frame pre main() musel byt pod frejmom pre first_function()

    • Re: Debuggovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy 29.01.2009 | 14:35
      Avatar blackhole   Návštevník

      Dobry clanok.

      Akurat mala nepresnost:
      Kedysi mohol byť Linux portovaný iba na architektúry, ktoré mali MMU (takže Linux nebežal na, napríklad x286)

      286 samozrejme MMU ma, ale nema 32 bitove registre. Preto nie je linuxom podporovana.

      Linux pre procaky bez MMU sa vola uClinux.http://www.uclinux.org/

      • Re: Debuggovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy 29.01.2009 | 14:56
        Avatar vid   Používateľ

        286 ma strankovanie? ja mam pocit ze nie.

        • Re: Debuggovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy 29.01.2009 | 19:15
          Avatar blackhole   Návštevník

          Tak podla wiki 286 MMU ma...hm...

    • Re: Debuggovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy 05.03.2009 | 22:15
      Avatar nemesis   Používateľ
      Super článok velmi mi pomohol pochopiť GDB. Ja osobne požívam jeho Xkovu nadstavbu DDD a ta mi už pomohla vyriešiť nejeden skrytý bug. Dúfam že sa tu čoskoro objavia preložené ďalšie časti.
      Who controls the past controls the future: who controls the present controls the past.
    • Re: Debuggovanie v GDB #1: Virtuálna pamäť a zásobníkove frejmy 07.03.2009 | 17:35
      Avatar blackhole   Návštevník

      Dalsie casti by mali byt na ceste... Autor mi pisal ze ide tutorial znacne prerobit, co sa aj deje, takze cakam.