BACI


Slovo uvodem

 

  • disassembler "dekompiluje" PCODE soubor vytvoreny BACI Pascal nebo BACI C-- prekladacem
  • informace poskytovana disassemblerem muze byt uzitecna pro zjisteni, jak BACI system funguje

 

Format PCODE instrukce

  • PCODE instrukce ma 3 polozky: operacni kod, x a y modifikatory
  • typicka LOAD_ADDR PCODE instrukce ma tvar:

0    1    6

  • 0 je operacni kod instrukce LOAD_ADDR, vyznam modifikatoru: promenna, jejiz adresa se uklada do runtime zasobniku je ulozena s offsetem 6 v zasobniku beziciho procesu na urovni vnoreni 1
  • pro program obsahujici takovou instrukci pouzije disassembler symbolickou tabulku a ladici informace ulozene v PCODE souboru a poskytne uzivateli mnemotechnicky popis instrukci se jmenem promenne, pr.:

0    1    6   LOAD_ADDR, push &i


Pouziti disassembleru

Pouziti: badis [optional_flags] pcode_filename

Optional flags:

-h ukaze tento help

-s nevypisuje zdrojovy kod

 

  • PCODE soubor ma priponu .pco ci .pbo, vystup ma priponu .dco nebo .dbo
  • pokud je k dispozici zdrojovy kod, pak jsou na vystupu prokladany radky zdrojoveho kodu s PCODE instrukcemi, neni-li ovsem zapnuta volba -s

 

Priklad

(incr.cm z posledni kapitoly o BACI C-- prekladaci)

1 const int m = 5;

2 int n;

3

4 void incr(char id)

5 {

6 int i;

7

8 for(i = 1; i <= m; i = i + 1)

 

lc f x y PCODE

0 0 1 6 LOAD_ADDR, push &i

1 24 0 1 PUSH_LIT 1

2 38 0 0 STORE, s[s[t-1]] = s[t], pop(2)

3 1 1 6 LOAD_VALUE, push i

4 24 0 5 PUSH_LIT 5

5 48 0 0 TEST_LE,pop(1),s[t] = (s[oldt-1] <= s[oldt])

6 15 0 32 JZER s[t] to 32, pop(1)

7 14 0 14 JUMP to 14

8 0 1 6 LOAD_ADDR, push &i

9 1 1 6 LOAD_VALUE, push i

10 24 0 1 PUSH_LIT 1

11 52 0 0 DO_ADD, pop(1), s[t] = (s[oldt-1] + s[oldt])

12 38 0 0 STORE, s[s[t-1]] = s[t], pop(2)

13 14 0 3 JUMP to 3

 

9 {

10 n = n + 1;

 

14 0 0 0 LOAD_ADDR, push &n

15 1 0 0 LOAD_VALUE, push n

16 24 0 1 PUSH_LIT 1

17 52 0 0 DO_ADD, pop(1), s[t] = (s[oldt-1] + s[oldt])

18 38 0 0 STORE, s[s[t-1]] = s[t], pop(2)

 

11 cout << id << " n =" << n << " i =";

 

19 1 1 5 LOAD_VALUE, push id

20 29 0 3 WRITE (char) s[t] to stdout, pop(1)

21 28 0 0 WRITE_RAWSTRING stab[0] to stdout

22 1 0 0 LOAD_VALUE, push n

23 29 0 1 WRITE (int) s[t] to stdout, pop(1)

24 28 0 6 WRITE_RAWSTRING stab[6] to stdout

 

12 cout << i << " " << id << endl;

 

25 1 1 6 LOAD_VALUE, push i

26 29 0 1 WRITE (int) s[t] to stdout, pop(1)

27 28 0 12 WRITE_RAWSTRING stab[12] to stdout

28 1 1 5 LOAD_VALUE, push id

29 29 0 3 WRITE (char) s[t] to stdout, pop(1)

30 63 0 0 WRITELN

 

13 }

31 14 0 8 JUMP to 8

 

14 }

 

32 32 0 0 EXIT_PROC

 

15

16 main()

 

33 80 0 56 SHORTCALL to 56, shortcall_reg = pc, pc = 56

 

17 {

18 n = 0;

 

34 0 0 0 LOAD_ADDR, push &n

35 24 0 0 PUSH_LIT 0

36 38 0 0 STORE, s[s[t-1]] = s[t], pop(2)

 

19 cobegin

 

37 4 0 0 COBEGIN

 

20 {

21 incr( 'A'); incr( 'B' ); incr('C');

 

38 18 0 4 MARKSTACK incr

39 24 0 65 PUSH_LIT 65

40 19 0 5 CALL, psize-1 = 5

41 3 0 1 UPDATE_DISPLAY from level 1 out to level 0

42 18 0 4 MARKSTACK incr

43 24 0 66 PUSH_LIT 66

44 19 0 5 CALL, psize-1 = 5

45 3 0 1 UPDATE_DISPLAY from level 1 out to level 0

46 18 0 4 MARKSTACK incr

47 24 0 67 PUSH_LIT 67

48 19 0 5 CALL, psize-1 = 5

49 3 0 1 UPDATE_DISPLAY from level 1 out to level 0

 

22 }

 

50 5 0 0 COEND

 

23 cout << "The sum is " << n << endl;

 

51 28 0 14 WRITE_RAWSTRING stab[14] to stdout

52 1 0 0 LOAD_VALUE, push n

53 29 0 1 WRITE (int) s[t] to stdout, pop(1)

54 63 0 0 WRITELN

 

24 }

 

