]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/kdump/kdump.c
BSD 4.4 Lite Usr.bin Sources
[FreeBSD/FreeBSD.git] / usr.bin / kdump / kdump.c
1 /*-
2  * Copyright (c) 1988, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static char copyright[] =
36 "@(#) Copyright (c) 1988, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 static char sccsid[] = "@(#)kdump.c     8.1 (Berkeley) 6/6/93";
42 #endif /* not lint */
43
44 #include <sys/param.h>
45 #include <sys/errno.h>
46 #include <sys/time.h>
47 #include <sys/uio.h>
48 #include <sys/ktrace.h>
49 #include <sys/ioctl.h>
50 #include <sys/ptrace.h>
51 #define KERNEL
52 #include <sys/errno.h>
53 #undef KERNEL
54 #include <vis.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include "ktrace.h"
59
60 int timestamp, decimal, fancy = 1, tail, maxdata;
61 char *tracefile = DEF_TRACEFILE;
62 struct ktr_header ktr_header;
63
64 #define eqs(s1, s2)     (strcmp((s1), (s2)) == 0)
65
66 main(argc, argv)
67         int argc;
68         char *argv[];
69 {
70         extern int optind;
71         extern char *optarg;
72         int ch, ktrlen, size;
73         register void *m;
74         int trpoints = ALL_POINTS;
75
76         while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != EOF)
77                 switch((char)ch) {
78                 case 'f':
79                         tracefile = optarg;
80                         break;
81                 case 'd':
82                         decimal = 1;
83                         break;
84                 case 'l':
85                         tail = 1;
86                         break;
87                 case 'm':
88                         maxdata = atoi(optarg);
89                         break;
90                 case 'n':
91                         fancy = 0;
92                         break;
93                 case 'R':
94                         timestamp = 2;  /* relative timestamp */
95                         break;
96                 case 'T':
97                         timestamp = 1;
98                         break;
99                 case 't':
100                         trpoints = getpoints(optarg);
101                         if (trpoints < 0) {
102                                 (void)fprintf(stderr,
103                                     "kdump: unknown trace point in %s\n",
104                                     optarg);
105                                 exit(1);
106                         }
107                         break;
108                 default:
109                         usage();
110                 }
111         argv += optind;
112         argc -= optind;
113
114         if (argc > 1)
115                 usage();
116
117         m = (void *)malloc(size = 1025);
118         if (m == NULL) {
119                 (void)fprintf(stderr, "kdump: %s.\n", strerror(ENOMEM));
120                 exit(1);
121         }
122         if (!freopen(tracefile, "r", stdin)) {
123                 (void)fprintf(stderr,
124                     "kdump: %s: %s.\n", tracefile, strerror(errno));
125                 exit(1);
126         }
127         while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
128                 if (trpoints & (1<<ktr_header.ktr_type))
129                         dumpheader(&ktr_header);
130                 if ((ktrlen = ktr_header.ktr_len) < 0) {
131                         (void)fprintf(stderr,
132                             "kdump: bogus length 0x%x\n", ktrlen);
133                         exit(1);
134                 }
135                 if (ktrlen > size) {
136                         m = (void *)realloc(m, ktrlen+1);
137                         if (m == NULL) {
138                                 (void)fprintf(stderr,
139                                     "kdump: %s.\n", strerror(ENOMEM));
140                                 exit(1);
141                         }
142                         size = ktrlen;
143                 }
144                 if (ktrlen && fread_tail(m, ktrlen, 1) == 0) {
145                         (void)fprintf(stderr, "kdump: data too short.\n");
146                         exit(1);
147                 }
148                 if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
149                         continue;
150                 switch (ktr_header.ktr_type) {
151                 case KTR_SYSCALL:
152                         ktrsyscall((struct ktr_syscall *)m);
153                         break;
154                 case KTR_SYSRET:
155                         ktrsysret((struct ktr_sysret *)m);
156                         break;
157                 case KTR_NAMEI:
158                         ktrnamei(m, ktrlen);
159                         break;
160                 case KTR_GENIO:
161                         ktrgenio((struct ktr_genio *)m, ktrlen);
162                         break;
163                 case KTR_PSIG:
164                         ktrpsig((struct ktr_psig *)m);
165                         break;
166                 case KTR_CSW:
167                         ktrcsw((struct ktr_csw *)m);
168                         break;
169                 }
170                 if (tail)
171                         (void)fflush(stdout);
172         }
173 }
174
175 fread_tail(buf, size, num)
176         char *buf;
177         int num, size;
178 {
179         int i;
180
181         while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
182                 (void)sleep(1);
183                 clearerr(stdin);
184         }
185         return (i);
186 }
187
188 dumpheader(kth)
189         struct ktr_header *kth;
190 {
191         static char unknown[64];
192         static struct timeval prevtime, temp;
193         char *type;
194
195         switch (kth->ktr_type) {
196         case KTR_SYSCALL:
197                 type = "CALL";
198                 break;
199         case KTR_SYSRET:
200                 type = "RET ";
201                 break;
202         case KTR_NAMEI:
203                 type = "NAMI";
204                 break;
205         case KTR_GENIO:
206                 type = "GIO ";
207                 break;
208         case KTR_PSIG:
209                 type = "PSIG";
210                 break;
211         case KTR_CSW:
212                 type = "CSW";
213                 break;
214         default:
215                 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
216                 type = unknown;
217         }
218
219         (void)printf("%6d %-8s ", kth->ktr_pid, kth->ktr_comm);
220         if (timestamp) {
221                 if (timestamp == 2) {
222                         temp = kth->ktr_time;
223                         timevalsub(&kth->ktr_time, &prevtime);
224                         prevtime = temp;
225                 }
226                 (void)printf("%ld.%06ld ",
227                     kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
228         }
229         (void)printf("%s  ", type);
230 }
231
232 #include <sys/syscall.h>
233 #define KTRACE
234 #include "/sys/kern/syscalls.c"
235 #undef KTRACE
236 int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
237
238 static char *ptrace_ops[] = {
239         "PT_TRACE_ME",  "PT_READ_I",    "PT_READ_D",    "PT_READ_U",
240         "PT_WRITE_I",   "PT_WRITE_D",   "PT_WRITE_U",   "PT_CONTINUE",
241         "PT_KILL",      "PT_STEP",
242 };
243
244 ktrsyscall(ktr)
245         register struct ktr_syscall *ktr;
246 {
247         register narg = ktr->ktr_narg;
248         register int *ip;
249         char *ioctlname();
250
251         if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
252                 (void)printf("[%d]", ktr->ktr_code);
253         else
254                 (void)printf("%s", syscallnames[ktr->ktr_code]);
255         ip = (int *)((char *)ktr + sizeof(struct ktr_syscall));
256         if (narg) {
257                 char c = '(';
258                 if (fancy) {
259                         if (ktr->ktr_code == SYS_ioctl) {
260                                 char *cp;
261                                 if (decimal)
262                                         (void)printf("(%d", *ip);
263                                 else
264                                         (void)printf("(%#x", *ip);
265                                 ip++;
266                                 narg--;
267                                 if ((cp = ioctlname(*ip)) != NULL)
268                                         (void)printf(",%s", cp);
269                                 else {
270                                         if (decimal)
271                                                 (void)printf(",%d", *ip);
272                                         else
273                                                 (void)printf(",%#x ", *ip);
274                                 }
275                                 c = ',';
276                                 ip++;
277                                 narg--;
278                         } else if (ktr->ktr_code == SYS_ptrace) {
279                                 if (*ip <= PT_STEP && *ip >= 0)
280                                         (void)printf("(%s", ptrace_ops[*ip]);
281                                 else
282                                         (void)printf("(%d", *ip);
283                                 c = ',';
284                                 ip++;
285                                 narg--;
286                         }
287                 }
288                 while (narg) {
289                         if (decimal)
290                                 (void)printf("%c%d", c, *ip);
291                         else
292                                 (void)printf("%c%#x", c, *ip);
293                         c = ',';
294                         ip++;
295                         narg--;
296                 }
297                 (void)putchar(')');
298         }
299         (void)putchar('\n');
300 }
301
302 ktrsysret(ktr)
303         struct ktr_sysret *ktr;
304 {
305         register int ret = ktr->ktr_retval;
306         register int error = ktr->ktr_error;
307         register int code = ktr->ktr_code;
308
309         if (code >= nsyscalls || code < 0)
310                 (void)printf("[%d] ", code);
311         else
312                 (void)printf("%s ", syscallnames[code]);
313
314         if (error == 0) {
315                 if (fancy) {
316                         (void)printf("%d", ret);
317                         if (ret < 0 || ret > 9)
318                                 (void)printf("/%#x", ret);
319                 } else {
320                         if (decimal)
321                                 (void)printf("%d", ret);
322                         else
323                                 (void)printf("%#x", ret);
324                 }
325         } else if (error == ERESTART)
326                 (void)printf("RESTART");
327         else if (error == EJUSTRETURN)
328                 (void)printf("JUSTRETURN");
329         else {
330                 (void)printf("-1 errno %d", ktr->ktr_error);
331                 if (fancy)
332                         (void)printf(" %s", strerror(ktr->ktr_error));
333         }
334         (void)putchar('\n');
335 }
336
337 ktrnamei(cp, len) 
338         char *cp;
339 {
340         (void)printf("\"%.*s\"\n", len, cp);
341 }
342
343 ktrgenio(ktr, len)
344         struct ktr_genio *ktr;
345 {
346         register int datalen = len - sizeof (struct ktr_genio);
347         register char *dp = (char *)ktr + sizeof (struct ktr_genio);
348         register char *cp;
349         register int col = 0;
350         register width;
351         char visbuf[5];
352         static screenwidth = 0;
353
354         if (screenwidth == 0) {
355                 struct winsize ws;
356
357                 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
358                     ws.ws_col > 8)
359                         screenwidth = ws.ws_col;
360                 else
361                         screenwidth = 80;
362         }
363         printf("fd %d %s %d bytes\n", ktr->ktr_fd,
364                 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen);
365         if (maxdata && datalen > maxdata)
366                 datalen = maxdata;
367         (void)printf("       \"");
368         col = 8;
369         for (;datalen > 0; datalen--, dp++) {
370                 (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
371                 cp = visbuf;
372                 /*
373                  * Keep track of printables and
374                  * space chars (like fold(1)).
375                  */
376                 if (col == 0) {
377                         (void)putchar('\t');
378                         col = 8;
379                 }
380                 switch(*cp) {
381                 case '\n':
382                         col = 0;
383                         (void)putchar('\n');
384                         continue;
385                 case '\t':
386                         width = 8 - (col&07);
387                         break;
388                 default:
389                         width = strlen(cp);
390                 }
391                 if (col + width > (screenwidth-2)) {
392                         (void)printf("\\\n\t");
393                         col = 8;
394                 }
395                 col += width;
396                 do {
397                         (void)putchar(*cp++);
398                 } while (*cp);
399         }
400         if (col == 0)
401                 (void)printf("       ");
402         (void)printf("\"\n");
403 }
404
405 char *signames[] = {
406         "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",     /*  1 - 6  */
407         "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",             /*  7 - 12 */
408         "PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",         /* 13 - 18 */
409         "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",           /* 19 - 24 */
410         "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",        /* 25 - 30 */
411         "USR2", NULL,                                           /* 31 - 32 */
412 };
413
414 ktrpsig(psig)
415         struct ktr_psig *psig;
416 {
417         (void)printf("SIG%s ", signames[psig->signo]);
418         if (psig->action == SIG_DFL)
419                 (void)printf("SIG_DFL\n");
420         else
421                 (void)printf("caught handler=0x%x mask=0x%x code=0x%x\n",
422                     (u_int)psig->action, psig->mask, psig->code);
423 }
424
425 ktrcsw(cs)
426         struct ktr_csw *cs;
427 {
428         (void)printf("%s %s\n", cs->out ? "stop" : "resume",
429                 cs->user ? "user" : "kernel");
430 }
431
432 usage()
433 {
434         (void)fprintf(stderr,
435             "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnis]]\n");
436         exit(1);
437 }