程序终止的原因systemtap

无非以下几点:

1、正常退出

2、程序自身异常

3、系统终止程序(如内存不足等)

4、信号

对于23,可以用dmesg命令来查找日志信息;如果程序产生了core dump文件,也可以用gdb调试。

对于4,程序可能被某些信号终止的,比如SIGTERM, SIGINT, SIGPIPE,甚至于SIGKILL (kill -9)

往往SIGKILL是不能捕获的,所以在程序内部时没法判断的。

借用systemtap,可用yum安装: yum install systemtap systemtap-runtime

运行此工具需要管理员权限!!!

程序执行sudo stap stpfile [args] 或 sudo stap -x pid stpfile [args]

后者用-x指定target pid,需要在stpfile调用target()获得。不指定-x不要用target()!

也可以直接sudo stap -e '....'

关键在于stpfile的编写, 里面有个probe的概念: 不同的探针获取到不同的信息!不同的probe对应到不同的事件;当事件发生时,probe的hander会被调用!

每个probe类似于一个C的回调函数,事实上,systemtap的确会把脚本用C编译器编译。

probe        event[,event2...] { statements

function func_name(arguments) { statements }

probe event1 { func_name(arguments) }

probe event2 { func_name(arguments) }

 

常用事件名:

begin  // stap脚本执行时

end    // stap脚本终止时

timer.s(秒数)  //定时器

timer.ms(毫秒)

timer.us(微妙)

timer.ns(纳秒)

syscall.system_call  // 如syscall.*, syscall.open, syscall.open.return

 

常用函数:

exit() // 无参数。stap在Ctrl+C或执行到exit()函数时终止

printf(fmt,....) // 类似C的printf

isinstr(str, substr) // 返回1如果str包含有substr;否则0

execname() // target程序名

pid() // target程序的pid

tid() // target程序所在线程的tid

uid() // target进程的uid。可比较于/etc/passwd!

pp()  // 描述当前probe的字符串

target() // 返回一PID。 仅当执行stap时指定了-x pid或-c command时

name  // 注意没有(),不是函数,是个变量。仅用于syscall probe

 

【【函数 - probe - 变量列表】】

和C同或不同的是,stap脚本里

  • 不需要分号等作为分隔符。。。
  • 声明变量不需类型或var/auto这样的关键字,直接用名字即可。
  • probe之外声明的变量前需加global关键字。
  • 有++ --运算
  • 字符串可以用==比较,不能用广义* ?
  • if / while/ for和C基本相同~~~

stap脚本可传入参数,基于1。整数用$开头,字符串用@开头。如果没有或不对,将报错!

probe syscall.open {
if (@1 == execname)
exit()
}

 

进程信号发送监视:

sigmon.stp 修改于这里

probe begin

{

printf("%-8s %-16s %-8s %-16s %6s %-16s\n",

"SENDPID", "SENDNAME", "RECEPID", "RECENAME", "SIGNUM", "SIGNAME")

}

 

probe signal.send

{

if (uid() == 3100 && (isinstr(pid_name,"ld") || isinstr(execname(),"ld")))

printf("%-8d %-16s %-8d %-16s %-6d %-16s\n",

pid(), execname(), sig_pid, pid_name, sig, sig_name)

}

注意

  • 类似kill(pid, signum)(调用此函数)发送信号的进程是SENDer, 它的pid和程序名分别是pid()execname;而要接收这个信号的则是sig_pidpid_name
  • 通过uid()只显示属于某个用户的发送进程(类似top -u user)。并通过isinstr只显示发送或接收进程名包含ld字符的进程。
  • SIG_IGN忽略掉的信号,依然会显示出来!这很正常,毕竟这是send阶段。。。