1 /* $OpenBSD: ktrstruct.c,v 1.22 2016/08/26 08:52:19 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/types.h> 33 #include <sys/resource.h> 34 #include <sys/socket.h> 35 #include <sys/select.h> 36 #include <sys/stat.h> 37 #include <sys/time.h> 38 #include <sys/event.h> 39 #include <sys/un.h> 40 #include <ufs/ufs/quota.h> 41 #include <netinet/in.h> 42 #include <arpa/inet.h> 43 44 #include <ctype.h> 45 #include <err.h> 46 #include <limits.h> 47 #include <netdb.h> 48 #include <poll.h> 49 #include <signal.h> 50 #include <stddef.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <stdint.h> 54 #include <string.h> 55 #include <grp.h> 56 #include <pwd.h> 57 #include <unistd.h> 58 #include <vis.h> 59 60 #include "kdump.h" 61 #include "kdump_subr.h" 62 63 #define TIME_FORMAT "%b %e %T %Y" 64 65 static void 66 ktrsockaddr(struct sockaddr *sa) 67 { 68 /* 69 * TODO: Support additional address families 70 * #include <netmpls/mpls.h> 71 * struct sockaddr_mpls *mpls; 72 */ 73 74 /* 75 * note: ktrstruct() has already verified that sa points to a 76 * buffer at least sizeof(struct sockaddr) bytes long and exactly 77 * sa->sa_len bytes long. 78 */ 79 printf("struct sockaddr { "); 80 sockfamilyname(sa->sa_family); 81 printf(", "); 82 83 #define check_sockaddr_len(n) \ 84 if (sa_##n->s##n##_len < sizeof(struct sockaddr_##n)) { \ 85 printf("invalid"); \ 86 break; \ 87 } 88 89 switch(sa->sa_family) { 90 case AF_INET: { 91 struct sockaddr_in *sa_in; 92 char addr[64]; 93 94 sa_in = (struct sockaddr_in *)sa; 95 check_sockaddr_len(in); 96 inet_ntop(AF_INET, &sa_in->sin_addr, addr, sizeof addr); 97 printf("%s:%u", addr, ntohs(sa_in->sin_port)); 98 break; 99 } 100 case AF_INET6: { 101 struct sockaddr_in6 *sa_in6; 102 char addr[64]; 103 104 sa_in6 = (struct sockaddr_in6 *)sa; 105 check_sockaddr_len(in6); 106 inet_ntop(AF_INET6, &sa_in6->sin6_addr, addr, sizeof addr); 107 printf("[%s]:%u", addr, htons(sa_in6->sin6_port)); 108 break; 109 } 110 case AF_UNIX: { 111 struct sockaddr_un *sa_un; 112 char path[4 * sizeof(sa_un->sun_path) + 1]; 113 size_t len; 114 115 sa_un = (struct sockaddr_un *)sa; 116 len = sa_un->sun_len; 117 if (len <= offsetof(struct sockaddr_un, sun_path)) { 118 printf("invalid"); 119 break; 120 } 121 len -= offsetof(struct sockaddr_un, sun_path); 122 if (len > sizeof(sa_un->sun_path)) { 123 printf("too long"); 124 break; 125 } 126 /* format, stopping at first NUL */ 127 len = strnlen(sa_un->sun_path, len); 128 strvisx(path, sa_un->sun_path, len, 129 VIS_CSTYLE | VIS_DQ | VIS_TAB | VIS_NL); 130 printf("\"%s\"", path); 131 break; 132 } 133 default: 134 printf("unknown address family"); 135 } 136 printf(" }\n"); 137 } 138 139 static void 140 print_time(time_t t, int relative, int have_subsec) 141 { 142 char timestr[PATH_MAX + 4]; 143 struct tm *tm; 144 145 if (t < 0 && have_subsec) { 146 /* negative times with non-zero subsecs require care */ 147 printf("-%jd", -(intmax_t)(t + 1)); 148 } else 149 printf("%jd", (intmax_t)t); 150 151 /* 1970s times are probably relative */ 152 if (!relative && t > (10 * 365 * 24 * 3600)) { 153 tm = localtime(&t); 154 if (tm != NULL) { 155 (void)strftime(timestr, sizeof(timestr), TIME_FORMAT, 156 tm); 157 printf("<\"%s\">", timestr); 158 } 159 } 160 } 161 162 static void 163 print_timespec(const struct timespec *tsp, int relative) 164 { 165 if (tsp->tv_nsec == UTIME_NOW) 166 printf("UTIME_NOW"); 167 else if (tsp->tv_nsec == UTIME_OMIT) 168 printf("UTIME_OMIT"); 169 else { 170 print_time(tsp->tv_sec, relative, tsp->tv_nsec); 171 if (tsp->tv_nsec != 0) 172 printf(".%09ld", tsp->tv_sec >= 0 ? tsp->tv_nsec : 173 1000000000 - tsp->tv_nsec); 174 } 175 } 176 177 void 178 uidname(int uid) 179 { 180 const char *name; 181 182 if (uid == -1) 183 printf("-1"); 184 else { 185 printf("%u<", (unsigned)uid); 186 if (uid > UID_MAX || (name = user_from_uid(uid, 1)) == NULL) 187 printf("unknown>"); 188 else 189 printf("\"%s\">", name); 190 } 191 } 192 193 void 194 gidname(int gid) 195 { 196 const char *name; 197 198 if (gid == -1) 199 printf("-1"); 200 else { 201 printf("%u<", (unsigned)gid); 202 if (gid > GID_MAX || (name = group_from_gid(gid, 1)) == NULL) 203 printf("unknown>"); 204 else 205 printf("\"%s\">", name); 206 } 207 } 208 209 static void 210 ktrstat(const struct stat *statp) 211 { 212 char mode[12]; 213 214 /* 215 * note: ktrstruct() has already verified that statp points to a 216 * buffer exactly sizeof(struct stat) bytes long. 217 */ 218 printf("struct stat { "); 219 strmode(statp->st_mode, mode); 220 printf("dev=%d, ino=%llu, mode=%s, nlink=%u, uid=", 221 statp->st_dev, (unsigned long long)statp->st_ino, 222 mode, statp->st_nlink); 223 uidname(statp->st_uid); 224 printf(", gid="); 225 gidname(statp->st_gid); 226 printf(", rdev=%d, ", statp->st_rdev); 227 printf("atime="); 228 print_timespec(&statp->st_atim, 0); 229 printf(", mtime="); 230 print_timespec(&statp->st_mtim, 0); 231 printf(", ctime="); 232 print_timespec(&statp->st_ctim, 0); 233 printf(", size=%lld, blocks=%lld, blksize=%d, flags=0x%x, gen=0x%x", 234 statp->st_size, statp->st_blocks, statp->st_blksize, 235 statp->st_flags, statp->st_gen); 236 printf(" }\n"); 237 } 238 239 static void 240 ktrtimespec(const struct timespec *tsp, int relative) 241 { 242 printf("struct timespec { "); 243 print_timespec(tsp, relative); 244 printf(" }\n"); 245 } 246 247 static void 248 print_timeval(const struct timeval *tvp, int relative) 249 { 250 print_time(tvp->tv_sec, relative, tvp->tv_usec); 251 if (tvp->tv_usec != 0) 252 printf(".%06ld", tvp->tv_sec >= 0 ? tvp->tv_usec : 253 1000000 - tvp->tv_usec); 254 } 255 256 static void 257 ktrtimeval(const struct timeval *tvp, int relative) 258 { 259 printf("struct timeval { "); 260 print_timeval(tvp, relative); 261 printf(" }\n"); 262 } 263 264 static void 265 ktrsigaction(const struct sigaction *sa) 266 { 267 /* 268 * note: ktrstruct() has already verified that sa points to a 269 * buffer exactly sizeof(struct sigaction) bytes long. 270 */ 271 /* 272 * Fuck! Comparison of function pointers on hppa assumes you can 273 * dereference them if they're plabels! Cast everything to void * 274 * to suppress that extra logic; sorry folks, the address we report 275 * here might not match what you see in your executable... 276 */ 277 printf("struct sigaction { "); 278 if ((void *)sa->sa_handler == (void *)SIG_DFL) 279 printf("handler=SIG_DFL"); 280 else if ((void *)sa->sa_handler == (void *)SIG_IGN) 281 printf("handler=SIG_IGN"); 282 else if (sa->sa_flags & SA_SIGINFO) 283 printf("sigaction=%p", (void *)sa->sa_sigaction); 284 else 285 printf("handler=%p", (void *)sa->sa_handler); 286 printf(", mask="); 287 sigset(sa->sa_mask); 288 printf(", flags="); 289 sigactionflagname(sa->sa_flags); 290 printf(" }\n"); 291 } 292 293 static void 294 print_rlim(rlim_t lim) 295 { 296 if (lim == RLIM_INFINITY) 297 printf("infinite"); 298 else 299 printf("%llu", (unsigned long long)lim); 300 } 301 302 static void 303 ktrrlimit(const struct rlimit *limp) 304 { 305 printf("struct rlimit { "); 306 printf("cur="); 307 print_rlim(limp->rlim_cur); 308 printf(", max="); 309 print_rlim(limp->rlim_max); 310 printf(" }\n"); 311 } 312 313 static void 314 ktrtfork(const struct __tfork *tf) 315 { 316 printf("struct __tfork { tcb=%p, tid=%p, stack=%p }\n", 317 tf->tf_tcb, (void *)tf->tf_tid, tf->tf_stack); 318 } 319 320 static void 321 ktrfdset(struct fd_set *fds, int len) 322 { 323 int nfds, i, start = -1; 324 char sep = ' '; 325 326 nfds = len * NBBY; 327 printf("struct fd_set {"); 328 for (i = 0; i <= nfds; i++) 329 if (i != nfds && FD_ISSET(i, fds)) { 330 if (start == -1) 331 start = i; 332 } else if (start != -1) { 333 putchar(sep); 334 if (start == i - 1) 335 printf("%d", start); 336 else if (start == i - 2) 337 printf("%d,%d", start, i - 1); 338 else 339 printf("%d-%d", start, i - 1); 340 sep = ','; 341 start = -1; 342 } 343 344 printf(" }\n"); 345 } 346 347 static void 348 ktrrusage(const struct rusage *rup) 349 { 350 printf("struct rusage { utime="); 351 print_timeval(&rup->ru_utime, 1); 352 printf(", stime="); 353 print_timeval(&rup->ru_stime, 1); 354 printf(", maxrss=%ld, ixrss=%ld, idrss=%ld, isrss=%ld," 355 " minflt=%ld, majflt=%ld, nswap=%ld, inblock=%ld," 356 " oublock=%ld, msgsnd=%ld, msgrcv=%ld, nsignals=%ld," 357 " nvcsw=%ld, nivcsw=%ld }\n", 358 rup->ru_maxrss, rup->ru_ixrss, rup->ru_idrss, rup->ru_isrss, 359 rup->ru_minflt, rup->ru_majflt, rup->ru_nswap, rup->ru_inblock, 360 rup->ru_oublock, rup->ru_msgsnd, rup->ru_msgrcv, rup->ru_nsignals, 361 rup->ru_nvcsw, rup->ru_nivcsw); 362 } 363 364 static void 365 ktrquota(const struct dqblk *quota) 366 { 367 printf("struct dqblk { bhardlimit=%u, bsoftlimit=%u, curblocks=%u," 368 " ihardlimit=%u, isoftlimit=%u, curinodes=%u, btime=", 369 quota->dqb_bhardlimit, quota->dqb_bsoftlimit, 370 quota->dqb_curblocks, quota->dqb_ihardlimit, 371 quota->dqb_isoftlimit, quota->dqb_curinodes); 372 print_time(quota->dqb_btime, 0, 0); 373 printf(", itime="); 374 print_time(quota->dqb_itime, 0, 0); 375 printf(" }\n"); 376 } 377 378 static void 379 ktrmsghdr(const struct msghdr *msg) 380 { 381 printf("struct msghdr { name=%p, namelen=%u, iov=%p, iovlen=%u," 382 " control=%p, controllen=%u, flags=", 383 msg->msg_name, msg->msg_namelen, msg->msg_iov, msg->msg_iovlen, 384 msg->msg_control, msg->msg_controllen); 385 sendrecvflagsname(msg->msg_flags); 386 printf(" }\n"); 387 } 388 389 static void 390 ktriovec(const char *data, int count) 391 { 392 struct iovec iov; 393 int i; 394 395 printf("struct iovec"); 396 if (count > 1) 397 printf(" [%d]", count); 398 for (i = 0; i < count; i++) { 399 memcpy(&iov, data, sizeof(iov)); 400 data += sizeof(iov); 401 printf(" { base=%p, len=%lu }", iov.iov_base, iov.iov_len); 402 } 403 printf("\n"); 404 } 405 406 static void 407 ktrevent(const char *data, int count) 408 { 409 struct kevent kev; 410 int i; 411 412 printf("struct kevent"); 413 if (count > 1) 414 printf(" [%d]", count); 415 for (i = 0; i < count; i++) { 416 memcpy(&kev, data, sizeof(kev)); 417 data += sizeof(kev); 418 printf(" { ident=%lu, filter=", kev.ident); 419 evfiltername(kev.filter); 420 printf(", flags="); 421 evflagsname(kev.flags); 422 printf(", fflags="); 423 evfflagsname(kev.filter, kev.fflags); 424 printf(", data=%llu", kev.data); 425 if ((kev.flags & EV_ERROR) && fancy) { 426 printf("<\"%s\">", strerror(kev.data)); 427 } 428 printf(", udata=%p }", kev.udata); 429 } 430 printf("\n"); 431 } 432 433 static void 434 ktrpollfd(const char *data, int count) 435 { 436 struct pollfd pfd; 437 int i; 438 439 printf("struct pollfd"); 440 if (count > 1) 441 printf(" [%d]", count); 442 for (i = 0; i < count; i++) { 443 memcpy(&pfd, data, sizeof(pfd)); 444 data += sizeof(pfd); 445 printf(" { fd=%d, events=", pfd.fd); 446 pollfdeventname(pfd.events); 447 printf(", revents="); 448 pollfdeventname(pfd.revents); 449 printf(" }"); 450 } 451 printf("\n"); 452 } 453 454 static void 455 ktrcmsghdr(char *data, socklen_t len) 456 { 457 struct msghdr msg; 458 struct cmsghdr *cmsg; 459 int i, count, *fds; 460 461 msg.msg_control = data; 462 msg.msg_controllen = len; 463 464 /* count the control messages */ 465 count = 0; 466 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 467 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 468 count++; 469 } 470 471 printf("struct cmsghdr"); 472 if (count > 1) 473 printf(" [%d]", count); 474 475 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 476 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 477 printf(" { len=%u, level=", cmsg->cmsg_len); 478 if (cmsg->cmsg_level == SOL_SOCKET) { 479 printf("SOL_SOCKET, type="); 480 switch (cmsg->cmsg_type) { 481 case SCM_RIGHTS: 482 printf("SCM_RIGHTS, data="); 483 fds = (int *)CMSG_DATA(cmsg); 484 for (i = 0; 485 cmsg->cmsg_len > CMSG_LEN(sizeof(int) * i); 486 i++) { 487 printf("%s%d", i ? "," : "", fds[i]); 488 } 489 break; 490 case SCM_TIMESTAMP: 491 default: 492 printf("%d", cmsg->cmsg_type); 493 break; 494 } 495 } else { 496 struct protoent *p = getprotobynumber(cmsg->cmsg_level); 497 498 printf("%u<%s>, type=%d", cmsg->cmsg_level, 499 p != NULL ? p->p_name : "unknown", cmsg->cmsg_type); 500 } 501 printf(" }"); 502 } 503 printf("\n"); 504 } 505 506 void 507 ktrstruct(char *buf, size_t buflen) 508 { 509 char *name, *data; 510 size_t namelen, datalen; 511 int i; 512 513 for (name = buf, namelen = 0; namelen < buflen && name[namelen] != '\0'; 514 ++namelen) 515 /* nothing */; 516 if (namelen == buflen) 517 goto invalid; 518 if (name[namelen] != '\0') 519 goto invalid; 520 data = buf + namelen + 1; 521 datalen = buflen - namelen - 1; 522 if (datalen == 0) 523 goto invalid; 524 /* sanity check */ 525 for (i = 0; i < namelen; ++i) 526 if (!isalpha((unsigned char)name[i])) 527 goto invalid; 528 if (strcmp(name, "stat") == 0) { 529 struct stat sb; 530 531 if (datalen != sizeof(struct stat)) 532 goto invalid; 533 memcpy(&sb, data, datalen); 534 ktrstat(&sb); 535 } else if (strcmp(name, "sockaddr") == 0) { 536 struct sockaddr_storage ss; 537 538 if (datalen > sizeof(ss)) 539 goto invalid; 540 memcpy(&ss, data, datalen); 541 if ((ss.ss_family != AF_UNIX && 542 datalen < sizeof(struct sockaddr)) || datalen != ss.ss_len) 543 goto invalid; 544 ktrsockaddr((struct sockaddr *)&ss); 545 } else if (strcmp(name, "abstimespec") == 0 || 546 strcmp(name, "reltimespec") == 0) { 547 struct timespec ts; 548 549 if (datalen != sizeof(ts)) 550 goto invalid; 551 memcpy(&ts, data, datalen); 552 ktrtimespec(&ts, name[0] == 'r'); 553 } else if (strcmp(name, "abstimeval") == 0 || 554 strcmp(name, "reltimeval") == 0) { 555 struct timeval tv; 556 557 if (datalen != sizeof(tv)) 558 goto invalid; 559 memcpy(&tv, data, datalen); 560 ktrtimeval(&tv, name[0] == 'r'); 561 } else if (strcmp(name, "sigaction") == 0) { 562 struct sigaction sa; 563 564 if (datalen != sizeof(sa)) 565 goto invalid; 566 memcpy(&sa, data, datalen); 567 ktrsigaction(&sa); 568 } else if (strcmp(name, "rlimit") == 0) { 569 struct rlimit lim; 570 571 if (datalen != sizeof(lim)) 572 goto invalid; 573 memcpy(&lim, data, datalen); 574 ktrrlimit(&lim); 575 } else if (strcmp(name, "rusage") == 0) { 576 struct rusage ru; 577 578 if (datalen != sizeof(ru)) 579 goto invalid; 580 memcpy(&ru, data, datalen); 581 ktrrusage(&ru); 582 } else if (strcmp(name, "tfork") == 0) { 583 struct __tfork tf; 584 585 if (datalen != sizeof(tf)) 586 goto invalid; 587 memcpy(&tf, data, datalen); 588 ktrtfork(&tf); 589 } else if (strcmp(name, "fdset") == 0) { 590 struct fd_set *fds; 591 592 if ((fds = malloc(datalen)) == NULL) 593 err(1, "malloc"); 594 memcpy(fds, data, datalen); 595 ktrfdset(fds, datalen); 596 free(fds); 597 } else if (strcmp(name, "quota") == 0) { 598 struct dqblk quota; 599 600 if (datalen != sizeof(quota)) 601 goto invalid; 602 memcpy("a, data, datalen); 603 ktrquota("a); 604 } else if (strcmp(name, "msghdr") == 0) { 605 struct msghdr msg; 606 607 if (datalen != sizeof(msg)) 608 goto invalid; 609 memcpy(&msg, data, datalen); 610 ktrmsghdr(&msg); 611 } else if (strcmp(name, "iovec") == 0) { 612 if (datalen % sizeof(struct iovec)) 613 goto invalid; 614 ktriovec(data, datalen / sizeof(struct iovec)); 615 } else if (strcmp(name, "kevent") == 0) { 616 if (datalen % sizeof(struct kevent)) 617 goto invalid; 618 ktrevent(data, datalen / sizeof(struct kevent)); 619 } else if (strcmp(name, "pollfd") == 0) { 620 if (datalen % sizeof(struct pollfd)) 621 goto invalid; 622 ktrpollfd(data, datalen / sizeof(struct pollfd)); 623 } else if (strcmp(name, "cmsghdr") == 0) { 624 char *cmsg; 625 626 if ((cmsg = malloc(datalen)) == NULL) 627 err(1, "malloc"); 628 memcpy(cmsg, data, datalen); 629 ktrcmsghdr(cmsg, datalen); 630 free(cmsg); 631 } else if (strcmp(name, "pledgereq") == 0) { 632 printf("pledge request="); 633 showbufc(basecol + sizeof("pledge request=") - 1, 634 (unsigned char *)data, datalen, VIS_DQ | VIS_TAB | VIS_NL); 635 } else if (strcmp(name, "pledgepath") == 0) { 636 printf("pledge path="); 637 showbufc(basecol + sizeof("pledge path=") - 1, 638 (unsigned char *)data, datalen, VIS_DQ | VIS_TAB | VIS_NL); 639 } else { 640 printf("unknown structure %s\n", name); 641 } 642 return; 643 invalid: 644 printf("invalid record\n"); 645 } 646