55 31 0 0 HALT

 

++-outer-++:

56 81 0 0 SHORTRET, pc = shortcall_reg

 

  • podivame se na kritickou sekci v programu (radka 10: n = n + 1)

 

14 0 0 0 LOAD_ADDR, push &n

15 1 0 0 LOAD_VALUE, push n

16 24 0 1 PUSH_LIT 1

17 52 0 0 DO_ADD,pop(1),s[t] =(s[oldt-1] + s[oldt])

18 38 0 0 STORE, s[s[t-1]] = s[t], pop(2)

 

  • pri interpretaci inkrementace promenne n znamena jedna radka programu 5 PCODE instrukci
  • proces zpracovavajici tuto radku muze byt napr. pozastaven mezi LOAD_ADDR a STORE instrukci a prepnut na jiny proces, ten napriklad dokonci svoji STORE instrukci, ta muze byt pote zrusena puvodnim procesem, ktery po preruseni pokracuje a uklada svou hodnotu

 

Pouziti vypisu disassembleru pro ladeni

  • rozebereme znovu priklad incr.cm, protoze demonstruje, jak konkurencne zpracovavana vlakna mohou vzajemne "skodit", kdyz vzajemny pristup ke globalni promenne neni vylucny
  • bezi 3 vlakna procedury incr, ktera inkrementuji globalni promennou n 5 krat, celkovy pocet inkrementaci je 15, nicmene hodnota promenne a je na konci skoro vzdy mensi nez 15
  • pro ilustraci duvodu vzniku konfliktu pouzijeme debugger

 

  1. pokud neni prelozen soubor incr.cm, spustime
    bacc incr.cm
  2. interpretujeme program v ladicim modu:
    bainterp -p -d incr.cm

 

nasleduje komunikace s interpretem (akce uzivatele jsou zvyrazneny)

...

Executing PCODE ...

33 80 0 56 SHORTCALL to 56,shortcall_reg=pc,pc = 56

(h = help)> h

Debugger Commands:

b lc -- set a break at location 'lc'

c -- continue to the next breakpoint

d -- dump the stack of the current process

d t -- dump 10 stack words from s[t] down to s[t-10]

d t b -- dump stack words from s[t] down to s[b]

h -- show this help

i -- show current breakpoints

p -- show process table

q -- terminate execution

s -- execute one PCODE instruction

RETURN -- repeat singlestep or continue

u i -- unset breakpoint[i]

w -- show where current execution is

x -- disassemble the next 10 instructions

x loc --dissassemble 10instructions starting at 'loc'

(h = help)> b 16

(h = help)> b 18

 

  • chceme zastavit na pozici 16 pred instrukci PUSH_LIT a na pozici 18 pred instrukci STORE
  • na pozici 16 je hodnota n, kterou precetlo vlakno incr, na vrcholu runtime zasobniku, na pozici 18 je hodnota, kterou chce vlakno ulozit zpet do globalni promenne n, opet ulozena na vrcholu zasobniku
  • pri kazdem zastaveni na obou z breakpointu vypiseme si zasobnik prave beziciho vlakna, pripadne se nam podari narazit na pripad, kdy se nam inkrementace ztrati

(h = help)> c

Breakpoint 0 Process #3: incr

16 24 0 1 PUSH_LIT 1

(h = help)> d

Stack for Process #3: incr from 2809 down to 2801

0 0 1 67 4 1 0 0 0

(h = help)> c

Breakpoint 1 Process #3: incr

18 38 0 0 STORE, s[s[t-1]] = s[t], pop(2)

(h = help)> d

Stack for Process #3: incr from 2809 down to 2801

1 0 1 67 4 1 0 0 0

(h = help)> s

19 1 1 5 LOAD_VALUE, push id

(h = help)> p

Process Table

Process Active Suspend PC xpc atomic

0 main 0 -1 51 6 0

1 incr 1 -1 1 5 0

2 incr 1 -1 1 5 0

3 incr 1 -1 19 18 0

Global Variables

type name level adr value

int n 0 0 1

Mainproc Variables

Monitor Variables

Process Variables

Process #1 incr

int i 1 6 0

char id 1 5 A

Process #2 incr

int i 1 6 0

char id 1 5 B

Process #3 incr

int i 1 6 1

