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