]> granicus.if.org Git - strace/blob - syscall.c
2004-09-03 Roland McGrath <roland@redhat.com>
[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 #if defined (SPARC) || defined (SPARC64)
47 #  define fpq kernel_fpq
48 #  define fq kernel_fq
49 #  define fpu kernel_fpu
50 #endif
51 #include <asm/reg.h>
52 #if defined (SPARC) || defined (SPARC64)
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 # ifdef HAVE_STRUCT_IA64_FPREG
67 #  define ia64_fpreg XXX_ia64_fpreg
68 # endif
69 # ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70 #  define pt_all_user_regs XXX_pt_all_user_regs
71 # endif
72 #include <linux/ptrace.h>
73 # undef ia64_fpreg
74 # undef pt_all_user_regs
75 #endif
76
77 #if defined (LINUX) && defined (SPARC64)
78 # define r_pc r_tpc
79 # undef PTRACE_GETREGS
80 # define PTRACE_GETREGS PTRACE_GETREGS64
81 # undef PTRACE_SETREGS
82 # define PTRACE_SETREGS PTRACE_SETREGS64
83 #endif /* LINUX && SPARC64 */
84
85 #if defined(LINUX) && defined(IA64)
86 # include <asm/ptrace_offsets.h>
87 # include <asm/rse.h>
88 #endif
89
90 #define NR_SYSCALL_BASE 0
91 #ifdef LINUX
92 #ifndef ERESTARTSYS
93 #define ERESTARTSYS     512
94 #endif
95 #ifndef ERESTARTNOINTR
96 #define ERESTARTNOINTR  513
97 #endif
98 #ifndef ERESTARTNOHAND
99 #define ERESTARTNOHAND  514     /* restart if no handler.. */
100 #endif
101 #ifndef ENOIOCTLCMD
102 #define ENOIOCTLCMD     515     /* No ioctl command */
103 #endif
104 #ifndef ERESTART_RESTARTBLOCK
105 #define ERESTART_RESTARTBLOCK 516       /* restart by calling sys_restart_syscall */
106 #endif
107 #ifndef NSIG
108 #define NSIG 32
109 #endif
110 #ifdef ARM
111 #undef NSIG
112 #define NSIG 32
113 #undef NR_SYSCALL_BASE
114 #define NR_SYSCALL_BASE __NR_SYSCALL_BASE
115 #endif
116 #endif /* LINUX */
117
118 #include "syscall.h"
119
120 /* Define these shorthand notations to simplify the syscallent files. */
121 #define TF TRACE_FILE
122 #define TI TRACE_IPC
123 #define TN TRACE_NETWORK
124 #define TP TRACE_PROCESS
125 #define TS TRACE_SIGNAL
126
127 static const struct sysent sysent0[] = {
128 #include "syscallent.h"
129 };
130 static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
131
132 #if SUPPORTED_PERSONALITIES >= 2
133 static const struct sysent sysent1[] = {
134 #include "syscallent1.h"
135 };
136 static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
137 #endif /* SUPPORTED_PERSONALITIES >= 2 */
138
139 #if SUPPORTED_PERSONALITIES >= 3
140 static const struct sysent sysent2[] = {
141 #include "syscallent2.h"
142 };
143 static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
144 #endif /* SUPPORTED_PERSONALITIES >= 3 */
145
146 const struct sysent *sysent;
147 int nsyscalls;
148
149 /* Now undef them since short defines cause wicked namespace pollution. */
150 #undef TF
151 #undef TI
152 #undef TN
153 #undef TP
154 #undef TS
155
156 static const char *const errnoent0[] = {
157 #include "errnoent.h"
158 };
159 static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
160
161 #if SUPPORTED_PERSONALITIES >= 2
162 static const char *const errnoent1[] = {
163 #include "errnoent1.h"
164 };
165 static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
166 #endif /* SUPPORTED_PERSONALITIES >= 2 */
167
168 #if SUPPORTED_PERSONALITIES >= 3
169 static const char *const errnoent2[] = {
170 #include "errnoent2.h"
171 };
172 static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
173 #endif /* SUPPORTED_PERSONALITIES >= 3 */
174
175 const char *const *errnoent;
176 int nerrnos;
177
178 int current_personality;
179
180 int
181 set_personality(personality)
182 int personality;
183 {
184         switch (personality) {
185         case 0:
186                 errnoent = errnoent0;
187                 nerrnos = nerrnos0;
188                 sysent = sysent0;
189                 nsyscalls = nsyscalls0;
190                 ioctlent = ioctlent0;
191                 nioctlents = nioctlents0;
192                 signalent = signalent0;
193                 nsignals = nsignals0;
194                 break;
195
196 #if SUPPORTED_PERSONALITIES >= 2
197         case 1:
198                 errnoent = errnoent1;
199                 nerrnos = nerrnos1;
200                 sysent = sysent1;
201                 nsyscalls = nsyscalls1;
202                 ioctlent = ioctlent1;
203                 nioctlents = nioctlents1;
204                 signalent = signalent1;
205                 nsignals = nsignals1;
206                 break;
207 #endif /* SUPPORTED_PERSONALITIES >= 2 */
208
209 #if SUPPORTED_PERSONALITIES >= 3
210         case 2:
211                 errnoent = errnoent2;
212                 nerrnos = nerrnos2;
213                 sysent = sysent2;
214                 nsyscalls = nsyscalls2;
215                 ioctlent = ioctlent2;
216                 nioctlents = nioctlents2;
217                 signalent = signalent2;
218                 nsignals = nsignals2;
219                 break;
220 #endif /* SUPPORTED_PERSONALITIES >= 3 */
221
222         default:
223                 return -1;
224         }
225
226         current_personality = personality;
227         return 0;
228 }
229
230 int qual_flags[MAX_QUALS];
231
232 static int call_count[MAX_QUALS];
233 static int error_count[MAX_QUALS];
234 static struct timeval tv_count[MAX_QUALS];
235 static int sorted_count[MAX_QUALS];
236
237 static struct timeval shortest = { 1000000, 0 };
238
239 static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
240
241 static struct qual_options {
242         int bitflag;
243         char *option_name;
244         int (*qualify)();
245         char *argument_name;
246 } qual_options[] = {
247         { QUAL_TRACE,   "trace",        qual_syscall,   "system call"   },
248         { QUAL_TRACE,   "t",            qual_syscall,   "system call"   },
249         { QUAL_ABBREV,  "abbrev",       qual_syscall,   "system call"   },
250         { QUAL_ABBREV,  "a",            qual_syscall,   "system call"   },
251         { QUAL_VERBOSE, "verbose",      qual_syscall,   "system call"   },
252         { QUAL_VERBOSE, "v",            qual_syscall,   "system call"   },
253         { QUAL_RAW,     "raw",          qual_syscall,   "system call"   },
254         { QUAL_RAW,     "x",            qual_syscall,   "system call"   },
255         { QUAL_SIGNAL,  "signal",       qual_signal,    "signal"        },
256         { QUAL_SIGNAL,  "signals",      qual_signal,    "signal"        },
257         { QUAL_SIGNAL,  "s",            qual_signal,    "signal"        },
258         { QUAL_FAULT,   "fault",        qual_fault,     "fault"         },
259         { QUAL_FAULT,   "faults",       qual_fault,     "fault"         },
260         { QUAL_FAULT,   "m",            qual_fault,     "fault"         },
261         { QUAL_READ,    "read",         qual_desc,      "descriptor"    },
262         { QUAL_READ,    "reads",        qual_desc,      "descriptor"    },
263         { QUAL_READ,    "r",            qual_desc,      "descriptor"    },
264         { QUAL_WRITE,   "write",        qual_desc,      "descriptor"    },
265         { QUAL_WRITE,   "writes",       qual_desc,      "descriptor"    },
266         { QUAL_WRITE,   "w",            qual_desc,      "descriptor"    },
267         { 0,            NULL,           NULL,           NULL            },
268 };
269
270 static void
271 qualify_one(n, opt, not)
272         int n;
273         struct qual_options *opt;
274         int not;
275 {
276         if (not)
277                 qual_flags[n] &= ~opt->bitflag;
278         else
279                 qual_flags[n] |= opt->bitflag;
280 }
281
282 static int
283 qual_syscall(s, opt, not)
284         char *s;
285         struct qual_options *opt;
286         int not;
287 {
288         int i;
289         int any = 0;
290
291         for (i = 0; i < nsyscalls; i++) {
292                 if (strcmp(s, sysent[i].sys_name) == 0) {
293                         qualify_one(i, opt, not);
294                         any = 1;
295                 }
296         }
297         return !any;
298 }
299
300 static int
301 qual_signal(s, opt, not)
302         char *s;
303         struct qual_options *opt;
304         int not;
305 {
306         int i;
307         char buf[32];
308
309         if (s && *s && isdigit((unsigned char)*s)) {
310                 qualify_one(atoi(s), opt, not);
311                 return 1;
312         }
313         if (strlen(s) >= sizeof buf)
314                 return 0;
315         strcpy(buf, s);
316         s = buf;
317         for (i = 0; s[i]; i++)
318                 s[i] = toupper((unsigned char)(s[i]));
319         if (strncmp(s, "SIG", 3) == 0)
320                 s += 3;
321         for (i = 0; i <= NSIG; i++)
322                 if (strcmp(s, signame(i) + 3) == 0) {
323                         qualify_one(atoi(s), opt, not);
324                         return 1;
325                 }
326         return 0;
327 }
328
329 static int
330 qual_fault(s, opt, not)
331         char *s;
332         struct qual_options *opt;
333         int not;
334 {
335         return -1;
336 }
337
338 static int
339 qual_desc(s, opt, not)
340         char *s;
341         struct qual_options *opt;
342         int not;
343 {
344         if (s && *s && isdigit((unsigned char)*s)) {
345                 qualify_one(atoi(s), opt, not);
346                 return 0;
347         }
348         return -1;
349 }
350
351 static int
352 lookup_class(s)
353         char *s;
354 {
355         if (strcmp(s, "file") == 0)
356                 return TRACE_FILE;
357         if (strcmp(s, "ipc") == 0)
358                 return TRACE_IPC;
359         if (strcmp(s, "network") == 0)
360                 return TRACE_NETWORK;
361         if (strcmp(s, "process") == 0)
362                 return TRACE_PROCESS;
363         if (strcmp(s, "signal") == 0)
364                 return TRACE_SIGNAL;
365         return -1;
366 }
367
368 void
369 qualify(s)
370 char *s;
371 {
372         struct qual_options *opt;
373         int not;
374         char *p;
375         int i, n;
376
377         opt = &qual_options[0];
378         for (i = 0; (p = qual_options[i].option_name); i++) {
379                 n = strlen(p);
380                 if (strncmp(s, p, n) == 0 && s[n] == '=') {
381                         opt = &qual_options[i];
382                         s += n + 1;
383                         break;
384                 }
385         }
386         not = 0;
387         if (*s == '!') {
388                 not = 1;
389                 s++;
390         }
391         if (strcmp(s, "none") == 0) {
392                 not = 1 - not;
393                 s = "all";
394         }
395         if (strcmp(s, "all") == 0) {
396                 for (i = 0; i < MAX_QUALS; i++) {
397                         if (not)
398                                 qual_flags[i] &= ~opt->bitflag;
399                         else
400                                 qual_flags[i] |= opt->bitflag;
401                 }
402                 return;
403         }
404         for (i = 0; i < MAX_QUALS; i++) {
405                 if (not)
406                         qual_flags[i] |= opt->bitflag;
407                 else
408                         qual_flags[i] &= ~opt->bitflag;
409         }
410         for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
411                 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
412                         for (i = 0; i < MAX_QUALS; i++) {
413                                 if (sysent[i].sys_flags & n) {
414                                         if (not)
415                                                 qual_flags[i] &= ~opt->bitflag;
416                                         else
417                                                 qual_flags[i] |= opt->bitflag;
418                                 }
419                         }
420                         continue;
421                 }
422                 if (opt->qualify(p, opt, not)) {
423                         fprintf(stderr, "strace: invalid %s `%s'\n",
424                                 opt->argument_name, p);
425                         exit(1);
426                 }
427         }
428         return;
429 }
430
431 static void
432 dumpio(tcp)
433 struct tcb *tcp;
434 {
435         if (syserror(tcp))
436                 return;
437         if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
438                 return;
439         switch (tcp->scno + NR_SYSCALL_BASE) {
440         case SYS_read:
441 #ifdef SYS_pread64
442         case SYS_pread64:
443 #endif
444 #if defined SYS_pread && SYS_pread64 != SYS_pread
445         case SYS_pread:
446 #endif
447 #ifdef SYS_recv
448         case SYS_recv:
449 #endif
450 #ifdef SYS_recvfrom
451         case SYS_recvfrom:
452 #endif
453                 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
454                         dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
455                 break;
456         case SYS_write:
457 #ifdef SYS_pwrite64
458         case SYS_pwrite64:
459 #endif
460 #if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
461         case SYS_pwrite:
462 #endif
463 #ifdef SYS_send
464         case SYS_send:
465 #endif
466 #ifdef SYS_sendto
467         case SYS_sendto:
468 #endif
469                 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
470                         dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
471                 break;
472 #ifdef SYS_readv
473         case SYS_readv:
474                 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
475                         dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
476                 break;
477 #endif
478 #ifdef SYS_writev
479         case SYS_writev:
480
481                 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
482                         dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
483                 break;
484 #endif
485         }
486 }
487
488 #ifndef FREEBSD
489 enum subcall_style { shift_style, deref_style, mask_style, door_style };
490 #else /* FREEBSD */
491 enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
492
493 struct subcall {
494   int call;
495   int nsubcalls;
496   int subcalls[5];
497 };
498
499 const struct subcall subcalls_table[] = {
500   { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
501 #ifdef SYS_semconfig
502   { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
503 #else
504   { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
505 #endif
506   { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
507 };
508 #endif /* FREEBSD */
509
510 #if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
511
512 const int socket_map [] = {
513                /* SYS_SOCKET      */ 97,
514                /* SYS_BIND        */ 104,
515                /* SYS_CONNECT     */ 98,
516                /* SYS_LISTEN      */ 106,
517                /* SYS_ACCEPT      */ 99,
518                /* SYS_GETSOCKNAME */ 150,
519                /* SYS_GETPEERNAME */ 141,
520                /* SYS_SOCKETPAIR  */ 135,
521                /* SYS_SEND        */ 101,
522                /* SYS_RECV        */ 102,
523                /* SYS_SENDTO      */ 133,
524                /* SYS_RECVFROM    */ 125,
525                /* SYS_SHUTDOWN    */ 134,
526                /* SYS_SETSOCKOPT  */ 105,
527                /* SYS_GETSOCKOPT  */ 118,
528                /* SYS_SENDMSG     */ 114,
529                /* SYS_RECVMSG     */ 113
530 };
531
532 void
533 sparc_socket_decode (tcp)
534 struct tcb *tcp;
535 {
536         volatile long addr;
537         volatile int i, n;
538
539         if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
540                 return;
541         }
542         tcp->scno = socket_map [tcp->u_arg [0]-1];
543         n = tcp->u_nargs = sysent [tcp->scno].nargs;
544         addr = tcp->u_arg [1];
545         for (i = 0; i < n; i++){
546                 int arg;
547                 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
548                         arg = 0;
549                 tcp->u_arg [i] = arg;
550                 addr += sizeof (arg);
551         }
552 }
553
554 void
555 decode_subcall(tcp, subcall, nsubcalls, style)
556 struct tcb *tcp;
557 int subcall;
558 int nsubcalls;
559 enum subcall_style style;
560 {
561         long addr, mask, arg;
562         int i;
563
564         switch (style) {
565         case shift_style:
566                 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
567                         return;
568                 tcp->scno = subcall + tcp->u_arg[0];
569                 if (sysent[tcp->scno].nargs != -1)
570                         tcp->u_nargs = sysent[tcp->scno].nargs;
571                 else
572                         tcp->u_nargs--;
573                 for (i = 0; i < tcp->u_nargs; i++)
574                         tcp->u_arg[i] = tcp->u_arg[i + 1];
575                 break;
576         case deref_style:
577                 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
578                         return;
579                 tcp->scno = subcall + tcp->u_arg[0];
580                 addr = tcp->u_arg[1];
581                 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
582                         if (umove(tcp, addr, &arg) < 0)
583                                 arg = 0;
584                         tcp->u_arg[i] = arg;
585                         addr += sizeof(arg);
586                 }
587                 tcp->u_nargs = sysent[tcp->scno].nargs;
588                 break;
589         case mask_style:
590                 mask = (tcp->u_arg[0] >> 8) & 0xff;
591                 for (i = 0; mask; i++)
592                         mask >>= 1;
593                 if (i >= nsubcalls)
594                         return;
595                 tcp->u_arg[0] &= 0xff;
596                 tcp->scno = subcall + i;
597                 if (sysent[tcp->scno].nargs != -1)
598                         tcp->u_nargs = sysent[tcp->scno].nargs;
599                 break;
600         case door_style:
601                 /*
602                  * Oh, yuck.  The call code is the *sixth* argument.
603                  * (don't you mean the *last* argument? - JH)
604                  */
605                 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
606                         return;
607                 tcp->scno = subcall + tcp->u_arg[5];
608                 if (sysent[tcp->scno].nargs != -1)
609                         tcp->u_nargs = sysent[tcp->scno].nargs;
610                 else
611                         tcp->u_nargs--;
612                 break;
613 #ifdef FREEBSD
614         case table_style:
615                 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
616                         if (subcalls_table[i].call == tcp->scno) break;
617                 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
618                     tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
619                         tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
620                         for (i = 0; i < tcp->u_nargs; i++)
621                                 tcp->u_arg[i] = tcp->u_arg[i + 1];
622                 }
623                 break;
624 #endif /* FREEBSD */
625         }
626 }
627 #endif
628
629 struct tcb *tcp_last = NULL;
630
631 static int
632 internal_syscall(tcp)
633 struct tcb *tcp;
634 {
635         /*
636          * We must always trace a few critical system calls in order to
637          * correctly support following forks in the presence of tracing
638          * qualifiers.
639          */
640         switch (tcp->scno + NR_SYSCALL_BASE) {
641 #ifdef SYS_fork
642         case SYS_fork:
643 #endif
644 #ifdef SYS_vfork
645         case SYS_vfork:
646 #endif
647 #ifdef SYS_fork1
648         case SYS_fork1:
649 #endif
650 #ifdef SYS_forkall
651         case SYS_forkall:
652 #endif
653 #ifdef SYS_rfork1
654         case SYS_rfork1:
655 #endif
656 #ifdef SYS_rforkall
657         case SYS_rforkall:
658 #endif
659 #ifdef SYS_rfork
660         case SYS_rfork:
661 #endif
662                 internal_fork(tcp);
663                 break;
664 #ifdef SYS_clone
665         case SYS_clone:
666                 internal_clone(tcp);
667                 break;
668 #endif
669 #ifdef SYS_clone2
670         case SYS_clone2:
671                 internal_clone(tcp);
672                 break;
673 #endif
674 #ifdef SYS_execv
675         case SYS_execv:
676 #endif
677 #ifdef SYS_execve
678         case SYS_execve:
679 #endif
680 #ifdef SYS_rexecve
681         case SYS_rexecve:
682 #endif
683                 internal_exec(tcp);
684                 break;
685
686 #ifdef SYS_wait
687         case SYS_wait:
688 #endif
689 #ifdef SYS_wait4
690         case SYS_wait4:
691 #endif
692 #ifdef SYS32_wait4
693         case SYS32_wait4:
694 #endif
695 #ifdef SYS_waitpid
696         case SYS_waitpid:
697 #endif
698 #ifdef SYS_waitsys
699         case SYS_waitsys:
700 #endif
701                 internal_wait(tcp, 2);
702                 break;
703 #ifdef SYS_waitid
704         case SYS_waitid:
705                 internal_wait(tcp, 3);
706                 break;
707 #endif
708
709 #ifdef SYS_exit
710         case SYS_exit:
711 #endif
712 #ifdef SYS32_exit
713         case SYS32_exit:
714 #endif
715 #ifdef __NR_exit_group
716         case __NR_exit_group:
717 #endif
718 #ifdef IA64
719         case 252: /* IA-32 __NR_exit_group */
720 #endif
721                 internal_exit(tcp);
722                 break;
723         }
724         return 0;
725 }
726
727
728 #ifdef LINUX
729 #if defined (I386)
730         static long eax;
731 #elif defined (IA64)
732         long r8, r10, psr;
733         long ia32 = 0;
734 #elif defined (POWERPC)
735         static long result,flags;
736 #elif defined (M68K)
737         static int d0;
738 #elif defined (ARM)
739         static struct pt_regs regs;
740 #elif defined (ALPHA)
741         static long r0;
742         static long a3;
743 #elif defined (SPARC) || defined (SPARC64)
744         static struct regs regs;
745         static unsigned long trap;
746 #elif defined(MIPS)
747         static long a3;
748         static long r2;
749 #elif defined(S390) || defined(S390X)
750         static long gpr2;
751         static long pc;
752         static long syscall_mode;
753 #elif defined(HPPA)
754         static long r28;
755 #elif defined(SH)
756        static long r0;
757 #elif defined(SH64)
758        static long r9;
759 #elif defined(X86_64)
760        static long rax;
761 #endif
762 #endif /* LINUX */
763 #ifdef FREEBSD
764         struct reg regs;
765 #endif /* FREEBSD */
766
767 int
768 get_scno(tcp)
769 struct tcb *tcp;
770 {
771         long scno = 0;
772 #ifndef USE_PROCFS
773         int pid = tcp->pid;
774 #endif /* !PROCFS */
775
776 #ifdef LINUX
777 #if defined(S390) || defined(S390X)
778         if (tcp->flags & TCB_WAITEXECVE) {
779                 /*
780                  * When the execve system call completes successfully, the
781                  * new process still has -ENOSYS (old style) or __NR_execve
782                  * (new style) in gpr2.  We cannot recover the scno again
783                  * by disassembly, because the image that executed the
784                  * syscall is gone now.  Fortunately, we don't want it.  We
785                  * leave the flag set so that syscall_fixup can fake the
786                  * result.
787                  */
788                 if (tcp->flags & TCB_INSYSCALL)
789                         return 1;
790                 /*
791                  * This is the SIGTRAP after execve.  We cannot try to read
792                  * the system call here either.
793                  */
794                 tcp->flags &= ~TCB_WAITEXECVE;
795                 return 0;
796         }
797
798         if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
799                         return -1;
800
801         if (syscall_mode != -ENOSYS) {
802                 /*
803                  * Since kernel version 2.5.44 the scno gets passed in gpr2.
804                  */
805                 scno = syscall_mode;
806         } else {
807                 /*
808                  * Old style of "passing" the scno via the SVC instruction.
809                  */
810
811                 long opcode, offset_reg, tmp;
812                 void * svc_addr;
813                 int gpr_offset[16] = {PT_GPR0,  PT_GPR1,  PT_ORIGGPR2, PT_GPR3,
814                                       PT_GPR4,  PT_GPR5,  PT_GPR6,     PT_GPR7,
815                                       PT_GPR8,  PT_GPR9,  PT_GPR10,    PT_GPR11,
816                                       PT_GPR12, PT_GPR13, PT_GPR14,    PT_GPR15};
817
818                 if (upeek(pid, PT_PSWADDR, &pc) < 0)
819                         return -1;
820                 errno = 0;
821                 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
822                 if (errno) {
823                         perror("peektext(pc-oneword)");
824                         return -1;
825                 }
826
827                 /*
828                  *  We have to check if the SVC got executed directly or via an
829                  *  EXECUTE instruction. In case of EXECUTE it is necessary to do
830                  *  instruction decoding to derive the system call number.
831                  *  Unfortunately the opcode sizes of EXECUTE and SVC are differently,
832                  *  so that this doesn't work if a SVC opcode is part of an EXECUTE
833                  *  opcode. Since there is no way to find out the opcode size this
834                  *  is the best we can do...
835                  */
836
837                 if ((opcode & 0xff00) == 0x0a00) {
838                         /* SVC opcode */
839                         scno = opcode & 0xff;
840                 }
841                 else {
842                         /* SVC got executed by EXECUTE instruction */
843
844                         /*
845                          *  Do instruction decoding of EXECUTE. If you really want to
846                          *  understand this, read the Principles of Operations.
847                          */
848                         svc_addr = (void *) (opcode & 0xfff);
849
850                         tmp = 0;
851                         offset_reg = (opcode & 0x000f0000) >> 16;
852                         if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
853                                 return -1;
854                         svc_addr += tmp;
855
856                         tmp = 0;
857                         offset_reg = (opcode & 0x0000f000) >> 12;
858                         if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
859                                 return -1;
860                         svc_addr += tmp;
861
862                         scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
863                         if (errno)
864                                 return -1;
865 #if defined(S390X)
866                         scno >>= 48;
867 #else
868                         scno >>= 16;
869 #endif
870                         tmp = 0;
871                         offset_reg = (opcode & 0x00f00000) >> 20;
872                         if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
873                                 return -1;
874
875                         scno = (scno | tmp) & 0xff;
876                 }
877         }
878 #elif defined (POWERPC)
879         if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
880                 return -1;
881         if (!(tcp->flags & TCB_INSYSCALL)) {
882                 /* Check if we return from execve. */
883                 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
884                         tcp->flags &= ~TCB_WAITEXECVE;
885                         return 0;
886                 }
887         }
888 #elif defined (I386)
889         if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
890                 return -1;
891 #elif defined (X86_64)
892         if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
893                 return -1;
894
895         if (!(tcp->flags & TCB_INSYSCALL)) {
896                 static int currpers=-1;
897                 long val;
898
899                 /* Check CS register value. On x86-64 linux it is:
900                  *      0x33    for long mode (64 bit)
901                  *      0x23    for compatibility mode (32 bit)
902                  * It takes only one ptrace and thus doesn't need
903                  * to be cached.
904                  */
905                 if (upeek(pid, 8*CS, &val) < 0)
906                         return -1;
907                 switch(val)
908                 {
909                         case 0x23: currpers = 1; break;
910                         case 0x33: currpers = 0; break;
911                         default:
912                                 fprintf(stderr, "Unknown value CS=0x%02X while "
913                                          "detecting personality of process "
914                                          "PID=%d\n", (int)val, pid);
915                                 currpers = current_personality;
916                                 break;
917                 }
918 #if 0
919                 /* This version analyzes the opcode of a syscall instruction.
920                  * (int 0x80 on i386 vs. syscall on x86-64)
921                  * It works, but is too complicated.
922                  */
923                 unsigned long val, rip, i;
924
925                 if(upeek(pid, 8*RIP, &rip)<0)
926                         perror("upeek(RIP)");
927
928                 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
929                 rip-=2;
930                 errno = 0;
931
932                 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
933                 if (errno)
934                         printf("ptrace_peektext failed: %s\n",
935                                         strerror(errno));
936                 switch (call & 0xffff)
937                 {
938                         /* x86-64: syscall = 0x0f 0x05 */
939                         case 0x050f: currpers = 0; break;
940                         /* i386: int 0x80 = 0xcd 0x80 */
941                         case 0x80cd: currpers = 1; break;
942                         default:
943                                 currpers = current_personality;
944                                 fprintf(stderr,
945                                         "Unknown syscall opcode (0x%04X) while "
946                                         "detecting personality of process "
947                                         "PID=%d\n", (int)call, pid);
948                                 break;
949                 }
950 #endif
951                 if(currpers != current_personality)
952                 {
953                         char *names[]={"64 bit", "32 bit"};
954                         set_personality(currpers);
955                         printf("[ Process PID=%d runs in %s mode. ]\n",
956                                         pid, names[current_personality]);
957                 }
958         }
959 #elif defined(IA64)
960 #       define IA64_PSR_IS      ((long)1 << 34)
961         if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
962                 ia32 = (psr & IA64_PSR_IS) != 0;
963         if (!(tcp->flags & TCB_INSYSCALL)) {
964                 if (ia32) {
965                         if (upeek(pid, PT_R1, &scno) < 0)       /* orig eax */
966                                 return -1;
967                 } else {
968                         if (upeek (pid, PT_R15, &scno) < 0)
969                                 return -1;
970                 }
971                 /* Check if we return from execve. */
972                 if (tcp->flags & TCB_WAITEXECVE) {
973                         tcp->flags &= ~TCB_WAITEXECVE;
974                         return 0;
975                 }
976         } else {
977                 /* syscall in progress */
978                 if (upeek (pid, PT_R8, &r8) < 0)
979                         return -1;
980                 if (upeek (pid, PT_R10, &r10) < 0)
981                         return -1;
982         }
983 #elif defined (ARM)
984         /*
985          * Read complete register set in one go.
986          */
987         if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
988                 return -1;
989
990         /*
991          * We only need to grab the syscall number on syscall entry.
992          */
993         if (regs.ARM_ip == 0) {
994                 /*
995                  * Note: we only deal with only 32-bit CPUs here.
996                  */
997                 if (regs.ARM_cpsr & 0x20) {
998                         /*
999                          * Get the Thumb-mode system call number
1000                          */
1001                         scno = regs.ARM_r7;
1002                 } else {
1003                         /*
1004                          * Get the ARM-mode system call number
1005                          */
1006                         errno = 0;
1007                         scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1008                         if (errno)
1009                                 return -1;
1010
1011                         if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1012                                 tcp->flags &= ~TCB_WAITEXECVE;
1013                                 return 0;
1014                         }
1015
1016                         if ((scno & 0x0ff00000) != 0x0f900000) {
1017                                 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1018                                         scno);
1019                                 return -1;
1020                         }
1021
1022                         /*
1023                          * Fixup the syscall number
1024                          */
1025                         scno &= 0x000fffff;
1026                 }
1027
1028                 if (tcp->flags & TCB_INSYSCALL) {
1029                         fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1030                         tcp->flags &= ~TCB_INSYSCALL;
1031                 }
1032         } else {
1033                 if (!(tcp->flags & TCB_INSYSCALL)) {
1034                         fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1035                         tcp->flags |= TCB_INSYSCALL;
1036                 }
1037         }
1038 #elif defined (M68K)
1039         if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1040                 return -1;
1041 #elif defined (MIPS)
1042         if (upeek(pid, REG_A3, &a3) < 0)
1043                 return -1;
1044
1045         if(!(tcp->flags & TCB_INSYSCALL)) {
1046                 if (upeek(pid, REG_V0, &scno) < 0)
1047                         return -1;
1048
1049                 if (scno < 0 || scno > nsyscalls) {
1050                         if(a3 == 0 || a3 == -1) {
1051                                 if(debug)
1052                                         fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1053                                 return 0;
1054                         }
1055                 }
1056         } else {
1057                 if (upeek(pid, REG_V0, &r2) < 0)
1058                         return -1;
1059         }
1060 #elif defined (ALPHA)
1061         if (upeek(pid, REG_A3, &a3) < 0)
1062                 return -1;
1063
1064         if (!(tcp->flags & TCB_INSYSCALL)) {
1065                 if (upeek(pid, REG_R0, &scno) < 0)
1066                         return -1;
1067
1068                 /* Check if we return from execve. */
1069                 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1070                         tcp->flags &= ~TCB_WAITEXECVE;
1071                         return 0;
1072                 }
1073
1074                 /*
1075                  * Do some sanity checks to figure out if it's
1076                  * really a syscall entry
1077                  */
1078                 if (scno < 0 || scno > nsyscalls) {
1079                         if (a3 == 0 || a3 == -1) {
1080                                 if (debug)
1081                                         fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1082                                 return 0;
1083                         }
1084                 }
1085         }
1086         else {
1087                 if (upeek(pid, REG_R0, &r0) < 0)
1088                         return -1;
1089         }
1090 #elif defined (SPARC) || defined (SPARC64)
1091         /* Everything we need is in the current register set. */
1092         if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1093                 return -1;
1094
1095         /* If we are entering, then disassemble the syscall trap. */
1096         if (!(tcp->flags & TCB_INSYSCALL)) {
1097                 /* Retrieve the syscall trap instruction. */
1098                 errno = 0;
1099                 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
1100 #if defined(SPARC64)
1101                 trap >>= 32;
1102 #endif
1103                 if (errno)
1104                         return -1;
1105
1106                 /* Disassemble the trap to see what personality to use. */
1107                 switch (trap) {
1108                 case 0x91d02010:
1109                         /* Linux/SPARC syscall trap. */
1110                         set_personality(0);
1111                         break;
1112                 case 0x91d0206d:
1113                         /* Linux/SPARC64 syscall trap. */
1114                         set_personality(2);
1115                         break;
1116                 case 0x91d02000:
1117                         /* SunOS syscall trap. (pers 1) */
1118                         fprintf(stderr,"syscall: SunOS no support\n");
1119                         return -1;
1120                 case 0x91d02008:
1121                         /* Solaris 2.x syscall trap. (per 2) */
1122                         set_personality(1);
1123                         break;
1124                 case 0x91d02009:
1125                         /* NetBSD/FreeBSD syscall trap. */
1126                         fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1127                         return -1;
1128                 case 0x91d02027:
1129                         /* Solaris 2.x gettimeofday */
1130                         set_personality(1);
1131                         break;
1132                 default:
1133                         /* Unknown syscall trap. */
1134                         if(tcp->flags & TCB_WAITEXECVE) {
1135                                 tcp->flags &= ~TCB_WAITEXECVE;
1136                                 return 0;
1137                         }
1138 #if defined (SPARC64)
1139                         fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1140 #else
1141                         fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
1142 #endif
1143                         return -1;
1144                 }
1145
1146                 /* Extract the system call number from the registers. */
1147                 if (trap == 0x91d02027)
1148                         scno = 156;
1149                 else
1150                         scno = regs.r_g1;
1151                 if (scno == 0) {
1152                         scno = regs.r_o0;
1153                         memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
1154                 }
1155         }
1156 #elif defined(HPPA)
1157         if (upeek(pid, PT_GR20, &scno) < 0)
1158                 return -1;
1159         if (!(tcp->flags & TCB_INSYSCALL)) {
1160                 /* Check if we return from execve. */
1161                 if ((tcp->flags & TCB_WAITEXECVE)) {
1162                         tcp->flags &= ~TCB_WAITEXECVE;
1163                         return 0;
1164                 }
1165         }
1166 #elif defined(SH)
1167        /*
1168         * In the new syscall ABI, the system call number is in R3.
1169         */
1170        if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1171                return -1;
1172
1173        if (scno < 0) {
1174            /* Odd as it may seem, a glibc bug has been known to cause
1175               glibc to issue bogus negative syscall numbers.  So for
1176               our purposes, make strace print what it *should* have been */
1177            long correct_scno = (scno & 0xff);
1178            if (debug)
1179                fprintf(stderr,
1180                    "Detected glibc bug: bogus system call number = %ld, "
1181                    "correcting to %ld\n",
1182                    scno,
1183                    correct_scno);
1184            scno = correct_scno;
1185        }
1186
1187
1188        if (!(tcp->flags & TCB_INSYSCALL)) {
1189                /* Check if we return from execve. */
1190                if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1191                        tcp->flags &= ~TCB_WAITEXECVE;
1192                        return 0;
1193                }
1194        }
1195 #elif defined(SH64)
1196         if (upeek(pid, REG_SYSCALL, &scno) < 0)
1197                 return -1;
1198         scno &= 0xFFFF;
1199
1200         if (!(tcp->flags & TCB_INSYSCALL)) {
1201                 /* Check if we return from execve. */
1202                 if (tcp->flags & TCB_WAITEXECVE) {
1203                         tcp->flags &= ~TCB_WAITEXECVE;
1204                         return 0;
1205                 }
1206         }
1207 #endif /* SH64 */
1208 #endif /* LINUX */
1209 #ifdef SUNOS4
1210         if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1211                 return -1;
1212 #elif defined(SH)
1213         /* new syscall ABI returns result in R0 */
1214         if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1215                 return -1;
1216 #elif defined(SH64)
1217         /* ABI defines result returned in r9 */
1218         if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1219                 return -1;
1220
1221 #endif
1222 #ifdef USE_PROCFS
1223 #ifdef HAVE_PR_SYSCALL
1224         scno = tcp->status.PR_SYSCALL;
1225 #else /* !HAVE_PR_SYSCALL */
1226 #ifndef FREEBSD
1227         scno = tcp->status.PR_WHAT;
1228 #else /* FREEBSD */
1229         if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1230                 perror("pread");
1231                 return -1;
1232         }
1233         switch (regs.r_eax) {
1234         case SYS_syscall:
1235         case SYS___syscall:
1236                 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1237                 break;
1238         default:
1239                 scno = regs.r_eax;
1240                 break;
1241         }
1242 #endif /* FREEBSD */
1243 #endif /* !HAVE_PR_SYSCALL */
1244 #endif /* USE_PROCFS */
1245         if (!(tcp->flags & TCB_INSYSCALL))
1246                 tcp->scno = scno;
1247         return 1;
1248 }
1249
1250
1251 int
1252 syscall_fixup(tcp)
1253 struct tcb *tcp;
1254 {
1255 #ifndef USE_PROCFS
1256         int pid = tcp->pid;
1257 #else /* USE_PROCFS */
1258         int scno = tcp->scno;
1259
1260         if (!(tcp->flags & TCB_INSYSCALL)) {
1261                 if (tcp->status.PR_WHY != PR_SYSENTRY) {
1262                         if (
1263                             scno == SYS_fork
1264 #ifdef SYS_vfork
1265                             || scno == SYS_vfork
1266 #endif /* SYS_vfork */
1267 #ifdef SYS_fork1
1268                             || scno == SYS_fork1
1269 #endif /* SYS_fork1 */
1270 #ifdef SYS_forkall
1271                             || scno == SYS_forkall
1272 #endif /* SYS_forkall */
1273 #ifdef SYS_rfork1
1274                             || scno == SYS_rfork1
1275 #endif /* SYS_fork1 */
1276 #ifdef SYS_rforkall
1277                             || scno == SYS_rforkall
1278 #endif /* SYS_rforkall */
1279                             ) {
1280                                 /* We are returning in the child, fake it. */
1281                                 tcp->status.PR_WHY = PR_SYSENTRY;
1282                                 trace_syscall(tcp);
1283                                 tcp->status.PR_WHY = PR_SYSEXIT;
1284                         }
1285                         else {
1286                                 fprintf(stderr, "syscall: missing entry\n");
1287                                 tcp->flags |= TCB_INSYSCALL;
1288                         }
1289                 }
1290         }
1291         else {
1292                 if (tcp->status.PR_WHY != PR_SYSEXIT) {
1293                         fprintf(stderr, "syscall: missing exit\n");
1294                         tcp->flags &= ~TCB_INSYSCALL;
1295                 }
1296         }
1297 #endif /* USE_PROCFS */
1298 #ifdef SUNOS4
1299         if (!(tcp->flags & TCB_INSYSCALL)) {
1300                 if (scno == 0) {
1301                         fprintf(stderr, "syscall: missing entry\n");
1302                         tcp->flags |= TCB_INSYSCALL;
1303                 }
1304         }
1305         else {
1306                 if (scno != 0) {
1307                         if (debug) {
1308                                 /*
1309                                  * This happens when a signal handler
1310                                  * for a signal which interrupted a
1311                                  * a system call makes another system call.
1312                                  */
1313                                 fprintf(stderr, "syscall: missing exit\n");
1314                         }
1315                         tcp->flags &= ~TCB_INSYSCALL;
1316                 }
1317         }
1318 #endif /* SUNOS4 */
1319 #ifdef LINUX
1320 #if defined (I386)
1321         if (upeek(pid, 4*EAX, &eax) < 0)
1322                 return -1;
1323         if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1324                 if (debug)
1325                         fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1326                 return 0;
1327         }
1328 #elif defined (X86_64)
1329         if (upeek(pid, 8*RAX, &rax) < 0)
1330                 return -1;
1331         if (current_personality == 1)
1332                 rax = (long int)(int)rax; /* sign extend from 32 bits */
1333         if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1334                 if (debug)
1335                         fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1336                 return 0;
1337         }
1338 #elif defined (S390) || defined (S390X)
1339         if (upeek(pid, PT_GPR2, &gpr2) < 0)
1340                 return -1;
1341         if (syscall_mode != -ENOSYS)
1342                 syscall_mode = tcp->scno;
1343         if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
1344                 if (debug)
1345                         fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1346                 return 0;
1347         }
1348         else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1349                   == (TCB_INSYSCALL|TCB_WAITEXECVE))
1350                  && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1351                 /*
1352                  * Fake a return value of zero.  We leave the TCB_WAITEXECVE
1353                  * flag set for the post-execve SIGTRAP to see and reset.
1354                  */
1355                 gpr2 = 0;
1356         }
1357 #elif defined (POWERPC)
1358 # define SO_MASK 0x10000000
1359         if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1360                 return -1;
1361         if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
1362                 return -1;
1363         if (flags & SO_MASK)
1364                 result = -result;
1365 #elif defined (M68K)
1366         if (upeek(pid, 4*PT_D0, &d0) < 0)
1367                 return -1;
1368         if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1369                 if (debug)
1370                         fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1371                 return 0;
1372         }
1373 #elif defined (ARM)
1374         /*
1375          * Nothing required
1376          */
1377 #elif defined (HPPA)
1378         if (upeek(pid, PT_GR28, &r28) < 0)
1379                 return -1;
1380 #elif defined(IA64)
1381         if (upeek(pid, PT_R10, &r10) < 0)
1382                 return -1;
1383         if (upeek(pid, PT_R8, &r8) < 0)
1384                 return -1;
1385         if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1386                 if (debug)
1387                         fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1388                 return 0;
1389         }
1390 #endif
1391 #endif /* LINUX */
1392         return 1;
1393 }
1394
1395 int
1396 get_error(tcp)
1397 struct tcb *tcp;
1398 {
1399         int u_error = 0;
1400 #ifdef LINUX
1401 #if defined(S390) || defined(S390X)
1402                 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1403                         tcp->u_rval = -1;
1404                         u_error = -gpr2;
1405                 }
1406                 else {
1407                         tcp->u_rval = gpr2;
1408                         u_error = 0;
1409                 }
1410 #else /* !S390 && !S390X */
1411 #ifdef I386
1412                 if (eax < 0 && -eax < nerrnos) {
1413                         tcp->u_rval = -1;
1414                         u_error = -eax;
1415                 }
1416                 else {
1417                         tcp->u_rval = eax;
1418                         u_error = 0;
1419                 }
1420 #else /* !I386 */
1421 #ifdef X86_64
1422                 if (rax < 0 && -rax < nerrnos) {
1423                         tcp->u_rval = -1;
1424                         u_error = -rax;
1425                 }
1426                 else {
1427                         tcp->u_rval = rax;
1428                         u_error = 0;
1429                 }
1430 #else
1431 #ifdef IA64
1432                 if (ia32) {
1433                         int err;
1434
1435                         err = (int)r8;
1436                         if (err < 0 && -err < nerrnos) {
1437                                 tcp->u_rval = -1;
1438                                 u_error = -err;
1439                         }
1440                         else {
1441                                 tcp->u_rval = err;
1442                                 u_error = 0;
1443                         }
1444                 } else {
1445                         if (r10) {
1446                                 tcp->u_rval = -1;
1447                                 u_error = r8;
1448                         } else {
1449                                 tcp->u_rval = r8;
1450                                 u_error = 0;
1451                         }
1452                 }
1453 #else /* !IA64 */
1454 #ifdef MIPS
1455                 if (a3) {
1456                         tcp->u_rval = -1;
1457                         u_error = r2;
1458                 } else {
1459                         tcp->u_rval = r2;
1460                         u_error = 0;
1461                 }
1462 #else
1463 #ifdef POWERPC
1464                 if (result && (unsigned long) -result < nerrnos) {
1465                         tcp->u_rval = -1;
1466                         u_error = -result;
1467                 }
1468                 else {
1469                         tcp->u_rval = result;
1470                         u_error = 0;
1471                 }
1472 #else /* !POWERPC */
1473 #ifdef M68K
1474                 if (d0 && (unsigned) -d0 < nerrnos) {
1475                         tcp->u_rval = -1;
1476                         u_error = -d0;
1477                 }
1478                 else {
1479                         tcp->u_rval = d0;
1480                         u_error = 0;
1481                 }
1482 #else /* !M68K */
1483 #ifdef ARM
1484                 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
1485                         tcp->u_rval = -1;
1486                         u_error = -regs.ARM_r0;
1487                 }
1488                 else {
1489                         tcp->u_rval = regs.ARM_r0;
1490                         u_error = 0;
1491                 }
1492 #else /* !ARM */
1493 #ifdef ALPHA
1494                 if (a3) {
1495                         tcp->u_rval = -1;
1496                         u_error = r0;
1497                 }
1498                 else {
1499                         tcp->u_rval = r0;
1500                         u_error = 0;
1501                 }
1502 #else /* !ALPHA */
1503 #ifdef SPARC
1504                 if (regs.r_psr & PSR_C) {
1505                         tcp->u_rval = -1;
1506                         u_error = regs.r_o0;
1507                 }
1508                 else {
1509                         tcp->u_rval = regs.r_o0;
1510                         u_error = 0;
1511                 }
1512 #else /* !SPARC */
1513 #ifdef SPARC64
1514                 if (regs.r_tstate & 0x1100000000UL) {
1515                         tcp->u_rval = -1;
1516                         u_error = regs.r_o0;
1517                 }
1518                 else {
1519                         tcp->u_rval = regs.r_o0;
1520                         u_error = 0;
1521                 }
1522 #else /* !SPARC64 */
1523 #ifdef HPPA
1524                 if (r28 && (unsigned) -r28 < nerrnos) {
1525                         tcp->u_rval = -1;
1526                         u_error = -r28;
1527                 }
1528                 else {
1529                         tcp->u_rval = r28;
1530                         u_error = 0;
1531                 }
1532 #else
1533 #ifdef SH
1534                /* interpret R0 as return value or error number */
1535                if (r0 && (unsigned) -r0 < nerrnos) {
1536                        tcp->u_rval = -1;
1537                        u_error = -r0;
1538                }
1539                else {
1540                        tcp->u_rval = r0;
1541                        u_error = 0;
1542                }
1543 #else
1544 #ifdef SH64
1545                 /* interpret result as return value or error number */
1546                 if (r9 && (unsigned) -r9 < nerrnos) {
1547                         tcp->u_rval = -1;
1548                         u_error = -r9;
1549                 }
1550                 else {
1551                         tcp->u_rval = r9;
1552                         u_error = 0;
1553                 }
1554 #endif /* SH64 */
1555 #endif /* SH */
1556 #endif /* HPPA */
1557 #endif /* SPARC */
1558 #endif /* SPARC64 */
1559 #endif /* ALPHA */
1560 #endif /* ARM */
1561 #endif /* M68K */
1562 #endif /* POWERPC */
1563 #endif /* MIPS */
1564 #endif /* IA64 */
1565 #endif /* X86_64 */
1566 #endif /* I386 */
1567 #endif /* S390 || S390X */
1568 #endif /* LINUX */
1569 #ifdef SUNOS4
1570                 /* get error code from user struct */
1571                 if (upeek(pid, uoff(u_error), &u_error) < 0)
1572                         return -1;
1573                 u_error >>= 24; /* u_error is a char */
1574
1575                 /* get system call return value */
1576                 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1577                         return -1;
1578 #endif /* SUNOS4 */
1579 #ifdef SVR4
1580 #ifdef SPARC
1581                 /* Judicious guessing goes a long way. */
1582                 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1583                         tcp->u_rval = -1;
1584                         u_error = tcp->status.pr_reg[R_O0];
1585                 }
1586                 else {
1587                         tcp->u_rval = tcp->status.pr_reg[R_O0];
1588                         u_error = 0;
1589                 }
1590 #endif /* SPARC */
1591 #ifdef I386
1592                 /* Wanna know how to kill an hour single-stepping? */
1593                 if (tcp->status.PR_REG[EFL] & 0x1) {
1594                         tcp->u_rval = -1;
1595                         u_error = tcp->status.PR_REG[EAX];
1596                 }
1597                 else {
1598                         tcp->u_rval = tcp->status.PR_REG[EAX];
1599 #ifdef HAVE_LONG_LONG
1600                         tcp->u_lrval =
1601                                 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1602                                 tcp->status.PR_REG[EAX];
1603 #endif
1604                         u_error = 0;
1605                 }
1606 #endif /* I386 */
1607 #ifdef X86_64
1608                 /* Wanna know how to kill an hour single-stepping? */
1609                 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1610                         tcp->u_rval = -1;
1611                         u_error = tcp->status.PR_REG[RAX];
1612                 }
1613                 else {
1614                         tcp->u_rval = tcp->status.PR_REG[RAX];
1615                         u_error = 0;
1616                 }
1617 #endif /* X86_64 */
1618 #ifdef MIPS
1619                 if (tcp->status.pr_reg[CTX_A3]) {
1620                         tcp->u_rval = -1;
1621                         u_error = tcp->status.pr_reg[CTX_V0];
1622                 }
1623                 else {
1624                         tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1625                         u_error = 0;
1626                 }
1627 #endif /* MIPS */
1628 #endif /* SVR4 */
1629 #ifdef FREEBSD
1630                 if (regs.r_eflags & PSL_C) {
1631                         tcp->u_rval = -1;
1632                         u_error = regs.r_eax;
1633                 } else {
1634                         tcp->u_rval = regs.r_eax;
1635                         tcp->u_lrval =
1636                           ((unsigned long long) regs.r_edx << 32) +  regs.r_eax;
1637                         u_error = 0;
1638                 }
1639 #endif /* FREEBSD */
1640         tcp->u_error = u_error;
1641         return 1;
1642 }
1643
1644 int
1645 force_result(tcp, error, rval)
1646         struct tcb *tcp;
1647         int error;
1648         long rval;
1649 {
1650 #ifdef LINUX
1651 #if defined(S390) || defined(S390X)
1652         gpr2 = error ? -error : rval;
1653         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1654                 return -1;
1655 #else /* !S390 && !S390X */
1656 #ifdef I386
1657         eax = error ? -error : rval;
1658         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1659                 return -1;
1660 #else /* !I386 */
1661 #ifdef X86_64
1662         rax = error ? -error : rval;
1663         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
1664                 return -1;
1665 #else
1666 #ifdef IA64
1667         if (ia32) {
1668                 r8 = error ? -error : rval;
1669                 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1670                         return -1;
1671         }
1672         else {
1673                 if (error) {
1674                         r8 = error;
1675                         r10 = -1;
1676                 }
1677                 else {
1678                         r8 = rval;
1679                         r10 = 0;
1680                 }
1681                 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1682                     ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1683                         return -1;
1684         }
1685 #else /* !IA64 */
1686 #ifdef MIPS
1687         if (error) {
1688                 r2 = error;
1689                 a3 = -1;
1690         }
1691         else {
1692                 r2 = rval;
1693                 a3 = 0;
1694         }
1695         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1696             ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1697                 return -1;
1698 #else
1699 #ifdef POWERPC
1700         if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1701                 return -1;
1702         if (error) {
1703                 flags |= SO_MASK;
1704                 result = error;
1705         }
1706         else {
1707                 flags &= ~SO_MASK;
1708                 result = rval;
1709         }
1710         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1711             ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
1712                 return -1;
1713 #else /* !POWERPC */
1714 #ifdef M68K
1715         d0 = error ? -error : rval;
1716         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1717                 return -1;
1718 #else /* !M68K */
1719 #ifdef ARM
1720        regs.ARM_r0 = error ? -error : rval;
1721        if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
1722                 return -1;
1723 #else /* !ARM */
1724 #ifdef ALPHA
1725         if (error) {
1726                 a3 = -1;
1727                 r0 = error;
1728         }
1729         else {
1730                 a3 = 0;
1731                 r0 = rval;
1732         }
1733         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1734             ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1735                 return -1;
1736 #else /* !ALPHA */
1737 #ifdef SPARC
1738         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1739                 return -1;
1740         if (error) {
1741                 regs.r_psr |= PSR_C;
1742                 regs.r_o0 = error;
1743         }
1744         else {
1745                 regs.r_psr &= ~PSR_C;
1746                 regs.r_o0 = rval;
1747         }
1748         if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1749                 return -1;
1750 #else /* !SPARC */
1751 #ifdef SPARC64
1752         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1753                 return -1;
1754         if (error) {
1755                 regs.r_tstate |= 0x1100000000UL;
1756                 regs.r_o0 = error;
1757         }
1758         else {
1759                 regs.r_tstate &= ~0x1100000000UL;
1760                 regs.r_o0 = rval;
1761         }
1762         if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1763                 return -1;
1764 #else /* !SPARC64 */
1765 #ifdef HPPA
1766         r28 = error ? -error : rval;
1767         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1768                 return -1;
1769 #else
1770 #ifdef SH
1771         r0 = error ? -error : rval;
1772         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1773                 return -1;
1774 #else
1775 #ifdef SH64
1776         r9 = error ? -error : rval;
1777         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1778                 return -1;
1779 #endif /* SH64 */
1780 #endif /* SH */
1781 #endif /* HPPA */
1782 #endif /* SPARC */
1783 #endif /* SPARC64 */
1784 #endif /* ALPHA */
1785 #endif /* ARM */
1786 #endif /* M68K */
1787 #endif /* POWERPC */
1788 #endif /* MIPS */
1789 #endif /* IA64 */
1790 #endif /* X86_64 */
1791 #endif /* I386 */
1792 #endif /* S390 || S390X */
1793 #endif /* LINUX */
1794 #ifdef SUNOS4
1795         if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1796                    error << 24) < 0 ||
1797             ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1798                 return -1;
1799 #endif /* SUNOS4 */
1800 #ifdef SVR4
1801         /* XXX no clue */
1802         return -1;
1803 #endif /* SVR4 */
1804 #ifdef FREEBSD
1805         if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1806                 perror("pread");
1807                 return -1;
1808         }
1809         if (error) {
1810                 regs.r_eflags |= PSL_C;
1811                 regs.r_eax = error;
1812         }
1813         else {
1814                 regs.r_eflags &= ~PSL_C;
1815                 regs.r_eax = rval;
1816         }
1817         if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1818                 perror("pwrite");
1819                 return -1;
1820         }
1821 #endif /* FREEBSD */
1822
1823         /* All branches reach here on success (only).  */
1824         tcp->u_error = error;
1825         tcp->u_rval = rval;
1826         return 0;
1827 }
1828
1829 int syscall_enter(tcp)
1830 struct tcb *tcp;
1831 {
1832 #ifndef USE_PROCFS
1833         int pid = tcp->pid;
1834 #endif /* !USE_PROCFS */
1835 #ifdef LINUX
1836 #if defined(S390) || defined(S390X)
1837         {
1838                 int i;
1839                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1840                         tcp->u_nargs = sysent[tcp->scno].nargs;
1841                 else
1842                         tcp->u_nargs = MAX_ARGS;
1843                 for (i = 0; i < tcp->u_nargs; i++) {
1844                         if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
1845                                 return -1;
1846                 }
1847         }
1848 #elif defined (ALPHA)
1849         {
1850                 int i;
1851                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1852                         tcp->u_nargs = sysent[tcp->scno].nargs;
1853                 else
1854                         tcp->u_nargs = MAX_ARGS;
1855                 for (i = 0; i < tcp->u_nargs; i++) {
1856                         /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1857                          * for scno somewhere above here!
1858                          */
1859                         if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1860                                 return -1;
1861                 }
1862         }
1863 #elif defined (IA64)
1864         {
1865                 if (!ia32) {
1866                         unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1867                         /* be backwards compatible with kernel < 2.4.4... */
1868 #                       ifndef PT_RBS_END
1869 #                         define PT_RBS_END     PT_AR_BSP
1870 #                       endif
1871
1872                         if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
1873                                 return -1;
1874                         if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1875                                 return -1;
1876
1877                         sof = (cfm >> 0) & 0x7f;
1878                         sol = (cfm >> 7) & 0x7f;
1879                         out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1880
1881                         if (tcp->scno >= 0 && tcp->scno < nsyscalls
1882                             && sysent[tcp->scno].nargs != -1)
1883                                 tcp->u_nargs = sysent[tcp->scno].nargs;
1884                         else
1885                                 tcp->u_nargs = MAX_ARGS;
1886                         for (i = 0; i < tcp->u_nargs; ++i) {
1887                                 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1888                                            sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1889                                         return -1;
1890                         }
1891                 } else {
1892                         int i;
1893
1894                         if (/* EBX = out0 */
1895                             upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1896                             /* ECX = out1 */
1897                             || upeek(pid, PT_R9,  (long *) &tcp->u_arg[1]) < 0
1898                             /* EDX = out2 */
1899                             || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1900                             /* ESI = out3 */
1901                             || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1902                             /* EDI = out4 */
1903                             || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1904                             /* EBP = out5 */
1905                             || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1906                                 return -1;
1907
1908                         for (i = 0; i < 6; ++i)
1909                                 /* truncate away IVE sign-extension */
1910                                 tcp->u_arg[i] &= 0xffffffff;
1911
1912                         if (tcp->scno >= 0 && tcp->scno < nsyscalls
1913                             && sysent[tcp->scno].nargs != -1)
1914                                 tcp->u_nargs = sysent[tcp->scno].nargs;
1915                         else
1916                                 tcp->u_nargs = 5;
1917                 }
1918         }
1919 #elif defined (MIPS)
1920         {
1921                 long sp;
1922                 int i, nargs;
1923
1924                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1925                         nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
1926                 else
1927                         nargs = tcp->u_nargs = MAX_ARGS;
1928                 if(nargs > 4) {
1929                         if(upeek(pid, REG_SP, &sp) < 0)
1930                                 return -1;
1931                         for(i = 0; i < 4; i++) {
1932                                 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
1933                                         return -1;
1934                         }
1935                         umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
1936                                (char *)(tcp->u_arg + 4));
1937                 } else {
1938                         for(i = 0; i < nargs; i++) {
1939                                 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
1940                                         return -1;
1941                         }
1942                 }
1943         }
1944 #elif defined (POWERPC)
1945 #ifndef PT_ORIG_R3
1946 #define PT_ORIG_R3 34
1947 #endif
1948         {
1949                 int i;
1950                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1951                         tcp->u_nargs = sysent[tcp->scno].nargs;
1952                 else
1953                         tcp->u_nargs = MAX_ARGS;
1954                 for (i = 0; i < tcp->u_nargs; i++) {
1955                         if (upeek(pid, (i==0) ?
1956                                 (sizeof(unsigned long)*PT_ORIG_R3) :
1957                                 ((i+PT_R3)*sizeof(unsigned long)),
1958                                         &tcp->u_arg[i]) < 0)
1959                                 return -1;
1960                 }
1961         }
1962 #elif defined (SPARC) || defined (SPARC64)
1963         {
1964                 int i;
1965
1966                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1967                         tcp->u_nargs = sysent[tcp->scno].nargs;
1968                 else
1969                         tcp->u_nargs = MAX_ARGS;
1970                 for (i = 0; i < tcp->u_nargs; i++)
1971                         tcp->u_arg[i] = *((&regs.r_o0) + i);
1972         }
1973 #elif defined (HPPA)
1974         {
1975                 int i;
1976
1977                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1978                         tcp->u_nargs = sysent[tcp->scno].nargs;
1979                 else
1980                         tcp->u_nargs = MAX_ARGS;
1981                 for (i = 0; i < tcp->u_nargs; i++) {
1982                         if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1983                                 return -1;
1984                 }
1985         }
1986 #elif defined(ARM)
1987         {
1988                 int i;
1989
1990                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1991                         tcp->u_nargs = sysent[tcp->scno].nargs;
1992                 else
1993                         tcp->u_nargs = MAX_ARGS;
1994                 for (i = 0; i < tcp->u_nargs; i++)
1995                         tcp->u_arg[i] = regs.uregs[i];
1996         }
1997 #elif defined(SH)
1998        {
1999                int i;
2000                static int syscall_regs[] = {
2001                    REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2002                    REG_REG0, REG_REG0+1, REG_REG0+2
2003                    };
2004
2005                tcp->u_nargs = sysent[tcp->scno].nargs;
2006                for (i = 0; i < tcp->u_nargs; i++) {
2007                        if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2008                                return -1;
2009                }
2010         }
2011 #elif defined(SH64)
2012         {
2013                 int i;
2014                 /* Registers used by SH5 Linux system calls for parameters */
2015                 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2016
2017                 /*
2018                  * TODO: should also check that the number of arguments encoded
2019                  *       in the trap number matches the number strace expects.
2020                  */
2021                 /*
2022                     assert(sysent[tcp->scno].nargs <
2023                         sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2024                  */
2025
2026                 tcp->u_nargs = sysent[tcp->scno].nargs;
2027                 for (i = 0; i < tcp->u_nargs; i++) {
2028                         if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2029                                 return -1;
2030                 }
2031         }
2032
2033 #elif defined(X86_64)
2034         {
2035                 int i;
2036                 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2037                         {RDI,RSI,RDX,R10,R8,R9},        /* x86-64 ABI */
2038                         {RBX,RCX,RDX,RDX,RSI,RDI,RBP}   /* i386 ABI */
2039                 };
2040
2041                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2042                         tcp->u_nargs = sysent[tcp->scno].nargs;
2043                 else
2044                         tcp->u_nargs = MAX_ARGS;
2045                 for (i = 0; i < tcp->u_nargs; i++) {
2046                         if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2047                                 return -1;
2048                 }
2049         }
2050 #else /* Other architecture (like i386) (32bits specific) */
2051         {
2052                 int i;
2053                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2054                         tcp->u_nargs = sysent[tcp->scno].nargs;
2055                 else
2056                         tcp->u_nargs = MAX_ARGS;
2057                 for (i = 0; i < tcp->u_nargs; i++) {
2058                         if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2059                                 return -1;
2060                 }
2061         }
2062 #endif
2063 #endif /* LINUX */
2064 #ifdef SUNOS4
2065         {
2066                 int i;
2067                 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2068                         tcp->u_nargs = sysent[tcp->scno].nargs;
2069                 else
2070                         tcp->u_nargs = MAX_ARGS;
2071                 for (i = 0; i < tcp->u_nargs; i++) {
2072                         struct user *u;
2073
2074                         if (upeek(pid, uoff(u_arg[0]) +
2075                             (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2076                                 return -1;
2077                 }
2078         }
2079 #endif /* SUNOS4 */
2080 #ifdef SVR4
2081 #ifdef MIPS
2082         /*
2083          * SGI is broken: even though it has pr_sysarg, it doesn't
2084          * set them on system call entry.  Get a clue.
2085          */
2086         if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2087                 tcp->u_nargs = sysent[tcp->scno].nargs;
2088         else
2089                 tcp->u_nargs = tcp->status.pr_nsysarg;
2090         if (tcp->u_nargs > 4) {
2091                 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2092                         4*sizeof(tcp->u_arg[0]));
2093                 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2094                         (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2095         }
2096         else {
2097                 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2098                         tcp->u_nargs*sizeof(tcp->u_arg[0]));
2099         }
2100 #elif UNIXWARE >= 2
2101         /*
2102          * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2103          */
2104         if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2105                 tcp->u_nargs = sysent[tcp->scno].nargs;
2106         else
2107                 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2108         umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2109                 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2110 #elif defined (HAVE_PR_SYSCALL)
2111         if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2112                 tcp->u_nargs = sysent[tcp->scno].nargs;
2113         else
2114                 tcp->u_nargs = tcp->status.pr_nsysarg;
2115         {
2116                 int i;
2117                 for (i = 0; i < tcp->u_nargs; i++)
2118                         tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2119         }
2120 #elif defined (I386)
2121         if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2122                 tcp->u_nargs = sysent[tcp->scno].nargs;
2123         else
2124                 tcp->u_nargs = 5;
2125         umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2126                 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2127 #else
2128         I DONT KNOW WHAT TO DO
2129 #endif /* !HAVE_PR_SYSCALL */
2130 #endif /* SVR4 */
2131 #ifdef FREEBSD
2132         if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2133             sysent[tcp->scno].nargs > tcp->status.val)
2134                 tcp->u_nargs = sysent[tcp->scno].nargs;
2135         else
2136                 tcp->u_nargs = tcp->status.val;
2137         if (tcp->u_nargs < 0)
2138                 tcp->u_nargs = 0;
2139         if (tcp->u_nargs > MAX_ARGS)
2140                 tcp->u_nargs = MAX_ARGS;
2141         switch(regs.r_eax) {
2142         case SYS___syscall:
2143                 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2144                       regs.r_esp + sizeof(int) + sizeof(quad_t));
2145           break;
2146         case SYS_syscall:
2147                 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2148                       regs.r_esp + 2 * sizeof(int));
2149           break;
2150         default:
2151                 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2152                       regs.r_esp + sizeof(int));
2153           break;
2154         }
2155 #endif /* FREEBSD */
2156         return 1;
2157 }
2158
2159 int
2160 trace_syscall(tcp)
2161 struct tcb *tcp;
2162 {
2163         int sys_res;
2164         struct timeval tv;
2165         int res;
2166
2167         /* Measure the exit time as early as possible to avoid errors. */
2168         if (dtime && (tcp->flags & TCB_INSYSCALL))
2169                 gettimeofday(&tv, NULL);
2170
2171         res = get_scno(tcp);
2172         if (res != 1)
2173                 return res;
2174
2175         res = syscall_fixup(tcp);
2176         if (res != 1)
2177                 return res;
2178
2179         if (tcp->flags & TCB_INSYSCALL) {
2180                 long u_error;
2181                 res = get_error(tcp);
2182                 if (res != 1)
2183                         return res;
2184
2185                 internal_syscall(tcp);
2186                 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2187                     !(qual_flags[tcp->scno] & QUAL_TRACE)) {
2188                         tcp->flags &= ~TCB_INSYSCALL;
2189                         return 0;
2190                 }
2191
2192                 if (tcp->flags & TCB_REPRINT) {
2193                         printleader(tcp);
2194                         tprintf("<... ");
2195                         if (tcp->scno >= nsyscalls || tcp->scno < 0)
2196                                 tprintf("syscall_%lu", tcp->scno);
2197                         else
2198                                 tprintf("%s", sysent[tcp->scno].sys_name);
2199                         tprintf(" resumed> ");
2200                 }
2201
2202                 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
2203                         call_count[tcp->scno]++;
2204                         if (tcp->u_error)
2205                                 error_count[tcp->scno]++;
2206                         tv_sub(&tv, &tv, &tcp->etime);
2207 #ifdef LINUX
2208                         if (tv_cmp(&tv, &tcp->dtime) > 0) {
2209                                 static struct timeval one_tick;
2210                                 if (one_tick.tv_usec == 0) {
2211                                         /* Initialize it.  */
2212                                         struct itimerval it;
2213                                         memset(&it, 0, sizeof it);
2214                                         it.it_interval.tv_usec = 1;
2215                                         setitimer(ITIMER_REAL, &it, NULL);
2216                                         getitimer(ITIMER_REAL, &it);
2217                                         one_tick = it.it_interval;
2218                                 }
2219
2220                                 if (tv_nz(&tcp->dtime))
2221                                         tv = tcp->dtime;
2222                                 else if (tv_cmp(&tv, &one_tick) > 0) {
2223                                         if (tv_cmp(&shortest, &one_tick) < 0)
2224                                                 tv = shortest;
2225                                         else
2226                                                 tv = one_tick;
2227                                 }
2228                         }
2229 #endif /* LINUX */
2230                         if (tv_cmp(&tv, &shortest) < 0)
2231                                 shortest = tv;
2232                         tv_add(&tv_count[tcp->scno],
2233                                 &tv_count[tcp->scno], &tv);
2234                         tcp->flags &= ~TCB_INSYSCALL;
2235                         return 0;
2236                 }
2237
2238                 if (tcp->scno >= nsyscalls || tcp->scno < 0
2239                     || (qual_flags[tcp->scno] & QUAL_RAW))
2240                         sys_res = printargs(tcp);
2241                 else {
2242                         if (not_failing_only && tcp->u_error)
2243                                 return 0;       /* ignore failed syscalls */
2244                         sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2245                 }
2246                 u_error = tcp->u_error;
2247                 tprintf(") ");
2248                 tabto(acolumn);
2249                 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2250                     qual_flags[tcp->scno] & QUAL_RAW) {
2251                         if (u_error)
2252                                 tprintf("= -1 (errno %ld)", u_error);
2253                         else
2254                                 tprintf("= %#lx", tcp->u_rval);
2255                 }
2256                 else if (!(sys_res & RVAL_NONE) && u_error) {
2257                         switch (u_error) {
2258 #ifdef LINUX
2259                         case ERESTARTSYS:
2260                                 tprintf("= ? ERESTARTSYS (To be restarted)");
2261                                 break;
2262                         case ERESTARTNOINTR:
2263                                 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2264                                 break;
2265                         case ERESTARTNOHAND:
2266                                 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2267                                 break;
2268                         case ERESTART_RESTARTBLOCK:
2269                                 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2270                                 break;
2271 #endif /* LINUX */
2272                         default:
2273                                 tprintf("= -1 ");
2274                                 if (u_error < 0)
2275                                         tprintf("E??? (errno %ld)", u_error);
2276                                 else if (u_error < nerrnos)
2277                                         tprintf("%s (%s)", errnoent[u_error],
2278                                                 strerror(u_error));
2279                                 else
2280                                         tprintf("ERRNO_%ld (%s)", u_error,
2281                                                 strerror(u_error));
2282                                 break;
2283                         }
2284                 }
2285                 else {
2286                         if (sys_res & RVAL_NONE)
2287                                 tprintf("= ?");
2288                         else {
2289                                 switch (sys_res & RVAL_MASK) {
2290                                 case RVAL_HEX:
2291                                         tprintf("= %#lx", tcp->u_rval);
2292                                         break;
2293                                 case RVAL_OCTAL:
2294                                         tprintf("= %#lo", tcp->u_rval);
2295                                         break;
2296                                 case RVAL_UDECIMAL:
2297                                         tprintf("= %lu", tcp->u_rval);
2298                                         break;
2299                                 case RVAL_DECIMAL:
2300                                         tprintf("= %ld", tcp->u_rval);
2301                                         break;
2302 #ifdef HAVE_LONG_LONG
2303                                 case RVAL_LHEX:
2304                                         tprintf("= %#llx", tcp->u_lrval);
2305                                         break;
2306                                 case RVAL_LOCTAL:
2307                                         tprintf("= %#llo", tcp->u_lrval);
2308                                         break;
2309                                 case RVAL_LUDECIMAL:
2310                                         tprintf("= %llu", tcp->u_lrval);
2311                                         break;
2312                                 case RVAL_LDECIMAL:
2313                                         tprintf("= %lld", tcp->u_lrval);
2314                                         break;
2315 #endif
2316                                 default:
2317                                         fprintf(stderr,
2318                                                 "invalid rval format\n");
2319                                         break;
2320                                 }
2321                         }
2322                         if ((sys_res & RVAL_STR) && tcp->auxstr)
2323                                 tprintf(" (%s)", tcp->auxstr);
2324                 }
2325                 if (dtime) {
2326                         tv_sub(&tv, &tv, &tcp->etime);
2327                         tprintf(" <%ld.%06ld>",
2328                                 (long) tv.tv_sec, (long) tv.tv_usec);
2329                 }
2330                 printtrailer(tcp);
2331
2332                 dumpio(tcp);
2333                 if (fflush(tcp->outf) == EOF)
2334                         return -1;
2335                 tcp->flags &= ~TCB_INSYSCALL;
2336                 return 0;
2337         }
2338
2339         /* Entering system call */
2340         res = syscall_enter(tcp);
2341         if (res != 1)
2342                 return res;
2343
2344         switch (tcp->scno + NR_SYSCALL_BASE) {
2345 #ifdef LINUX
2346 #if !defined (ALPHA) && !defined(SPARC) && !defined(SPARC64) && !defined(MIPS) && !defined(HPPA) && !defined(X86_64)
2347         case SYS_socketcall:
2348                 decode_subcall(tcp, SYS_socket_subcall,
2349                         SYS_socket_nsubcalls, deref_style);
2350                 break;
2351         case SYS_ipc:
2352                 decode_subcall(tcp, SYS_ipc_subcall,
2353                         SYS_ipc_nsubcalls, shift_style);
2354                 break;
2355 #endif /* !ALPHA && !MIPS && !SPARC && !SPARC64 && !HPPA && !X86_64 */
2356 #if defined (SPARC) || defined (SPARC64)
2357         case SYS_socketcall:
2358                 sparc_socket_decode (tcp);
2359                 break;
2360 #endif
2361 #endif /* LINUX */
2362 #ifdef SVR4
2363 #ifdef SYS_pgrpsys_subcall
2364         case SYS_pgrpsys:
2365                 decode_subcall(tcp, SYS_pgrpsys_subcall,
2366                         SYS_pgrpsys_nsubcalls, shift_style);
2367                 break;
2368 #endif /* SYS_pgrpsys_subcall */
2369 #ifdef SYS_sigcall_subcall
2370         case SYS_sigcall:
2371                 decode_subcall(tcp, SYS_sigcall_subcall,
2372                         SYS_sigcall_nsubcalls, mask_style);
2373                 break;
2374 #endif /* SYS_sigcall_subcall */
2375         case SYS_msgsys:
2376                 decode_subcall(tcp, SYS_msgsys_subcall,
2377                         SYS_msgsys_nsubcalls, shift_style);
2378                 break;
2379         case SYS_shmsys:
2380                 decode_subcall(tcp, SYS_shmsys_subcall,
2381                         SYS_shmsys_nsubcalls, shift_style);
2382                 break;
2383         case SYS_semsys:
2384                 decode_subcall(tcp, SYS_semsys_subcall,
2385                         SYS_semsys_nsubcalls, shift_style);
2386                 break;
2387 #if 0 /* broken */
2388         case SYS_utssys:
2389                 decode_subcall(tcp, SYS_utssys_subcall,
2390                         SYS_utssys_nsubcalls, shift_style);
2391                 break;
2392 #endif
2393         case SYS_sysfs:
2394                 decode_subcall(tcp, SYS_sysfs_subcall,
2395                         SYS_sysfs_nsubcalls, shift_style);
2396                 break;
2397         case SYS_spcall:
2398                 decode_subcall(tcp, SYS_spcall_subcall,
2399                         SYS_spcall_nsubcalls, shift_style);
2400                 break;
2401 #ifdef SYS_context_subcall
2402         case SYS_context:
2403                 decode_subcall(tcp, SYS_context_subcall,
2404                         SYS_context_nsubcalls, shift_style);
2405                 break;
2406 #endif /* SYS_context_subcall */
2407 #ifdef SYS_door_subcall
2408         case SYS_door:
2409                 decode_subcall(tcp, SYS_door_subcall,
2410                         SYS_door_nsubcalls, door_style);
2411                 break;
2412 #endif /* SYS_door_subcall */
2413 #ifdef SYS_kaio_subcall
2414         case SYS_kaio:
2415                 decode_subcall(tcp, SYS_kaio_subcall,
2416                         SYS_kaio_nsubcalls, shift_style);
2417                 break;
2418 #endif
2419 #endif /* SVR4 */
2420 #ifdef FREEBSD
2421         case SYS_msgsys:
2422         case SYS_shmsys:
2423         case SYS_semsys:
2424                 decode_subcall(tcp, 0, 0, table_style);
2425                 break;
2426 #endif
2427 #ifdef SUNOS4
2428         case SYS_semsys:
2429                 decode_subcall(tcp, SYS_semsys_subcall,
2430                         SYS_semsys_nsubcalls, shift_style);
2431                 break;
2432         case SYS_msgsys:
2433                 decode_subcall(tcp, SYS_msgsys_subcall,
2434                         SYS_msgsys_nsubcalls, shift_style);
2435                 break;
2436         case SYS_shmsys:
2437                 decode_subcall(tcp, SYS_shmsys_subcall,
2438                         SYS_shmsys_nsubcalls, shift_style);
2439                 break;
2440 #endif
2441         }
2442
2443         internal_syscall(tcp);
2444         if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
2445                 tcp->flags |= TCB_INSYSCALL;
2446                 return 0;
2447         }
2448
2449         if (cflag) {
2450                 gettimeofday(&tcp->etime, NULL);
2451                 tcp->flags |= TCB_INSYSCALL;
2452                 return 0;
2453         }
2454
2455         printleader(tcp);
2456         tcp->flags &= ~TCB_REPRINT;
2457         tcp_last = tcp;
2458         if (tcp->scno >= nsyscalls || tcp->scno < 0)
2459                 tprintf("syscall_%lu(", tcp->scno);
2460         else
2461                 tprintf("%s(", sysent[tcp->scno].sys_name);
2462         if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2463             ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2464                 sys_res = printargs(tcp);
2465         else
2466                 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2467         if (fflush(tcp->outf) == EOF)
2468                 return -1;
2469         tcp->flags |= TCB_INSYSCALL;
2470         /* Measure the entrance time as late as possible to avoid errors. */
2471         if (dtime)
2472                 gettimeofday(&tcp->etime, NULL);
2473         return sys_res;
2474 }
2475
2476 int
2477 printargs(tcp)
2478 struct tcb *tcp;
2479 {
2480         if (entering(tcp)) {
2481                 int i;
2482
2483                 for (i = 0; i < tcp->u_nargs; i++)
2484                         tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2485         }
2486         return 0;
2487 }
2488
2489 long
2490 getrval2(tcp)
2491 struct tcb *tcp;
2492 {
2493         long val = -1;
2494
2495 #ifdef LINUX
2496 #if defined (SPARC) || defined (SPARC64)
2497         struct regs regs;
2498         if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2499                 return -1;
2500         val = regs.r_o1;
2501 #elif defined(SH)
2502         if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2503                 return -1;
2504 #endif /* SPARC || SPARC64 */
2505 #elif defined(IA64)
2506         if (upeek(tcp->pid, PT_R9, &val) < 0)
2507                 return -1;
2508 #endif /* LINUX */
2509
2510 #ifdef SUNOS4
2511         if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2512                 return -1;
2513 #endif /* SUNOS4 */
2514
2515 #ifdef SVR4
2516 #ifdef SPARC
2517         val = tcp->status.PR_REG[R_O1];
2518 #endif /* SPARC */
2519 #ifdef I386
2520         val = tcp->status.PR_REG[EDX];
2521 #endif /* I386 */
2522 #ifdef X86_64
2523         val = tcp->status.PR_REG[RDX];
2524 #endif /* X86_64 */
2525 #ifdef MIPS
2526         val = tcp->status.PR_REG[CTX_V1];
2527 #endif /* MIPS */
2528 #endif /* SVR4 */
2529 #ifdef FREEBSD
2530         struct reg regs;
2531         pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2532         val = regs.r_edx;
2533 #endif
2534         return val;
2535 }
2536
2537 /*
2538  * Apparently, indirect system calls have already be converted by ptrace(2),
2539  * so if you see "indir" this program has gone astray.
2540  */
2541 int
2542 sys_indir(tcp)
2543 struct tcb *tcp;
2544 {
2545         int i, scno, nargs;
2546
2547         if (entering(tcp)) {
2548                 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2549                         fprintf(stderr, "Bogus syscall: %u\n", scno);
2550                         return 0;
2551                 }
2552                 nargs = sysent[scno].nargs;
2553                 tprintf("%s", sysent[scno].sys_name);
2554                 for (i = 0; i < nargs; i++)
2555                         tprintf(", %#lx", tcp->u_arg[i+1]);
2556         }
2557         return 0;
2558 }
2559
2560 static int
2561 time_cmp(a, b)
2562 void *a;
2563 void *b;
2564 {
2565         return -tv_cmp(&tv_count[*((int *) a)], &tv_count[*((int *) b)]);
2566 }
2567
2568 static int
2569 syscall_cmp(a, b)
2570 void *a;
2571 void *b;
2572 {
2573         return strcmp(sysent[*((int *) a)].sys_name,
2574                 sysent[*((int *) b)].sys_name);
2575 }
2576
2577 static int
2578 count_cmp(a, b)
2579 void *a;
2580 void *b;
2581 {
2582         int m = call_count[*((int *) a)], n = call_count[*((int *) b)];
2583
2584         return (m < n) ? 1 : (m > n) ? -1 : 0;
2585 }
2586
2587 static int (*sortfun)();
2588 static struct timeval overhead = { -1, -1 };
2589
2590 void
2591 set_sortby(sortby)
2592 char *sortby;
2593 {
2594         if (strcmp(sortby, "time") == 0)
2595                 sortfun = time_cmp;
2596         else if (strcmp(sortby, "calls") == 0)
2597                 sortfun = count_cmp;
2598         else if (strcmp(sortby, "name") == 0)
2599                 sortfun = syscall_cmp;
2600         else if (strcmp(sortby, "nothing") == 0)
2601                 sortfun = NULL;
2602         else {
2603                 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2604                 exit(1);
2605         }
2606 }
2607
2608 void set_overhead(n)
2609 int n;
2610 {
2611         overhead.tv_sec = n / 1000000;
2612         overhead.tv_usec = n % 1000000;
2613 }
2614
2615 void
2616 call_summary(outf)
2617 FILE *outf;
2618 {
2619         int i, j;
2620         int call_cum, error_cum;
2621         struct timeval tv_cum, dtv;
2622         double percent;
2623         char *dashes = "-------------------------";
2624         char error_str[16];
2625
2626         call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2627         if (overhead.tv_sec == -1) {
2628                 tv_mul(&overhead, &shortest, 8);
2629                 tv_div(&overhead, &overhead, 10);
2630         }
2631         for (i = 0; i < nsyscalls; i++) {
2632                 sorted_count[i] = i;
2633                 if (call_count[i] == 0)
2634                         continue;
2635                 tv_mul(&dtv, &overhead, call_count[i]);
2636                 tv_sub(&tv_count[i], &tv_count[i], &dtv);
2637                 call_cum += call_count[i];
2638                 error_cum += error_count[i];
2639                 tv_add(&tv_cum, &tv_cum, &tv_count[i]);
2640         }
2641         if (sortfun)
2642                 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2643         fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2644                 "% time", "seconds", "usecs/call",
2645                 "calls", "errors", "syscall");
2646         fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2647                 dashes, dashes, dashes, dashes, dashes, dashes);
2648         for (i = 0; i < nsyscalls; i++) {
2649                 j = sorted_count[i];
2650                 if (call_count[j] == 0)
2651                         continue;
2652                 tv_div(&dtv, &tv_count[j], call_count[j]);
2653                 if (error_count[j])
2654                         sprintf(error_str, "%d", error_count[j]);
2655                 else
2656                         error_str[0] = '\0';
2657                 percent = 100.0*tv_float(&tv_count[j])/tv_float(&tv_cum);
2658                 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2659                         percent, (long) tv_count[j].tv_sec,
2660                         (long) tv_count[j].tv_usec,
2661                         (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2662                         call_count[j], error_str, sysent[j].sys_name);
2663         }
2664         fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2665                 dashes, dashes, dashes, dashes, dashes, dashes);
2666         if (error_cum)
2667                 sprintf(error_str, "%d", error_cum);
2668         else
2669                 error_str[0] = '\0';
2670         fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2671                 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2672                 call_cum, error_str, "total");
2673 }