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