すがブロ

sugamasaoのhatenablogだよ

GDBを使ってみる

ちょっとコマンドラインデバッガを使いたくなった

IDEを使うのが許されるのは小学生までらしいのでコマンドラインでやってみる。
ここで GDB を触っておけば Ruby でも似たようなノリでデバッグできること請け合いですからして、これはとても有意義な挑戦ですね。

超サンプル

  1 #include <stdio.h>
  2 
  3 int main(void) {
  4   int i;
  5   for(i = 0; i < 10; i++) {
  6     printf("test%02d\n", i);
  7   }
  8 
  9   return 0;
 10 }

コンパイルして GDB で実行する

/tmp% gcc -g ./test.c && gdb ./a.out

なんか色々文字が出てきた。

GNU gdb 6.3.50-20050815 (Apple version gdb-768) (Tue Oct  2 04:07:49 UTC 2007)
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.
This GDB was configured as "i386-apple-darwin"...Reading symbols for shared libraries ... done

(gdb) 

適当にググってみると、どうやら break main とやれば main 関数で止まってくれるようだ。
参考:http://blog.miraclelinux.com/yume/2006/09/post_fa59.html(吉岡さん素晴らしい!!)

(gdb) break main
Breakpoint 1 at 0x1fbf: file test.c, line 5.

これでブレイクポイントを設置できたようだ。実行してみよう。

(gdb) run
Starting program: /private/tmp/a.out 
Reading symbols for shared libraries ++. done

Breakpoint 1, main () at test.c:5
5         for(i = 0; i < 10; i++) {
(gdb) 

おぉ、5行目で止まっているっぽい。
次の行に進めるのは next でやるようだ。nでも大丈夫みたい。

(gdb) next
6           printf("test%02d\n", i);
(gdb) n
test00
5         for(i = 0; i < 10; i++) {
(gdb) n
6           printf("test%02d\n", i);
(gdb) n
test01
5         for(i = 0; i < 10; i++) {
(gdb) 

おぉ、実行できてる!
ちなみに、n だと関数の中に入って行かないらしいが、 step(s)を使うと中に潜れるようだ。

さて、そろそろ変数が見たい訳だが

どうやら p で覗けるらしい。

(gdb) n
test03
5         for(i = 0; i < 10; i++) {
(gdb) p i
$10 = 3

3 を出力した後の i の値は 3 になっているらしい。ちなみに、計算もできる。

(gdb) p 123+124
$12 = 247

どうでも良いまめ知識だ。
ちなみに、再実行、もしくは処理をそのまま続行して抜けるには continue(c) でやるようだ。

(gdb) c
Continuing.
test04
test05
test06
test07
test08
test09

Program exited normally.
(gdb) 

おぉ、おわった。
ここでまた run をやると break point まで行って止まるんだろうな。ちなみに、 run は r でもよかったみたいだ。

ここまでのまとめ

  1. とりあえず関数に break point を打つ(例: break main)
  2. break point まで実行(例: r)
  3. n(関数の中に入りたければ s)でお目当ての行まで進む
  4. 変数の中身を見るときは p 変数名(例:p i)

関数があるプログラムで試し見る

アホみたいに簡単なプログラム。変数を見やすくする為に、あえて int z とか使ってみる。

  1 #include <stdio.h>
  2 
  3 int sum(int a, int b) {
  4   int z = a + b;
  5   return z;
  6 }
  7 
  8 int main(void) {
  9   int i;
 10   for(i = 0; i < 10; i++) {
 11     printf("sum=%02d\n", sum(i, 10));
 12   }
 13 
 14   return 0;
 15 }

実行して、 break point を仕掛ける。試しに適当な文字を入力したら「そんなのしらねー」とおこられた。

/tmp% gcc -g ./test.c && gdb ./a.out
GNU gdb 6.3.50-20050815 (Apple version gdb-768) (Tue Oct  2 04:07:49 UTC 2007)
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.
This GDB was configured as "i386-apple-darwin"...Reading symbols for shared libraries ... done

(gdb) break a
Cannot access memory at address 0xfb536088
(gdb) break sum
Breakpoint 1 at 0x1f94: file test.c, line 4.

やっぱり break 関数名でちゃんと行けるようだ。
さっそく run してみよう。

(gdb) run
Starting program: /private/tmp/a.out 

Breakpoint 1, sum (a=0, b=10) at test.c:4
4         int z = a + b;

おぉ、ちゃんと sum 関数で止まってる。しかも引数が表示されてるぞ!

(gdb) p z
$1 = -1880951536

先走って z をインスペクトしたらおかしな値になった。まだ初期化が済んでないっぽい。どうやら先走りすぎたようだ。
一度勧めてからインスペクトしてみる。

(gdb) n
5         return z;
(gdb) p z
$3 = 10

今度は値が入ってる。
ちなみに、list(l) でソースが見れる。
引数を与えないと、今 break している箇所前後のソースが見れる。

(gdb) p z
$3 = 10
(gdb) list
1       #include <stdio.h>
2
3       int sum(int a, int b) {
4         int z = a + b;
5         return z;
6       }
7
8       int main(void) {
9         int i;
10        for(i = 0; i < 10; i++) {

もう一度押すとソースの続きが表示される。

(gdb) list
11          printf("sum=%02d\n", sum(i, 10));
12        }
13
14        return 0;
15      }

ソースの一番したまで行ったら n とかで次に進むと良いらしい。
引数に関数名を入れてみる。

Line number 16 out of range; test.c has 15 lines.
(gdb) list sum
1       #include <stdio.h>
2
3       int sum(int a, int b) {
4         int z = a + b;
5         return z;
6       }
7
8       int main(void) {
9         int i;
10        for(i = 0; i < 10; i++) {

おぉ、今ソースの一番したに居るのに sum 関数の所のソースが見れる。

なるほどなるほど

基本的な使い方は大分わかってきた気がする。
あと、ちょっとした発見だけど、コマンドを入力しないでエンターを押すと直前のコマンドを入力してくれるっぽい。これで無駄に n キーを連打しないでステップ実行できるようですね。
あとは変数がポインタだったり、構造体だった場合にどんな具合が見たいのだけど、さすがに力つきた/(^o^)\