星期一, 1月 31, 2005

核心傾印, core dump

本文重點是第三節 III. Generating core without fatel error. 前兩節為 core dump 之背景介紹, 熟悉這套機制的人大可略去不看, 不影響對第三節的理解.

I. What's core dump?
core dump 是 Unix 上程式執行發生錯誤時, 將記憶體裡的內容做 snap shot, 存到檔案裡. 以方便 debug. 尤其是如程式區段錯誤 (Segmentation fault) 之類的錯因為經常難以重現, 在缺少 core file 的情況下很難解決. 程式設計師對於 core file 只能說是又愛又恨. 因為出現了代表有錯, 少了它又難以除蟲.

II. How to use it?
許 多系統上平常就算程式發生錯誤同樣不會產生 core file. 這是因為不是人人都用得到, 而且 core file 的大小通常不小, 普通使用者用不到沒注意到相當佔硬碟空間. 要開啟 core dump 要使用 limit (tcsh) 或 ulimit (bash, ksh).
tcsh$ limit
cputime unlimited
filesize unlimited
datasize unlimited
stacksize 8192 kbytes
coredumpsize 0 kbytes
memoryuse unlimited
vmemoryuse unlimited
descriptors 1024
memorylocked unlimited
maxproc unlimited
tcsh$ limit coredumpsize 8192

bash&ksh$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 8189
virtual memory (kbytes, -v) unlimited
bash&ksh$ ulimit -c 8192
這樣會將 core file 的大小限制在 8M 以下. 這樣執行有問題的程式時:
$ cat t.c
#include

int main(){
int* p = NULL;
scanf(" %d", p);
return 0;
}
$ gcc -g t.c
$ ./a.out
1
Segmentation fault (core dumped)
$ ls
t.c a.out core
$ gdb -q a.out core
...
#0 0xb7eff18e in _IO_vfscanf_internal () from /lib/tls/libc.so.6
(gdb) where
#0 0xb7eff18e in _IO_vfscanf_internal () from /lib/tls/libc.so.6
#1 0xb7f09458 in scanf () from /lib/tls/libc.so.6
#2 0x080483ae in main () at t.c:5
就很容易確定問題出在哪裡了.

III. Generating core without fatel error.
這 次 blog 的重點其實在這一節. 不知道為了什麼原因, in2 想讓一支程式產生 core file 但是正常運行. 如果不是這樣的話, 把 limit 打開, 然後 kill -SIGABRT 就足以產生 core file 了. 事實上 FreeBSD 上很容易做到, 只要用 gcore(1) 就可以了:
$ cat t.cpp
#include
#include

int main(){
int a;
std::cin >> a;
sleep(10);
std::cout <<>
return 0;
}
$ g++ -g t.cpp
$ ./a.out
1
^Z
[1]+ Stopped ./a.out
$ ps
PID TT STAT TIME COMMAND
59960 p1 Ss 0:00.05 -bash (bash)
59996 p1 T 0:00.00 ./a.out
59997 p1 R+ 0:00.00 ps
$ gcore 59996
$ fg
./a.out
1
$ gdb a.out core.59996
...
#0 0x481361b4 in nanosleep () from /usr/lib/libc.so.4
(gdb) where
#0 0x481361b4 in nanosleep () from /usr/lib/libc.so.4
#1 0x48101a26 in sleep () from /usr/lib/libc.so.4
#2 0x80486d8 in main () at t.cpp:7
(gdb) up
#1 0x48101a26 in sleep () from /usr/lib/libc.so.4
(gdb) up
#2 0x80486d8 in main () at t.cpp:7
7 sleep(10);
(gdb) list
2 #include
3
4 int main(){
5 int a;
6 std::cin >> a;
7 sleep(10);
8 std::cout <<>
9 return 0;
10 }
(gdb) output a
1(gdb) q
可 以看到, 用 gcore 就可以產生 core file 同時讓原程式正常執行. 而事實上他要的是 Linux 上的 solution. 在沒有直接一支 gcore 程式的情況下, google 了一陣發現 Linux 幾個 distribution 裡的 gdb 原始碼都有出現 gcore 的內容, 可是都沒有編譯出獨立的程式. 於是估且一試:
(gdb) help gcore
Save a core file with the current state of the debugged process.
Argument is optional filename. Default filename is 'core.'.
(gdb)
全部用法:
$ cat t.cpp
#include

int main(){
int a;
std::cin >> a;
std::cout << a << std::endl;
return 0;
}
$ g++ -g t.cpp
$ gdb -q a.out
Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) b 6
Breakpoint 1 at 0x8048777: file t.cpp, line 6.
(gdb) r
Starting program: /tmp/a.out
23

Breakpoint 1, main () at t.cpp:6
6 std::cout << a << std::endl;
(gdb) gcore
Saved corefile core.20251
(gdb) cont
Continuing.
23

Program exited normally.
(gdb) q
$ gdb -q a.out core.20251
Using host libthread_db library "/lib/tls/libthread_db.so.1".
Failed to read a valid object file image from memory.
Core was generated by `/tmp/a.out'.
Program terminated with signal 5, Trace/breakpoint trap.
...
#0 main () at t.cpp:6
6 std::cout << a << std::endl;
(gdb) output a
23(gdb) q

0 Comments:

張貼留言

<< Home