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 | #include <iostream> #include "sum.h" int main() { std::cout << Sum(1, 2) << std::endl; return 0; } |
1 2 3 4 5 6 | #ifndef SUM_H_ #define SUM_H_ int Sum(int a, int b); #endif // SUM_H_ |
1 2 3 4 5 | #include "sum.h" int Sum(int a, int b) { return a + b; } |
追加¶
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 | #include <iostream> #include "swap.h" // 最大公約数 int GreatestCommonDivisor(int a, int b) { while (a != 0) { b = b % a; Swap(&a, &b); } return b; } // 最小公倍数 int LeastCommonMultiple(int a, int b) { int gcd = GreatestCommonDivisor(a, b); return a * b / gcd; } int main() { int a = 12; int b = 18; std::cout << a << " と " << b << " の最小公倍数は " << LeastCommonMultiple(a, b) << " です" << std::endl; return 0; } |
1 2 3 4 5 6 7 | #ifndef SWAP_H_ #define SWAP_H_ // 2つの変数の値を入れ替える void Swap(int* a, int* b); #endif // SWAP_H_ |
1 2 3 4 5 6 7 | #include "swap.h" void Swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } |
変数の値を確認¶
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 | #include <iostream> #include "circle.h" double SquareOf(double v) { return v * v; } double SquareOfDistance(const Point& p, const Point& q) { return SquareOf(q.X() - p.X()) + SquareOf(q.Y() - p.Y()); } bool Intersects(const Circle& c1, const Circle& c2) { auto c = SquareOfDistance(c1.Center(), c2.Center()); auto r = SquareOf(c1.Radius() + c2.Radius()); return c < r; } int main() { Circle c1(Point(1, 2), 3); Circle c2(Point(5, 0), 2); if (Intersects(c1, c2)) { std::cout << "2つの円は交差します" << std::endl; } else { std::cout << "2つの円は交差しません" << std::endl; } return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #ifndef CIRCLE_H_ #define CIRCLE_H_ #include "point.h" class Circle { public: Circle(const Point& center, double radius) : center_(center), radius_(radius) {} Point Center() const { return center_; } double Radius() const { return radius_; } private: Point center_; double radius_; }; #endif // CIRCLE_H_ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #ifndef POINT_H_ #define POINT_H_ class Point { public: Point(double x, double y) : x_(x), y_(y) {} double X() const { return x_; } double Y() const { return y_; } private: double x_; double y_; }; #endif // POINT_H_ |
ステップオーバー¶
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 | #include <iostream> int GreatestCommonDivisor(int a, int b) { if (a == 0) { return b; } return GreatestCommonDivisor(b % a, a); } int main() { int a = 12; int b = 18; std::cout << a << " と " << b << " の最大公約数は " << GreatestCommonDivisor(a, b) << " です" << std::endl; return 0; } |
表示¶
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 | struct Point { double x; double y; Point(double x, double y) : x(x), y(y) {} }; struct Triangle { Point a; Point b; Point c; Triangle(const Point& a, const Point& b, const Point& c) : a(a), b(b), c(c) {} }; int main() { Triangle t(Point(1, 1), Point(2, 0), Point(3, 2)); return 0; } |
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 | #include <iostream> int Fibonacchi(int n) { if (n == 0) { return 0; } if (n == 1) { return 1; } return Fibonacchi(n - 1) + Fibonacchi(n - 2); } int main() { std::cout << Fibonacchi(100) << std::endl; } |
スタックフレームの一覧が画面内に収まらない場合に ページ送りの有無で次のように出力が変化します。
(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