1 /* $OpenBSD: ktrstruct.c,v 1.5 2014/07/11 21:49:13 tedu 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/stat.h> 36 #include <sys/time.h> 37 #include <sys/un.h> 38 #include <netinet/in.h> 39 #include <arpa/inet.h> 40 41 #include <ctype.h> 42 #include <err.h> 43 #include <limits.h> 44 #include <poll.h> 45 #include <signal.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <stdint.h> 49 #include <string.h> 50 #include <grp.h> 51 #include <pwd.h> 52 #include <unistd.h> 53 54 #include "kdump.h" 55 #include "kdump_subr.h" 56 57 #define TIME_FORMAT "%b %e %T %Y" 58 59 static void 60 ktrsockaddr(struct sockaddr *sa) 61 { 62 /* 63 TODO: Support additional address families 64 #include <netmpls/mpls.h> 65 struct sockaddr_mpls *mpls; 66 */ 67 char addr[64]; 68 69 /* 70 * note: ktrstruct() has already verified that sa points to a 71 * buffer at least sizeof(struct sockaddr) bytes long and exactly 72 * sa->sa_len bytes long. 73 */ 74 printf("struct sockaddr { "); 75 sockfamilyname(sa->sa_family); 76 printf(", "); 77 78 #define check_sockaddr_len(n) \ 79 if (sa_##n->s##n##_len < sizeof(struct sockaddr_##n)) { \ 80 printf("invalid"); \ 81 break; \ 82 } 83 84 switch(sa->sa_family) { 85 case AF_INET: { 86 struct sockaddr_in *sa_in; 87 88 sa_in = (struct sockaddr_in *)sa; 89 check_sockaddr_len(in); 90 inet_ntop(AF_INET, &sa_in->sin_addr, addr, sizeof addr); 91 printf("%s:%u", addr, ntohs(sa_in->sin_port)); 92 break; 93 } 94 case AF_INET6: { 95 struct sockaddr_in6 *sa_in6; 96 97 sa_in6 = (struct sockaddr_in6 *)sa; 98 check_sockaddr_len(in6); 99 inet_ntop(AF_INET6, &sa_in6->sin6_addr, addr, sizeof addr); 100 printf("[%s]:%u", addr, htons(sa_in6->sin6_port)); 101 break; 102 } 103 #ifdef IPX 104 case AF_IPX: { 105 struct sockaddr_ipx *sa_ipx; 106 107 sa_ipx = (struct sockaddr_ipx *)sa; 108 check_sockaddr_len(ipx); 109 /* XXX wish we had ipx_ntop */ 110 printf("%s", ipx_ntoa(sa_ipx->sipx_addr)); 111 break; 112 } 113 #endif 114 case AF_UNIX: { 115 struct sockaddr_un *sa_un; 116 117 sa_un = (struct sockaddr_un *)sa; 118 if (sa_un->sun_len <= sizeof(sa_un->sun_len) + 119 sizeof(sa_un->sun_family)) { 120 printf("invalid"); 121 break; 122 } 123 printf("\"%.*s\"", (int)(sa_un->sun_len - 124 sizeof(sa_un->sun_len) - sizeof(sa_un->sun_family)), 125 sa_un->sun_path); 126 break; 127 } 128 default: 129 printf("unknown address family"); 130 } 131 printf(" }\n"); 132 } 133 134 static void 135 print_time(time_t t, int relative) 136 { 137 char timestr[PATH_MAX + 4]; 138 struct tm *tm; 139 140 if (resolv == 0 || relative) 141 printf("%jd", (intmax_t)t); 142 else { 143 tm = localtime(&t); 144 (void)strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); 145 printf("\"%s\"", timestr); 146 } 147 } 148 149 static void 150 print_timespec(const struct timespec *tsp, int relative) 151 { 152 if (tsp->tv_nsec == UTIME_NOW) 153 printf("UTIME_NOW"); 154 else if (tsp->tv_nsec == UTIME_OMIT) 155 printf("UTIME_OMIT"); 156 else if ((resolv == 0 || relative) && tsp->tv_sec < 0 && 157 tsp->tv_nsec > 0) { 158 /* negative relative times with non-zero nsecs require care */ 159 printf("-%jd.%09ld", -(intmax_t)(tsp->tv_sec+1), 160 1000000000 - tsp->tv_nsec); 161 } else { 162 print_time(tsp->tv_sec, relative); 163 if (tsp->tv_nsec != 0) 164 printf(".%09ld", tsp->tv_nsec); 165 } 166 } 167 168 static void 169 ktrstat(const struct stat *statp) 170 { 171 char mode[12]; 172 struct passwd *pwd; 173 struct group *grp; 174 175 /* 176 * note: ktrstruct() has already verified that statp points to a 177 * buffer exactly sizeof(struct stat) bytes long. 178 */ 179 printf("struct stat { "); 180 strmode(statp->st_mode, mode); 181 printf("dev=%d, ino=%llu, mode=%s, nlink=%u, ", 182 statp->st_dev, (unsigned long long)statp->st_ino, 183 mode, statp->st_nlink); 184 if (resolv == 0 || (pwd = getpwuid(statp->st_uid)) == NULL) 185 printf("uid=%u, ", statp->st_uid); 186 else 187 printf("uid=\"%s\", ", pwd->pw_name); 188 if (resolv == 0 || (grp = getgrgid(statp->st_gid)) == NULL) 189 printf("gid=%u, ", statp->st_gid); 190 else 191 printf("gid=\"%s\", ", grp->gr_name); 192 printf("rdev=%d, ", statp->st_rdev); 193 printf("atime="); 194 print_timespec(&statp->st_atim, 0); 195 printf(", mtime="); 196 print_timespec(&statp->st_mtim, 0); 197 printf(", ctime="); 198 print_timespec(&statp->st_ctim, 0); 199 printf(", size=%lld, blocks=%lld, blksize=%u, flags=0x%x, gen=0x%x", 200 statp->st_size, statp->st_blocks, statp->st_blksize, 201 statp->st_flags, statp->st_gen); 202 printf(" }\n"); 203 } 204 205 static void 206 ktrtimespec(const struct timespec *tsp, int relative) 207 { 208 printf("struct timespec { "); 209 print_timespec(tsp, relative); 210 printf(" }\n"); 211 } 212 213 static void 214 print_timeval(const struct timeval *tvp, int relative) 215 { 216 if ((resolv == 0 || relative) && tvp->tv_sec < 0 && 217 tvp->tv_usec > 0) { 218 /* negative relative times with non-zero usecs require care */ 219 printf("-%jd.%06ld", -(intmax_t)(tvp->tv_sec+1), 220 1000000 - tvp->tv_usec); 221 } else { 222 print_time(tvp->tv_sec, relative); 223 if (tvp->tv_usec != 0) 224 printf(".%06ld", tvp->tv_usec); 225 } 226 } 227 228 static void 229 ktrtimeval(const struct timeval *tvp, int relative) 230 { 231 printf("struct timeval { "); 232 print_timeval(tvp, relative); 233 printf(" }\n"); 234 } 235 236 static void 237 ktrsigaction(const struct sigaction *sa) 238 { 239 /* 240 * note: ktrstruct() has already verified that sa points to a 241 * buffer exactly sizeof(struct sigaction) bytes long. 242 */ 243 printf("struct sigaction { "); 244 if (sa->sa_handler == SIG_DFL) 245 printf("handler=SIG_DFL"); 246 else if (sa->sa_handler == SIG_IGN) 247 printf("handler=SIG_IGN"); 248 else if (sa->sa_flags & SA_SIGINFO) 249 printf("sigaction=%p", (void *)sa->sa_sigaction); 250 else 251 printf("handler=%p", (void *)sa->sa_handler); 252 printf(", mask="); 253 sigset(sa->sa_mask); 254 printf(", flags="); 255 sigactionflagname(sa->sa_flags); 256 printf(" }\n"); 257 } 258 259 static void 260 print_rlim(rlim_t lim) 261 { 262 if (lim == RLIM_INFINITY) 263 printf("infinite"); 264 else 265 printf("%llu", (unsigned long long)lim); 266 } 267 268 static void 269 ktrrlimit(const struct rlimit *limp) 270 { 271 printf("struct rlimit { "); 272 printf("cur="); 273 print_rlim(limp->rlim_cur); 274 printf(", max="); 275 print_rlim(limp->rlim_max); 276 printf(" }\n"); 277 } 278 279 static void 280 ktrtfork(const struct __tfork *tf) 281 { 282 printf("struct __tfork { tcb=%p, tid=%p, stack=%p }\n", 283 tf->tf_tcb, (void *)tf->tf_tid, tf->tf_stack); 284 } 285 286 static void 287 ktrfdset(const struct fd_set *fds, int len) 288 { 289 int nfds, i, start = -1; 290 char sep = ' '; 291 292 nfds = len * NBBY; 293 printf("struct fd_set {"); 294 for (i = 0; i <= nfds; i++) 295 if (i != nfds && FD_ISSET(i, fds)) { 296 if (start == -1) 297 start = i; 298 } else if (start != -1) { 299 putchar(sep); 300 if (start == i - 1) 301 printf("%d", start); 302 else if (start == i - 2) 303 printf("%d,%d", start, i - 1); 304 else 305 printf("%d-%d", start, i - 1); 306 sep = ','; 307 start = -1; 308 } 309 310 printf(" }\n"); 311 } 312 313 static void 314 ktrrusage(const struct rusage *rup) 315 { 316 printf("struct rusage { utime="); 317 print_timeval(&rup->ru_utime, 1); 318 printf(", stime="); 319 print_timeval(&rup->ru_stime, 1); 320 printf(", maxrss=%ld, ixrss=%ld, idrss=%ld, isrss=%ld," 321 " minflt=%ld, majflt=%ld, nswap=%ld, inblock=%ld," 322 " oublock=%ld, msgsnd=%ld, msgrcv=%ld, nsignals=%ld," 323 " nvcsw=%ld, nivcsw=%ld }\n", 324 rup->ru_maxrss, rup->ru_ixrss, rup->ru_idrss, rup->ru_isrss, 325 rup->ru_minflt, rup->ru_majflt, rup->ru_nswap, rup->ru_inblock, 326 rup->ru_oublock, rup->ru_msgsnd, rup->ru_msgrcv, rup->ru_nsignals, 327 rup->ru_nvcsw, rup->ru_nivcsw); 328 } 329 330 void 331 ktrstruct(char *buf, size_t buflen) 332 { 333 char *name, *data; 334 size_t namelen, datalen; 335 int i; 336 337 for (name = buf, namelen = 0; namelen < buflen && name[namelen] != '\0'; 338 ++namelen) 339 /* nothing */; 340 if (namelen == buflen) 341 goto invalid; 342 if (name[namelen] != '\0') 343 goto invalid; 344 data = buf + namelen + 1; 345 datalen = buflen - namelen - 1; 346 if (datalen == 0) 347 goto invalid; 348 /* sanity check */ 349 for (i = 0; i < namelen; ++i) 350 if (!isalpha((unsigned char)name[i])) 351 goto invalid; 352 if (strcmp(name, "stat") == 0) { 353 struct stat sb; 354 355 if (datalen != sizeof(struct stat)) 356 goto invalid; 357 memcpy(&sb, data, datalen); 358 ktrstat(&sb); 359 } else if (strcmp(name, "sockaddr") == 0) { 360 struct sockaddr_storage ss; 361 362 if (datalen > sizeof(ss)) 363 goto invalid; 364 memcpy(&ss, data, datalen); 365 if ((ss.ss_family != AF_UNIX && 366 datalen < sizeof(struct sockaddr)) || datalen != ss.ss_len) 367 goto invalid; 368 ktrsockaddr((struct sockaddr *)&ss); 369 } else if (strcmp(name, "abstimespec") == 0 || 370 strcmp(name, "reltimespec") == 0) { 371 struct timespec ts; 372 373 if (datalen != sizeof(ts)) 374 goto invalid; 375 memcpy(&ts, data, datalen); 376 ktrtimespec(&ts, name[0] == 'r'); 377 } else if (strcmp(name, "abstimeval") == 0 || 378 strcmp(name, "reltimeval") == 0) { 379 struct timeval tv; 380 381 if (datalen != sizeof(tv)) 382 goto invalid; 383 memcpy(&tv, data, datalen); 384 ktrtimeval(&tv, name[0] == 'r'); 385 } else if (strcmp(name, "sigaction") == 0) { 386 struct sigaction sa; 387 388 if (datalen != sizeof(sa)) 389 goto invalid; 390 memcpy(&sa, data, datalen); 391 ktrsigaction(&sa); 392 } else if (strcmp(name, "rlimit") == 0) { 393 struct rlimit lim; 394 395 if (datalen != sizeof(lim)) 396 goto invalid; 397 memcpy(&lim, data, datalen); 398 ktrrlimit(&lim); 399 } else if (strcmp(name, "rusage") == 0) { 400 struct rusage ru; 401 402 if (datalen != sizeof(ru)) 403 goto invalid; 404 memcpy(&ru, data, datalen); 405 ktrrusage(&ru); 406 } else if (strcmp(name, "tfork") == 0) { 407 struct __tfork tf; 408 409 if (datalen != sizeof(tf)) 410 goto invalid; 411 memcpy(&tf, data, datalen); 412 ktrtfork(&tf); 413 } else if (strcmp(name, "fdset") == 0) { 414 struct fd_set *fds; 415 if ((fds = malloc(datalen)) == NULL) 416 err(1, "malloc"); 417 memcpy(fds, data, datalen); 418 ktrfdset(fds, datalen); 419 free(fds); 420 } else { 421 printf("unknown structure %s\n", name); 422 } 423 return; 424 invalid: 425 printf("invalid record\n"); 426 } 427