]> granicus.if.org Git - strace/blob - syscall.c
Define table entries for sys_stat64, sys_lstat64, and sys_fstat64.
[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                 internal_fork(tcp);
535                 break;
536 #ifdef SYS_clone
537         case SYS_clone:
538                 internal_clone(tcp);
539                 break;
540 #endif
541 #ifdef SYS_execv
542         case SYS_execv:
543 #endif
544 #ifdef SYS_execve
545         case SYS_execve:
546 #endif
547                 internal_exec(tcp);
548                 break;
549
550 #ifdef SYS_wait
551         case SYS_wait:
552 #endif
553 #ifdef SYS_wait4
554         case SYS_wait4:
555 #endif
556 #ifdef SYS_waitpid
557         case SYS_waitpid:
558 #endif
559 #ifdef SYS_waitsys
560         case SYS_waitsys:
561 #endif
562                 internal_wait(tcp);
563                 break;
564
565 #ifdef SYS_exit
566         case SYS_exit:
567 #endif
568                 internal_exit(tcp);
569                 break;
570         }
571         return 0;
572 }
573
574 int
575 trace_syscall(tcp)
576 struct tcb *tcp;
577 {
578         int sys_res;
579         struct timeval tv;
580         long scno = 0;
581 #ifdef LINUX
582 #if defined (I386)
583         long eax;
584 #elif defined (POWERPC)
585         long result,flags;
586 #elif defined (M68K)
587         int d0;
588 #elif defined (ARM)
589         int r0;
590 #elif defined (ALPHA)
591         long r0;
592         long a3;
593 #elif defined(MIPS)
594         long r2,a3;
595 #elif defined (SPARC)
596         struct regs regs;
597         unsigned long trap;
598 #elif defined(S390)
599         long gpr2;
600         long pc;
601 #endif 
602 #endif /* LINUX */
603
604 #ifndef SVR4
605         int pid = tcp->pid;
606 #endif /* !SVR4 */
607
608         /* Measure the exit time as early as possible to avoid errors. */
609         if (dtime && (tcp->flags & TCB_INSYSCALL))
610                 gettimeofday(&tv, NULL);
611 #ifdef LINUX
612 #if defined(S390)
613         if (upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
614                 return -1;
615         scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-4),0);
616         if (errno)
617                 return -1;
618         scno&=0xFF;
619 #elif defined (POWERPC)
620         if (upeek(pid, 4*PT_R0, &scno) < 0)
621                 return -1;
622         if (!(tcp->flags & TCB_INSYSCALL)) {
623                 /* Check if we return from execve. */
624                 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
625                         tcp->flags &= ~TCB_WAITEXECVE;
626                         return 0;
627                 }
628         }
629 #elif defined (I386)
630         if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
631                 return -1;
632 #elif defined (ARM)
633         { 
634             long pc;
635             upeek(pid, 4*15, &pc);
636             umoven(tcp, pc-4, 4, (char *)&scno);
637             scno &= 0x000fffff;
638         }
639 #elif defined (M68K)
640         if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
641                 return -1;
642 #elif defined (MIPS)
643         if (upeek(pid, REG_A3, &a3) < 0)
644                 return -1;
645
646         if(!(tcp->flags & TCB_INSYSCALL)) {
647                 if (upeek(pid, REG_V0, &scno) < 0)
648                         return -1;
649
650                 if (scno < 0 || scno > nsyscalls) {
651                         if(a3 == 0 || a3 == -1) {
652                                 if(debug)
653                                         fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
654                                 return 0;
655                         }
656                 }
657         } else {
658                 if (upeek(pid, REG_V0, &r2) < 0)
659                         return -1;
660         }
661 #elif defined (ALPHA)
662         if (upeek(pid, REG_A3, &a3) < 0)
663                 return -1;
664
665         if (!(tcp->flags & TCB_INSYSCALL)) {
666                 if (upeek(pid, REG_R0, &scno) < 0)
667                         return -1;
668
669                 /* Check if we return from execve. */
670                 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
671                         tcp->flags &= ~TCB_WAITEXECVE;
672                         return 0;
673                 }
674
675                 /*
676                  * Do some sanity checks to figure out if it's
677                  * really a syscall entry
678                  */
679                 if (scno < 0 || scno > nsyscalls) {
680                         if (a3 == 0 || a3 == -1) {
681                                 if (debug)
682                                         fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
683                                 return 0;
684                         }
685                 }
686         }
687         else {
688                 if (upeek(pid, REG_R0, &r0) < 0)
689                         return -1;
690         }
691 #elif defined (SPARC)
692         /* Everything we need is in the current register set. */
693         if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
694                 return -1;
695
696         /* If we are entering, then disassemble the syscall trap. */
697         if (!(tcp->flags & TCB_INSYSCALL)) {
698                 /* Retrieve the syscall trap instruction. */
699                 errno = 0;
700                 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
701                 if (errno)
702                         return -1;
703
704                 /* Disassemble the trap to see what personality to use. */
705                 switch (trap) {
706                 case 0x91d02010:
707                         /* Linux/SPARC syscall trap. */
708                         set_personality(0);
709                         break;
710                 case 0x91d0206d:
711                         /* Linux/SPARC64 syscall trap. */
712                         fprintf(stderr,"syscall: Linux/SPARC64 not supported yet\n");
713                         return -1;
714                 case 0x91d02000:
715                         /* SunOS syscall trap. (pers 1) */
716                         fprintf(stderr,"syscall: SunOS no support\n");
717                         return -1;
718                 case 0x91d02008:
719                         /* Solaris 2.x syscall trap. (per 2) */
720                         set_personality(1);
721                         break; 
722                 case 0x91d02009:
723                         /* NetBSD/FreeBSD syscall trap. */
724                         fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
725                         return -1;
726                 case 0x91d02027:
727                         /* Solaris 2.x gettimeofday */
728                         set_personality(1);
729                         break;
730                 default:
731                         /* Unknown syscall trap. */
732                         if(tcp->flags & TCB_WAITEXECVE) {
733                                 tcp->flags &= ~TCB_WAITEXECVE;
734                                 return 0;
735                         }
736                         fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
737                         return -1;
738                 }
739
740                 /* Extract the system call number from the registers. */
741                 if (trap == 0x91d02027)
742                         scno = 156;
743                 else
744                         scno = regs.r_g1;
745                 if (scno == 0) {
746                         scno = regs.r_o0;
747                         memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
748                 }
749         }
750 #endif 
751 #endif /* LINUX */
752 #ifdef SUNOS4
753         if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
754                 return -1;
755 #endif
756 #ifdef SVR4
757 #ifdef HAVE_PR_SYSCALL
758         scno = tcp->status.pr_syscall;
759 #else /* !HAVE_PR_SYSCALL */
760         scno = tcp->status.PR_WHAT;
761 #endif /* !HAVE_PR_SYSCALL */
762         if (!(tcp->flags & TCB_INSYSCALL)) {
763                 if (tcp->status.PR_WHY != PR_SYSENTRY) {
764                         if (
765                             scno == SYS_fork
766 #ifdef SYS_vfork
767                             || scno == SYS_vfork
768 #endif /* SYS_vfork */
769                             ) {
770                                 /* We are returning in the child, fake it. */
771                                 tcp->status.PR_WHY = PR_SYSENTRY;
772                                 trace_syscall(tcp);
773                                 tcp->status.PR_WHY = PR_SYSEXIT;
774                         }
775                         else {
776                                 fprintf(stderr, "syscall: missing entry\n");
777                                 tcp->flags |= TCB_INSYSCALL;
778                         }
779                 }
780         }
781         else {
782                 if (tcp->status.PR_WHY != PR_SYSEXIT) {
783                         fprintf(stderr, "syscall: missing exit\n");
784                         tcp->flags &= ~TCB_INSYSCALL;
785                 }
786         }
787 #endif /* SVR4 */
788 #ifdef SUNOS4
789         if (!(tcp->flags & TCB_INSYSCALL)) {
790                 if (scno == 0) {
791                         fprintf(stderr, "syscall: missing entry\n");
792                         tcp->flags |= TCB_INSYSCALL;
793                 }
794         }
795         else {
796                 if (scno != 0) {
797                         if (debug) {
798                                 /*
799                                  * This happens when a signal handler
800                                  * for a signal which interrupted a
801                                  * a system call makes another system call.
802                                  */
803                                 fprintf(stderr, "syscall: missing exit\n");
804                         }
805                         tcp->flags &= ~TCB_INSYSCALL;
806                 }
807         }
808 #endif /* SUNOS4 */
809 #ifdef LINUX
810 #if defined (I386)
811         if (upeek(pid, 4*EAX, &eax) < 0)
812                 return -1;
813         if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
814                 if (debug)
815                         fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
816                 return 0;
817         }
818 #elif defined (POWERPC)
819 # define SO_MASK 0x10000000
820         if (upeek(pid, 4*PT_CCR, &flags) < 0)
821                 return -1;
822         if (upeek(pid, 4*PT_R3, &result) < 0)
823                 return -1;
824         if (flags & SO_MASK)
825                 result = -result;
826 #elif defined (M68K)
827         if (upeek(pid, 4*PT_D0, &d0) < 0)
828                 return -1;
829         if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
830                 if (debug)
831                         fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
832                 return 0;
833         }
834 #elif defined (ARM)
835         if (upeek(pid, 4*0, (long *)&r0) < 0)
836                 return -1;
837         if ( 0 && r0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
838                 if (debug)
839                         fprintf(stderr, "stray syscall exit: d0 = %ld\n", r0);
840                 return 0;
841         }
842 #else
843 #endif
844 #endif /* LINUX */
845
846         if (tcp->flags & TCB_INSYSCALL) {
847                 long u_error;
848
849 #ifdef LINUX
850 #ifdef I386
851                 if (eax < 0 && -eax < nerrnos) {
852                         tcp->u_rval = -1;
853                         u_error = -eax;
854                 }
855                 else {
856                         tcp->u_rval = eax;
857                         u_error = 0;
858                 }
859 #else /* !I386 */
860 #ifdef MIPS
861                 if (a3) {
862                         tcp->u_rval = -1;
863                         u_error = r2;
864                 } else {
865                         tcp->u_rval = r2;
866                         u_error = 0;
867                 }
868 #else
869 #ifdef POWERPC
870                 if (result && (unsigned) -result < nerrnos) {
871                         tcp->u_rval = -1;
872                         u_error = -result;
873                 }
874                 else {
875                         tcp->u_rval = result;
876                         u_error = 0;
877                 }
878 #else /* !POWERPC */
879 #ifdef M68K
880                 if (d0 && (unsigned) -d0 < nerrnos) {
881                         tcp->u_rval = -1;
882                         u_error = -d0;
883                 }
884                 else {
885                         tcp->u_rval = d0;
886                         u_error = 0;
887                 }
888 #else /* !M68K */
889 #ifdef ARM
890                 if (r0 && (unsigned) -r0 < nerrnos) {
891                         tcp->u_rval = -1;
892                         u_error = -r0;
893                 }
894                 else {
895                         tcp->u_rval = r0;
896                         u_error = 0;
897                 }
898 #else /* !ARM */
899 #ifdef ALPHA
900                 if (a3) {
901                         tcp->u_rval = -1;
902                         u_error = r0;
903                 }
904                 else {
905                         tcp->u_rval = r0;
906                         u_error = 0;
907                 }
908 #else /* !ALPHA */
909 #ifdef SPARC
910                 if (regs.r_psr & PSR_C) {
911                         tcp->u_rval = -1;
912                         u_error = regs.r_o0;
913                 }
914                 else {
915                         tcp->u_rval = regs.r_o0;
916                         u_error = 0;
917                 }
918 #endif /* SPARC */
919 #endif /* ALPHA */
920 #endif /* ARM */
921 #endif /* M68K */
922 #endif /* POWERPC */
923 #endif /* MIPS */
924 #endif /* I386 */
925 #endif /* LINUX */
926 #ifdef SUNOS4
927                 /* get error code from user struct */
928                 if (upeek(pid, uoff(u_error), &u_error) < 0)
929                         return -1;
930                 u_error >>= 24; /* u_error is a char */
931
932                 /* get system call return value */
933                 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
934                         return -1;
935 #endif /* SUNOS4 */
936 #ifdef SVR4
937 #ifdef SPARC
938                 /* Judicious guessing goes a long way. */
939                 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
940                         tcp->u_rval = -1;
941                         u_error = tcp->status.pr_reg[R_O0];
942                 }
943                 else {
944                         tcp->u_rval = tcp->status.pr_reg[R_O0];
945                         u_error = 0;
946                 }
947 #endif /* SPARC */
948 #ifdef I386
949                 /* Wanna know how to kill an hour single-stepping? */
950                 if (tcp->status.PR_REG[EFL] & 0x1) {
951                         tcp->u_rval = -1;
952                         u_error = tcp->status.PR_REG[EAX];
953                 }
954                 else {
955                         tcp->u_rval = tcp->status.PR_REG[EAX];
956                         u_error = 0;
957                 }
958 #endif /* I386 */
959 #ifdef MIPS
960                 if (tcp->status.pr_reg[CTX_A3]) {
961                         tcp->u_rval = -1;
962                         u_error = tcp->status.pr_reg[CTX_V0];
963                 }
964                 else {
965                         tcp->u_rval = tcp->status.pr_reg[CTX_V0];
966                         u_error = 0;
967                 }
968 #endif /* MIPS */
969 #endif /* SVR4 */
970                 tcp->u_error = u_error;
971
972                 internal_syscall(tcp);
973                 if (!(qual_flags[tcp->scno] & QUAL_TRACE)) {
974                         tcp->flags &= ~TCB_INSYSCALL;
975                         return 0;
976                 }
977
978                 if (tcp->flags & TCB_REPRINT) {
979                         printleader(tcp);
980                         tprintf("<... ");
981                         if (tcp->scno >= nsyscalls)
982                                 tprintf("syscall_%lu", tcp->scno);
983                         else
984                                 tprintf("%s", sysent[tcp->scno].sys_name);
985                         tprintf(" resumed> ");
986                 }
987
988                 if (cflag) {
989                         call_count[tcp->scno]++;
990                         if (u_error)
991                                 error_count[tcp->scno]++;
992                         tv_sub(&tv, &tv, &tcp->etime);
993 #ifdef LINUX
994                         if (tv_cmp(&tv, &tcp->dtime) > 0) {
995                                 static struct timeval one_tick =
996                                         { 0, 1000000 / HZ };
997
998                                 if (tv_nz(&tcp->dtime))
999                                         tv = tcp->dtime;
1000                                 else if (tv_cmp(&tv, &one_tick) > 0) {
1001                                         if (tv_cmp(&shortest, &one_tick) < 0)
1002                                                 tv = shortest;
1003                                         else
1004                                                 tv = one_tick;
1005                                 }
1006                         }
1007 #endif /* LINUX */
1008                         if (tv_cmp(&tv, &shortest) < 0)
1009                                 shortest = tv;
1010                         tv_add(&tv_count[tcp->scno],
1011                                 &tv_count[tcp->scno], &tv);
1012                         tcp->flags &= ~TCB_INSYSCALL;
1013                         return 0;
1014                 }
1015
1016                 if (tcp->scno >= nsyscalls
1017                     || (qual_flags[tcp->scno] & QUAL_RAW))
1018                         sys_res = printargs(tcp);
1019                 else
1020                         sys_res = (*sysent[tcp->scno].sys_func)(tcp);
1021                 u_error = tcp->u_error;
1022                 tprintf(") ");
1023                 tabto(acolumn);
1024                 if (qual_flags[tcp->scno] & QUAL_RAW) {
1025                         if (u_error)
1026                                 tprintf("= -1 (errno %ld)", u_error);
1027                         else
1028                                 tprintf("= %#lx", tcp->u_rval);
1029                 }
1030                 else if (!(sys_res & RVAL_NONE) && u_error) {
1031 #ifdef LINUX
1032                         switch (u_error) {
1033                         case ERESTARTSYS:
1034                                 tprintf("= ? ERESTARTSYS (To be restarted)");
1035                                 break;
1036                         case ERESTARTNOINTR:
1037                                 tprintf("= ? ERESTARTNOINTR (To be restarted)");
1038                                 break;
1039                         case ERESTARTNOHAND:
1040                                 tprintf("= ? ERESTARTNOHAND (To be restarted)");
1041                                 break;
1042                         default:
1043 #endif /* LINUX */
1044                                 tprintf("= -1 ");
1045                                 if (u_error < nerrnos && u_error < sys_nerr)
1046                                         tprintf("%s (%s)", errnoent[u_error],
1047                                                 sys_errlist[u_error]);
1048                                 else if (u_error < nerrnos)
1049                                         tprintf("%s (errno %ld)",
1050                                                 errnoent[u_error], u_error);
1051                                 else if (u_error < sys_nerr)
1052                                         tprintf("ERRNO_%ld (%s)", u_error,
1053                                                 sys_errlist[u_error]);
1054                                 else
1055                                         tprintf("E??? (errno %ld)", u_error);
1056 #ifdef LINUX
1057                                 break;
1058                         }
1059 #endif /* LINUX */
1060                 }
1061                 else {
1062                         if (sys_res & RVAL_NONE)
1063                                 tprintf("= ?");
1064                         else {
1065                                 switch (sys_res & RVAL_MASK) {
1066                                 case RVAL_HEX:
1067                                         tprintf("= %#lx", tcp->u_rval);
1068                                         break;
1069                                 case RVAL_OCTAL:
1070                                         tprintf("= %#lo", tcp->u_rval);
1071                                         break;
1072                                 case RVAL_UDECIMAL:
1073                                         tprintf("= %lu", tcp->u_rval);
1074                                         break;
1075                                 case RVAL_DECIMAL:
1076                                         tprintf("= %ld", tcp->u_rval);
1077                                         break;
1078                                 default:
1079                                         fprintf(stderr,
1080                                                 "invalid rval format\n");
1081                                         break;
1082                                 }
1083                         }
1084                         if ((sys_res & RVAL_STR) && tcp->auxstr)
1085                                 tprintf(" (%s)", tcp->auxstr);
1086                 }
1087                 if (dtime) {
1088                         tv_sub(&tv, &tv, &tcp->etime);
1089                         tprintf(" <%ld.%06ld>",
1090                                 (long) tv.tv_sec, (long) tv.tv_usec);
1091                 }
1092                 printtrailer(tcp);
1093
1094                 dumpio(tcp);
1095                 if (fflush(tcp->outf) == EOF)
1096                         return -1;
1097                 tcp->flags &= ~TCB_INSYSCALL;
1098                 return 0;
1099         }
1100
1101         /* Entering system call */
1102         tcp->scno = scno;
1103 #ifdef LINUX
1104 #if defined(S390)
1105         {
1106                 int i;
1107                 tcp->u_nargs = sysent[tcp->scno].nargs;
1108                 for (i = 0; i < tcp->u_nargs; i++) {
1109                         if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+(i<<2), &tcp->u_arg[i]) < 0)
1110                                 return -1;
1111                 }
1112         }
1113 #elif defined (ALPHA)
1114         {
1115                 int i;
1116                 tcp->u_nargs = sysent[tcp->scno].nargs;
1117                 for (i = 0; i < tcp->u_nargs; i++) {
1118                         /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1119                          * for scno somewhere above here!
1120                          */
1121                         if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1122                                 return -1;
1123                 }
1124         }
1125 #elif defined (MIPS)
1126         {
1127                 long sp;
1128                 int i, nargs;
1129
1130                 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
1131                 if(nargs > 4) {
1132                         if(upeek(pid, REG_SP, &sp) < 0)
1133                                 return -1;
1134                         for(i = 0; i < 4; i++) {
1135                                 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
1136                                         return -1;
1137                         }
1138                         umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
1139                                (char *)(tcp->u_arg + 4));
1140                 } else {
1141                         for(i = 0; i < nargs; i++) {
1142                                 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
1143                                         return -1;
1144                         }
1145                 }
1146         }
1147 #elif defined (POWERPC)
1148         {
1149                 int i;
1150                 tcp->u_nargs = sysent[tcp->scno].nargs;
1151                 for (i = 0; i < tcp->u_nargs; i++) {
1152                         if (upeek(pid, (i==0) ? (4*PT_ORIG_R3) : ((i+PT_R3)*4), &tcp->u_arg[i]) < 0)
1153                                 return -1;
1154                 }
1155         }
1156 #elif defined (SPARC)
1157         {
1158                 int i;
1159                  
1160                 tcp->u_nargs = sysent[tcp->scno].nargs;
1161                 for (i = 0; i < tcp->u_nargs; i++)
1162                         tcp->u_arg[i] = *((&regs.r_o0) + i);
1163         }
1164 #else 
1165         {
1166                 int i;
1167                 tcp->u_nargs = sysent[tcp->scno].nargs;
1168                 for (i = 0; i < tcp->u_nargs; i++) {
1169                         if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
1170                                 return -1;
1171                 }
1172         }
1173 #endif 
1174 #endif /* LINUX */
1175 #ifdef SUNOS4
1176         {
1177                 int i;
1178                 tcp->u_nargs = sysent[tcp->scno].nargs;
1179                 for (i = 0; i < tcp->u_nargs; i++) {
1180                         struct user *u;
1181
1182                         if (upeek(pid, uoff(u_arg[0]) +
1183                             (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1184                                 return -1;
1185                 }
1186         }
1187 #endif /* SUNOS4 */
1188 #ifdef SVR4
1189 #ifdef MIPS
1190         /*
1191          * SGI is broken: even though it has pr_sysarg, it doesn't
1192          * set them on system call entry.  Get a clue.
1193          */
1194         if (sysent[tcp->scno].nargs != -1)
1195                 tcp->u_nargs = sysent[tcp->scno].nargs;
1196         else
1197                 tcp->u_nargs = tcp->status.pr_nsysarg;
1198         if (tcp->u_nargs > 4) {
1199                 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
1200                         4*sizeof(tcp->u_arg[0]));
1201                 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
1202                         (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
1203         }
1204         else {
1205                 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
1206                         tcp->u_nargs*sizeof(tcp->u_arg[0]));
1207         }
1208 #else /* !MIPS */
1209 #ifdef HAVE_PR_SYSCALL
1210         if (sysent[tcp->scno].nargs != -1)
1211                 tcp->u_nargs = sysent[tcp->scno].nargs;
1212         else
1213                 tcp->u_nargs = tcp->status.pr_nsysarg;
1214         {
1215                 int i;
1216                 for (i = 0; i < tcp->u_nargs; i++)
1217                         tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1218         }
1219 #else /* !HAVE_PR_SYSCALL */
1220 #ifdef I386
1221         if (sysent[tcp->scno].nargs != -1)
1222                 tcp->u_nargs = sysent[tcp->scno].nargs;
1223         else
1224 #if UNIXWARE >= 2
1225                 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1226 #else
1227                 tcp->u_nargs = 5;
1228 #endif
1229         umoven(tcp, tcp->status.PR_REG[UESP] + 4,
1230                 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1231 #endif /* I386 */
1232 #endif /* !HAVE_PR_SYSCALL */
1233 #endif /* !MIPS */
1234 #endif /* SVR4 */
1235 #ifdef __arm__
1236         switch (tcp->scno + __NR_SYSCALL_BASE) {
1237 #else
1238         switch (tcp->scno) {
1239 #endif
1240 #ifdef LINUX
1241 #if !defined (ALPHA) && !defined(SPARC) && !defined(MIPS)
1242         case SYS_socketcall:
1243                 decode_subcall(tcp, SYS_socket_subcall,
1244                         SYS_socket_nsubcalls, deref_style);
1245                 break;
1246         case SYS_ipc:
1247                 decode_subcall(tcp, SYS_ipc_subcall,
1248                         SYS_ipc_nsubcalls, shift_style);
1249                 break;
1250 #endif /* !ALPHA && !SPARC */
1251 #ifdef SPARC
1252         case SYS_socketcall:
1253                 sparc_socket_decode (tcp);
1254                 break;
1255 #endif
1256 #endif /* LINUX */
1257 #ifdef SVR4
1258 #ifdef SYS_pgrpsys_subcall
1259         case SYS_pgrpsys:
1260                 decode_subcall(tcp, SYS_pgrpsys_subcall,
1261                         SYS_pgrpsys_nsubcalls, shift_style);
1262                 break;
1263 #endif /* SYS_pgrpsys_subcall */
1264 #ifdef SYS_sigcall_subcall
1265         case SYS_sigcall:
1266                 decode_subcall(tcp, SYS_sigcall_subcall,
1267                         SYS_sigcall_nsubcalls, mask_style);
1268                 break;
1269 #endif /* SYS_sigcall_subcall */
1270         case SYS_msgsys:
1271                 decode_subcall(tcp, SYS_msgsys_subcall,
1272                         SYS_msgsys_nsubcalls, shift_style);
1273                 break;
1274         case SYS_shmsys:
1275                 decode_subcall(tcp, SYS_shmsys_subcall,
1276                         SYS_shmsys_nsubcalls, shift_style);
1277                 break;
1278         case SYS_semsys:
1279                 decode_subcall(tcp, SYS_semsys_subcall,
1280                         SYS_semsys_nsubcalls, shift_style);
1281                 break;
1282 #if 0 /* broken */
1283         case SYS_utssys:
1284                 decode_subcall(tcp, SYS_utssys_subcall,
1285                         SYS_utssys_nsubcalls, shift_style);
1286                 break;
1287 #endif
1288         case SYS_sysfs:
1289                 decode_subcall(tcp, SYS_sysfs_subcall,
1290                         SYS_sysfs_nsubcalls, shift_style);
1291                 break;
1292         case SYS_spcall:
1293                 decode_subcall(tcp, SYS_spcall_subcall,
1294                         SYS_spcall_nsubcalls, shift_style);
1295                 break;
1296 #ifdef SYS_context_subcall
1297         case SYS_context:
1298                 decode_subcall(tcp, SYS_context_subcall,
1299                         SYS_context_nsubcalls, shift_style);
1300                 break;
1301 #endif /* SYS_context_subcall */
1302 #ifdef SYS_door_subcall
1303         case SYS_door:
1304                 decode_subcall(tcp, SYS_door_subcall,
1305                         SYS_door_nsubcalls, door_style);
1306                 break;
1307 #endif /* SYS_door_subcall */
1308 #endif /* SVR4 */
1309 #ifdef SUNOS4
1310         case SYS_semsys:
1311                 decode_subcall(tcp, SYS_semsys_subcall,
1312                         SYS_semsys_nsubcalls, shift_style);
1313                 break;
1314         case SYS_msgsys:
1315                 decode_subcall(tcp, SYS_msgsys_subcall,
1316                         SYS_msgsys_nsubcalls, shift_style);
1317                 break;
1318         case SYS_shmsys:
1319                 decode_subcall(tcp, SYS_shmsys_subcall,
1320                         SYS_shmsys_nsubcalls, shift_style);
1321                 break;
1322 #endif
1323         }
1324
1325         internal_syscall(tcp);
1326         if (!(qual_flags[tcp->scno] & QUAL_TRACE)) {
1327                 tcp->flags |= TCB_INSYSCALL;
1328                 return 0;
1329         }
1330
1331         if (cflag) {
1332                 gettimeofday(&tcp->etime, NULL);
1333                 tcp->flags |= TCB_INSYSCALL;
1334                 return 0;
1335         }
1336
1337         printleader(tcp);
1338         tcp->flags &= ~TCB_REPRINT;
1339         tcp_last = tcp;
1340         if (tcp->scno >= nsyscalls)
1341                 tprintf("syscall_%lu(", tcp->scno);
1342         else
1343                 tprintf("%s(", sysent[tcp->scno].sys_name);
1344         if (tcp->scno >= nsyscalls ||
1345             ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
1346                 sys_res = printargs(tcp);
1347         else
1348                 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
1349         if (fflush(tcp->outf) == EOF)
1350                 return -1;
1351         tcp->flags |= TCB_INSYSCALL;
1352         /* Measure the entrance time as late as possible to avoid errors. */
1353         if (dtime)
1354                 gettimeofday(&tcp->etime, NULL);
1355         return sys_res;
1356 }
1357
1358 int
1359 printargs(tcp)
1360 struct tcb *tcp;
1361 {
1362         if (entering(tcp)) {
1363                 int i;
1364
1365                 for (i = 0; i < tcp->u_nargs; i++)
1366                         tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
1367         }
1368         return 0;
1369 }
1370
1371 long
1372 getrval2(tcp)
1373 struct tcb *tcp;
1374 {
1375         long val = -1;
1376
1377 #ifdef LINUX
1378 #ifdef SPARC
1379         struct regs regs;
1380         if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
1381                 return -1;
1382         val = regs.r_o1;
1383 #endif /* SPARC */
1384 #endif /* LINUX */
1385
1386 #ifdef SUNOS4
1387         if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
1388                 return -1;
1389 #endif /* SUNOS4 */
1390
1391 #ifdef SVR4
1392 #ifdef SPARC
1393         val = tcp->status.PR_REG[R_O1];
1394 #endif /* SPARC */
1395 #ifdef I386
1396         val = tcp->status.PR_REG[EDX];
1397 #endif /* I386 */
1398 #ifdef MIPS
1399         val = tcp->status.PR_REG[CTX_V1];
1400 #endif /* MIPS */
1401 #endif /* SVR4 */
1402
1403         return val;
1404 }
1405
1406 /*
1407  * Apparently, indirect system calls have already be converted by ptrace(2),
1408  * so if you see "indir" this program has gone astray.
1409  */
1410 int
1411 sys_indir(tcp)
1412 struct tcb *tcp;
1413 {
1414         int i, scno, nargs;
1415
1416         if (entering(tcp)) {
1417                 if ((scno = tcp->u_arg[0]) > nsyscalls) {
1418                         fprintf(stderr, "Bogus syscall: %u\n", scno);
1419                         return 0;
1420                 }
1421                 nargs = sysent[scno].nargs;
1422                 tprintf("%s", sysent[scno].sys_name);
1423                 for (i = 0; i < nargs; i++)
1424                         tprintf(", %#lx", tcp->u_arg[i+1]);
1425         }
1426         return 0;
1427 }
1428
1429 static int
1430 time_cmp(a, b)
1431 void *a;
1432 void *b;
1433 {
1434         return -tv_cmp(&tv_count[*((int *) a)], &tv_count[*((int *) b)]);
1435 }
1436
1437 static int
1438 syscall_cmp(a, b)
1439 void *a;
1440 void *b;
1441 {
1442         return strcmp(sysent[*((int *) a)].sys_name,
1443                 sysent[*((int *) b)].sys_name);
1444 }
1445
1446 static int
1447 count_cmp(a, b)
1448 void *a;
1449 void *b;
1450 {
1451         int m = call_count[*((int *) a)], n = call_count[*((int *) b)];
1452
1453         return (m < n) ? 1 : (m > n) ? -1 : 0;
1454 }
1455
1456 static int (*sortfun)();
1457 static struct timeval overhead = { -1, -1 };
1458
1459 void
1460 set_sortby(sortby)
1461 char *sortby;
1462 {
1463         if (strcmp(sortby, "time") == 0)
1464                 sortfun = time_cmp;
1465         else if (strcmp(sortby, "calls") == 0)
1466                 sortfun = count_cmp;
1467         else if (strcmp(sortby, "name") == 0)
1468                 sortfun = syscall_cmp;
1469         else if (strcmp(sortby, "nothing") == 0)
1470                 sortfun = NULL;
1471         else {
1472                 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
1473                 exit(1);
1474         }
1475 }
1476
1477 void set_overhead(n)
1478 int n;
1479 {
1480         overhead.tv_sec = n / 1000000;
1481         overhead.tv_usec = n % 1000000;
1482 }
1483
1484 void
1485 call_summary(outf)
1486 FILE *outf;
1487 {
1488         int i, j;
1489         int call_cum, error_cum;
1490         struct timeval tv_cum, dtv;
1491         double percent;
1492         char *dashes = "-------------------------";
1493         char error_str[16];
1494
1495         call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
1496         if (overhead.tv_sec == -1) {
1497                 tv_mul(&overhead, &shortest, 8);
1498                 tv_div(&overhead, &overhead, 10);
1499         }
1500         for (i = 0; i < nsyscalls; i++) {
1501                 sorted_count[i] = i;
1502                 if (call_count[i] == 0)
1503                         continue;
1504                 tv_mul(&dtv, &overhead, call_count[i]);
1505                 tv_sub(&tv_count[i], &tv_count[i], &dtv);
1506                 call_cum += call_count[i];
1507                 error_cum += error_count[i];
1508                 tv_add(&tv_cum, &tv_cum, &tv_count[i]);
1509         }
1510         if (sortfun)
1511                 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
1512         fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
1513                 "% time", "seconds", "usecs/call",
1514                 "calls", "errors", "syscall");
1515         fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
1516                 dashes, dashes, dashes, dashes, dashes, dashes);
1517         for (i = 0; i < nsyscalls; i++) {
1518                 j = sorted_count[i];
1519                 if (call_count[j] == 0)
1520                         continue;
1521                 tv_div(&dtv, &tv_count[j], call_count[j]);
1522                 if (error_count[j])
1523                         sprintf(error_str, "%d", error_count[j]);
1524                 else
1525                         error_str[0] = '\0';
1526                 percent = 100.0*tv_float(&tv_count[j])/tv_float(&tv_cum);
1527                 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
1528                         percent, (long) tv_count[j].tv_sec,
1529                         (long) tv_count[j].tv_usec,
1530                         (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
1531                         call_count[j], error_str, sysent[j].sys_name);
1532         }
1533         fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
1534                 dashes, dashes, dashes, dashes, dashes, dashes);
1535         if (error_cum)
1536                 sprintf(error_str, "%d", error_cum);
1537         else
1538                 error_str[0] = '\0';
1539         fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
1540                 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
1541                 call_cum, error_str, "total");
1542 }