summaryrefslogtreecommitdiffstats
path: root/tapset/signal.stp
blob: 1e568ae510e4cb6ebb260d28d65621f5b779e2aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
// Signal tapset
// Copyright (C) 2006 IBM Corp.
// Copyright (C) 2006 Intel Corporation.
//
// 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 signal is sent to a process.
 *
 * Context:
 *  The signal's sender.
 *
 * Arguments:
 *  sig - the number of the signal
 *  sig_name - a string representation of the signal
 *  task - a task handle to the signal recipient
 *  shared - indicates whether this signal is shared by the thread group
 */
probe signal.send = _signal.send.*
{
    sig=$sig
    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.send.part1 = kernel.function("__group_send_sig_info")
{
    name = "__group_send_sig_info"
    task = $p
    sinfo = $info
    shared = 1
    send2queue = 0
}

probe _signal.send.part2 = kernel.function("send_group_sigqueue")
{
    name = "send_group_sigqueue"
    task = $p
    sinfo = $q->info
    shared = 1
    send2queue = 1
}

probe _signal.send.part3 = kernel.function("send_sigqueue")
{
    name = "send_sigqueue"
    task = $p
    sinfo = $q->info
    shared = 0
    send2queue = 1
}

probe _signal.send.part4 = kernel.function("specific_send_sig_info")
{
    name = "specific_send_sig_info"
    task = $t
    sinfo = $info
    shared = 0
    send2queue = 0
}

/* probe signal.send.return
 */
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()
 *
 */
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_sigqueueu"
    shared = 0
    send2queue = 1
}

/* probe signal.checkperm
 *
 *  check permissions for sending the signal
 *
 */
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
 *
 * Wake up the process for new active signals.
 *
 */
probe signal.wakeup = kernel.function("signal_wake_up")
{
    sig_pid = $t->pid
    pid_name = kernel_string($t->comm)
    state   = $resume
    if (state == 0) {
        sig_state = "TASK_INTERRUPTIBLE"
    } else {
        sig_state = "TASK_INTERRUPTIBLE | TASK_STOPPED | TASK_TRACED"
    }
}


/* probe signal.ignored
 *
 *  Checks whether the signal is ignored or not.
 *
 */
