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