xref: /minix/minix/usr.bin/trace/service/pm.c (revision e1cdaee1)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
678 pm_getmcontext_out(struct trace_proc * proc, const message * m_out)
679 {
680 
681 	return CT_NOTDONE;
682 }
683 
684 static void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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