プログラミングなどなど

プログラミングに関係しそうな内容を

SPIN,C言語,デバッグ:State Vectorと変数

SpinIntro.pdf」の「SPIN's Basic Data Structures」を見ると状態ベクトル(State vecot)は全ての変数を保持している旨の記載があります。また、PanのCompile-Time Optionsには状態ベクトルをダンプするオプション(SDUMP)について記載があります。

コンパイルオプションを指定して状態ベクトルを出力させてみたのですが、読み方がわからず、私は読み方の情報も探せませんでした。ちょうどpanのソースはC言語なので変数の部分に着目してデバッグしてみました。

使用したソースは以下となります。

使用したソースから検証器の実行まで

ソース 2p.pml
byte a;

active proctype p()
{
  a = 170; /* 0xaa = -86 */
}

byte b;
active proctype q()
{
  b = 187; /* 0xbb = -69 */
}
検証器の生成

検証器の生成時に-o2オプションを使用しています。今回使用したソースでは、-o2オプションを使用しないと変数a,bが状態ベクトルに含まれてきませんでした。これは、aとbを書き込みにのみ使用しているためと思われます。

$ spin -a -o2 2p.pml
検証器のコンパイル

SDUMPを含めて以下のようにコンパイルを行いました。

$ gcc -w -g3 -DVERBOSE -DSDUMP -DNOCOMP pan.c -o pan
実行結果

今回のケースではStateとVectorが同じ値になりました。(NOCOMPの効果?)
^が変数aとbの部分となります。顕著な変化があるのは以下の部分となります。

  • New state 1 でStateが変化しています。0から-69になっている部分がbの部分でb = 187 によるものです。
  • New state 3 でStateが変化しています。0から-86になっている部分がaの部分でa = 170 によるものです。
$ ./pan 
0: Down - program non-accepting [pids 1-0]
	New state 0
	 State: 2,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1,9,0,0,
	Vector: 2,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1,9,0,0,
                                 ^a^b
Pr: 1 Tr: 3
  0: proc 1 exec 3, 1 to 2, b = 187   non-accepting [tau=0]
1: Down - program non-accepting [pids 1-0]
	New state 1
	 State: 2,0,0,0,0,0,28,0,0,-69,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1,17,0,0,
	Vector: 2,0,0,0,0,0,28,0,0,-69,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1,17,0,0,
                                 ^a^^^b
  1: proc 1 PreSelected (tau=32)
Pr: 1 Tr: 4
  1: proc 1 exec 4, 2 to 0, -end-   non-accepting [tau=32]
2: Down - program non-accepting [pids 0-0]
	New state 2
	 State: 1,0,0,0,0,0,20,0,0,-69,0,0,0,0,0,0,0,8,0,0,
	Vector: 1,0,0,0,0,0,20,0,0,-69,0,0,0,0,0,0,0,8,0,0,
                                 ^a^^^b
Pr: 0 Tr: 5
  2: proc 0 exec 5, 1 to 2, a = 170   non-accepting [tau=0]
3: Down - program non-accepting [pids 0-0]
	New state 3
	 State: 1,0,0,0,0,0,20,0,-86,-69,0,0,0,0,0,0,0,16,0,0,
	Vector: 1,0,0,0,0,0,20,0,-86,-69,0,0,0,0,0,0,0,16,0,0,
                                 ^^^a^^^b
Pr: 0 Tr: 6
  3: proc 0 exec 6, 2 to 0, -end-   non-accepting [tau=0]
4: Down - program non-accepting [pids -1-0]
	New state 4
	 State: 0,0,0,0,0,0,10,0,-86,-69,
	Vector: 0,0,0,0,0,0,10,0,-86,-69,
                                 ^^^a^^^b
  4: no move [II=-1, tau=0, boq=-1]
4: Up - program
  4: proc 0 reverses 6, 2 to 0
	-end- [abit=0,adepth=0,tau=0,0]
3: Up - program
  3: proc 0 reverses 5, 1 to 2
	a = 170 [abit=0,adepth=0,tau=0,0]
2: Up - program
  2: proc 1 reverses 4, 2 to 0
	-end- [abit=0,adepth=0,tau=0,32]
1: Up - program
  1: proc 1 reverses 3, 1 to 2
	b = 187 [abit=0,adepth=0,tau=32,0]
Pr: 0 Tr: 5
  0: proc 0 exec 5, 1 to 2, a = 170   non-accepting [tau=0]
1: Down - program non-accepting [pids 1-0]
	New state 5
	 State: 2,0,0,0,0,0,28,0,-86,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,1,9,0,0,
	Vector: 2,0,0,0,0,0,28,0,-86,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,1,9,0,0,
                               ^a^^^b
Pr: 1 Tr: 3
  1: proc 1 exec 3, 1 to 2, b = 187   non-accepting [tau=0]
2: Down - program non-accepting [pids 1-0]
	New state 6
	 State: 2,0,0,0,0,0,28,0,-86,-69,0,0,0,0,0,0,0,16,0,0,0,0,0,0,1,17,0,0,
	Vector: 2,0,0,0,0,0,28,0,-86,-69,0,0,0,0,0,0,0,16,0,0,0,0,0,0,1,17,0,0,
                                 ^^^a^^^b
  2: proc 1 PreSelected (tau=32)
Pr: 1 Tr: 4
  2: proc 1 exec 4, 2 to 0, -end-   non-accepting [tau=32]
3: Down - program non-accepting [pids 0-0]
	Old state 3
	 State: 1,0,0,0,0,0,20,0,-86,-69,0,0,0,0,0,0,0,16,0,0,
	Vector: 1,0,0,0,0,0,20,0,-86,-69,0,0,0,0,0,0,0,16,0,0,
                                 ^^^a^^^b
