GDB による CUI デバッグ¶
GDB の起動と終了¶
起動¶
デバッグビルドされた a.exe
をデバッグするために
下記コマンドを打って GDB を起動します。
$ gdb a.exe
GDB は起動時にバージョンなどの情報を出力します。
a.exe
の読み込みに成功するとバージョンなどの情報の後に
Reading symbols from ./a.exe...done.
のようなメッセージが出力されます。
プロンプトと呼ばれる文字列 (gdb)
が出力されると GDB のコマンドを入力することができます。
終了¶
quit
で GDB を終了することができます。
(gdb) quit
quit
は q
と省略できます。
(gdb) q
デバッグ開始¶
run
でデバッグ対象プログラムを開始します。
(gdb) run
run
は r
と省略できます。
(gdb) r
ブレークポイントが設定されていない状態だとプログラム終了まで実行されます。
ブレークポイント¶
以下のコードで説明します。
1 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 |
|
1 2 3 4 5 |
|
追加¶
break ファイル:行番号
または break 関数名
でブレークポイントを追加します。
(gdb) break main.cc:6
Breakpoint 1 at 0x10040108d: file main.cc, line 6.
(gdb) break Sum
Breakpoint 2 at 0x10040113a: file sum.cc, line 4.
break
は b
と省略することもできます。
(gdb) b main.cc:6
Breakpoint 1 at 0x10040108d: file main.cc, line 6.
(gdb) b Sum
Breakpoint 2 at 0x10040113a: file sum.cc, line 4.
一覧の確認¶
info breakpoints
でブレークポイントの一覧を確認することができます。
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000010040108d in main() at main.cc:6
2 breakpoint keep y 0x000000010040113a in Sum(int, int) at sum.cc:4
info
は i
と省略できます。
breakpoints
は break
や b
と省略できます。
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000010040108d in main() at main.cc:6
2 breakpoint keep y 0x000000010040113a in Sum(int, int) at sum.cc:4
プログラムの一時停止¶
ブレークポイントを追加した状態でデバッグを開始すると、 ブレークポイントに到達した時点でプログラムが一時停止します。
(gdb) run
Starting program: a.exe
[New Thread 10676.0x3cf8]
[New Thread 10676.0x1ab8]
[New Thread 10676.0x17e4]
[New Thread 10676.0x1494]
[New Thread 10676.0x36a4]
Thread 1 "a" hit Breakpoint 1, main () at main.cc:6
6 std::cout << Sum(1, 2) << std::endl;
プログラムの再開¶
continue
でプログラムを再開することができます。
次のブレークポイントに到達すると再び一時停止します。
(gdb) continue
Continuing.
Thread 1 "a" hit Breakpoint 2, Sum (a=1, b=2) at sum.cc:4
4 return a + b;
削除¶
delete n
でブレークポイントを削除することができます。
n
には info breakpoints
の Num
の値で指定します。
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000010040108d in main() at main.cc:6
2 breakpoint keep y 0x000000010040113a in Sum(int, int) at sum.cc:4
(gdb) delete 1
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y 0x000000010040113a in Sum(int, int) at sum.cc:4
delete
は d
と省略できます。
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000010040108d in main() at main.cc:6
2 breakpoint keep y 0x000000010040113a in Sum(int, int) at sum.cc:4
(gdb) d 1
(gdb) i b
Num Type Disp Enb Address What
2 breakpoint keep y 0x000000010040113a in Sum(int, int) at sum.cc:4
delete
で対象を指定しない場合にはすべてのブレークポイントを削除します。
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000010040108d in main() at main.cc:6
2 breakpoint keep y 0x000000010040113a in Sum(int, int) at sum.cc:4
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) info breakpoints
No breakpoints or watchpoints.
評価値の表示¶
以下のコードで説明します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
変数の値を確認¶
print
で変数の値を確認することができます。
(gdb) break main.cc:17
(gdb) run
Thread 1 "a" hit Breakpoint 1, LeastCommonMultiple (a=12, b=18) at main.cc:17
17 return a * b / gcd;
(gdb) print a
$1 = 12
(gdb) print b
$2 = 18
(gdb) print gcd
$3 = 6
print
は p
と省略できます。
(gdb) b main.cc:17
(gdb) r
Thread 1 "a" hit Breakpoint 1, LeastCommonMultiple (a=12, b=18) at main.cc:17
17 return a * b / gcd;
(gdb) p a
$1 = 12
(gdb) p b
$2 = 18
(gdb) p gcd
$3 = 6
確認した値の再利用¶
値を確認すると $n = 値
と出力され、 $n
で結果を再利用することができます。
(gdb) break main.cc:8
(gdb) break main.cc:9
(gdb) run
Starting program: a.exe
Thread 1 "a" hit Breakpoint 1, GreatestCommonDivisor (a=12, b=18) at main.cc:8
8 b = b % a;
(gdb) print b
$1 = 18
(gdb) continue
Continuing.
Thread 1 "a" hit Breakpoint 2, GreatestCommonDivisor (a=12, b=6) at main.cc:9
9 Swap(&a, &b);
(gdb) print b
$2 = 6
(gdb) print $1
$3 = 18
任意の処理を実行¶
print
では変数の値を確認するだけでなく、
関数呼び出しを行ってその戻り値を確認したり、任意の演算を行った結果を確認することができます。
(gdb) break main.cc:17
(gdb) run
Thread 1 "a" hit Breakpoint 1, LeastCommonMultiple (a=12, b=18) at main.cc:17
17 return a * b / gcd;
(gdb) print gcd
$1 = 6
(gdb) print GreatestCommonDivisor(b, a)
$2 = 6
変数の値を変更する代入なども行えてしまうため、副作用に気をつける必要があります。
(gdb) break main.cc:17
(gdb) run
Thread 1 "a" hit Breakpoint 1, LeastCommonMultiple (a=12, b=18) at main.cc:17
17 return a * b / gcd;
(gdb) print gcd
$1 = 6
(gdb) print gcd = 0
$2 = 0
(gdb) print gcd
$3 = 0
ポインタに対する操作¶
変数からポインタを得る &
やデリファレンスの *
が使用できます。
(gdb) break main.cc:9
(gdb) break Swap
(gdb) run
Starting program: a.exe
Thread 1 "a" hit Breakpoint 1, GreatestCommonDivisor (a=12, b=6) at main.cc:9
9 Swap(&a, &b);
(gdb) print &a
$1 = (int *) 0xffffcb70
(gdb) continue
Continuing.
Thread 1 "a" hit Breakpoint 2, Swap (a=0xffffcb70, b=0xffffcb78) at swap.cc:4
4 int tmp = *a;
(gdb) print a
$2 = (int *) 0xffffcb70
(gdb) print *a
$3 = 12
ステップ実行¶
以下のコードで説明します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
ステップオーバー¶
next
で現在の行から次に処理がある行まで進めます。
(gdb) break Intersects
(gdb) run
Thread 1 "a" hit Breakpoint 1, Intersects (c1=..., c2=...) at main.cc:14
14 auto c = SquareOfDistance(c1.Center(), c2.Center());
(gdb) next
15 auto r = SquareOf(c1.Radius() + c2.Radius());
next
は n
と省略できます。
(gdb) b Intersects
(gdb) r
Thread 1 "a" hit Breakpoint 1, Intersects (c1=..., c2=...) at main.cc:14
14 auto c = SquareOfDistance(c1.Center(), c2.Center());
(gdb) n
15 auto r = SquareOf(c1.Radius() + c2.Radius());
ステップイン¶
step
で現在の処理から次の処理まで進めます。
現在の処理が関数呼び出しの場合には呼び出した関数の内部で停止します。
(gdb) break Intersects
(gdb) run
Thread 1 "a" hit Breakpoint 1, Intersects (c1=..., c2=...) at main.cc:14
14 auto c = SquareOfDistance(c1.Center(), c2.Center());
(gdb) step
Circle::Center (this=0xffffcb90) at circle.h:12
12 return center_;
step
は s
と省略できます。
(gdb) b Intersects
(gdb) r
Thread 1 "a" hit Breakpoint 1, Intersects (c1=..., c2=...) at main.cc:14
14 auto c = SquareOfDistance(c1.Center(), c2.Center());
(gdb) s
Circle::Center (this=0xffffcb90) at circle.h:12
12 return center_;
ステップアウト¶
finish
で現在の関数が終了して呼び出し元に戻るまで進めます。
(gdb) break Intersects
(gdb) run
Thread 1 "a" hit Breakpoint 1, Intersects (c1=..., c2=...) at main.cc:14
14 auto c = SquareOfDistance(c1.Center(), c2.Center());
(gdb) finish
Run till exit from #0 Intersects (c1=..., c2=...) at main.cc:14
0x0000000100401233 in main () at main.cc:23
23 if (Intersects(c1, c2)) {
Value returned is $1 = true
finish
は fin
と省略できます。
(gdb) b Intersects
(gdb) r
Thread 1 "a" hit Breakpoint 1, Intersects (c1=..., c2=...) at main.cc:14
14 auto c = SquareOfDistance(c1.Center(), c2.Center());
(gdb) fin
Run till exit from #0 Intersects (c1=..., c2=...) at main.cc:14
0x0000000100401233 in main () at main.cc:23
23 if (Intersects(c1, c2)) {
Value returned is $1 = true
実引数で関数の戻り値を使用する場合
auto c = SquareOfDistance(c1.Center(), c2.Center());
のように実引数として他の関数の戻り値を使用する場合には、
次のように step
と finish
を交互に使用することで実引数を求める各処理と
実引数を定めた後に呼び出す関数をデバッグすることができます。
(gdb) break Intersects
(gdb) run
Thread 1 "a" hit Breakpoint 1, Intersects (c1=..., c2=...) at main.cc:14
14 auto c = SquareOfDistance(c1.Center(), c2.Center());
(gdb) step
Circle::Center (this=0xffffcb90) at circle.h:12
12 return center_;
(gdb) finish
Run till exit from #0 Circle::Center (this=0xffffcb90) at circle.h:12
0x0000000100401133 in Intersects (c1=..., c2=...) at main.cc:14
14 auto c = SquareOfDistance(c1.Center(), c2.Center());
Value returned is $1 = {x_ = 5, y_ = 0}
(gdb) step
Circle::Center (this=0xffffcbb0) at circle.h:12
12 return center_;
(gdb) finish
Run till exit from #0 Circle::Center (this=0xffffcbb0) at circle.h:12
0x0000000100401143 in Intersects (c1=..., c2=...) at main.cc:14
14 auto c = SquareOfDistance(c1.Center(), c2.Center());
Value returned is $2 = {x_ = 1, y_ = 2}
(gdb) step
SquareOfDistance (p=..., q=...) at main.cc:10
10 return SquareOf(q.X() - p.X()) + SquareOf(q.Y() - p.Y());
スタックフレーム¶
以下のコードで説明します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
表示¶
backtrace
でスタックフレームの一覧を表示します。
現在の箇所に到達するまでの関数呼び出しを確認できます。
(gdb) break main.cc:5
(gdb) run
Thread 1 "a" hit Breakpoint 1, GreatestCommonDivisor (a=0, b=6) at main.cc:5
5 return b;
(gdb) backtrace
#0 GreatestCommonDivisor (a=0, b=6) at main.cc:5
#1 0x00000001004010ac in GreatestCommonDivisor (a=6, b=12) at main.cc:8
#2 0x00000001004010ac in GreatestCommonDivisor (a=12, b=18) at main.cc:8
#3 0x000000010040111f in main () at main.cc:15
backtrace
は bt
と省略できます。
(gdb) b main.cc:5
Breakpoint 1 at 0x100401094: file main.cc, line 5.
(gdb) r
Thread 1 "a" hit Breakpoint 1, GreatestCommonDivisor (a=0, b=6) at main.cc:5
5 return b;
(gdb) bt
#0 GreatestCommonDivisor (a=0, b=6) at main.cc:5
#1 0x00000001004010ac in GreatestCommonDivisor (a=6, b=12) at main.cc:8
#2 0x00000001004010ac in GreatestCommonDivisor (a=12, b=18) at main.cc:8
#3 0x000000010040111f in main () at main.cc:15
移動¶
up
や down
で GDB が参照するスタックフレームを上下に移動します。
GDB の参照箇所が移動するだけでプログラムの実行箇所は移動しません。
(gdb) backtrace
#0 GreatestCommonDivisor (a=0, b=6) at main.cc:5
#1 0x00000001004010ac in GreatestCommonDivisor (a=6, b=12) at main.cc:8
#2 0x00000001004010ac in GreatestCommonDivisor (a=12, b=18) at main.cc:8
#3 0x000000010040111f in main () at main.cc:15
(gdb) up
#1 0x00000001004010ac in GreatestCommonDivisor (a=6, b=12) at main.cc:8
8 return GreatestCommonDivisor(b % a, a);
(gdb) down
#0 GreatestCommonDivisor (a=0, b=6) at main.cc:5
5 return b;
frame
で GDB が参照しているスタックフレームを表示することができます。
(gdb) frame
#0 GreatestCommonDivisor (a=0, b=6) at main.cc:5
5 return b;
frame n
で #n
のフレームへ移動できます。
(gdb) frame
#0 GreatestCommonDivisor (a=0, b=6) at main.cc:5
5 return b;
(gdb) frame 3
#3 0x000000010040111f in main () at main.cc:15
15 << GreatestCommonDivisor(a, b) << " です" << std::endl;
(gdb) frame
#3 0x000000010040111f in main () at main.cc:15
15 << GreatestCommonDivisor(a, b) << " です" << std::endl;
frame
は f
と省略できます。
(gdb) bt
#0 GreatestCommonDivisor (a=0, b=6) at main.cc:5
#1 0x00000001004010ac in GreatestCommonDivisor (a=6, b=12) at main.cc:8
#2 0x00000001004010ac in GreatestCommonDivisor (a=12, b=18) at main.cc:8
#3 0x000000010040111f in main () at main.cc:15
(gdb) f 3
#3 0x000000010040111f in main () at main.cc:15
15 << GreatestCommonDivisor(a, b) << " です" << std::endl;
便利な機能¶
set pretty print¶
クラスや構造体を表示する際に見やすく整形するかどうか設定します。
set print pretty on
で有効、
set print pretty off
で無効にします。
使用例
以下のコードで説明します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
print
で t
の値を確認する際に整形の有無で次のように出力が変化します。
(gdb) break main.cc:19
(gdb) run
Thread 1 "a" hit Breakpoint 1, main () at main.cc:19
19 return 0;
(gdb) set print pretty on
(gdb) print t
$1 = {
a = {
x = 1,
y = 1
},
b = {
x = 2,
y = 0
},
c = {
x = 3,
y = 2
}
}
(gdb) set print pretty off
(gdb) print t
$2 = {a = {x = 1, y = 1}, b = {x = 2, y = 0}, c = {x = 3, y = 2}}
set pagination¶
出力する情報が画面内に収まらない場合に 収まる量ずつでページ送りをするかどうか設定します。
set pagination on
で有効、
set pagination off
で無効にします。
使用例
以下のコードで説明します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
スタックフレームの一覧が画面内に収まらない場合に ページ送りの有無で次のように出力が変化します。
(gdb) break main.cc:5
Breakpoint 1 at 0x100401097: file main.cc, line 5.
(gdb) run
Thread 1 "a" hit Breakpoint 1, Fibonacchi (n=0) at main.cc:5
5 return 0;
(gdb) set pagination on
(gdb) backtrace
#0 Fibonacchi (n=0) at main.cc:5
#1 0x00000001004010c7 in Fibonacchi (n=2) at main.cc:10
#2 0x00000001004010b8 in Fibonacchi (n=3) at main.cc:10
#3 0x00000001004010b8 in Fibonacchi (n=4) at main.cc:10
#4 0x00000001004010b8 in Fibonacchi (n=5) at main.cc:10
#5 0x00000001004010b8 in Fibonacchi (n=6) at main.cc:10
#6 0x00000001004010b8 in Fibonacchi (n=7) at main.cc:10
#7 0x00000001004010b8 in Fibonacchi (n=8) at main.cc:10
#8 0x00000001004010b8 in Fibonacchi (n=9) at main.cc:10
#9 0x00000001004010b8 in Fibonacchi (n=10) at main.cc:10
#10 0x00000001004010b8 in Fibonacchi (n=11) at main.cc:10
#11 0x00000001004010b8 in Fibonacchi (n=12) at main.cc:10
#12 0x00000001004010b8 in Fibonacchi (n=13) at main.cc:10
#13 0x00000001004010b8 in Fibonacchi (n=14) at main.cc:10
#14 0x00000001004010b8 in Fibonacchi (n=15) at main.cc:10
#15 0x00000001004010b8 in Fibonacchi (n=16) at main.cc:10
#16 0x00000001004010b8 in Fibonacchi (n=17) at main.cc:10
#17 0x00000001004010b8 in Fibonacchi (n=18) at main.cc:10
#18 0x00000001004010b8 in Fibonacchi (n=19) at main.cc:10
#19 0x00000001004010b8 in Fibonacchi (n=20) at main.cc:10
#20 0x00000001004010b8 in Fibonacchi (n=21) at main.cc:10
#21 0x00000001004010b8 in Fibonacchi (n=22) at main.cc:10
#22 0x00000001004010b8 in Fibonacchi (n=23) at main.cc:10
--Type <RET> for more, q to quit, c to continue without paging--q
Quit
(gdb) set pagination off
(gdb) backtrace
#0 Fibonacchi (n=0) at main.cc:5
#1 0x00000001004010c7 in Fibonacchi (n=2) at main.cc:10
#2 0x00000001004010b8 in Fibonacchi (n=3) at main.cc:10
#3 0x00000001004010b8 in Fibonacchi (n=4) at main.cc:10
#4 0x00000001004010b8 in Fibonacchi (n=5) at main.cc:10
#5 0x00000001004010b8 in Fibonacchi (n=6) at main.cc:10
#6 0x00000001004010b8 in Fibonacchi (n=7) at main.cc:10
#7 0x00000001004010b8 in Fibonacchi (n=8) at main.cc:10
#8 0x00000001004010b8 in Fibonacchi (n=9) at main.cc:10
#9 0x00000001004010b8 in Fibonacchi (n=10) at main.cc:10
#10 0x00000001004010b8 in Fibonacchi (n=11) at main.cc:10
#11 0x00000001004010b8 in Fibonacchi (n=12) at main.cc:10
#12 0x00000001004010b8 in Fibonacchi (n=13) at main.cc:10
#13 0x00000001004010b8 in Fibonacchi (n=14) at main.cc:10
#14 0x00000001004010b8 in Fibonacchi (n=15) at main.cc:10
#15 0x00000001004010b8 in Fibonacchi (n=16) at main.cc:10
#16 0x00000001004010b8 in Fibonacchi (n=17) at main.cc:10
#17 0x00000001004010b8 in Fibonacchi (n=18) at main.cc:10
#18 0x00000001004010b8 in Fibonacchi (n=19) at main.cc:10
#19 0x00000001004010b8 in Fibonacchi (n=20) at main.cc:10
#20 0x00000001004010b8 in Fibonacchi (n=21) at main.cc:10
#21 0x00000001004010b8 in Fibonacchi (n=22) at main.cc:10
#22 0x00000001004010b8 in Fibonacchi (n=23) at main.cc:10
#23 0x00000001004010b8 in Fibonacchi (n=24) at main.cc:10
#24 0x00000001004010b8 in Fibonacchi (n=25) at main.cc:10
#25 0x00000001004010e7 in main () at main.cc:14