kdump.c revision 1.32 1 /* $NetBSD: kdump.c,v 1.32 2000/12/17 16:09:40 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.32 2000/12/17 16:09:40 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 #include "setemul.h"
70
71 #include <sys/syscall.h>
72
73 int timestamp, decimal, fancy = 1, tail, maxdata;
74 const char *tracefile = DEF_TRACEFILE;
75 struct ktr_header ktr_header;
76
77 #define eqs(s1, s2) (strcmp((s1), (s2)) == 0)
78
79 static const char *ptrace_ops[] = {
80 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U",
81 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE",
82 "PT_KILL", "PT_ATTACH", "PT_DETACH",
83 };
84
85 static const char *linux_ptrace_ops[] = {
86 "PTRACE_TRACEME",
87 "PTRACE_PEEKTEXT", "PTRACE_PEEKDATA", "PTRACE_PEEKUSER",
88 "PTRACE_POKETEXT", "PTRACE_POKEDATA", "PTRACE_POKEUSER",
89 "PTRACE_CONT", "PTRACE_KILL", "PTRACE_SINGLESTEP",
90 NULL, NULL,
91 "PTRACE_GETREGS", "PTRACE_SETREGS", "PTRACE_GETFPREGS",
92 "PTRACE_SETFPREGS", "PTRACE_ATTACH", "PTRACE_DETACH",
93 "PTRACE_SYSCALL",
94 };
95
96 int main __P((int, char **));
97 int fread_tail __P((char *, int, int));
98 void dumpheader __P((struct ktr_header *));
99 void ioctldecode __P((u_long));
100 void ktrsyscall __P((struct ktr_syscall *));
101 void ktrsysret __P((struct ktr_sysret *));
102 void ktrnamei __P((char *, int));
103 void ktremul __P((char *, int, int));
104 void ktrgenio __P((struct ktr_genio *, int));
105 void ktrpsig __P((struct ktr_psig *));
106 void ktrcsw __P((struct ktr_csw *));
107 void ktruser __P((char *, int));
108 void usage __P((void));
109 void eprint __P((int));
110 char *ioctlname __P((long));
111
112 int
113 main(argc, argv)
114 int argc;
115 char *argv[];
116 {
117 int ch, ktrlen, size;
118 void *m;
119 int trpoints = ALL_POINTS;
120 const char *emul_name = "netbsd";
121
122 while ((ch = getopt(argc, argv, "e:f:dlm:nRTt:")) != -1)
123 switch (ch) {
124 case 'e':
125 emul_name = strdup(optarg); /* it's safer to copy it */
126 break;
127 case 'f':
128 tracefile = optarg;
129 break;
130 case 'd':
131 decimal = 1;
132 break;
133 case 'l':
134 tail = 1;
135 break;
136 case 'm':
137 maxdata = atoi(optarg);
138 break;
139 case 'n':
140 fancy = 0;
141 break;
142 case 'R':
143 timestamp = 2; /* relative timestamp */
144 break;
145 case 'T':
146 timestamp = 1;
147 break;
148 case 't':
149 trpoints = getpoints(optarg);
150 if (trpoints < 0)
151 errx(1, "unknown trace point in %s", optarg);
152 break;
153 default:
154 usage();
155 }
156 argv += optind;
157 argc -= optind;
158
159 if (argc > 1)
160 usage();
161
162 setemul(emul_name, 0, 0);
163
164 m = malloc(size = 1024);
165 if (m == NULL)
166 errx(1, "malloc: %s", strerror(ENOMEM));
167 if (!freopen(tracefile, "r", stdin))
168 err(1, "%s", tracefile);
169 while (fread_tail((char *)&ktr_header, sizeof(struct ktr_header), 1)) {
170 if (trpoints & (1<<ktr_header.ktr_type))
171 dumpheader(&ktr_header);
172 if ((ktrlen = ktr_header.ktr_len) < 0)
173 errx(1, "bogus length 0x%x", ktrlen);
174 if (ktrlen > size) {
175 while(ktrlen > size) size *= 2;
176 m = (void *)realloc(m, size);
177 if (m == NULL)
178 errx(1, "realloc: %s", strerror(ENOMEM));
179 }
180 if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
181 errx(1, "data too short");
182 if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
183 continue;
184
185 /* update context to match currently processed record */
186 ectx_sanify(ktr_header.ktr_pid);
187
188 switch (ktr_header.ktr_type) {
189 case KTR_SYSCALL:
190 ktrsyscall((struct ktr_syscall *)m);
191 break;
192 case KTR_SYSRET:
193 ktrsysret((struct ktr_sysret *)m);
194 break;
195 case KTR_NAMEI:
196 ktrnamei(m, ktrlen);
197 break;
198 case KTR_GENIO:
199 ktrgenio((struct ktr_genio *)m, ktrlen);
200 break;
201 case KTR_PSIG:
202 ktrpsig((struct ktr_psig *)m);
203 break;
204 case KTR_CSW:
205 ktrcsw((struct ktr_csw *)m);
206 break;
207 case KTR_EMUL:
208 ktremul(m, ktrlen, size);
209 break;
210 case KTR_USER:
211 ktruser(m, ktrlen);
212 break;
213 }
214 if (tail)
215 (void)fflush(stdout);
216 }
217 return (0);
218 }
219
220 int
221 fread_tail(buf, size, num)
222 char *buf;
223 int num, size;
224 {
225 int i;
226
227 while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
228 (void)sleep(1);
229 clearerr(stdin);
230 }
231 return (i);
232 }
233
234 void
235 dumpheader(kth)
236 struct ktr_header *kth;
237 {
238 char unknown[64], *type;
239 static struct timeval prevtime;
240 struct timeval temp;
241
242 switch (kth->ktr_type) {
243 case KTR_SYSCALL:
244 type = "CALL";
245 break;
246 case KTR_SYSRET:
247 type = "RET ";
248 break;
249 case KTR_NAMEI:
250 type = "NAMI";
251 break;
252 case KTR_GENIO:
253 type = "GIO ";
254 break;
255 case KTR_PSIG:
256 type = "PSIG";
257 break;
258 case KTR_CSW:
259 type = "CSW";
260 break;
261 case KTR_EMUL:
262 type = "EMUL";
263 break;
264 case KTR_USER:
265 type = "USER";
266 break;
267 default:
268 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
269 type = unknown;
270 }
271
272 (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
273 if (timestamp) {
274 if (timestamp == 2) {
275 timersub(&kth->ktr_time, &prevtime, &temp);
276 prevtime = kth->ktr_time;
277 } else
278 temp = kth->ktr_time;
279 (void)printf("%ld.%06ld ",
280 (long int)temp.tv_sec, (long int)temp.tv_usec);
281 }
282 (void)printf("%s ", type);
283 }
284
285 void
286 ioctldecode(cmd)
287 u_long cmd;
288 {
289 char dirbuf[4], *dir = dirbuf;
290
291 if (cmd & IOC_IN)
292 *dir++ = 'W';
293 if (cmd & IOC_OUT)
294 *dir++ = 'R';
295 *dir = '\0';
296
297 printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx",
298 dirbuf, (int) ((cmd >> 8) & 0xff), cmd & 0xff);
299 if ((cmd & IOC_VOID) == 0)
300 printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff);
301 else
302 printf(")");
303 }
304
305 void
306 ktrsyscall(ktr)
307 struct ktr_syscall *ktr;
308 {
309 int argsize = ktr->ktr_argsize;
310 register_t *ap;
311
312 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0)
313 (void)printf("[%d]", ktr->ktr_code);
314 else
315 (void)printf("%s", current->sysnames[ktr->ktr_code]);
316 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
317 if (argsize) {
318 char c = '(';
319 if (fancy) {
320 if (ktr->ktr_code == SYS_ioctl) {
321 char *cp;
322 if (decimal)
323 (void)printf("(%ld", (long)*ap);
324 else
325 (void)printf("(%#lx", (long)*ap);
326 ap++;
327 argsize -= sizeof(register_t);
328 if ((cp = ioctlname(*ap)) != NULL)
329 (void)printf(",%s", cp);
330 else
331 ioctldecode(*ap);
332 c = ',';
333 ap++;
334 argsize -= sizeof(register_t);
335 } else if (ktr->ktr_code == SYS_ptrace) {
336 if (strcmp(current->name, "linux") == 0) {
337 if (*ap >= 0 && *ap <=
338 sizeof(linux_ptrace_ops) / sizeof(linux_ptrace_ops[0]))
339 (void)printf("(%s", linux_ptrace_ops[*ap]);
340 else
341 (void)printf("(%ld", (long)*ap);
342 } else {
343 if (*ap >= 0 && *ap <=
344 sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
345 (void)printf("(%s", ptrace_ops[*ap]);
346 else
347 (void)printf("(%ld", (long)*ap);
348 }
349 c = ',';
350 ap++;
351 argsize -= sizeof(register_t);
352 }
353 }
354 while (argsize) {
355 if (decimal)
356 (void)printf("%c%ld", c, (long)*ap);
357 else
358 (void)printf("%c%#lx", c, (long)*ap);
359 c = ',';
360 ap++;
361 argsize -= sizeof(register_t);
362 }
363 (void)putchar(')');
364 }
365 (void)putchar('\n');
366 }
367
368 void
369 ktrsysret(ktr)
370 struct ktr_sysret *ktr;
371 {
372 register_t ret = ktr->ktr_retval;
373 int error = ktr->ktr_error;
374 int code = ktr->ktr_code;
375
376 if (code >= current->nsysnames || code < 0)
377 (void)printf("[%d] ", code);
378 else
379 (void)printf("%s ", current->sysnames[code]);
380
381 switch (error) {
382 case 0:
383 if (fancy) {
384 (void)printf("%ld", (long)ret);
385 if (ret < 0 || ret > 9)
386 (void)printf("/%#lx", (long)ret);
387 } else {
388 if (decimal)
389 (void)printf("%ld", (long)ret);
390 else
391 (void)printf("%#lx", (long)ret);
392 }
393 break;
394
395 default:
396 eprint(error);
397 break;
398 }
399 (void)putchar('\n');
400
401 }
402
403 /*
404 * We print the original emulation's error numerically, but we
405 * translate it to netbsd to print it symbolically.
406 */
407 void
408 eprint(e)
409 int e;
410 {
411 int i = e;
412
413 if (current->errno) {
414
415 /* No remapping for ERESTART and EJUSTRETURN */
416 /* Kludge for linux that has negative error numbers */
417 if (current->errno[2] > 0 && e < 0)
418 goto normal;
419
420 for (i = 0; i < current->nerrno; i++)
421 if (e == current->errno[i])
422 break;
423
424 if (i == current->nerrno) {
425 printf("-1 unknown errno %d", e);
426 return;
427 }
428 }
429
430 normal:
431 switch (i) {
432 case ERESTART:
433 (void)printf("RESTART");
434 break;
435
436 case EJUSTRETURN:
437 (void)printf("JUSTRETURN");
438 break;
439
440 default:
441 (void)printf("-1 errno %d", e);
442 if (fancy)
443 (void)printf(" %s", strerror(i));
444 }
445 }
446
447 void
448 ktrnamei(cp, len)
449 char *cp;
450 int len;
451 {
452
453 (void)printf("\"%.*s\"\n", len, cp);
454 }
455
456 void
457 ktremul(name, len, bufsize)
458 char *name;
459 int len, bufsize;
460 {
461 if (len >= bufsize)
462 len = bufsize - 1;
463
464 name[len] = '\0';
465 setemul(name, ktr_header.ktr_pid, 1);
466
467 (void)printf("\"%s\"\n", name);
468 }
469
470 void
471 ktrgenio(ktr, len)
472 struct ktr_genio *ktr;
473 int len;
474 {
475 int datalen = len - sizeof (struct ktr_genio);
476 char *dp = (char *)ktr + sizeof (struct ktr_genio);
477 char *cp;
478 int col = 0;
479 int width;
480 char visbuf[5];
481 static int screenwidth = 0;
482
483 if (screenwidth == 0) {
484 struct winsize ws;
485
486 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
487 ws.ws_col > 8)
488 screenwidth = ws.ws_col;
489 else
490 screenwidth = 80;
491 }
492 printf("fd %d %s %d bytes\n", ktr->ktr_fd,
493 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
494 if (maxdata && datalen > maxdata)
495 datalen = maxdata;
496 (void)printf(" \"");
497 col = 8;
498 for (; datalen > 0; datalen--, dp++) {
499 (void) vis(visbuf, *dp, VIS_CSTYLE, datalen>1?*(dp+1):0);
500 cp = visbuf;
501 /*
502 * Keep track of printables and
503 * space chars (like fold(1)).
504 */
505 if (col == 0) {
506 (void)putchar('\t');
507 col = 8;
508 }
509 switch(*cp) {
510 case '\n':
511 col = 0;
512 (void)putchar('\n');
513 continue;
514 case '\t':
515 width = 8 - (col&07);
516 break;
517 default:
518 width = strlen(cp);
519 }
520 if (col + width > (screenwidth-2)) {
521 (void)printf("\\\n\t");
522 col = 8;
523 }
524 col += width;
525 do {
526 (void)putchar(*cp++);
527 } while (*cp);
528 }
529 if (col == 0)
530 (void)printf(" ");
531 (void)printf("\"\n");
532 }
533
534 void
535 ktrpsig(psig)
536 struct ktr_psig *psig;
537 {
538 int signo, first;
539
540 (void)printf("SIG%s ", sys_signame[psig->signo]);
541 if (psig->action == SIG_DFL)
542 (void)printf("SIG_DFL\n");
543 else {
544 (void)printf("caught handler=0x%lx mask=(",
545 (u_long)psig->action);
546 first = 1;
547 for (signo = 1; signo < NSIG; signo++) {
548 if (sigismember(&psig->mask, signo)) {
549 if (first)
550 first = 0;
551 else
552 (void)printf(",");
553 (void)printf("%d", signo);
554 }
555 }
556 (void)printf(") code=0x%x\n", psig->code);
557 }
558 }
559
560 void
561 ktrcsw(cs)
562 struct ktr_csw *cs;
563 {
564
565 (void)printf("%s %s\n", cs->out ? "stop" : "resume",
566 cs->user ? "user" : "kernel");
567 }
568
569 void
570 ktruser(name, len)
571 char *name;
572 int len;
573 {
574 int i;
575 printf("\"%d, ", len);
576 for(i=0; i < len; i++)
577 printf("%x", name[i]);
578 printf("\"\n");
579 }
580
581 void
582 usage()
583 {
584
585 (void)fprintf(stderr,
586 "usage: kdump [-dnlRT] [-e emulation] [-f trfile] [-m maxdata] [-t [cnis]]\n");
587 exit(1);
588 }
589