kdump.c revision 1.60 1 /* $NetBSD: kdump.c,v 1.60 2003/09/19 22:49:02 christos 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/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
35 The Regents of the University of California. All rights reserved.\n");
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95";
41 #else
42 __RCSID("$NetBSD: kdump.c,v 1.60 2003/09/19 22:49:02 christos Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <sys/param.h>
47 #define _KERNEL
48 #include <sys/errno.h>
49 #undef _KERNEL
50 #include <sys/time.h>
51 #include <sys/uio.h>
52 #include <sys/ktrace.h>
53 #include <sys/ioctl.h>
54 #include <sys/ptrace.h>
55
56 #include <ctype.h>
57 #include <err.h>
58 #include <signal.h>
59 #include <stddef.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64 #include <vis.h>
65
66 #include "ktrace.h"
67 #include "setemul.h"
68
69 #include <sys/syscall.h>
70
71 int timestamp, decimal, plain, tail, maxdata = -1, numeric;
72 int hexdump;
73 pid_t do_pid = -1;
74 const char *tracefile = NULL;
75 struct ktr_header ktr_header;
76 int emul_changed = 0;
77
78 #define eqs(s1, s2) (strcmp((s1), (s2)) == 0)
79
80 static const char *ptrace_ops[] = {
81 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U",
82 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE",
83 "PT_KILL", "PT_ATTACH", "PT_DETACH",
84 };
85
86 static const char *linux_ptrace_ops[] = {
87 "PTRACE_TRACEME",
88 "PTRACE_PEEKTEXT", "PTRACE_PEEKDATA", "PTRACE_PEEKUSER",
89 "PTRACE_POKETEXT", "PTRACE_POKEDATA", "PTRACE_POKEUSER",
90 "PTRACE_CONT", "PTRACE_KILL", "PTRACE_SINGLESTEP",
91 NULL, NULL,
92 "PTRACE_GETREGS", "PTRACE_SETREGS", "PTRACE_GETFPREGS",
93 "PTRACE_SETFPREGS", "PTRACE_ATTACH", "PTRACE_DETACH",
94 "PTRACE_SYSCALL",
95 };
96
97 int main __P((int, char **));
98 int fread_tail __P((char *, int, int));
99 int dumpheader __P((struct ktr_header *));
100 void ioctldecode __P((u_long));
101 void ktrsyscall __P((struct ktr_syscall *));
102 void ktrsysret __P((struct ktr_sysret *, int));
103 void ktrnamei __P((char *, int));
104 void ktremul __P((char *, int, int));
105 void ktrgenio __P((struct ktr_genio *, int));
106 void ktrpsig __P((void *, int));
107 void ktrcsw __P((struct ktr_csw *));
108 void ktruser __P((struct ktr_user *, int));
109 void ktrmmsg __P((struct ktr_mmsg *, int));
110 void usage __P((void));
111 void eprint __P((int));
112 void rprint __P((register_t));
113 char *ioctlname __P((long));
114 static const char *signame __P((long, int));
115 static void hexdump_buf(const void *, int);
116 static void visdump_buf(const void *, int, int);
117
118 int
119 main(argc, argv)
120 int argc;
121 char *argv[];
122 {
123 int ch, ktrlen, size;
124 void *m;
125 int trpoints = 0;
126 int trset = 0;
127 const char *emul_name = "netbsd";
128 int col;
129
130 while ((ch = getopt(argc, argv, "e:f:dlm:Nnp:RTt:x")) != -1)
131 switch (ch) {
132 case 'e':
133 emul_name = strdup(optarg); /* it's safer to copy it */
134 break;
135 case 'f':
136 tracefile = optarg;
137 break;
138 case 'd':
139 decimal = 1;
140 break;
141 case 'l':
142 tail = 1;
143 break;
144 case 'p':
145 do_pid = atoi(optarg);
146 break;
147 case 'm':
148 maxdata = atoi(optarg);
149 break;
150 case 'N':
151 numeric++;
152 break;
153 case 'n':
154 plain++;
155 break;
156 case 'R':
157 timestamp = 2; /* relative timestamp */
158 break;
159 case 'T':
160 timestamp = 1;
161 break;
162 case 't':
163 trset = 1;
164 trpoints = getpoints(trpoints, optarg);
165 if (trpoints < 0)
166 errx(1, "unknown trace point in %s", optarg);
167 break;
168 case 'x':
169 hexdump = 1;
170 break;
171 default:
172 usage();
173 }
174 argv += optind;
175 argc -= optind;
176
177 if (!trset)
178 trpoints = ALL_POINTS;
179
180 if (tracefile == NULL) {
181 if (argc == 1) {
182 tracefile = argv[0];
183 argv++;
184 argc--;
185 }
186 else
187 tracefile = DEF_TRACEFILE;
188 }
189
190 if (argc > 0)
191 usage();
192
193 setemul(emul_name, 0, 0);
194 mach_lookup_emul();
195
196 m = malloc(size = 1024);
197 if (m == NULL)
198 errx(1, "malloc: %s", strerror(ENOMEM));
199 if (!freopen(tracefile, "r", stdin))
200 err(1, "%s", tracefile);
201 while (fread_tail((char *)&ktr_header, sizeof(struct ktr_header), 1)) {
202 if (trpoints & (1<<ktr_header.ktr_type)
203 && (do_pid == -1 || ktr_header.ktr_pid == do_pid))
204 col = dumpheader(&ktr_header);
205 else
206 col = -1;
207 if ((ktrlen = ktr_header.ktr_len) < 0)
208 errx(1, "bogus length 0x%x", ktrlen);
209 if (ktrlen > size) {
210 while (ktrlen > size)
211 size *= 2;
212 m = realloc(m, size);
213 if (m == NULL)
214 errx(1, "realloc: %s", strerror(ENOMEM));
215 }
216 if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
217 errx(1, "data too short");
218 if (col == -1)
219 continue;
220
221 /* update context to match currently processed record */
222 ectx_sanify(ktr_header.ktr_pid);
223
224 switch (ktr_header.ktr_type) {
225 case KTR_SYSCALL:
226 ktrsyscall(m);
227 break;
228 case KTR_SYSRET:
229 ktrsysret(m, ktrlen);
230 break;
231 case KTR_NAMEI:
232 ktrnamei(m, ktrlen);
233 break;
234 case KTR_GENIO:
235 ktrgenio(m, ktrlen);
236 break;
237 case KTR_PSIG:
238 ktrpsig(m, ktrlen);
239 break;
240 case KTR_CSW:
241 ktrcsw(m);
242 break;
243 case KTR_EMUL:
244 ktremul(m, ktrlen, size);
245 break;
246 case KTR_USER:
247 ktruser(m, ktrlen);
248 break;
249 case KTR_MMSG:
250 ktrmmsg(m, ktrlen);
251 break;
252 case KTR_EXEC_ARG:
253 case KTR_EXEC_ENV:
254 visdump_buf(m, ktrlen, col);
255 break;
256 default:
257 printf("\n");
258 hexdump_buf(m, ktrlen);
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 int
281 dumpheader(kth)
282 struct ktr_header *kth;
283 {
284 char unknown[64], *type;
285 static struct timeval prevtime;
286 struct timeval temp;
287 int col;
288
289 switch (kth->ktr_type) {
290 case KTR_SYSCALL:
291 type = "CALL";
292 break;
293 case KTR_SYSRET:
294 type = "RET ";
295 break;
296 case KTR_NAMEI:
297 type = "NAMI";
298 break;
299 case KTR_GENIO:
300 type = "GIO ";
301 break;
302 case KTR_PSIG:
303 type = "PSIG";
304 break;
305 case KTR_CSW:
306 type = "CSW ";
307 break;
308 case KTR_EMUL:
309 type = "EMUL";
310 break;
311 case KTR_USER:
312 type = "USER";
313 break;
314 case KTR_MMSG:
315 type = "MMSG";
316 break;
317 case KTR_EXEC_ENV:
318 type = "ENV";
319 break;
320 case KTR_EXEC_ARG:
321 type = "ARG";
322 break;
323 default:
324 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
325 type = unknown;
326 }
327
328 col = printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
329 if (timestamp) {
330 if (timestamp == 2) {
331 if (prevtime.tv_sec == 0)
332 temp.tv_sec = temp.tv_usec = 0;
333 else
334 timersub(&kth->ktr_time, &prevtime, &temp);
335 prevtime = kth->ktr_time;
336 } else
337 temp = kth->ktr_time;
338 col += printf("%ld.%06ld ",
339 (long int)temp.tv_sec, (long int)temp.tv_usec);
340 }
341 col += printf("%-4s ", type);
342 return col;
343 }
344
345 void
346 ioctldecode(cmd)
347 u_long cmd;
348 {
349 char dirbuf[4], *dir = dirbuf;
350
351 if (cmd & IOC_IN)
352 *dir++ = 'W';
353 if (cmd & IOC_OUT)
354 *dir++ = 'R';
355 *dir = '\0';
356
357 printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx",
358 dirbuf, (int) ((cmd >> 8) & 0xff), cmd & 0xff);
359 if ((cmd & IOC_VOID) == 0)
360 printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff);
361 else
362 printf(")");
363 }
364
365 void
366 ktrsyscall(ktr)
367 struct ktr_syscall *ktr;
368 {
369 int argsize = ktr->ktr_argsize;
370 const struct emulation *revelant = current;
371 register_t *ap;
372
373 if (((ktr->ktr_code >= revelant->nsysnames || ktr->ktr_code < 0)
374 && (mach_traps_dispatch(&ktr->ktr_code, &revelant) == 0)) ||
375 numeric)
376 (void)printf("[%d]", ktr->ktr_code);
377 else
378 (void)printf("%s", revelant->sysnames[ktr->ktr_code]);
379 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
380 if (argsize) {
381 char c = '(';
382 if (!plain) {
383 char *cp;
384
385 switch (ktr->ktr_code) {
386 case SYS_ioctl:
387 if (decimal)
388 (void)printf("(%ld", (long)*ap);
389 else
390 (void)printf("(%#lx", (long)*ap);
391 ap++;
392 argsize -= sizeof(register_t);
393 if ((cp = ioctlname(*ap)) != NULL)
394 (void)printf(",%s", cp);
395 else
396 ioctldecode(*ap);
397 c = ',';
398 ap++;
399 argsize -= sizeof(register_t);
400 break;
401
402 case SYS_ptrace:
403 if (strcmp(revelant->name, "linux") == 0) {
404 if (*ap >= 0 && *ap <=
405 sizeof(linux_ptrace_ops) /
406 sizeof(linux_ptrace_ops[0]))
407 (void)printf("(%s",
408 linux_ptrace_ops[*ap]);
409 else
410 (void)printf("(%ld", (long)*ap);
411 } else {
412 if (*ap >= 0 && *ap <=
413 sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
414 (void)printf("(%s", ptrace_ops[*ap]);
415 else
416 (void)printf("(%ld", (long)*ap);
417 }
418 c = ',';
419 ap++;
420 argsize -= sizeof(register_t);
421 break;
422
423 case SYS_kill:
424 if (decimal)
425 (void)printf("(%ld, SIG%s",
426 (long)ap[0], signame(ap[1], 1));
427 else
428 (void)printf("(%#lx, SIG%s",
429 (long)ap[0], signame(ap[1], 1));
430 ap += 2;
431 argsize -= 2 * sizeof(register_t);
432 break;
433
434 default:
435 /* No special handling */
436 break;
437 }
438 }
439 while (argsize) {
440 if (decimal)
441 (void)printf("%c%ld", c, (long)*ap);
442 else
443 (void)printf("%c%#lx", c, (long)*ap);
444 c = ',';
445 ap++;
446 argsize -= sizeof(register_t);
447 }
448 (void)putchar(')');
449 }
450 (void)putchar('\n');
451 }
452
453 void
454 ktrsysret(ktr, len)
455 struct ktr_sysret *ktr;
456 int len;
457 {
458 const struct emulation *revelant;
459 int error = ktr->ktr_error;
460 int code = ktr->ktr_code;
461
462 if (emul_changed)
463 revelant = previous;
464 else
465 revelant = current;
466 emul_changed = 0;
467
468 if ((code >= revelant->nsysnames || code < 0 || plain > 1)
469 && (mach_traps_dispatch(&code, &revelant) == 0))
470 (void)printf("[%d] ", code);
471 else
472 (void)printf("%s ", revelant->sysnames[code]);
473
474 switch (error) {
475 case 0:
476 rprint(ktr->ktr_retval);
477 if (len > offsetof(struct ktr_sysret, ktr_retval_1) &&
478 ktr->ktr_retval_1 != 0) {
479 (void)printf(", ");
480 rprint(ktr->ktr_retval_1);
481 }
482 break;
483
484 default:
485 eprint(error);
486 break;
487 }
488 (void)putchar('\n');
489 }
490
491 void
492 rprint(register_t ret)
493 {
494 if (!plain) {
495 (void)printf("%ld", (long)ret);
496 if (ret < 0 || ret > 9)
497 (void)printf("/%#lx", (long)ret);
498 } else {
499 if (decimal)
500 (void)printf("%ld", (long)ret);
501 else
502 (void)printf("%#lx", (long)ret);
503 }
504 }
505
506 /*
507 * We print the original emulation's error numerically, but we
508 * translate it to netbsd to print it symbolically.
509 */
510 void
511 eprint(e)
512 int e;
513 {
514 int i = e;
515
516 if (current->errnomap) {
517
518 /* No remapping for ERESTART and EJUSTRETURN */
519 /* Kludge for linux that has negative error numbers */
520 if (current->errnomap[2] > 0 && e < 0)
521 goto normal;
522
523 for (i = 0; i < current->nerrnomap; i++)
524 if (e == current->errnomap[i])
525 break;
526
527 if (i == current->nerrnomap) {
528 printf("-1 unknown errno %d", e);
529 return;
530 }
531 }
532
533 normal:
534 switch (i) {
535 case ERESTART:
536 (void)printf("RESTART");
537 break;
538
539 case EJUSTRETURN:
540 (void)printf("JUSTRETURN");
541 break;
542
543 default:
544 (void)printf("-1 errno %d", e);
545 if (!plain)
546 (void)printf(" %s", strerror(i));
547 }
548 }
549
550 void
551 ktrnamei(cp, len)
552 char *cp;
553 int len;
554 {
555
556 (void)printf("\"%.*s\"\n", len, cp);
557 }
558
559 void
560 ktremul(name, len, bufsize)
561 char *name;
562 int len, bufsize;
563 {
564 if (len >= bufsize)
565 len = bufsize - 1;
566
567 name[len] = '\0';
568 setemul(name, ktr_header.ktr_pid, 1);
569 emul_changed = 1;
570
571 (void)printf("\"%s\"\n", name);
572 }
573
574 static void
575 hexdump_buf(const void *vdp, int datalen)
576 {
577 char chars[16];
578 const unsigned char *dp = vdp;
579 int line_end, off, l, c;
580 char *cp;
581
582 for (off = 0; off < datalen;) {
583 line_end = off + 16;
584 if (line_end > datalen)
585 line_end = datalen;
586 printf("\t%3.3x ", off);
587 for (l = 0, cp = chars; off < line_end; off++) {
588 c = *dp++;
589 if ((off & 7) == 0)
590 l += printf(" ");
591 l += printf(" %2.2x", c);
592 *cp++ = isgraph(c) ? c : '.';
593 };
594 printf("%*s %.*s\n", 50 - l, "", (int)(cp - chars), chars);
595 }
596 }
597
598 static void
599 visdump_buf(const void *vdp, int datalen, int col)
600 {
601 const unsigned char *dp = vdp;
602 char *cp;
603 int width;
604 char visbuf[5];
605 static int screenwidth = 0;
606
607 if (screenwidth == 0) {
608 struct winsize ws;
609
610 if (!plain && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
611 ws.ws_col > 8)
612 screenwidth = ws.ws_col;
613 else
614 screenwidth = 80;
615 }
616
617 (void)printf("\"");
618 col++;
619 for (; datalen > 0; datalen--, dp++) {
620 (void)svis(visbuf, *dp, VIS_CSTYLE,
621 datalen > 1 ? *(dp + 1) : 0, "\"");
622 cp = visbuf;
623 /*
624 * Keep track of printables and
625 * space chars (like fold(1)).
626 */
627 if (col == 0) {
628 (void)putchar('\t');
629 col = 8;
630 }
631 switch(*cp) {
632 case '\n':
633 col = 0;
634 (void)putchar('\n');
635 continue;
636 case '\t':
637 width = 8 - (col & 07);
638 break;
639 default:
640 width = strlen(cp);
641 }
642 if (col + width > (screenwidth - 2)) {
643 (void)printf("\\\n\t");
644 col = 8;
645 }
646 col += width;
647 do {
648 (void)putchar(*cp++);
649 } while (*cp);
650 }
651 if (col == 0)
652 (void)printf(" ");
653 (void)printf("\"\n");
654 }
655
656 void
657 ktrgenio(ktr, len)
658 struct ktr_genio *ktr;
659 int len;
660 {
661 int datalen = len - sizeof (struct ktr_genio);
662 char *dp = (char *)ktr + sizeof (struct ktr_genio);
663
664 printf("fd %d %s %d bytes\n", ktr->ktr_fd,
665 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
666 if (maxdata == 0)
667 return;
668 if (maxdata > 0 && datalen > maxdata)
669 datalen = maxdata;
670 if (hexdump) {
671 hexdump_buf(dp, datalen);
672 return;
673 }
674 (void)printf(" ");
675 visdump_buf(dp, datalen, 7);
676 }
677
678 void
679 ktrpsig(v, len)
680 void *v;
681 int len;
682 {
683 int signo, first;
684 struct {
685 struct ktr_psig ps;
686 siginfo_t si;
687 } *psig = v;
688 siginfo_t *si = &psig->si;
689 const char *code;
690
691 (void)printf("SIG%s ", signame(psig->ps.signo, 0));
692 if (psig->ps.action == SIG_DFL)
693 (void)printf("SIG_DFL");
694 else {
695 (void)printf("caught handler=%p mask=(", psig->ps.action);
696 first = 1;
697 for (signo = 1; signo < NSIG; signo++) {
698 if (sigismember(&psig->ps.mask, signo)) {
699 if (first)
700 first = 0;
701 else
702 (void)printf(",");
703 (void)printf("%d", signo);
704 }
705 }
706 (void)printf(")");
707 }
708 switch (len) {
709 case sizeof(struct ktr_psig):
710 printf("\n");
711 return;
712 case sizeof(*psig):
713 if (si->si_code == 0) {
714 printf(": code=SI_USER sent by pid=%d, uid=%d\n",
715 si->si_pid, si->si_uid);
716 return;
717 }
718
719 if (si->si_code < 0) {
720 switch (si->si_code) {
721 case SI_TIMER:
722 printf(": code=SI_TIMER sigval %p\n",
723 si->si_sigval.sival_ptr);
724 return;
725 case SI_QUEUE:
726 code = "SI_QUEUE";
727 break;
728 case SI_ASYNCIO:
729 code = "SI_ASYNCIO";
730 break;
731 case SI_MESGQ:
732 code = "SI_MESGQ";
733 break;
734 default:
735 code = NULL;
736 break;
737 }
738 if (code)
739 printf(": code=%s unimplemented\n", code);
740 else
741 printf(": code=%d unimplemented\n",
742 si->si_code);
743 return;
744 }
745
746 code = siginfocodename(si->si_signo, si->si_code);
747 switch (si->si_signo) {
748 case SIGCHLD:
749 printf(": code=%s child pid=%d, uid=%d, "
750 " status=%u, utime=%lu, stime=%lu\n",
751 code, si->si_pid,
752 si->si_uid, si->si_status, si->si_utime,
753 si->si_stime);
754 return;
755 case SIGILL:
756 case SIGFPE:
757 case SIGSEGV:
758 case SIGBUS:
759 case SIGTRAP:
760 printf(": code=%s, addr=%p, trap=%d\n",
761 code, si->si_addr, si->si_trap);
762 return;
763 case SIGIO:
764 printf(": code=%s, fd=%d, band=%lx\n",
765 code, si->si_fd, si->si_band);
766 return;
767 default:
768 printf(": code=%s, errno=%d\n",
769 code, si->si_errno);
770 return;
771 }
772 /*NOTREACHED*/
773 default:
774 warnx("Unhandled size %d for ktrpsig\n", len);
775 break;
776 }
777 }
778
779 void
780 ktrcsw(cs)
781 struct ktr_csw *cs;
782 {
783
784 (void)printf("%s %s\n", cs->out ? "stop" : "resume",
785 cs->user ? "user" : "kernel");
786 }
787
788 void
789 ktruser(usr, len)
790 struct ktr_user *usr;
791 int len;
792 {
793 int i;
794 unsigned char *dta;
795
796 printf("\"%.*s: %d, ", KTR_USER_MAXIDLEN, usr->ktr_id, len);
797 dta = (unsigned char *)usr;
798 for(i=sizeof(struct ktr_user); i < len; i++)
799 printf("%02x", (unsigned int) dta[i]);
800 printf("\"\n");
801 }
802
803 void
804 ktrmmsg(mmsg, len)
805 struct ktr_mmsg *mmsg;
806 int len;
807 {
808 printf("id %d [0x%x -> 0x%x] flags 0x%x\n",
809 mmsg->ktr_id, mmsg->ktr_local_port,
810 mmsg->ktr_remote_port, mmsg->ktr_bits);
811
812 hexdump_buf(mmsg, len);
813 }
814
815 static const char *
816 signame(long sig, int xlat)
817 {
818 static char buf[64];
819 if (sig == 0)
820 return " 0";
821 else if (sig < 0 || sig >= NSIG) {
822 (void)snprintf(buf, sizeof(buf), "*unknown %ld*", sig);
823 return buf;
824 } else
825 return sys_signame[(xlat && current->signalmap != NULL) ?
826 current->signalmap[sig] : sig];
827 }
828
829 void
830 usage()
831 {
832
833 (void)fprintf(stderr, "usage: kdump [-dlNnRTx] [-e emulation] "
834 "[-f file] [-m maxdata] [-p pid]\n [-t trstr] "
835 "[file]\n");
836 exit(1);
837 }
838