gdb チートシート
[履歴] [最終更新] (2020/04/03 22:58:39)
最近の投稿
注目の記事

概要

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

操作方法

ステップ実行

cs 等のコマンドは、エンターを入力するだけで繰り返し実行できます。

現在位置の確認 (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       }
関連ページ
    概要 よく使う python ライブラリのサンプルコード集です。 JSON #!/usr/bin/python # -*- coding: utf-8 -*- import json arr = [1, 2, {'xxx': 3}] # オブジェクト ←→ JSON 文字列 jsonStr = json.dumps(arr) arr2 = json.loads(jsonStr) # オ
    コマンドのエイリアスを登録する (update-alternatives) mybin という名前のコマンドを登録 sudo update-alternatives --install /usr/local/bin/mybin mybin /usr/bin/echo 10 sudo update-alternatives --install /usr/local/bin/mybin mybin