问题描述:在linux环境下,有时候进程会异常退出,这个时候可以用strace 跟踪进程的运行情况。如果是进程内部错误,则strace日志可以看到进程的异常错误点。但如果是被其它人或进程杀掉(kill), 则strace 日志里只能看到被杀信息:“+++ killed by SIGKILL +++”。 此时要找到“杀手”进程,就需要跟踪信号量,找出是谁发送了信号量给目标进程。
/*jprobe_signal.c, 基于jprobe,注册钩子函数,在信号发送的地方,根据需要,打印发送信号的进程,发送的信号量,信号接收的目标进程。
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/sched.h>
static int g_pid=0; //-1=all process
static int g_sig=9; //SIGKILL, 0=all signal
module_param_named(pid,g_pid,int,S_IRUGO|S_IWUSR);
module_param_named(signal,g_sig,int,S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(pid, "The specified process PID,-1 Reprensent all processes. 0 Represent no processes be traced. default is 0");
MODULE_PARM_DESC(signal, "The signal that needs to be tracked,0 represent all signal. default is 9");
static int jsend_signal(int sig,struct siginfo *info,struct task_struct *t,int group)
{
struct task_struct *parent=NULL;
int prev_pid=0;
if(((g_pid < 0) ||(t->pid==g_pid))&&((g_sig==0)||(sig==g_sig))){
printk(KERN_INFO "jprobe_signal:PID %d name:%s send SIG %d to PID=%d,name=%s\n",current->pid,current->comm,sig,t->pid,t->comm);
parent=current->parent;
prev_pid=current->pid;
while(parent&&(parent->pid >= 1)){
printk(KERN_INFO"jprobe_signal:PID %d create by Parent Pid:%d,name:%s\n",prev_pid,parent->pid,parent->comm);
prev_pid=parent->pid;
parent=parent->parent;
}
}
/* Always end with a call to jprobe_return(). */
jprobe_return();
return 0;
}
static struct jprobe my_jprobe = {
.entry = jsend_signal,
.kp = {
.symbol_name = "send_signal",
},
};
static int __init jprobe_init(void)
{
int ret;
ret = register_jprobe(&my_jprobe);
if (ret < 0) {
printk(KERN_INFO "register_jprobe failed, returned %d\n", ret);
return -1;
}
printk(KERN_INFO "Planted jprobe at %p, handler addr %p\n",
my_jprobe.kp.addr, my_jprobe.entry);
return 0;
}
static void __exit jprobe_exit(void)
{
unregister_jprobe(&my_jprobe);
printk(KERN_INFO "jprobe at %p unregistered\n", my_jprobe.kp.addr);
}
module_init(jprobe_init)
module_exit(jprobe_exit)
MODULE_LICENSE("Dual BSD/GPL");
Makefile 文件:
ifneq ($(KERNELRELEASE),)
obj-m := jprobe_signal.o
else
KERNELDIR ?=/usr/src/$(shell uname -r)/
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY: clean
clean:
-rm -rf *.mod.c *.o *.order *.sym .j* .tmp*