2007年5月6日 星期日

如何在child process 中利用gdb debug

問題描述:
跑一個process, 中間 fork ㄧ個 child process, 之後parent process 繼續執行, 發現child process 好像卡住, 不會繼續動作

Step1.
ulimit -c unlimited
設定 core dump file size 為unlimited, 預設值為0 size

ulimit 程式的主要目的是用來設定程式執行的許多參數, 包括 core file size, data segment size 還有許多其他的參數, 請利用 ulimit -a 來秀所有support 的參數
# ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
pending signals (-i) 1024
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024t
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 3072
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited


Step2.
執行主程式, 可以看到parent process fork 出child process 的process id 為 31887 (利用 getpid()得知), 另外在 ps 也可以看到

# ps aux | grep prog
root 31886 0.1 0.4 2932 904 pts/1 S+ 00:42 0:00 ./prog
root 31887 0.0 0.4 2912 872 pts/1 S+ 00:42 0:00 ./prog
root 31888 0.0 0.4 2928 928 pts/1 S+ 00:42 0:00 ./prog


Step3.
kill -11 31887
送出 SIGSEGV signal 給 child process, child process 收到 segmentation fault 的signal, 就會 core dump 並且在同一個目錄下, 產生core.XXX (XXX為process id) 的檔案, 以這裡的例子而言就是
core.31887

/usr/include/asm/signal.h 下的定義
#define SIGSEGV 11


Step4.
利用 gdb 來debug
# gdb prog core.31887

[略]
Core was generated by `./prog'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /usr/lib/libstdc++.so.6...done.
Loaded symbols for /usr/lib/libstdc++.so.6
Reading symbols from /lib/tls/libm.so.6...done.
Loaded symbols for /lib/tls/libm.so.6
Reading symbols from /lib/libgcc_s.so.1...done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /lib/tls/libc.so.6...done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0 0x0092e7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
(gdb) bt << 下bt (backtrace) 去 trace 所有的 function
#0 0x0092e7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
#1 0x00a0cfc1 in recvfrom () from /lib/tls/libc.so.6
#2 0x0804f0b7 in getMessage (fd=2048, buf=0xfef6d4a0 "\001\001", len=0xfef6cfc4, srcIp=0x800, srcPort=0x800,
verbose=false) at udp.cxx:127
#3 0x0804daf6 in MyTest (myFd=3, dest=@0x800, testNum=1, verbose=false, reply=0xfef6df18) at stun.cxx:2188
#4 0x0804a460 in get_mess (req=0xfef6df50, reqtype=QT_Reflexive, reply=0x0, type=0xfffffe00)
at myclient.cxx:632
#5 0x0804a8c6 in refresh (reqfd=3, svr=0xfef6ea60) at myclient.cxx:572
#6 0x08049299 in main (argc=1, argv=0xfef6eb24) at sip8test.c:71

因為 frame 0, 1 都是system call
frame 2, 3, 4, 5, 6 都是我們程式自己寫的 function
所以可以懷疑程式是卡在 fram 2 getMessage function 當中, 也就是 udp.cxx 的第127 行

Step5.
frame 就是有許多不同層 stack 的意思, 在gdb 中可以利用frame 去jump 到某ㄧ個特定的stack (frame), 來print variable value

(gdb) frame 2 << 我們這裡執行 frame 2 來看stack2 的variable value, 可以用 p XXX 來看
#2 0x0804f0b7 in getMessage (fd=2048, buf=0xfef6d4a0 "\001\001", len=0xfef6cfc4, srcIp=0x800, srcPort=0x800,
verbose=false) at udp.cxx:127
127 *len = recvfrom(fd,


Step6.
這時可以list 來看 code 的內容, 找出錯誤的原因

(gdb) list
122 assert( originalSize > 0 );
123
124 struct sockaddr_in from;
125 int fromLen = sizeof(from);
126
127 *len = recvfrom(fd,
128 buf,
129 originalSize,
130 0,
131 (struct sockaddr *)&from,


Embedded system debug
# toolChain_gdb daemon coreFile
For example
# /opt/v6_be_uclibc/bin/arm_v6_be_uclibc-gdb daemon coreFile

沒有留言: