syscall.c revision b046b38593b6bca6b6c49ac1fcc09dd5cd4c94b2
1/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 * 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. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 *	$Id$
30 */
31
32#include "defs.h"
33
34#include <signal.h>
35#include <time.h>
36#include <errno.h>
37#include <sys/user.h>
38#include <sys/syscall.h>
39#include <sys/param.h>
40
41#ifdef HAVE_SYS_REG_H
42#include <sys/reg.h>
43# define PTRACE_PEEKUSR PTRACE_PEEKUSER
44#endif
45
46#if defined(linux) && !defined(__GLIBC__)
47#include <linux/ptrace.h>
48#endif
49
50#ifndef SYS_ERRLIST_DECLARED
51extern int sys_nerr;
52extern char *sys_errlist[];
53#endif /* SYS_ERRLIST_DECLARED */
54
55#ifdef LINUX
56#ifndef ERESTARTSYS
57#define ERESTARTSYS	512
58#endif
59#ifndef ERESTARTNOINTR
60#define ERESTARTNOINTR	513
61#endif
62#ifndef ERESTARTNOHAND
63#define ERESTARTNOHAND	514	/* restart if no handler.. */
64#endif
65#ifndef ENOIOCTLCMD
66#define ENOIOCTLCMD	515	/* No ioctl command */
67#endif
68#ifndef NSIG
69#define NSIG 32
70#endif
71#ifdef ARM
72#undef NSIG
73#define NSIG 32
74#endif
75#endif /* LINUX */
76
77#include "syscall.h"
78
79/* Define these shorthand notations to simplify the syscallent files. */
80#define TF TRACE_FILE
81#define TI TRACE_IPC
82#define TN TRACE_NETWORK
83#define TP TRACE_PROCESS
84#define TS TRACE_SIGNAL
85
86struct sysent sysent0[] = {
87#include "syscallent.h"
88};
89int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
90
91#if SUPPORTED_PERSONALITIES >= 2
92struct sysent sysent1[] = {
93#include "syscallent1.h"
94};
95int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
96#endif /* SUPPORTED_PERSONALITIES >= 2 */
97
98#if SUPPORTED_PERSONALITIES >= 3
99struct sysent sysent2[] = {
100#include "syscallent2.h"
101};
102int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
103#endif /* SUPPORTED_PERSONALITIES >= 3 */
104
105struct sysent *sysent;
106int nsyscalls;
107
108/* Now undef them since short defines cause wicked namespace pollution. */
109#undef TF
110#undef TI
111#undef TN
112#undef TP
113#undef TS
114
115char *errnoent0[] = {
116#include "errnoent.h"
117};
118int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
119
120#if SUPPORTED_PERSONALITIES >= 2
121char *errnoent1[] = {
122#include "errnoent1.h"
123};
124int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
125#endif /* SUPPORTED_PERSONALITIES >= 2 */
126
127#if SUPPORTED_PERSONALITIES >= 3
128char *errnoent2[] = {
129#include "errnoent2.h"
130};
131int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
132#endif /* SUPPORTED_PERSONALITIES >= 3 */
133
134char **errnoent;
135int nerrnos;
136
137int current_personality;
138
139int
140set_personality(personality)
141int personality;
142{
143	switch (personality) {
144	case 0:
145		errnoent = errnoent0;
146		nerrnos = nerrnos0;
147		sysent = sysent0;
148		nsyscalls = nsyscalls0;
149		ioctlent = ioctlent0;
150		nioctlents = nioctlents0;
151		signalent = signalent0;
152		nsignals = nsignals0;
153		break;
154
155#if SUPPORTED_PERSONALITIES >= 2
156	case 1:
157		errnoent = errnoent1;
158		nerrnos = nerrnos1;
159		sysent = sysent1;
160		nsyscalls = nsyscalls1;
161		ioctlent = ioctlent1;
162		nioctlents = nioctlents1;
163		signalent = signalent1;
164		nsignals = nsignals1;
165		break;
166#endif /* SUPPORTED_PERSONALITIES >= 2 */
167
168#if SUPPORTED_PERSONALITIES >= 3
169	case 2:
170		errnoent = errnoent2;
171		nerrnos = nerrnos2;
172		sysent = sysent2;
173		nsyscalls = nsyscalls2;
174		ioctlent = ioctlent2;
175		nioctlents = nioctlents2;
176		signalent = signalent2;
177		nsignals = nsignals2;
178		break;
179#endif /* SUPPORTED_PERSONALITIES >= 3 */
180
181	default:
182		return -1;
183	}
184
185	current_personality = personality;
186	return 0;
187}
188
189int qual_flags[MAX_QUALS];
190
191static int call_count[MAX_QUALS];
192static int error_count[MAX_QUALS];
193static struct timeval tv_count[MAX_QUALS];
194static int sorted_count[MAX_QUALS];
195
196static struct timeval shortest = { 1000000, 0 };
197
198static int lookup_syscall(), lookup_signal(), lookup_fault(), lookup_desc();
199
200static struct qual_options {
201	int bitflag;
202	char *option_name;
203	int (*lookup)();
204	char *argument_name;
205} qual_options[] = {
206	{ QUAL_TRACE,	"trace",	lookup_syscall,	"system call"	},
207	{ QUAL_TRACE,	"t",		lookup_syscall,	"system call"	},
208	{ QUAL_ABBREV,	"abbrev",	lookup_syscall,	"system call"	},
209	{ QUAL_ABBREV,	"a",		lookup_syscall,	"system call"	},
210	{ QUAL_VERBOSE,	"verbose",	lookup_syscall,	"system call"	},
211	{ QUAL_VERBOSE,	"v",		lookup_syscall,	"system call"	},
212	{ QUAL_RAW,	"raw",		lookup_syscall,	"system call"	},
213	{ QUAL_RAW,	"x",		lookup_syscall,	"system call"	},
214	{ QUAL_SIGNAL,	"signal",	lookup_signal,	"signal"	},
215	{ QUAL_SIGNAL,	"signals",	lookup_signal,	"signal"	},
216	{ QUAL_SIGNAL,	"s",		lookup_signal,	"signal"	},
217	{ QUAL_FAULT,	"fault",	lookup_fault,	"fault"		},
218	{ QUAL_FAULT,	"faults",	lookup_fault,	"fault"		},
219	{ QUAL_FAULT,	"m",		lookup_fault,	"fault"		},
220	{ QUAL_READ,	"read",		lookup_desc,	"descriptor"	},
221	{ QUAL_READ,	"reads",	lookup_desc,	"descriptor"	},
222	{ QUAL_READ,	"r",		lookup_desc,	"descriptor"	},
223	{ QUAL_WRITE,	"write",	lookup_desc,	"descriptor"	},
224	{ QUAL_WRITE,	"writes",	lookup_desc,	"descriptor"	},
225	{ QUAL_WRITE,	"w",		lookup_desc,	"descriptor"	},
226	{ 0,		NULL,		NULL,		NULL		},
227};
228
229static int
230lookup_syscall(s)
231char *s;
232{
233	int i;
234
235	for (i = 0; i < nsyscalls; i++) {
236		if (strcmp(s, sysent[i].sys_name) == 0)
237			return i;
238	}
239	return -1;
240}
241
242static int
243lookup_signal(s)
244char *s;
245{
246	int i;
247	char buf[32];
248
249	if (s && *s && isdigit(*s))
250		return atoi(s);
251	strcpy(buf, s);
252	s = buf;
253	for (i = 0; s[i]; i++)
254		s[i] = toupper(s[i]);
255	if (strncmp(s, "SIG", 3) == 0)
256		s += 3;
257	for (i = 0; i <= NSIG; i++) {
258		if (strcmp(s, signame(i) + 3) == 0)
259			return i;
260	}
261	return -1;
262}
263
264static int
265lookup_fault(s)
266char *s;
267{
268	return -1;
269}
270
271static int
272lookup_desc(s)
273char *s;
274{
275	if (s && *s && isdigit(*s))
276		return atoi(s);
277	return -1;
278}
279
280static int
281lookup_class(s)
282char *s;
283{
284	if (strcmp(s, "file") == 0)
285		return TRACE_FILE;
286	if (strcmp(s, "ipc") == 0)
287		return TRACE_IPC;
288	if (strcmp(s, "network") == 0)
289		return TRACE_NETWORK;
290	if (strcmp(s, "process") == 0)
291		return TRACE_PROCESS;
292	if (strcmp(s, "signal") == 0)
293		return TRACE_SIGNAL;
294	return -1;
295}
296
297void
298qualify(s)
299char *s;
300{
301	struct qual_options *opt;
302	int not;
303	char *p;
304	int i, n;
305
306	opt = &qual_options[0];
307	for (i = 0; (p = qual_options[i].option_name); i++) {
308		n = strlen(p);
309		if (strncmp(s, p, n) == 0 && s[n] == '=') {
310			opt = &qual_options[i];
311			s += n + 1;
312			break;
313		}
314	}
315	not = 0;
316	if (*s == '!') {
317		not = 1;
318		s++;
319	}
320	if (strcmp(s, "none") == 0) {
321		not = 1 - not;
322		s = "all";
323	}
324	if (strcmp(s, "all") == 0) {
325		for (i = 0; i < MAX_QUALS; i++) {
326			if (not)
327				qual_flags[i] &= ~opt->bitflag;
328			else
329				qual_flags[i] |= opt->bitflag;
330		}
331		return;
332	}
333	for (i = 0; i < MAX_QUALS; i++) {
334		if (not)
335			qual_flags[i] |= opt->bitflag;
336		else
337			qual_flags[i] &= ~opt->bitflag;
338	}
339	for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
340		if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
341			for (i = 0; i < MAX_QUALS; i++) {
342				if (sysent[i].sys_flags & n) {
343					if (not)
344						qual_flags[i] &= ~opt->bitflag;
345					else
346						qual_flags[i] |= opt->bitflag;
347				}
348			}
349			continue;
350		}
351		if ((n = (*opt->lookup)(p)) < 0) {
352			fprintf(stderr, "strace: invalid %s `%s'\n",
353				opt->argument_name, p);
354			exit(1);
355		}
356		if (not)
357			qual_flags[n] &= ~opt->bitflag;
358		else
359			qual_flags[n] |= opt->bitflag;
360	}
361	return;
362}
363
364static void
365dumpio(tcp)
366struct tcb *tcp;
367{
368	if (syserror(tcp))
369		return;
370	if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
371		return;
372#ifdef __arm__
373	switch (tcp->scno + __NR_SYSCALL_BASE) {
374#else
375	switch (tcp->scno) {
376#endif
377	case SYS_read:
378#ifdef SYS_recv
379	case SYS_recv:
380#endif
381#ifdef SYS_recvfrom
382	case SYS_recvfrom:
383#endif
384		if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
385			dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
386		break;
387	case SYS_write:
388#ifdef SYS_send
389	case SYS_send:
390#endif
391#ifdef SYS_sendto
392	case SYS_sendto:
393#endif
394		if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
395			dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
396		break;
397	}
398}
399
400enum subcall_style { shift_style, deref_style, mask_style, door_style };
401
402#if !(defined(LINUX) && defined(ALPHA))
403
404const int socket_map [] = {
405	       /* SYS_SOCKET      */ 97,
406	       /* SYS_BIND        */ 104,
407	       /* SYS_CONNECT     */ 98,
408	       /* SYS_LISTEN      */ 106,
409	       /* SYS_ACCEPT      */ 99,
410	       /* SYS_GETSOCKNAME */ 150,
411	       /* SYS_GETPEERNAME */ 141,
412	       /* SYS_SOCKETPAIR  */ 135,
413	       /* SYS_SEND        */ 101,
414	       /* SYS_RECV        */ 102,
415	       /* SYS_SENDTO      */ 133,
416	       /* SYS_RECVFROM    */ 125,
417	       /* SYS_SHUTDOWN    */ 134,
418	       /* SYS_SETSOCKOPT  */ 105,
419	       /* SYS_GETSOCKOPT  */ 118,
420	       /* SYS_SENDMSG     */ 114,
421	       /* SYS_RECVMSG     */ 113
422};
423
424void
425sparc_socket_decode (tcp)
426struct tcb *tcp;
427{
428	volatile long addr;
429	volatile int i, n;
430
431	if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
432		return;
433	}
434	tcp->scno = socket_map [tcp->u_arg [0]-1];
435	n = tcp->u_nargs = sysent [tcp->scno].nargs;
436	addr = tcp->u_arg [1];
437	for (i = 0; i < n; i++){
438	        int arg;
439		if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
440			arg = 0;
441		tcp->u_arg [i] = arg;
442		addr += sizeof (arg);
443	}
444}
445
446static void
447decode_subcall(tcp, subcall, nsubcalls, style)
448struct tcb *tcp;
449int subcall;
450int nsubcalls;
451enum subcall_style style;
452{
453	int i, addr, mask, arg;
454
455	if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
456		return;
457	switch (style) {
458	case shift_style:
459		tcp->scno = subcall + tcp->u_arg[0];
460		if (sysent[tcp->scno].nargs != -1)
461			tcp->u_nargs = sysent[tcp->scno].nargs;
462		else
463			tcp->u_nargs--;
464		for (i = 0; i < tcp->u_nargs; i++)
465			tcp->u_arg[i] = tcp->u_arg[i + 1];
466		break;
467	case deref_style:
468		tcp->scno = subcall + tcp->u_arg[0];
469		addr = tcp->u_arg[1];
470		for (i = 0; i < sysent[tcp->scno].nargs; i++) {
471			if (umove(tcp, addr, &arg) < 0)
472				arg = 0;
473			tcp->u_arg[i] = arg;
474			addr += sizeof(arg);
475		}
476		tcp->u_nargs = sysent[tcp->scno].nargs;
477		break;
478	case mask_style:
479		mask = (tcp->u_arg[0] >> 8) & 0xff;
480		tcp->u_arg[0] &= 0xff;
481		for (i = 0; mask; i++)
482			mask >>= 1;
483		tcp->scno = subcall + i;
484		if (sysent[tcp->scno].nargs != -1)
485			tcp->u_nargs = sysent[tcp->scno].nargs;
486		break;
487	case door_style:
488		/*
489		 * Oh, yuck.  The call code is the *sixth* argument.
490		 */
491		tcp->scno = subcall + tcp->u_arg[5];
492		if (sysent[tcp->scno].nargs != -1)
493			tcp->u_nargs = sysent[tcp->scno].nargs;
494		else
495			tcp->u_nargs--;
496		break;
497	}
498}
499#endif
500
501struct tcb *tcp_last = NULL;
502
503static int
504internal_syscall(tcp)
505struct tcb *tcp;
506{
507	/*
508	 * We must always trace a few critical system calls in order to
509	 * correctly support following forks in the presence of tracing
510	 * qualifiers.
511	 */
512#ifdef __arm__
513	switch (tcp->scno + __NR_SYSCALL_BASE) {
514#else
515	switch (tcp->scno) {
516#endif
517#ifdef SYS_fork
518	case SYS_fork:
519#endif
520#ifdef SYS_vfork
521	case SYS_vfork:
522#endif
523#ifdef SYS_clone
524	case SYS_clone:
525#endif
526		internal_fork(tcp);
527		break;
528
529#ifdef SYS_execv
530	case SYS_execv:
531#endif
532#ifdef SYS_execve
533	case SYS_execve:
534#endif
535		internal_exec(tcp);
536		break;
537
538#ifdef SYS_wait
539	case SYS_wait:
540#endif
541#ifdef SYS_wait4
542	case SYS_wait4:
543#endif
544#ifdef SYS_waitpid
545	case SYS_waitpid:
546#endif
547#ifdef SYS_waitsys
548	case SYS_waitsys:
549#endif
550		internal_wait(tcp);
551		break;
552
553#ifdef SYS_exit
554	case SYS_exit:
555#endif
556		internal_exit(tcp);
557		break;
558	}
559	return 0;
560}
561
562int
563trace_syscall(tcp)
564struct tcb *tcp;
565{
566	int sys_res;
567	struct timeval tv;
568	long scno = 0;
569#ifdef LINUX
570#if defined (I386)
571	long eax;
572#elif defined (POWERPC)
573	long result,flags;
574#elif defined (M68K)
575	int d0;
576#elif defined (ARM)
577	int r0;
578#elif defined (ALPHA)
579	long r0;
580	long a3;
581#elif defined (SPARC)
582	struct pt_regs regs;
583	unsigned long trap;
584#endif
585#endif /* LINUX */
586
587#ifndef SVR4
588	int pid = tcp->pid;
589#endif /* !SVR4 */
590
591	/* Measure the exit time as early as possible to avoid errors. */
592	if (dtime && (tcp->flags & TCB_INSYSCALL))
593		gettimeofday(&tv, NULL);
594#ifdef LINUX
595#if defined (POWERPC)
596	if (upeek(pid, 4*PT_R0, &scno) < 0)
597		return -1;
598	if (!(tcp->flags & TCB_INSYSCALL)) {
599		/* Check if we return from execve. */
600		if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
601			tcp->flags &= ~TCB_WAITEXECVE;
602			return 0;
603		}
604	}
605#elif defined (I386)
606	if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
607		return -1;
608#elif defined (ARM)
609	{
610	    long pc;
611	    upeek(pid, 4*15, &pc);
612	    umoven(tcp, pc-4, 4, (char *)&scno);
613	    scno &= 0x000fffff;
614	}
615#elif defined (M68K)
616	if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
617		return -1;
618#elif defined (ALPHA)
619	if (upeek(pid, REG_A3, &a3) < 0)
620		return -1;
621
622	if (!(tcp->flags & TCB_INSYSCALL)) {
623		if (upeek(pid, REG_R0, &scno) < 0)
624			return -1;
625
626		/* Check if we return from execve. */
627		if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
628			tcp->flags &= ~TCB_WAITEXECVE;
629			return 0;
630		}
631
632		/*
633		 * Do some sanity checks to figure out if it's
634		 * really a syscall entry
635		 */
636		if (scno < 0 || scno > nsyscalls) {
637			if (a3 == 0 || a3 == -1) {
638				if (debug)
639					fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
640				return 0;
641			}
642		}
643	}
644	else {
645		if (upeek(pid, REG_R0, &r0) < 0)
646			return -1;
647	}
648#elif defined (SPARC)
649	/* Everything we need is in the current register set. */
650	if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
651		return -1;
652
653	memmove (&regs.u_regs [1], &regs.u_regs [0],
654		 sizeof (regs.u_regs) - sizeof (regs.u_regs [0]));
655
656        /* If we are entering, then disassemble the syscall trap. */
657	if (!(tcp->flags & TCB_INSYSCALL)) {
658		/* Retrieve the syscall trap instruction. */
659		errno = 0;
660		trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.pc,0);
661		if (errno)
662			return -1;
663
664		/* Disassemble the trap to see what personality to use. */
665		switch (trap) {
666		case 0x91d02010:
667			/* Linux/SPARC syscall trap. */
668			set_personality(0);
669			break;
670		case 0x91d0206d:
671			/* Linux/SPARC64 syscall trap. */
672			fprintf(stderr,"syscall: Linux/SPARC64 not supported yet\n");
673			return -1;
674		case 0x91d02000:
675			/* SunOS syscall trap. (pers 1) */
676			fprintf(stderr,"syscall: SunOS no support\n");
677			return -1;
678		case 0x91d02008:
679			/* Solaris 2.x syscall trap. (per 2) */
680			set_personality(1);
681			break;
682		case 0x91d02009:
683			/* NetBSD/FreeBSD syscall trap. */
684			fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
685			return -1;
686		case 0x91d02027:
687			/* Solaris 2.x gettimeofday */
688			set_personality(1);
689			break;
690		default:
691			/* Unknown syscall trap. */
692			if(tcp->flags & TCB_WAITEXECVE) {
693				tcp->flags &= ~TCB_WAITEXECVE;
694				return 0;
695			}
696			fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.pc);
697			return -1;
698		}
699
700		/* Extract the system call number from the registers. */
701		if (trap == 0x91d02027)
702			scno = 156;
703		else
704			scno = regs.u_regs[UREG_G1];
705		if (scno == 0) {
706			scno = regs.u_regs[UREG_I0];
707			memmove (&regs.u_regs[UREG_I0], &regs.u_regs[UREG_I1], 7*sizeof(regs.u_regs[0]));
708		}
709	}
710#endif
711#endif /* LINUX */
712#ifdef SUNOS4
713	if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
714		return -1;
715#endif
716#ifdef SVR4
717#ifdef HAVE_PR_SYSCALL
718	scno = tcp->status.pr_syscall;
719#else /* !HAVE_PR_SYSCALL */
720	scno = tcp->status.pr_what;
721#endif /* !HAVE_PR_SYSCALL */
722	if (!(tcp->flags & TCB_INSYSCALL)) {
723		if (tcp->status.pr_why != PR_SYSENTRY) {
724			if (
725			    scno == SYS_fork
726#ifdef SYS_vfork
727			    || scno == SYS_vfork
728#endif /* SYS_vfork */
729			    ) {
730				/* We are returning in the child, fake it. */
731				tcp->status.pr_why = PR_SYSENTRY;
732				trace_syscall(tcp);
733				tcp->status.pr_why = PR_SYSEXIT;
734			}
735			else {
736				fprintf(stderr, "syscall: missing entry\n");
737				tcp->flags |= TCB_INSYSCALL;
738			}
739		}
740	}
741	else {
742		if (tcp->status.pr_why != PR_SYSEXIT) {
743			fprintf(stderr, "syscall: missing exit\n");
744			tcp->flags &= ~TCB_INSYSCALL;
745		}
746	}
747#endif /* SVR4 */
748#ifdef SUNOS4
749	if (!(tcp->flags & TCB_INSYSCALL)) {
750		if (scno == 0) {
751			fprintf(stderr, "syscall: missing entry\n");
752			tcp->flags |= TCB_INSYSCALL;
753		}
754	}
755	else {
756		if (scno != 0) {
757			if (debug) {
758				/*
759				 * This happens when a signal handler
760				 * for a signal which interrupted a
761				 * a system call makes another system call.
762				 */
763				fprintf(stderr, "syscall: missing exit\n");
764			}
765			tcp->flags &= ~TCB_INSYSCALL;
766		}
767	}
768#endif /* SUNOS4 */
769#ifdef LINUX
770#if defined (I386)
771	if (upeek(pid, 4*EAX, &eax) < 0)
772		return -1;
773	if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
774		if (debug)
775			fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
776		return 0;
777	}
778#elif defined (POWERPC)
779# define SO_MASK 0x10000000
780	if (upeek(pid, 4*PT_CCR, &flags) < 0)
781		return -1;
782	if (upeek(pid, 4*PT_R3, &result) < 0)
783		return -1;
784	if (flags & SO_MASK)
785		result = -result;
786#elif defined (M68K)
787	if (upeek(pid, 4*PT_D0, &d0) < 0)
788		return -1;
789	if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
790		if (debug)
791			fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
792		return 0;
793	}
794#elif defined (ARM)
795	if (upeek(pid, 4*0, (long *)&r0) < 0)
796		return -1;
797	if ( 0 && r0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
798		if (debug)
799			fprintf(stderr, "stray syscall exit: d0 = %ld\n", r0);
800		return 0;
801	}
802#else
803#endif
804#endif /* LINUX */
805
806	if (tcp->flags & TCB_INSYSCALL) {
807		long u_error;
808
809#ifdef LINUX
810#ifdef I386
811		if (eax < 0 && -eax < nerrnos) {
812			tcp->u_rval = -1;
813			u_error = -eax;
814		}
815		else {
816			tcp->u_rval = eax;
817			u_error = 0;
818		}
819#else /* !I386 */
820#ifdef POWERPC
821		if (result && (unsigned) -result < nerrnos) {
822			tcp->u_rval = -1;
823			u_error = -result;
824		}
825		else {
826			tcp->u_rval = result;
827			u_error = 0;
828		}
829#else /* !POWERPC */
830#ifdef M68K
831		if (d0 && (unsigned) -d0 < nerrnos) {
832			tcp->u_rval = -1;
833			u_error = -d0;
834		}
835		else {
836			tcp->u_rval = d0;
837			u_error = 0;
838		}
839#else /* !M68K */
840#ifdef ARM
841		if (r0 && (unsigned) -r0 < nerrnos) {
842			tcp->u_rval = -1;
843			u_error = -r0;
844		}
845		else {
846			tcp->u_rval = r0;
847			u_error = 0;
848		}
849#else /* !ARM */
850#ifdef ALPHA
851		if (a3) {
852			tcp->u_rval = -1;
853			u_error = r0;
854		}
855		else {
856			tcp->u_rval = r0;
857			u_error = 0;
858		}
859#else /* !ALPHA */
860#ifdef SPARC
861		if (regs.psr & PSR_C) {
862			tcp->u_rval = -1;
863			u_error = regs.u_regs[UREG_I0];
864		}
865		else {
866			tcp->u_rval = regs.u_regs[UREG_I0];
867			u_error = 0;
868		}
869#endif /* SPARC */
870#endif /* ALPHA */
871#endif /* ARM */
872#endif /* M68K */
873#endif /* POWERPC */
874#endif /* I386 */
875#endif /* LINUX */
876#ifdef SUNOS4
877		/* get error code from user struct */
878		if (upeek(pid, uoff(u_error), &u_error) < 0)
879			return -1;
880		u_error >>= 24; /* u_error is a char */
881
882		/* get system call return value */
883		if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
884			return -1;
885#endif /* SUNOS4 */
886#ifdef SVR4
887#ifdef SPARC
888		/* Judicious guessing goes a long way. */
889		if (tcp->status.pr_reg[R_PSR] & 0x100000) {
890			tcp->u_rval = -1;
891			u_error = tcp->status.pr_reg[R_O0];
892		}
893		else {
894			tcp->u_rval = tcp->status.pr_reg[R_O0];
895			u_error = 0;
896		}
897#endif /* SPARC */
898#ifdef I386
899		/* Wanna know how to kill an hour single-stepping? */
900		if (tcp->status.pr_reg[EFL] & 0x1) {
901			tcp->u_rval = -1;
902			u_error = tcp->status.pr_reg[EAX];
903		}
904		else {
905			tcp->u_rval = tcp->status.pr_reg[EAX];
906			u_error = 0;
907		}
908#endif /* I386 */
909#ifdef MIPS
910		if (tcp->status.pr_reg[CTX_A3]) {
911			tcp->u_rval = -1;
912			u_error = tcp->status.pr_reg[CTX_V0];
913		}
914		else {
915			tcp->u_rval = tcp->status.pr_reg[CTX_V0];
916			u_error = 0;
917		}
918#endif /* MIPS */
919#endif /* SVR4 */
920		tcp->u_error = u_error;
921
922		internal_syscall(tcp);
923		if (!(qual_flags[tcp->scno] & QUAL_TRACE)) {
924			tcp->flags &= ~TCB_INSYSCALL;
925			return 0;
926		}
927
928		if (tcp->flags & TCB_REPRINT) {
929			printleader(tcp);
930			tprintf("<... ");
931			if (tcp->scno >= nsyscalls)
932				tprintf("syscall_%lu", tcp->scno);
933			else
934				tprintf("%s", sysent[tcp->scno].sys_name);
935			tprintf(" resumed> ");
936		}
937
938		if (cflag) {
939			call_count[tcp->scno]++;
940			if (u_error)
941				error_count[tcp->scno]++;
942			tv_sub(&tv, &tv, &tcp->etime);
943#ifdef LINUX
944			if (tv_cmp(&tv, &tcp->dtime) > 0) {
945				static struct timeval one_tick =
946					{ 0, 1000000 / HZ };
947
948				if (tv_nz(&tcp->dtime))
949					tv = tcp->dtime;
950				else if (tv_cmp(&tv, &one_tick) > 0) {
951					if (tv_cmp(&shortest, &one_tick) < 0)
952						tv = shortest;
953					else
954						tv = one_tick;
955				}
956			}
957#endif /* LINUX */
958			if (tv_cmp(&tv, &shortest) < 0)
959				shortest = tv;
960			tv_add(&tv_count[tcp->scno],
961				&tv_count[tcp->scno], &tv);
962			tcp->flags &= ~TCB_INSYSCALL;
963			return 0;
964		}
965
966		if (tcp->scno >= nsyscalls
967		    || (qual_flags[tcp->scno] & QUAL_RAW))
968			sys_res = printargs(tcp);
969		else
970			sys_res = (*sysent[tcp->scno].sys_func)(tcp);
971		u_error = tcp->u_error;
972		tprintf(") ");
973		tabto(acolumn);
974		if (qual_flags[tcp->scno] & QUAL_RAW) {
975			if (u_error)
976				tprintf("= -1 (errno %ld)", u_error);
977			else
978				tprintf("= %#lx", tcp->u_rval);
979		}
980		else if (!(sys_res & RVAL_NONE) && u_error) {
981#ifdef LINUX
982			switch (u_error) {
983			case ERESTARTSYS:
984				tprintf("= ? ERESTARTSYS (To be restarted)");
985				break;
986			case ERESTARTNOINTR:
987				tprintf("= ? ERESTARTNOINTR (To be restarted)");
988				break;
989			case ERESTARTNOHAND:
990				tprintf("= ? ERESTARTNOHAND (To be restarted)");
991				break;
992			default:
993#endif /* LINUX */
994				tprintf("= -1 ");
995				if (u_error < nerrnos && u_error < sys_nerr)
996					tprintf("%s (%s)", errnoent[u_error],
997						sys_errlist[u_error]);
998				else if (u_error < nerrnos)
999					tprintf("%s (errno %ld)",
1000						errnoent[u_error], u_error);
1001				else if (u_error < sys_nerr)
1002					tprintf("ERRNO_%ld (%s)", u_error,
1003						sys_errlist[u_error]);
1004				else
1005					tprintf("E??? (errno %ld)", u_error);
1006#ifdef LINUX
1007				break;
1008			}
1009#endif /* LINUX */
1010		}
1011		else {
1012			if (sys_res & RVAL_NONE)
1013				tprintf("= ?");
1014			else {
1015				switch (sys_res & RVAL_MASK) {
1016				case RVAL_HEX:
1017					tprintf("= %#lx", tcp->u_rval);
1018					break;
1019				case RVAL_OCTAL:
1020					tprintf("= %#lo", tcp->u_rval);
1021					break;
1022				case RVAL_UDECIMAL:
1023					tprintf("= %lu", tcp->u_rval);
1024					break;
1025				case RVAL_DECIMAL:
1026					tprintf("= %ld", tcp->u_rval);
1027					break;
1028				default:
1029					fprintf(stderr,
1030						"invalid rval format\n");
1031					break;
1032				}
1033			}
1034			if ((sys_res & RVAL_STR) && tcp->auxstr)
1035				tprintf(" (%s)", tcp->auxstr);
1036		}
1037		if (dtime) {
1038			tv_sub(&tv, &tv, &tcp->etime);
1039			tprintf(" <%ld.%06ld>",
1040				(long) tv.tv_sec, (long) tv.tv_usec);
1041		}
1042		printtrailer(tcp);
1043
1044		dumpio(tcp);
1045		if (fflush(tcp->outf) == EOF)
1046			return -1;
1047		tcp->flags &= ~TCB_INSYSCALL;
1048		return 0;
1049	}
1050
1051	/* Entering system call */
1052	tcp->scno = scno;
1053#ifdef LINUX
1054#if defined (ALPHA)
1055	{
1056		int i;
1057		tcp->u_nargs = sysent[tcp->scno].nargs;
1058		for (i = 0; i < tcp->u_nargs; i++) {
1059			/* WTA: if scno is out-of-bounds this will bomb. Add range-check
1060			 * for scno somewhere above here!
1061			 */
1062			if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1063				return -1;
1064		}
1065	}
1066#elif defined (POWERPC)
1067	{
1068		int i;
1069		tcp->u_nargs = sysent[tcp->scno].nargs;
1070		for (i = 0; i < tcp->u_nargs; i++) {
1071			if (upeek(pid, (i==0) ? (4*PT_ORIG_R3) : ((i+PT_R3)*4), &tcp->u_arg[i]) < 0)
1072				return -1;
1073		}
1074	}
1075#elif defined (SPARC)
1076	{
1077		int i, offset;
1078
1079	        offset = UREG_I0;
1080		tcp->u_nargs = sysent[tcp->scno].nargs;
1081		for (i = 0; i < tcp->u_nargs; i++)
1082			tcp->u_arg[i] = regs.u_regs[offset + i];
1083	}
1084#else
1085	{
1086		int i;
1087		tcp->u_nargs = sysent[tcp->scno].nargs;
1088		for (i = 0; i < tcp->u_nargs; i++) {
1089			if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
1090				return -1;
1091		}
1092	}
1093#endif
1094#endif /* LINUX */
1095#ifdef SUNOS4
1096	{
1097		int i;
1098		tcp->u_nargs = sysent[tcp->scno].nargs;
1099		for (i = 0; i < tcp->u_nargs; i++) {
1100			struct user *u;
1101
1102			if (upeek(pid, uoff(u_arg[0]) +
1103			    (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1104				return -1;
1105		}
1106	}
1107#endif /* SUNOS4 */
1108#ifdef SVR4
1109#ifdef MIPS
1110	/*
1111	 * SGI is broken: even though it has pr_sysarg, it doesn't
1112	 * set them on system call entry.  Get a clue.
1113	 */
1114	if (sysent[tcp->scno].nargs != -1)
1115		tcp->u_nargs = sysent[tcp->scno].nargs;
1116	else
1117		tcp->u_nargs = tcp->status.pr_nsysarg;
1118	if (tcp->u_nargs > 4) {
1119		memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
1120			4*sizeof(tcp->u_arg[0]));
1121		umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
1122			(tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
1123	}
1124	else {
1125		memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
1126			tcp->u_nargs*sizeof(tcp->u_arg[0]));
1127	}
1128#else /* !MIPS */
1129#ifdef HAVE_PR_SYSCALL
1130	if (sysent[tcp->scno].nargs != -1)
1131		tcp->u_nargs = sysent[tcp->scno].nargs;
1132	else
1133		tcp->u_nargs = tcp->status.pr_nsysarg;
1134	{
1135		int i;
1136		for (i = 0; i < tcp->u_nargs; i++)
1137			tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1138	}
1139#else /* !HAVE_PR_SYSCALL */
1140#ifdef I386
1141	if (sysent[tcp->scno].nargs != -1)
1142		tcp->u_nargs = sysent[tcp->scno].nargs;
1143	else
1144		tcp->u_nargs = 5;
1145	umoven(tcp, tcp->status.pr_reg[UESP] + 4,
1146		tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1147#endif /* I386 */
1148#endif /* !HAVE_PR_SYSCALL */
1149#endif /* !MIPS */
1150#endif /* SVR4 */
1151#ifdef __arm__
1152	switch (tcp->scno + __NR_SYSCALL_BASE) {
1153#else
1154	switch (tcp->scno) {
1155#endif
1156#ifdef LINUX
1157#if !defined (ALPHA) && !defined(SPARC)
1158	case SYS_socketcall:
1159		decode_subcall(tcp, SYS_socket_subcall,
1160			SYS_socket_nsubcalls, deref_style);
1161		break;
1162	case SYS_ipc:
1163		decode_subcall(tcp, SYS_ipc_subcall,
1164			SYS_ipc_nsubcalls, shift_style);
1165		break;
1166#endif /* !ALPHA && !SPARC */
1167#ifdef SPARC
1168	case SYS_socketcall:
1169		sparc_socket_decode (tcp);
1170		break;
1171#endif
1172#endif /* LINUX */
1173#ifdef SVR4
1174#ifdef SYS_pgrpsys_subcall
1175	case SYS_pgrpsys:
1176		decode_subcall(tcp, SYS_pgrpsys_subcall,
1177			SYS_pgrpsys_nsubcalls, shift_style);
1178		break;
1179#endif /* SYS_pgrpsys_subcall */
1180#ifdef SYS_sigcall_subcall
1181	case SYS_sigcall:
1182		decode_subcall(tcp, SYS_sigcall_subcall,
1183			SYS_sigcall_nsubcalls, mask_style);
1184		break;
1185#endif /* SYS_sigcall_subcall */
1186	case SYS_msgsys:
1187		decode_subcall(tcp, SYS_msgsys_subcall,
1188			SYS_msgsys_nsubcalls, shift_style);
1189		break;
1190	case SYS_shmsys:
1191		decode_subcall(tcp, SYS_shmsys_subcall,
1192			SYS_shmsys_nsubcalls, shift_style);
1193		break;
1194	case SYS_semsys:
1195		decode_subcall(tcp, SYS_semsys_subcall,
1196			SYS_semsys_nsubcalls, shift_style);
1197		break;
1198#if 0 /* broken */
1199	case SYS_utssys:
1200		decode_subcall(tcp, SYS_utssys_subcall,
1201			SYS_utssys_nsubcalls, shift_style);
1202		break;
1203#endif
1204	case SYS_sysfs:
1205		decode_subcall(tcp, SYS_sysfs_subcall,
1206			SYS_sysfs_nsubcalls, shift_style);
1207		break;
1208	case SYS_spcall:
1209		decode_subcall(tcp, SYS_spcall_subcall,
1210			SYS_spcall_nsubcalls, shift_style);
1211		break;
1212#ifdef SYS_context_subcall
1213	case SYS_context:
1214		decode_subcall(tcp, SYS_context_subcall,
1215			SYS_context_nsubcalls, shift_style);
1216		break;
1217#endif /* SYS_context_subcall */
1218#ifdef SYS_door_subcall
1219	case SYS_door:
1220		decode_subcall(tcp, SYS_door_subcall,
1221			SYS_door_nsubcalls, door_style);
1222		break;
1223#endif /* SYS_door_subcall */
1224#endif /* SVR4 */
1225#ifdef SUNOS4
1226	case SYS_semsys:
1227		decode_subcall(tcp, SYS_semsys_subcall,
1228			SYS_semsys_nsubcalls, shift_style);
1229		break;
1230	case SYS_msgsys:
1231		decode_subcall(tcp, SYS_msgsys_subcall,
1232			SYS_msgsys_nsubcalls, shift_style);
1233		break;
1234	case SYS_shmsys:
1235		decode_subcall(tcp, SYS_shmsys_subcall,
1236			SYS_shmsys_nsubcalls, shift_style);
1237		break;
1238#endif
1239	}
1240
1241	internal_syscall(tcp);
1242	if (!(qual_flags[tcp->scno] & QUAL_TRACE)) {
1243		tcp->flags |= TCB_INSYSCALL;
1244		return 0;
1245	}
1246
1247	if (cflag) {
1248		gettimeofday(&tcp->etime, NULL);
1249		tcp->flags |= TCB_INSYSCALL;
1250		return 0;
1251	}
1252
1253	printleader(tcp);
1254	tcp->flags &= ~TCB_REPRINT;
1255	tcp_last = tcp;
1256	if (tcp->scno >= nsyscalls)
1257		tprintf("syscall_%lu(", tcp->scno);
1258	else
1259		tprintf("%s(", sysent[tcp->scno].sys_name);
1260	if (tcp->scno >= nsyscalls ||
1261	    ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
1262		sys_res = printargs(tcp);
1263	else
1264		sys_res = (*sysent[tcp->scno].sys_func)(tcp);
1265	if (fflush(tcp->outf) == EOF)
1266		return -1;
1267	tcp->flags |= TCB_INSYSCALL;
1268	/* Measure the entrance time as late as possible to avoid errors. */
1269	if (dtime)
1270		gettimeofday(&tcp->etime, NULL);
1271	return sys_res;
1272}
1273
1274int
1275printargs(tcp)
1276struct tcb *tcp;
1277{
1278	if (entering(tcp)) {
1279		int i;
1280
1281		for (i = 0; i < tcp->u_nargs; i++)
1282			tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
1283	}
1284	return 0;
1285}
1286
1287long
1288getrval2(tcp)
1289struct tcb *tcp;
1290{
1291	long val = -1;
1292
1293#ifdef LINUX
1294#ifdef SPARC
1295	struct pt_regs regs;
1296	if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
1297		return -1;
1298	val = regs.u_regs[UREG_I1];
1299#endif /* SPARC */
1300#endif /* LINUX */
1301
1302#ifdef SUNOS4
1303	if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
1304		return -1;
1305#endif /* SUNOS4 */
1306
1307#ifdef SVR4
1308#ifdef SPARC
1309	val = tcp->status.pr_reg[R_O1];
1310#endif /* SPARC */
1311#ifdef I386
1312	val = tcp->status.pr_reg[EDX];
1313#endif /* I386 */
1314#ifdef MIPS
1315	val = tcp->status.pr_reg[CTX_V1];
1316#endif /* MIPS */
1317#endif /* SVR4 */
1318
1319	return val;
1320}
1321
1322/*
1323 * Apparently, indirect system calls have already be converted by ptrace(2),
1324 * so if you see "indir" this program has gone astray.
1325 */
1326int
1327sys_indir(tcp)
1328struct tcb *tcp;
1329{
1330	int i, scno, nargs;
1331
1332	if (entering(tcp)) {
1333		if ((scno = tcp->u_arg[0]) > nsyscalls) {
1334			fprintf(stderr, "Bogus syscall: %u\n", scno);
1335			return 0;
1336		}
1337		nargs = sysent[scno].nargs;
1338		tprintf("%s", sysent[scno].sys_name);
1339		for (i = 0; i < nargs; i++)
1340			tprintf(", %#lx", tcp->u_arg[i+1]);
1341	}
1342	return 0;
1343}
1344
1345static int
1346time_cmp(a, b)
1347void *a;
1348void *b;
1349{
1350	return -tv_cmp(&tv_count[*((int *) a)], &tv_count[*((int *) b)]);
1351}
1352
1353static int
1354syscall_cmp(a, b)
1355void *a;
1356void *b;
1357{
1358	return strcmp(sysent[*((int *) a)].sys_name,
1359		sysent[*((int *) b)].sys_name);
1360}
1361
1362static int
1363count_cmp(a, b)
1364void *a;
1365void *b;
1366{
1367	int m = call_count[*((int *) a)], n = call_count[*((int *) b)];
1368
1369	return (m < n) ? 1 : (m > n) ? -1 : 0;
1370}
1371
1372static int (*sortfun)();
1373static struct timeval overhead = { -1, -1 };
1374
1375void
1376set_sortby(sortby)
1377char *sortby;
1378{
1379	if (strcmp(sortby, "time") == 0)
1380		sortfun = time_cmp;
1381	else if (strcmp(sortby, "calls") == 0)
1382		sortfun = count_cmp;
1383	else if (strcmp(sortby, "name") == 0)
1384		sortfun = syscall_cmp;
1385	else if (strcmp(sortby, "nothing") == 0)
1386		sortfun = NULL;
1387	else {
1388		fprintf(stderr, "invalid sortby: `%s'\n", sortby);
1389		exit(1);
1390	}
1391}
1392
1393void set_overhead(n)
1394int n;
1395{
1396	overhead.tv_sec = n / 1000000;
1397	overhead.tv_usec = n % 1000000;
1398}
1399
1400void
1401call_summary(outf)
1402FILE *outf;
1403{
1404	int i, j;
1405	int call_cum, error_cum;
1406	struct timeval tv_cum, dtv;
1407	double percent;
1408	char *dashes = "-------------------------";
1409	char error_str[16];
1410
1411	call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
1412	if (overhead.tv_sec == -1) {
1413		tv_mul(&overhead, &shortest, 8);
1414		tv_div(&overhead, &overhead, 10);
1415	}
1416	for (i = 0; i < nsyscalls; i++) {
1417		sorted_count[i] = i;
1418		if (call_count[i] == 0)
1419			continue;
1420		tv_mul(&dtv, &overhead, call_count[i]);
1421		tv_sub(&tv_count[i], &tv_count[i], &dtv);
1422		call_cum += call_count[i];
1423		error_cum += error_count[i];
1424		tv_add(&tv_cum, &tv_cum, &tv_count[i]);
1425	}
1426	if (sortfun)
1427		qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
1428	fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
1429		"% time", "seconds", "usecs/call",
1430		"calls", "errors", "syscall");
1431	fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
1432		dashes, dashes, dashes, dashes, dashes, dashes);
1433	for (i = 0; i < nsyscalls; i++) {
1434		j = sorted_count[i];
1435		if (call_count[j] == 0)
1436			continue;
1437		tv_div(&dtv, &tv_count[j], call_count[j]);
1438		if (error_count[j])
1439			sprintf(error_str, "%d", error_count[j]);
1440		else
1441			error_str[0] = '\0';
1442		percent = 100.0*tv_float(&tv_count[j])/tv_float(&tv_cum);
1443		fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
1444			percent, (long) tv_count[j].tv_sec,
1445			(long) tv_count[j].tv_usec,
1446			(long) 1000000 * dtv.tv_sec + dtv.tv_usec,
1447			call_count[j], error_str, sysent[j].sys_name);
1448	}
1449	fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
1450		dashes, dashes, dashes, dashes, dashes, dashes);
1451	if (error_cum)
1452		sprintf(error_str, "%d", error_cum);
1453	else
1454		error_str[0] = '\0';
1455	fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
1456		"100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
1457		call_cum, error_str, "total");
1458}
1459