1
2 #include "inc.h"
3
4 #include <signal.h>
5 #include <sys/time.h>
6 #include <sys/wait.h>
7 #include <sys/resource.h>
8 #include <sys/utsname.h>
9 #include <sys/reboot.h>
10 #include <minix/profile.h>
11
12 static int
pm_exit_out(struct trace_proc * proc,const message * m_out)13 pm_exit_out(struct trace_proc * proc, const message * m_out)
14 {
15
16 put_value(proc, "status", "%d", m_out->m_lc_pm_exit.status);
17
18 return CT_NORETURN;
19 }
20
21 static const struct flags wait4_options[] = {
22 FLAG(WNOHANG),
23 FLAG(WUNTRACED),
24 FLAG(WALTSIG),
25 FLAG(WALLSIG),
26 FLAG(WNOWAIT),
27 FLAG(WNOZOMBIE),
28 FLAG(WOPTSCHECKED),
29 };
30
31 static void
put_wait4_status(struct trace_proc * proc,const char * name,int status)32 put_wait4_status(struct trace_proc * proc, const char * name, int status)
33 {
34 const char *signame;
35 int sig;
36
37 /*
38 * There is no suitable set of macros to be used here, so we're going
39 * to invent our own: W_EXITED, W_SIGNALED, and W_STOPPED. Hopefully
40 * they are sufficiently clear even though they don't actually exist.
41 * The code below is downright messy, but it also ensures that no bits
42 * are set unexpectedly in the status.
43 */
44 if (!valuesonly && WIFEXITED(status) &&
45 status == W_EXITCODE(WEXITSTATUS(status), 0)) {
46 put_value(proc, name, "W_EXITED(%d)",
47 WEXITSTATUS(status));
48
49 return;
50 }
51
52 /* WCOREDUMP() actually returns WCOREFLAG or 0, but better safe.. */
53 if (!valuesonly && WIFSIGNALED(status) && status == (W_EXITCODE(0,
54 WTERMSIG(status)) | (WCOREDUMP(status) ? WCOREFLAG : 0))) {
55 sig = WTERMSIG(status);
56
57 if ((signame = get_signal_name(sig)) != NULL)
58 put_value(proc, name, "W_SIGNALED(%s)", signame);
59 else
60 put_value(proc, name, "W_SIGNALED(%u)", sig);
61
62 if (WCOREDUMP(status))
63 put_text(proc, "|WCOREDUMP");
64
65 return;
66 }
67
68 if (!valuesonly && WIFSTOPPED(status) &&
69 status == W_STOPCODE(WSTOPSIG(status))) {
70 sig = WSTOPSIG(status);
71
72 if ((signame = get_signal_name(sig)) != NULL)
73 put_value(proc, name, "W_STOPPED(%s)", signame);
74 else
75 put_value(proc, name, "W_STOPPED(%u)", sig);
76
77 return;
78 }
79
80 /*
81 * If we get here, either valuesonly is enabled or the resulting status
82 * is not one we recognize, for example because extra bits are set.
83 */
84 put_value(proc, name, "0x%04x", status);
85 }
86
87 static int
pm_wait4_out(struct trace_proc * proc,const message * m_out)88 pm_wait4_out(struct trace_proc * proc, const message * m_out)
89 {
90
91 put_value(proc, "pid", "%d", m_out->m_lc_pm_wait4.pid);
92
93 return CT_NOTDONE;
94 }
95
96 static void
put_struct_rusage(struct trace_proc * proc,const char * name,int flags,vir_bytes addr)97 put_struct_rusage(struct trace_proc * proc, const char * name, int flags,
98 vir_bytes addr)
99 {
100 struct rusage ru;
101
102 if (!put_open_struct(proc, name, flags, addr, &ru, sizeof(ru)))
103 return;
104
105 put_struct_timeval(proc, "ru_utime", PF_LOCADDR,
106 (vir_bytes)&ru.ru_utime);
107 put_struct_timeval(proc, "ru_stime", PF_LOCADDR,
108 (vir_bytes)&ru.ru_stime);
109
110 if (verbose > 0) {
111 put_value(proc, "ru_maxrss", "%ld", ru.ru_maxrss);
112 put_value(proc, "ru_minflt", "%ld", ru.ru_minflt);
113 put_value(proc, "ru_majflt", "%ld", ru.ru_majflt);
114 }
115
116 put_close_struct(proc, verbose > 0);
117 }
118
119 static void
pm_wait4_in(struct trace_proc * proc,const message * m_out,const message * m_in,int failed)120 pm_wait4_in(struct trace_proc * proc, const message * m_out,
121 const message * m_in, int failed)
122 {
123
124 /*
125 * If the result is zero, there is no status to show. Also, since the
126 * status is returned in the result message, we cannot print the user-
127 * given pointer. Instead, upon failure we show "&.." to indicate an
128 * unknown pointer.
129 */
130 if (!failed && m_in->m_type > 0)
131 put_wait4_status(proc, "status", m_in->m_pm_lc_wait4.status);
132 else
133 put_field(proc, "status", "&..");
134 put_flags(proc, "options", wait4_options, COUNT(wait4_options),
135 "0x%x", m_out->m_lc_pm_wait4.options);
136 put_struct_rusage(proc, "rusage", failed, m_out->m_lc_pm_wait4.addr);
137 put_equals(proc);
138 put_result(proc);
139 }
140
141 static void
pm_getpid_in(struct trace_proc * proc,const message * __unused m_out,const message * m_in,int failed)142 pm_getpid_in(struct trace_proc * proc, const message * __unused m_out,
143 const message * m_in, int failed)
144 {
145
146 put_result(proc);
147 if (!failed) {
148 put_open(proc, NULL, 0, "(", ", ");
149 put_value(proc, "ppid", "%d", m_in->m_pm_lc_getpid.parent_pid);
150 put_close(proc, ")");
151 }
152 }
153
154 /* This function is shared between setuid and seteuid. */
155 static int
pm_setuid_out(struct trace_proc * proc,const message * m_out)156 pm_setuid_out(struct trace_proc * proc, const message * m_out)
157 {
158
159 put_value(proc, "uid", "%u", m_out->m_lc_pm_setuid.uid);
160
161 return CT_DONE;
162 }
163
164 static void
pm_getuid_in(struct trace_proc * proc,const message * __unused m_out,const message * m_in,int failed)165 pm_getuid_in(struct trace_proc * proc, const message * __unused m_out,
166 const message * m_in, int failed)
167 {
168
169 put_result(proc);
170 if (!failed) {
171 put_open(proc, NULL, 0, "(", ", ");
172 put_value(proc, "euid", "%u", m_in->m_pm_lc_getuid.euid);
173 put_close(proc, ")");
174 }
175 }
176
177 static int
pm_stime_out(struct trace_proc * proc,const message * m_out)178 pm_stime_out(struct trace_proc * proc, const message * m_out)
179 {
180
181 put_time(proc, "time", m_out->m_lc_pm_time.sec);
182
183 return CT_DONE;
184 }
185
186 static void
put_signal(struct trace_proc * proc,const char * name,int sig)187 put_signal(struct trace_proc * proc, const char * name, int sig)
188 {
189 const char *signame;
190
191 if (!valuesonly && (signame = get_signal_name(sig)) != NULL)
192 put_field(proc, name, signame);
193 else
194 put_value(proc, name, "%d", sig);
195 }
196
197 static void
put_ptrace_req(struct trace_proc * proc,const char * name,int req)198 put_ptrace_req(struct trace_proc * proc, const char * name, int req)
199 {
200 const char *text = NULL;
201
202 if (!valuesonly) {
203 switch (req) {
204 TEXT(T_STOP);
205 TEXT(T_OK);
206 TEXT(T_ATTACH);
207 TEXT(T_DETACH);
208 TEXT(T_RESUME);
209 TEXT(T_STEP);
210 TEXT(T_SYSCALL);
211 TEXT(T_EXIT);
212 TEXT(T_GETINS);
213 TEXT(T_GETDATA);
214 TEXT(T_GETUSER);
215 TEXT(T_SETINS);
216 TEXT(T_SETDATA);
217 TEXT(T_SETUSER);
218 TEXT(T_SETOPT);
219 TEXT(T_GETRANGE);
220 TEXT(T_SETRANGE);
221 TEXT(T_READB_INS);
222 TEXT(T_WRITEB_INS);
223 }
224 }
225
226 if (text != NULL)
227 put_field(proc, name, text);
228 else
229 put_value(proc, name, "%d", req);
230 }
231
232 static void
put_struct_ptrace_range(struct trace_proc * proc,const char * name,int flags,vir_bytes addr)233 put_struct_ptrace_range(struct trace_proc * proc, const char * name, int flags,
234 vir_bytes addr)
235 {
236 struct ptrace_range pr;
237
238 if (!put_open_struct(proc, name, flags, addr, &pr, sizeof(pr)))
239 return;
240
241 if (!valuesonly && pr.pr_space == TS_INS)
242 put_field(proc, "pr_space", "TS_INS");
243 else if (!valuesonly && pr.pr_space == TS_DATA)
244 put_field(proc, "pr_space", "TS_DATA");
245 else
246 put_value(proc, "pr_space", "%d", pr.pr_space);
247 put_value(proc, "pr_addr", "0x%lx", pr.pr_addr);
248 put_ptr(proc, "pr_ptr", (vir_bytes)pr.pr_ptr);
249 put_value(proc, "pr_size", "%zu", pr.pr_size);
250
251 put_close_struct(proc, TRUE /*all*/);
252 }
253
254 static int
pm_ptrace_out(struct trace_proc * proc,const message * m_out)255 pm_ptrace_out(struct trace_proc * proc, const message * m_out)
256 {
257
258 put_ptrace_req(proc, "req", m_out->m_lc_pm_ptrace.req);
259 put_value(proc, "pid", "%d", m_out->m_lc_pm_ptrace.pid);
260
261 switch (m_out->m_lc_pm_ptrace.req) {
262 case T_GETINS:
263 case T_GETDATA:
264 case T_GETUSER:
265 case T_READB_INS:
266 put_value(proc, "addr", "0x%lx", m_out->m_lc_pm_ptrace.addr);
267 put_value(proc, "data", "%ld", m_out->m_lc_pm_ptrace.data);
268 break;
269 case T_SETINS:
270 case T_SETDATA:
271 case T_SETUSER:
272 case T_WRITEB_INS:
273 put_value(proc, "addr", "0x%lx", m_out->m_lc_pm_ptrace.addr);
274 put_value(proc, "data", "0x%lx", m_out->m_lc_pm_ptrace.data);
275 break;
276 case T_RESUME:
277 case T_STEP:
278 case T_SYSCALL:
279 put_value(proc, "addr", "%ld", m_out->m_lc_pm_ptrace.addr);
280 put_signal(proc, "data", m_out->m_lc_pm_ptrace.data);
281 break;
282 case T_GETRANGE:
283 case T_SETRANGE:
284 put_struct_ptrace_range(proc, "addr", 0,
285 m_out->m_lc_pm_ptrace.addr);
286 put_value(proc, "data", "%ld", m_out->m_lc_pm_ptrace.data);
287 break;
288 default:
289 put_value(proc, "addr", "%ld", m_out->m_lc_pm_ptrace.addr);
290 put_value(proc, "data", "%ld", m_out->m_lc_pm_ptrace.data);
291 break;
292 }
293
294 return CT_DONE;
295 }
296
297 static void
pm_ptrace_in(struct trace_proc * proc,const message * m_out,const message * m_in,int failed)298 pm_ptrace_in(struct trace_proc * proc, const message * m_out,
299 const message * m_in, int failed)
300 {
301
302 if (!failed) {
303 switch (m_out->m_lc_pm_ptrace.req) {
304 case T_GETINS:
305 case T_GETDATA:
306 case T_GETUSER:
307 case T_READB_INS:
308 put_value(proc, NULL, "0x%lx",
309 m_in->m_pm_lc_ptrace.data);
310 return;
311 }
312 }
313
314 put_result(proc);
315 }
316
317 void
put_groups(struct trace_proc * proc,const char * name,int flags,vir_bytes addr,int count)318 put_groups(struct trace_proc * proc, const char * name, int flags,
319 vir_bytes addr, int count)
320 {
321 gid_t groups[NGROUPS_MAX];
322 int i;
323
324 if ((flags & PF_FAILED) || valuesonly || count < 0 ||
325 count > NGROUPS_MAX || (count > 0 && mem_get_data(proc->pid, addr,
326 groups, count * sizeof(groups[0])) < 0)) {
327 if (flags & PF_LOCADDR)
328 put_field(proc, name, "&..");
329 else
330 put_ptr(proc, name, addr);
331
332 return;
333 }
334
335 put_open(proc, name, PF_NONAME, "[", ", ");
336 for (i = 0; i < count; i++)
337 put_value(proc, NULL, "%u", groups[i]);
338 put_close(proc, "]");
339 }
340
341 static int
pm_setgroups_out(struct trace_proc * proc,const message * m_out)342 pm_setgroups_out(struct trace_proc * proc, const message * m_out)
343 {
344
345 put_value(proc, "ngroups", "%d", m_out->m_lc_pm_groups.num);
346 put_groups(proc, "grouplist", 0, m_out->m_lc_pm_groups.ptr,
347 m_out->m_lc_pm_groups.num);
348
349 return CT_DONE;
350 }
351
352 static int
pm_getgroups_out(struct trace_proc * proc,const message * m_out)353 pm_getgroups_out(struct trace_proc * proc, const message * m_out)
354 {
355
356 put_value(proc, "ngroups", "%d", m_out->m_lc_pm_groups.num);
357
358 return CT_NOTDONE;
359 }
360
361 static void
pm_getgroups_in(struct trace_proc * proc,const message * m_out,const message * m_in,int failed)362 pm_getgroups_in(struct trace_proc * proc, const message * m_out,
363 const message * m_in, int failed)
364 {
365
366 put_groups(proc, "grouplist", failed, m_out->m_lc_pm_groups.ptr,
367 m_in->m_type);
368 put_equals(proc);
369 put_result(proc);
370 }
371
372 static int
pm_kill_out(struct trace_proc * proc,const message * m_out)373 pm_kill_out(struct trace_proc * proc, const message * m_out)
374 {
375
376 put_value(proc, "pid", "%d", m_out->m_lc_pm_sig.pid);
377 put_signal(proc, "sig", m_out->m_lc_pm_sig.nr);
378
379 return CT_DONE;
380 }
381
382 /* This function is shared between setgid and setegid. */
383 static int
pm_setgid_out(struct trace_proc * proc,const message * m_out)384 pm_setgid_out(struct trace_proc * proc, const message * m_out)
385 {
386
387 put_value(proc, "gid", "%u", m_out->m_lc_pm_setgid.gid);
388
389 return CT_DONE;
390 }
391
392 static void
pm_getgid_in(struct trace_proc * proc,const message * __unused m_out,const message * m_in,int failed)393 pm_getgid_in(struct trace_proc * proc, const message * __unused m_out,
394 const message * m_in, int failed)
395 {
396
397 put_result(proc);
398 if (!failed) {
399 put_open(proc, NULL, 0, "(", ", ");
400 put_value(proc, "egid", "%u", m_in->m_pm_lc_getgid.egid);
401 put_close(proc, ")");
402 }
403 }
404
405 static int
put_frame_string(struct trace_proc * proc,vir_bytes frame,size_t len,vir_bytes addr)406 put_frame_string(struct trace_proc * proc, vir_bytes frame, size_t len,
407 vir_bytes addr)
408 {
409 vir_bytes stacktop, offset;
410
411 /*
412 * The addresses in the frame assume that the process has already been
413 * changed, and the top of the frame is now located at the new process
414 * stack top, which is a hardcoded system-global value. In order to
415 * print the strings, we must convert back each address to its location
416 * within the given frame.
417 */
418 stacktop = kernel_get_stacktop();
419
420 if (addr >= stacktop)
421 return FALSE;
422 offset = stacktop - addr;
423 if (offset >= len)
424 return FALSE;
425 addr = frame + len - offset;
426
427 /*
428 * TODO: while using put_buf() is highly convenient, it does require at
429 * least one copy operation per printed string. The strings are very
430 * likely to be consecutive in memory, so copying in larger chunks at
431 * once would be preferable. Also, if copying from the frame fails,
432 * put_buf() will print the string address as we corrected it above,
433 * rather than the address as found in the frame. A copy failure would
434 * always be a case of malice on the traced process's behalf, though.
435 */
436 put_buf(proc, NULL, PF_STRING, addr, len - offset);
437
438 return TRUE;
439 }
440
441 /*
442 * Print the contents of the exec frame, which includes both pointers and
443 * actual string data for the arguments and environment variables to be used.
444 * Even though we know that the entire frame is not going to exceed ARG_MAX
445 * bytes, this is too large a size for a static buffer, and we'd like to avoid
446 * allocating large dynamic buffers as well. The situation is complicated by
447 * the fact that any string in the frame may run up to the end of the frame.
448 */
449 static void
put_exec_frame(struct trace_proc * proc,vir_bytes addr,size_t len)450 put_exec_frame(struct trace_proc * proc, vir_bytes addr, size_t len)
451 {
452 void *argv[64];
453 size_t off, chunk;
454 unsigned int i, count, max, argv_max, envp_max;
455 int first, ok, nulls;
456
457 if (valuesonly) {
458 put_ptr(proc, "frame", addr);
459 put_value(proc, "framelen", "%zu", len);
460
461 return;
462 }
463
464 if (verbose == 0) {
465 argv_max = 16;
466 envp_max = 0;
467 } else if (verbose == 1)
468 argv_max = envp_max = 64;
469 else
470 argv_max = envp_max = INT_MAX;
471
472 off = sizeof(int); /* skip 'argc' at the start of the frame */
473 first = TRUE;
474 ok = TRUE;
475 nulls = 0;
476 count = 0;
477 max = argv_max;
478
479 do {
480 chunk = sizeof(argv);
481 if (chunk > len - off)
482 chunk = len - off;
483
484 if (mem_get_data(proc->pid, addr + off, argv, chunk) != 0)
485 break;
486
487 if (first) {
488 put_open(proc, "argv", PF_NONAME, "[", ", ");
489
490 first = FALSE;
491 }
492
493 for (i = 0; i < chunk / sizeof(void *) && ok; i++) {
494 if (argv[i] == NULL) {
495 if (count > max)
496 put_tail(proc, count, max);
497 put_close(proc, "]");
498 if (nulls++ == 0) {
499 put_open(proc, "envp", PF_NONAME, "[",
500 ", ");
501 count = 0;
502 max = envp_max;
503 } else
504 break; /* two NULL pointers: done! */
505 } else if (count++ < max)
506 ok = put_frame_string(proc, addr, len,
507 (vir_bytes)argv[i]);
508 }
509
510 off += chunk;
511 } while (nulls < 2 && ok);
512
513 /*
514 * Handle failure cases, implied by not reaching the second NULL
515 * in the array. Successful completion is handled in the loop above.
516 * Note that 'ok' is not always cleared on failure, as it is used only
517 * to break out of the outer loop.
518 */
519 if (first) {
520 put_ptr(proc, "argv", addr + off);
521 put_field(proc, "envp", "&..");
522 } else if (nulls < 2) {
523 put_tail(proc, 0, 0);
524 put_close(proc, "]");
525 if (nulls < 1) {
526 put_open(proc, "envp", PF_NONAME, "[", ", ");
527 put_tail(proc, 0, 0);
528 put_close(proc, "]");
529 }
530 }
531 }
532
533 static int
pm_exec_out(struct trace_proc * proc,const message * m_out)534 pm_exec_out(struct trace_proc * proc, const message * m_out)
535 {
536
537 put_buf(proc, "path", PF_PATH, m_out->m_lc_pm_exec.name,
538 m_out->m_lc_pm_exec.namelen);
539 put_exec_frame(proc, m_out->m_lc_pm_exec.frame,
540 m_out->m_lc_pm_exec.framelen);
541
542 return CT_NORETURN;
543 }
544
545 /* The idea is that this function may one day print a human-readable time. */
546 void
put_time(struct trace_proc * proc,const char * name,time_t time)547 put_time(struct trace_proc * proc, const char * name, time_t time)
548 {
549
550 put_value(proc, name, "%"PRId64, time);
551 }
552
553 void
put_struct_timeval(struct trace_proc * proc,const char * name,int flags,vir_bytes addr)554 put_struct_timeval(struct trace_proc * proc, const char * name, int flags,
555 vir_bytes addr)
556 {
557 struct timeval tv;
558
559 /* No field names; they just make things harder to read. */
560 if (!put_open_struct(proc, name, flags | PF_NONAME, addr, &tv,
561 sizeof(tv)))
562 return;
563
564 if (flags & PF_ALT)
565 put_time(proc, "tv_sec", tv.tv_sec);
566 else
567 put_value(proc, "tv_sec", "%"PRId64, tv.tv_sec);
568 put_value(proc, "tv_usec", "%d", tv.tv_usec);
569
570 put_close_struct(proc, TRUE /*all*/);
571 }
572
573 static void
put_struct_itimerval(struct trace_proc * proc,const char * name,int flags,vir_bytes addr)574 put_struct_itimerval(struct trace_proc * proc, const char * name, int flags,
575 vir_bytes addr)
576 {
577 struct itimerval it;
578
579 /*
580 * This used to pass PF_NONAME, but the layout may not be clear enough
581 * without names. It does turn simple alarm(1) calls into rather
582 * lengthy output, though.
583 */
584 if (!put_open_struct(proc, name, flags, addr, &it, sizeof(it)))
585 return;
586
587 put_struct_timeval(proc, "it_interval", PF_LOCADDR,
588 (vir_bytes)&it.it_interval);
589 put_struct_timeval(proc, "it_value", PF_LOCADDR,
590 (vir_bytes)&it.it_value);
591
592 put_close_struct(proc, TRUE /*all*/);
593 }
594
595 static void
put_itimer_which(struct trace_proc * proc,const char * name,int which)596 put_itimer_which(struct trace_proc * proc, const char * name, int which)
597 {
598 const char *text = NULL;
599
600 if (!valuesonly) {
601 switch (which) {
602 TEXT(ITIMER_REAL);
603 TEXT(ITIMER_VIRTUAL);
604 TEXT(ITIMER_PROF);
605 TEXT(ITIMER_MONOTONIC);
606 }
607 }
608
609 if (text != NULL)
610 put_field(proc, name, text);
611 else
612 put_value(proc, name, "%d", which);
613 }
614
615 static const char *
pm_itimer_name(const message * m_out)616 pm_itimer_name(const message * m_out)
617 {
618
619 return (m_out->m_lc_pm_itimer.value != 0) ? "setitimer" : "getitimer";
620 }
621
622 static int
pm_itimer_out(struct trace_proc * proc,const message * m_out)623 pm_itimer_out(struct trace_proc * proc, const message * m_out)
624 {
625
626 put_itimer_which(proc, "which", m_out->m_lc_pm_itimer.which);
627 if (m_out->m_lc_pm_itimer.value != 0) {
628 put_struct_itimerval(proc, "value", 0,
629 m_out->m_lc_pm_itimer.value);
630
631 /*
632 * If there will be no old values to print, finish the call
633 * now. For setitimer only; getitimer may not pass NULL.
634 */
635 if (m_out->m_lc_pm_itimer.ovalue == 0) {
636 put_ptr(proc, "ovalue", 0);
637
638 return CT_DONE;
639 }
640 }
641
642 return CT_NOTDONE;
643 }
644
645 static void
pm_itimer_in(struct trace_proc * proc,const message * m_out,const message * __unused m_in,int failed)646 pm_itimer_in(struct trace_proc * proc, const message * m_out,
647 const message * __unused m_in, int failed)
648 {
649
650 if (m_out->m_lc_pm_itimer.value == 0 ||
651 m_out->m_lc_pm_itimer.ovalue != 0) {
652 put_struct_itimerval(proc,
653 (m_out->m_lc_pm_itimer.value != 0) ? "ovalue" : "value",
654 failed, m_out->m_lc_pm_itimer.ovalue);
655 put_equals(proc);
656 }
657 put_result(proc);
658 }
659
660 static void
put_struct_mcontext(struct trace_proc * proc,const char * name,int flags,vir_bytes addr)661 put_struct_mcontext(struct trace_proc * proc, const char * name, int flags,
662 vir_bytes addr)
663 {
664 mcontext_t ctx;
665
666 if (!put_open_struct(proc, name, flags, addr, &ctx, sizeof(ctx)))
667 return;
668
669 /*
670 * TODO: print actual fields. Then again, the ones that are saved and
671 * restored (FPU state) are hardly interesting enough to print..
672 */
673
674 put_close_struct(proc, FALSE /*all*/);
675 }
676
677 static int
pm_getmcontext_out(struct trace_proc * proc,const message * m_out)678 pm_getmcontext_out(struct trace_proc * proc, const message * m_out)
679 {
680
681 return CT_NOTDONE;
682 }
683
684 static void
pm_getmcontext_in(struct trace_proc * proc,const message * m_out,const message * m_in,int failed)685 pm_getmcontext_in(struct trace_proc * proc, const message * m_out,
686 const message * m_in, int failed)
687 {
688
689 put_struct_mcontext(proc, "mcp", failed, m_out->m_lc_pm_mcontext.ctx);
690 put_equals(proc);
691 put_result(proc);
692 }
693
694 static int
pm_setmcontext_out(struct trace_proc * proc,const message * m_out)695 pm_setmcontext_out(struct trace_proc * proc, const message * m_out)
696 {
697
698 put_struct_mcontext(proc, "mcp", 0, m_out->m_lc_pm_mcontext.ctx);
699
700 return CT_DONE;
701 }
702
703 static void
put_sigset(struct trace_proc * proc,const char * name,sigset_t set)704 put_sigset(struct trace_proc * proc, const char * name, sigset_t set)
705 {
706 const char *signame;
707 unsigned int count, unknown;
708 int sig, invert;
709
710 /*
711 * First decide whether we should print a normal or an inverted mask.
712 * Unfortunately, depending on the place, a filled set may or may not
713 * have bits outside the 1..NSIG range set. Therefore, we ignore the
714 * bits outside this range entirely, and use simple heuristics to
715 * decide whether to show an inverted set. If we know all the signal
716 * names for either set and not the other, show that one; otherwise,
717 * show an inverted mask if at least 3/4th of the bits are set.
718 */
719 count = 0;
720 unknown = 0;
721 for (sig = 1; sig < NSIG; sig++) {
722 if (sigismember(&set, sig))
723 count++;
724 if (get_signal_name(sig) == NULL)
725 unknown |= 1 << !!sigismember(&set, sig);
726 }
727 if (unknown == 1 /*for unset bit*/ || unknown == 2 /*for set bit*/)
728 invert = unknown - 1;
729 else
730 invert = (count >= (NSIG - 1) * 3 / 4);
731
732 put_open(proc, name, PF_NONAME, invert ? "~[" : "[", " ");
733
734 for (sig = 1; sig < NSIG; sig++) {
735 /* Note that sigismember() may not strictly return 0 or 1.. */
736 if (!sigismember(&set, sig) != invert)
737 continue;
738
739 if ((signame = get_signal_name(sig)) != NULL) {
740 /* Skip the "SIG" prefix for brevity. */
741 if (!strncmp(signame, "SIG", 3))
742 put_field(proc, NULL, &signame[3]);
743 else
744 put_field(proc, NULL, signame);
745 } else
746 put_value(proc, NULL, "%d", sig);
747 }
748
749 put_close(proc, "]");
750 }
751
752 static const struct flags sa_flags[] = {
753 FLAG(SA_ONSTACK),
754 FLAG(SA_RESTART),
755 FLAG(SA_RESETHAND),
756 FLAG(SA_NODEFER),
757 FLAG(SA_NOCLDSTOP),
758 FLAG(SA_NOCLDWAIT),
759 #ifdef SA_SIGINFO
760 FLAG(SA_SIGINFO),
761 #endif
762 FLAG(SA_NOKERNINFO)
763 };
764
765 static void
put_sa_handler(struct trace_proc * proc,const char * name,vir_bytes handler)766 put_sa_handler(struct trace_proc * proc, const char * name, vir_bytes handler)
767 {
768 const char *text = NULL;
769
770 if (!valuesonly) {
771 switch ((int)handler) {
772 case (int)SIG_DFL: text = "SIG_DFL"; break;
773 case (int)SIG_IGN: text = "SIG_IGN"; break;
774 case (int)SIG_HOLD: text = "SIG_HOLD"; break;
775 }
776 }
777
778 if (text != NULL)
779 put_field(proc, name, text);
780 else
781 put_ptr(proc, name, handler);
782 }
783
784 static void
put_struct_sigaction(struct trace_proc * proc,const char * name,int flags,vir_bytes addr)785 put_struct_sigaction(struct trace_proc * proc, const char * name, int flags,
786 vir_bytes addr)
787 {
788 struct sigaction sa;
789
790 if (!put_open_struct(proc, name, flags, addr, &sa, sizeof(sa)))
791 return;
792
793 put_sa_handler(proc, "sa_handler", (vir_bytes)sa.sa_handler);
794
795 if (verbose > 1)
796 put_sigset(proc, "sa_mask", sa.sa_mask);
797
798 /* A somewhat lame attempt to reduce noise a bit. */
799 if ((sa.sa_flags & ~(SA_ONSTACK | SA_RESTART | SA_RESETHAND |
800 SA_NODEFER)) != 0 || sa.sa_handler != SIG_DFL || verbose > 0)
801 put_flags(proc, "sa_flags", sa_flags, COUNT(sa_flags), "0x%x",
802 sa.sa_flags);
803
804 put_close_struct(proc, verbose > 1);
805 }
806
807 static int
pm_sigaction_out(struct trace_proc * proc,const message * m_out)808 pm_sigaction_out(struct trace_proc * proc, const message * m_out)
809 {
810
811 put_signal(proc, "signal", m_out->m_lc_pm_sig.nr);
812 put_struct_sigaction(proc, "act", 0, m_out->m_lc_pm_sig.act);
813
814 /* If there will be no old values to print, finish the call now. */
815 if (m_out->m_lc_pm_sig.oact == 0) {
816 put_ptr(proc, "oact", 0);
817 return CT_DONE;
818 } else
819 return CT_NOTDONE;
820 }
821
822 static void
pm_sigaction_in(struct trace_proc * proc,const message * m_out,const message * __unused m_in,int failed)823 pm_sigaction_in(struct trace_proc * proc, const message * m_out,
824 const message * __unused m_in, int failed)
825 {
826
827 if (m_out->m_lc_pm_sig.oact != 0) {
828 put_struct_sigaction(proc, "oact", failed,
829 m_out->m_lc_pm_sig.oact);
830 put_equals(proc);
831 }
832 put_result(proc);
833 }
834
835 static int
pm_sigsuspend_out(struct trace_proc * proc,const message * m_out)836 pm_sigsuspend_out(struct trace_proc * proc, const message * m_out)
837 {
838
839 put_sigset(proc, "set", m_out->m_lc_pm_sigset.set);
840
841 return CT_DONE;
842 }
843
844 static int
pm_sigpending_out(struct trace_proc * __unused proc,const message * __unused m_out)845 pm_sigpending_out(struct trace_proc * __unused proc,
846 const message * __unused m_out)
847 {
848
849 return CT_NOTDONE;
850 }
851
852 static void
pm_sigpending_in(struct trace_proc * proc,const message * __unused m_out,const message * m_in,int failed)853 pm_sigpending_in(struct trace_proc * proc, const message * __unused m_out,
854 const message * m_in, int failed)
855 {
856
857 if (!failed)
858 put_sigset(proc, "set", m_in->m_pm_lc_sigset.set);
859 else
860 put_field(proc, "set", "&..");
861 put_equals(proc);
862 put_result(proc);
863 }
864
865 static void
put_sigprocmask_how(struct trace_proc * proc,const char * name,int how)866 put_sigprocmask_how(struct trace_proc * proc, const char * name, int how)
867 {
868 const char *text = NULL;
869
870 if (!valuesonly) {
871 switch (how) {
872 case SIG_INQUIRE: /* pseudocode, print something else */
873 TEXT(SIG_BLOCK);
874 TEXT(SIG_UNBLOCK);
875 TEXT(SIG_SETMASK);
876 }
877 }
878
879 if (text != NULL)
880 put_field(proc, name, text);
881 else
882 put_value(proc, name, "%d", how);
883 }
884
885 static int
pm_sigprocmask_out(struct trace_proc * proc,const message * m_out)886 pm_sigprocmask_out(struct trace_proc * proc, const message * m_out)
887 {
888
889 put_sigprocmask_how(proc, "how", m_out->m_lc_pm_sigset.how);
890 if (m_out->m_lc_pm_sigset.how == SIG_INQUIRE)
891 put_ptr(proc, "set", 0);
892 else
893 put_sigset(proc, "set", m_out->m_lc_pm_sigset.set);
894
895 return CT_NOTDONE;
896 }
897
898 static void
pm_sigprocmask_in(struct trace_proc * proc,const message * __unused m_out,const message * m_in,int failed)899 pm_sigprocmask_in(struct trace_proc * proc, const message * __unused m_out,
900 const message * m_in, int failed)
901 {
902
903 if (!failed)
904 put_sigset(proc, "oset", m_in->m_pm_lc_sigset.set);
905 else
906 put_field(proc, "oset", "&..");
907 put_equals(proc);
908 put_result(proc);
909 }
910
911 static int
pm_sigreturn_out(struct trace_proc * proc,const message * m_out)912 pm_sigreturn_out(struct trace_proc * proc, const message * m_out)
913 {
914 struct sigcontext scp;
915
916 if (put_open_struct(proc, "scp", 0, m_out->m_lc_pm_sigset.ctx, &scp,
917 sizeof(scp))) {
918 if (verbose == 1) {
919 #if defined(__i386__)
920 put_ptr(proc, "sc_eip", scp.sc_eip);
921 put_ptr(proc, "sc_esp", scp.sc_esp);
922 #elif defined(__arm__)
923 put_ptr(proc, "sc_pc", scp.sc_pc);
924 put_ptr(proc, "sc_usr_sp", scp.sc_usr_sp);
925 #endif
926 }
927
928 /*
929 * We deliberately print the signal set from the message rather
930 * than from the structure, since in theory they may be
931 * different and PM uses the one from the message only.
932 */
933 put_sigset(proc, "sc_mask", m_out->m_lc_pm_sigset.set);
934
935 /*
936 * TODO: print some other fields, although it is probably not
937 * useful to print all registers even with verbose > 1?
938 */
939 put_close_struct(proc, FALSE /*all*/);
940 }
941
942 return CT_NORETURN;
943 }
944
945 static void
pm_sigreturn_in(struct trace_proc * proc,const message * __unused m_out,const message * __unused m_in,int failed)946 pm_sigreturn_in(struct trace_proc * proc, const message * __unused m_out,
947 const message * __unused m_in, int failed)
948 {
949
950 if (failed) {
951 put_equals(proc);
952 put_result(proc);
953 }
954 }
955
956 static void
put_priority_which(struct trace_proc * proc,const char * name,int which)957 put_priority_which(struct trace_proc * proc, const char * name, int which)
958 {
959 const char *text = NULL;
960
961 if (!valuesonly) {
962 switch (which) {
963 TEXT(PRIO_PROCESS);
964 TEXT(PRIO_PGRP);
965 TEXT(PRIO_USER);
966 }
967 }
968
969 if (text != NULL)
970 put_field(proc, name, text);
971 else
972 put_value(proc, name, "%d", which);
973 }
974
975 static int
pm_getpriority_out(struct trace_proc * proc,const message * m_out)976 pm_getpriority_out(struct trace_proc * proc, const message * m_out)
977 {
978
979 put_priority_which(proc, "which", m_out->m_lc_pm_priority.which);
980 put_value(proc, "who", "%d", m_out->m_lc_pm_priority.who);
981
982 return CT_DONE;
983 }
984
985 static void
pm_getpriority_in(struct trace_proc * proc,const message * __unused m_out,const message * m_in,int failed)986 pm_getpriority_in(struct trace_proc * proc, const message * __unused m_out,
987 const message * m_in, int failed)
988 {
989
990 if (!failed)
991 put_value(proc, NULL, "%d", m_in->m_type + PRIO_MIN);
992 else
993 put_result(proc);
994 }
995
996 static int
pm_setpriority_out(struct trace_proc * proc,const message * m_out)997 pm_setpriority_out(struct trace_proc * proc, const message * m_out)
998 {
999
1000 put_priority_which(proc, "which", m_out->m_lc_pm_priority.which);
1001 put_value(proc, "who", "%d", m_out->m_lc_pm_priority.who);
1002 put_value(proc, "prio", "%d", m_out->m_lc_pm_priority.prio);
1003
1004 return CT_DONE;
1005 }
1006
1007 static int
pm_gettimeofday_out(struct trace_proc * __unused proc,const message * __unused m_out)1008 pm_gettimeofday_out(struct trace_proc * __unused proc,
1009 const message * __unused m_out)
1010 {
1011
1012 return CT_NOTDONE;
1013 }
1014
1015 static void
put_timespec_as_timeval(struct trace_proc * proc,const char * name,time_t sec,long nsec)1016 put_timespec_as_timeval(struct trace_proc * proc, const char * name,
1017 time_t sec, long nsec)
1018 {
1019
1020 /* No field names within the structure. */
1021 put_open(proc, name, PF_NONAME, "{", ", ");
1022
1023 put_time(proc, "tv_sec", sec);
1024 put_value(proc, "tv_usec", "%ld", nsec / 1000);
1025
1026 put_close(proc, "}");
1027 }
1028
1029 static void
pm_gettimeofday_in(struct trace_proc * proc,const message * __unused m_out,const message * m_in,int failed)1030 pm_gettimeofday_in(struct trace_proc * proc, const message * __unused m_out,
1031 const message * m_in, int failed)
1032 {
1033
1034 if (!failed) {
1035 /*
1036 * The system call returns values which do not match the call
1037 * being made, so just like libc, we have to correct..
1038 */
1039 put_timespec_as_timeval(proc, "tp", m_in->m_pm_lc_time.sec,
1040 m_in->m_pm_lc_time.nsec);
1041 } else
1042 put_field(proc, "tp", "&..");
1043 put_ptr(proc, "tzp", 0); /* not part of the system call (yet) */
1044
1045 put_equals(proc);
1046 put_result(proc);
1047 }
1048
1049 static int
pm_getsid_out(struct trace_proc * proc,const message * m_out)1050 pm_getsid_out(struct trace_proc * proc, const message * m_out)
1051 {
1052
1053 put_value(proc, "pid", "%d", m_out->m_lc_pm_getsid.pid);
1054
1055 return CT_DONE;
1056 }
1057
1058 static void
put_clockid(struct trace_proc * proc,const char * name,clockid_t clock_id)1059 put_clockid(struct trace_proc * proc, const char * name, clockid_t clock_id)
1060 {
1061 const char *text = NULL;
1062
1063 if (!valuesonly) {
1064 switch (clock_id) {
1065 TEXT(CLOCK_REALTIME);
1066 #ifdef CLOCK_VIRTUAL
1067 TEXT(CLOCK_VIRTUAL);
1068 #endif
1069 #ifdef CLOCK_PROF
1070 TEXT(CLOCK_PROF);
1071 #endif
1072 TEXT(CLOCK_MONOTONIC);
1073 }
1074 }
1075
1076 if (text != NULL)
1077 put_field(proc, name, text);
1078 else
1079 put_value(proc, name, "%d", clock_id);
1080 }
1081
1082 static void
put_clock_timespec(struct trace_proc * proc,const char * name,int flags,time_t sec,long nsec)1083 put_clock_timespec(struct trace_proc * proc, const char * name, int flags,
1084 time_t sec, long nsec)
1085 {
1086
1087 if (flags & PF_FAILED) {
1088 put_field(proc, name, "&..");
1089
1090 return;
1091 }
1092
1093 /* No field names within the structure. */
1094 put_open(proc, name, PF_NONAME, "{", ", ");
1095
1096 if (flags & PF_ALT)
1097 put_time(proc, "tv_sec", sec);
1098 else
1099 put_value(proc, "tv_sec", "%"PRId64, sec);
1100 put_value(proc, "tv_nsec", "%ld", nsec);
1101
1102 put_close(proc, "}");
1103 }
1104
1105 /* This function is shared between clock_getres and clock_gettime. */
1106 static int
pm_clock_get_out(struct trace_proc * proc,const message * m_out)1107 pm_clock_get_out(struct trace_proc * proc, const message * m_out)
1108 {
1109
1110 put_clockid(proc, "clock_id", m_out->m_lc_pm_time.clk_id);
1111
1112 return CT_NOTDONE;
1113 }
1114
1115 static void
pm_clock_getres_in(struct trace_proc * proc,const message * __unused m_out,const message * m_in,int failed)1116 pm_clock_getres_in(struct trace_proc * proc, const message * __unused m_out,
1117 const message * m_in, int failed)
1118 {
1119
1120 put_clock_timespec(proc, "res", failed, m_in->m_pm_lc_time.sec,
1121 m_in->m_pm_lc_time.nsec);
1122 put_equals(proc);
1123 put_result(proc);
1124 }
1125
1126 /*
1127 * Same as pm_clock_getres_in, but different field name and the option to print
1128 * at least some results as time strings (in the future).
1129 */
1130 static void
pm_clock_gettime_in(struct trace_proc * proc,const message * m_out,const message * m_in,int failed)1131 pm_clock_gettime_in(struct trace_proc * proc, const message * m_out,
1132 const message * m_in, int failed)
1133 {
1134 int flags;
1135
1136 flags = failed;
1137 if (m_out->m_lc_pm_time.clk_id == CLOCK_REALTIME)
1138 flags |= PF_ALT; /* TODO: make this print a time string. */
1139
1140 put_clock_timespec(proc, "tp", flags, m_in->m_pm_lc_time.sec,
1141 m_in->m_pm_lc_time.nsec);
1142 put_equals(proc);
1143 put_result(proc);
1144 }
1145
1146 static const char *
pm_clock_settime_name(const message * m_out)1147 pm_clock_settime_name(const message * m_out)
1148 {
1149
1150 if (m_out->m_lc_pm_time.now == 0)
1151 return "adjtime";
1152 else
1153 return "clock_settime";
1154 }
1155
1156 static int
pm_clock_settime_out(struct trace_proc * proc,const message * m_out)1157 pm_clock_settime_out(struct trace_proc * proc, const message * m_out)
1158 {
1159 int flags;
1160
1161 /* These two calls just look completely different.. */
1162 if (m_out->m_lc_pm_time.now == 0) {
1163 put_timespec_as_timeval(proc, "delta", m_out->m_lc_pm_time.sec,
1164 m_out->m_lc_pm_time.nsec);
1165 put_ptr(proc, "odelta", 0); /* not supported on MINIX3 */
1166 } else {
1167 flags = 0;
1168 if (m_out->m_lc_pm_time.clk_id == CLOCK_REALTIME)
1169 flags |= PF_ALT;
1170 put_clockid(proc, "clock_id", m_out->m_lc_pm_time.clk_id);
1171 put_clock_timespec(proc, "tp", flags, m_out->m_lc_pm_time.sec,
1172 m_out->m_lc_pm_time.nsec);
1173 }
1174
1175 return CT_DONE;
1176 }
1177
1178 static int
pm_getrusage_out(struct trace_proc * proc,const message * m_out)1179 pm_getrusage_out(struct trace_proc * proc, const message * m_out)
1180 {
1181
1182 if (!valuesonly && m_out->m_lc_pm_rusage.who == RUSAGE_SELF)
1183 put_field(proc, "who", "RUSAGE_SELF");
1184 else if (!valuesonly && m_out->m_lc_pm_rusage.who == RUSAGE_CHILDREN)
1185 put_field(proc, "who", "RUSAGE_CHILDREN");
1186 else
1187 put_value(proc, "who", "%d", m_out->m_lc_pm_rusage.who);
1188
1189 return CT_NOTDONE;
1190 }
1191
1192 static void
pm_getrusage_in(struct trace_proc * proc,const message * m_out,const message * __unused m_in,int failed)1193 pm_getrusage_in(struct trace_proc * proc, const message * m_out,
1194 const message * __unused m_in, int failed)
1195 {
1196
1197 put_struct_rusage(proc, "rusage", failed, m_out->m_lc_pm_rusage.addr);
1198 put_equals(proc);
1199 put_result(proc);
1200 }
1201
1202 static const struct flags reboot_flags[] = {
1203 FLAG_ZERO(RB_AUTOBOOT),
1204 FLAG(RB_ASKNAME),
1205 FLAG(RB_DUMP),
1206 FLAG_MASK(RB_POWERDOWN, RB_HALT),
1207 FLAG(RB_POWERDOWN),
1208 FLAG(RB_INITNAME),
1209 FLAG(RB_KDB),
1210 FLAG(RB_NOSYNC),
1211 FLAG(RB_RDONLY),
1212 FLAG(RB_SINGLE),
1213 FLAG(RB_STRING),
1214 FLAG(RB_USERCONF),
1215 };
1216
1217 static int
pm_reboot_out(struct trace_proc * proc,const message * m_out)1218 pm_reboot_out(struct trace_proc * proc, const message * m_out)
1219 {
1220
1221 put_flags(proc, "how", reboot_flags, COUNT(reboot_flags), "0x%x",
1222 m_out->m_lc_pm_reboot.how);
1223 put_ptr(proc, "bootstr", 0); /* not supported on MINIX3 */
1224
1225 return CT_DONE;
1226 }
1227
1228 static int
pm_svrctl_out(struct trace_proc * proc,const message * m_out)1229 pm_svrctl_out(struct trace_proc * proc, const message * m_out)
1230 {
1231
1232 put_ioctl_req(proc, "request", m_out->m_lc_svrctl.request,
1233 TRUE /*is_svrctl*/);
1234 return put_ioctl_arg_out(proc, "arg", m_out->m_lc_svrctl.request,
1235 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/);
1236 }
1237
1238 static void
pm_svrctl_in(struct trace_proc * proc,const message * m_out,const message * __unused m_in,int failed)1239 pm_svrctl_in(struct trace_proc * proc, const message * m_out,
1240 const message * __unused m_in, int failed)
1241 {
1242
1243 put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_svrctl.request,
1244 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/);
1245 }
1246
1247 static int
pm_sprof_out(struct trace_proc * proc,const message * m_out)1248 pm_sprof_out(struct trace_proc * proc, const message * m_out)
1249 {
1250 int freq;
1251
1252 if (!valuesonly && m_out->m_lc_pm_sprof.action == PROF_START)
1253 put_field(proc, "action", "PROF_START");
1254 else if (!valuesonly && m_out->m_lc_pm_sprof.action == PROF_STOP)
1255 put_field(proc, "action", "PROF_STOP");
1256 else
1257 put_value(proc, "action", "%d", m_out->m_lc_pm_sprof.action);
1258
1259 put_value(proc, "size", "%zu", m_out->m_lc_pm_sprof.mem_size);
1260
1261 freq = m_out->m_lc_pm_sprof.freq;
1262 if (!valuesonly && freq >= 3 && freq <= 15) /* no constants.. */
1263 put_value(proc, "freq", "%u /*%uHz*/", freq, 1 << (16 - freq));
1264 else
1265 put_value(proc, "freq", "%u", freq);
1266
1267 if (!valuesonly && m_out->m_lc_pm_sprof.intr_type == PROF_RTC)
1268 put_field(proc, "type", "PROF_RTC");
1269 else if (!valuesonly && m_out->m_lc_pm_sprof.intr_type == PROF_NMI)
1270 put_field(proc, "type", "PROF_NMI");
1271 else
1272 put_value(proc, "type", "%d", m_out->m_lc_pm_sprof.intr_type);
1273
1274 put_ptr(proc, "ctl_ptr", m_out->m_lc_pm_sprof.ctl_ptr);
1275 put_ptr(proc, "mem_ptr", m_out->m_lc_pm_sprof.mem_ptr);
1276
1277 return CT_DONE;
1278 }
1279
1280 #define PM_CALL(c) [((PM_ ## c) - PM_BASE)]
1281
1282 static const struct call_handler pm_map[] = {
1283 PM_CALL(EXIT) = HANDLER("exit", pm_exit_out, default_in),
1284 PM_CALL(FORK) = HANDLER("fork", default_out, default_in),
1285 PM_CALL(WAIT4) = HANDLER("wait4", pm_wait4_out, pm_wait4_in),
1286 PM_CALL(GETPID) = HANDLER("getpid", default_out, pm_getpid_in),
1287 PM_CALL(SETUID) = HANDLER("setuid", pm_setuid_out, default_in),
1288 PM_CALL(GETUID) = HANDLER("getuid", default_out, pm_getuid_in),
1289 PM_CALL(STIME) = HANDLER("stime", pm_stime_out, default_in),
1290 PM_CALL(PTRACE) = HANDLER("ptrace", pm_ptrace_out, pm_ptrace_in),
1291 PM_CALL(SETGROUPS) = HANDLER("setgroups", pm_setgroups_out,
1292 default_in),
1293 PM_CALL(GETGROUPS) = HANDLER("getgroups", pm_getgroups_out,
1294 pm_getgroups_in),
1295 PM_CALL(KILL) = HANDLER("kill", pm_kill_out, default_in),
1296 PM_CALL(SETGID) = HANDLER("setgid", pm_setgid_out, default_in),
1297 PM_CALL(GETGID) = HANDLER("getgid", default_out, pm_getgid_in),
1298 PM_CALL(EXEC) = HANDLER("execve", pm_exec_out, default_in),
1299 PM_CALL(SETSID) = HANDLER("setsid", default_out, default_in),
1300 PM_CALL(GETPGRP) = HANDLER("getpgrp", default_out, default_in),
1301 PM_CALL(ITIMER) = HANDLER_NAME(pm_itimer_name, pm_itimer_out,
1302 pm_itimer_in),
1303 PM_CALL(GETMCONTEXT) = HANDLER("getmcontext", pm_getmcontext_out,
1304 pm_getmcontext_in),
1305 PM_CALL(SETMCONTEXT) = HANDLER("setmcontext", pm_setmcontext_out,
1306 default_in),
1307 PM_CALL(SIGACTION) = HANDLER("sigaction", pm_sigaction_out,
1308 pm_sigaction_in),
1309 PM_CALL(SIGSUSPEND) = HANDLER("sigsuspend", pm_sigsuspend_out,
1310 default_in),
1311 PM_CALL(SIGPENDING) = HANDLER("sigpending", pm_sigpending_out,
1312 pm_sigpending_in),
1313 PM_CALL(SIGPROCMASK) = HANDLER("sigprocmask", pm_sigprocmask_out,
1314 pm_sigprocmask_in),
1315 PM_CALL(SIGRETURN) = HANDLER("sigreturn", pm_sigreturn_out,
1316 pm_sigreturn_in),
1317 PM_CALL(GETPRIORITY) = HANDLER("getpriority", pm_getpriority_out,
1318 pm_getpriority_in),
1319 PM_CALL(SETPRIORITY) = HANDLER("setpriority", pm_setpriority_out,
1320 default_in),
1321 PM_CALL(GETTIMEOFDAY) = HANDLER("gettimeofday", pm_gettimeofday_out,
1322 pm_gettimeofday_in),
1323 PM_CALL(SETEUID) = HANDLER("seteuid", pm_setuid_out, default_in),
1324 PM_CALL(SETEGID) = HANDLER("setegid", pm_setgid_out, default_in),
1325 PM_CALL(ISSETUGID) = HANDLER("issetugid", default_out, default_in),
1326 PM_CALL(GETSID) = HANDLER("getsid", pm_getsid_out, default_in),
1327 PM_CALL(CLOCK_GETRES) = HANDLER("clock_getres", pm_clock_get_out,
1328 pm_clock_getres_in),
1329 PM_CALL(CLOCK_GETTIME) = HANDLER("clock_gettime", pm_clock_get_out,
1330 pm_clock_gettime_in),
1331 PM_CALL(CLOCK_SETTIME) = HANDLER_NAME(pm_clock_settime_name,
1332 pm_clock_settime_out, default_in),
1333 PM_CALL(GETRUSAGE) = HANDLER("getrusage", pm_getrusage_out,
1334 pm_getrusage_in),
1335 PM_CALL(REBOOT) = HANDLER("reboot", pm_reboot_out, default_in),
1336 PM_CALL(SVRCTL) = HANDLER("pm_svrctl", pm_svrctl_out, pm_svrctl_in),
1337 PM_CALL(SPROF) = HANDLER("sprofile", pm_sprof_out, default_in),
1338 };
1339
1340 const struct calls pm_calls = {
1341 .endpt = PM_PROC_NR,
1342 .base = PM_BASE,
1343 .map = pm_map,
1344 .count = COUNT(pm_map)
1345 };
1346