]> granicus.if.org Git - strace/blob - syscall.c
2002-09-23 Michal Ludvig <mludvig@suse.cz>
[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  * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6  * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7  *                     Linux for s390 port by D.J. Barrow
8  *                    <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  *      $Id$
34  */
35
36 #include "defs.h"
37
38 #include <signal.h>
39 #include <time.h>
40 #include <errno.h>
41 #include <sys/user.h>
42 #include <sys/syscall.h>
43 #include <sys/param.h>
44
45 #if HAVE_ASM_REG_H
46 #ifdef SPARC
47 #  define fpq kernel_fpq
48 #  define fq kernel_fq
49 #  define fpu kernel_fpu
50 #endif
51 #include <asm/reg.h>
52 #ifdef SPARC
53 #  undef fpq
54 #  undef fq
55 #  undef fpu 
56 #endif
57 #endif
58
59 #ifdef HAVE_SYS_REG_H
60 #include <sys/reg.h>
61 #ifndef PTRACE_PEEKUSR
62 # define PTRACE_PEEKUSR PTRACE_PEEKUSER
63 #endif
64 #elif defined(HAVE_LINUX_PTRACE_H)
65 #undef PTRACE_SYSCALL
66 #include <linux/ptrace.h>
67 #endif
68
69 #if defined(LINUX) && defined(IA64)
70 # include <asm/ptrace_offsets.h>
71 # include <asm/rse.h>
72 #endif
73
74 #ifndef SYS_ERRLIST_DECLARED
75 extern int sys_nerr;
76 extern char *sys_errlist[];
77 #endif /* SYS_ERRLIST_DECLARED */
78
79 #define NR_SYSCALL_BASE 0
80 #ifdef LINUX
81 #ifndef ERESTARTSYS
82 #define ERESTARTSYS     512
83 #endif
84 #ifndef ERESTARTNOINTR
85 #define ERESTARTNOINTR  513
86 #endif
87 #ifndef ERESTARTNOHAND
88 #define ERESTARTNOHAND  514     /* restart if no handler.. */
89 #endif
90 #ifndef ENOIOCTLCMD
91 #define ENOIOCTLCMD     515     /* No ioctl command */
92 #endif
93 #ifndef NSIG
94 #define NSIG 32
95 #endif
96 #ifdef ARM
97 #undef NSIG
98 #define NSIG 32
99 #undef NR_SYSCALL_BASE
100 #define NR_SYSCALL_BASE __NR_SYSCALL_BASE
101 #endif
102 #endif /* LINUX */
103
104 #include "syscall.h"
105
106 /* Define these shorthand notations to simplify the syscallent files. */
107 #define TF TRACE_FILE
108 #define TI TRACE_IPC
109 #define TN TRACE_NETWORK
110 #define TP TRACE_PROCESS
111 #define TS TRACE_SIGNAL
112
113 struct sysent sysent0[] = {
114 #include "syscallent.h"
115 };
116 int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
117
118 #if SUPPORTED_PERSONALITIES >= 2
119 struct sysent sysent1[] = {
120 #include "syscallent1.h"
121 };
122 int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
123 #endif /* SUPPORTED_PERSONALITIES >= 2 */
124
125 #if SUPPORTED_PERSONALITIES >= 3
126 struct sysent sysent2[] = {
127 #include "syscallent2.h"
128 };
129 int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
130 #endif /* SUPPORTED_PERSONALITIES >= 3 */
131
132 struct sysent *sysent;
133 int nsyscalls;
134
135 /* Now undef them since short defines cause wicked namespace pollution. */
136 #undef TF
137 #undef TI
138 #undef TN
139 #undef TP
140 #undef TS
141
142 char *errnoent0[] = {
143 #include "errnoent.h"
144 };
145 int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
146
147 #if SUPPORTED_PERSONALITIES >= 2
148 char *errnoent1[] = {
149 #include "errnoent1.h"
150 };
151 int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
152 #endif /* SUPPORTED_PERSONALITIES >= 2 */
153
154 #if SUPPORTED_PERSONALITIES >= 3
155 char *errnoent2[] = {
156 #include "errnoent2.h"
157 };
158 int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
159 #endif /* SUPPORTED_PERSONALITIES >= 3 */
160
161 char **errnoent;
162 int nerrnos;
163
164 int current_personality;
165
166 int
167 set_personality(personality)
168 int personality;
169 {
170         switch (personality) {
171         case 0:
172                 errnoent = errnoent0;
173                 nerrnos = nerrnos0;
174                 sysent = sysent0;
175                 nsyscalls = nsyscalls0;
176                 ioctlent = ioctlent0;
177                 nioctlents = nioctlents0;
178                 signalent = signalent0;
179                 nsignals = nsignals0;
180                 break;
181
182 #if SUPPORTED_PERSONALITIES >= 2
183         case 1:
184                 errnoent = errnoent1;
185                 nerrnos = nerrnos1;
186                 sysent = sysent1;
187                 nsyscalls = nsyscalls1;
188                 ioctlent = ioctlent1;
189                 nioctlents = nioctlents1;
190                 signalent = signalent1;
191                 nsignals = nsignals1;
192                 break;
193 #endif /* SUPPORTED_PERSONALITIES >= 2 */
194
195 #if SUPPORTED_PERSONALITIES >= 3
196         case 2:
197                 errnoent = errnoent2;
198                 nerrnos = nerrnos2;
199                 sysent = sysent2;
200                 nsyscalls = nsyscalls2;
201                 ioctlent = ioctlent2;
202                 nioctlents = nioctlents2;
203                 signalent = signalent2;
204                 nsignals = nsignals2;
205                 break;
206 #endif /* SUPPORTED_PERSONALITIES >= 3 */
207
208         default:
209                 return -1;
210         }
211
212         current_personality = personality;
213         return 0;
214 }
215
216 int qual_flags[MAX_QUALS];
217
218 static int call_count[MAX_QUALS];
219 static int error_count[MAX_QUALS];
220 static struct timeval tv_count[MAX_QUALS];
221 static int sorted_count[MAX_QUALS];
222
223 static struct timeval shortest = { 1000000, 0 };
224
225 static int lookup_syscall(), lookup_signal(), lookup_fault(), lookup_desc();
226
227 static struct qual_options {
228         int bitflag;
229         char *option_name;
230         int (*lookup)();
231         char *argument_name;
232 } qual_options[] = {
233         { QUAL_TRACE,   "trace",        lookup_syscall, "system call"   },
234         { QUAL_TRACE,   "t",            lookup_syscall, "system call"   },
235         { QUAL_ABBREV,  "abbrev",       lookup_syscall, "system call"   },
236         { QUAL_ABBREV,  "a",            lookup_syscall, "system call"   },
237         { QUAL_VERBOSE, "verbose",      lookup_syscall, "system call"   },
238         { QUAL_VERBOSE, "v",            lookup_syscall, "system call"   },
239         { QUAL_RAW,     "raw",          lookup_syscall, "system call"   },
240         { QUAL_RAW,     "x",            lookup_syscall, "system call"   },
241         { QUAL_SIGNAL,  "signal",       lookup_signal,  "signal"        },
242         { QUAL_SIGNAL,  "signals",      lookup_signal,  "signal"        },
243         { QUAL_SIGNAL,  "s",            lookup_signal,  "signal"        },
244         { QUAL_FAULT,   "fault",        lookup_fault,   "fault"         },
245         { QUAL_FAULT,   "faults",       lookup_fault,   "fault"         },
246         { QUAL_FAULT,   "m",            lookup_fault,   "fault"         },
247         { QUAL_READ,    "read",         lookup_desc,    "descriptor"    },
248         { QUAL_READ,    "reads",        lookup_desc,    "descriptor"    },
249         { QUAL_READ,    "r",            lookup_desc,    "descriptor"    },
250         { QUAL_WRITE,   "write",        lookup_desc,    "descriptor"    },
251         { QUAL_WRITE,   "writes",       lookup_desc,    "descriptor"    },
252         { QUAL_WRITE,   "w",            lookup_desc,    "descriptor"    },
253         { 0,            NULL,           NULL,           NULL            },
254 };
255
256 static int
257 lookup_syscall(s)
258 char *s;
259 {
260         int i;
261
262         for (i = 0; i < nsyscalls; i++) {
263                 if (strcmp(s, sysent[i].sys_name) == 0)
264                         return i;
265         }
266         return -1;
267 }
268
269 static int
270 lookup_signal(s)
271 char *s;
272 {
273         int i;
274         char buf[32];
275
276         if (s && *s && isdigit((unsigned char)*s))
277                 return atoi(s);
278         strcpy(buf, s);
279         s = buf;
280         for (i = 0; s[i]; i++)
281                 s[i] = toupper((unsigned char)(s[i]));
282         if (strncmp(s, "SIG", 3) == 0)
283                 s += 3;
284         for (i = 0; i <= NSIG; i++) {
285                 if (strcmp(s, signame(i) + 3) == 0)
286                         return i;
287         }
288         return -1;
289 }
290
291 static int
292 lookup_fault(s)
293 char *s;
294 {
295         return -1;
296 }
297
298 static int
299 lookup_desc(s)
300 char *s;
301 {
302         if (s && *s && isdigit((unsigned char)*s))
303                 return atoi(s);
304         return -1;
305 }
306
307 static int
308 lookup_class(s)
309 char *s;
310 {
311         if (strcmp(s, "file") == 0)
312                 return TRACE_FILE;
313         if (strcmp(s, "ipc") == 0)
314                 return TRACE_IPC;
315         if (strcmp(s, "network") == 0)
316                 return TRACE_NETWORK;
317         if (strcmp(s, "process") == 0)
318                 return TRACE_PROCESS;
319         if (strcmp(s, "signal") == 0)
320                 return TRACE_SIGNAL;
321         return -1;
322 }
323
324 void
325 qualify(s)
326 char *s;
327 {
328         struct qual_options *opt;
329         int not;
330         char *p;
331         int i, n;
332
333         opt = &qual_options[0];
334         for (i = 0; (p = qual_options[i].option_name); i++) {
335                 n = strlen(p);
336                 if (strncmp(s, p, n) == 0 && s[n] == '=') {
337                         opt = &qual_options[i];
338                         s += n + 1;
339                         break;
340                 }
341         }
342         not = 0;
343         if (*s == '!') {
344                 not = 1;
345                 s++;
346         }
347         if (strcmp(s, "none") == 0) {
348                 not = 1 - not;
349                 s = "all";
350         }
351         if (strcmp(s, "all") == 0) {
352                 for (i = 0; i < MAX_QUALS; i++) {
353                         if (not)
354                                 qual_flags[i] &= ~opt->bitflag;
355                         else
356                                 qual_flags[i] |= opt->bitflag;
357                 }
358                 return;
359         }
360         for (i = 0; i < MAX_QUALS; i++) {
361                 if (not)
362                         qual_flags[i] |= opt->bitflag;
363                 else
364                         qual_flags[i] &= ~opt->bitflag;
365         }
366         for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
367                 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
368                         for (i = 0; i < MAX_QUALS; i++) {
369                                 if (sysent[i].sys_flags & n) {
370                                         if (not)
371                                                 qual_flags[i] &= ~opt->bitflag;
372                                         else
373                                                 qual_flags[i] |= opt->bitflag;
374                                 }
375                         }
376                         continue;
377                 }
378                 if ((n = (*opt->lookup)(p)) < 0) {
379                         fprintf(stderr, "strace: invalid %s `%s'\n",
380                                 opt->argument_name, p);
381                         exit(1);
382                 }
383                 if (not)
384                         qual_flags[n] &= ~opt->bitflag;
385                 else
386                         qual_flags[n] |= opt->bitflag;
387         }
388         return;
389 }
390
391 static void
392 dumpio(tcp)
393 struct tcb *tcp;
394 {
395         if (syserror(tcp))
396                 return;
397         if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
398                 return;
399         switch (tcp->scno + NR_SYSCALL_BASE) {
400         case SYS_read:
401 #ifdef SYS_recv
402         case SYS_recv:
403 #endif
404 #ifdef SYS_recvfrom
405         case SYS_recvfrom:
406 #endif
407                 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
408                         dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
409                 break;
410         case SYS_write:
411 #ifdef SYS_send
412         case SYS_send:
413 #endif
414 #ifdef SYS_sendto
415         case SYS_sendto:
416 #endif
417                 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
418                         dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
419                 break;
420 #ifdef SYS_readv
421         case SYS_readv:
422                 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
423                         dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
424                 break;
425 #endif
426 #ifdef SYS_writev
427         case SYS_writev:
428
429                 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
430                         dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
431                 break;
432 #endif
433         }
434 }
435
436 #ifndef FREEBSD
437 enum subcall_style { shift_style, deref_style, mask_style, door_style };
438 #else /* FREEBSD */
439 enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
440
441 struct subcall {
442   int call;
443   int nsubcalls;
444   int subcalls[5];
445 };
446
447 const struct subcall subcalls_table[] = {
448   { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
449 #ifdef SYS_semconfig
450   { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
451 #else
452   { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
453 #endif
454   { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
455 };
456 #endif /* FREEBSD */
457
458 #if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
459
460 const int socket_map [] = {
461                /* SYS_SOCKET      */ 97,
462                /* SYS_BIND        */ 104,
463                /* SYS_CONNECT     */ 98,
464                /* SYS_LISTEN      */ 106,
465                /* SYS_ACCEPT      */ 99,
466                /* SYS_GETSOCKNAME */ 150,
467                /* SYS_GETPEERNAME */ 141,
468                /* SYS_SOCKETPAIR  */ 135,
469                /* SYS_SEND        */ 101,
470                /* SYS_RECV        */ 102,
471                /* SYS_SENDTO      */ 133,
472                /* SYS_RECVFROM    */ 125,
473                /* SYS_SHUTDOWN    */ 134,
474                /* SYS_SETSOCKOPT  */ 105,
475                /* SYS_GETSOCKOPT  */ 118,
476                /* SYS_SENDMSG     */ 114,
477                /* SYS_RECVMSG     */ 113
478 };
479
480 void
481 sparc_socket_decode (tcp)
482 struct tcb *tcp;
483 {
484         volatile long addr;
485         volatile int i, n;
486
487         if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
488                 return;
489         }
490         tcp->scno = socket_map [tcp->u_arg [0]-1];
491         n = tcp->u_nargs = sysent [tcp->scno].nargs;
492         addr = tcp->u_arg [1];
493         for (i = 0; i < n; i++){
494                 int arg;
495                 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
496                         arg = 0;
497                 tcp->u_arg [i] = arg;
498                 addr += sizeof (arg);
499         }
500 }
501
502 static void
503 decode_subcall(tcp, subcall, nsubcalls, style)
504 struct tcb *tcp;
505 int subcall;
506 int nsubcalls;
507 enum subcall_style style;
508 {
509         int i, addr, mask, arg;
510
511         switch (style) {
512         case shift_style:
513                 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
514                         return;
515                 tcp->scno = subcall + tcp->u_arg[0];
516                 if (sysent[tcp->scno].nargs != -1)
517                         tcp->u_nargs = sysent[tcp->scno].nargs;
518                 else
519                         tcp->u_nargs--;
520                 for (i = 0; i < tcp->u_nargs; i++)
521                         tcp->u_arg[i] = tcp->u_arg[i + 1];
522                 break;
523         case deref_style:
524                 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
525                         return;
526                 tcp->scno = subcall + tcp->u_arg[0];
527                 addr = tcp->u_arg[1];
528                 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
529                         if (umove(tcp, addr, &arg) < 0)
530                                 arg = 0;
531                         tcp->u_arg[i] = arg;
532                         addr += sizeof(arg);
533                 }
534                 tcp->u_nargs = sysent[tcp->scno].nargs;
535                 break;
536         case mask_style:
537                 mask = (tcp->u_arg[0] >> 8) & 0xff;
538                 for (i = 0; mask; i++)
539                         mask >>= 1;
540                 if (i >= nsubcalls)
541                         return;
542                 tcp->u_arg[0] &= 0xff;
543                 tcp->scno = subcall + i;
544                 if (sysent[tcp->scno].nargs != -1)
545                         tcp->u_nargs = sysent[tcp->scno].nargs;
546                 break;
547         case door_style:
548                 /*
549                  * Oh, yuck.  The call code is the *sixth* argument.
550                  * (don't you mean the *last* argument? - JH)
551                  */
552                 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
553                         return;
554                 tcp->scno = subcall + tcp->u_arg[5];
555                 if (sysent[tcp->scno].nargs != -1)
556                         tcp->u_nargs = sysent[tcp->scno].nargs;
557                 else
558                         tcp->u_nargs--;
559                 break;
560 #ifdef FREEBSD
561         case table_style:
562                 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
563                         if (subcalls_table[i].call == tcp->scno) break;
564                 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
565                     tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
566                         tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
567                         for (i = 0; i < tcp->u_nargs; i++)
568                                 tcp->u_arg[i] = tcp->u_arg[i + 1];
569                 }
570                 break;
571 #endif /* FREEBSD */
572         }
573 }
574 #endif
575
576 struct tcb *tcp_last = NULL;
577
578 static int
579 internal_syscall(tcp)
580 struct tcb *tcp;
581 {
582         /*
583          * We must always trace a few critical system calls in order to
584          * correctly support following forks in the presence of tracing
585          * qualifiers.
586          */
587         switch (tcp->scno + NR_SYSCALL_BASE) {
588 #ifdef SYS_fork
589         case SYS_fork:
590 #endif
591 #ifdef SYS_vfork
592         case SYS_vfork:
593 #endif
594 #ifdef SYS_fork1
595         case SYS_fork1:
596 #endif
597 #ifdef SYS_forkall
598         case SYS_forkall:
599 #endif
600 #ifdef SYS_rfork1
601         case SYS_rfork1:
602 #endif
603 #ifdef SYS_rforkall
604         case SYS_rforkall:
605 #endif
606                 internal_fork(tcp);
607                 break;
608 #ifdef SYS_clone
609         case SYS_clone:
610                 internal_clone(tcp);
611                 break;
612 #endif
613 #ifdef SYS_clone2
614         case SYS_clone2:
615                 internal_clone(tcp);
616                 break;
617 #endif
618 #ifdef SYS_execv
619         case SYS_execv:
620 #endif
621 #ifdef SYS_execve
622         case SYS_execve:
623 #endif
624 #ifdef SYS_rexecve
625         case SYS_rexecve:
626 #endif
627                 internal_exec(tcp);
628                 break;
629
630 #ifdef SYS_wait
631         case SYS_wait:
632 #endif
633 #ifdef SYS_wait4
634         case SYS_wait4:
635 #endif
636 #ifdef SYS32_wait4
637         case SYS32_wait4:
638 #endif
639 #ifdef SYS_waitpid
640         case SYS_waitpid:
641 #endif
642 #ifdef SYS_waitsys
643         case SYS_waitsys:
644 #endif
645                 internal_wait(tcp);
646                 break;
647
648 #ifdef SYS_exit
649         case SYS_exit:
650 #endif
651 #ifdef SYS32_exit
652         case SYS32_exit:
653 #endif
654                 internal_exit(tcp);
655                 break;
656         }
657         return 0;
658 }
659
660
661 #ifdef LINUX
662 #if defined (I386)
663         static long eax;
664 #elif defined (IA64)
665         long r8, r10, psr;
666         long ia32 = 0;
667 #elif defined (POWERPC)
668         static long result,flags;
669 #elif defined (M68K)
670         static int d0;
671 #elif defined (ARM)
672         static int r0;
673 #elif defined (ALPHA)
674         static long r0;
675         static long a3;
676 #elif defined (SPARC)
677         static struct regs regs;
678         static unsigned long trap;
679 #elif defined(MIPS)
680         static long a3;
681         static long r2;
682 #elif defined(S390)
683         static long gpr2;
684         static long pc;
685 #elif defined(HPPA)
686         static long r28;
687 #elif defined(SH)
688        static long r0;
689
690 #endif 
691 #endif /* LINUX */
692 #ifdef FREEBSD
693         struct reg regs;
694 #endif /* FREEBSD */    
695
696 int
697 get_scno(tcp)
698 struct tcb *tcp;
699 {
700         long scno = 0;
701 #ifndef USE_PROCFS
702         int pid = tcp->pid;
703 #endif /* !PROCFS */    
704
705 #ifdef LINUX
706 #if defined(S390)
707         if (upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
708                 return -1;
709         scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-4),0);
710         if (errno)
711                 return -1;
712         scno&=0xFF;
713 #elif defined (POWERPC)
714         if (upeek(pid, 4*PT_R0, &scno) < 0)
715                 return -1;
716         if (!(tcp->flags & TCB_INSYSCALL)) {
717                 /* Check if we return from execve. */
718                 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
719                         tcp->flags &= ~TCB_WAITEXECVE;
720                         return 0;
721                 }
722         }
723 #elif defined (I386)
724         if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
725                 return -1;
726 #elif defined(IA64)
727 #       define IA64_PSR_IS      ((long)1 << 34)
728         if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
729                 ia32 = (psr & IA64_PSR_IS) != 0;
730         if (!(tcp->flags & TCB_INSYSCALL)) {
731                 if (ia32) {
732                         if (upeek(pid, PT_R1, &scno) < 0)       /* orig eax */
733                                 return -1;
734                         /* Check if we return from execve. */
735                 } else {
736                         if (upeek (pid, PT_R15, &scno) < 0)
737                                 return -1;
738                 }
739         } else {
740                 /* syscall in progress */
741                 if (upeek (pid, PT_R8, &r8) < 0)
742                         return -1;
743                 if (upeek (pid, PT_R10, &r10) < 0)
744                         return -1;
745         }
746         if (tcp->flags & TCB_WAITEXECVE) {
747                 tcp->flags &= ~TCB_WAITEXECVE;
748                 return 0;
749         }
750
751 #elif defined (ARM)
752         { 
753             long pc;
754             upeek(pid, 4*15, &pc);
755             umoven(tcp, pc-4, 4, (char *)&scno);
756             scno &= 0x000fffff;
757         }
758 #elif defined (M68K)
759         if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
760                 return -1;
761 #elif defined (MIPS)
762         if (upeek(pid, REG_A3, &a3) < 0)
763                 return -1;
764
765         if(!(tcp->flags & TCB_INSYSCALL)) {
766                 if (upeek(pid, REG_V0, &scno) < 0)
767                         return -1;
768
769                 if (scno < 0 || scno > nsyscalls) {
770                         if(a3 == 0 || a3 == -1) {
771                                 if(debug)
772                                         fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
773                                 return 0;
774                         }
775                 }
776         } else {
777                 if (upeek(pid, REG_V0, &r2) < 0)
778                         return -1;
779         }
780 #elif defined (ALPHA)
781         if (upeek(pid, REG_A3, &a3) < 0)
782                 return -1;
783
784         if (!(tcp->flags & TCB_INSYSCALL)) {
785                 if (upeek(pid, REG_R0, &scno) < 0)
786                         return -1;
787
788                 /* Check if we return from execve. */
789                 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
790                         tcp->flags &= ~TCB_WAITEXECVE;
791                         return 0;
792                 }
793
794                 /*
795                  * Do some sanity checks to figure out if it's
796                  * really a syscall entry
797                  */
798                 if (scno < 0 || scno > nsyscalls) {
799                         if (a3 == 0 || a3 == -1) {
800                                 if (debug)
801                                         fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
802                                 return 0;
803                         }
804                 }
805         }
806         else {
807                 if (upeek(pid, REG_R0, &r0) < 0)
808                         return -1;
809         }
810 #elif defined (SPARC)
811         /* Everything we need is in the current register set. */
812         if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
813                 return -1;
814
815         /* If we are entering, then disassemble the syscall trap. */
816         if (!(tcp->flags & TCB_INSYSCALL)) {
817                 /* Retrieve the syscall trap instruction. */
818                 errno = 0;
819                 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
820                 if (errno)
821                         return -1;
822
823                 /* Disassemble the trap to see what personality to use. */
824                 switch (trap) {
825                 case 0x91d02010:
826                         /* Linux/SPARC syscall trap. */
827                         set_personality(0);
828                         break;
829                 case 0x91d0206d:
830                         /* Linux/SPARC64 syscall trap. */
831                         fprintf(stderr,"syscall: Linux/SPARC64 not supported yet\n");
832                         return -1;
833                 case 0x91d02000:
834                         /* SunOS syscall trap. (pers 1) */
835                         fprintf(stderr,"syscall: SunOS no support\n");
836                         return -1;
837                 case 0x91d02008:
838                         /* Solaris 2.x syscall trap. (per 2) */
839                         set_personality(1);
840                         break; 
841                 case 0x91d02009:
842                         /* NetBSD/FreeBSD syscall trap. */
843                         fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
844                         return -1;
845                 case 0x91d02027:
846                         /* Solaris 2.x gettimeofday */
847                         set_personality(1);
848                         break;
849                 default:
850                         /* Unknown syscall trap. */
851                         if(tcp->flags & TCB_WAITEXECVE) {
852                                 tcp->flags &= ~TCB_WAITEXECVE;
853                                 return 0;
854                         }
855                         fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
856                         return -1;
857                 }
858
859                 /* Extract the system call number from the registers. */
860                 if (trap == 0x91d02027)
861                         scno = 156;
862                 else
863                         scno = regs.r_g1;
864                 if (scno == 0) {
865                         scno = regs.r_o0;
866                         memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
867                 }
868         }
869 #elif defined(HPPA)
870         if (upeek(pid, PT_GR20, &scno) < 0)
871                 return -1;
872         if (!(tcp->flags & TCB_INSYSCALL)) {
873                 /* Check if we return from execve. */
874                 if ((tcp->flags & TCB_WAITEXECVE)) {
875                         tcp->flags &= ~TCB_WAITEXECVE;
876                         return 0;
877                 }
878         }
879 #elif defined(SH)
880        /*
881         * In the new syscall ABI, the system call number is in R3.
882         */
883        if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
884                return -1;
885
886        if (scno < 0) {
887            /* Odd as it may seem, a glibc bug has been known to cause
888               glibc to issue bogus negative syscall numbers.  So for
889               our purposes, make strace print what it *should* have been */
890            long correct_scno = (scno & 0xff);
891            if (debug)
892                fprintf(stderr,
893                    "Detected glibc bug: bogus system call number = %ld, "
894                    "correcting to %ld\n",
895                    scno,
896                    correct_scno);
897            scno = correct_scno;
898        }
899
900
901        if (!(tcp->flags & TCB_INSYSCALL)) {
902                /* Check if we return from execve. */
903                if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
904                        tcp->flags &= ~TCB_WAITEXECVE;
905                        return 0;
906                }
907        }
908 #endif /* SH */
909 #endif /* LINUX */
910 #ifdef SUNOS4
911         if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
912                 return -1;
913 #elif defined(SH)
914        /* new syscall ABI returns result in R0 */
915        if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
916                return -1;
917 #endif
918 #ifdef USE_PROCFS
919 #ifdef HAVE_PR_SYSCALL
920         scno = tcp->status.PR_SYSCALL;
921 #else /* !HAVE_PR_SYSCALL */
922 #ifndef FREEBSD
923         scno = tcp->status.PR_WHAT;
924 #else /* FREEBSD */
925         if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
926                 perror("pread");
927                 return -1;
928         }
929         switch (regs.r_eax) {
930         case SYS_syscall:
931         case SYS___syscall:
932                 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
933                 break;
934         default:
935                 scno = regs.r_eax;
936                 break;
937         }
938 #endif /* FREEBSD */
939 #endif /* !HAVE_PR_SYSCALL */
940 #endif /* USE_PROCFS */
941         if (!(tcp->flags & TCB_INSYSCALL))
942                 tcp->scno = scno;
943         return 1;
944 }
945
946
947 int
948 syscall_fixup(tcp)
949 struct tcb *tcp;
950 {
951 #ifndef USE_PROCFS
952         int pid = tcp->pid;
953 #else /* USE_PROCFS */  
954         int scno = tcp->scno;
955
956         if (!(tcp->flags & TCB_INSYSCALL)) {
957                 if (tcp->status.PR_WHY != PR_SYSENTRY) {
958                         if (
959                             scno == SYS_fork
960 #ifdef SYS_vfork
961                             || scno == SYS_vfork
962 #endif /* SYS_vfork */
963 #ifdef SYS_fork1
964                             || scno == SYS_fork1
965 #endif /* SYS_fork1 */
966 #ifdef SYS_forkall
967                             || scno == SYS_forkall
968 #endif /* SYS_forkall */
969 #ifdef SYS_rfork1
970                             || scno == SYS_rfork1
971 #endif /* SYS_fork1 */
972 #ifdef SYS_rforkall
973                             || scno == SYS_rforkall
974 #endif /* SYS_rforkall */
975                             ) {
976                                 /* We are returning in the child, fake it. */
977                                 tcp->status.PR_WHY = PR_SYSENTRY;
978                                 trace_syscall(tcp);
979                                 tcp->status.PR_WHY = PR_SYSEXIT;
980                         }
981                         else {
982                                 fprintf(stderr, "syscall: missing entry\n");
983                                 tcp->flags |= TCB_INSYSCALL;
984                         }
985                 }
986         }
987         else {
988                 if (tcp->status.PR_WHY != PR_SYSEXIT) {
989                         fprintf(stderr, "syscall: missing exit\n");
990                         tcp->flags &= ~TCB_INSYSCALL;
991                 }
992         }
993 #endif /* USE_PROCFS */
994 #ifdef SUNOS4
995         if (!(tcp->flags & TCB_INSYSCALL)) {
996                 if (scno == 0) {
997                         fprintf(stderr, "syscall: missing entry\n");
998                         tcp->flags |= TCB_INSYSCALL;
999                 }
1000         }
1001         else {
1002                 if (scno != 0) {
1003                         if (debug) {
1004                                 /*
1005                                  * This happens when a signal handler
1006                                  * for a signal which interrupted a
1007                                  * a system call makes another system call.
1008                                  */
1009                                 fprintf(stderr, "syscall: missing exit\n");
1010                         }
1011                         tcp->flags &= ~TCB_INSYSCALL;
1012                 }
1013         }
1014 #endif /* SUNOS4 */
1015 #ifdef LINUX
1016 #if defined (I386)
1017         if (upeek(pid, 4*EAX, &eax) < 0)
1018                 return -1;
1019         if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1020                 if (debug)
1021                         fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1022                 return 0;
1023         }
1024 #elif defined (S390)
1025         if (upeek(pid, PT_GPR2, &gpr2) < 0)
1026                 return -1;
1027         if (gpr2 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1028                 if (debug)
1029                         fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1030                 return 0;
1031         }
1032 #elif defined (POWERPC)
1033 # define SO_MASK 0x10000000
1034         if (upeek(pid, 4*PT_CCR, &flags) < 0)
1035                 return -1;
1036         if (upeek(pid, 4*PT_R3, &result) < 0)
1037                 return -1;
1038         if (flags & SO_MASK)
1039                 result = -result;
1040 #elif defined (M68K)
1041         if (upeek(pid, 4*PT_D0, &d0) < 0)
1042                 return -1;
1043         if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1044                 if (debug)
1045                         fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1046                 return 0;
1047         }
1048 #elif defined (ARM)
1049         if (upeek(pid, 4*0, (long *)&r0) < 0)
1050                 return -1;
1051         if ( 0 && r0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1052                 if (debug)
1053                         fprintf(stderr, "stray syscall exit: d0 = %ld\n", r0);
1054                 return 0;
1055         }
1056 #elif defined (HPPA)
1057         if (upeek(pid, PT_GR28, &r28) < 0)
1058                 return -1;
1059 #elif defined(IA64)
1060         if (upeek(pid, PT_R10, &r10) < 0)
1061                 return -1;
1062         if (upeek(pid, PT_R8, &r8) < 0)
1063                 return -1;
1064         if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1065                 if (debug)
1066                         fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1067                 return 0;
1068         }
1069 #endif
1070 #endif /* LINUX */
1071         return 1;
1072 }
1073
1074 int
1075 get_error(tcp)
1076 struct tcb *tcp;
1077 {
1078         int u_error = 0;
1079 #ifdef LINUX
1080 #ifdef S390
1081                 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1082                         tcp->u_rval = -1;
1083                         u_error = -gpr2;
1084                 }
1085                 else {
1086                         tcp->u_rval = gpr2;
1087                         u_error = 0;
1088                 }
1089 #else /* !S390 */
1090 #ifdef I386
1091                 if (eax < 0 && -eax < nerrnos) {
1092                         tcp->u_rval = -1;
1093                         u_error = -eax;
1094                 }
1095                 else {
1096                         tcp->u_rval = eax;
1097                         u_error = 0;
1098                 }
1099 #else /* !I386 */
1100 #ifdef IA64
1101                 if (ia32) {
1102                         int err;
1103
1104                         err = (int)r8;
1105                         if (err < 0 && -err < nerrnos) {
1106                                 tcp->u_rval = -1;
1107                                 u_error = -err;
1108                         }
1109                         else {
1110                                 tcp->u_rval = err;
1111                                 u_error = 0;
1112                         }
1113                 } else {
1114                         if (r10) {
1115                                 tcp->u_rval = -1;
1116                                 u_error = r8;
1117                         } else {
1118                                 tcp->u_rval = r8;
1119                                 u_error = 0;
1120                         }
1121                 }
1122 #else /* !IA64 */
1123 #ifdef MIPS
1124                 if (a3) {
1125                         tcp->u_rval = -1;
1126                         u_error = r2;
1127                 } else {
1128                         tcp->u_rval = r2;
1129                         u_error = 0;
1130                 }
1131 #else
1132 #ifdef POWERPC
1133                 if (result && (unsigned) -result < nerrnos) {
1134                         tcp->u_rval = -1;
1135                         u_error = -result;
1136                 }
1137                 else {
1138                         tcp->u_rval = result;
1139                         u_error = 0;
1140                 }
1141 #else /* !POWERPC */
1142 #ifdef M68K
1143                 if (d0 && (unsigned) -d0 < nerrnos) {
1144                         tcp->u_rval = -1;
1145                         u_error = -d0;
1146                 }
1147                 else {
1148                         tcp->u_rval = d0;
1149                         u_error = 0;
1150                 }
1151 #else /* !M68K */
1152 #ifdef ARM
1153                 if (r0 && (unsigned) -r0 < nerrnos) {
1154                         tcp->u_rval = -1;
1155                         u_error = -r0;
1156                 }
1157                 else {
1158                         tcp->u_rval = r0;
1159                         u_error = 0;
1160                 }
1161 #else /* !ARM */
1162 #ifdef ALPHA
1163                 if (a3) {
1164                         tcp->u_rval = -1;
1165                         u_error = r0;
1166                 }
1167                 else {
1168                         tcp->u_rval = r0;
1169                         u_error = 0;
1170                 }
1171 #else /* !ALPHA */
1172 #ifdef SPARC
1173                 if (regs.r_psr & PSR_C) {
1174                         tcp->u_rval = -1;
1175                         u_error = regs.r_o0;
1176                 }
1177                 else {
1178                         tcp->u_rval = regs.r_o0;
1179                         u_error = 0;
1180                 }
1181 #else /* !SPARC */
1182 #ifdef HPPA
1183                 if (r28 && (unsigned) -r28 < nerrnos) {
1184                         tcp->u_rval = -1;
1185                         u_error = -r28;
1186                 }
1187                 else {
1188                         tcp->u_rval = r28;
1189                         u_error = 0;
1190                 }
1191 #else
1192 #ifdef SH
1193                /* interpret R0 as return value or error number */
1194                if (r0 && (unsigned) -r0 < nerrnos) {
1195                        tcp->u_rval = -1;
1196                        u_error = -r0;
1197                }
1198                else {
1199                        tcp->u_rval = r0;
1200                        u_error = 0;
1201                }
1202 #endif /* SH */
1203 #endif /* HPPA */
1204 #endif /* SPARC */
1205 #endif /* ALPHA */
1206 #endif /* ARM */
1207 #endif /* M68K */
1208 #endif /* POWERPC */
1209 #endif /* MIPS */
1210 #endif /* IA64 */
1211 #endif /* I386 */
1212 #endif /* S390 */
1213 #endif /* LINUX */
1214 #ifdef SUNOS4
1215                 /* get error code from user struct */
1216                 if (upeek(pid, uoff(u_error), &u_error) < 0)
1217                         return -1;
1218                 u_error >>= 24; /* u_error is a char */
1219
1220                 /* get system call return value */
1221                 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1222                         return -1;
1223 #endif /* SUNOS4 */
1224 #ifdef SVR4
1225 #ifdef SPARC
1226                 /* Judicious guessing goes a long way. */
1227                 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1228                         tcp->u_rval = -1;
1229                         u_error = tcp->status.pr_reg[R_O0];
1230                 }
1231                 else {
1232                         tcp->u_rval = tcp->status.pr_reg[R_O0];
1233                         u_error = 0;
1234                 }
1235 #endif /* SPARC */
1236 #ifdef I386
1237                 /* Wanna know how to kill an hour single-stepping? */
1238                 if (tcp->status.PR_REG[EFL] & 0x1) {
1239                         tcp->u_rval = -1;
1240                         u_error = tcp->status.PR_REG[EAX];
1241                 }
1242                 else {
1243                         tcp->u_rval = tcp->status.PR_REG[EAX];
1244 #ifdef HAVE_LONG_LONG
1245                         tcp->u_lrval =
1246                                 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1247                                 tcp->status.PR_REG[EAX];
1248 #endif
1249                         u_error = 0;
1250                 }
1251 #endif /* I386 */
1252 #ifdef MIPS
1253                 if (tcp->status.pr_reg[CTX_A3]) {
1254                         tcp->u_rval = -1;
1255                         u_error = tcp->status.pr_reg[CTX_V0];
1256                 }
1257                 else {
1258                         tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1259                         u_error = 0;
1260                 }
1261 #endif /* MIPS */
1262 #endif /* SVR4 */
1263 #ifdef FREEBSD
1264                 if (regs.r_eflags & PSL_C) {
1265                         tcp->u_rval = -1;
1266                         u_error = regs.r_eax;
1267                 } else {
1268                         tcp->u_rval = regs.r_eax;
1269                         tcp->u_lrval =
1270                           ((unsigned long long) regs.r_edx << 32) +  regs.r_eax;
1271                         u_error = 0;
1272                 }
1273 #endif /* FREEBSD */    
1274         tcp->u_error = u_error;
1275         return 1;
1276 }
1277
1278 int syscall_enter(tcp)
1279 struct tcb *tcp;
1280 {
1281 #ifndef USE_PROCFS
1282         int pid = tcp->pid;
1283 #endif /* !USE_PROCFS */        
1284 #ifdef LINUX
1285 #if defined(S390)
1286         {
1287                 int i;
1288                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1289                         tcp->u_nargs = sysent[tcp->scno].nargs;
1290                 else 
1291                         tcp->u_nargs = MAX_ARGS;
1292                 for (i = 0; i < tcp->u_nargs; i++) {
1293                         if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+(i<<2), &tcp->u_arg[i]) < 0)
1294                                 return -1;
1295                 }
1296         }
1297 #elif defined (ALPHA)
1298         {
1299                 int i;
1300                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1301                         tcp->u_nargs = sysent[tcp->scno].nargs;
1302                 else 
1303                         tcp->u_nargs = MAX_ARGS;
1304                 for (i = 0; i < tcp->u_nargs; i++) {
1305                         /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1306                          * for scno somewhere above here!
1307                          */
1308                         if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1309                                 return -1;
1310                 }
1311         }
1312 #elif defined (IA64)
1313         {
1314                 if (!ia32) {
1315                         unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1316                         /* be backwards compatible with kernel < 2.4.4... */
1317 #                       ifndef PT_RBS_END
1318 #                         define PT_RBS_END     PT_AR_BSP
1319 #                       endif
1320
1321                         if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
1322                                 return -1;
1323                         if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1324                                 return -1;
1325
1326                         sof = (cfm >> 0) & 0x7f;
1327                         sol = (cfm >> 7) & 0x7f;
1328                         out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1329
1330                         if (tcp->scno >= 0 && tcp->scno < nsyscalls
1331                             && sysent[tcp->scno].nargs != -1)
1332                                 tcp->u_nargs = sysent[tcp->scno].nargs;
1333                         else
1334                                 tcp->u_nargs = MAX_ARGS;
1335                         for (i = 0; i < tcp->u_nargs; ++i) {
1336                                 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1337                                            sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1338                                         return -1;
1339                         }
1340                 } else {
1341                         int i;
1342
1343                         if (/* EBX = out0 */
1344                             upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1345                             /* ECX = out1 */
1346                             || upeek(pid, PT_R9,  (long *) &tcp->u_arg[1]) < 0
1347                             /* EDX = out2 */
1348                             || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1349                             /* ESI = out3 */
1350                             || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1351                             /* EDI = out4 */
1352                             || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1353                             /* EBP = out5 */
1354                             || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1355                                 return -1;
1356
1357                         for (i = 0; i < 6; ++i)
1358                                 /* truncate away IVE sign-extension */
1359                                 tcp->u_arg[i] &= 0xffffffff;
1360
1361                         if (tcp->scno >= 0 && tcp->scno < nsyscalls
1362                             && sysent[tcp->scno].nargs != -1)
1363                                 tcp->u_nargs = sysent[tcp->scno].nargs;
1364                         else
1365                                 tcp->u_nargs = 5;
1366                 }
1367         }
1368 #elif defined (MIPS)
1369         {
1370                 long sp;
1371                 int i, nargs;
1372
1373                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1374                         nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
1375                 else 
1376                         nargs = tcp->u_nargs = MAX_ARGS;
1377                 if(nargs > 4) {
1378                         if(upeek(pid, REG_SP, &sp) < 0)
1379                                 return -1;
1380                         for(i = 0; i < 4; i++) {
1381                                 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
1382                                         return -1;
1383                         }
1384                         umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
1385                                (char *)(tcp->u_arg + 4));
1386                 } else {
1387                         for(i = 0; i < nargs; i++) {
1388                                 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
1389                                         return -1;
1390                         }
1391                 }
1392         }
1393 #elif defined (POWERPC)
1394         {
1395                 int i;
1396                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1397                         tcp->u_nargs = sysent[tcp->scno].nargs;
1398                 else 
1399                         tcp->u_nargs = MAX_ARGS;
1400                 for (i = 0; i < tcp->u_nargs; i++) {
1401                         if (upeek(pid, (i==0) ? (4*PT_ORIG_R3) : ((i+PT_R3)*4), &tcp->u_arg[i]) < 0)
1402                                 return -1;
1403                 }
1404         }
1405 #elif defined (SPARC)
1406         {
1407                 int i;
1408
1409                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1410                         tcp->u_nargs = sysent[tcp->scno].nargs;
1411                 else 
1412                         tcp->u_nargs = MAX_ARGS;
1413                 for (i = 0; i < tcp->u_nargs; i++)
1414                         tcp->u_arg[i] = *((&regs.r_o0) + i);
1415         }
1416 #elif defined (HPPA)
1417         {
1418                 int i;
1419
1420                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1421                         tcp->u_nargs = sysent[tcp->scno].nargs;
1422                 else 
1423                         tcp->u_nargs = MAX_ARGS;
1424                 for (i = 0; i < tcp->u_nargs; i++) {
1425                         if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1426                                 return -1;
1427                 }
1428         }
1429 #elif defined(SH)
1430        {
1431                int i; 
1432                static int syscall_regs[] = {
1433                    REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
1434                    REG_REG0, REG_REG0+1, REG_REG0+2
1435                    };
1436
1437                tcp->u_nargs = sysent[tcp->scno].nargs;
1438                for (i = 0; i < tcp->u_nargs; i++) {
1439                        if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
1440                                return -1;
1441                }
1442         }
1443 #else /* Other architecture (like i386) (32bits specific) */
1444         {
1445                 int i;
1446                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1447                         tcp->u_nargs = sysent[tcp->scno].nargs;
1448                 else 
1449                         tcp->u_nargs = MAX_ARGS;
1450                 for (i = 0; i < tcp->u_nargs; i++) {
1451                         if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
1452                                 return -1;
1453                 }
1454         }
1455 #endif 
1456 #endif /* LINUX */
1457 #ifdef SUNOS4
1458         {
1459                 int i;
1460                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1461                         tcp->u_nargs = sysent[tcp->scno].nargs;
1462                 else 
1463                         tcp->u_nargs = MAX_ARGS;
1464                 for (i = 0; i < tcp->u_nargs; i++) {
1465                         struct user *u;
1466
1467                         if (upeek(pid, uoff(u_arg[0]) +
1468                             (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1469                                 return -1;
1470                 }
1471         }
1472 #endif /* SUNOS4 */
1473 #ifdef SVR4
1474 #ifdef MIPS
1475         /*
1476          * SGI is broken: even though it has pr_sysarg, it doesn't
1477          * set them on system call entry.  Get a clue.
1478          */
1479         if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1480                 tcp->u_nargs = sysent[tcp->scno].nargs;
1481         else
1482                 tcp->u_nargs = tcp->status.pr_nsysarg;
1483         if (tcp->u_nargs > 4) {
1484                 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
1485                         4*sizeof(tcp->u_arg[0]));
1486                 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
1487                         (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
1488         }
1489         else {
1490                 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
1491                         tcp->u_nargs*sizeof(tcp->u_arg[0]));
1492         }
1493 #elif UNIXWARE >= 2
1494         /*
1495          * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1496          */
1497         if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1498                 tcp->u_nargs = sysent[tcp->scno].nargs;
1499         else
1500                 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1501         umoven(tcp, tcp->status.PR_REG[UESP] + 4,
1502                 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1503 #elif defined (HAVE_PR_SYSCALL)
1504         if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1505                 tcp->u_nargs = sysent[tcp->scno].nargs;
1506         else
1507                 tcp->u_nargs = tcp->status.pr_nsysarg;
1508         {
1509                 int i;
1510                 for (i = 0; i < tcp->u_nargs; i++)
1511                         tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1512         }
1513 #elif defined (I386)
1514         if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1515                 tcp->u_nargs = sysent[tcp->scno].nargs;
1516         else
1517                 tcp->u_nargs = 5;
1518         umoven(tcp, tcp->status.PR_REG[UESP] + 4,
1519                 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1520 #else
1521         I DONT KNOW WHAT TO DO
1522 #endif /* !HAVE_PR_SYSCALL */
1523 #endif /* SVR4 */
1524 #ifdef FREEBSD
1525         if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1526             sysent[tcp->scno].nargs > tcp->status.val)
1527                 tcp->u_nargs = sysent[tcp->scno].nargs;
1528         else 
1529                 tcp->u_nargs = tcp->status.val;
1530         if (tcp->u_nargs < 0)
1531                 tcp->u_nargs = 0;
1532         if (tcp->u_nargs > MAX_ARGS)
1533                 tcp->u_nargs = MAX_ARGS;
1534         switch(regs.r_eax) {
1535         case SYS___syscall:
1536                 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1537                       regs.r_esp + sizeof(int) + sizeof(quad_t));
1538           break;
1539         case SYS_syscall:
1540                 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1541                       regs.r_esp + 2 * sizeof(int));
1542           break;
1543         default:
1544                 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1545                       regs.r_esp + sizeof(int));
1546           break;
1547         }
1548 #endif /* FREEBSD */
1549         return 1;
1550 }
1551
1552 int
1553 trace_syscall(tcp)
1554 struct tcb *tcp;
1555 {
1556         int sys_res;
1557         struct timeval tv;
1558         int res;
1559
1560         /* Measure the exit time as early as possible to avoid errors. */
1561         if (dtime && (tcp->flags & TCB_INSYSCALL))
1562                 gettimeofday(&tv, NULL);
1563
1564         res = get_scno(tcp);
1565         if (res != 1)
1566                 return res;
1567
1568         res = syscall_fixup(tcp);
1569         if (res != 1)
1570                 return res;
1571
1572         if (tcp->flags & TCB_INSYSCALL) {
1573                 long u_error;
1574                 res = get_error(tcp);
1575                 if (res != 1)
1576                         return res;
1577                 u_error = tcp->u_error;
1578
1579
1580                 internal_syscall(tcp);
1581                 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1582                     !(qual_flags[tcp->scno] & QUAL_TRACE)) {
1583                         tcp->flags &= ~TCB_INSYSCALL;
1584                         return 0;
1585                 }
1586
1587                 if (tcp->flags & TCB_REPRINT) {
1588                         printleader(tcp);
1589                         tprintf("<... ");
1590                         if (tcp->scno >= nsyscalls || tcp->scno < 0)
1591                                 tprintf("syscall_%lu", tcp->scno);
1592                         else
1593                                 tprintf("%s", sysent[tcp->scno].sys_name);
1594                         tprintf(" resumed> ");
1595                 }
1596
1597                 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
1598                         call_count[tcp->scno]++;
1599                         if (tcp->u_error)
1600                                 error_count[tcp->scno]++;
1601                         tv_sub(&tv, &tv, &tcp->etime);
1602 #ifdef LINUX
1603                         if (tv_cmp(&tv, &tcp->dtime) > 0) {
1604                                 static struct timeval one_tick =
1605                                         { 0, 1000000 / HZ };
1606
1607                                 if (tv_nz(&tcp->dtime))
1608                                         tv = tcp->dtime;
1609                                 else if (tv_cmp(&tv, &one_tick) > 0) {
1610                                         if (tv_cmp(&shortest, &one_tick) < 0)
1611                                                 tv = shortest;
1612                                         else
1613                                                 tv = one_tick;
1614                                 }
1615                         }
1616 #endif /* LINUX */
1617                         if (tv_cmp(&tv, &shortest) < 0)
1618                                 shortest = tv;
1619                         tv_add(&tv_count[tcp->scno],
1620                                 &tv_count[tcp->scno], &tv);
1621                         tcp->flags &= ~TCB_INSYSCALL;
1622                         return 0;
1623                 }
1624
1625                 if (tcp->scno >= nsyscalls || tcp->scno < 0
1626                     || (qual_flags[tcp->scno] & QUAL_RAW))
1627                         sys_res = printargs(tcp);
1628                 else
1629                         sys_res = (*sysent[tcp->scno].sys_func)(tcp);
1630                 u_error = tcp->u_error;
1631                 tprintf(") ");
1632                 tabto(acolumn);
1633                 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
1634                     qual_flags[tcp->scno] & QUAL_RAW) {
1635                         if (u_error)
1636                                 tprintf("= -1 (errno %ld)", u_error);
1637                         else
1638                                 tprintf("= %#lx", tcp->u_rval);
1639                 }
1640                 else if (!(sys_res & RVAL_NONE) && u_error) {
1641                         switch (u_error) {
1642 #ifdef LINUX
1643                         case ERESTARTSYS:
1644                                 tprintf("= ? ERESTARTSYS (To be restarted)");
1645                                 break;
1646                         case ERESTARTNOINTR:
1647                                 tprintf("= ? ERESTARTNOINTR (To be restarted)");
1648                                 break;
1649                         case ERESTARTNOHAND:
1650                                 tprintf("= ? ERESTARTNOHAND (To be restarted)");
1651                                 break;
1652 #endif /* LINUX */
1653                         default:
1654                                 tprintf("= -1 ");
1655                                 if (u_error < 0)
1656                                         tprintf("E??? (errno %ld)", u_error);
1657                                 else if (u_error < nerrnos && u_error < sys_nerr)
1658                                         tprintf("%s (%s)", errnoent[u_error],
1659                                                 sys_errlist[u_error]);
1660                                 else if (u_error < nerrnos)
1661                                         tprintf("%s (errno %ld)",
1662                                                 errnoent[u_error], u_error);
1663                                 else if (u_error < sys_nerr)
1664                                         tprintf("ERRNO_%ld (%s)", u_error,
1665                                                 sys_errlist[u_error]);
1666                                 else
1667                                         tprintf("E??? (errno %ld)", u_error);
1668                                 break;
1669                         }
1670                 }
1671                 else {
1672                         if (sys_res & RVAL_NONE)
1673                                 tprintf("= ?");
1674                         else {
1675                                 switch (sys_res & RVAL_MASK) {
1676                                 case RVAL_HEX:
1677                                         tprintf("= %#lx", tcp->u_rval);
1678                                         break;
1679                                 case RVAL_OCTAL:
1680                                         tprintf("= %#lo", tcp->u_rval);
1681                                         break;
1682                                 case RVAL_UDECIMAL:
1683                                         tprintf("= %lu", tcp->u_rval);
1684                                         break;
1685                                 case RVAL_DECIMAL:
1686                                         tprintf("= %ld", tcp->u_rval);
1687                                         break;
1688 #ifdef HAVE_LONG_LONG
1689                                 case RVAL_LHEX:
1690                                         tprintf("= %#llx", tcp->u_lrval);
1691                                         break;
1692                                 case RVAL_LOCTAL:
1693                                         tprintf("= %#llo", tcp->u_lrval);
1694                                         break;
1695                                 case RVAL_LUDECIMAL:
1696                                         tprintf("= %llu", tcp->u_lrval);
1697                                         break;
1698                                 case RVAL_LDECIMAL:
1699                                         tprintf("= %lld", tcp->u_lrval);
1700                                         break;
1701 #endif
1702                                 default:
1703                                         fprintf(stderr,
1704                                                 "invalid rval format\n");
1705                                         break;
1706                                 }
1707                         }
1708                         if ((sys_res & RVAL_STR) && tcp->auxstr)
1709                                 tprintf(" (%s)", tcp->auxstr);
1710                 }
1711                 if (dtime) {
1712                         tv_sub(&tv, &tv, &tcp->etime);
1713                         tprintf(" <%ld.%06ld>",
1714                                 (long) tv.tv_sec, (long) tv.tv_usec);
1715                 }
1716                 printtrailer(tcp);
1717
1718                 dumpio(tcp);
1719                 if (fflush(tcp->outf) == EOF)
1720                         return -1;
1721                 tcp->flags &= ~TCB_INSYSCALL;
1722                 return 0;
1723         }
1724
1725         /* Entering system call */
1726         res = syscall_enter(tcp);
1727         if (res != 1)
1728                 return res;
1729
1730         switch (tcp->scno + NR_SYSCALL_BASE) {
1731 #ifdef LINUX
1732 #if !defined (ALPHA) && !defined(SPARC) && !defined(MIPS) && !defined(HPPA)
1733         case SYS_socketcall:
1734                 decode_subcall(tcp, SYS_socket_subcall,
1735                         SYS_socket_nsubcalls, deref_style);
1736                 break;
1737         case SYS_ipc:
1738                 decode_subcall(tcp, SYS_ipc_subcall,
1739                         SYS_ipc_nsubcalls, shift_style);
1740                 break;
1741 #endif /* !ALPHA && !MIPS && !SPARC */
1742 #ifdef SPARC
1743         case SYS_socketcall:
1744                 sparc_socket_decode (tcp);
1745                 break;
1746 #endif
1747 #endif /* LINUX */
1748 #ifdef SVR4
1749 #ifdef SYS_pgrpsys_subcall
1750         case SYS_pgrpsys:
1751                 decode_subcall(tcp, SYS_pgrpsys_subcall,
1752                         SYS_pgrpsys_nsubcalls, shift_style);
1753                 break;
1754 #endif /* SYS_pgrpsys_subcall */
1755 #ifdef SYS_sigcall_subcall
1756         case SYS_sigcall:
1757                 decode_subcall(tcp, SYS_sigcall_subcall,
1758                         SYS_sigcall_nsubcalls, mask_style);
1759                 break;
1760 #endif /* SYS_sigcall_subcall */
1761         case SYS_msgsys:
1762                 decode_subcall(tcp, SYS_msgsys_subcall,
1763                         SYS_msgsys_nsubcalls, shift_style);
1764                 break;
1765         case SYS_shmsys:
1766                 decode_subcall(tcp, SYS_shmsys_subcall,
1767                         SYS_shmsys_nsubcalls, shift_style);
1768                 break;
1769         case SYS_semsys:
1770                 decode_subcall(tcp, SYS_semsys_subcall,
1771                         SYS_semsys_nsubcalls, shift_style);
1772                 break;
1773 #if 0 /* broken */
1774         case SYS_utssys:
1775                 decode_subcall(tcp, SYS_utssys_subcall,
1776                         SYS_utssys_nsubcalls, shift_style);
1777                 break;
1778 #endif
1779         case SYS_sysfs:
1780                 decode_subcall(tcp, SYS_sysfs_subcall,
1781                         SYS_sysfs_nsubcalls, shift_style);
1782                 break;
1783         case SYS_spcall:
1784                 decode_subcall(tcp, SYS_spcall_subcall,
1785                         SYS_spcall_nsubcalls, shift_style);
1786                 break;
1787 #ifdef SYS_context_subcall
1788         case SYS_context:
1789                 decode_subcall(tcp, SYS_context_subcall,
1790                         SYS_context_nsubcalls, shift_style);
1791                 break;
1792 #endif /* SYS_context_subcall */
1793 #ifdef SYS_door_subcall
1794         case SYS_door:
1795                 decode_subcall(tcp, SYS_door_subcall,
1796                         SYS_door_nsubcalls, door_style);
1797                 break;
1798 #endif /* SYS_door_subcall */
1799 #ifdef SYS_kaio_subcall
1800         case SYS_kaio:
1801                 decode_subcall(tcp, SYS_kaio_subcall,
1802                         SYS_kaio_nsubcalls, shift_style);
1803                 break;
1804 #endif
1805 #endif /* SVR4 */
1806 #ifdef FREEBSD
1807         case SYS_msgsys:
1808         case SYS_shmsys:
1809         case SYS_semsys:
1810                 decode_subcall(tcp, 0, 0, table_style);
1811                 break;
1812 #endif
1813 #ifdef SUNOS4
1814         case SYS_semsys:
1815                 decode_subcall(tcp, SYS_semsys_subcall,
1816                         SYS_semsys_nsubcalls, shift_style);
1817                 break;
1818         case SYS_msgsys:
1819                 decode_subcall(tcp, SYS_msgsys_subcall,
1820                         SYS_msgsys_nsubcalls, shift_style);
1821                 break;
1822         case SYS_shmsys:
1823                 decode_subcall(tcp, SYS_shmsys_subcall,
1824                         SYS_shmsys_nsubcalls, shift_style);
1825                 break;
1826 #endif
1827         }
1828
1829         internal_syscall(tcp);
1830         if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
1831                 tcp->flags |= TCB_INSYSCALL;
1832                 return 0;
1833         }
1834
1835         if (cflag) {
1836                 gettimeofday(&tcp->etime, NULL);
1837                 tcp->flags |= TCB_INSYSCALL;
1838                 return 0;
1839         }
1840
1841         printleader(tcp);
1842         tcp->flags &= ~TCB_REPRINT;
1843         tcp_last = tcp;
1844         if (tcp->scno >= nsyscalls || tcp->scno < 0)
1845                 tprintf("syscall_%lu(", tcp->scno);
1846         else
1847                 tprintf("%s(", sysent[tcp->scno].sys_name);
1848         if (tcp->scno >= nsyscalls || tcp->scno < 0 || 
1849             ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
1850                 sys_res = printargs(tcp);
1851         else
1852                 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
1853         if (fflush(tcp->outf) == EOF)
1854                 return -1;
1855         tcp->flags |= TCB_INSYSCALL;
1856         /* Measure the entrance time as late as possible to avoid errors. */
1857         if (dtime)
1858                 gettimeofday(&tcp->etime, NULL);
1859         return sys_res;
1860 }
1861
1862 int
1863 printargs(tcp)
1864 struct tcb *tcp;
1865 {
1866         if (entering(tcp)) {
1867                 int i;
1868
1869                 for (i = 0; i < tcp->u_nargs; i++)
1870                         tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
1871         }
1872         return 0;
1873 }
1874
1875 long
1876 getrval2(tcp)
1877 struct tcb *tcp;
1878 {
1879         long val = -1;
1880
1881 #ifdef LINUX
1882 #ifdef SPARC
1883         struct regs regs;
1884         if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
1885                 return -1;
1886         val = regs.r_o1;
1887 #endif /* SPARC */
1888 #endif /* LINUX */
1889
1890 #ifdef SUNOS4
1891         if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
1892                 return -1;
1893 #endif /* SUNOS4 */
1894
1895 #ifdef SVR4
1896 #ifdef SPARC
1897         val = tcp->status.PR_REG[R_O1];
1898 #endif /* SPARC */
1899 #ifdef I386
1900         val = tcp->status.PR_REG[EDX];
1901 #endif /* I386 */
1902 #ifdef MIPS
1903         val = tcp->status.PR_REG[CTX_V1];
1904 #endif /* MIPS */
1905 #endif /* SVR4 */
1906 #ifdef FREEBSD
1907         struct reg regs;
1908         pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1909         val = regs.r_edx;
1910 #endif  
1911         return val;
1912 }
1913
1914 /*
1915  * Apparently, indirect system calls have already be converted by ptrace(2),
1916  * so if you see "indir" this program has gone astray.
1917  */
1918 int
1919 sys_indir(tcp)
1920 struct tcb *tcp;
1921 {
1922         int i, scno, nargs;
1923
1924         if (entering(tcp)) {
1925                 if ((scno = tcp->u_arg[0]) > nsyscalls) {
1926                         fprintf(stderr, "Bogus syscall: %u\n", scno);
1927                         return 0;
1928                 }
1929                 nargs = sysent[scno].nargs;
1930                 tprintf("%s", sysent[scno].sys_name);
1931                 for (i = 0; i < nargs; i++)
1932                         tprintf(", %#lx", tcp->u_arg[i+1]);
1933         }
1934         return 0;
1935 }
1936
1937 static int
1938 time_cmp(a, b)
1939 void *a;
1940 void *b;
1941 {
1942         return -tv_cmp(&tv_count[*((int *) a)], &tv_count[*((int *) b)]);
1943 }
1944
1945 static int
1946 syscall_cmp(a, b)
1947 void *a;
1948 void *b;
1949 {
1950         return strcmp(sysent[*((int *) a)].sys_name,
1951                 sysent[*((int *) b)].sys_name);
1952 }
1953
1954 static int
1955 count_cmp(a, b)
1956 void *a;
1957 void *b;
1958 {
1959         int m = call_count[*((int *) a)], n = call_count[*((int *) b)];
1960
1961         return (m < n) ? 1 : (m > n) ? -1 : 0;
1962 }
1963
1964 static int (*sortfun)();
1965 static struct timeval overhead = { -1, -1 };
1966
1967 void
1968 set_sortby(sortby)
1969 char *sortby;
1970 {
1971         if (strcmp(sortby, "time") == 0)
1972                 sortfun = time_cmp;
1973         else if (strcmp(sortby, "calls") == 0)
1974                 sortfun = count_cmp;
1975         else if (strcmp(sortby, "name") == 0)
1976                 sortfun = syscall_cmp;
1977         else if (strcmp(sortby, "nothing") == 0)
1978                 sortfun = NULL;
1979         else {
1980                 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
1981                 exit(1);
1982         }
1983 }
1984
1985 void set_overhead(n)
1986 int n;
1987 {
1988         overhead.tv_sec = n / 1000000;
1989         overhead.tv_usec = n % 1000000;
1990 }
1991
1992 void
1993 call_summary(outf)
1994 FILE *outf;
1995 {
1996         int i, j;
1997         int call_cum, error_cum;
1998         struct timeval tv_cum, dtv;
1999         double percent;
2000         char *dashes = "-------------------------";
2001         char error_str[16];
2002
2003         call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2004         if (overhead.tv_sec == -1) {
2005                 tv_mul(&overhead, &shortest, 8);
2006                 tv_div(&overhead, &overhead, 10);
2007         }
2008         for (i = 0; i < nsyscalls; i++) {
2009                 sorted_count[i] = i;
2010                 if (call_count[i] == 0)
2011                         continue;
2012                 tv_mul(&dtv, &overhead, call_count[i]);
2013                 tv_sub(&tv_count[i], &tv_count[i], &dtv);
2014                 call_cum += call_count[i];
2015                 error_cum += error_count[i];
2016                 tv_add(&tv_cum, &tv_cum, &tv_count[i]);
2017         }
2018         if (sortfun)
2019                 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2020         fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2021                 "% time", "seconds", "usecs/call",
2022                 "calls", "errors", "syscall");
2023         fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2024                 dashes, dashes, dashes, dashes, dashes, dashes);
2025         for (i = 0; i < nsyscalls; i++) {
2026                 j = sorted_count[i];
2027                 if (call_count[j] == 0)
2028                         continue;
2029                 tv_div(&dtv, &tv_count[j], call_count[j]);
2030                 if (error_count[j])
2031                         sprintf(error_str, "%d", error_count[j]);
2032                 else
2033                         error_str[0] = '\0';
2034                 percent = 100.0*tv_float(&tv_count[j])/tv_float(&tv_cum);
2035                 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2036                         percent, (long) tv_count[j].tv_sec,
2037                         (long) tv_count[j].tv_usec,
2038                         (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2039                         call_count[j], error_str, sysent[j].sys_name);
2040         }
2041         fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2042                 dashes, dashes, dashes, dashes, dashes, dashes);
2043         if (error_cum)
2044                 sprintf(error_str, "%d", error_cum);
2045         else
2046                 error_str[0] = '\0';
2047         fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2048                 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2049                 call_cum, error_str, "total");
2050 }