set follow-fork-mode <mode>
modeはparent(デフォルト)またはchild。
childを指定すると、フォークした子プロセスをデバッグする。
show follow-fork-mode
で現在のモードを確認できる。
set follow-fork-mode <mode>
modeはparent(デフォルト)またはchild。
childを指定すると、フォークした子プロセスをデバッグする。
show follow-fork-mode
で現在のモードを確認できる。
Ubuntu(14.04 LTS)で、コアダンプが出力できない場合があるという現象が発生した。
できる場合もある。プログラムによる。
以下のように、ulimitは問題ない。
$ ulimit -c unlimited $ ulimit -a core file size (blocks, -c) unlimited data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 15739 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 15739 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
コアダンプの出力先を確認。
$ sudo sysctl -a | grep core_pattern kernel.core_pattern = |/usr/share/apport/apport %p %s %c %P
Ubuntu(14.04 LTS)では、デフォルトでcore_patternがapportを使用するように設定されていた。
コアダンプが出力されるケースでは、カレントディレクトリにcoreというファイルが出力される。
コアダンプが出力されないケースでは、apportでエラーが発生していた。
/var/log/apport.log
ERROR: apport (pid 3480) Tue May 12 18:48:31 2015: called for pid 3479, signal 6, core limit 18446744073709551615 ERROR: apport (pid 3480) Tue May 12 18:48:31 2015: ignoring implausibly big core limit, treating as unlimited ERROR: ERROR: apport (pid 3480) Tue May 12 18:48:31 2015: Unhandled exception: Traceback (most recent call last): File "/usr/share/apport/apport", line 357, in <module> (info['ExecutablePath'], info['ProcCmdline'])) File "/usr/share/apport/apport", line 99, in error_log apport.error('apport (pid %s) %s: %s', os.getpid(), time.asctime(), msg) File "/usr/lib/python3/dist-packages/apport/__init__.py", line 44, in error sys.stderr.write(msg % args) UnicodeEncodeError: 'ascii' codec can't encode character '\ufffd' in position 143: ordinal not in range(128) ERROR: apport (pid 3480) Tue May 12 18:48:31 2015: pid: 3480, uid: 0, gid: 0, euid: 0, egid: 0 ERROR: apport (pid 3480) Tue May 12 18:48:31 2015: environment: environ({})
apportでエラーになっているから、コアダンプが出力されないのだ。
PythonのUnicodeEncodeErrorが発生しているようだが、よく分からないので、core_patternにapportを使用しないよう設定することにした。
# echo 'core.%e.%p' > /proc/sys/kernel/core_pattern
$ ulimit -c unlimited $ cat segfault.c #include <stdio.h> int main(void) { char *s = "hello, world!"; *s = 'H'; return 0; } $ gcc -Wall -g -o segfault segfault.c $ ./segfault Segmentation fault (コアダンプ) $ ls core.segfault.3423 segfault segfault.c
echoで変更した設定は、システム再起動後には無効になってしまう。
変更を永続化するためには、/etc/sysctl.confに設定する。
情報源: E.4. sysctl コマンドの使用
/etc/sysctl.conf
kernel.core_pattern = core.%e.%p
しかし、なぜかシステムを再起動すると、apportを使用するように設定が戻ってしまっている。
システム起動時のapport起動で、設定を上書きしているらしい。
情報源: 12.04 - How to permanently edit the core_pattern file? - Ask Ubuntu
これを止めさせるには、apportを無効にして再起動する。
/etc/default/apport
# set this to 0 to disable apport, or to 1 to enable it # you can temporarily override this with # sudo service apport start force_start=1 #enabled=1 enabled=0
コマンドの終了コードが128を超える場合はシグナルで終了した場合。
$ man bash
The return value of a simple command is its exit status, or 128+n if the command is terminated by signal n.
$ some_command $ echo $? 139
例えば上記のように終了コードが139なら、139=128+11なので、シグナル11で終了したということになる。
man signalとかで見ると、シグナル11はSIGSEGVで、セグメンテーション違反だということが分かる。
GDBとLLDBのコマンド対照表。
# は、引数を文字列に変換する。
## は二つの識別子を連結させる。
C 言語 マクロ講座 # ## 編: uyota 匠の一手
配列はprintコマンド(p)で参照できるが、配列を引数で受け取った場合などポインタになっている場合は、@演算子を用いるとうまく表示できる。
@演算子は、左項をアドレスとみなし、左項の型のデータを右項の数だけ配列のように表示する。
(gdb) list 34 35 void func(int v[], int len) 36 { (gdb) p v[0] @ len $1 = {4470, 5197, 2482, 1016, 4154, 9986, 8313, 6873, 8517, 5857, 9019, 8002, 349, 9817, 365, 1018, 2269, 9759, 7092, 8674, 4902, 3890, 9746, 7668, 792, 3842, 4053, 6422, 630, 4880, 9996, 7164, 8392, 8469, 2959, 8380, 6533, 1795, 4296, 9964, 8259, 7474, 72, 2948, 3681, 501, 3994, 508, 9544, 941, 8054, 2186, 7418, 8684, 3224, 7322, 3822, 5022, 3085, 8341, 2296, 4073, 1034, 9839, 7067, 1197, 739, 7028, 2809, 6610, 8633, 483, 3017, 9634, 4758, 8101, 7604, 4018, 2174, 5014, 6600, 3754, 2854, 4798, 3921, 2124, 9889, 1147, 2409, 6105, 224, 6973, 5937, 2953, 8614, 9101, 3399, 8431, 2226, 3548} (gdb) p *v @ len $2 = {4470, 5197, 2482, 1016, 4154, 9986, 8313, 6873, 8517, 5857, 9019, 8002, 349, 9817, 365, 1018, 2269, 9759, 7092, 8674, 4902, 3890, 9746, 7668, 792, 3842, 4053, 6422, 630, 4880, 9996, 7164, 8392, 8469, 2959, 8380, 6533, 1795, 4296, 9964, 8259, 7474, 72, 2948, 3681, 501, 3994, 508, 9544, 941, 8054, 2186, 7418, 8684, 3224, 7322, 3822, 5022, 3085, 8341, 2296, 4073, 1034, 9839, 7067, 1197, 739, 7028, 2809, 6610, 8633, 483, 3017, 9634, 4758, 8101, 7604, 4018, 2174, 5014, 6600, 3754, 2854, 4798, 3921, 2124, 9889, 1147, 2409, 6105, 224, 6973, 5937, 2953, 8614, 9101, 3399, 8431, 2226, 3548}
Source: Arrays - Debugging with GDB
Cの型宣言は読みにくい。
「例解UNIXプログラミング教室」(冨永和人、権藤 克彦 ピアソンエデュケーション)の説明が分かりやすい。
- 最左の識別子(関数名や変数名など)に注目する。それ以外の識別子は引数の名前なので無視する。
- 下記の優先度に従い、その識別子から外側に向かいカッコをつける。左側の*よりも先に、右側の()や[]にカッコをつけるのがポイント。
- 日本語なら外側から、英語なら内側から読む。
優先度(上ほど強く結合)
記号 説明 () 宣言のグループ化 [], () 配列、関数引数 * ポインタ その他 intなど 例: signalの型
void (*signal (int sig, void (*handler)(int)))(int);
- 最左の識別子はsignal。(sigとhandlerは引数)。
- signalからカッコをつける。
- *より()の方が強いので、signal (int sig, void (*handler)(int)) をカッコで囲む。
- 一番左のvoidより一番右の (int) の方が強いので、一番左の void 以外をカッコで囲む。
- 結果はこうなる。
void ((*(signal (int sig, void (*handler)(int))))(int));- 外側からカッコを外しながら読む。
- void ⚫; ⚫はvoid
- void (⚫)(int); ⚫はvoidを返す関数(引数はint)
- void (* ⚫)(int); ⚫はvoidを返す関数(引数はint)へのポインタ
- void (*signal(⚫))(int); signalはvoidを返す関数(引数はint)へのポインタを返す関数(引数は⚫)
- void (*signal(int sig, void (*handler)(int)))(int); signalはvoidを返す関数(引数はint)へのポインタを返す関数(引数はintとvoidを返す関数(引数はint))
gdbのptypeを使うのが簡単。
例えば、以下のfoo.c。
#include <sys/types.h> struct st { int i; char c; }; typedef int Array[10]; typedef struct st St; int main(void) { size_t s1; ssize_t s2; pid_t pid; Array arr; St st1; return 0; }
$ gcc -Wall -g -o foo foo.c $ gdb foo (gdb) b main (gdb) run (gdb) ptype s1 type = long unsigned int (gdb) ptype size_t type = long unsigned int (gdb) ptype s2 type = long int (gdb) ptype ssize_t type = long int (gdb) ptype pid type = int (gdb) ptype pid_t type = int (gdb) ptype arr type = int [10] (gdb) ptype Array type = int [10] (gdb) ptype st1 type = struct st { int i; char c; } (gdb) ptype St type = struct st { int i; char c; }
のように、
ptype 式や型名
で実際の型が表示される。
配列の場合はサイズが表示されるし、構造体の場合はメンバの型が表示されるので便利。
以下のように、gccの-Eオプションでプリプロセッサの出力調べても分かりそうだが、面倒くさいし、追い切れないかもしれない。
$ gcc -E foo.c | grep ssize_t typedef long int __ssize_t; typedef __ssize_t ssize_t; (以下略)
このシステム(x86_64 GNU/Linux)では、ssize_tは
__ssize_t => long int
$ gcc -E foo.c | grep ssize_t typedef long __darwin_ssize_t; (中略) typedef __darwin_ssize_t ssize_t; (以下略)
このシステム(Mac OS X)では、ssize_tは
ssize_t => __darwin_ssize_t => long
であることが分かる。