3: Up - program
  3: proc 1 reverses 4, 2 to 0
	-end- [abit=0,adepth=0,tau=0,32]
2: Up - program
  2: proc 1 reverses 3, 1 to 2
	b = 187 [abit=0,adepth=0,tau=32,0]
Pr: 0 Tr: 6
1: Up - program
  1: proc 0 reverses 5, 1 to 2
	a = 170 [abit=0,adepth=0,tau=0,0]

(Spin Version 6.4.9 -- 17 December 2018)
	+ Partial Order Reduction
	+ FullStack Matching

Full statespace search for:
	never claim         	- (none specified)
	assertion violations	+
	acceptance   cycles 	- (not selected)
	invalid end states	+

State-vector 28 byte, depth reached 4, errors: 0
        7 states, stored
        1 states, matched
        0 matches within stack
        8 transitions (= stored+matched)
        0 atomic steps
hash conflicts:         0 (resolved)
stackframes: 2/0

stats: fa 0, fh 0, zh 0, zn 0 - check 3 holds 2
stack stats: puts 0, probes 0, zaps 0
  128.730	memory usage (Mbyte)

unreached in proctype p
	(0 of 2 states)
unreached in proctype q
	(0 of 2 states)

pan: elapsed time 0 seconds

State の出力部分をGDBで調べる

実際にデバッグした際はmainから調べるなどトライ&エラーしていますが、以下の説明ではその辺りは省略しています。

pan実行時のState:...部分を出力しているdumpstate関数にブレークポイントを設定することからデバッグを始めています。

$ gdb ./pan 
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 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 ./pan...done.
(gdb) break dumpstate <-- トライ&エラーでこの関数でState: ...の部分が出力されいることを予め調べています。
Breakpoint 1 at 0xa050: file pan.c, line 11346.
(gdb) run
Starting program: /home/makoto/blog/13/pan 
0: Down - program non-accepting [pids 1-0]
	New state 0

Breakpoint 1, dumpstate (wasnew=-1, v=0x55555576d1e0 <now> "\002", n=28, tag=1) at pan.c:11346
11346		printf("	 State: ");
(gdb) until 
11351		for (i = 0; i < vsize; i++)
(gdb) 
11352			printf("%d,", ((char *)&now)[i]); <-- ここでコンマセパレートで出力されています。
(gdb) 
11351		for (i = 0; i < vsize; i++)
(gdb) 
11354		printf("\n	Vector: ");
(gdb) 
	 State: 2,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1,9,0,0,
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         出力されているのは、nowの値のようです。

11355		for (i = 0; i < n; i++)
(gdb) ptype now <-- nowの型を調べます。
type = struct State {
    unsigned char _nr_pr;
    unsigned char _nr_qs;
    unsigned char _a_t;
    unsigned char _cnt[2];
    unsigned short _vsz;
    unsigned char a;   <--  変数a
    unsigned char b;          <--  変数b
    unsigned char sv[1024];
}
(gdb) l 11352
11347	#if !defined(NOCOMP) && !defined(HC)
11348		for (i = 0; i < vsize; i++) printf("%d%s,",
11349			((char *)&now)[i], Mask[i]?"*":"");
11350	#else
11351		for (i = 0; i < vsize; i++)
11352			printf("%d,", ((char *)&now)[i]); <-- NOCOMPを定義しているのでこのルートを通ります。
11353	#endif
11354		printf("\n	Vector: ");
11355		for (i = 0; i < n; i++)
11356			printf("%d,", v[i]);
(gdb) continue 
Continuing.
	Vector: 2,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1,9,0,0,
Pr: 1 Tr: 3
  0: proc 1 exec 3, 1 to 2, b = 187   non-accepting [tau=0]
1: Down - program non-accepting [pids 1-0]
	New state 1

Breakpoint 1, dumpstate (wasnew=-1, v=0x55555576d1e0 <now> "\002", n=28, tag=2) at pan.c:11346
^^^^^^^^^^^^2回目のブレークなので、b=187が実行された後となります。

11346		printf("	 State: ");
(gdb) p now
$1 = {_nr_pr = 2 '\002', _nr_qs = 0 '\000', _a_t = 0 '\000', _cnt = "\000", _vsz = 28, a = 0 '\000', 
  b = 187 '\273', 
  sv = "\000\000\000\000\000\000\000\b\000\000\000\000\000\000\001\021", '\000' <repeats 1007 times>}

  -> nowの中身を見るとbは187となっています。

(gdb) until 
11351		for (i = 0; i < vsize; i++)
(gdb) 
11352			printf("%d,", ((char *)&now)[i]);
(gdb) 
11351		for (i = 0; i < vsize; i++)
(gdb) 
11354		printf("\n	Vector: ");
(gdb) 
	 State: 2,0,0,0,0,0,28,0,0,-69,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1,17,0,0,
                ^^^^^^^^^^^^^^^^^^^^^^^
               +0,1,2,3,4,5, 6,7,8,  9

               -> 9個目がbの場所となります。詳細を調べてみます。

11355		for (i = 0; i < n; i++)
(gdb) printf "%d\n", (char)187
-69
(gdb) p (char *)(&now.b) - (char *)&now  <-- nowの先頭とnow.bの差を確認する。
$9 = 9
(gdb) x/16x &now
                        +0      +1      +2      +3      +4      +5      +6      +7
0x55555576d1e0 <now>:	0x02	0x00	0x00	0x00	0x00	0x00	0x1c	0x00
                        +8      +9
0x55555576d1e8 <now+8>:	0x00	0xbb	0x00	0x00	0x00	0x00	0x00	0x00

状態aとbを保持したState型の変数nowがコンマセパレートで出力されていました。