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