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