1 /* $OpenBSD: kdump.c,v 1.75 2012/07/11 11:18:40 guenther Exp $ */ 2 3 /*- 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/time.h> 34 #include <sys/uio.h> 35 #include <sys/ktrace.h> 36 #include <sys/ioctl.h> 37 #include <sys/malloc.h> 38 #include <sys/namei.h> 39 #include <sys/ptrace.h> 40 #include <sys/sem.h> 41 #include <sys/shm.h> 42 #include <sys/socket.h> 43 #include <sys/sysctl.h> 44 #include <sys/siginfo.h> 45 #include <sys/un.h> 46 #include <sys/vmmeter.h> 47 #include <sys/stat.h> 48 #include <sys/tty.h> 49 #include <netinet/in.h> 50 #include <arpa/inet.h> 51 #define _KERNEL 52 #include <sys/errno.h> 53 #undef _KERNEL 54 #include <ddb/db_var.h> 55 #include <machine/cpu.h> 56 57 #include <ctype.h> 58 #include <err.h> 59 #include <fcntl.h> 60 #include <limits.h> 61 #include <signal.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <stdint.h> 65 #include <string.h> 66 #include <grp.h> 67 #include <pwd.h> 68 #include <unistd.h> 69 #include <vis.h> 70 71 #include "ktrace.h" 72 #include "kdump.h" 73 #include "kdump_subr.h" 74 #include "extern.h" 75 76 int timestamp, decimal, iohex, fancy = 1, maxdata = INT_MAX; 77 int needtid, resolv, tail; 78 char *tracefile = DEF_TRACEFILE; 79 struct ktr_header ktr_header; 80 pid_t pid = -1; 81 82 #define TIME_FORMAT "%b %e %T %Y" 83 #define eqs(s1, s2) (strcmp((s1), (s2)) == 0) 84 85 #include <sys/syscall.h> 86 87 #include <compat/linux/linux_syscall.h> 88 89 #define KTRACE 90 #define PTRACE 91 #define NFSCLIENT 92 #define NFSSERVER 93 #define SYSVSEM 94 #define SYSVMSG 95 #define SYSVSHM 96 #define LFS 97 #include <kern/syscalls.c> 98 99 #include <compat/linux/linux_syscalls.c> 100 #undef KTRACE 101 #undef PTRACE 102 #undef NFSCLIENT 103 #undef NFSSERVER 104 #undef SYSVSEM 105 #undef SYSVMSG 106 #undef SYSVSHM 107 #undef LFS 108 109 struct emulation { 110 char *name; /* Emulation name */ 111 char **sysnames; /* Array of system call names */ 112 int nsysnames; /* Number of */ 113 }; 114 115 static struct emulation emulations[] = { 116 { "native", syscallnames, SYS_MAXSYSCALL }, 117 { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL }, 118 { NULL, NULL, 0 } 119 }; 120 121 static struct emulation *current; 122 static struct emulation *def_emul; 123 124 struct pid_emul { 125 struct emulation *e; 126 pid_t p; 127 }; 128 129 static struct pid_emul *pe_table; 130 static size_t pe_size; 131 132 133 static char *ptrace_ops[] = { 134 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", 135 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", 136 "PT_KILL", "PT_ATTACH", "PT_DETACH", "PT_IO", 137 "PT_SET_EVENT_MASK", "PT_GET_EVENT_MASK", "PT_GET_PROCESS_STATE", 138 "PT_GET_THREAD_FIRST", "PT_GET_THREAD_NEXT", 139 }; 140 141 static int narg; 142 static register_t *ap; 143 static char sep; 144 145 static void mappidtoemul(pid_t, struct emulation *); 146 static struct emulation * findemul(pid_t); 147 static int fread_tail(void *, size_t, size_t); 148 static void dumpheader(struct ktr_header *); 149 static void ktrcsw(struct ktr_csw *); 150 static void ktremul(char *, size_t); 151 static void ktrgenio(struct ktr_genio *, size_t); 152 static void ktrnamei(const char *, size_t); 153 static void ktrpsig(struct ktr_psig *); 154 static void ktrsyscall(struct ktr_syscall *); 155 static const char *kresolvsysctl(int, int *, int); 156 static void ktrsysret(struct ktr_sysret *); 157 static void ktrstruct(char *, size_t); 158 static void setemul(const char *); 159 static void usage(void); 160 static void atfd(int); 161 162 int 163 main(int argc, char *argv[]) 164 { 165 int ch, silent; 166 size_t ktrlen, size; 167 int trpoints = ALL_POINTS; 168 void *m; 169 170 def_emul = current = &emulations[0]; /* native */ 171 172 while ((ch = getopt(argc, argv, "e:f:dHlm:nrRp:Tt:xX")) != -1) 173 switch (ch) { 174 case 'e': 175 setemul(optarg); 176 def_emul = current; 177 break; 178 case 'f': 179 tracefile = optarg; 180 break; 181 case 'd': 182 decimal = 1; 183 break; 184 case 'H': 185 needtid = 1; 186 break; 187 case 'l': 188 tail = 1; 189 break; 190 case 'm': 191 maxdata = atoi(optarg); 192 break; 193 case 'n': 194 fancy = 0; 195 break; 196 case 'p': 197 pid = atoi(optarg); 198 break; 199 case 'r': 200 resolv = 1; 201 break; 202 case 'R': 203 timestamp = 2; /* relative timestamp */ 204 break; 205 case 'T': 206 timestamp = 1; 207 break; 208 case 't': 209 trpoints = getpoints(optarg); 210 if (trpoints < 0) 211 errx(1, "unknown trace point in %s", optarg); 212 break; 213 case 'x': 214 iohex = 1; 215 break; 216 case 'X': 217 iohex = 2; 218 break; 219 default: 220 usage(); 221 } 222 if (argc > optind) 223 usage(); 224 225 m = malloc(size = 1025); 226 if (m == NULL) 227 err(1, NULL); 228 if (!freopen(tracefile, "r", stdin)) 229 err(1, "%s", tracefile); 230 if (fread_tail(&ktr_header, sizeof(struct ktr_header), 1) == 0 || 231 ktr_header.ktr_type != htobe32(KTR_START)) 232 errx(1, "%s: not a dump", tracefile); 233 while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { 234 silent = 0; 235 if (pe_size == 0) 236 mappidtoemul(ktr_header.ktr_pid, current); 237 if (pid != -1 && pid != ktr_header.ktr_pid) 238 silent = 1; 239 if (silent == 0 && trpoints & (1<<ktr_header.ktr_type)) 240 dumpheader(&ktr_header); 241 ktrlen = ktr_header.ktr_len; 242 if (ktrlen > size) { 243 void *newm; 244 245 if (ktrlen == SIZE_MAX) 246 errx(1, "data too long"); 247 newm = realloc(m, ktrlen+1); 248 if (newm == NULL) 249 err(1, "realloc"); 250 m = newm; 251 size = ktrlen; 252 } 253 if (ktrlen && fread_tail(m, ktrlen, 1) == 0) 254 errx(1, "data too short"); 255 if (silent) 256 continue; 257 if ((trpoints & (1<<ktr_header.ktr_type)) == 0) 258 continue; 259 current = findemul(ktr_header.ktr_pid); 260 switch (ktr_header.ktr_type) { 261 case KTR_SYSCALL: 262 ktrsyscall((struct ktr_syscall *)m); 263 break; 264 case KTR_SYSRET: 265 ktrsysret((struct ktr_sysret *)m); 266 break; 267 case KTR_NAMEI: 268 ktrnamei(m, ktrlen); 269 break; 270 case KTR_GENIO: 271 ktrgenio((struct ktr_genio *)m, ktrlen); 272 break; 273 case KTR_PSIG: 274 ktrpsig((struct ktr_psig *)m); 275 break; 276 case KTR_CSW: 277 ktrcsw((struct ktr_csw *)m); 278 break; 279 case KTR_EMUL: 280 ktremul(m, ktrlen); 281 mappidtoemul(ktr_header.ktr_pid, current); 282 break; 283 case KTR_STRUCT: 284 ktrstruct(m, ktrlen); 285 break; 286 } 287 if (tail) 288 (void)fflush(stdout); 289 } 290 exit(0); 291 } 292 293 static void 294 mappidtoemul(pid_t pid, struct emulation *emul) 295 { 296 size_t i; 297 struct pid_emul *tmp; 298 299 for (i = 0; i < pe_size; i++) { 300 if (pe_table[i].p == pid) { 301 pe_table[i].e = emul; 302 return; 303 } 304 } 305 tmp = realloc(pe_table, (pe_size + 1) * sizeof(*pe_table)); 306 if (tmp == NULL) 307 err(1, NULL); 308 pe_table = tmp; 309 pe_table[pe_size].p = pid; 310 pe_table[pe_size].e = emul; 311 pe_size++; 312 } 313 314 static struct emulation* 315 findemul(pid_t pid) 316 { 317 size_t i; 318 319 for (i = 0; i < pe_size; i++) 320 if (pe_table[i].p == pid) 321 return pe_table[i].e; 322 return def_emul; 323 } 324 325 static int 326 fread_tail(void *buf, size_t size, size_t num) 327 { 328 int i; 329 330 while ((i = fread(buf, size, num, stdin)) == 0 && tail) { 331 (void)sleep(1); 332 clearerr(stdin); 333 } 334 return (i); 335 } 336 337 static void 338 dumpheader(struct ktr_header *kth) 339 { 340 static struct timespec prevtime; 341 char unknown[64], *type; 342 struct timespec temp; 343 344 switch (kth->ktr_type) { 345 case KTR_SYSCALL: 346 type = "CALL"; 347 break; 348 case KTR_SYSRET: 349 type = "RET "; 350 break; 351 case KTR_NAMEI: 352 type = "NAMI"; 353 break; 354 case KTR_GENIO: 355 type = "GIO "; 356 break; 357 case KTR_PSIG: 358 type = "PSIG"; 359 break; 360 case KTR_CSW: 361 type = "CSW"; 362 break; 363 case KTR_EMUL: 364 type = "EMUL"; 365 break; 366 case KTR_STRUCT: 367 type = "STRU"; 368 break; 369 default: 370 (void)snprintf(unknown, sizeof unknown, "UNKNOWN(%d)", 371 kth->ktr_type); 372 type = unknown; 373 } 374 375 (void)printf("%6ld", (long)kth->ktr_pid); 376 if (needtid) 377 (void)printf("/%-7ld", (long)kth->ktr_tid); 378 (void)printf(" %-8.*s ", MAXCOMLEN, kth->ktr_comm); 379 if (timestamp) { 380 if (timestamp == 2) { 381 timespecsub(&kth->ktr_time, &prevtime, &temp); 382 prevtime = kth->ktr_time; 383 } else 384 temp = kth->ktr_time; 385 (void)printf("%ld.%06ld ", temp.tv_sec, temp.tv_nsec / 1000); 386 } 387 (void)printf("%s ", type); 388 } 389 390 static void 391 ioctldecode(u_long cmd) 392 { 393 char dirbuf[4], *dir = dirbuf; 394 395 if (cmd & IOC_IN) 396 *dir++ = 'W'; 397 if (cmd & IOC_OUT) 398 *dir++ = 'R'; 399 *dir = '\0'; 400 401 printf(decimal ? ",_IO%s('%c',%lu" : ",_IO%s('%c',%#lx", 402 dirbuf, (int)((cmd >> 8) & 0xff), cmd & 0xff); 403 if ((cmd & IOC_VOID) == 0) 404 printf(decimal ? ",%lu)" : ",%#lx)", (cmd >> 16) & 0xff); 405 else 406 printf(")"); 407 } 408 409 static void 410 ptracedecode(void) 411 { 412 if (*ap >= 0 && *ap < 413 sizeof(ptrace_ops) / sizeof(ptrace_ops[0])) 414 (void)printf("%s", ptrace_ops[*ap]); 415 else switch(*ap) { 416 #ifdef PT_GETFPREGS 417 case PT_GETFPREGS: 418 (void)printf("PT_GETFPREGS"); 419 break; 420 #endif 421 case PT_GETREGS: 422 (void)printf("PT_GETREGS"); 423 break; 424 #ifdef PT_GETXMMREGS 425 case PT_GETXMMREGS: 426 (void)printf("PT_GETXMMREGS"); 427 break; 428 #endif 429 #ifdef PT_SETFPREGS 430 case PT_SETFPREGS: 431 (void)printf("PT_SETFPREGS"); 432 break; 433 #endif 434 case PT_SETREGS: 435 (void)printf("PT_SETREGS"); 436 break; 437 #ifdef PT_SETXMMREGS 438 case PT_SETXMMREGS: 439 (void)printf("PT_SETXMMREGS"); 440 break; 441 #endif 442 #ifdef PT_STEP 443 case PT_STEP: 444 (void)printf("PT_STEP"); 445 break; 446 #endif 447 #ifdef PT_WCOOKIE 448 case PT_WCOOKIE: 449 (void)printf("PT_WCOOKIE"); 450 break; 451 #endif 452 default: 453 (void)printf("%ld", (long)*ap); 454 break; 455 } 456 sep = ','; 457 ap++; 458 narg--; 459 } 460 461 static void 462 pn(void (*f)(int)) 463 { 464 if (sep) 465 (void)putchar(sep); 466 if (fancy && f != NULL) 467 f((int)*ap); 468 else if (decimal) 469 (void)printf("%ld", (long)*ap); 470 else 471 (void)printf("%#lx", (long)*ap); 472 ap++; 473 narg--; 474 sep = ','; 475 } 476 477 #ifdef __LP64__ 478 #define plln() pn(NULL) 479 #elif _BYTE_ORDER == _LITTLE_ENDIAN 480 static void 481 plln(void) 482 { 483 long long val = ((long long)*ap) & 0xffffffff; 484 ap++; 485 val |= ((long long)*ap) << 32; 486 ap++; 487 narg -= 2; 488 if (sep) 489 (void)putchar(sep); 490 if (decimal) 491 (void)printf("%lld", val); 492 else 493 (void)printf("%#llx", val); 494 sep = ','; 495 } 496 #else 497 static void 498 plln(void) 499 { 500 long long val = ((long long)*ap) << 32; 501 ap++; 502 val |= ((long long)*ap) & 0xffffffff; 503 ap++; 504 narg -= 2; 505 if (sep) 506 (void)putchar(sep); 507 if (decimal) 508 (void)printf("%lld", val); 509 else 510 (void)printf("%#llx", val); 511 sep = ','; 512 } 513 #endif 514 515 static void 516 ktrsyscall(struct ktr_syscall *ktr) 517 { 518 narg = ktr->ktr_argsize / sizeof(register_t); 519 sep = '\0'; 520 521 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0) 522 (void)printf("[%d]", ktr->ktr_code); 523 else 524 (void)printf("%s", current->sysnames[ktr->ktr_code]); 525 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall)); 526 (void)putchar('('); 527 528 if (current != &emulations[0]) 529 goto nonnative; 530 531 switch (ktr->ktr_code) { 532 case SYS_ioctl: { 533 const char *cp; 534 535 pn(NULL); 536 if (!fancy) 537 break; 538 if ((cp = ioctlname(*ap)) != NULL) 539 (void)printf(",%s", cp); 540 else 541 ioctldecode(*ap); 542 ap++; 543 narg--; 544 break; 545 } 546 case SYS___sysctl: { 547 const char *s; 548 int *np, n, i, *top; 549 550 if (!fancy) 551 break; 552 n = ap[1]; 553 if (n > CTL_MAXNAME) 554 n = CTL_MAXNAME; 555 np = top = (int *)(ap + 6); 556 for (i = 0; n--; np++, i++) { 557 if (sep) 558 putchar(sep); 559 if (resolv && (s = kresolvsysctl(i, top, *np)) != NULL) 560 printf("%s", s); 561 else 562 printf("%d", *np); 563 sep = '.'; 564 } 565 566 sep = ','; 567 ap += 2; 568 narg -= 2; 569 break; 570 } 571 case SYS_ptrace: 572 if (!fancy) 573 break; 574 ptracedecode(); 575 break; 576 case SYS_access: 577 pn(NULL); 578 pn(accessmodename); 579 break; 580 case SYS_chmod: 581 case SYS_fchmod: 582 pn(NULL); 583 pn(modename); 584 break; 585 case SYS_fcntl: { 586 int cmd; 587 int arg; 588 pn(NULL); 589 if (!fancy) 590 break; 591 cmd = ap[0]; 592 arg = ap[1]; 593 (void)putchar(','); 594 fcntlcmdname(cmd, arg); 595 ap += 2; 596 narg -= 2; 597 break; 598 } 599 case SYS_flock: 600 pn(NULL); 601 pn(flockname); 602 break; 603 case SYS_getrlimit: 604 case SYS_setrlimit: 605 pn(rlimitname); 606 break; 607 case SYS_getsockopt: 608 case SYS_setsockopt: { 609 int level; 610 611 pn(NULL); 612 level = *ap; 613 pn(sockoptlevelname); 614 if (level == SOL_SOCKET) 615 pn(sockoptname); 616 break; 617 } 618 case SYS_kill: 619 pn(NULL); 620 pn(signame); 621 break; 622 case SYS_lseek: 623 pn(NULL); 624 /* skip padding */ 625 ap++; 626 narg--; 627 plln(); 628 pn(whencename); 629 break; 630 case SYS_madvise: 631 pn(NULL); 632 pn(NULL); 633 pn(madvisebehavname); 634 break; 635 case SYS_minherit: 636 pn(NULL); 637 pn(NULL); 638 pn(minheritname); 639 break; 640 case SYS_mlockall: 641 pn(mlockallname); 642 break; 643 case SYS_mmap: 644 pn(NULL); 645 pn(NULL); 646 pn(mmapprotname); 647 pn(mmapflagsname); 648 pn(NULL); 649 /* skip padding */ 650 ap++; 651 narg--; 652 plln(); 653 break; 654 case SYS_mprotect: 655 pn(NULL); 656 pn(NULL); 657 pn(mmapprotname); 658 break; 659 case SYS_mquery: 660 pn(NULL); 661 pn(NULL); 662 pn(mmapprotname); 663 pn(mmapflagsname); 664 pn(NULL); 665 /* skip padding */ 666 ap++; 667 narg--; 668 plln(); 669 break; 670 case SYS_msync: 671 pn(NULL); 672 pn(NULL); 673 pn(msyncflagsname); 674 break; 675 case SYS_msgctl: 676 pn(NULL); 677 pn(shmctlname); 678 break; 679 case SYS_open: { 680 int flags; 681 int mode; 682 683 pn(NULL); 684 if (!fancy) 685 break; 686 flags = ap[0]; 687 mode = ap[1]; 688 (void)putchar(','); 689 flagsandmodename(flags, mode); 690 ap += 2; 691 narg -= 2; 692 break; 693 } 694 case SYS_pread: 695 case SYS_preadv: 696 case SYS_pwrite: 697 case SYS_pwritev: 698 pn(NULL); 699 pn(NULL); 700 pn(NULL); 701 /* skip padding */ 702 ap++; 703 narg--; 704 plln(); 705 break; 706 case SYS_recvmsg: 707 case SYS_sendmsg: 708 pn(NULL); 709 pn(NULL); 710 pn(sendrecvflagsname); 711 break; 712 case SYS_recvfrom: 713 case SYS_sendto: 714 pn(NULL); 715 pn(NULL); 716 pn(NULL); 717 pn(sendrecvflagsname); 718 break; 719 case SYS___semctl: 720 pn(NULL); 721 pn(NULL); 722 pn(semctlname); 723 break; 724 case SYS_semget: 725 pn(NULL); 726 pn(NULL); 727 pn(semgetname); 728 break; 729 case SYS_shmat: 730 pn(NULL); 731 pn(NULL); 732 pn(shmatname); 733 break; 734 case SYS_shmctl: 735 pn(NULL); 736 pn(shmctlname); 737 break; 738 case SYS_clock_gettime: 739 case SYS_clock_settime: 740 case SYS_clock_getres: 741 pn(clockname); 742 break; 743 case SYS_sigaction: 744 pn(signame); 745 break; 746 case SYS_sigprocmask: 747 pn(sigprocmaskhowname); 748 pn(sigset); 749 break; 750 case SYS_sigsuspend: 751 pn(sigset); 752 break; 753 case SYS_socket: { 754 int sockdomain = *ap; 755 756 pn(sockdomainname); 757 pn(socktypename); 758 if (sockdomain == PF_INET || sockdomain == PF_INET6) 759 pn(sockipprotoname); 760 break; 761 } 762 case SYS_socketpair: 763 pn(sockdomainname); 764 pn(socktypename); 765 break; 766 case SYS_truncate: 767 case SYS_ftruncate: 768 pn(NULL); 769 /* skip padding */ 770 ap++; 771 narg--; 772 plln(); 773 break; 774 case SYS_wait4: 775 pn(NULL); 776 pn(NULL); 777 pn(wait4optname); 778 break; 779 case SYS___thrsleep: 780 pn(NULL); 781 pn(clockname); 782 break; 783 case SYS___thrsigdivert: 784 pn(sigset); 785 break; 786 case SYS_faccessat: 787 pn(atfd); 788 pn(NULL); 789 pn(accessmodename); 790 pn(atflagsname); 791 break; 792 case SYS_fchmodat: 793 pn(atfd); 794 pn(NULL); 795 pn(modename); 796 pn(atflagsname); 797 break; 798 case SYS_fchownat: 799 pn(atfd); 800 pn(NULL); 801 pn(NULL); 802 pn(NULL); 803 pn(atflagsname); 804 break; 805 case SYS_fstatat: 806 pn(atfd); 807 pn(NULL); 808 pn(NULL); 809 pn(atflagsname); 810 break; 811 case SYS_linkat: 812 pn(atfd); 813 pn(NULL); 814 pn(atfd); 815 pn(NULL); 816 pn(atflagsname); 817 break; 818 case SYS_mkdirat: 819 case SYS_mkfifoat: 820 case SYS_mknodat: 821 pn(atfd); 822 pn(NULL); 823 pn(modename); 824 break; 825 case SYS_openat: { 826 int flags; 827 int mode; 828 829 pn(atfd); 830 pn(NULL); 831 if (!fancy) 832 break; 833 flags = ap[0]; 834 mode = ap[1]; 835 (void)putchar(','); 836 flagsandmodename(flags, mode); 837 ap += 2; 838 narg -= 2; 839 break; 840 } 841 case SYS_readlinkat: 842 pn(atfd); 843 break; 844 case SYS_renameat: 845 pn(atfd); 846 pn(NULL); 847 pn(atfd); 848 break; 849 case SYS_symlinkat: 850 pn(NULL); 851 pn(atfd); 852 break; 853 case SYS_unlinkat: 854 pn(atfd); 855 pn(NULL); 856 pn(atflagsname); 857 break; 858 case SYS_utimensat: 859 pn(atfd); 860 pn(NULL); 861 pn(NULL); 862 pn(atflagsname); 863 break; 864 } 865 866 nonnative: 867 while (narg) { 868 if (sep) 869 putchar(sep); 870 if (decimal) 871 (void)printf("%ld", (long)*ap); 872 else 873 (void)printf("%#lx", (long)*ap); 874 sep = ','; 875 ap++; 876 narg--; 877 } 878 (void)printf(")\n"); 879 } 880 881 static struct ctlname topname[] = CTL_NAMES; 882 static struct ctlname kernname[] = CTL_KERN_NAMES; 883 static struct ctlname vmname[] = CTL_VM_NAMES; 884 static struct ctlname fsname[] = CTL_FS_NAMES; 885 static struct ctlname netname[] = CTL_NET_NAMES; 886 static struct ctlname hwname[] = CTL_HW_NAMES; 887 static struct ctlname username[] = CTL_USER_NAMES; 888 static struct ctlname debugname[CTL_DEBUG_MAXID]; 889 static struct ctlname kernmallocname[] = CTL_KERN_MALLOC_NAMES; 890 static struct ctlname forkstatname[] = CTL_KERN_FORKSTAT_NAMES; 891 static struct ctlname nchstatsname[] = CTL_KERN_NCHSTATS_NAMES; 892 static struct ctlname kernprocname[] = 893 { 894 { NULL }, 895 { "all" }, 896 { "pid" }, 897 { "pgrp" }, 898 { "session" }, 899 { "tty" }, 900 { "uid" }, 901 { "ruid" }, 902 }; 903 static struct ctlname ttysname[] = CTL_KERN_TTY_NAMES; 904 static struct ctlname semname[] = CTL_KERN_SEMINFO_NAMES; 905 static struct ctlname shmname[] = CTL_KERN_SHMINFO_NAMES; 906 static struct ctlname watchdogname[] = CTL_KERN_WATCHDOG_NAMES; 907 static struct ctlname tcname[] = CTL_KERN_TIMECOUNTER_NAMES; 908 #ifdef CTL_MACHDEP_NAMES 909 static struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 910 #endif 911 static struct ctlname ddbname[] = CTL_DDB_NAMES; 912 913 #ifndef nitems 914 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 915 #endif 916 917 #define SETNAME(name) do { names = (name); limit = nitems(name); } while (0) 918 919 static const char * 920 kresolvsysctl(int depth, int *top, int idx) 921 { 922 struct ctlname *names; 923 size_t limit; 924 925 names = NULL; 926 927 switch (depth) { 928 case 0: 929 SETNAME(topname); 930 break; 931 case 1: 932 switch (top[0]) { 933 case CTL_KERN: 934 SETNAME(kernname); 935 break; 936 case CTL_VM: 937 SETNAME(vmname); 938 break; 939 case CTL_FS: 940 SETNAME(fsname); 941 break; 942 case CTL_NET: 943 SETNAME(netname); 944 break; 945 case CTL_DEBUG: 946 SETNAME(debugname); 947 break; 948 case CTL_HW: 949 SETNAME(hwname); 950 break; 951 #ifdef CTL_MACHDEP_NAMES 952 case CTL_MACHDEP: 953 SETNAME(machdepname); 954 break; 955 #endif 956 case CTL_USER: 957 SETNAME(username); 958 break; 959 case CTL_DDB: 960 SETNAME(ddbname); 961 break; 962 } 963 break; 964 case 2: 965 switch (top[0]) { 966 case CTL_KERN: 967 switch (top[1]) { 968 case KERN_MALLOCSTATS: 969 SETNAME(kernmallocname); 970 break; 971 case KERN_FORKSTAT: 972 SETNAME(forkstatname); 973 break; 974 case KERN_NCHSTATS: 975 SETNAME(nchstatsname); 976 break; 977 case KERN_TTY: 978 SETNAME(ttysname); 979 break; 980 case KERN_SEMINFO: 981 SETNAME(semname); 982 break; 983 case KERN_SHMINFO: 984 SETNAME(shmname); 985 break; 986 case KERN_WATCHDOG: 987 SETNAME(watchdogname); 988 break; 989 case KERN_PROC: 990 idx++; /* zero is valid at this level */ 991 SETNAME(kernprocname); 992 break; 993 case KERN_TIMECOUNTER: 994 SETNAME(tcname); 995 break; 996 } 997 } 998 break; 999 } 1000 if (names != NULL && idx > 0 && idx < limit) 1001 return (names[idx].ctl_name); 1002 return (NULL); 1003 } 1004 1005 static void 1006 ktrsysret(struct ktr_sysret *ktr) 1007 { 1008 register_t ret = ktr->ktr_retval; 1009 int error = ktr->ktr_error; 1010 int code = ktr->ktr_code; 1011 1012 if (code >= current->nsysnames || code < 0) 1013 (void)printf("[%d] ", code); 1014 else { 1015 (void)printf("%s ", current->sysnames[code]); 1016 if (ret > 0 && (strcmp(current->sysnames[code], "fork") == 0 || 1017 strcmp(current->sysnames[code], "vfork") == 0 || 1018 strcmp(current->sysnames[code], "__tfork") == 0 || 1019 strcmp(current->sysnames[code], "clone") == 0)) 1020 mappidtoemul(ret, current); 1021 } 1022 1023 if (error == 0) { 1024 if (fancy) { 1025 switch (current == &emulations[0] ? code : -1) { 1026 case SYS_sigprocmask: 1027 case SYS_sigpending: 1028 sigset(ret); 1029 break; 1030 case SYS___thrsigdivert: 1031 signame(ret); 1032 break; 1033 case -1: /* non-default emulation */ 1034 default: 1035 (void)printf("%ld", (long)ret); 1036 if (ret < 0 || ret > 9) 1037 (void)printf("/%#lx", (long)ret); 1038 } 1039 } else { 1040 if (decimal) 1041 (void)printf("%ld", (long)ret); 1042 else 1043 (void)printf("%#lx", (long)ret); 1044 } 1045 } else if (error == ERESTART) 1046 (void)printf("RESTART"); 1047 else if (error == EJUSTRETURN) 1048 (void)printf("JUSTRETURN"); 1049 else { 1050 (void)printf("-1 errno %d", ktr->ktr_error); 1051 if (fancy) 1052 (void)printf(" %s", strerror(ktr->ktr_error)); 1053 } 1054 (void)putchar('\n'); 1055 } 1056 1057 static void 1058 ktrnamei(const char *cp, size_t len) 1059 { 1060 (void)printf("\"%.*s\"\n", (int)len, cp); 1061 } 1062 1063 static void 1064 ktremul(char *cp, size_t len) 1065 { 1066 char name[1024]; 1067 1068 if (len >= sizeof(name)) 1069 errx(1, "Emulation name too long"); 1070 1071 strncpy(name, cp, len); 1072 name[len] = '\0'; 1073 (void)printf("\"%s\"\n", name); 1074 1075 setemul(name); 1076 } 1077 1078 static void 1079 ktrgenio(struct ktr_genio *ktr, size_t len) 1080 { 1081 unsigned char *dp = (unsigned char *)ktr + sizeof(struct ktr_genio); 1082 int i, j; 1083 size_t datalen = len - sizeof(struct ktr_genio); 1084 static int screenwidth = 0; 1085 int col = 0, width, bpl; 1086 unsigned char visbuf[5], *cp, c; 1087 1088 if (screenwidth == 0) { 1089 struct winsize ws; 1090 1091 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 1092 ws.ws_col > 8) 1093 screenwidth = ws.ws_col; 1094 else 1095 screenwidth = 80; 1096 } 1097 printf("fd %d %s %zu bytes\n", ktr->ktr_fd, 1098 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen); 1099 if (maxdata == 0) 1100 return; 1101 if (datalen > maxdata) 1102 datalen = maxdata; 1103 if (iohex && !datalen) 1104 return; 1105 if (iohex == 1) { 1106 putchar('\t'); 1107 col = 8; 1108 for (i = 0; i < datalen; i++) { 1109 printf("%02x", dp[i]); 1110 col += 3; 1111 if (i < datalen - 1) { 1112 if (col + 3 > screenwidth) { 1113 printf("\n\t"); 1114 col = 8; 1115 } else 1116 putchar(' '); 1117 } 1118 } 1119 putchar('\n'); 1120 return; 1121 } 1122 if (iohex == 2) { 1123 bpl = (screenwidth - 13)/4; 1124 if (bpl <= 0) 1125 bpl = 1; 1126 for (i = 0; i < datalen; i += bpl) { 1127 printf(" %04x: ", i); 1128 for (j = 0; j < bpl; j++) { 1129 if (i+j >= datalen) 1130 printf(" "); 1131 else 1132 printf("%02x ", dp[i+j]); 1133 } 1134 putchar(' '); 1135 for (j = 0; j < bpl; j++) { 1136 if (i+j >= datalen) 1137 break; 1138 c = dp[i+j]; 1139 if (!isprint(c)) 1140 c = '.'; 1141 putchar(c); 1142 } 1143 putchar('\n'); 1144 } 1145 return; 1146 } 1147 (void)printf(" \""); 1148 col = 8; 1149 for (; datalen > 0; datalen--, dp++) { 1150 (void)vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); 1151 cp = visbuf; 1152 1153 /* 1154 * Keep track of printables and 1155 * space chars (like fold(1)). 1156 */ 1157 if (col == 0) { 1158 (void)putchar('\t'); 1159 col = 8; 1160 } 1161 switch (*cp) { 1162 case '\n': 1163 col = 0; 1164 (void)putchar('\n'); 1165 continue; 1166 case '\t': 1167 width = 8 - (col&07); 1168 break; 1169 default: 1170 width = strlen(cp); 1171 } 1172 if (col + width > (screenwidth-2)) { 1173 (void)printf("\\\n\t"); 1174 col = 8; 1175 } 1176 col += width; 1177 do { 1178 (void)putchar(*cp++); 1179 } while (*cp); 1180 } 1181 if (col == 0) 1182 (void)printf(" "); 1183 (void)printf("\"\n"); 1184 } 1185 1186 static void 1187 ktrpsig(struct ktr_psig *psig) 1188 { 1189 (void)printf("SIG%s ", sys_signame[psig->signo]); 1190 if (psig->action == SIG_DFL) 1191 (void)printf("SIG_DFL"); 1192 else { 1193 (void)printf("caught handler=0x%lx mask=", 1194 (u_long)psig->action); 1195 sigset(psig->mask); 1196 } 1197 if (psig->code) { 1198 printf(" code "); 1199 if (fancy) { 1200 switch (psig->signo) { 1201 case SIGILL: 1202 sigill_name(psig->code); 1203 break; 1204 case SIGTRAP: 1205 sigtrap_name(psig->code); 1206 break; 1207 case SIGEMT: 1208 sigemt_name(psig->code); 1209 break; 1210 case SIGFPE: 1211 sigfpe_name(psig->code); 1212 break; 1213 case SIGBUS: 1214 sigbus_name(psig->code); 1215 break; 1216 case SIGSEGV: 1217 sigsegv_name(psig->code); 1218 break; 1219 case SIGCHLD: 1220 sigchld_name(psig->code); 1221 break; 1222 } 1223 } 1224 printf("<%d>", psig->code); 1225 } 1226 1227 switch (psig->signo) { 1228 case SIGSEGV: 1229 case SIGILL: 1230 case SIGBUS: 1231 case SIGFPE: 1232 printf(" addr=%p trapno=%d", psig->si.si_addr, 1233 psig->si.si_trapno); 1234 break; 1235 default: 1236 break; 1237 } 1238 printf("\n"); 1239 } 1240 1241 static void 1242 ktrcsw(struct ktr_csw *cs) 1243 { 1244 (void)printf("%s %s\n", cs->out ? "stop" : "resume", 1245 cs->user ? "user" : "kernel"); 1246 } 1247 1248 1249 1250 static void 1251 ktrsockaddr(struct sockaddr *sa) 1252 { 1253 /* 1254 TODO: Support additional address families 1255 #include <netnatm/natm.h> 1256 struct sockaddr_natm *natm; 1257 #include <netsmb/netbios.h> 1258 struct sockaddr_nb *nb; 1259 */ 1260 char addr[64]; 1261 1262 /* 1263 * note: ktrstruct() has already verified that sa points to a 1264 * buffer at least sizeof(struct sockaddr) bytes long and exactly 1265 * sa->sa_len bytes long. 1266 */ 1267 printf("struct sockaddr { "); 1268 sockfamilyname(sa->sa_family); 1269 printf(", "); 1270 1271 #define check_sockaddr_len(n) \ 1272 if (sa_##n->s##n##_len < sizeof(struct sockaddr_##n)) { \ 1273 printf("invalid"); \ 1274 break; \ 1275 } 1276 1277 switch(sa->sa_family) { 1278 case AF_INET: { 1279 struct sockaddr_in *sa_in; 1280 1281 sa_in = (struct sockaddr_in *)sa; 1282 check_sockaddr_len(in); 1283 inet_ntop(AF_INET, &sa_in->sin_addr, addr, sizeof addr); 1284 printf("%s:%u", addr, ntohs(sa_in->sin_port)); 1285 break; 1286 } 1287 case AF_INET6: { 1288 struct sockaddr_in6 *sa_in6; 1289 1290 sa_in6 = (struct sockaddr_in6 *)sa; 1291 check_sockaddr_len(in6); 1292 inet_ntop(AF_INET6, &sa_in6->sin6_addr, addr, sizeof addr); 1293 printf("[%s]:%u", addr, htons(sa_in6->sin6_port)); 1294 break; 1295 } 1296 #ifdef IPX 1297 case AF_IPX: { 1298 struct sockaddr_ipx *sa_ipx; 1299 1300 sa_ipx = (struct sockaddr_ipx *)sa; 1301 check_sockaddr_len(ipx); 1302 /* XXX wish we had ipx_ntop */ 1303 printf("%s", ipx_ntoa(sa_ipx->sipx_addr)); 1304 break; 1305 } 1306 #endif 1307 case AF_UNIX: { 1308 struct sockaddr_un *sa_un; 1309 1310 sa_un = (struct sockaddr_un *)sa; 1311 if (sa_un->sun_len <= sizeof(sa_un->sun_len) + 1312 sizeof(sa_un->sun_family)) { 1313 printf("invalid"); 1314 break; 1315 } 1316 printf("\"%.*s\"", (int)(sa_un->sun_len - 1317 sizeof(sa_un->sun_len) - sizeof(sa_un->sun_family)), 1318 sa_un->sun_path); 1319 break; 1320 } 1321 default: 1322 printf("unknown address family"); 1323 } 1324 printf(" }\n"); 1325 } 1326 1327 static void 1328 print_time(time_t t, int relative) 1329 { 1330 char timestr[PATH_MAX + 4]; 1331 struct tm *tm; 1332 1333 if (resolv == 0 || relative) 1334 printf("%jd", (intmax_t)t); 1335 else { 1336 tm = localtime(&t); 1337 (void)strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); 1338 printf("\"%s\"", timestr); 1339 } 1340 } 1341 1342 static void 1343 print_timespec(const struct timespec *tsp, int relative) 1344 { 1345 print_time(tsp->tv_sec, relative); 1346 if (tsp->tv_nsec != 0) 1347 printf(".%09ld", tsp->tv_nsec); 1348 } 1349 1350 static void 1351 ktrstat(const struct stat *statp) 1352 { 1353 char mode[12]; 1354 struct passwd *pwd; 1355 struct group *grp; 1356 1357 /* 1358 * note: ktrstruct() has already verified that statp points to a 1359 * buffer exactly sizeof(struct stat) bytes long. 1360 */ 1361 printf("struct stat { "); 1362 strmode(statp->st_mode, mode); 1363 printf("dev=%d, ino=%u, mode=%s, nlink=%u, ", 1364 statp->st_dev, statp->st_ino, mode, statp->st_nlink); 1365 if (resolv == 0 || (pwd = getpwuid(statp->st_uid)) == NULL) 1366 printf("uid=%u, ", statp->st_uid); 1367 else 1368 printf("uid=\"%s\", ", pwd->pw_name); 1369 if (resolv == 0 || (grp = getgrgid(statp->st_gid)) == NULL) 1370 printf("gid=%u, ", statp->st_gid); 1371 else 1372 printf("gid=\"%s\", ", grp->gr_name); 1373 printf("rdev=%d, ", statp->st_rdev); 1374 printf("atime="); 1375 print_timespec(&statp->st_atim, 0); 1376 printf(", mtime="); 1377 print_timespec(&statp->st_mtim, 0); 1378 printf(", ctime="); 1379 print_timespec(&statp->st_ctim, 0); 1380 printf(", size=%lld, blocks=%lld, blksize=%u, flags=0x%x, gen=0x%x", 1381 statp->st_size, statp->st_blocks, statp->st_blksize, 1382 statp->st_flags, statp->st_gen); 1383 printf(" }\n"); 1384 } 1385 1386 static void 1387 ktrtimespec(const struct timespec *tsp, int relative) 1388 { 1389 printf("struct timespec { "); 1390 print_timespec(tsp, relative); 1391 printf(" }\n"); 1392 } 1393 1394 static void 1395 ktrtimeval(const struct timeval *tvp, int relative) 1396 { 1397 printf("struct timeval { "); 1398 print_time(tvp->tv_sec, relative); 1399 if (tvp->tv_usec != 0) 1400 printf(".%06ld", tvp->tv_usec); 1401 printf(" }\n"); 1402 } 1403 1404 static void 1405 ktrsigaction(const struct sigaction *sa) 1406 { 1407 /* 1408 * note: ktrstruct() has already verified that sa points to a 1409 * buffer exactly sizeof(struct sigaction) bytes long. 1410 */ 1411 printf("struct sigaction { "); 1412 if (sa->sa_handler == SIG_DFL) 1413 printf("handler=SIG_DFL"); 1414 else if (sa->sa_handler == SIG_IGN) 1415 printf("handler=SIG_IGN"); 1416 else if (sa->sa_flags & SA_SIGINFO) 1417 printf("sigaction=%p", (void *)sa->sa_sigaction); 1418 else 1419 printf("handler=%p", (void *)sa->sa_handler); 1420 printf(", mask="); 1421 sigset(sa->sa_mask); 1422 printf(", flags="); 1423 sigactionflagname(sa->sa_flags); 1424 printf(" }\n"); 1425 } 1426 1427 static void 1428 print_rlim(rlim_t lim) 1429 { 1430 if (lim == RLIM_INFINITY) 1431 printf("infinite"); 1432 else 1433 printf("%llu", (unsigned long long)lim); 1434 } 1435 1436 static void 1437 ktrrlimit(const struct rlimit *limp) 1438 { 1439 printf("struct rlimit { "); 1440 printf("cur="); 1441 print_rlim(limp->rlim_cur); 1442 printf(", max="); 1443 print_rlim(limp->rlim_max); 1444 printf(" }\n"); 1445 } 1446 1447 static void 1448 ktrtfork(const struct __tfork *tf) 1449 { 1450 printf("struct __tfork { tcb=%p, tid=%p, stack=%p }\n", 1451 tf->tf_tcb, (void *)tf->tf_tid, tf->tf_stack); 1452 } 1453 1454 static void 1455 ktrfdset(const struct fd_set *fds, int len) 1456 { 1457 int nfds, i, start = -1; 1458 char sep = ' '; 1459 1460 nfds = len * NBBY; 1461 printf("struct fd_set {"); 1462 for (i = 0; i <= nfds; i++) 1463 if (i != nfds && FD_ISSET(i, fds)) { 1464 if (start == -1) 1465 start = i; 1466 } else if (start != -1) { 1467 putchar(sep); 1468 if (start == i - 1) 1469 printf("%d", start); 1470 else if (start == i - 2) 1471 printf("%d,%d", start, i - 1); 1472 else 1473 printf("%d-%d", start, i - 1); 1474 sep = ','; 1475 start = -1; 1476 } 1477 1478 printf(" }\n"); 1479 } 1480 1481 static void 1482 ktrstruct(char *buf, size_t buflen) 1483 { 1484 char *name, *data; 1485 size_t namelen, datalen; 1486 int i; 1487 1488 for (name = buf, namelen = 0; namelen < buflen && name[namelen] != '\0'; 1489 ++namelen) 1490 /* nothing */; 1491 if (namelen == buflen) 1492 goto invalid; 1493 if (name[namelen] != '\0') 1494 goto invalid; 1495 data = buf + namelen + 1; 1496 datalen = buflen - namelen - 1; 1497 if (datalen == 0) 1498 goto invalid; 1499 /* sanity check */ 1500 for (i = 0; i < namelen; ++i) 1501 if (!isalpha((unsigned char)name[i])) 1502 goto invalid; 1503 if (strcmp(name, "stat") == 0) { 1504 struct stat sb; 1505 1506 if (datalen != sizeof(struct stat)) 1507 goto invalid; 1508 memcpy(&sb, data, datalen); 1509 ktrstat(&sb); 1510 } else if (strcmp(name, "sockaddr") == 0) { 1511 struct sockaddr_storage ss; 1512 1513 if (datalen > sizeof(ss)) 1514 goto invalid; 1515 memcpy(&ss, data, datalen); 1516 if ((ss.ss_family != AF_UNIX && 1517 datalen < sizeof(struct sockaddr)) || datalen != ss.ss_len) 1518 goto invalid; 1519 ktrsockaddr((struct sockaddr *)&ss); 1520 } else if (strcmp(name, "abstimespec") == 0 || 1521 strcmp(name, "reltimespec") == 0) { 1522 struct timespec ts; 1523 1524 if (datalen != sizeof(ts)) 1525 goto invalid; 1526 memcpy(&ts, data, datalen); 1527 ktrtimespec(&ts, name[0] == 'r'); 1528 } else if (strcmp(name, "abstimeval") == 0 || 1529 strcmp(name, "reltimeval") == 0) { 1530 struct timeval tv; 1531 1532 if (datalen != sizeof(tv)) 1533 goto invalid; 1534 memcpy(&tv, data, datalen); 1535 ktrtimeval(&tv, name[0] == 'r'); 1536 } else if (strcmp(name, "sigaction") == 0) { 1537 struct sigaction sa; 1538 1539 if (datalen != sizeof(sa)) 1540 goto invalid; 1541 memcpy(&sa, data, datalen); 1542 ktrsigaction(&sa); 1543 } else if (strcmp(name, "rlimit") == 0) { 1544 struct rlimit lim; 1545 1546 if (datalen != sizeof(lim)) 1547 goto invalid; 1548 memcpy(&lim, data, datalen); 1549 ktrrlimit(&lim); 1550 } else if (strcmp(name, "tfork") == 0) { 1551 struct __tfork tf; 1552 1553 if (datalen != sizeof(tf)) 1554 goto invalid; 1555 memcpy(&tf, data, datalen); 1556 ktrtfork(&tf); 1557 } else if (strcmp(name, "fdset") == 0) { 1558 struct fd_set *fds; 1559 if ((fds = malloc(datalen)) == NULL) 1560 err(1, "malloc"); 1561 memcpy(fds, data, datalen); 1562 ktrfdset(fds, datalen); 1563 free(fds); 1564 } else { 1565 printf("unknown structure %s\n", name); 1566 } 1567 return; 1568 invalid: 1569 printf("invalid record\n"); 1570 } 1571 1572 static void 1573 usage(void) 1574 { 1575 1576 extern char *__progname; 1577 fprintf(stderr, "usage: %s " 1578 "[-dHlnRrTXx] [-e emulation] [-f file] [-m maxdata] [-p pid]\n" 1579 "%*s[-t [ceinsw]]\n", 1580 __progname, (int)(sizeof("usage: ") + strlen(__progname)), ""); 1581 exit(1); 1582 } 1583 1584 static void 1585 setemul(const char *name) 1586 { 1587 int i; 1588 1589 for (i = 0; emulations[i].name != NULL; i++) 1590 if (strcmp(emulations[i].name, name) == 0) { 1591 current = &emulations[i]; 1592 return; 1593 } 1594 warnx("Emulation `%s' unknown", name); 1595 } 1596 1597 static void 1598 atfd(int fd) 1599 { 1600 if (fd == AT_FDCWD) 1601 (void)printf("AT_FDCWD"); 1602 else if (decimal) 1603 (void)printf("%d", fd); 1604 else 1605 (void)printf("%#x", fd); 1606 } 1607