Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / usr.bin / trace / service / pm.c
blob1bbef8896f2512dc3675bf3e255a6b873a2e9a21
2 #include "inc.h"
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>
12 static int
13 pm_exit_out(struct trace_proc * proc, const message * m_out)
16 put_value(proc, "status", "%d", m_out->m_lc_pm_exit.status);
18 return CT_NORETURN;
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),
31 static void
32 put_wait4_status(struct trace_proc * proc, const char * name, int status)
34 const char *signame;
35 int sig;
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.
44 if (!valuesonly && WIFEXITED(status) &&
45 status == W_EXITCODE(WEXITSTATUS(status), 0)) {
46 put_value(proc, name, "W_EXITED(%d)",
47 WEXITSTATUS(status));
49 return;
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);
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);
62 if (WCOREDUMP(status))
63 put_text(proc, "|WCOREDUMP");
65 return;
68 if (!valuesonly && WIFSTOPPED(status) &&
69 status == W_STOPCODE(WSTOPSIG(status))) {
70 sig = WSTOPSIG(status);
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);
77 return;
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.
84 put_value(proc, name, "0x%04x", status);
87 static int
88 pm_wait4_out(struct trace_proc * proc, const message * m_out)
91 put_value(proc, "pid", "%d", m_out->m_lc_pm_wait4.pid);
93 return CT_NOTDONE;
96 static void
97 put_struct_rusage(struct trace_proc * proc, const char * name, int flags,
98 vir_bytes addr)
100 struct rusage ru;
102 if (!put_open_struct(proc, name, flags, addr, &ru, sizeof(ru)))
103 return;
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);
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);
116 put_close_struct(proc, verbose > 0);
119 static void
120 pm_wait4_in(struct trace_proc * proc, const message * m_out,
121 const message * m_in, int failed)
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.
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);
141 static void
142 pm_getpid_in(struct trace_proc * proc, const message * __unused m_out,
143 const message * m_in, int failed)
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, ")");
154 /* This function is shared between setuid and seteuid. */
155 static int
156 pm_setuid_out(struct trace_proc * proc, const message * m_out)
159 put_value(proc, "uid", "%u", m_out->m_lc_pm_setuid.uid);
161 return CT_DONE;
164 static void
165 pm_getuid_in(struct trace_proc * proc, const message * __unused m_out,
166 const message * m_in, int failed)
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, ")");
177 static int
178 pm_stime_out(struct trace_proc * proc, const message * m_out)
181 put_time(proc, "time", m_out->m_lc_pm_time.sec);
183 return CT_DONE;
186 static void
187 put_signal(struct trace_proc * proc, const char * name, int sig)
189 const char *signame;
191 if (!valuesonly && (signame = get_signal_name(sig)) != NULL)
192 put_field(proc, name, signame);
193 else
194 put_value(proc, name, "%d", sig);
197 static void
198 put_ptrace_req(struct trace_proc * proc, const char * name, int req)
200 const char *text = NULL;
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);
226 if (text != NULL)
227 put_field(proc, name, text);
228 else
229 put_value(proc, name, "%d", req);
232 static void
233 put_struct_ptrace_range(struct trace_proc * proc, const char * name, int flags,
234 vir_bytes addr)
236 struct ptrace_range pr;
238 if (!put_open_struct(proc, name, flags, addr, &pr, sizeof(pr)))
239 return;
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);
251 put_close_struct(proc, TRUE /*all*/);
254 static int
255 pm_ptrace_out(struct trace_proc * proc, const message * m_out)
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);
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;
294 return CT_DONE;
297 static void
298 pm_ptrace_in(struct trace_proc * proc, const message * m_out,
299 const message * m_in, int failed)
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;
314 put_result(proc);
317 void
318 put_groups(struct trace_proc * proc, const char * name, int flags,
319 vir_bytes addr, int count)
321 gid_t groups[NGROUPS_MAX];
322 int i;
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);
332 return;
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, "]");
341 static int
342 pm_setgroups_out(struct trace_proc * proc, const message * m_out)
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);
349 return CT_DONE;
352 static int
353 pm_getgroups_out(struct trace_proc * proc, const message * m_out)
356 put_value(proc, "ngroups", "%d", m_out->m_lc_pm_groups.num);
358 return CT_NOTDONE;
361 static void
362 pm_getgroups_in(struct trace_proc * proc, const message * m_out,
363 const message * m_in, int failed)
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);
372 static int
373 pm_kill_out(struct trace_proc * proc, const message * m_out)
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);
379 return CT_DONE;
382 /* This function is shared between setgid and setegid. */
383 static int
384 pm_setgid_out(struct trace_proc * proc, const message * m_out)
387 put_value(proc, "gid", "%u", m_out->m_lc_pm_setgid.gid);
389 return CT_DONE;
392 static void
393 pm_getgid_in(struct trace_proc * proc, const message * __unused m_out,
394 const message * m_in, int failed)
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, ")");
405 static int
406 put_frame_string(struct trace_proc * proc, vir_bytes frame, size_t len,
407 vir_bytes addr)
409 vir_bytes stacktop, offset;
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.
418 stacktop = kernel_get_stacktop();
420 if (addr >= stacktop)
421 return FALSE;
422 offset = stacktop - addr;
423 if (offset >= len)
424 return FALSE;
425 addr = frame + len - offset;
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.
436 put_buf(proc, NULL, PF_STRING, addr, len - offset);
438 return TRUE;
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.
449 static void
450 put_exec_frame(struct trace_proc * proc, vir_bytes addr, size_t len)
452 void *argv[64];
453 size_t off, chunk;
454 unsigned int i, count, max, argv_max, envp_max;
455 int first, ok, nulls;
457 if (valuesonly) {
458 put_ptr(proc, "frame", addr);
459 put_value(proc, "framelen", "%zu", len);
461 return;
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;
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;
479 do {
480 chunk = sizeof(argv);
481 if (chunk > len - off)
482 chunk = len - off;
484 if (mem_get_data(proc->pid, addr + off, argv, chunk) != 0)
485 break;
487 if (first) {
488 put_open(proc, "argv", PF_NONAME, "[", ", ");
490 first = FALSE;
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]);
510 off += chunk;
511 } while (nulls < 2 && ok);
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.
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, "]");
533 static int
534 pm_exec_out(struct trace_proc * proc, const message * m_out)
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);
542 return CT_NORETURN;
545 /* The idea is that this function may one day print a human-readable time. */
546 void
547 put_time(struct trace_proc * proc, const char * name, time_t time)
550 put_value(proc, name, "%"PRId64, time);
553 void
554 put_struct_timeval(struct trace_proc * proc, const char * name, int flags,
555 vir_bytes addr)
557 struct timeval tv;
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;
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);
570 put_close_struct(proc, TRUE /*all*/);
573 static void
574 put_struct_itimerval(struct trace_proc * proc, const char * name, int flags,
575 vir_bytes addr)
577 struct itimerval it;
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.
584 if (!put_open_struct(proc, name, flags, addr, &it, sizeof(it)))
585 return;
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);
592 put_close_struct(proc, TRUE /*all*/);
595 static void
596 put_itimer_which(struct trace_proc * proc, const char * name, int which)
598 const char *text = NULL;
600 if (!valuesonly) {
601 switch (which) {
602 TEXT(ITIMER_REAL);
603 TEXT(ITIMER_VIRTUAL);
604 TEXT(ITIMER_PROF);
605 TEXT(ITIMER_MONOTONIC);
609 if (text != NULL)
610 put_field(proc, name, text);
611 else
612 put_value(proc, name, "%d", which);
615 static const char *
616 pm_itimer_name(const message * m_out)
619 return (m_out->m_lc_pm_itimer.value != 0) ? "setitimer" : "getitimer";
622 static int
623 pm_itimer_out(struct trace_proc * proc, const message * m_out)
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);
632 * If there will be no old values to print, finish the call
633 * now. For setitimer only; getitimer may not pass NULL.
635 if (m_out->m_lc_pm_itimer.ovalue == 0) {
636 put_ptr(proc, "ovalue", 0);
638 return CT_DONE;
642 return CT_NOTDONE;
645 static void
646 pm_itimer_in(struct trace_proc * proc, const message * m_out,
647 const message * __unused m_in, int failed)
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);
657 put_result(proc);
660 static void
661 put_struct_mcontext(struct trace_proc * proc, const char * name, int flags,
662 vir_bytes addr)
664 mcontext_t ctx;
666 if (!put_open_struct(proc, name, flags, addr, &ctx, sizeof(ctx)))
667 return;
670 * TODO: print actual fields. Then again, the ones that are saved and
671 * restored (FPU state) are hardly interesting enough to print..
674 put_close_struct(proc, FALSE /*all*/);
677 static int
678 pm_getmcontext_out(struct trace_proc * proc, const message * m_out)
681 return CT_NOTDONE;
684 static void
685 pm_getmcontext_in(struct trace_proc * proc, const message * m_out,
686 const message * m_in, int failed)
689 put_struct_mcontext(proc, "mcp", failed, m_out->m_lc_pm_mcontext.ctx);
690 put_equals(proc);
691 put_result(proc);
694 static int
695 pm_setmcontext_out(struct trace_proc * proc, const message * m_out)
698 put_struct_mcontext(proc, "mcp", 0, m_out->m_lc_pm_mcontext.ctx);
700 return CT_DONE;
703 static void
704 put_sigset(struct trace_proc * proc, const char * name, sigset_t set)
706 const char *signame;
707 unsigned int count, unknown;
708 int sig, invert;
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.
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);
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);
732 put_open(proc, name, PF_NONAME, invert ? "~[" : "[", " ");
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;
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);
749 put_close(proc, "]");
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)
765 static void
766 put_sa_handler(struct trace_proc * proc, const char * name, vir_bytes handler)
768 const char *text = NULL;
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;
778 if (text != NULL)
779 put_field(proc, name, text);
780 else
781 put_ptr(proc, name, handler);
784 static void
785 put_struct_sigaction(struct trace_proc * proc, const char * name, int flags,
786 vir_bytes addr)
788 struct sigaction sa;
790 if (!put_open_struct(proc, name, flags, addr, &sa, sizeof(sa)))
791 return;
793 put_sa_handler(proc, "sa_handler", (vir_bytes)sa.sa_handler);
795 if (verbose > 1)
796 put_sigset(proc, "sa_mask", sa.sa_mask);
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);
804 put_close_struct(proc, verbose > 1);
807 static int
808 pm_sigaction_out(struct trace_proc * proc, const message * m_out)
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);
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;
822 static void
823 pm_sigaction_in(struct trace_proc * proc, const message * m_out,
824 const message * __unused m_in, int failed)
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);
832 put_result(proc);
835 static int
836 pm_sigsuspend_out(struct trace_proc * proc, const message * m_out)
839 put_sigset(proc, "set", m_out->m_lc_pm_sigset.set);
841 return CT_DONE;
844 static int
845 pm_sigpending_out(struct trace_proc * __unused proc,
846 const message * __unused m_out)
849 return CT_NOTDONE;
852 static void
853 pm_sigpending_in(struct trace_proc * proc, const message * __unused m_out,
854 const message * m_in, int failed)
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);
865 static void
866 put_sigprocmask_how(struct trace_proc * proc, const char * name, int how)
868 const char *text = NULL;
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);
879 if (text != NULL)
880 put_field(proc, name, text);
881 else
882 put_value(proc, name, "%d", how);
885 static int
886 pm_sigprocmask_out(struct trace_proc * proc, const message * m_out)
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);
895 return CT_NOTDONE;
898 static void
899 pm_sigprocmask_in(struct trace_proc * proc, const message * __unused m_out,
900 const message * m_in, int failed)
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);
911 static int
912 pm_sigreturn_out(struct trace_proc * proc, const message * m_out)
914 struct sigcontext scp;
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
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.
933 put_sigset(proc, "sc_mask", m_out->m_lc_pm_sigset.set);
936 * TODO: print some other fields, although it is probably not
937 * useful to print all registers even with verbose > 1?
939 put_close_struct(proc, FALSE /*all*/);
942 return CT_NORETURN;
945 static void
946 pm_sigreturn_in(struct trace_proc * proc, const message * __unused m_out,
947 const message * __unused m_in, int failed)
950 if (failed) {
951 put_equals(proc);
952 put_result(proc);
956 static void
957 put_priority_which(struct trace_proc * proc, const char * name, int which)
959 const char *text = NULL;
961 if (!valuesonly) {
962 switch (which) {
963 TEXT(PRIO_PROCESS);
964 TEXT(PRIO_PGRP);
965 TEXT(PRIO_USER);
969 if (text != NULL)
970 put_field(proc, name, text);
971 else
972 put_value(proc, name, "%d", which);
975 static int
976 pm_getpriority_out(struct trace_proc * proc, const message * m_out)
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);
982 return CT_DONE;
985 static void
986 pm_getpriority_in(struct trace_proc * proc, const message * __unused m_out,
987 const message * m_in, int failed)
990 if (!failed)
991 put_value(proc, NULL, "%d", m_in->m_type + PRIO_MIN);
992 else
993 put_result(proc);
996 static int
997 pm_setpriority_out(struct trace_proc * proc, const message * m_out)
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);
1004 return CT_DONE;
1007 static int
1008 pm_gettimeofday_out(struct trace_proc * __unused proc,
1009 const message * __unused m_out)
1012 return CT_NOTDONE;
1015 static void
1016 put_timespec_as_timeval(struct trace_proc * proc, const char * name,
1017 time_t sec, long nsec)
1020 /* No field names within the structure. */
1021 put_open(proc, name, PF_NONAME, "{", ", ");
1023 put_time(proc, "tv_sec", sec);
1024 put_value(proc, "tv_usec", "%ld", nsec / 1000);
1026 put_close(proc, "}");
1029 static void
1030 pm_gettimeofday_in(struct trace_proc * proc, const message * __unused m_out,
1031 const message * m_in, int failed)
1034 if (!failed) {
1036 * The system call returns values which do not match the call
1037 * being made, so just like libc, we have to correct..
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) */
1045 put_equals(proc);
1046 put_result(proc);
1049 static int
1050 pm_getsid_out(struct trace_proc * proc, const message * m_out)
1053 put_value(proc, "pid", "%d", m_out->m_lc_pm_getsid.pid);
1055 return CT_DONE;
1058 static void
1059 put_clockid(struct trace_proc * proc, const char * name, clockid_t clock_id)
1061 const char *text = NULL;
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);
1076 if (text != NULL)
1077 put_field(proc, name, text);
1078 else
1079 put_value(proc, name, "%d", clock_id);
1082 static void
1083 put_clock_timespec(struct trace_proc * proc, const char * name, int flags,
1084 time_t sec, long nsec)
1087 if (flags & PF_FAILED) {
1088 put_field(proc, name, "&..");
1090 return;
1093 /* No field names within the structure. */
1094 put_open(proc, name, PF_NONAME, "{", ", ");
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);
1102 put_close(proc, "}");
1105 /* This function is shared between clock_getres and clock_gettime. */
1106 static int
1107 pm_clock_get_out(struct trace_proc * proc, const message * m_out)
1110 put_clockid(proc, "clock_id", m_out->m_lc_pm_time.clk_id);
1112 return CT_NOTDONE;
1115 static void
1116 pm_clock_getres_in(struct trace_proc * proc, const message * __unused m_out,
1117 const message * m_in, int failed)
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);
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).
1130 static void
1131 pm_clock_gettime_in(struct trace_proc * proc, const message * m_out,
1132 const message * m_in, int failed)
1134 int flags;
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. */
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);
1146 static const char *
1147 pm_clock_settime_name(const message * m_out)
1150 if (m_out->m_lc_pm_time.now == 0)
1151 return "adjtime";
1152 else
1153 return "clock_settime";
1156 static int
1157 pm_clock_settime_out(struct trace_proc * proc, const message * m_out)
1159 int flags;
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);
1175 return CT_DONE;
1178 static int
1179 pm_getrusage_out(struct trace_proc * proc, const message * m_out)
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);
1189 return CT_NOTDONE;
1192 static void
1193 pm_getrusage_in(struct trace_proc * proc, const message * m_out,
1194 const message * __unused m_in, int failed)
1197 put_struct_rusage(proc, "rusage", failed, m_out->m_lc_pm_rusage.addr);
1198 put_equals(proc);
1199 put_result(proc);
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),
1217 static int
1218 pm_reboot_out(struct trace_proc * proc, const message * m_out)
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 */
1225 return CT_DONE;
1228 static int
1229 pm_svrctl_out(struct trace_proc * proc, const message * m_out)
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*/);
1238 static void
1239 pm_svrctl_in(struct trace_proc * proc, const message * m_out,
1240 const message * __unused m_in, int failed)
1243 put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_svrctl.request,
1244 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/);
1247 static int
1248 pm_sprof_out(struct trace_proc * proc, const message * m_out)
1250 int freq;
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);
1259 put_value(proc, "size", "%zu", m_out->m_lc_pm_sprof.mem_size);
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);
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);
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);
1277 return CT_DONE;
1280 #define PM_CALL(c) [((PM_ ## c) - PM_BASE)]
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),
1340 const struct calls pm_calls = {
1341 .endpt = PM_PROC_NR,
1342 .base = PM_BASE,
1343 .map = pm_map,
1344 .count = COUNT(pm_map)