char id 1 5 C

  • proces 3 ulozili hodnotu 1 do promenne n, pricemz mohl provest vsech 5 instrukci (radky 14-18 .. inkrementace n) najednou bez preruseni
  • zminovanych 5 PCODE instrukci tvori kritickou sekci, incr proces nesmi byt prerusen, jinak muze dojit ke ztrate inkrementace
  • pokracujeme

(h = help)> c

C n =1 i =1 CBreakpoint 0 Process #2: incr

  16 24 0 1 PUSH_LIT 1

(h = help)> d

Stack for Process #2: incr from 2609 down to 2601

  1 0 1 66 4 1 0 0 0

(h = help)> c

Breakpoint 1 Process #2: incr

  18 38 0 0 STORE, s[s[t-1]] = s[t], pop(2)

(h = help)> d

Stack for Process #2: incr from 2609 down to 2601

  2 0 1 66 4 1 0 0 0

 

  • vystup "C n =1 i =1 C" procesu se objevi pred dosazenim breakpointu 0, vse zatim vypada normalne
  • proces 2 cte hodnotu 2 z globalni promenne n a je pripraven na radce 18 ulozit 2 zpet do globalni promenne
  • pokracujeme

(h = help)> c

 

Breakpoint 0 Process #1: incr

  16 24 0 1 PUSH_LIT 1

(h = help)> d

Stack for Process #1: incr from 2409 down to 2401

  2 0 1 65 4 1 0 0 0

(h = help)> c

Breakpoint 0 Process #3: incr

  16 24 0 1 PUSH_LIT 1

(h = help)> d

Stack for Process #3: incr from 2809 down to 2801

  2 0 2 67 4 1 0 0 0

(h = help)> c

Breakpoint 1 Process #3: incr

  18 38 0 0 STORE, s[s[t-1]] = s[t], pop(2)

(h = help)> d

Stack for Process #3: incr from 2809 down to 2801

  3 0 2 67 4 1 0 0 0

(h = help)> c

Breakpoint 1 Process #1: incr

  18 38 0 0 STORE, s[s[t-1]] = s[t], pop(2)

(h = help)> d

Stack for Process #1: incr from 2409 down to 2401

  3 0 1 65 4 1 0 0 0

(h = help)> p

Process Table

Process Active Suspend PC xpc atomic

  0 main 0 -1 51 6 0

  1 incr 1 -1 18 16 0

  2 incr 1 -1 20 18 0

  3 incr 1 -1 20 48 0

Global Variables

type name level adr value

int n 0 0 3

Mainproc Variables

Monitor Variables

Process Variables

Process #1 incr

int i 1 6 1

char id 1 5 A

Process #2 incr

int i 1 6 1

char id 1 5 B

Process #3 incr

int i 1 6 2

char id 1 5 C

  • nejprve si vsimneme odradkovani hned za prikazem c, ktere tiskne proces 3 pri dokonceni sveho vystupu
  • patrne proces 2 mohl ulozit hodnotu 2 do globalni promenne n, protoze proces 1 precetl tuto hodnotu a ulozil do sveho runtime zasobniku
  • nicmeme, tady zacinaji problemy, protoze proces 3 cte stejnou hodnotu 2 z globalni promenne n, to se evidentne stalo, protoze proces 1 byl prerusen, predtim, nez mohl ulozit svoji zmenu na hodnotu 3 do globalni promenne n

Pri pouziti option -p pri spusteni intepretu byl vytvoren soubor s priponou .xpc, ve kterem je exaktne zapsano prokladani PCODE instrukci, pr.:

c. instrukce c. procesu PCODE pozice
81 1 14
82 1 15
83 1 16
84 1 17
85 3 16
86 3 17
87 3 18
88 3 19
89 1 18
90 1 19
99 2 20
  • po probehnuti instrukce 84procesu 1, DO_ADD instrukce, dojde k prepnuti kontextu a proces 3 pak provede instrukce 16.17.18.19, STORE instrukce na pozici 18 ulozi hodnotu 3, kterou ma proces 3 na vrcholu zasobniku, zpet do promenne n
  • pak proces 1 dostane sanci bezet a provede instrukce 18 a 19. Kdyz provadi STORE na pozici 18, prepise hodnotu 3 ulozenou procesem 3 hodnotou rovnez 3, inkrementace se ztratila
  • dokoncime program

(h = help)> u 0

(h = help)> u 1

(h = help)> c

A n =3 i =1 B n =3C n =3 i =A

2 i =C1

B

A n =4 i =2 A

C n =5B i =3 n =A n =7 i =2 B7 i =

3 A

C

A n =8 i =4 A

C n =9 i =4 C

A n =10B n =10 i = i =5 3 A

B

C n =11 i =5 C

B n =12 i =4 B

B n =13 i =5 B

The sum is 13

PCODE execution trace stored in incremen.xpc

  • protoze je soucet 13, konflikt nastal behem programu 2 krat
 

mailBox

Karel Tauser

Stranka BACI Stranka ZOS Posledni uprava : 16.11. 2000