kdump.c revision 1.25 1 /* $NetBSD: kdump.c,v 1.25 1999/12/31 22:27:59 eeh 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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95";
45 #else
46 __RCSID("$NetBSD: kdump.c,v 1.25 1999/12/31 22:27:59 eeh Exp $");
47 #endif
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #define _KERNEL
52 #include <sys/errno.h>
53 #undef _KERNEL
54 #include <sys/time.h>
55 #include <sys/uio.h>
56 #include <sys/ktrace.h>
57 #include <sys/ioctl.h>
58 #include <sys/ptrace.h>
59
60 #include <err.h>
61 #include <signal.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include <vis.h>
67
68 #include "ktrace.h"
69
70 int timestamp, decimal, fancy = 1, tail, maxdata;
71 char *tracefile = DEF_TRACEFILE;
72 struct ktr_header ktr_header;
73
74 #define eqs(s1, s2) (strcmp((s1), (s2)) == 0)
75
76 #include <sys/syscall.h>
77
78 #include "../../sys/compat/netbsd32/netbsd32_syscall.h"
79 #include "../../sys/compat/freebsd/freebsd_syscall.h"
80 #include "../../sys/compat/hpux/hpux_syscall.h"
81 #include "../../sys/compat/ibcs2/ibcs2_syscall.h"
82 #include "../../sys/compat/linux/linux_syscall.h"
83 #include "../../sys/compat/osf1/osf1_syscall.h"
84 #include "../../sys/compat/sunos/sunos_syscall.h"
85 #include "../../sys/compat/svr4/svr4_syscall.h"
86 #include "../../sys/compat/ultrix/ultrix_syscall.h"
87
88 #define KTRACE
89 #include "../../sys/kern/syscalls.c"
90
91 #include "../../sys/compat/netbsd32/netbsd32_syscalls.c"
92 #include "../../sys/compat/freebsd/freebsd_syscalls.c"
93 #include "../../sys/compat/hpux/hpux_syscalls.c"
94 #include "../../sys/compat/ibcs2/ibcs2_syscalls.c"
95 #include "../../sys/compat/linux/linux_syscalls.c"
96 #include "../../sys/compat/osf1/osf1_syscalls.c"
97 #include "../../sys/compat/sunos/sunos_syscalls.c"
98 #include "../../sys/compat/svr4/svr4_syscalls.c"
99 #include "../../sys/compat/ultrix/ultrix_syscalls.c"
100
101 #include "../../sys/compat/hpux/hpux_errno.c"
102 #include "../../sys/compat/svr4/svr4_errno.c"
103 #include "../../sys/compat/ibcs2/ibcs2_errno.c"
104 #include "../../sys/compat/linux/common/linux_errno.c"
105 #undef KTRACE
106
107 struct emulation {
108 char *name; /* Emulation name */
109 char **sysnames; /* Array of system call names */
110 int nsysnames; /* Number of */
111 int *errno; /* Array of error number mapping */
112 int nerrno; /* number of elements in array */
113 };
114
115 #define NELEM(a) (sizeof(a) / sizeof(a[0]))
116
117 static struct emulation emulations[] = {
118 { "netbsd", syscallnames, SYS_MAXSYSCALL,
119 NULL, 0 },
120 { "netbsd32", netbsd32_syscallnames, SYS_MAXSYSCALL,
121 NULL, 0 },
122 { "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL,
123 NULL, 0 },
124 { "hpux", hpux_syscallnames, HPUX_SYS_MAXSYSCALL,
125 native_to_hpux_errno, NELEM(native_to_hpux_errno) },
126 { "ibcs2", ibcs2_syscallnames, IBCS2_SYS_MAXSYSCALL,
127 native_to_ibcs2_errno, NELEM(native_to_ibcs2_errno) },
128 { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL,
129 native_to_linux_errno, NELEM(native_to_linux_errno) },
130 { "osf1", osf1_syscallnames, OSF1_SYS_MAXSYSCALL,
131 NULL, 0 },
132 { "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL,
133 NULL, 0 },
134 { "svr4", svr4_syscallnames, SVR4_SYS_MAXSYSCALL,
135 native_to_svr4_errno, NELEM(native_to_svr4_errno) },
136 { "ultrix", ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL,
137 NULL, 0 },
138 { NULL, NULL, 0,
139 NULL, 0 }
140 };
141
142 struct emulation *current;
143
144 static const char *ptrace_ops[] = {
145 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U",
146 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE",
147 "PT_KILL", "PT_ATTACH", "PT_DETACH",
148 };
149
150 int main __P((int, char **));
151 int fread_tail __P((char *, int, int));
152 void dumpheader __P((struct ktr_header *));
153 void ioctldecode __P((u_long));
154 void ktrsyscall __P((struct ktr_syscall *));
155 void ktrsysret __P((struct ktr_sysret *));
156 void ktrnamei __P((char *, int));
157 void ktremul __P((char *, int));
158 void ktrgenio __P((struct ktr_genio *, int));
159 void ktrpsig __P((struct ktr_psig *));
160 void ktrcsw __P((struct ktr_csw *));
161 void usage __P((void));
162 void setemul __P((char *));
163 void eprint __P((int));
164 char *ioctlname __P((long));
165
166 int
167 main(argc, argv)
168 int argc;
169 char *argv[];
170 {
171 int ch, ktrlen, size;
172 void *m;
173 int trpoints = ALL_POINTS;
174
175 current = &emulations[0]; /* NetBSD */
176
177 while ((ch = getopt(argc, argv, "e:f:dlm:nRTt:")) != -1)
178 switch (ch) {
179 case 'e':
180 setemul(optarg);
181 break;
182 case 'f':
183 tracefile = optarg;
184 break;
185 case 'd':
186 decimal = 1;
187 break;
188 case 'l':
189 tail = 1;
190 break;
191 case 'm':
192 maxdata = atoi(optarg);
193 break;
194 case 'n':
195 fancy = 0;
196 break;
197 case 'R':
198 timestamp = 2; /* relative timestamp */
199 break;
200 case 'T':
201 timestamp = 1;
202 break;
203 case 't':
204 trpoints = getpoints(optarg);
205 if (trpoints < 0)
206 errx(1, "unknown trace point in %s", optarg);
207 break;
208 default:
209 usage();
210 }
211 argv += optind;
212 argc -= optind;
213
214 if (argc > 1)
215 usage();
216
217 m = malloc(size = 1025);
218 if (m == NULL)
219 errx(1, "%s", strerror(ENOMEM));
220 if (!freopen(tracefile, "r", stdin))
221 err(1, "%s", tracefile);
222 while (fread_tail((char *)&ktr_header, sizeof(struct ktr_header), 1)) {
223 if (trpoints & (1<<ktr_header.ktr_type))
224 dumpheader(&ktr_header);
225 if ((ktrlen = ktr_header.ktr_len) < 0)
226 errx(1, "bogus length 0x%x", ktrlen);
227 if (ktrlen > size) {
228 m = (void *)realloc(m, ktrlen+1);
229 if (m == NULL)
230 errx(1, "%s", strerror(ENOMEM));
231 size = ktrlen;
232 }
233 if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
234 errx(1, "data too short");
235 if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
236 continue;
237 switch (ktr_header.ktr_type) {
238 case KTR_SYSCALL:
239 ktrsyscall((struct ktr_syscall *)m);
240 break;
241 case KTR_SYSRET:
242 ktrsysret((struct ktr_sysret *)m);
243 break;
244 case KTR_NAMEI:
245 ktrnamei(m, ktrlen);
246 break;
247 case KTR_GENIO:
248 ktrgenio((struct ktr_genio *)m, ktrlen);
249 break;
250 case KTR_PSIG:
251 ktrpsig((struct ktr_psig *)m);
252 break;
253 case KTR_CSW:
254 ktrcsw((struct ktr_csw *)m);
255 break;
256 case KTR_EMUL:
257 ktremul(m, ktrlen);
258 break;
259 }
260 if (tail)
261 (void)fflush(stdout);
262 }
263 return (0);
264 }
265
266 int
267 fread_tail(buf, size, num)
268 char *buf;
269 int num, size;
270 {
271 int i;
272
273 while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
274 (void)sleep(1);
275 clearerr(stdin);
276 }
277 return (i);
278 }
279
280 void
281 dumpheader(kth)
282 struct ktr_header *kth;
283 {
284 char unknown[64], *type;
285 static struct timeval prevtime;
286 struct timeval temp;
287
288 switch (kth->ktr_type) {
289 case KTR_SYSCALL:
290 type = "CALL";
291 break;
292 case KTR_SYSRET:
293 type = "RET ";
294 break;
295 case KTR_NAMEI:
296 type = "NAMI";
297 break;
298 case KTR_GENIO:
299 type = "GIO ";
300 break;
301 case KTR_PSIG:
302 type = "PSIG";
303 break;
304 case KTR_CSW:
305 type = "CSW";
306 break;
307 case KTR_EMUL:
308 type = "EMUL";
309 break;
310 default:
311 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
312 type = unknown;
313 }
314
315 (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
316 if (timestamp) {
317 if (timestamp == 2) {
318 timersub(&kth->ktr_time, &prevtime, &temp);
319 prevtime = kth->ktr_time;
320 } else
321 temp = kth->ktr_time;
322 (void)printf("%ld.%06ld ", temp.tv_sec, temp.tv_usec);
323 }
324 (void)printf("%s ", type);
325 }
326
327 void
328 ioctldecode(cmd)
329 u_long cmd;
330 {
331 char dirbuf[4], *dir = dirbuf;
332
333 if (cmd & IOC_IN)
334 *dir++ = 'W';
335 if (cmd & IOC_OUT)
336 *dir++ = 'R';
337 *dir = '\0';
338
339 printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx",
340 dirbuf, (cmd >> 8) & 0xff, cmd & 0xff);
341 if ((cmd & IOC_VOID) == 0)
342 printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff);
343 else
344 printf(")");
345 }
346
347 void
348 ktrsyscall(ktr)
349 struct ktr_syscall *ktr;
350 {
351 int argsize = ktr->ktr_argsize;
352 register_t *ap;
353
354 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0)
355 (void)printf("[%d]", ktr->ktr_code);
356 else
357 (void)printf("%s", current->sysnames[ktr->ktr_code]);
358 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
359 if (argsize) {
360 char c = '(';
361 if (fancy) {
362 if (ktr->ktr_code == SYS_ioctl) {
363 char *cp;
364 if (decimal)
365 (void)printf("(%ld", (long)*ap);
366 else
367 (void)printf("(%#lx", (long)*ap);
368 ap++;
369 argsize -= sizeof(register_t);
370 if ((cp = ioctlname(*ap)) != NULL)
371 (void)printf(",%s", cp);
372 else
373 ioctldecode(*ap);
374 c = ',';
375 ap++;
376 argsize -= sizeof(register_t);
377 } else if (ktr->ktr_code == SYS_ptrace) {
378 if (*ap >= 0 && *ap <=
379 sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
380 (void)printf("(%s", ptrace_ops[*ap]);
381 else
382 (void)printf("(%ld", (long)*ap);
383 c = ',';
384 ap++;
385 argsize -= sizeof(register_t);
386 }
387 }
388 while (argsize) {
389 if (decimal)
390 (void)printf("%c%ld", c, (long)*ap);
391 else
392 (void)printf("%c%#lx", c, (long)*ap);
393 c = ',';
394 ap++;
395 argsize -= sizeof(register_t);
396 }
397 (void)putchar(')');
398 }
399 (void)putchar('\n');
400 }
401
402 void
403 ktrsysret(ktr)
404 struct ktr_sysret *ktr;
405 {
406 register_t ret = ktr->ktr_retval;
407 int error = ktr->ktr_error;
408 int code = ktr->ktr_code;
409
410 if (code >= current->nsysnames || code < 0)
411 (void)printf("[%d] ", code);
412 else
413 (void)printf("%s ", current->sysnames[code]);
414
415 switch (error) {
416 case 0:
417 if (fancy) {
418 (void)printf("%ld", (long)ret);
419 if (ret < 0 || ret > 9)
420 (void)printf("/%#lx", (long)ret);
421 } else {
422 if (decimal)
423 (void)printf("%ld", (long)ret);
424 else
425 (void)printf("%#lx", (long)ret);
426 }
427 break;
428
429 default:
430 eprint(error);
431 break;
432 }
433 (void)putchar('\n');
434
435 }
436
437 /*
438 * We print the original emulation's error numerically, but we
439 * translate it to netbsd to print it symbolically.
440 */
441 void
442 eprint(e)
443 int e;
444 {
445 int i = e;
446
447 if (current->errno) {
448
449 /* No remapping for ERESTART and EJUSTRETURN */
450 /* Kludge for linux that has negative error numbers */
451 if (current->errno[2] > 0 && e < 0)
452 goto normal;
453
454 for (i = 0; i < current->nerrno; i++)
455 if (e == current->errno[i])
456 break;
457
458 if (i == current->nerrno) {
459 printf("-1 unknown errno %d", e);
460 return;
461 }
462 }
463
464 normal:
465 switch (i) {
466 case ERESTART:
467 (void)printf("RESTART");
468 break;
469
470 case EJUSTRETURN:
471 (void)printf("JUSTRETURN");
472 break;
473
474 default:
475 (void)printf("-1 errno %d", e);
476 if (fancy)
477 (void)printf(" %s", strerror(i));
478 }
479 }
480
481 void
482 ktrnamei(cp, len)
483 char *cp;
484 int len;
485 {
486
487 (void)printf("\"%.*s\"\n", len, cp);
488 }
489
490 void
491 ktremul(cp, len)
492 char *cp;
493 int len;
494 {
495 char name[1024];
496
497 if (len >= sizeof(name))
498 errx(1, "Emulation name too long");
499
500 strncpy(name, cp, len);
501 name[len] = '\0';
502 (void)printf("\"%s\"\n", name);
503
504 setemul(name);
505 }
506
507 void
508 ktrgenio(ktr, len)
509 struct ktr_genio *ktr;
510 int len;
511 {
512 int datalen = len - sizeof (struct ktr_genio);
513 char *dp = (char *)ktr + sizeof (struct ktr_genio);
514 char *cp;
515 int col = 0;
516 int width;
517 char visbuf[5];
518 static int screenwidth = 0;
519
520 if (screenwidth == 0) {
521 struct winsize ws;
522
523 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
524 ws.ws_col > 8)
525 screenwidth = ws.ws_col;
526 else
527 screenwidth = 80;
528 }
529 printf("fd %d %s %d bytes\n", ktr->ktr_fd,
530 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
531 if (maxdata && datalen > maxdata)
532 datalen = maxdata;
533 (void)printf(" \"");
534 col = 8;
535 for (; datalen > 0; datalen--, dp++) {
536 (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
537 cp = visbuf;
538 /*
539 * Keep track of printables and
540 * space chars (like fold(1)).
541 */
542 if (col == 0) {
543 (void)putchar('\t');
544 col = 8;
545 }
546 switch(*cp) {
547 case '\n':
548 col = 0;
549 (void)putchar('\n');
550 continue;
551 case '\t':
552 width = 8 - (col&07);
553 break;
554 default:
555 width = strlen(cp);
556 }
557 if (col + width > (screenwidth-2)) {
558 (void)printf("\\\n\t");
559 col = 8;
560 }
561 col += width;
562 do {
563 (void)putchar(*cp++);
564 } while (*cp);
565 }
566 if (col == 0)
567 (void)printf(" ");
568 (void)printf("\"\n");
569 }
570
571 void
572 ktrpsig(psig)
573 struct ktr_psig *psig;
574 {
575 int signo, first;
576
577 (void)printf("SIG%s ", sys_signame[psig->signo]);
578 if (psig->action == SIG_DFL)
579 (void)printf("SIG_DFL\n");
580 else {
581 (void)printf("caught handler=0x%lx mask=(",
582 (u_long)psig->action);
583 first = 1;
584 for (signo = 1; signo < NSIG; signo++) {
585 if (sigismember(&psig->mask, signo)) {
586 if (first)
587 first = 0;
588 else
589 (void)printf(",");
590 (void)printf("%d", signo);
591 }
592 }
593 (void)printf(") code=0x%x\n", psig->code);
594 }
595 }
596
597 void
598 ktrcsw(cs)
599 struct ktr_csw *cs;
600 {
601
602 (void)printf("%s %s\n", cs->out ? "stop" : "resume",
603 cs->user ? "user" : "kernel");
604 }
605
606 void
607 usage()
608 {
609
610 (void)fprintf(stderr,
611 "usage: kdump [-dnlRT] [-e emulation] [-f trfile] [-m maxdata] [-t [cnis]]\n");
612 exit(1);
613 }
614
615 void
616 setemul(name)
617 char *name;
618 {
619 int i;
620
621 for (i = 0; emulations[i].name != NULL; i++)
622 if (strcmp(emulations[i].name, name) == 0) {
623 current = &emulations[i];
624 return;
625 }
626 warnx("Emulation `%s' unknown", name);
627 }
628