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_sysuname_field(struct trace_proc * proc, const char * name, int field) 958 { 959 const char *text = NULL; 960 961 if (!valuesonly) { 962 switch (field) { 963 TEXT(_UTS_ARCH); 964 TEXT(_UTS_KERNEL); 965 TEXT(_UTS_MACHINE); 966 TEXT(_UTS_HOSTNAME); 967 TEXT(_UTS_NODENAME); 968 TEXT(_UTS_RELEASE); 969 TEXT(_UTS_VERSION); 970 TEXT(_UTS_SYSNAME); 971 TEXT(_UTS_BUS); 972 } 973 } 974 975 if (text != NULL) 976 put_field(proc, name, text); 977 else 978 put_value(proc, name, "%d", field); 979 } 980 981 static int 982 pm_sysuname_out(struct trace_proc * proc, const message * m_out) 983 { 984 985 if (!valuesonly && m_out->m_lc_pm_sysuname.req == _UTS_GET) 986 put_field(proc, "req", "_UTS_GET"); 987 else if (!valuesonly && m_out->m_lc_pm_sysuname.req == _UTS_SET) 988 put_field(proc, "req", "_UTS_SET"); 989 else 990 put_value(proc, "req", "%d", m_out->m_lc_pm_sysuname.req); 991 put_sysuname_field(proc, "field", m_out->m_lc_pm_sysuname.field); 992 993 if (m_out->m_lc_pm_sysuname.req == _UTS_GET) 994 return CT_NOTDONE; 995 996 put_buf(proc, "value", PF_STRING, m_out->m_lc_pm_sysuname.value, 997 m_out->m_lc_pm_sysuname.len); 998 put_value(proc, "len", "%zu", m_out->m_lc_pm_sysuname.len); 999 return CT_DONE; 1000 } 1001 1002 static void 1003 pm_sysuname_in(struct trace_proc * proc, const message * m_out, 1004 const message * m_in, int failed) 1005 { 1006 1007 if (m_out->m_lc_pm_sysuname.req == _UTS_GET) { 1008 put_buf(proc, "value", failed | PF_STRING, 1009 m_out->m_lc_pm_sysuname.value, m_in->m_type); 1010 put_value(proc, "len", "%zu", m_out->m_lc_pm_sysuname.len); 1011 put_equals(proc); 1012 } 1013 put_result(proc); 1014 } 1015 1016 static void 1017 put_priority_which(struct trace_proc * proc, const char * name, int which) 1018 { 1019 const char *text = NULL; 1020 1021 if (!valuesonly) { 1022 switch (which) { 1023 TEXT(PRIO_PROCESS); 1024 TEXT(PRIO_PGRP); 1025 TEXT(PRIO_USER); 1026 } 1027 } 1028 1029 if (text != NULL) 1030 put_field(proc, name, text); 1031 else 1032 put_value(proc, name, "%d", which); 1033 } 1034 1035 static int 1036 pm_getpriority_out(struct trace_proc * proc, const message * m_out) 1037 { 1038 1039 put_priority_which(proc, "which", m_out->m_lc_pm_priority.which); 1040 put_value(proc, "who", "%d", m_out->m_lc_pm_priority.who); 1041 1042 return CT_DONE; 1043 } 1044 1045 static void 1046 pm_getpriority_in(struct trace_proc * proc, const message * __unused m_out, 1047 const message * m_in, int failed) 1048 { 1049 1050 if (!failed) 1051 put_value(proc, NULL, "%d", m_in->m_type + PRIO_MIN); 1052 else 1053 put_result(proc); 1054 } 1055 1056 static int 1057 pm_setpriority_out(struct trace_proc * proc, const message * m_out) 1058 { 1059 1060 put_priority_which(proc, "which", m_out->m_lc_pm_priority.which); 1061 put_value(proc, "who", "%d", m_out->m_lc_pm_priority.who); 1062 put_value(proc, "prio", "%d", m_out->m_lc_pm_priority.prio); 1063 1064 return CT_DONE; 1065 } 1066 1067 static int 1068 pm_gettimeofday_out(struct trace_proc * __unused proc, 1069 const message * __unused m_out) 1070 { 1071 1072 return CT_NOTDONE; 1073 } 1074 1075 static void 1076 put_timespec_as_timeval(struct trace_proc * proc, const char * name, 1077 time_t sec, long nsec) 1078 { 1079 1080 /* No field names within the structure. */ 1081 put_open(proc, name, PF_NONAME, "{", ", "); 1082 1083 put_time(proc, "tv_sec", sec); 1084 put_value(proc, "tv_usec", "%ld", nsec / 1000); 1085 1086 put_close(proc, "}"); 1087 } 1088 1089 static void 1090 pm_gettimeofday_in(struct trace_proc * proc, const message * __unused m_out, 1091 const message * m_in, int failed) 1092 { 1093 1094 if (!failed) { 1095 /* 1096 * The system call returns values which do not match the call 1097 * being made, so just like libc, we have to correct.. 1098 */ 1099 put_timespec_as_timeval(proc, "tp", m_in->m_pm_lc_time.sec, 1100 m_in->m_pm_lc_time.nsec); 1101 } else 1102 put_field(proc, "tp", "&.."); 1103 put_ptr(proc, "tzp", 0); /* not part of the system call (yet) */ 1104 1105 put_equals(proc); 1106 put_result(proc); 1107 } 1108 1109 static int 1110 pm_getsid_out(struct trace_proc * proc, const message * m_out) 1111 { 1112 1113 put_value(proc, "pid", "%d", m_out->m_lc_pm_getsid.pid); 1114 1115 return CT_DONE; 1116 } 1117 1118 static void 1119 put_clockid(struct trace_proc * proc, const char * name, clockid_t clock_id) 1120 { 1121 const char *text = NULL; 1122 1123 if (!valuesonly) { 1124 switch (clock_id) { 1125 TEXT(CLOCK_REALTIME); 1126 #ifdef CLOCK_VIRTUAL 1127 TEXT(CLOCK_VIRTUAL); 1128 #endif 1129 #ifdef CLOCK_PROF 1130 TEXT(CLOCK_PROF); 1131 #endif 1132 TEXT(CLOCK_MONOTONIC); 1133 } 1134 } 1135 1136 if (text != NULL) 1137 put_field(proc, name, text); 1138 else 1139 put_value(proc, name, "%d", clock_id); 1140 } 1141 1142 static void 1143 put_clock_timespec(struct trace_proc * proc, const char * name, int flags, 1144 time_t sec, long nsec) 1145 { 1146 1147 if (flags & PF_FAILED) { 1148 put_field(proc, name, "&.."); 1149 1150 return; 1151 } 1152 1153 /* No field names within the structure. */ 1154 put_open(proc, name, PF_NONAME, "{", ", "); 1155 1156 if (flags & PF_ALT) 1157 put_time(proc, "tv_sec", sec); 1158 else 1159 put_value(proc, "tv_sec", "%"PRId64, sec); 1160 put_value(proc, "tv_nsec", "%ld", nsec); 1161 1162 put_close(proc, "}"); 1163 } 1164 1165 /* This function is shared between clock_getres and clock_gettime. */ 1166 static int 1167 pm_clock_get_out(struct trace_proc * proc, const message * m_out) 1168 { 1169 1170 put_clockid(proc, "clock_id", m_out->m_lc_pm_time.clk_id); 1171 1172 return CT_NOTDONE; 1173 } 1174 1175 static void 1176 pm_clock_getres_in(struct trace_proc * proc, const message * __unused m_out, 1177 const message * m_in, int failed) 1178 { 1179 1180 put_clock_timespec(proc, "res", failed, m_in->m_pm_lc_time.sec, 1181 m_in->m_pm_lc_time.nsec); 1182 put_equals(proc); 1183 put_result(proc); 1184 } 1185 1186 /* 1187 * Same as pm_clock_getres_in, but different field name and the option to print 1188 * at least some results as time strings (in the future). 1189 */ 1190 static void 1191 pm_clock_gettime_in(struct trace_proc * proc, const message * m_out, 1192 const message * m_in, int failed) 1193 { 1194 int flags; 1195 1196 flags = failed; 1197 if (m_out->m_lc_pm_time.clk_id == CLOCK_REALTIME) 1198 flags |= PF_ALT; /* TODO: make this print a time string. */ 1199 1200 put_clock_timespec(proc, "tp", flags, m_in->m_pm_lc_time.sec, 1201 m_in->m_pm_lc_time.nsec); 1202 put_equals(proc); 1203 put_result(proc); 1204 } 1205 1206 static const char * 1207 pm_clock_settime_name(const message * m_out) 1208 { 1209 1210 if (m_out->m_lc_pm_time.now == 0) 1211 return "adjtime"; 1212 else 1213 return "clock_settime"; 1214 } 1215 1216 static int 1217 pm_clock_settime_out(struct trace_proc * proc, const message * m_out) 1218 { 1219 int flags; 1220 1221 /* These two calls just look completely different.. */ 1222 if (m_out->m_lc_pm_time.now == 0) { 1223 put_timespec_as_timeval(proc, "delta", m_out->m_lc_pm_time.sec, 1224 m_out->m_lc_pm_time.nsec); 1225 put_ptr(proc, "odelta", 0); /* not supported on MINIX3 */ 1226 } else { 1227 flags = 0; 1228 if (m_out->m_lc_pm_time.clk_id == CLOCK_REALTIME) 1229 flags |= PF_ALT; 1230 put_clockid(proc, "clock_id", m_out->m_lc_pm_time.clk_id); 1231 put_clock_timespec(proc, "tp", flags, m_out->m_lc_pm_time.sec, 1232 m_out->m_lc_pm_time.nsec); 1233 } 1234 1235 return CT_DONE; 1236 } 1237 1238 static int 1239 pm_getrusage_out(struct trace_proc * proc, const message * m_out) 1240 { 1241 1242 if (!valuesonly && m_out->m_lc_pm_rusage.who == RUSAGE_SELF) 1243 put_field(proc, "who", "RUSAGE_SELF"); 1244 else if (!valuesonly && m_out->m_lc_pm_rusage.who == RUSAGE_CHILDREN) 1245 put_field(proc, "who", "RUSAGE_CHILDREN"); 1246 else 1247 put_value(proc, "who", "%d", m_out->m_lc_pm_rusage.who); 1248 1249 return CT_NOTDONE; 1250 } 1251 1252 static void 1253 pm_getrusage_in(struct trace_proc * proc, const message * m_out, 1254 const message * __unused m_in, int failed) 1255 { 1256 1257 put_struct_rusage(proc, "rusage", failed, m_out->m_lc_pm_rusage.addr); 1258 put_equals(proc); 1259 put_result(proc); 1260 } 1261 1262 static const struct flags reboot_flags[] = { 1263 FLAG_ZERO(RB_AUTOBOOT), 1264 FLAG(RB_ASKNAME), 1265 FLAG(RB_DUMP), 1266 FLAG_MASK(RB_POWERDOWN, RB_HALT), 1267 FLAG(RB_POWERDOWN), 1268 FLAG(RB_INITNAME), 1269 FLAG(RB_KDB), 1270 FLAG(RB_NOSYNC), 1271 FLAG(RB_RDONLY), 1272 FLAG(RB_SINGLE), 1273 FLAG(RB_STRING), 1274 FLAG(RB_USERCONF), 1275 }; 1276 1277 static int 1278 pm_reboot_out(struct trace_proc * proc, const message * m_out) 1279 { 1280 1281 put_flags(proc, "how", reboot_flags, COUNT(reboot_flags), "0x%x", 1282 m_out->m_lc_pm_reboot.how); 1283 put_ptr(proc, "bootstr", 0); /* not supported on MINIX3 */ 1284 1285 return CT_DONE; 1286 } 1287 1288 static int 1289 pm_svrctl_out(struct trace_proc * proc, const message * m_out) 1290 { 1291 1292 put_ioctl_req(proc, "request", m_out->m_lc_svrctl.request, 1293 TRUE /*is_svrctl*/); 1294 return put_ioctl_arg_out(proc, "arg", m_out->m_lc_svrctl.request, 1295 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/); 1296 } 1297 1298 static void 1299 pm_svrctl_in(struct trace_proc * proc, const message * m_out, 1300 const message * __unused m_in, int failed) 1301 { 1302 1303 put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_svrctl.request, 1304 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/); 1305 } 1306 1307 static int 1308 pm_sprof_out(struct trace_proc * proc, const message * m_out) 1309 { 1310 int freq; 1311 1312 if (!valuesonly && m_out->m_lc_pm_sprof.action == PROF_START) 1313 put_field(proc, "action", "PROF_START"); 1314 else if (!valuesonly && m_out->m_lc_pm_sprof.action == PROF_STOP) 1315 put_field(proc, "action", "PROF_STOP"); 1316 else 1317 put_value(proc, "action", "%d", m_out->m_lc_pm_sprof.action); 1318 1319 put_value(proc, "size", "%zu", m_out->m_lc_pm_sprof.mem_size); 1320 1321 freq = m_out->m_lc_pm_sprof.freq; 1322 if (!valuesonly && freq >= 3 && freq <= 15) /* no constants.. */ 1323 put_value(proc, "freq", "%u /*%uHz*/", freq, 1 << (16 - freq)); 1324 else 1325 put_value(proc, "freq", "%u", freq); 1326 1327 if (!valuesonly && m_out->m_lc_pm_sprof.intr_type == PROF_RTC) 1328 put_field(proc, "type", "PROF_RTC"); 1329 else if (!valuesonly && m_out->m_lc_pm_sprof.intr_type == PROF_NMI) 1330 put_field(proc, "type", "PROF_NMI"); 1331 else 1332 put_value(proc, "type", "%d", m_out->m_lc_pm_sprof.intr_type); 1333 1334 put_ptr(proc, "ctl_ptr", m_out->m_lc_pm_sprof.ctl_ptr); 1335 put_ptr(proc, "mem_ptr", m_out->m_lc_pm_sprof.mem_ptr); 1336 1337 return CT_DONE; 1338 } 1339 1340 #define PM_CALL(c) [((PM_ ## c) - PM_BASE)] 1341 1342 static const struct call_handler pm_map[] = { 1343 PM_CALL(EXIT) = HANDLER("exit", pm_exit_out, default_in), 1344 PM_CALL(FORK) = HANDLER("fork", default_out, default_in), 1345 PM_CALL(WAIT4) = HANDLER("wait4", pm_wait4_out, pm_wait4_in), 1346 PM_CALL(GETPID) = HANDLER("getpid", default_out, pm_getpid_in), 1347 PM_CALL(SETUID) = HANDLER("setuid", pm_setuid_out, default_in), 1348 PM_CALL(GETUID) = HANDLER("getuid", default_out, pm_getuid_in), 1349 PM_CALL(STIME) = HANDLER("stime", pm_stime_out, default_in), 1350 PM_CALL(PTRACE) = HANDLER("ptrace", pm_ptrace_out, pm_ptrace_in), 1351 PM_CALL(SETGROUPS) = HANDLER("setgroups", pm_setgroups_out, 1352 default_in), 1353 PM_CALL(GETGROUPS) = HANDLER("getgroups", pm_getgroups_out, 1354 pm_getgroups_in), 1355 PM_CALL(KILL) = HANDLER("kill", pm_kill_out, default_in), 1356 PM_CALL(SETGID) = HANDLER("setgid", pm_setgid_out, default_in), 1357 PM_CALL(GETGID) = HANDLER("getgid", default_out, pm_getgid_in), 1358 PM_CALL(EXEC) = HANDLER("execve", pm_exec_out, default_in), 1359 PM_CALL(SETSID) = HANDLER("setsid", default_out, default_in), 1360 PM_CALL(GETPGRP) = HANDLER("getpgrp", default_out, default_in), 1361 PM_CALL(ITIMER) = HANDLER_NAME(pm_itimer_name, pm_itimer_out, 1362 pm_itimer_in), 1363 PM_CALL(GETMCONTEXT) = HANDLER("getmcontext", pm_getmcontext_out, 1364 pm_getmcontext_in), 1365 PM_CALL(SETMCONTEXT) = HANDLER("setmcontext", pm_setmcontext_out, 1366 default_in), 1367 PM_CALL(SIGACTION) = HANDLER("sigaction", pm_sigaction_out, 1368 pm_sigaction_in), 1369 PM_CALL(SIGSUSPEND) = HANDLER("sigsuspend", pm_sigsuspend_out, 1370 default_in), 1371 PM_CALL(SIGPENDING) = HANDLER("sigpending", pm_sigpending_out, 1372 pm_sigpending_in), 1373 PM_CALL(SIGPROCMASK) = HANDLER("sigprocmask", pm_sigprocmask_out, 1374 pm_sigprocmask_in), 1375 PM_CALL(SIGRETURN) = HANDLER("sigreturn", pm_sigreturn_out, 1376 pm_sigreturn_in), 1377 PM_CALL(SYSUNAME) = HANDLER("sysuname", pm_sysuname_out, 1378 pm_sysuname_in), 1379 PM_CALL(GETPRIORITY) = HANDLER("getpriority", pm_getpriority_out, 1380 pm_getpriority_in), 1381 PM_CALL(SETPRIORITY) = HANDLER("setpriority", pm_setpriority_out, 1382 default_in), 1383 PM_CALL(GETTIMEOFDAY) = HANDLER("gettimeofday", pm_gettimeofday_out, 1384 pm_gettimeofday_in), 1385 PM_CALL(SETEUID) = HANDLER("seteuid", pm_setuid_out, default_in), 1386 PM_CALL(SETEGID) = HANDLER("setegid", pm_setgid_out, default_in), 1387 PM_CALL(ISSETUGID) = HANDLER("issetugid", default_out, default_in), 1388 PM_CALL(GETSID) = HANDLER("getsid", pm_getsid_out, default_in), 1389 PM_CALL(CLOCK_GETRES) = HANDLER("clock_getres", pm_clock_get_out, 1390 pm_clock_getres_in), 1391 PM_CALL(CLOCK_GETTIME) = HANDLER("clock_gettime", pm_clock_get_out, 1392 pm_clock_gettime_in), 1393 PM_CALL(CLOCK_SETTIME) = HANDLER_NAME(pm_clock_settime_name, 1394 pm_clock_settime_out, default_in), 1395 PM_CALL(GETRUSAGE) = HANDLER("getrusage", pm_getrusage_out, 1396 pm_getrusage_in), 1397 PM_CALL(REBOOT) = HANDLER("reboot", pm_reboot_out, default_in), 1398 PM_CALL(SVRCTL) = HANDLER("pm_svrctl", pm_svrctl_out, pm_svrctl_in), 1399 PM_CALL(SPROF) = HANDLER("sprofile", pm_sprof_out, default_in), 1400 }; 1401 1402 const struct calls pm_calls = { 1403 .endpt = PM_PROC_NR, 1404 .base = PM_BASE, 1405 .map = pm_map, 1406 .count = COUNT(pm_map) 1407 }; 1408