kdump.c revision 1.27 1 /* $NetBSD: kdump.c,v 1.27 2000/04/10 07:58:30 jdolecek 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.27 2000/04/10 07:58:30 jdolecek 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 const 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 const 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 struct emulation_ctx {
116 pid_t pid;
117 struct emulation *emulation;
118 struct emulation_ctx *next;
119 };
120
121 #define NELEM(a) (sizeof(a) / sizeof(a[0]))
122
123 static struct emulation emulations[] = {
124 #define EMUL_NETBSD_IDX 0
125 { "netbsd", syscallnames, SYS_MAXSYSCALL,
126 NULL, 0 },
127 { "netbsd32", netbsd32_syscallnames, SYS_MAXSYSCALL,
128 NULL, 0 },
129 { "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL,
130 NULL, 0 },
131 { "hpux", hpux_syscallnames, HPUX_SYS_MAXSYSCALL,
132 native_to_hpux_errno, NELEM(native_to_hpux_errno) },
133 { "ibcs2", ibcs2_syscallnames, IBCS2_SYS_MAXSYSCALL,
134 native_to_ibcs2_errno, NELEM(native_to_ibcs2_errno) },
135 { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL,
136 native_to_linux_errno, NELEM(native_to_linux_errno) },
137 { "osf1", osf1_syscallnames, OSF1_SYS_MAXSYSCALL,
138 NULL, 0 },
139 { "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL,
140 NULL, 0 },
141 { "svr4", svr4_syscallnames, SVR4_SYS_MAXSYSCALL,
142 native_to_svr4_errno, NELEM(native_to_svr4_errno) },
143 { "ultrix", ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL,
144 NULL, 0 },
145 { NULL, NULL, 0,
146 NULL, 0 }
147 };
148
149 struct emulation *current, *default_emul;
150
151 struct emulation_ctx *current_ctx;
152 struct emulation_ctx *emul_ctx = NULL;
153
154 static const char *ptrace_ops[] = {
155 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U",
156 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE",
157 "PT_KILL", "PT_ATTACH", "PT_DETACH",
158 };
159
160 int main __P((int, char **));
161 int fread_tail __P((char *, int, int));
162 void dumpheader __P((struct ktr_header *));
163 void ioctldecode __P((u_long));
164 void ktrsyscall __P((struct ktr_syscall *));
165 void ktrsysret __P((struct ktr_sysret *));
166 void ktrnamei __P((char *, int));
167 void ktremul __P((char *, int, int));
168 void ktrgenio __P((struct ktr_genio *, int));
169 void ktrpsig __P((struct ktr_psig *));
170 void ktrcsw __P((struct ktr_csw *));
171 void usage __P((void));
172 void eprint __P((int));
173 char *ioctlname __P((long));
174
175 static struct emulation_ctx *ectx_find __P((pid_t));
176 static void ectx_update __P((pid_t, struct emulation *));
177 static void ectx_sanify __P((pid_t));
178
179 int
180 main(argc, argv)
181 int argc;
182 char *argv[];
183 {
184 int ch, ktrlen, size;
185 void *m;
186 int trpoints = ALL_POINTS;
187 const char *emul_name = "netbsd";
188
189 while ((ch = getopt(argc, argv, "e:f:dlm:nRTt:")) != -1)
190 switch (ch) {
191 case 'e':
192 emul_name = strdup(optarg); /* it's safer to copy it */
193 break;
194 case 'f':
195 tracefile = optarg;
196 break;
197 case 'd':
198 decimal = 1;
199 break;
200 case 'l':
201 tail = 1;
202 break;
203 case 'm':
204 maxdata = atoi(optarg);
205 break;
206 case 'n':
207 fancy = 0;
208 break;
209 case 'R':
210 timestamp = 2; /* relative timestamp */
211 break;
212 case 'T':
213 timestamp = 1;
214 break;
215 case 't':
216 trpoints = getpoints(optarg);
217 if (trpoints < 0)
218 errx(1, "unknown trace point in %s", optarg);
219 break;
220 default:
221 usage();
222 }
223 argv += optind;
224 argc -= optind;
225
226 if (argc > 1)
227 usage();
228
229 setemul(emul_name, 0, 0);
230 default_emul = current;
231
232 m = malloc(size = 1024);
233 if (m == NULL)
234 errx(1, "malloc: %s", strerror(ENOMEM));
235 if (!freopen(tracefile, "r", stdin))
236 err(1, "%s", tracefile);
237 while (fread_tail((char *)&ktr_header, sizeof(struct ktr_header), 1)) {
238 if (trpoints & (1<<ktr_header.ktr_type))
239 dumpheader(&ktr_header);
240 if ((ktrlen = ktr_header.ktr_len) < 0)
241 errx(1, "bogus length 0x%x", ktrlen);
242 if (ktrlen > size) {
243 while(ktrlen > size) size *= 2;
244 m = (void *)realloc(m, size);
245 if (m == NULL)
246 errx(1, "realloc: %s", strerror(ENOMEM));
247 }
248 if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
249 errx(1, "data too short");
250 if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
251 continue;
252
253 /* update context to match currently processed record */
254 ectx_sanify(ktr_header.ktr_pid);
255
256 switch (ktr_header.ktr_type) {
257 case KTR_SYSCALL:
258 ktrsyscall((struct ktr_syscall *)m);
259 break;
260 case KTR_SYSRET:
261 ktrsysret((struct ktr_sysret *)m);
262 break;
263 case KTR_NAMEI:
264 ktrnamei(m, ktrlen);
265 break;
266 case KTR_GENIO:
267 ktrgenio((struct ktr_genio *)m, ktrlen);
268 break;
269 case KTR_PSIG:
270 ktrpsig((struct ktr_psig *)m);
271 break;
272 case KTR_CSW:
273 ktrcsw((struct ktr_csw *)m);
274 break;
275 case KTR_EMUL:
276 ktremul(m, ktrlen, size);
277 break;
278 }
279 if (tail)
280 (void)fflush(stdout);
281 }
282 return (0);
283 }
284
285 int
286 fread_tail(buf, size, num)
287 char *buf;
288 int num, size;
289 {
290 int i;
291
292 while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
293 (void)sleep(1);
294 clearerr(stdin);
295 }
296 return (i);
297 }
298
299 void
300 dumpheader(kth)
301 struct ktr_header *kth;
302 {
303 char unknown[64], *type;
304 static struct timeval prevtime;
305 struct timeval temp;
306
307 switch (kth->ktr_type) {
308 case KTR_SYSCALL:
309 type = "CALL";
310 break;
311 case KTR_SYSRET:
312 type = "RET ";
313 break;
314 case KTR_NAMEI:
315 type = "NAMI";
316 break;
317 case KTR_GENIO:
318 type = "GIO ";
319 break;
320 case KTR_PSIG:
321 type = "PSIG";
322 break;
323 case KTR_CSW:
324 type = "CSW";
325 break;
326 case KTR_EMUL:
327 type = "EMUL";
328 break;
329 default:
330 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
331 type = unknown;
332 }
333
334 (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
335 if (timestamp) {
336 if (timestamp == 2) {
337 timersub(&kth->ktr_time, &prevtime, &temp);
338 prevtime = kth->ktr_time;
339 } else
340 temp = kth->ktr_time;
341 (void)printf("%ld.%06ld ",
342 (long int)temp.tv_sec, (long int)temp.tv_usec);
343 }
344 (void)printf("%s ", type);
345 }
346
347 void
348 ioctldecode(cmd)
349 u_long cmd;
350 {
351 char dirbuf[4], *dir = dirbuf;
352
353 if (cmd & IOC_IN)
354 *dir++ = 'W';
355 if (cmd & IOC_OUT)
356 *dir++ = 'R';
357 *dir = '\0';
358
359 printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx",
360 dirbuf, (cmd >> 8) & 0xff, cmd & 0xff);
361 if ((cmd & IOC_VOID) == 0)
362 printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff);
363 else
364 printf(")");
365 }
366
367 void
368 ktrsyscall(ktr)
369 struct ktr_syscall *ktr;
370 {
371 int argsize = ktr->ktr_argsize;
372 register_t *ap;
373
374 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0)
375 (void)printf("[%d]", ktr->ktr_code);
376 else
377 (void)printf("%s", current->sysnames[ktr->ktr_code]);
378 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
379 if (argsize) {
380 char c = '(';
381 if (fancy) {
382 if (ktr->ktr_code == SYS_ioctl) {
383 char *cp;
384 if (decimal)
385 (void)printf("(%ld", (long)*ap);
386 else
387 (void)printf("(%#lx", (long)*ap);
388 ap++;
389 argsize -= sizeof(register_t);
390 if ((cp = ioctlname(*ap)) != NULL)
391 (void)printf(",%s", cp);
392 else
393 ioctldecode(*ap);
394 c = ',';
395 ap++;
396 argsize -= sizeof(register_t);
397 } else if (ktr->ktr_code == SYS_ptrace) {
398 if (*ap >= 0 && *ap <=
399 sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
400 (void)printf("(%s", ptrace_ops[*ap]);
401 else
402 (void)printf("(%ld", (long)*ap);
403 c = ',';
404 ap++;
405 argsize -= sizeof(register_t);
406 }
407 }
408 while (argsize) {
409 if (decimal)
410 (void)printf("%c%ld", c, (long)*ap);
411 else
412 (void)printf("%c%#lx", c, (long)*ap);
413 c = ',';
414 ap++;
415 argsize -= sizeof(register_t);
416 }
417 (void)putchar(')');
418 }
419 (void)putchar('\n');
420 }
421
422 void
423 ktrsysret(ktr)
424 struct ktr_sysret *ktr;
425 {
426 register_t ret = ktr->ktr_retval;
427 int error = ktr->ktr_error;
428 int code = ktr->ktr_code;
429
430 if (code >= current->nsysnames || code < 0)
431 (void)printf("[%d] ", code);
432 else
433 (void)printf("%s ", current->sysnames[code]);
434
435 switch (error) {
436 case 0:
437 if (fancy) {
438 (void)printf("%ld", (long)ret);
439 if (ret < 0 || ret > 9)
440 (void)printf("/%#lx", (long)ret);
441 } else {
442 if (decimal)
443 (void)printf("%ld", (long)ret);
444 else
445 (void)printf("%#lx", (long)ret);
446 }
447 break;
448
449 default:
450 eprint(error);
451 break;
452 }
453 (void)putchar('\n');
454
455 }
456
457 /*
458 * We print the original emulation's error numerically, but we
459 * translate it to netbsd to print it symbolically.
460 */
461 void
462 eprint(e)
463 int e;
464 {
465 int i = e;
466
467 if (current->errno) {
468
469 /* No remapping for ERESTART and EJUSTRETURN */
470 /* Kludge for linux that has negative error numbers */
471 if (current->errno[2] > 0 && e < 0)
472 goto normal;
473
474 for (i = 0; i < current->nerrno; i++)
475 if (e == current->errno[i])
476 break;
477
478 if (i == current->nerrno) {
479 printf("-1 unknown errno %d", e);
480 return;
481 }
482 }
483
484 normal:
485 switch (i) {
486 case ERESTART:
487 (void)printf("RESTART");
488 break;
489
490 case EJUSTRETURN:
491 (void)printf("JUSTRETURN");
492 break;
493
494 default:
495 (void)printf("-1 errno %d", e);
496 if (fancy)
497 (void)printf(" %s", strerror(i));
498 }
499 }
500
501 void
502 ktrnamei(cp, len)
503 char *cp;
504 int len;
505 {
506
507 (void)printf("\"%.*s\"\n", len, cp);
508 }
509
510 void
511 ktremul(name, len, bufsize)
512 char *name;
513 int len, bufsize;
514 {
515 if (len >= bufsize)
516 len = bufsize - 1;
517
518 name[len] = '\0';
519 setemul(name, ktr_header.ktr_pid, 1);
520
521 (void)printf("\"%s\"\n", name);
522 }
523
524 void
525 ktrgenio(ktr, len)
526 struct ktr_genio *ktr;
527 int len;
528 {
529 int datalen = len - sizeof (struct ktr_genio);
530 char *dp = (char *)ktr + sizeof (struct ktr_genio);
531 char *cp;
532 int col = 0;
533 int width;
534 char visbuf[5];
535 static int screenwidth = 0;
536
537 if (screenwidth == 0) {
538 struct winsize ws;
539
540 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
541 ws.ws_col > 8)
542 screenwidth = ws.ws_col;
543 else
544 screenwidth = 80;
545 }
546 printf("fd %d %s %d bytes\n", ktr->ktr_fd,
547 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
548 if (maxdata && datalen > maxdata)
549 datalen = maxdata;
550 (void)printf(" \"");
551 col = 8;
552 for (; datalen > 0; datalen--, dp++) {
553 (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
554 cp = visbuf;
555 /*
556 * Keep track of printables and
557 * space chars (like fold(1)).
558 */
559 if (col == 0) {
560 (void)putchar('\t');
561 col = 8;
562 }
563 switch(*cp) {
564 case '\n':
565 col = 0;
566 (void)putchar('\n');
567 continue;
568 case '\t':
569 width = 8 - (col&07);
570 break;
571 default:
572 width = strlen(cp);
573 }
574 if (col + width > (screenwidth-2)) {
575 (void)printf("\\\n\t");
576 col = 8;
577 }
578 col += width;
579 do {
580 (void)putchar(*cp++);
581 } while (*cp);
582 }
583 if (col == 0)
584 (void)printf(" ");
585 (void)printf("\"\n");
586 }
587
588 void
589 ktrpsig(psig)
590 struct ktr_psig *psig;
591 {
592 int signo, first;
593
594 (void)printf("SIG%s ", sys_signame[psig->signo]);
595 if (psig->action == SIG_DFL)
596 (void)printf("SIG_DFL\n");
597 else {
598 (void)printf("caught handler=0x%lx mask=(",
599 (u_long)psig->action);
600 first = 1;
601 for (signo = 1; signo < NSIG; signo++) {
602 if (sigismember(&psig->mask, signo)) {
603 if (first)
604 first = 0;
605 else
606 (void)printf(",");
607 (void)printf("%d", signo);
608 }
609 }
610 (void)printf(") code=0x%x\n", psig->code);
611 }
612 }
613
614 void
615 ktrcsw(cs)
616 struct ktr_csw *cs;
617 {
618
619 (void)printf("%s %s\n", cs->out ? "stop" : "resume",
620 cs->user ? "user" : "kernel");
621 }
622
623 void
624 usage()
625 {
626
627 (void)fprintf(stderr,
628 "usage: kdump [-dnlRT] [-e emulation] [-f trfile] [-m maxdata] [-t [cnis]]\n");
629 exit(1);
630 }
631
632 void
633 setemul(name, pid, update_ectx)
634 const char *name;
635 pid_t pid;
636 int update_ectx;
637 {
638 int i;
639 struct emulation *match = NULL;
640
641 for (i = 0; emulations[i].name != NULL; i++) {
642 if (strcmp(emulations[i].name, name) == 0) {
643 match = &emulations[i];
644 break;
645 }
646 }
647
648 if (!match) {
649 warnx("Emulation `%s' unknown", name);
650 return;
651 }
652
653 if (update_ectx)
654 ectx_update(pid, match);
655
656 current = match;
657 }
658
659 /*
660 * Emulation context list is very simple chained list, not even hashed.
661 * We expect the number of separate traced contexts/processes to be
662 * fairly low, so it's not worth it to optimize this.
663 */
664
665 /*
666 * Find an emulation context appropriate for the given pid.
667 */
668 static struct emulation_ctx *
669 ectx_find(pid)
670 pid_t pid;
671 {
672 struct emulation_ctx *ctx;
673
674 for(ctx = emul_ctx; ctx != NULL; ctx = ctx->next) {
675 if (ctx->pid == pid)
676 return ctx;
677 }
678
679 return NULL;
680 }
681
682 /*
683 * Update emulation context for given pid, or create new if no context
684 * for this pid exists.
685 */
686 static void
687 ectx_update(pid, emul)
688 pid_t pid;
689 struct emulation *emul;
690 {
691 struct emulation_ctx *ctx;
692
693
694 if ((ctx = ectx_find(pid)) != NULL) {
695 /* found and entry, ensure the emulation is right (exec!) */
696 ctx->emulation = emul;
697 return;
698 }
699
700 ctx = (struct emulation_ctx *)malloc(sizeof(struct emulation_ctx));
701 ctx->pid = pid;
702 ctx->emulation = emul;
703
704 /* put the entry on start of emul_ctx chain */
705 ctx->next = emul_ctx;
706 emul_ctx = ctx;
707 }
708
709 /*
710 * Ensure current emulation context is correct for given pid.
711 */
712 static void
713 ectx_sanify(pid)
714 pid_t pid;
715 {
716 struct emulation_ctx *ctx;
717
718 if ((ctx = ectx_find(pid)) != NULL && ctx->emulation != current)
719 current = ctx->emulation;
720 else
721 current = default_emul;
722 }
723
724