kdump.c revision 1.26 1 /* $NetBSD: kdump.c,v 1.26 2000/03/27 17:03:25 kleink 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.26 2000/03/27 17:03:25 kleink 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 ",
323 (long int)temp.tv_sec, (long int)temp.tv_usec);
324 }
325 (void)printf("%s ", type);
326 }
327
328 void
329 ioctldecode(cmd)
330 u_long cmd;
331 {
332 char dirbuf[4], *dir = dirbuf;
333
334 if (cmd & IOC_IN)
335 *dir++ = 'W';
336 if (cmd & IOC_OUT)
337 *dir++ = 'R';
338 *dir = '\0';
339
340 printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx",
341 dirbuf, (cmd >> 8) & 0xff, cmd & 0xff);
342 if ((cmd & IOC_VOID) == 0)
343 printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff);
344 else
345 printf(")");
346 }
347
348 void
349 ktrsyscall(ktr)
350 struct ktr_syscall *ktr;
351 {
352 int argsize = ktr->ktr_argsize;
353 register_t *ap;
354
355 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0)
356 (void)printf("[%d]", ktr->ktr_code);
357 else
358 (void)printf("%s", current->sysnames[ktr->ktr_code]);
359 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
360 if (argsize) {
361 char c = '(';
362 if (fancy) {
363 if (ktr->ktr_code == SYS_ioctl) {
364 char *cp;
365 if (decimal)
366 (void)printf("(%ld", (long)*ap);
367 else
368 (void)printf("(%#lx", (long)*ap);
369 ap++;
370 argsize -= sizeof(register_t);
371 if ((cp = ioctlname(*ap)) != NULL)
372 (void)printf(",%s", cp);
373 else
374 ioctldecode(*ap);
375 c = ',';
376 ap++;
377 argsize -= sizeof(register_t);
378 } else if (ktr->ktr_code == SYS_ptrace) {
379 if (*ap >= 0 && *ap <=
380 sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
381 (void)printf("(%s", ptrace_ops[*ap]);
382 else
383 (void)printf("(%ld", (long)*ap);
384 c = ',';
385 ap++;
386 argsize -= sizeof(register_t);
387 }
388 }
389 while (argsize) {
390 if (decimal)
391 (void)printf("%c%ld", c, (long)*ap);
392 else
393 (void)printf("%c%#lx", c, (long)*ap);
394 c = ',';
395 ap++;
396 argsize -= sizeof(register_t);
397 }
398 (void)putchar(')');
399 }
400 (void)putchar('\n');
401 }
402
403 void
404 ktrsysret(ktr)
405 struct ktr_sysret *ktr;
406 {
407 register_t ret = ktr->ktr_retval;
408 int error = ktr->ktr_error;
409 int code = ktr->ktr_code;
410
411 if (code >= current->nsysnames || code < 0)
412 (void)printf("[%d] ", code);
413 else
414 (void)printf("%s ", current->sysnames[code]);
415
416 switch (error) {
417 case 0:
418 if (fancy) {
419 (void)printf("%ld", (long)ret);
420 if (ret < 0 || ret > 9)
421 (void)printf("/%#lx", (long)ret);
422 } else {
423 if (decimal)
424 (void)printf("%ld", (long)ret);
425 else
426 (void)printf("%#lx", (long)ret);
427 }
428 break;
429
430 default:
431 eprint(error);
432 break;
433 }
434 (void)putchar('\n');
435
436 }
437
438 /*
439 * We print the original emulation's error numerically, but we
440 * translate it to netbsd to print it symbolically.
441 */
442 void
443 eprint(e)
444 int e;
445 {
446 int i = e;
447
448 if (current->errno) {
449
450 /* No remapping for ERESTART and EJUSTRETURN */
451 /* Kludge for linux that has negative error numbers */
452 if (current->errno[2] > 0 && e < 0)
453 goto normal;
454
455 for (i = 0; i < current->nerrno; i++)
456 if (e == current->errno[i])
457 break;
458
459 if (i == current->nerrno) {
460 printf("-1 unknown errno %d", e);
461 return;
462 }
463 }
464
465 normal:
466 switch (i) {
467 case ERESTART:
468 (void)printf("RESTART");
469 break;
470
471 case EJUSTRETURN:
472 (void)printf("JUSTRETURN");
473 break;
474
475 default:
476 (void)printf("-1 errno %d", e);
477 if (fancy)
478 (void)printf(" %s", strerror(i));
479 }
480 }
481
482 void
483 ktrnamei(cp, len)
484 char *cp;
485 int len;
486 {
487
488 (void)printf("\"%.*s\"\n", len, cp);
489 }
490
491 void
492 ktremul(cp, len)
493 char *cp;
494 int len;
495 {
496 char name[1024];
497
498 if (len >= sizeof(name))
499 errx(1, "Emulation name too long");
500
501 strncpy(name, cp, len);
502 name[len] = '\0';
503 (void)printf("\"%s\"\n", name);
504
505 setemul(name);
506 }
507
508 void
509 ktrgenio(ktr, len)
510 struct ktr_genio *ktr;
511 int len;
512 {
513 int datalen = len - sizeof (struct ktr_genio);
514 char *dp = (char *)ktr + sizeof (struct ktr_genio);
515 char *cp;
516 int col = 0;
517 int width;
518 char visbuf[5];
519 static int screenwidth = 0;
520
521 if (screenwidth == 0) {
522 struct winsize ws;
523
524 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
525 ws.ws_col > 8)
526 screenwidth = ws.ws_col;
527 else
528 screenwidth = 80;
529 }
530 printf("fd %d %s %d bytes\n", ktr->ktr_fd,
531 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
532 if (maxdata && datalen > maxdata)
533 datalen = maxdata;
534 (void)printf(" \"");
535 col = 8;
536 for (; datalen > 0; datalen--, dp++) {
537 (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
538 cp = visbuf;
539 /*
540 * Keep track of printables and
541 * space chars (like fold(1)).
542 */
543 if (col == 0) {
544 (void)putchar('\t');
545 col = 8;
546 }
547 switch(*cp) {
548 case '\n':
549 col = 0;
550 (void)putchar('\n');
551 continue;
552 case '\t':
553 width = 8 - (col&07);
554 break;
555 default:
556 width = strlen(cp);
557 }
558 if (col + width > (screenwidth-2)) {
559 (void)printf("\\\n\t");
560 col = 8;
561 }
562 col += width;
563 do {
564 (void)putchar(*cp++);
565 } while (*cp);
566 }
567 if (col == 0)
568 (void)printf(" ");
569 (void)printf("\"\n");
570 }
571
572 void
573 ktrpsig(psig)
574 struct ktr_psig *psig;
575 {
576 int signo, first;
577
578 (void)printf("SIG%s ", sys_signame[psig->signo]);
579 if (psig->action == SIG_DFL)
580 (void)printf("SIG_DFL\n");
581 else {
582 (void)printf("caught handler=0x%lx mask=(",
583 (u_long)psig->action);
584 first = 1;
585 for (signo = 1; signo < NSIG; signo++) {
586 if (sigismember(&psig->mask, signo)) {
587 if (first)
588 first = 0;
589 else
590 (void)printf(",");
591 (void)printf("%d", signo);
592 }
593 }
594 (void)printf(") code=0x%x\n", psig->code);
595 }
596 }
597
598 void
599 ktrcsw(cs)
600 struct ktr_csw *cs;
601 {
602
603 (void)printf("%s %s\n", cs->out ? "stop" : "resume",
604 cs->user ? "user" : "kernel");
605 }
606
607 void
608 usage()
609 {
610
611 (void)fprintf(stderr,
612 "usage: kdump [-dnlRT] [-e emulation] [-f trfile] [-m maxdata] [-t [cnis]]\n");
613 exit(1);
614 }
615
616 void
617 setemul(name)
618 char *name;
619 {
620 int i;
621
622 for (i = 0; emulations[i].name != NULL; i++)
623 if (strcmp(emulations[i].name, name) == 0) {
624 current = &emulations[i];
625 return;
626 }
627 warnx("Emulation `%s' unknown", name);
628 }
629