probe signal.check_ignored = kernel.function("sig_ignored")
{
    sig_pid = $t->pid
    pid_name = kernel_string($t->comm)
    sig_info = $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
 *
 *  Forces SIGSEGV when there are some issues while handling signals for the process.
 *
 */
probe signal.force_segv = kernel.function("force_sigsegv")
{
    sig_pid = $p->pid
    pid_name = kernel_string($p->comm)
    sig_info = $sig
    sig_name = _signal_name($sig)
}

probe signal.force_segv.return = kernel.function("force_sigsegv").return
{
    name = "force_sigsegv"
    retstr = returnstr(1)
}


/* probe signal.syskill
 *
 *  To kill a process, Pass the pid and signal to kill the process.
 *
 */
probe signal.syskill = syscall.kill
{
    sig_name = _signal_name($sig)
}

probe signal.syskill.return = syscall.kill.return
{
}


/* probe signal.sys_tgkill
 *
 *  Sends a signal to one specific thread.
 *
 */
probe signal.systgkill = syscall.tgkill
{
    sig_name = _signal_name($sig)
}

probe signal.systgkill.return = syscall.tgkill.return
{
}


/* probe signal.sys_tkill
 *
 *  Sends a signal to one specific task.
 *
 */
probe signal.systkill = syscall.tkill
{
    sig_name = _signal_name($sig)
}

probe signal.systkill.return = syscall.tkill.return
{
}


/* probe signal.send_sig_queue
 *
 * Queue signal to a process.
 *
 */
probe signal.send_sig_queue =
        kernel.function("send_sigqueue"),
        kernel.function("send_group_sigqueue")
{
    sig_info = $sig
    sig_name = _signal_name($sig)
    sig_pid = $p->pid
    pid_name = kernel_string($p->comm)
    user_id = $q->uid
    nos_process = $q->processes
    nos_pending_sig = $q->sigpending
}

probe signal.send_sig_queue.return =
        kernel.function("send_sigqueue").return,
        kernel.function("send_group_sigqueue").return
{
    retstr = returnstr(1)
}


/* probe signal.pending
 *
 * Used to examine the set of signals that are pending for 
 * delivery to the calling thread
 *
 * long do_sigpending(void __user *set, unsigned long sigsetsize)
 */
probe signal.pending = kernel.function("do_sigpending")
{
    uspace_add=$set
    sset_size=$sigsetsize
}

probe signal.pending.return = kernel.function("do_sigpending").return
{
    retstr = returnstr(1)
}


/* probe signal.handle
 *
 * Used to invoke signals
 *
 * static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 *					sigset_t *oldset, struct pt_regs * regs)
 * Argument :-
 *  sig    : Signal number
 *  info   : address of siginfo table.
 *  ka     : Address of the k_sigaction table associated with the signal
 *  oldset : Address of a bit mask array of blocked signals
 *  regs   : Address in the Kernel Mode stack area 
 *  
 */
probe signal.handle = kernel.function("handle_signal")?,
        kernel.inline("handle_signal")?
{
    sig = $sig
    sig_name = _signal_name($sig)
    sinfo_addr = $info
    sig_code = $info->si_code
    sig_stack_add=$ka
    bitmask_add=$oldset
    kernmode_stack_add=$regs

    // Check whether the signal is a User Mode or Kernel mode Signal.
    
    if (sinfo_addr == 0 && sig_code <= 0)
        sig_mode = "User Mode Signal"
    else if (sinfo_addr >=  1)
        sig_mode = "Kernel Mode Signal"
}

probe signal.handle.return = kernel.function("handle_signal").return
{
    retstr = returnstr(1)
}


/* probe signal.do_action
 *
 * Called by sys_sigaction() to copy the new new_ka table into the entry at the sig-1 position.
 *
 * int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
 *
 * Argument :-
 *  sig    : Signal number
 *  act    : Address of the sigaction table associated with the signal
 *  oact   : Address of a previous sigaction table
 *
 */
probe signal.do_action = kernel.function("do_sigaction")
{
    sig = $sig
    sigact_table=$act
    psigact_table=$oact
    if(sigact_table != 0)
    {
         sa_handler = $act->sa->sa_handler
         sa_mask = $act->sa->sa_mask
    }
}

probe signal.do_action.return = kernel.function("do_sigaction").return
{
    retstr = returnstr(1)
}


/* probe signal.procmask
 *
 * Allows processes to modify the set of blocked signals.
 *
 * int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
 *
 * Argument :-
 *  how    : Flag having one of the values (SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK)
 *  set    : Address of the process address space to a bit array.
 *  oldset : Address of the process address space where the previous bit mask must be stored.
 *
 */
probe signal.procmask = kernel.function("sigprocmask")
{
    stemp=$how
    sigset_addr = $set
    sigoset_addr = $oldset

    sigset = get_sigset($set)
    if (stemp == 0)
        sig_how ="SIG_BLOCK"
    else if (stemp ==  1)
        sig_how="SIG_UNBLOCK"
    else if (stemp == 2)
        sig_how="SIG_SETMASK"
}

function get_sigset:long(sigset:long) %{ /* pure */

    sigset_t *sigset = (sigset_t *)((long)THIS->sigset);

if(_NSIG_BPW == 64)
    THIS->__retvalue = deref(sizeof(sigset_t), sigset);
else if(_NSIG_BPW == 32)
    THIS->__retvalue = deref(sizeof(int), &(sigset->sig[0])) |
        ((u_int64_t)deref(sizeof(int), &(sigset->sig[1])))<<32;

    if(0)  {
deref_fault:
        CONTEXT->last_error = "pointer deref error";
    }
%}

probe signal.procmask.return = kernel.function("sigprocmask").return
{
    retstr = returnstr(1)
}


/*
 * probe signal.flush
 * 
 * Flush all pending signals for a task.
 *
 * 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)
}