1 /* $NetBSD: dump.c,v 1.35 2009/05/02 21:01:01 mlelstv Exp $ */
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95";
42 __RCSID("$NetBSD: dump.c,v 1.35 2009/05/02 21:01:01 mlelstv Exp $");
45 #include <sys/param.h>
47 #include <sys/errno.h>
49 #include <sys/ioctl.h>
52 #include <sys/ktrace.h>
53 #include <sys/ptrace.h>
54 #include <sys/queue.h>
70 int timestamp
, decimal
, fancy
= 1, tail
, maxdata
;
72 int width
; /* Keep track of current columns. */
74 #include <sys/syscall.h>
76 static const char *const ptrace_ops
[] = {
77 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U",
78 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE",
79 "PT_KILL", "PT_ATTACH", "PT_DETACH",
83 TAILQ_ENTRY(ktr_entry
) kte_list
;
84 struct ktr_header kte_kth
;
87 TAILQ_HEAD(kteq
, ktr_entry
) ktependq
= TAILQ_HEAD_INITIALIZER(ktependq
);
89 void argprint(const char *, register_t
**, int *);
90 void dumpheader(struct ktr_header
*);
91 int dumprecord(int, FILE *);
92 void flushpendq(struct ktr_entry
*);
93 int fread_tail(void *, int, int, FILE *);
94 void genioprint(struct ktr_header
*);
96 getpendq(struct ktr_header
*, int, struct kteq
*);
100 void ioctldecode(u_long
);
101 void ktrcsw(struct ktr_entry
*);
102 void ktremul(struct ktr_entry
*);
103 void ktrgenio(struct ktr_entry
*);
104 void ktrnamei(struct ktr_entry
*);
105 void ktrpsig(struct ktr_entry
*);
106 void ktrsyscall(struct ktr_entry
*);
107 void ktrsysret(struct ktr_entry
*);
108 void nameiargprint(const char *, struct ktr_header
*, register_t
**, int *);
109 void nameiprint(struct ktr_header
*);
111 void putpendq(struct ktr_entry
*);
112 void syscallnameprint(int);
113 void syscallprint(struct ktr_header
*);
114 void sysretprint(struct ktr_header
*);
115 int wprintf(const char *, ...);
116 void *xrealloc(void *, size_t *, size_t);
119 wprintf(const char *fmt
, ...)
125 w
= vprintf(fmt
, ap
);
149 if (wprintf(" ") < 0)
154 xrealloc(void *p
, size_t *siz
, size_t req
)
162 p
= realloc(p
, *siz
);
164 err(EXIT_FAILURE
, "realloc: %lu bytes",
173 struct ktr_entry
*kte
;
174 struct ktr_header
*kth
;
179 kte
= xrealloc(NULL
, &siz
, sizeof(struct ktr_entry
));
181 if (fread_tail(kth
, sizeof(struct ktr_header
), 1, fp
) == 0) {
186 if (kth
->ktr_len
< 0)
187 errx(EXIT_FAILURE
, "bogus length 0x%x", kth
->ktr_len
);
190 /* + 1 to ensure room for NUL terminate */
191 kte
= xrealloc(kte
, &siz
, sizeof(struct ktr_entry
) + len
+ 1);
192 if (fread_tail(cp
= (char *)(&kte
->kte_kth
+ 1),
194 errx(EXIT_FAILURE
, "data too short");
201 #define KTE_TYPE(kte) ((kte)->kte_kth.ktr_type)
202 #define KTE_PID(kte) ((kte)->kte_kth.ktr_pid)
203 #define KTE_LID(kte) ((kte)->kte_kth.ktr_lid)
204 #define KTE_MATCH(kte, type, pid, lid) \
205 (KTE_TYPE(kte) == (type) && KTE_PID(kte) == (pid) && \
206 KTE_LID(kte) == (lid))
209 putpendq(struct ktr_entry
*kte
)
212 TAILQ_INSERT_TAIL(&ktependq
, kte
, kte_list
);
216 flushpendq(struct ktr_entry
*us
)
218 struct ktr_entry
*kte
, *kte_next
;
219 int pid
= KTE_PID(us
), lid
= KTE_LID(us
);
221 for (kte
= TAILQ_FIRST(&ktependq
); kte
!= NULL
; kte
= kte_next
) {
222 kte_next
= TAILQ_NEXT(kte
, kte_list
);
223 if (KTE_PID(kte
) == pid
|| KTE_LID(kte
) == lid
) {
224 TAILQ_REMOVE(&ktependq
, kte
, kte_list
);
231 getpendq(struct ktr_header
*us
, int type
, struct kteq
*kteq
)
233 struct ktr_entry
*kte
, *kte_next
;
234 int pid
= us
->ktr_pid
, lid
= us
->ktr_lid
;
238 for (kte
= TAILQ_FIRST(&ktependq
); kte
!= NULL
; kte
= kte_next
) {
239 kte_next
= TAILQ_NEXT(kte
, kte_list
);
240 if (KTE_MATCH(kte
, type
, pid
, lid
)) {
241 TAILQ_REMOVE(&ktependq
, kte
, kte_list
);
243 TAILQ_INSERT_TAIL(kteq
, kte
, kte_list
);
249 return (kteq
? TAILQ_FIRST(kteq
) : kte
);
253 dumprecord(int trpoints
, FILE *fp
)
255 struct ktr_entry
*kte
;
256 struct ktr_header
*kth
;
263 if ((trpoints
& (1 << kth
->ktr_type
)) == 0) {
268 /* Update context to match currently processed record. */
269 ectx_sanify(kth
->ktr_pid
);
271 switch (kth
->ktr_type
) {
295 * XXX: Other types added recently.
307 dumpfile(const char *file
, int fd
, int trpoints
)
311 if (file
== NULL
|| *file
== 0) {
312 if ((fp
= fdopen(fd
, "r")) == NULL
)
313 err(EXIT_FAILURE
, "fdopen(%d)", fd
);
314 } else if (strcmp(file
, "-") == 0)
316 else if ((fp
= fopen(file
, "r")) == NULL
)
317 err(EXIT_FAILURE
, "fopen: %s", file
);
319 for (width
= 0; dumprecord(trpoints
, fp
) != 0;)
321 (void)fflush(stdout
);
326 * XXX: Dump pending KTR_SYSCALL if any?
331 fread_tail(void *buf
, int size
, int num
, FILE *fp
)
335 while ((i
= fread(buf
, size
, num
, fp
)) == 0 && tail
) {
343 dumpheader(struct ktr_header
*kth
)
349 static union timeholder prevtime
;
350 union timeholder temp
;
352 wprintf("%6d ", kth
->ktr_pid
);
353 if (kth
->ktr_version
> KTRFAC_VERSION(KTRFACv0
))
354 wprintf("%6d ", kth
->ktr_lid
);
355 wprintf("%-8.*s ", MAXCOMLEN
, kth
->ktr_comm
);
357 if (timestamp
== 2) {
358 switch (kth
->ktr_version
) {
359 case KTRFAC_VERSION(KTRFACv0
):
360 if (prevtime
.tv
.tv_sec
== 0)
361 temp
.tv
.tv_sec
= temp
.tv
.tv_usec
= 0;
363 timersub(&kth
->ktr_otv
,
364 &prevtime
.tv
, &temp
.tv
);
365 prevtime
.tv
.tv_sec
= kth
->ktr_otv
.tv_sec
;
366 prevtime
.tv
.tv_usec
= kth
->ktr_otv
.tv_usec
;
369 case KTRFAC_VERSION(KTRFACv1
):
370 if (prevtime
.ts
.tv_sec
== 0)
371 temp
.ts
.tv_sec
= temp
.ts
.tv_nsec
= 0;
373 timespecsub(&kth
->ktr_time
,
374 &prevtime
.ts
, &temp
.ts
);
375 prevtime
.ts
.tv_sec
= kth
->ktr_ots
.tv_sec
;
376 prevtime
.ts
.tv_nsec
= kth
->ktr_ots
.tv_nsec
;
379 case KTRFAC_VERSION(KTRFACv2
):
380 if (prevtime
.ts
.tv_sec
== 0)
381 temp
.ts
.tv_sec
= temp
.ts
.tv_nsec
= 0;
383 timespecsub(&kth
->ktr_time
,
384 &prevtime
.ts
, &temp
.ts
);
385 prevtime
.ts
.tv_sec
= kth
->ktr_ts
.tv_sec
;
386 prevtime
.ts
.tv_nsec
= kth
->ktr_ts
.tv_nsec
;
390 switch (kth
->ktr_version
) {
391 case KTRFAC_VERSION(KTRFACv0
):
392 temp
.tv
.tv_sec
= kth
->ktr_otv
.tv_sec
;
393 temp
.tv
.tv_usec
= kth
->ktr_otv
.tv_usec
;
395 case KTRFAC_VERSION(KTRFACv1
):
396 temp
.ts
.tv_sec
= kth
->ktr_ots
.tv_sec
;
397 temp
.ts
.tv_nsec
= kth
->ktr_ots
.tv_nsec
;
399 case KTRFAC_VERSION(KTRFACv2
):
400 temp
.ts
.tv_sec
= kth
->ktr_ts
.tv_sec
;
401 temp
.ts
.tv_nsec
= kth
->ktr_ts
.tv_nsec
;
405 if (kth
->ktr_version
== KTRFAC_VERSION(KTRFACv0
))
406 wprintf("%lld.%06ld ",
407 (long long)temp
.tv
.tv_sec
, (long)temp
.tv
.tv_usec
);
409 wprintf("%lld.%09ld ",
410 (long long)temp
.ts
.tv_sec
, (long)temp
.ts
.tv_nsec
);
415 ioctldecode(u_long cmd
)
417 char dirbuf
[4], *dir
= dirbuf
;
425 wprintf(decimal
? ", _IO%s('%c',%ld" : ", _IO%s('%c',%#lx",
426 dirbuf
, (int) ((cmd
>> 8) & 0xff), cmd
& 0xff);
427 if ((cmd
& IOC_VOID
) == 0)
428 wprintf(decimal
? ",%ld)" : ",%#lx)",
435 nameiargprint(const char *prefix
, struct ktr_header
*kth
,
436 register_t
**ap
, int *argsize
)
438 struct ktr_entry
*kte
;
441 errx(EXIT_FAILURE
, "argument expected");
443 * XXX: binary emulation mode.
445 kte
= getpendq(kth
, KTR_NAMEI
, NULL
);
447 argprint(prefix
, ap
, argsize
);
449 wprintf("%s", prefix
);
450 nameiprint(&kte
->kte_kth
);
453 *argsize
-= sizeof(register_t
);
458 syscallnameprint(int code
)
461 if (code
>= cur_emul
->nsysnames
|| code
< 0)
462 wprintf("[%d]", code
);
464 wprintf("%s", cur_emul
->sysnames
[code
]);
468 argprint(const char *prefix
, register_t
**ap
, int *argsize
)
472 wprintf("%s%ld", prefix
, (long)**ap
);
474 wprintf("%s%#lx", prefix
, (long)**ap
);
476 *argsize
-= sizeof(register_t
);
480 syscallprint(struct ktr_header
*kth
)
482 struct ktr_syscall
*ktr
= (struct ktr_syscall
*)(kth
+ 1);
487 syscallnameprint(ktr
->ktr_code
);
490 * Arguments processing.
492 argsize
= ktr
->ktr_argsize
;
498 ap
= (register_t
*)(ktr
+ 1);
502 switch (ktr
->ktr_code
) {
504 * All these have a path as the first param.
505 * The order is same as syscalls.master.
530 case SYS_compat_30_getfh
:
534 case SYS___posix_rename
:
537 case SYS___lutimes50
:
540 case SYS___posix_chown
:
541 case SYS___posix_lchown
:
544 nameiargprint("(", kth
, &ap
, &argsize
);
547 * 2nd argument is also pathname.
549 switch (ktr
->ktr_code
) {
552 case SYS___posix_rename
:
553 nameiargprint(", ", kth
, &ap
, &argsize
);
558 case SYS_compat_16___sigaction14
:
559 wprintf("(%s", signals
[(int)*ap
].name
);
561 argsize
-= sizeof(register_t
);
565 argprint("(", &ap
, &argsize
);
566 if ((s
= ioctlname(*ap
)) != NULL
)
571 argsize
-= sizeof(register_t
);
575 if ((long)*ap
>= 0 &&
576 *ap
< (register_t
)(sizeof(ptrace_ops
) / sizeof(ptrace_ops
[0])))
577 wprintf("(%s", ptrace_ops
[*ap
]);
579 wprintf("(%ld", (long)*ap
);
581 argsize
-= sizeof(register_t
);
586 argprint("(", &ap
, &argsize
);
590 /* Print rest of argument. */
592 argprint(", ", &ap
, &argsize
);
599 ktrsyscall(struct ktr_entry
*kte
)
601 struct ktr_header
*kth
= &kte
->kte_kth
;
602 struct ktr_syscall
*ktr
= (struct ktr_syscall
*)(kth
+ 1);
604 switch (ktr
->ktr_code
) {
618 sysretprint(struct ktr_header
*kth
)
620 struct ktr_sysret
*ktr
= (struct ktr_sysret
*)(kth
+ 1);
621 register_t ret
= ktr
->ktr_retval
;
622 int error
= ktr
->ktr_error
;
625 if (error
== EJUSTRETURN
)
626 wprintf(" JUSTRETURN");
627 else if (error
== ERESTART
)
630 wprintf(" Err#%d", error
);
631 if (error
< MAXERRNOS
&& error
>= -2)
632 wprintf(" %s", errnos
[error
].name
);
634 switch (ktr
->ktr_code
) {
636 wprintf(" = %p", (long)ret
);
639 wprintf(" = %ld", (long)ret
);
640 if (kth
->ktr_len
> (int)offsetof(struct ktr_sysret
,
641 ktr_retval_1
) && ktr
->ktr_retval_1
!= 0)
642 wprintf(", %ld", (long)ktr
->ktr_retval_1
);
648 ktrsysret(struct ktr_entry
*kte
)
650 struct ktr_header
*kth
= &kte
->kte_kth
;
651 struct ktr_sysret
*ktr
= (struct ktr_sysret
*)(kth
+ 1);
652 struct ktr_entry
*emul
;
653 struct ktr_entry
*genio
;
654 struct ktr_entry
*syscall_ent
;
658 /* Print syscall name and arguments. */
659 syscall_ent
= getpendq(kth
, KTR_SYSCALL
, NULL
);
660 if (syscall_ent
== NULL
) {
662 * Possibilly a child of fork/vfork, or tracing of
663 * process started during system call.
665 syscallnameprint(ktr
->ktr_code
);
667 syscallprint(&syscall_ent
->kte_kth
);
671 /* Print return value and an error if any. */
674 genio
= getpendq(kth
, KTR_GENIO
, NULL
);
676 genioprint(&genio
->kte_kth
);
680 emul
= getpendq(kth
, KTR_EMUL
, NULL
);
691 nameiprint(struct ktr_header
*kth
)
694 wprintf("\"%.*s\"", kth
->ktr_len
, (char *)(kth
+ 1));
699 ktrnamei(struct ktr_entry
*kte
)
701 struct ktr_header
*kth
= &kte
->kte_kth
;
713 ktremul(struct ktr_entry
*kte
)
715 struct ktr_header
*kth
= &kte
->kte_kth
;
716 char *emul
= (char *)(kth
+ 1);
719 wprintf("emul(%s)", emul
);
720 setemul(emul
, kth
->ktr_pid
, 1);
726 genioprint(struct ktr_header
*kth
)
728 struct ktr_genio
*ktr
= (struct ktr_genio
*)(kth
+ 1);
729 static int screenwidth
= 0;
730 int datalen
= kth
->ktr_len
- sizeof(struct ktr_genio
);
732 * Need to be unsigned type so that positive value is passed
733 * to vis(), which will call isgraph().
735 unsigned char *dp
= (unsigned char *)(ktr
+ 1);
739 if (screenwidth
== 0) {
742 if (fancy
&& ioctl(fileno(stderr
), TIOCGWINSZ
, &ws
) != -1 &&
744 screenwidth
= ws
.ws_col
;
749 if (maxdata
&& datalen
> maxdata
)
753 for (; datalen
> 0; datalen
--, dp
++) {
754 (void) vis(visbuf
, *dp
, VIS_NL
|VIS_TAB
|VIS_CSTYLE
,
755 /* We put NUL at the end of buffer when reading */
759 if (width
+ w
+ 2 >= screenwidth
)
761 wprintf("%s", visbuf
);
762 if (width
+ 2 >= screenwidth
)
770 ktrgenio(struct ktr_entry
*kte
)
772 struct ktr_header
*kth
= &kte
->kte_kth
;
773 struct ktr_genio
*ktr
= (struct ktr_genio
*)(kth
+ 1);
776 wprintf("genio fd %d %s",
777 ktr
->ktr_fd
, ktr
->ktr_rw
? "write" : "read");
785 ktrpsig(struct ktr_entry
*kte
)
787 struct ktr_header
*kth
= &kte
->kte_kth
;
788 struct ktr_psig
*psig
= (struct ktr_psig
*)(kth
+ 1);
791 wprintf("SIG%s ", sys_signame
[psig
->signo
]);
792 if (psig
->action
== SIG_DFL
)
795 wprintf("caught handler=0x%lx mask=0x%lx code=0x%x",
796 (u_long
)psig
->action
, (unsigned long)psig
->mask
.__bits
[0],
804 ktrcsw(struct ktr_entry
*kte
)
806 struct ktr_header
*kth
= &kte
->kte_kth
;
807 struct ktr_csw
*cs
= (struct ktr_csw
*)(kth
+ 1);
810 wprintf("%s %s", cs
->out
? "stop" : "resume",
811 cs
->user
? "user" : "kernel");