gdbによるデバッグのチュートリアル その1

gccで作ったC言語のプログラムを、gdbコマンドを使用してデバッグしてみます。

今回の実験環境は以下の通り。
linux環境でテストしてますが、cygwinでも問題なく動作するはずです…

$ gcc --version
gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
 
$ gdb --version
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
 
$ uname -a
Linux linuxmint 3.0.0-12-generic #20-Ubuntu SMP Fri Oct 7 14:50:42 UTC 2011 i686 i686 i386 GNU/Linux



今回実験で使うソースコードです。
単なる足し算プログラムです。

/* test01.c */
#include <stdio.h>
 
int sum( int a, int b );
 
int main()
{
 
    int a = 10; 
    int b = a  * 2;
 
    int ans = sum( a, b );
    printf( "%d\n", ans );
    return 0;
}
 
int sum( int a, int b )
{
    int result = a + b;
    return result;
}



これをコンパイルします。
コンパイル時に-gでデバッグ情報を埋め込むと共に、-O0で最適化を抑制します。
また、-Sオプションでアセンブラのコードも出力しておきます。

$ gcc -g -O0 -o test01 test01.c
 
$ gcc -S -O0 test01.c
 
$ ls
test01  test01.c  test01.s



出来上がったtest01.sはこんな感じ。

        .file   "test01.c"
        .section        .rodata
.LC0:
        .string "%d\n"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        andl    $-16, %esp
        subl    $32, %esp
        movl    $10, 20(%esp)
        movl    20(%esp), %eax
        addl    %eax, %eax
        movl    %eax, 24(%esp)
        movl    24(%esp), %eax
        movl    %eax, 4(%esp)
        movl    20(%esp), %eax
        movl    %eax, (%esp)
        call    sum
        movl    %eax, 28(%esp)
        movl    $.LC0, %eax
        movl    28(%esp), %edx
        movl    %edx, 4(%esp)
        movl    %eax, (%esp)
        call    printf
        movl    $0, %eax
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .globl  sum
        .type   sum, @function
sum:
.LFB1:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        subl    $16, %esp
        movl    12(%ebp), %eax
        movl    8(%ebp), %edx
        addl    %edx, %eax
        movl    %eax, -4(%ebp)
        movl    -4(%ebp), %eax
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
.LFE1:
        .size   sum, .-sum
        .ident  "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
        .section        .note.GNU-stack,"",@progbits



作ったプログラムをgdbに読み込ませます。

$ gdb ./test01
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
Copyright (C) 2011 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 "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/user/work/test01...done.



コンパイル時に-gオプションを付け忘れると、最後の行が以下の出力になります。
デバッグシンボルが無いよ。と怒られてます。

Reading symbols from /home/user/work/test01...(no debugging symbols found)...done.



listコマンドでソースを確認します。
オプションをつけると、行番号指定や関数名指定で表示する事ができます。

(gdb) list 
1   #include <stdio.h>
2   
3   int sum( int a, int b );
4   
5   int main()
6   {
7   
8       int a = 10;
9       int b = a  * 2;
10  
 
(gdb) list 5, 12
5   int main()
6   {
7   
8       int a = 10;
9       int b = a  * 2;
10  
11      int ans = sum( a, b );
12      printf( "%d\n", ans );
 
(gdb) list sum
12      printf( "%d\n", ans );
13      return 0;
14  }
15  
16  int sum( int a, int b ) 
17  {
18      int result = a + b;
19      return result;
20  }



bコマンド(break)で、ブレークポイントをセットできます。

(gdb) b 8
Breakpoint 1 at 0x80483ed: file test01.c, line 8.



startでプログラムの実行開始です。
ブレークポイントを設定していたので、8行目で止まりました。
nextコマンドでもう1行だけ進めます。

(gdb) start
Temporary breakpoint 2 at 0x80483ed: file test01.c, line 8.
Starting program: /home/user1/work/test01 
 
Breakpoint 1, main () at test01.c:8
8       int a = 10;
(gdb) next
9       int b = a  * 2;



info bで、ブレークポイント一覧が確認できます。

(gdb) info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x080483ed in main at test01.c:8
    breakpoint already hit 1 time



printで変数の中身を表示します。
変数bは、まだ初期化されてないので不定値が入ってます。

(gdb) print a
$2 = 10
(gdb) print b
$3 = 134513753



もう一行進めたらセットされました。

(gdb) next
11      int ans = sum( a, b );
(gdb) print b
$4 = 20



変数のアドレスも確認できます。

(gdb) print &a
$5 = (int *) 0xbffff874
(gdb) print &b
$6 = (int *) 0xbffff878



長くなってきたので、続きは次の記事へ…
次記事 -> gdbによるデバッグのチュートリアル その2
続きはでは、レジスタとスタック領域の使われ方を確認します。

関連記事

コメントを残す

メールアドレスが公開されることはありません。