blob: ea57544e5e4e3946bdd609243081b02550f8e7c9 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
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>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000040
Wichert Akkermanb046b381999-07-13 22:20:16 +000041#ifdef HAVE_SYS_REG_H
42#include <sys/reg.h>
43# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkerman2b483ba1999-06-24 13:55:29 +000044#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000045
Wichert Akkermanb046b381999-07-13 22:20:16 +000046#if defined(linux) && !defined(__GLIBC__)
47#include <linux/ptrace.h>
48#endif
49
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000050#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
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000140set_personality(personality)
141int personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142{
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++) {
Nate Sammonsce780fc1999-03-29 23:23:13 +0000258 if (strcmp(s, signame(i) + 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000259 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
Wichert Akkerman8829a551999-06-11 13:18:40 +0000400enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000401
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
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000425sparc_socket_decode (tcp)
426struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000427{
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;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000487 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;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000497 }
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;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +0000670 case 0x91d0206d:
671 /* Linux/SPARC64 syscall trap. */
672 fprintf(stderr,"syscall: Linux/SPARC64 not supported yet\n");
673 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000674 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++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001059 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1060 * for scno somewhere above here!
1061 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001062 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 */
Wichert Akkerman8829a551999-06-11 13:18:40 +00001218#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 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224#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}