sysvbannerをGDBで追う(条件break)


『ViVid Strike!』(ヴィヴィッド ストライク)
孤児の少女フーカは、数十人の不良を一人で相手できるほど喧嘩が強いのですが、トレーニングジムの選手の少女たちには、まったく敵わないのでした。
でも、さすが、自力で強くなっただけあります。センスがあるので、少しのアドバイスで、訓練している選手を打ち負かすことができたのでした。

いくら良いものを持ってても、地道に訓練している人には勝てませんね。地道っていうのが大事です。訓練も継続しなければ上達はやってきません。 継続するにはどうすれば良いでしょうか。目標や計画が必要といいますが、頭の硬い話だなあと思います。継続なんてものは習慣化するかどうかの問題でしょう。 目標や計画がなくても習慣化はできるはずです。「計画を立てるべき」と、もっともなことを言う人ほど、継続をしていないなあと思います(もちろんやってる人もいると思いますが)。と、過去の自分を批判してみました。継続させるには、「よーし、やるぞ」と自分に宣言するだけでいいんです。

さて、プログラミングができても、デバッグができない、なんてこともあるかと思います。デバッグテクニックも、地道に身につけていこうかと思います。
今回は条件breakです。いつものようにGDBを起動します。runコマンドの引数は”Vivid Strike !”としました。

takk@deb83:~/sysvbanner-1.0.15$ gdb banner
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1

(省略)

(gdb) run Vivid Strike !
Starting program: /home/takk/sysvbanner-1.0.15/banner Vivid Strike !

