用 SystemTap 找出送 SIGKILL 的 process
問題
Linux 上的 process 執行一陣子後掛了。一般情況可以用 gdb attach process,這樣在 process 掛的時候,gdb 會顯示是怎麼掛的。比方說 segfault,或是收到別人送的 signal。若是 segfault 就看 backtrace 找原因; 收到 signal 就用 sigaction()
註冊 handler,從 siginfo_t.si_pid
找出是誰送 signal 來的。然而,SIGKILL 和 SIGSTOP 是無法攔截的,若是被 SIGKILL 殺掉,無法用 gdb 找出是那個 process 發出 SIGKILL。
SystemTap
SystemTap 提供觀察 kernel 內部狀態,它的運作原理是將 SystemTap script 編成 C 程式、編成 kernel module、載入 kernel,然後在觀察結束後再移除剛載入的 kernel module。所有 process 送出 SIGKILL 都得經過 kernel,所以我們可以用 SystemTap 注入觀察程式,找出誰呼叫 SIGKILL。
在 Ubuntu 16.04 的安裝方法很簡單,照官方文件作即可:
$ sudo apt-get install -y systemtap gcc$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C8CAB6595FDFF622$ codename=$(lsb_release -c | awk '{print $2}')
sudo tee /etc/apt/sources.list.d/ddebs.list << EOF
deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse
#deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse
EOF
sudo apt-get update
sudo apt-get install linux-image-$(uname -r)-dbgsym
後面那段 codename …
是產生 /etc/apt/sources.list.d/ddebs.list,裡面定義kernel debug image 套件的來源。注意我這邊註解掉 ${codename}-security 那行,有這行的時候,apt-get update 會回報錯誤:
W: The repository 'http://ddebs.ubuntu.com xenial-security Release' does not have a Release file.
N: Data from such a repository can't be authenticated and is therefore potentially dangerous to use.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: Failed to fetch http://ddebs.ubuntu.com/dists/xenial-security/main/binary-amd64/Packages 404 Not Found
E: Some index files failed to download. They have been ignored, or old ones used instead.
移掉後才能正常執行 apt-get update,然後就可以安裝 kernel debug image (我對到的版本是 linux-image-4.4.0–98-generic-dbgsym )。
測試 SystemTap 是否正常運作:
$ cat hello.tap
probe timer.s(1)
{
printf("hello world\n")
}$ sudo stap hello.tap
[sudo] password for fcamel:
hello world
hello world
hello world
^C
找出送出 SIGKILL 的 process
我們知道 Linux 程式會用 kill()
送 signal,所以偵測呼叫 kill()
的地方即可:
$ cat who_call_kill.tap
probe syscall.kill
{
printf("%s(%d) call kill(%s)\n", execname(), pid(), argstr)
}
$ sudo stap who_call_kill.tap
然後在第二個 bash 執行 cat,在第三個 bash 用 ps 找出 cat 的 pid 並用 kill -9 殺掉 cat,再回來看 stap 執行的結果:
$ sudo stap who_call_kill.tap
screen(25606) call kill(25607, SIG_0)
screen(3385) call kill(2888, SIG_0)
screen(25606) call kill(25607, SIG_0)
bash(8352) call kill(30393, SIGKILL)
screen(3385) call kill(2888, SIG_0)
^Cstap(29954) call kill(30356, SIGTERM)
中間的 bash(8352) call kill(30393, SIGKILL)
就是我們要的結果。相關參數可以參考官方 reference Chater35. syscalls。
更可靠的作法是用 SystemTap 的 signal API,畢竟送出 signal 的方法不只有 kill()
而已。改用 signal API 的作法如下:
$ cat who_send_signal.tap
probe signal.send{
printf("%s by %s: %s(%d) -> %s(%d)\n", sig_name, name, execname(), pid(), pid_name, sig_pid);
}$ sudo stap who_send_signal.tap
SIGCHLD by signal_generate: lpstat(31834) -> sh(31833)
...
SIGKILL by signal_generate: bash(8352) -> cat(31848)
...
^CSIGINT by signal_generate: kworker/u64:1(28733) -> stapio(31829)
SIGINT by signal_generate: kworker/u64:1(28733) -> stap(31825)
SIGINT by signal_generate: kworker/u64:1(28733) -> sudo(31824)
SIGTERM by signal_generate: stap(31825) -> stapio(31829)
相關參數可參考 prob::signal.send。
備註: 自行安裝 SystemTap
如果遇到問題懷疑是 Ubuntu 內建版本有問題的話,可以自行編 SystemTap。這裡有人提到這問題,並提供安裝步驟。備忘一下:
## Install build-required packages
$ apt-get update && \
apt-get install -y build-essential gettext elfutils libdw-dev python wget tar && \
apt-get clean;
## Build from source
$ wget https://sourceware.org/systemtap/ftp/releases/systemtap-3.1.tar.gz
$ tar xzvf systemtap-3.1.tar.gz
## Instruction: https://sourceware.org/git/?p=systemtap.git;a=blob_plain;f=README;hb=HEAD
$ cd systemtap-3.1/ && \
./configure && \
make all## Install by checkinstall
$ sudo checkinstall
最後一步我改用 checkinstall,這樣會包成 deb 再裝進去,方便日後移除。
參考資料
- SystemTap Chapter 3. Understanding How SystemTap Works: 加減看看,了解基本語法。不過還是找別人的程式碼來改比較快,有疑問再回來翻。
- SystemTap Tapset Reference Manual
- Red Hat Enterprise Linux 5 SystemTap Language Reference: 全部語法集中在一頁,方便搜尋。
- Linux 自检和 SystemTap: 快速掃過去可以掌握到許多有用資訊。
- IBM 寫的 SystemTap: Instrumenting the Linux Kernel for Analyzing Performance and Functional Problems: 留著有閒再學些技巧。
- 特別感謝 ytshen 先試了一遍,確認在 Ubuntu 16.04 上設置相當輕鬆愉快,幫我省了些時間。
相關文章
- 用 SystemTap 找出送 SIGKILL 的 process: 含安裝說明
- 用 SystemTap 找出 TCP 如何決定 MSS 的值
- 用 SystemTap 追踪 user space 程式執行的流程