Merge from vendor branch HOSTAPD:
[dragonfly.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  * @(#) Copyright (c) 1988, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)kdump.c  8.1 (Berkeley) 6/6/93
35  * $FreeBSD: src/usr.bin/kdump/kdump.c,v 1.17 1999/12/29 05:05:33 peter Exp $
36  * $DragonFly: src/usr.bin/kdump/kdump.c,v 1.8 2007/05/07 15:43:31 dillon Exp $
37  */
38
39 #define _KERNEL_STRUCTURES
40
41 #include <sys/errno.h>
42 #include <sys/param.h>
43 #include <sys/errno.h>
44 #include <sys/time.h>
45 #include <sys/uio.h>
46 #include <sys/ktrace.h>
47 #include <sys/ioctl.h>
48 #include <sys/ptrace.h>
49 #include <err.h>
50 #include <locale.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <vis.h>
56 #include "ktrace.h"
57
58 int timestamp, decimal, fancy = 1, tail, maxdata = 64;
59 int fixedformat;
60 char *tracefile = DEF_TRACEFILE;
61 struct ktr_header ktr_header;
62
63 #define eqs(s1, s2)     (strcmp((s1), (s2)) == 0)
64
65 main(int argc, char **argv)
66 {
67         int ch, col, ktrlen, size;
68         pid_t do_pid = -1;
69         register void *m;
70         int trpoints = ALL_POINTS;
71         char *cp;
72
73         (void) setlocale(LC_CTYPE, "");
74
75         while ((ch = getopt(argc,argv,"f:djlm:np:RTt:")) != -1)
76                 switch((char)ch) {
77                 case 'f':
78                         tracefile = optarg;
79                         break;
80                 case 'j':
81                         fixedformat = 1;
82                         break;
83                 case 'd':
84                         decimal = 1;
85                         break;
86                 case 'l':
87                         tail = 1;
88                         break;
89                 case 'm':
90                         maxdata = atoi(optarg);
91                         break;
92                 case 'n':
93                         fancy = 0;
94                         break;
95                 case 'p':
96                         do_pid = strtoul(optarg, &cp, 0);
97                         if (*cp != 0)
98                                 errx(1,"invalid number %s", optarg);
99                         break;
100                 case 'R':
101                         timestamp = 2;  /* relative timestamp */
102                         break;
103                 case 'T':
104                         timestamp = 1;
105                         break;
106                 case 't':
107                         trpoints = getpoints(optarg);
108                         if (trpoints < 0)
109                                 errx(1, "unknown trace point in %s", optarg);
110                         break;
111                 default:
112                         usage();
113                 }
114
115         if (argc > optind)
116                 usage();
117
118         m = (void *)malloc(size = 1025);
119         if (m == NULL)
120                 errx(1, "%s", strerror(ENOMEM));
121         if (!freopen(tracefile, "r", stdin))
122                 err(1, "%s", tracefile);
123         while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
124                 if (trpoints & (1 << ktr_header.ktr_type) &&
125                     (do_pid == -1 || ktr_header.ktr_pid == do_pid))
126                         col = dumpheader(&ktr_header);
127                 else
128                         col = -1;
129                 if ((ktrlen = ktr_header.ktr_len) < 0)
130                         errx(1, "bogus length 0x%x", ktrlen);
131                 if (ktrlen > size) {
132                         m = (void *)realloc(m, ktrlen+1);
133                         if (m == NULL)
134                                 errx(1, "%s", strerror(ENOMEM));
135                         size = ktrlen;
136                 }
137                 if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
138                         errx(1, "data too short");
139                 if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
140                         continue;
141                 if (col == -1)
142                         continue;
143                 switch (ktr_header.ktr_type) {
144                 case KTR_SYSCALL:
145                         ktrsyscall((struct ktr_syscall *)m);
146                         break;
147                 case KTR_SYSRET:
148                         ktrsysret((struct ktr_sysret *)m);
149                         break;
150                 case KTR_NAMEI:
151                         ktrnamei(m, ktrlen);
152                         break;
153                 case KTR_GENIO:
154                         ktrgenio((struct ktr_genio *)m, ktrlen);
155                         break;
156                 case KTR_PSIG:
157                         ktrpsig((struct ktr_psig *)m);
158                         break;
159                 case KTR_CSW:
160                         ktrcsw((struct ktr_csw *)m);
161                         break;
162                 case KTR_USER:
163                         ktruser(ktrlen, m);
164                         break;
165                 }
166                 if (tail)
167                         (void)fflush(stdout);
168         }
169 }
170
171 fread_tail(char *buf, int size, int num)
172 {
173         int i;
174
175         while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
176                 (void)sleep(1);
177                 clearerr(stdin);
178         }
179         return (i);
180 }
181
182 dumpheader(struct ktr_header *kth)
183 {
184         static char unknown[64];
185         static struct timeval prevtime, temp;
186         char *type;
187         int col;
188
189         switch (kth->ktr_type) {
190         case KTR_SYSCALL:
191                 type = "CALL";
192                 break;
193         case KTR_SYSRET:
194                 type = "RET ";
195                 break;
196         case KTR_NAMEI:
197                 type = "NAMI";
198                 break;
199         case KTR_GENIO:
200                 type = "GIO ";
201                 break;
202         case KTR_PSIG:
203                 type = "PSIG";
204                 break;
205         case KTR_CSW:
206                 type = "CSW";
207                 break;
208         case KTR_USER:
209                 type = "USER";
210                 break;
211         default:
212                 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
213                 type = unknown;
214         }
215
216         if (kth->ktr_tid || (kth->ktr_flags & KTRH_THREADED) || fixedformat)
217                 col = printf("%5d:%-4d", kth->ktr_pid, kth->ktr_tid);
218         else
219                 col = printf("%5d", kth->ktr_pid);
220         col += printf(" %-8.*s ", MAXCOMLEN, kth->ktr_comm);
221         if (timestamp) {
222                 if (timestamp == 2) {
223                         temp = kth->ktr_time;
224                         timevalsub(&kth->ktr_time, &prevtime);
225                         prevtime = temp;
226                 }
227                 col += printf("%ld.%06ld ",
228                     kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
229         }
230         col += printf("%s  ", type);
231         return col;
232 }
233
234 #include <sys/syscall.h>
235 #define KTRACE
236 #include <sys/kern/syscalls.c>
237 #undef KTRACE
238 int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
239
240 static char *ptrace_ops[] = {
241         "PT_TRACE_ME",  "PT_READ_I",    "PT_READ_D",    "PT_READ_U",
242         "PT_WRITE_I",   "PT_WRITE_D",   "PT_WRITE_U",   "PT_CONTINUE",
243         "PT_KILL",      "PT_STEP",      "PT_ATTACH",    "PT_DETACH",
244 };
245
246 ktrsyscall(register struct ktr_syscall *ktr)
247 {
248         register narg = ktr->ktr_narg;
249         register register_t *ip;
250         char *ioctlname();
251
252         if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
253                 (void)printf("[%d]", ktr->ktr_code);
254         else
255                 (void)printf("%s", syscallnames[ktr->ktr_code]);
256         ip = &ktr->ktr_args[0];
257         if (narg) {
258                 char c = '(';
259                 if (fancy) {
260                         if (ktr->ktr_code == SYS_ioctl) {
261                                 char *cp;
262                                 if (decimal)
263                                         (void)printf("(%ld", (long)*ip);
264                                 else
265                                         (void)printf("(%#lx", (long)*ip);
266                                 ip++;
267                                 narg--;
268                                 if ((cp = ioctlname(*ip)) != NULL)
269                                         (void)printf(",%s", cp);
270                                 else {
271                                         if (decimal)
272                                                 (void)printf(",%ld", (long)*ip);
273                                         else
274                                                 (void)printf(",%#lx ", (long)*ip);
275                                 }
276                                 c = ',';
277                                 ip++;
278                                 narg--;
279                         } else if (ktr->ktr_code == SYS_ptrace) {
280                                 if (*ip < sizeof(ptrace_ops) /
281                                     sizeof(ptrace_ops[0]) && *ip >= 0)
282                                         (void)printf("(%s", ptrace_ops[*ip]);
283 #ifdef PT_GETREGS
284                                 else if (*ip == PT_GETREGS)
285                                         (void)printf("(%s", "PT_GETREGS");
286 #endif
287 #ifdef PT_SETREGS
288                                 else if (*ip == PT_SETREGS)
289                                         (void)printf("(%s", "PT_SETREGS");
290 #endif
291 #ifdef PT_GETFPREGS
292                                 else if (*ip == PT_GETFPREGS)
293                                         (void)printf("(%s", "PT_GETFPREGS");
294 #endif
295 #ifdef PT_SETFPREGS
296                                 else if (*ip == PT_SETFPREGS)
297                                         (void)printf("(%s", "PT_SETFPREGS");
298 #endif
299 #ifdef PT_GETDBREGS
300                                 else if (*ip == PT_GETDBREGS)
301                                         (void)printf("(%s", "PT_GETDBREGS");
302 #endif
303 #ifdef PT_SETDBREGS
304                                 else if (*ip == PT_SETDBREGS)
305                                         (void)printf("(%s", "PT_SETDBREGS");
306 #endif
307                                 else
308                                         (void)printf("(%ld", (long)*ip);
309                                 c = ',';
310                                 ip++;
311                                 narg--;
312                         }
313                 }
314                 while (narg) {
315                         if (decimal)
316                                 (void)printf("%c%ld", c, (long)*ip);
317                         else
318                                 (void)printf("%c%#lx", c, (long)*ip);
319                         c = ',';
320                         ip++;
321                         narg--;
322                 }
323                 (void)putchar(')');
324         }
325         (void)putchar('\n');
326 }
327
328 ktrsysret(struct ktr_sysret *ktr)
329 {
330         register register_t ret = ktr->ktr_retval;
331         register int error = ktr->ktr_error;
332         register int code = ktr->ktr_code;
333
334         if (code >= nsyscalls || code < 0)
335                 (void)printf("[%d] ", code);
336         else
337                 (void)printf("%s ", syscallnames[code]);
338
339         if (error == 0) {
340                 if (fancy) {
341                         (void)printf("%d", ret);
342                         if (ret < 0 || ret > 9)
343                                 (void)printf("/%#lx", (long)ret);
344                 } else {
345                         if (decimal)
346                                 (void)printf("%ld", (long)ret);
347                         else
348                                 (void)printf("%#lx", (long)ret);
349                 }
350         } else if (error == ERESTART)
351                 (void)printf("RESTART");
352         else if (error == EJUSTRETURN)
353                 (void)printf("JUSTRETURN");
354         else {
355                 (void)printf("-1 errno %d", ktr->ktr_error);
356                 if (fancy)
357                         (void)printf(" %s", strerror(ktr->ktr_error));
358         }
359         (void)putchar('\n');
360 }
361
362 ktrnamei(char *cp, int len)
363 {
364         (void)printf("\"%.*s\"\n", len, cp);
365 }
366
367 ktrgenio(struct ktr_genio *ktr, int len)
368 {
369         register int datalen = len - sizeof (struct ktr_genio);
370         register char *dp = (char *)ktr + sizeof (struct ktr_genio);
371         register char *cp;
372         register int col = 0;
373         register width;
374         char visbuf[5];
375         static screenwidth = 0;
376
377         if (screenwidth == 0) {
378                 struct winsize ws;
379
380                 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
381                     ws.ws_col > 8)
382                         screenwidth = ws.ws_col;
383                 else
384                         screenwidth = 80;
385         }
386         printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
387                 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
388                 datalen == 1 ? "" : "s");
389         if (maxdata && datalen > maxdata)
390                 datalen = maxdata;
391         (void)printf("       \"");
392         col = 8;
393         for (;datalen > 0; datalen--, dp++) {
394                 (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
395                 cp = visbuf;
396                 /*
397                  * Keep track of printables and
398                  * space chars (like fold(1)).
399                  */
400                 if (col == 0) {
401                         (void)putchar('\t');
402                         col = 8;
403                 }
404                 switch(*cp) {
405                 case '\n':
406                         col = 0;
407                         (void)putchar('\n');
408                         continue;
409                 case '\t':
410                         width = 8 - (col&07);
411                         break;
412                 default:
413                         width = strlen(cp);
414                 }
415                 if (col + width > (screenwidth-2)) {
416                         (void)printf("\\\n\t");
417                         col = 8;
418                 }
419                 col += width;
420                 do {
421                         (void)putchar(*cp++);
422                 } while (*cp);
423         }
424         if (col == 0)
425                 (void)printf("       ");
426         (void)printf("\"\n");
427 }
428
429 char *signames[] = {
430         "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT",     /*  1 - 6  */
431         "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS",             /*  7 - 12 */
432         "PIPE", "ALRM",  "TERM", "URG", "STOP", "TSTP",         /* 13 - 18 */
433         "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU",           /* 19 - 24 */
434         "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1",        /* 25 - 30 */
435         "USR2", NULL,                                           /* 31 - 32 */
436 };
437
438 ktrpsig(struct ktr_psig *psig)
439 {
440         (void)printf("SIG%s ", signames[psig->signo]);
441         if (psig->action == SIG_DFL)
442                 (void)printf("SIG_DFL\n");
443         else
444                 (void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
445                     (u_long)psig->action, psig->mask, psig->code);
446 }
447
448 ktrcsw(struct ktr_csw *cs)
449 {
450         (void)printf("%s %s\n", cs->out ? "stop" : "resume",
451                 cs->user ? "user" : "kernel");
452 }
453
454 ktruser(int len, unsigned char *p)
455 {
456         (void)printf("%d ", len);
457         while (len--)
458                 (void)printf(" %02x", *p++);
459         (void)printf("\n");
460                 
461 }
462
463 usage(void)
464 {
465         (void)fprintf(stderr,
466             "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]] [-p pid]\n");
467         exit(1);
468 }
469
470 timevalsub(struct timeval *t1, struct timeval *t2)
471 {
472         t1->tv_sec -= t2->tv_sec;
473         t1->tv_usec -= t2->tv_usec;
474         timevalfix(t1);
475 }
476
477 timevalfix(struct timeval *t1)
478 {
479         if (t1->tv_usec < 0) {
480                 t1->tv_sec--;
481                 t1->tv_usec += 1000000;
482         }
483         if (t1->tv_usec >= 1000000) {
484                 t1->tv_sec++;
485                 t1->tv_usec -= 1000000;
486         }
487 }