Breakpoint 1, main (argc=4, argv=0xbffff774) at banner.c:132
132	  for (argv++; --argc; argv++) {
(gdb) 

スペース区切りで複数の文字列を指定すると、改行されてバナー表示されますが、”Strike”の文字列の時の動きを見たいので、*argvが”Strike”になった時にブレイクするように指定してみます。

ただ、C言語と同じで、文字列の一致ではなく、数値の一致になるので、**argv==’S’という形の条件設定となります。まずは、ソースを確認して、ブレイクする行を決めましょう。

(gdb) l
127	int main(int argc, char **argv)
128	{
129	  int a, b, c, len, ind;
130	  char line[80];
131	
132	  for (argv++; --argc; argv++) {
133	    len = strlen(*argv);
134	    if (len > 10)
135	      len = 10;
136	    for (a = 0; a < 7; a++) {
(gdb) 

各文字列の処理の開始っぽい、133行目にブレイク設定します。

(gdb) b 133 if **argv=='S'
Breakpoint 2 at 0x8048449: file banner.c, line 133.
(gdb) 

displayで、オート変数も自動表示するようにしておきます。
まとめられる変数は、括弧{}で、まとめます。

(gdb) disp {a,b,c,len,ind}
1: {a,b,c,len,ind} = {134514194, 134523828, 47, -1073743704, 134513341}
(gdb) 

次に、変数lineも登録したいですが、80Byteの配列となっています。 このままでは以下のように全部表示されて見難くなります。

(gdb) p line
$1 = "\001\000\000\000,\000\000\000\006\000\000\000}0\264,\000\000\000\000\024\3
67\377\277\210\366\377\277\200\366\377\277\062\202\004\b0\371\377\267\000\000\00
0\000\277\000\000\000\026o\352\267\377\377\377\377\256\366\377\277\370\333\341\2
67C\"\344\267\000\000\000\000}0\264,\001\000\000"
(gdb) 

ですので文字列にキャストして表示します。

(gdb) p/s (char*)line
$2 = 0xbffff64c "\001"
(gdb) 

文字列にキャストすることで、0(NULL)が出現するところまでしか表示されません。
これをdisplayに登録しておきます。

(gdb) disp/s (char*)line
2: x/s (char*)line  0xbffff64c:	"\001"
(gdb) 

現状の設定を確認しましょう。

(gdb) info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048440 in main at banner.c:132
	breakpoint already hit 1 time
2       breakpoint     keep y   0x08048449 in main at banner.c:133
	stop only if **argv=='S'
(gdb) disp
2: x/s (char*)line  0xbffff64c:	"\001"
1: {a,b,c,len,ind} = {134514194, 134523828, 47, -1073743704, 134513341}
(gdb) 

では、実行(continue)してみます。

(gdb) c
Continuing.
#     #
#     #     #    #    #     #    #####
#     #     #    #    #     #    #    #
#     #     #    #    #     #    #    #
 #   #      #    #    #     #    #    #
  # #       #     #  #      #    #    #
   #        #      ##       #    #####


Breakpoint 2, main (argc=2, argv=0xbffff77c) at banner.c:133
133	    len = strlen(*argv);
2: x/s (char*)line  0xbffff64c:	"   #        #      ##       #    #####"
1: {a,b,c,len,ind} = {7, 37, 7, 5, 68}
(gdb) 

Vividの結果表示がされましたが、 “Strike”でブレイクしたのでしょうか、*argvを確認してみます。

(gdb) p/s *argv
$1 = 0xbffff8d2 "Strike"
(gdb) 

*argvが”Strike”になっていますね。

続いてステップ実行(next)していきます。

(gdb) n
134	    if (len > 10)
2: x/s (char*)line  0xbffff64c:	"   #        #      ##       #    #####"
1: {a,b,c,len,ind} = {7, 37, 7, 6, 68}
(gdb) 

lenが10を超えているかのif文ですが、dispのlenの値を見ると6ですので、超えませんね。

続いて、各for文をステップ実行します。

(gdb) n
136	    for (a = 0; a < 7; a++) {
2: x/s (char*)line  0xbffff64c:	"   #        #      ##       #    #####"
1: {a,b,c,len,ind} = {7, 37, 7, 6, 68}
(gdb) 
137	      for (b = 0; b < len; b++) {
2: x/s (char*)line  0xbffff64c:	"   #        #      ##       #    #####"
1: {a,b,c,len,ind} = {0, 37, 7, 6, 68}
(gdb) 
138		if ((ind = (*argv)[b] - ' ') < 0)
2: x/s (char*)line  0xbffff64c:	"   #        #      ##       #    #####"
1: {a,b,c,len,ind} = {0, 0, 7, 6, 68}
(gdb) 

(*argv)[b]ということは、bが、文字列の先頭からの位置をしめしていますね。
bが文字列の長さつまり、len分回ります。

さらにステップ実行してみましょう。

(gdb) n
140		for (c = 0; c < 7; c++) {
2: x/s (char*)line  0xbffff64c:	"   #        #      ##       #    #####"
1: {a,b,c,len,ind} = {0, 0, 7, 6, 51}
(gdb) 
141		  line[b * 8 + c] = glyphs[(ind / 8 * 7) + a][(ind % 8 * 7) + c];
2: x/s (char*)line  0xbffff64c:	"   #        #      ##       #    #####"
1: {a,b,c,len,ind} = {0, 0, 0, 6, 51}
(gdb) 

この行にbreakでブレイクポイントを設定して、continueで一周してみましょう。

(gdb) b
Breakpoint 3 at 0x80484ae: file banner.c, line 141.
(gdb) c
Continuing.

Breakpoint 3, main (argc=2, argv=0xbffff77c) at banner.c:141
141		  line[b * 8 + c] = glyphs[(ind / 8 * 7) + a][(ind % 8 * 7) + c];
2: x/s (char*)line  0xbffff64c:	"   #        #      ##       #    #####"
1: {a,b,c,len,ind} = {0, 0, 1, 6, 51}
(gdb) 

変数cが1になりました。回数を指定してcontinueしてみます。

(gdb) c 5
Will ignore next 4 crossings of breakpoint 3.  Continuing.

Breakpoint 3, main (argc=2, argv=0xbffff77c) at banner.c:141
141		  line[b * 8 + c] = glyphs[(ind / 8 * 7) + a][(ind % 8 * 7) + c];
2: x/s (char*)line  0xbffff64c:	" #####      #      ##       #    #####"
1: {a,b,c,len,ind} = {0, 0, 6, 6, 51}
(gdb) 

5周回しました。次は変数cが7になるので、forから抜けますね。

(gdb) n
140		for (c = 0; c < 7; c++) {
2: x/s (char*)line  0xbffff64c:	" #####      #      ##       #    #####"
1: {a,b,c,len,ind} = {0, 0, 6, 6, 51}
(gdb) 
143		line[b * 8 + 7] = ' ';
2: x/s (char*)line  0xbffff64c:	" #####      #      ##       #    #####"
1: {a,b,c,len,ind} = {0, 0, 7, 6, 51}
(gdb) 
137	      for (b = 0; b < len; b++) {
2: x/s (char*)line  0xbffff64c:	" #####      #      ##       #    #####"
1: {a,b,c,len,ind} = {0, 0, 7, 6, 51}
(gdb) 

続く。

コメント

タイトルとURLをコピーしました