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