// Signal tapset
// Copyright (C) 2006 IBM Corp.
// Copyright (C) 2006 Intel Corporation.
// Copyright (C) 2008 Red Hat, Inc.
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
// Public License (GPL); either version 2, or (at your option) any
// later version.
//
// Note : Since there are so many signals sent to processes at any give
// point, it's better to filter the information according to the
// requirements. For example, filter only for a particular signal
// (if sig==2) or filter only for a particular process
// (if pid_name==stap).
//
/**
* probe signal.send- Fires when a system call or kernel function sends a signal to a process.
* Arguments:
* @sig: The number of the signal
* @sig_name: A string representation of the signal
* @sig_pid: The PID of the process receiving the signal
* @pid_name: The name of the signal recipient
* @si_code: Indicates the signal type
* @task: A task handle to the signal recipient
* @sinfo: The address of siginfo struct
* @shared: Indicates whether the signal is shared by the thread group
* @send2queue- Indicates whether the signal is sent to an existing sigqueue
* @name: The name of the function used to send out the signal
*
* Context:
* The signal's sender.
*
*/
probe signal.send = _signal.send.*
{
sig_name = _signal_name(sig)
sig_pid = task_pid(task)
pid_name = task_execname(task)
if (sinfo == 2)
si_code ="SIGSTOP or SIGKILL"
else if (sinfo > 0)
si_code="SI_KERNEL (SIGFPE, SIGSEGV, SIGTRAP, SIGCHLD, SIGPOLL)"
else if (sinfo <= 0)
si_code="SI_USER or SI_TIMER or SI_ASYNCIO"
}
%( kernel_v <= "2.6.25" %?
probe _signal.send.part1 = kernel.function("__group_send_sig_info")
{
name = "__group_send_sig_info"
sig = $sig
task = $p
sinfo = $info
shared = 1
send2queue = 0
}
probe _signal.send.part2 = kernel.function("send_group_sigqueue")
{
name = "send_group_sigqueue"
sig = $sig
task = $p
sinfo = 0 # $q->info
shared = 1
send2queue = 1
}
probe _signal.send.part4 = kernel.function("specific_send_sig_info")
{
name = "specific_send_sig_info"
sig = $sig
task = $t
sinfo = $info
shared = 0
send2queue = 0
}
%)
%( kernel_v > "2.6.25" %?
probe _signal.send.part1 = kernel.function("send_signal")
{
if ($group == 1) {
name = "__group_send_sig_info"
shared = 1
}
else if ($group == 0) {
name = "specific_send_sig_info"
shared = 0
}
sig = $sig
task = $t
sinfo = $info
send2queue = 0
}
%)
probe _signal.send.part3 = kernel.function("send_sigqueue")
{
name = "send_sigqueue"
%( kernel_v >= "2.6.26" %?
task = $t
sig = $q->info->si_signo
%:
task = $p
sig = $sig
%)
sinfo = 0 # $q->info
shared = 0
send2queue = 1
}
/**
* probe signal.send.return - Fires when a signal sent to a process returns.
* @retstr: The return value to either __group_send_sig_info,
* specific_send_sig_info, or send_sigqueue.
* Refer to the Description of this probe for more information about the return
* values of each function call.
* @shared: Indicates whether the sent signal is shared by the thread group.
* @send2queue: Indicates whether the sent signal was sent to an existing sigqueue
* @name: The name of the function used to send out the signal.
*
* Context:
* The signal's sender. (correct?)
*
* Possible __group_send_sig_info and
* specific_send_sig_info return values are as follows;
*
* 0 - The signal is sucessfully sent to a process,
* which means that
* <1> the signal was ignored by the receiving process,
* <2> this is a non-RT signal and the system already has one queued, and
* <3> the signal was successfully added to the sigqueue of the receiving process.
*
* -EAGAIN - The sigqueue of the receiving process is
* overflowing, the signal was RT, and the signal was sent by a user using something other
* than kill()
*
* Possible send_group_sigqueue and
* send_sigqueue return values are as follows;
*
* 0 - The signal was either sucessfully added into the
* sigqueue of the receiving process, or a SI_TIMER entry is already
* queued (in which case, the overrun count will be simply incremented).
*
* 1 - The signal was ignored by the receiving process.
*
*
* -1 - (send_sigqueue only) The task was marked
* exiting, allowing * posix_timer_event to redirect it to the group
* leader.
*
*/
probe signal.send.return = _signal.send.*.return
{
retstr = returnstr(1)
}
// Return values for "__group_send_sig_info" and "specific_send_sig_info"
//
// - return 0 if the signal is sucessfully sent to a process,
// which means the following:
// <1> the signal is ignored by receiving process
// <2> this is a non-RT signal and we already have one queued
// <3> the signal is successfully added into the sigqueue of
// receiving process
//
// - return -EAGAIN if the sigqueue is overflow the signal was RT
// and sent by user using something other than kill()
%( kernel_v > "2.6.25" %?
probe _signal.send.part1.return = kernel.function("send_signal").return
{
if ($group == 1) {
name = "__group_send_sig_info"
shared = 1
}
else if ($group == 0) {
name = "specific_send_sig_info"
shared = 0
}
send2queue = 0
}
%)
%( kernel_v <= "2.6.25" %?
probe _signal.send.part1.return = kernel.function("__group_send_sig_info").return
{
name = "__group_send_sig_info"
shared = 1
send2queue = 0
}
probe _signal.send.part4.return = kernel.function("specific_send_sig_info").return
{
name = "specific_send_sig_info"
shared = 0
send2queue = 0
}
// - return 0 if the signal is either sucessfully added into the
// sigqueue of receiving process or a SI_TIMER entry is already
// queued so just increment the overrun count
//
// - return 1 if this signal is ignored by receiving process
probe _signal.send.part2.return = kernel.function("send_group_sigqueue").return
{
name = "send_group_sigqueue"
shared = 1
send2queue = 1
}
%)
// - return 0 if the signal is either sucessfully added into the
// sigqueue of receiving process or a SI_TIMER entry is already
// queued so just increment the overrun count
//
// - return 1 if this signal is ignored by receiving process
//
// - return -1 if the task is marked exiting, so posix_timer_event
// can redirect it to the group leader
probe _signal.send.part3.return = kernel.function("send_sigqueue").return
{
name = "send_sigqueue"
shared = 0
send2queue = 1
}
/**
* probe signal.checkperm - Fires when a permission check is performed on a sent signal
* @sig: The number of the signal
* @sig_name: A string representation of the signal
* @sig_pid: The PID of the process receiving the signal
* @pid_name: Name of the process receiving the signal
* @si_code: Indicates the signal type
* @task: A task handle to the signal recipient
* @sinfo: The address of the siginfo structure
* @name: Name of the probe point; default value is signal.checkperm
*/
probe signal.checkperm = kernel.function("check_kill_permission")
{
sig = $sig
task = $t
sinfo = $info
name = "signal.checkperm"
sig_name = _signal_name($sig)
sig_pid = task_pid(task)
pid_name = task_execname(task)
if (sinfo == 2)
si_code ="SIGSTOP or SIGKILL"
else if (sinfo > 0)
si_code="SI_KERNEL (SIGFPE, SIGSEGV, SIGTRAP, SIGCHLD, SIGPOLL)"
else if (sinfo <= 0)
si_code="SI_USER or SI_TIMER or SI_ASYNCIO"
}
probe signal.checkperm.return = kernel.function("check_kill_permission").return
{
name = "signal.checkperm"
retstr = returnstr(1)
}
/**
* probe signal.wakeup - Wakes up a sleeping process, making it ready for new active signals
* @sig_pid: The PID of the process you wish to wake
* @pid_name: Name of the process you wish to wake
* @resume: Indicates whether to wake up a task in a STOPPED or
* TRACED state
* @state_mask: A string representation indicating the mask
* of task states you wish to wake. Possible values are TASK_INTERRUPTIBLE,
* TASK_STOPPED, TASK_TRACED,
* and TASK_INTERRUPTIBLE.
*/
probe signal.wakeup = kernel.function("signal_wake_up")
{
sig_pid = $t->pid
pid_name = kernel_string($t->comm)
resume = $resume
if (resume == 0) {
state_mask = "TASK_INTERRUPTIBLE"
} else {
state_mask = "TASK_INTERRUPTIBLE | TASK_STOPPED | TASK_TRACED"
}
}
/**
* probe signal.check_ignored - Fires when a system call or kernel function checks whether a
* signal was ignored or not
* @sig_pid: The PID of the process receiving the signal
* @pid_name: Name of the process receiving the signal
* @sig: The number of the signal
* @sig_name: A string representation of the signal
*/
probe signal.check_ignored = kernel.function("sig_ignored")
{
sig_pid = $t->pid
pid_name = kernel_string($t->comm)
sig = $sig
sig_name = _signal_name($sig)
}
probe signal.check_ignored.return = kernel.function("sig_ignored").return ?
{
name = "sig_ignored"
retstr = returnstr(1)
}
// probe signal.handle_stop
// For now, just comment it out since at the time handle_stop_signal()
// is called, it doesn't know whether current signal is STOP/COUNT.
// So the calling of handle_stop_signal() doesn't mean that the Kernel
// is now processing the STOP/COUNT signal
//
/*
probe signal.handle_stop = kernel.function("handle_stop_signal")
{
sig_pid = $p->pid
pid_name = kernel_string($p->comm)
sig_info = $sig
sig_name = _signal_name($sig)
}
*/
/**
* probe signal.force_segv - Fires when a system call, kernel function, or process sent a
* SIGSEGV as a result of problems it encountered while handling a received signal
* @sig_pid: The PID of the process receiving the signal
* @pid_name: Name of the process receiving the signal
* @sig: The number of the signal
* @sig_name: A string representation of the signal
*/
probe signal.force_segv = _signal.force_segv.*
{
}
probe _signal.force_segv.part1 = kernel.function("force_sigsegv")
{
sig_pid = $p->pid
pid_name = kernel_string($p->comm)
sig = $sig
sig_name = _signal_name($sig)
}
probe _signal.force_segv.part2 = kernel.function("force_sigsegv_info") ?
{
sig_pid = pid()
pid_name = execname()
sig = $sig
sig_name = _signal_name($sig)
}
probe signal.force_segv.return =
kernel.function("force_sigsegv").return,
kernel.function("force_sigsegv_info").return ?
{
name = "force_sigsegv"
retstr = returnstr(1)
}
/**
* probe signal.syskill - Fires when the kernel function sys_kill
* sends a kill signal to a process
* @pid: The PID of the process receiving the kill signal
* @sig: The specific signal sent to the process
*/
probe signal.syskill = syscall.kill
{
sig_name = _signal_name($sig)
}
probe signal.syskill.return = syscall.kill.return
{
}
/**
* probe signal.sys_tkill - Fires when tkill sends a kill signal
* to a process that is part of a thread group
* @pid: The PID of the process receiving the kill signal
* @sig: The specific signal sent to the process
* The tkill call is analogous to kill(2),
* except that it also allows a process within a specific thread group to
* be targetted. Such processes are targetted through their unique thread IDs (TID).
*/
probe signal.systkill = syscall.tkill
{
sig_name = _signal_name($sig)
}
probe signal.systkill.return = syscall.tkill.return
{
}
/**
* probe signal.sys_tgkill - Fires when the kernel function tgkill
* sends a kill signal to a specific thread group
* @pid: The PID of the thread receiving the kill signal
* @tgid: The thread group ID of the thread receiving the kill signal
* @sig: The specific kill signal sent to the process
* The tgkill call is similar to tkill,
* except that it also allows the caller to specify the thread group ID of
* the thread to be signalled. This protects against TID reuse.
*/
probe signal.systgkill = syscall.tgkill
{
sig_name = _signal_name($sig)
}
probe signal.systgkill.return = syscall.tgkill.return
{
}
/**
* probe signal.send_sig_queue - Fires when a signal is queued to a process
* @sig: The queued signal
* @sig_name: A string representation of the signal
* @sig_pid: The PID of the process to which the signal is queued
* @pid_name: Name of the process to which the signal is queued
* @sigqueue_addr: The address of the signal queue
*/
probe signal.send_sig_queue =
kernel.function("send_sigqueue"),
kernel.function("send_group_sigqueue") ?
{
sig = $sig
sig_name = _signal_name($sig)
sig_pid = $p->pid
pid_name = kernel_string($p->comm)
sigqueue_addr = $q
}
probe signal.send_sig_queue.return =
kernel.function("send_sigqueue").return,
kernel.function("send_group_sigqueue").return ?
{
retstr = returnstr(1)
}
/**
* probe signal.pending - Fires when the SIGPENDING system call is used;
* this normally occurs when the do_sigpending kernel function is executed
* @sigset_add: The address of the user-space signal set (sigset_t)
* @sigset_size: The size of the user-space signal set.
*
* Synopsis:
* long do_sigpending(void __user *set, unsigned long sigsetsize)
*
* This probe is used to examine a set of signals pending for delivery
* to a specific thread.
*/
// long do_sigpending(void __user *set, unsigned long sigsetsize)
probe signal.pending = kernel.function("do_sigpending")
{
sigset_add=$set
sigset_size=$sigsetsize
}
probe signal.pending.return = kernel.function("do_sigpending").return
{
retstr = returnstr(1)
}
/**
* probe signal.handle - Fires when the signal handler is invoked
* @sig: The signal number that invoked the signal handler
* @sinfo: The address of the siginfo table
* @sig_code: The si_code value of the siginfo signal
* @ka_addr: The address of the k_sigaction table associated with the signal
* @oldset_addr: The address of the bitmask array of blocked signals
* @regs: The address of the kernel-mode stack area
* @sig_mode: Indicates whether the signal was a user-mode or kernel-mode signal
*
* Synopsis:
* static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
* sigset_t *oldset, struct pt_regs * regs)
*/
//static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
// sigset_t *oldset, struct pt_regs * regs)
probe signal.handle = kernel.function("handle_signal")
{
sig = $sig
sig_name = _signal_name($sig)
sinfo = $info
sig_code = $info->si_code
ka_addr = $ka
oldset_addr =$oldset
regs = $regs
// Check whether the signal is a User Mode or Kernel mode Signal.
if (sinfo == 0 && sig_code <= 0)
sig_mode = "User Mode Signal"
else if (sinfo >= 1)
sig_mode = "Kernel Mode Signal"
}
probe signal.handle.return = kernel.function("handle_signal").return ?
{
retstr = returnstr(1)
}
/**
* probe signal.do_action - Initiates a trace when a thread is about to examine
* and change a signal action
* @sig: The signal to be examined/changed
* @sigact_addr: The address of the new sigaction struct associated with the signal
* @oldsigact_addr: The address of the old sigaction struct associated with the signal
* @sa_handler: The new handler of the signal
* @sa_mask: The new mask of the signal
*/
probe signal.do_action = kernel.function("do_sigaction")
{
sig = $sig
sigact_addr = $act
oldsigact_addr = $oact
if(sigact_addr != 0)
{
sa_handler = $act->sa->sa_handler
sa_mask = __get_action_mask($act)
}
}
probe signal.do_action.return = kernel.function("do_sigaction").return
{
retstr = returnstr(1)
}
function __get_action_mask:long(act:long) %{ /* pure */
int i;
struct k_sigaction *act = (struct k_sigaction *)((long)THIS->act);
sigset_t *sigset = &act->sa.sa_mask;
THIS->__retvalue = kread(&(sigset->sig[0]));
for (i=1; i<_NSIG_WORDS; ++i) {
uint64_t part = kread(&(sigset->sig[i]));
THIS->__retvalue |= part << (_NSIG_BPW*i);
}
CATCH_DEREF_FAULT();
%}
/**
* probe signal.procmask - Initiates a trace when a thread is about to examine and change blocked signals
* @how: Indicates how to change the blocked signals; possible values are
* SIG_BLOCK=0 (for blocking signals),
* SIG_UNBLOCK=1 (for unblocking signals), and
* SIG_SETMASK=2 for setting the signal mask.
* @sigset_addr: The address of the signal set (sigset_t) to be implemented
* @oldsigset_addr: The old address of the signal set (sigset_t)
* @sigset: The actual value to be set for sigset_t (correct?)
* Synopsis:
* int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
*/
probe signal.procmask = kernel.function("sigprocmask")
{
how=$how
sigset_addr = $set
oldsigset_addr = $oldset
sigset = get_sigset($set)
}
function get_sigset:long(sigset:long) %{ /* pure */
int i;
sigset_t *sigset = (sigset_t *)((long)THIS->sigset);
THIS->__retvalue = kread(&(sigset->sig[0]));
for (i=1; i<_NSIG_WORDS; ++i) {
uint64_t part = kread(&(sigset->sig[i]));
THIS->__retvalue |= part << (_NSIG_BPW*i);
}
CATCH_DEREF_FAULT();
%}
probe signal.procmask.return = kernel.function("sigprocmask").return
{
retstr = returnstr(1)
}
/**
* probe signal.flush - Fires when all pending signals for a task are flushed
* @task: The task handler of the process performing the flush
* @sig_pid: The PID of the process associated with the task performing the flush
* @pid_name: The name of the process associated with the task performing the flush
*
* Synopsis:
* void flush_signals(struct task_struct *t)
*/
//void flush_signals(struct task_struct *t)
probe signal.flush = kernel.function("flush_signals")
{
task = $t
sig_pid = $t->pid
pid_name = kernel_string($t->comm)
}
function get_sa_flags:long (act:long)
{
return @cast(act, "k_sigaction", "kernel")->sa->sa_flags
}
function get_sa_handler:long (act:long)
{
return @cast(act, "k_sigaction", "kernel")->sa->sa_handler
}
// sa_mask contains the set of signals to be blocked when executing the
// signal handler. This function returns a string, delimited by ",".
//
// struct task_struct {
// [...]
// struct signal_struct//signal;
// struct sighand_struct//sighand;
// [...]
// struct sighand_struct {
// atomic_t count;
// struct k_sigaction action[_NSIG];
// [...]
// struct k_sigaction {
// struct sigaction sa;
// };
//
// struct sigaction {
// [...]
// sigset_t sa_mask;
// };
function sigset_mask_str:string (mask:long) %{ /* pure */
int i, len;
char *str = THIS->__retvalue, tmp[5];
for (i = 1; i < _NSIG; ++i, THIS->mask >>=1)
if (THIS->mask & 1) {
sprintf(tmp, "%u,", i);
strlcat(str, tmp, MAXSTRINGLEN);
}
len = strlen(str);
if (len) str[len - 1] = '\0';
%}
// task_struct->blocked signal mask contains the set of signals that are
// currently blocked.
//
// struct task_struct {
// [...]
// sigset_t blocked, real_blocked;
function is_sig_blocked:long (task:long, sig:long) %{ /* pure */
int i;
sigset_t blocked;
struct task_struct *p = (struct task_struct *)((long)THIS->task);
for (i = 0; i < _NSIG_WORDS; ++i)
blocked.sig[i] = kread(&p->blocked.sig[i]);
THIS->__retvalue = sigismember(&blocked, THIS->sig);
CATCH_DEREF_FAULT();
%}
function sa_flags_str:string (sa_flags:long) %{ /* pure */
int len;
char *str = THIS->__retvalue;
if (THIS->sa_flags & 0x00000001u) strlcat(str, "NOCLDSTOP|", MAXSTRINGLEN);
if (THIS->sa_flags & 0x00000002u) strlcat(str, "NOCLDWAIT|", MAXSTRINGLEN);
if (THIS->sa_flags & 0x00000004u) strlcat(str, "SIGINFO|", MAXSTRINGLEN);
if (THIS->sa_flags & 0x08000000u) strlcat(str, "ONSTACK|", MAXSTRINGLEN);
if (THIS->sa_flags & 0x10000000u) strlcat(str, "RESTART|", MAXSTRINGLEN);
if (THIS->sa_flags & 0x40000000u) strlcat(str, "NODEFER|", MAXSTRINGLEN);
if (THIS->sa_flags & 0x80000000u) strlcat(str, "RESETHAND|", MAXSTRINGLEN);
if (THIS->sa_flags & 0x04000000) strlcat(str, "RESTORER|", MAXSTRINGLEN);
len = strlen(str);
if (len) str[len - 1] = '\0';
%}
function sa_handler_str(handler) {
if (handler == 0) return "default"; /* SIG_DFL */
if (handler == 1) return "ignored"; /* SIG_IGN */
if (handler == -1) return "error"; /* SIG_ERR */
return sprintf("%p", handler); /* userspace address */
}
// Signals start from 1 not 0.
global __sig[64]
function signal_str(num) {
if (!(64 in __sig)) {
__sig[1] = "HUP"
__sig[2] = "INT"
__sig[3] = "QUIT"
__sig[4] = "ILL"
__sig[5] = "TRAP"
__sig[6] = "ABRT" /* or IOT */
__sig[7] = "BUS"
__sig[8] = "FPE"
__sig[9] = "KILL"
__sig[10] = "USR1"
__sig[11] = "SEGV"
__sig[12] = "USR2"
__sig[13] = "PIPE"
__sig[14] = "ALRM"
__sig[15] = "TERM"
__sig[16] = "STKFLT"
__sig[17] = "CHLD" /* or CLD */
__sig[18] = "CONT"
__sig[19] = "STOP"
__sig[20] = "TSTP"
__sig[21] = "TTIN"
__sig[22] = "TTOU"
__sig[23] = "URG"
__sig[24] = "XCPU"
__sig[25] = "XFSZ"
__sig[26] = "VTALRM"
__sig[27] = "PROF"
__sig[28] = "WINCH"
__sig[29] = "IO/POLL"
__sig[30] = "PWR"
__sig[31] = "SYS" /* or UNUSED */
__sig[32] = "RTMIN"
__sig[33] = "RTMIN+1"
__sig[34] = "RTMIN+2"
__sig[35] = "RTMIN+3"
__sig[36] = "RTMIN+4"
__sig[37] = "RTMIN+5"
__sig[38] = "RTMIN+6"
__sig[39] = "RTMIN+7"
__sig[40] = "RTMIN+8"
__sig[41] = "RTMIN+9"
__sig[42] = "RTMIN+10"
__sig[43] = "RTMIN+11"
__sig[44] = "RTMIN+12"
__sig[45] = "RTMIN+13"
__sig[46] = "RTMIN+14"
__sig[47] = "RTMIN+15"
__sig[48] = "RTMIN+16"
__sig[49] = "RTMIN+17"
__sig[50] = "RTMIN+18"
__sig[51] = "RTMIN+19"
__sig[52] = "RTMIN+20"
__sig[53] = "RTMIN+21"
__sig[54] = "RTMIN+22"
__sig[55] = "RTMIN+23"
__sig[56] = "RTMIN+24"
__sig[57] = "RTMIN+25"
__sig[58] = "RTMIN+26"
__sig[59] = "RTMIN+27"
__sig[60] = "RTMIN+28"
__sig[61] = "RTMIN+29"
__sig[62] = "RTMIN+30"
__sig[63] = "RTMIN+31"
__sig[64] = "RTMIN+32"
}
return __sig[num]
}