目次
Microservicesアーキテクチャを実践中!
GNU Debugger (GDB) の簡単な使い方を記載します。
起動方法
main.cpp
#include <iostream>
#include <unistd.h>
using namespace std;
int main() {
int i = 0;
while(true) {
sleep(1);
cout << ++i << endl;
}
return 0;
}
実行プログラムを指定
-g -O0
オプションを指定してデバッグモードでコンパイルします。
g++ -Wall -g -O0 main.cpp
gdb ./a.out
(gdb) run
(gdb) run 引数
プロセスID を指定
gdb ./a.out -p 1234
コアファイルを指定
gcore 1528
gdb ./a.out -c core.1528
実行プログラムの確認
file core.1528
core.1528: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './a.out', real uid: 1000, effective uid: 1000, real gid: 1000, effective gid: 1000, execfn: './a.out', platform: 'x86_64'
共有ライブラリの確認 (lddでも確認できる情報)
(gdb) info share
別環境でコアファイルを解析する場合は、必要に応じて共有ライブラリのパスを追加する必要があります。
(gdb) set solib-absolute-prefix /tmp/lib
(gdb) set solib-search-path /tmp/lib
(gdb) file ./myhello
(gdb) core-file ./core.1234
別環境でコアファイルを解析する場合は、ソースコードのパスを追加すると便利です。
(gdb) directory /tmp/src
操作方法
ステップ実行
c
や s
等のコマンドは、エンターを入力するだけで繰り返し実行できます。
現在位置の確認 (list)
bt
l 123
一行進める (next)
n
ステップを進める (step; 関数の中にも入っていきます)
s
変数の値を確認、設定 (print)
p myvar
p myvar = myvar + 1
次のブレークポイントまで進める (continue)
c
バックトレースを表示
bt
関数内で実行すると、関数を抜けるまで進める。
(gdb) finish
for/while で実行すると、for/while を抜けるまで進める。
(gdb) until
シェルコマンドを実行
(gdb) shell pwd
(gdb) shell g++ -g -O0 main.cpp
(gdb) shell
$ pwd
作業ログの出力
./gdb.txt
にログ出力されます。
(gdb) set loggin on
(gdb) set loggin overwrite on
ブレークポイント
(gdb) b ファイル名:行数
(gdb) break ファイル名:行数 if i == j
(gdb) break main
(gdb) info breakpoints
(gdb) info breakpoints ブレークポイント番号
(gdb) delete
(gdb) delete ブレークポイント番号
(gdb) disable ブレークポイント番号
(gdb) enable ブレークポイント番号
変数の値の監視
値が変更される度にデバッガが停止します。
(gdb) watch i
読み込み時の監視
(gdb) rwatch i
書き込みと読み込みの監視
(gdb) awatch i
関数引数、ローカル変数、例外情報の表示
(gdb) info args
(gdb) info locals
(gdb) info catch
スタックフレームの移動
up
down
frame フレーム番号
(f フレーム番号)
シグナル処理情報の確認
info signals
info signals シグナル名
シグナルの送信
signal シグナル名
コアファイルの生成
(gdb) generate-core-file
コアファイルの最大サイズの確認および最大サイズの解除
ulimit -c
sudo su -l
ulimit -c unlimited
スレッド一覧の表示
(gdb) info threads
実行ファイルのないプロセスへのアタッチおよび制御
gdb -p 1234
(gdb) ...何らかの制御
(gdb) detach
(gdb) quit
型を調査
(gdb) whatis 変数名
CPython のコアダンプを解析したい場合
gdb python -c core.xxxx
参考: Python の実装を確認
$ python
>>> import platform
>>> print platform.python_implementation()
CPython
CPython の NSMALLPOSINTS が 257 となっている場合、0-256 の整数は同じメモリのデータが使い回される。
In : id(256)
Out: 94652018165808
In : id(256)
Out: 94652018165808 ←同じ
In : id(257)
Out: 94652020901008
In : id(257)
Out: 94652020900864 ←異なる
インスタンスのメソッドを実行
(gdb) p obj
$9 = {px = 0x557bb8d30c60, pn = {pi_ = 0x557bb8cf28d0}}
(gdb) p (obj.px)->MyIsOk()
$8 = false
全スレッドに対して bt
を適用
thread apply all bt
例外が投げられるまで実行
catch throw
run
例外とは関係ありませんが、Segmentation fault が発生した場合、自動で gdb に処理が戻ります。
Python を gdb でデバッグ
CPython 実装の Python は gdb でデバッグできます。必要なパッケージをインストールします。
sudo apt install python-dbg
threads.py
from threading import Thread
from time import sleep
threads = []
def mysleep(x):
print x
sleep(999)
def target():
mysleep('hi')
print 'done'
for i in range(2):
thread = Thread(target=target)
threads.append(thread)
thread.start()
mysleep('hi main')
for thread in threads:
thread.join()
ソースコードの存在するディレクトリでアタッチ
gdb -p `pgrep -f threads.py`
スレッド一覧の確認
(gdb) thread apply all py-list
Thread 3 (Thread 0x7f4a9f5f8700 (LWP 21559)):
3
4 threads = []
5
6 def mysleep(x):
7 print x
>8 sleep(999)
9
10 def target():
11 mysleep('hi')
12 print 'done'
13
Thread 2 (Thread 0x7f4a9fdf9700 (LWP 21558)):
3
4 threads = []
5
6 def mysleep(x):
7 print x
>8 sleep(999)
9
10 def target():
11 mysleep('hi')
12 print 'done'
13
Thread 1 (Thread 0x7f4aa0290740 (LWP 21557)):
3
4 threads = []
5
6 def mysleep(x):
7 print x
>8 sleep(999)
9
10 def target():
11 mysleep('hi')
12 print 'done'
13
(gdb) thread apply all py-locals
Thread 3 (Thread 0x7fd4ccbb4700 (LWP 21985)):
x = 'hi'
Thread 2 (Thread 0x7fd4cd3b5700 (LWP 21984)):
x = 'hi'
Thread 1 (Thread 0x7fd4cd84c740 (LWP 21983)):
x = 'hi main'
スレッドを選択する場合
info threads
thread 2
バックトレースの確認およびフレームの移動
py-bt
py-up
py-down
変数の値の確認
py-local
py-print x
デバッグシンボルを外部ファイルに分ける
main.cpp
#include <iostream>
int main() {
std::cout << "hi" << std::endl;
return 0;
}
デバッグシンボルを含めるようにコンパイル
g++ -g -O0 main.cpp
du -h a.out
40K a.out
デバッグシンボルを外部ファイルに切り出す
objcopy --only-keep-debug a.out a.debug
objcopy --remove-section .gnu_debuglink a.out
objcopy --add-gnu-debuglink a.debug a.out
objcopy --strip-all --discard-all --preserve-dates a.out
du -hs *
28K a.debug
16K a.out
4.0K main.cpp
a.out
と同じディレクトリにデバッグシンボル a.debug
が存在すれば gdb が利用できます。更にソースコード main.cpp
が存在すればファイル内容や行番号の確認も行えます。
$ ls
a.debug a.out main.cpp
$ gdb a.out
(gdb) b main.cpp:4
Breakpoint 1 at 0x1169: file main.cpp, line 4.
(gdb) run
Starting program: /home/path/to/a.out
Breakpoint 1, main () at main.cpp:4
4 std::cout << "hi" << std::endl;
(gdb) l
1 #include <iostream>
2
3 int main() {
4 std::cout << "hi" << std::endl;
5 return 0;
6 }
記事の執筆者にステッカーを贈る
有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。
さらに詳しく →Feedbacks
ログインするとコメントを投稿できます。
関連記事
- cmake で ccache を有効化するための設定YOCTO Linux で開発している場合など、ビルド速度が開発効率にそのまま影響する際は ccache (compiler cache) で C/C++ ビルドを高速化することを考えます。cmakeと併用する場合の設定およびコマンド例を記載します。 インストール sudo apt install ccache 以下のバイナリファイルに加えて $ w
- Python から C ライブラリを利用 (ctypes)FFI (Foreign Function Interface) の一つである ctypes を利用すると、C 言語のライブラリを Python から利用できます。サンプルコードを記載します。 適宜参照するための公式ドキュメント libm の sqrt を利用する例 main.py ``
- 低レイヤーネットワークプログラミングに関する雑多な知識TCP/IP モデルのうちトランスポート層ではなく、インターネット層およびネットワークインターフェイス層のパケット (正確には PDU) を扱う低レイヤープログラミングの雑多なテクニックをまとめます。『ルーター自作でわかるパケットの流れ』などを参考にしています。バックアップ目的で書籍のサンプルコードをホスティングしました。 検証環境
- ファイルディスクリプタ関連のシステムコールのサンプルコード (C 言語)ファイル記述子 (File Descriptor) に関連するシステムコールを利用した C 言語のサンプルコードを記載します。 ファイルの読み書き open/close main.c #include <unistd.h> #include <fcntl.h> #include <stdio.h> int main() { int fd_r, fd_w;...
- C言語の資産を利用 (C++をもう一度)サンプルコード メルセンヌ・ツイスタなど、C言語で記述されたライブラリをC++から利用するためには extern "C" を利用します。その際、組み込みマクロ __cplusplus を利用するとC言語からもC++からも利用できるヘッダファイルを作成できます。 sub.h #ifndef SUB_H_ #define SUB_H_ #ifdef __cplu