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