如何在 Ubuntu 裡的 container 用 core dump 來 debug
最近在寫專題時遇到麻煩的 segmentation fault,簡單檢查過程式碼找不到問題,後來才想到可以用 core dump 來定位問題。
但是在程式需要的 container 環境內產生 core dump 時遇到了一些問題,在此做個記錄。
設定 core dump 檔案大小
先用 ulimit -a
查看當前 shell 的資源設定:
$ ulimit -a
real-time non-blocking time (microseconds, -R) unlimited
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 127281
max locked memory (kbytes, -l) 4082572
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) 127281
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
core file size
的值為 0 表示不會產生 core dump 檔案,因此要使用 ulimit -c [limit]
調整 core dump 檔案的大小上限。ulimit -c unlimited
可以把上限調成無限大,若擔心檔案太大可自行調整 limit 的數值。
ulimit -c unlimited
使用 ulimit
設定 core dump 大小只會在此次 shell session 生效,下次登入就會恢復。
若要自動設定,可以將 ulimit
指令寫到 ~/.bashrc
或直接修改 /etc/security/limits.conf
。
設定 core dump 檔名
先查看 /proc/sys/kernel/core_pattern
的內容:
$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E
Ubuntu 預設會使用 apport
這個程式來管理 crash 並存在它自己的目錄。我們可以改將 core dump 放在 /tmp
(此資料夾的檔案一段時間沒更改會被清理),並修改其名稱格式:
$ echo "core.%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern
core.%e.%p.%t
由於我在 container 內已經是 root user,省略 sudo
,執行後卻出現以下錯誤:
$ echo "core.%e.%p.%t" | tee /proc/sys/kernel/core_pattern
tee: /proc/sys/kernel/core_pattern: Read-only file system
core.%e.%p.%t
這是因為系統的核心檔案是以 read only 的形式 mount 到 container 裡面共用的,而 rootless container 沒有權限去更改它。因此需要先在 container 外面設定好。
分析 core dump 檔案
設定完成後,當程式發生 core dump 時就會在 /tmp
資料夾產生對應的檔案。
我們可以用 gdb
對這個檔案進行分析:
gdb [program] [core dump file]
$ ll /tmp/
total 124
drwxrwxrwt 1 root root 4096 May 31 02:50 ./
dr-xr-xr-x 1 root root 4096 May 31 02:50 ../
-rw------- 1 root root 253952 May 31 02:50 core.test.58.1717095059
$ gdb test /tmp/core.test.58.1717095059
...
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...
(No debugging symbols found in test)
[New LWP 58]
Core was generated by `./test'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000566136e40135 in func () at test.cpp:4
4 *a = 1;
(gdb)
除了可以看到發生 segmentation fault 的那行以外,也能輸入 bt
(backtrace 的縮寫) 查看完整的函式呼叫的 stack:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000566136e40135 in func () at test.cpp:4
4 *a = 1;
(gdb) bt
#0 0x0000566136e40135 in func () at test.cpp:4
#1 0x0000566136e4014b in main () at test.cpp:8
(gdb)
這樣就能比較準確的知道是哪個地方導致 segmantation fault。
若要獲得完整的除錯資訊(行號及具體程式碼等),需要在編譯的指令加上 -g
這個 flag。
參考連結
- 讓程序崩潰時產生coredump | Jason note
- 在 Linux 上允許產生 core dump | by fcamel | Medium
- debugging - Where do I find core dump files, and how do I view and analyze the backtrace (stack trace) in one? - Ask Ubuntu
- bash - How to generate a core dump in Linux on a segmentation fault? - Stack Overflow
- 如何使用 gdb 查看 core dump - XpandNotes