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