blob: 19802ccfdd4506dae14c233d35da9e529c98d916 [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 Akkerman00a82ee2001-03-28 20:29:17 +000046#ifdef SPARC
47# define fpq kernel_fpq
48# define fq kernel_fq
49# define fpu kernel_fpu
50#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000051#include <asm/reg.h>
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000052#ifdef SPARC
53# undef fpq
54# undef fq
55# undef fpu
56#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000057#endif
58
Wichert Akkerman15dea971999-10-06 13:06:34 +000059#ifdef HAVE_SYS_REG_H
60#include <sys/reg.h>
61#ifndef PTRACE_PEEKUSR
62# define PTRACE_PEEKUSR PTRACE_PEEKUSER
63#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
66#include <linux/ptrace.h>
Wichert Akkerman15dea971999-10-06 13:06:34 +000067#endif
68
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000069#if defined(LINUX) && defined(IA64)
70# include <asm/ptrace_offsets.h>
71# include <asm/rse.h>
72#endif
73
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000074#ifndef SYS_ERRLIST_DECLARED
75extern int sys_nerr;
76extern char *sys_errlist[];
77#endif /* SYS_ERRLIST_DECLARED */
78
Pavel Machekd8ae7e32000-02-01 17:17:25 +000079#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000080#ifdef LINUX
81#ifndef ERESTARTSYS
82#define ERESTARTSYS 512
83#endif
84#ifndef ERESTARTNOINTR
85#define ERESTARTNOINTR 513
86#endif
87#ifndef ERESTARTNOHAND
88#define ERESTARTNOHAND 514 /* restart if no handler.. */
89#endif
90#ifndef ENOIOCTLCMD
91#define ENOIOCTLCMD 515 /* No ioctl command */
92#endif
93#ifndef NSIG
94#define NSIG 32
95#endif
96#ifdef ARM
97#undef NSIG
98#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +000099#undef NR_SYSCALL_BASE
100#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000101#endif
102#endif /* LINUX */
103
104#include "syscall.h"
105
106/* Define these shorthand notations to simplify the syscallent files. */
107#define TF TRACE_FILE
108#define TI TRACE_IPC
109#define TN TRACE_NETWORK
110#define TP TRACE_PROCESS
111#define TS TRACE_SIGNAL
112
113struct sysent sysent0[] = {
114#include "syscallent.h"
115};
116int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
117
118#if SUPPORTED_PERSONALITIES >= 2
119struct sysent sysent1[] = {
120#include "syscallent1.h"
121};
122int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
123#endif /* SUPPORTED_PERSONALITIES >= 2 */
124
125#if SUPPORTED_PERSONALITIES >= 3
126struct sysent sysent2[] = {
127#include "syscallent2.h"
128};
129int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
130#endif /* SUPPORTED_PERSONALITIES >= 3 */
131
132struct sysent *sysent;
133int nsyscalls;
134
135/* Now undef them since short defines cause wicked namespace pollution. */
136#undef TF
137#undef TI
138#undef TN
139#undef TP
140#undef TS
141
142char *errnoent0[] = {
143#include "errnoent.h"
144};
145int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
146
147#if SUPPORTED_PERSONALITIES >= 2
148char *errnoent1[] = {
149#include "errnoent1.h"
150};
151int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
152#endif /* SUPPORTED_PERSONALITIES >= 2 */
153
154#if SUPPORTED_PERSONALITIES >= 3
155char *errnoent2[] = {
156#include "errnoent2.h"
157};
158int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
159#endif /* SUPPORTED_PERSONALITIES >= 3 */
160
161char **errnoent;
162int nerrnos;
163
164int current_personality;
165
166int
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000167set_personality(personality)
168int personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169{
170 switch (personality) {
171 case 0:
172 errnoent = errnoent0;
173 nerrnos = nerrnos0;
174 sysent = sysent0;
175 nsyscalls = nsyscalls0;
176 ioctlent = ioctlent0;
177 nioctlents = nioctlents0;
178 signalent = signalent0;
179 nsignals = nsignals0;
180 break;
181
182#if SUPPORTED_PERSONALITIES >= 2
183 case 1:
184 errnoent = errnoent1;
185 nerrnos = nerrnos1;
186 sysent = sysent1;
187 nsyscalls = nsyscalls1;
188 ioctlent = ioctlent1;
189 nioctlents = nioctlents1;
190 signalent = signalent1;
191 nsignals = nsignals1;
192 break;
193#endif /* SUPPORTED_PERSONALITIES >= 2 */
194
195#if SUPPORTED_PERSONALITIES >= 3
196 case 2:
197 errnoent = errnoent2;
198 nerrnos = nerrnos2;
199 sysent = sysent2;
200 nsyscalls = nsyscalls2;
201 ioctlent = ioctlent2;
202 nioctlents = nioctlents2;
203 signalent = signalent2;
204 nsignals = nsignals2;
205 break;
206#endif /* SUPPORTED_PERSONALITIES >= 3 */
207
208 default:
209 return -1;
210 }
211
212 current_personality = personality;
213 return 0;
214}
215
216int qual_flags[MAX_QUALS];
217
218static int call_count[MAX_QUALS];
219static int error_count[MAX_QUALS];
220static struct timeval tv_count[MAX_QUALS];
221static int sorted_count[MAX_QUALS];
222
223static struct timeval shortest = { 1000000, 0 };
224
225static int lookup_syscall(), lookup_signal(), lookup_fault(), lookup_desc();
226
227static struct qual_options {
228 int bitflag;
229 char *option_name;
230 int (*lookup)();
231 char *argument_name;
232} qual_options[] = {
233 { QUAL_TRACE, "trace", lookup_syscall, "system call" },
234 { QUAL_TRACE, "t", lookup_syscall, "system call" },
235 { QUAL_ABBREV, "abbrev", lookup_syscall, "system call" },
236 { QUAL_ABBREV, "a", lookup_syscall, "system call" },
237 { QUAL_VERBOSE, "verbose", lookup_syscall, "system call" },
238 { QUAL_VERBOSE, "v", lookup_syscall, "system call" },
239 { QUAL_RAW, "raw", lookup_syscall, "system call" },
240 { QUAL_RAW, "x", lookup_syscall, "system call" },
241 { QUAL_SIGNAL, "signal", lookup_signal, "signal" },
242 { QUAL_SIGNAL, "signals", lookup_signal, "signal" },
243 { QUAL_SIGNAL, "s", lookup_signal, "signal" },
244 { QUAL_FAULT, "fault", lookup_fault, "fault" },
245 { QUAL_FAULT, "faults", lookup_fault, "fault" },
246 { QUAL_FAULT, "m", lookup_fault, "fault" },
247 { QUAL_READ, "read", lookup_desc, "descriptor" },
248 { QUAL_READ, "reads", lookup_desc, "descriptor" },
249 { QUAL_READ, "r", lookup_desc, "descriptor" },
250 { QUAL_WRITE, "write", lookup_desc, "descriptor" },
251 { QUAL_WRITE, "writes", lookup_desc, "descriptor" },
252 { QUAL_WRITE, "w", lookup_desc, "descriptor" },
253 { 0, NULL, NULL, NULL },
254};
255
256static int
257lookup_syscall(s)
258char *s;
259{
260 int i;
261
262 for (i = 0; i < nsyscalls; i++) {
263 if (strcmp(s, sysent[i].sys_name) == 0)
264 return i;
265 }
266 return -1;
267}
268
269static int
270lookup_signal(s)
271char *s;
272{
273 int i;
274 char buf[32];
275
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000276 if (s && *s && isdigit((unsigned char)*s))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000277 return atoi(s);
278 strcpy(buf, s);
279 s = buf;
280 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000281 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000282 if (strncmp(s, "SIG", 3) == 0)
283 s += 3;
284 for (i = 0; i <= NSIG; i++) {
Nate Sammonsce780fc1999-03-29 23:23:13 +0000285 if (strcmp(s, signame(i) + 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000286 return i;
287 }
288 return -1;
289}
290
291static int
292lookup_fault(s)
293char *s;
294{
295 return -1;
296}
297
298static int
299lookup_desc(s)
300char *s;
301{
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000302 if (s && *s && isdigit((unsigned char)*s))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000303 return atoi(s);
304 return -1;
305}
306
307static int
308lookup_class(s)
309char *s;
310{
311 if (strcmp(s, "file") == 0)
312 return TRACE_FILE;
313 if (strcmp(s, "ipc") == 0)
314 return TRACE_IPC;
315 if (strcmp(s, "network") == 0)
316 return TRACE_NETWORK;
317 if (strcmp(s, "process") == 0)
318 return TRACE_PROCESS;
319 if (strcmp(s, "signal") == 0)
320 return TRACE_SIGNAL;
321 return -1;
322}
323
324void
325qualify(s)
326char *s;
327{
328 struct qual_options *opt;
329 int not;
330 char *p;
331 int i, n;
332
333 opt = &qual_options[0];
334 for (i = 0; (p = qual_options[i].option_name); i++) {
335 n = strlen(p);
336 if (strncmp(s, p, n) == 0 && s[n] == '=') {
337 opt = &qual_options[i];
338 s += n + 1;
339 break;
340 }
341 }
342 not = 0;
343 if (*s == '!') {
344 not = 1;
345 s++;
346 }
347 if (strcmp(s, "none") == 0) {
348 not = 1 - not;
349 s = "all";
350 }
351 if (strcmp(s, "all") == 0) {
352 for (i = 0; i < MAX_QUALS; i++) {
353 if (not)
354 qual_flags[i] &= ~opt->bitflag;
355 else
356 qual_flags[i] |= opt->bitflag;
357 }
358 return;
359 }
360 for (i = 0; i < MAX_QUALS; i++) {
361 if (not)
362 qual_flags[i] |= opt->bitflag;
363 else
364 qual_flags[i] &= ~opt->bitflag;
365 }
366 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
367 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
368 for (i = 0; i < MAX_QUALS; i++) {
369 if (sysent[i].sys_flags & n) {
370 if (not)
371 qual_flags[i] &= ~opt->bitflag;
372 else
373 qual_flags[i] |= opt->bitflag;
374 }
375 }
376 continue;
377 }
378 if ((n = (*opt->lookup)(p)) < 0) {
379 fprintf(stderr, "strace: invalid %s `%s'\n",
380 opt->argument_name, p);
381 exit(1);
382 }
383 if (not)
384 qual_flags[n] &= ~opt->bitflag;
385 else
386 qual_flags[n] |= opt->bitflag;
387 }
388 return;
389}
390
391static void
392dumpio(tcp)
393struct tcb *tcp;
394{
395 if (syserror(tcp))
396 return;
397 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
398 return;
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000399 switch (tcp->scno + NR_SYSCALL_BASE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000400 case SYS_read:
401#ifdef SYS_recv
402 case SYS_recv:
403#endif
404#ifdef SYS_recvfrom
405 case SYS_recvfrom:
406#endif
407 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
408 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
409 break;
410 case SYS_write:
411#ifdef SYS_send
412 case SYS_send:
413#endif
414#ifdef SYS_sendto
415 case SYS_sendto:
416#endif
417 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
418 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
419 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000420#ifdef SYS_readv
421 case SYS_readv:
422 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
423 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
424 break;
425#endif
426#ifdef SYS_writev
427 case SYS_writev:
428
429 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
430 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
431 break;
432#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000433 }
434}
435
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000436#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000437enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000438#else /* FREEBSD */
439enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
440
441struct subcall {
442 int call;
443 int nsubcalls;
444 int subcalls[5];
445};
446
447const struct subcall subcalls_table[] = {
448 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000449#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000450 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000451#else
452 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
453#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000454 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
455};
456#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000457
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000458#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000459
460const int socket_map [] = {
461 /* SYS_SOCKET */ 97,
462 /* SYS_BIND */ 104,
463 /* SYS_CONNECT */ 98,
464 /* SYS_LISTEN */ 106,
465 /* SYS_ACCEPT */ 99,
466 /* SYS_GETSOCKNAME */ 150,
467 /* SYS_GETPEERNAME */ 141,
468 /* SYS_SOCKETPAIR */ 135,
469 /* SYS_SEND */ 101,
470 /* SYS_RECV */ 102,
471 /* SYS_SENDTO */ 133,
472 /* SYS_RECVFROM */ 125,
473 /* SYS_SHUTDOWN */ 134,
474 /* SYS_SETSOCKOPT */ 105,
475 /* SYS_GETSOCKOPT */ 118,
476 /* SYS_SENDMSG */ 114,
477 /* SYS_RECVMSG */ 113
478};
479
480void
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000481sparc_socket_decode (tcp)
482struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000483{
484 volatile long addr;
485 volatile int i, n;
486
487 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
488 return;
489 }
490 tcp->scno = socket_map [tcp->u_arg [0]-1];
491 n = tcp->u_nargs = sysent [tcp->scno].nargs;
492 addr = tcp->u_arg [1];
493 for (i = 0; i < n; i++){
494 int arg;
495 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
496 arg = 0;
497 tcp->u_arg [i] = arg;
498 addr += sizeof (arg);
499 }
500}
501
Michal Ludvig0e035502002-09-23 15:41:01 +0000502void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503decode_subcall(tcp, subcall, nsubcalls, style)
504struct tcb *tcp;
505int subcall;
506int nsubcalls;
507enum subcall_style style;
508{
Michal Ludvig10a88d02002-10-07 14:31:00 +0000509 long addr, mask, arg;
510 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000511
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000512 switch (style) {
513 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000514 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
515 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000516 tcp->scno = subcall + tcp->u_arg[0];
517 if (sysent[tcp->scno].nargs != -1)
518 tcp->u_nargs = sysent[tcp->scno].nargs;
519 else
520 tcp->u_nargs--;
521 for (i = 0; i < tcp->u_nargs; i++)
522 tcp->u_arg[i] = tcp->u_arg[i + 1];
523 break;
524 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000525 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
526 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527 tcp->scno = subcall + tcp->u_arg[0];
528 addr = tcp->u_arg[1];
529 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
530 if (umove(tcp, addr, &arg) < 0)
531 arg = 0;
532 tcp->u_arg[i] = arg;
533 addr += sizeof(arg);
534 }
535 tcp->u_nargs = sysent[tcp->scno].nargs;
536 break;
537 case mask_style:
538 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539 for (i = 0; mask; i++)
540 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000541 if (i >= nsubcalls)
542 return;
543 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544 tcp->scno = subcall + i;
545 if (sysent[tcp->scno].nargs != -1)
546 tcp->u_nargs = sysent[tcp->scno].nargs;
547 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000548 case door_style:
549 /*
550 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000551 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000552 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000553 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
554 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000555 tcp->scno = subcall + tcp->u_arg[5];
556 if (sysent[tcp->scno].nargs != -1)
557 tcp->u_nargs = sysent[tcp->scno].nargs;
558 else
559 tcp->u_nargs--;
560 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000561#ifdef FREEBSD
562 case table_style:
563 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
564 if (subcalls_table[i].call == tcp->scno) break;
565 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
566 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
567 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
568 for (i = 0; i < tcp->u_nargs; i++)
569 tcp->u_arg[i] = tcp->u_arg[i + 1];
570 }
571 break;
572#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000573 }
574}
575#endif
576
577struct tcb *tcp_last = NULL;
578
579static int
580internal_syscall(tcp)
581struct tcb *tcp;
582{
583 /*
584 * We must always trace a few critical system calls in order to
585 * correctly support following forks in the presence of tracing
586 * qualifiers.
587 */
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000588 switch (tcp->scno + NR_SYSCALL_BASE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589#ifdef SYS_fork
590 case SYS_fork:
591#endif
592#ifdef SYS_vfork
593 case SYS_vfork:
594#endif
John Hughes4e36a812001-04-18 15:11:51 +0000595#ifdef SYS_fork1
596 case SYS_fork1:
597#endif
598#ifdef SYS_forkall
599 case SYS_forkall:
600#endif
601#ifdef SYS_rfork1
602 case SYS_rfork1:
603#endif
604#ifdef SYS_rforkall
605 case SYS_rforkall:
606#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 internal_fork(tcp);
608 break;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000609#ifdef SYS_clone
610 case SYS_clone:
611 internal_clone(tcp);
612 break;
613#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000614#ifdef SYS_clone2
615 case SYS_clone2:
616 internal_clone(tcp);
617 break;
618#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000619#ifdef SYS_execv
620 case SYS_execv:
621#endif
622#ifdef SYS_execve
623 case SYS_execve:
624#endif
John Hughes4e36a812001-04-18 15:11:51 +0000625#ifdef SYS_rexecve
626 case SYS_rexecve:
627#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000628 internal_exec(tcp);
629 break;
630
631#ifdef SYS_wait
632 case SYS_wait:
633#endif
634#ifdef SYS_wait4
635 case SYS_wait4:
636#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000637#ifdef SYS32_wait4
638 case SYS32_wait4:
639#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640#ifdef SYS_waitpid
641 case SYS_waitpid:
642#endif
643#ifdef SYS_waitsys
644 case SYS_waitsys:
645#endif
646 internal_wait(tcp);
647 break;
648
649#ifdef SYS_exit
650 case SYS_exit:
651#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000652#ifdef SYS32_exit
653 case SYS32_exit:
654#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000655 internal_exit(tcp);
656 break;
657 }
658 return 0;
659}
660
Wichert Akkermanc7926982000-04-10 22:22:31 +0000661
662#ifdef LINUX
663#if defined (I386)
664 static long eax;
665#elif defined (IA64)
666 long r8, r10, psr;
667 long ia32 = 0;
668#elif defined (POWERPC)
669 static long result,flags;
670#elif defined (M68K)
671 static int d0;
672#elif defined (ARM)
673 static int r0;
674#elif defined (ALPHA)
675 static long r0;
676 static long a3;
677#elif defined (SPARC)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000678 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000679 static unsigned long trap;
680#elif defined(MIPS)
681 static long a3;
682 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000683#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000684 static long gpr2;
685 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000686 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000687#elif defined(HPPA)
688 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000689#elif defined(SH)
690 static long r0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000691#elif defined(X86_64)
692 static long rax;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000693#endif
694#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000695#ifdef FREEBSD
696 struct reg regs;
697#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000698
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000699int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000700get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000701struct tcb *tcp;
702{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000703 long scno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000704 static int currpers=-1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000705#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000706 int pid = tcp->pid;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000707#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000708
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000709#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000710#if defined(S390) || defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000711 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000712 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +0000713 if (syscall_mode != -ENOSYS){
714 /*
715 * Since kernel version 2.5.44 the scno gets passed in gpr2.
716 */
717 scno = syscall_mode;
718 }
719 else {
720 /*
721 * Old style of "passing" the scno via the SVC instruction.
722 */
723
724 long opcode, offset_reg, tmp;
725 void * svc_addr;
726 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
727 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
728 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
729 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
730
731 if (upeek(pid, PT_PSWADDR, &pc) < 0)
732 return -1;
733 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
734 if (errno)
735 return -1;
736
737 /*
738 * We have to check if the SVC got executed directly or via an
739 * EXECUTE instruction. In case of EXECUTE it is necessary to do
740 * instruction decoding to derive the system call number.
741 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
742 * so that this doesn't work if a SVC opcode is part of an EXECUTE
743 * opcode. Since there is no way to find out the opcode size this
744 * is the best we can do...
745 */
746
747 if ((opcode & 0xff00) == 0x0a00) {
748 /* SVC opcode */
749 scno = opcode & 0xff;
750 }
751 else {
752 /* SVC got executed by EXECUTE instruction */
753
754 /*
755 * Do instruction decoding of EXECUTE. If you really want to
756 * understand this, read the Principles of Operations.
757 */
758 svc_addr = (void *) (opcode & 0xfff);
759
760 tmp = 0;
761 offset_reg = (opcode & 0x000f0000) >> 16;
762 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
763 return -1;
764 svc_addr += tmp;
765
766 tmp = 0;
767 offset_reg = (opcode & 0x0000f000) >> 12;
768 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
769 return -1;
770 svc_addr += tmp;
771
772 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
773 if (errno)
774 return -1;
775#if defined(S390X)
776 scno >>= 48;
777#else
778 scno >>= 16;
779#endif
780 tmp = 0;
781 offset_reg = (opcode & 0x00f00000) >> 20;
782 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
783 return -1;
784
785 scno = (scno | tmp) & 0xff;
786 }
787 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000788#elif defined (POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 if (upeek(pid, 4*PT_R0, &scno) < 0)
790 return -1;
791 if (!(tcp->flags & TCB_INSYSCALL)) {
792 /* Check if we return from execve. */
793 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
794 tcp->flags &= ~TCB_WAITEXECVE;
795 return 0;
796 }
797 }
798#elif defined (I386)
799 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
800 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000801#elif defined (X86_64)
802 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
803 return -1;
804
805 if (!(tcp->flags & TCB_INSYSCALL)) {
806 long val;
807
808 /* Check CS register value. On x86-64 linux it is:
809 * 0x33 for long mode (64 bit)
810 * 0x23 for compatibility mode (32 bit)
811 * It takes only one ptrace and thus doesn't need
812 * to be cached.
813 */
814 if (upeek(pid, 8*CS, &val) < 0)
815 return -1;
816 switch(val)
817 {
818 case 0x23: currpers = 1; break;
819 case 0x33: currpers = 0; break;
820 default:
821 fprintf(stderr, "Unknown value CS=0x%02X while "
822 "detecting personality of process "
823 "PID=%d\n", (int)val, pid);
824 currpers = current_personality;
825 break;
826 }
827#if 0
828 /* This version analyzes the opcode of a syscall instruction.
829 * (int 0x80 on i386 vs. syscall on x86-64)
830 * It works, but is too complicated.
831 */
832 unsigned long val, rip, i;
833
834 if(upeek(pid, 8*RIP, &rip)<0)
835 perror("upeek(RIP)");
836
837 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
838 rip-=2;
839 errno = 0;
840
841 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
842 if (errno)
843 printf("ptrace_peektext failed: %s\n",
844 strerror(errno));
845 switch (call & 0xffff)
846 {
847 /* x86-64: syscall = 0x0f 0x05 */
848 case 0x050f: currpers = 0; break;
849 /* i386: int 0x80 = 0xcd 0x80 */
850 case 0x80cd: currpers = 1; break;
851 default:
852 currpers = current_personality;
853 fprintf(stderr,
854 "Unknown syscall opcode (0x%04X) while "
855 "detecting personality of process "
856 "PID=%d\n", (int)call, pid);
857 break;
858 }
859#endif
860 if(currpers != current_personality)
861 {
862 char *names[]={"64 bit", "32 bit"};
863 set_personality(currpers);
864 printf("[ Process PID=%d runs in %s mode. ]\n",
865 pid, names[current_personality]);
866 }
867 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000868#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000869# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000870 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000871 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000872 if (!(tcp->flags & TCB_INSYSCALL)) {
873 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000874 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000875 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000876 /* Check if we return from execve. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000877 } else {
878 if (upeek (pid, PT_R15, &scno) < 0)
879 return -1;
880 }
881 } else {
882 /* syscall in progress */
883 if (upeek (pid, PT_R8, &r8) < 0)
884 return -1;
885 if (upeek (pid, PT_R10, &r10) < 0)
886 return -1;
887 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000888 if (tcp->flags & TCB_WAITEXECVE) {
889 tcp->flags &= ~TCB_WAITEXECVE;
890 return 0;
891 }
892
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000893#elif defined (ARM)
894 {
895 long pc;
896 upeek(pid, 4*15, &pc);
897 umoven(tcp, pc-4, 4, (char *)&scno);
898 scno &= 0x000fffff;
899 }
900#elif defined (M68K)
901 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
902 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000903#elif defined (MIPS)
904 if (upeek(pid, REG_A3, &a3) < 0)
905 return -1;
906
907 if(!(tcp->flags & TCB_INSYSCALL)) {
908 if (upeek(pid, REG_V0, &scno) < 0)
909 return -1;
910
911 if (scno < 0 || scno > nsyscalls) {
912 if(a3 == 0 || a3 == -1) {
913 if(debug)
914 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
915 return 0;
916 }
917 }
918 } else {
919 if (upeek(pid, REG_V0, &r2) < 0)
920 return -1;
921 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000922#elif defined (ALPHA)
923 if (upeek(pid, REG_A3, &a3) < 0)
924 return -1;
925
926 if (!(tcp->flags & TCB_INSYSCALL)) {
927 if (upeek(pid, REG_R0, &scno) < 0)
928 return -1;
929
930 /* Check if we return from execve. */
931 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
932 tcp->flags &= ~TCB_WAITEXECVE;
933 return 0;
934 }
935
936 /*
937 * Do some sanity checks to figure out if it's
938 * really a syscall entry
939 */
940 if (scno < 0 || scno > nsyscalls) {
941 if (a3 == 0 || a3 == -1) {
942 if (debug)
943 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
944 return 0;
945 }
946 }
947 }
948 else {
949 if (upeek(pid, REG_R0, &r0) < 0)
950 return -1;
951 }
952#elif defined (SPARC)
953 /* Everything we need is in the current register set. */
954 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
955 return -1;
956
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000957 /* If we are entering, then disassemble the syscall trap. */
958 if (!(tcp->flags & TCB_INSYSCALL)) {
959 /* Retrieve the syscall trap instruction. */
960 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000961 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962 if (errno)
963 return -1;
964
965 /* Disassemble the trap to see what personality to use. */
966 switch (trap) {
967 case 0x91d02010:
968 /* Linux/SPARC syscall trap. */
969 set_personality(0);
970 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +0000971 case 0x91d0206d:
972 /* Linux/SPARC64 syscall trap. */
973 fprintf(stderr,"syscall: Linux/SPARC64 not supported yet\n");
974 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000975 case 0x91d02000:
976 /* SunOS syscall trap. (pers 1) */
977 fprintf(stderr,"syscall: SunOS no support\n");
978 return -1;
979 case 0x91d02008:
980 /* Solaris 2.x syscall trap. (per 2) */
981 set_personality(1);
982 break;
983 case 0x91d02009:
984 /* NetBSD/FreeBSD syscall trap. */
985 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
986 return -1;
987 case 0x91d02027:
988 /* Solaris 2.x gettimeofday */
989 set_personality(1);
990 break;
991 default:
992 /* Unknown syscall trap. */
993 if(tcp->flags & TCB_WAITEXECVE) {
994 tcp->flags &= ~TCB_WAITEXECVE;
995 return 0;
996 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000997 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000998 return -1;
999 }
1000
1001 /* Extract the system call number from the registers. */
1002 if (trap == 0x91d02027)
1003 scno = 156;
1004 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001005 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001007 scno = regs.r_o0;
1008 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001009 }
1010 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001011#elif defined(HPPA)
1012 if (upeek(pid, PT_GR20, &scno) < 0)
1013 return -1;
1014 if (!(tcp->flags & TCB_INSYSCALL)) {
1015 /* Check if we return from execve. */
1016 if ((tcp->flags & TCB_WAITEXECVE)) {
1017 tcp->flags &= ~TCB_WAITEXECVE;
1018 return 0;
1019 }
1020 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001021#elif defined(SH)
1022 /*
1023 * In the new syscall ABI, the system call number is in R3.
1024 */
1025 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1026 return -1;
1027
1028 if (scno < 0) {
1029 /* Odd as it may seem, a glibc bug has been known to cause
1030 glibc to issue bogus negative syscall numbers. So for
1031 our purposes, make strace print what it *should* have been */
1032 long correct_scno = (scno & 0xff);
1033 if (debug)
1034 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001035 "Detected glibc bug: bogus system call number = %ld, "
1036 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001037 scno,
1038 correct_scno);
1039 scno = correct_scno;
1040 }
1041
1042
1043 if (!(tcp->flags & TCB_INSYSCALL)) {
1044 /* Check if we return from execve. */
1045 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1046 tcp->flags &= ~TCB_WAITEXECVE;
1047 return 0;
1048 }
1049 }
1050#endif /* SH */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051#endif /* LINUX */
1052#ifdef SUNOS4
1053 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1054 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001055#elif defined(SH)
1056 /* new syscall ABI returns result in R0 */
1057 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1058 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001060#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001062 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001064#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001065 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001066#else /* FREEBSD */
1067 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1068 perror("pread");
1069 return -1;
1070 }
1071 switch (regs.r_eax) {
1072 case SYS_syscall:
1073 case SYS___syscall:
1074 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1075 break;
1076 default:
1077 scno = regs.r_eax;
1078 break;
1079 }
1080#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001082#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001083 if (!(tcp->flags & TCB_INSYSCALL))
1084 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001085 return 1;
1086}
1087
Pavel Machek4dc3b142000-02-01 17:58:41 +00001088
1089int
1090syscall_fixup(tcp)
1091struct tcb *tcp;
1092{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001093#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001094 int pid = tcp->pid;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001095#else /* USE_PROCFS */
1096 int scno = tcp->scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001097
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001099 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100 if (
1101 scno == SYS_fork
1102#ifdef SYS_vfork
1103 || scno == SYS_vfork
1104#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001105#ifdef SYS_fork1
1106 || scno == SYS_fork1
1107#endif /* SYS_fork1 */
1108#ifdef SYS_forkall
1109 || scno == SYS_forkall
1110#endif /* SYS_forkall */
1111#ifdef SYS_rfork1
1112 || scno == SYS_rfork1
1113#endif /* SYS_fork1 */
1114#ifdef SYS_rforkall
1115 || scno == SYS_rforkall
1116#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 ) {
1118 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001119 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001121 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 }
1123 else {
1124 fprintf(stderr, "syscall: missing entry\n");
1125 tcp->flags |= TCB_INSYSCALL;
1126 }
1127 }
1128 }
1129 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001130 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 fprintf(stderr, "syscall: missing exit\n");
1132 tcp->flags &= ~TCB_INSYSCALL;
1133 }
1134 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001135#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001136#ifdef SUNOS4
1137 if (!(tcp->flags & TCB_INSYSCALL)) {
1138 if (scno == 0) {
1139 fprintf(stderr, "syscall: missing entry\n");
1140 tcp->flags |= TCB_INSYSCALL;
1141 }
1142 }
1143 else {
1144 if (scno != 0) {
1145 if (debug) {
1146 /*
1147 * This happens when a signal handler
1148 * for a signal which interrupted a
1149 * a system call makes another system call.
1150 */
1151 fprintf(stderr, "syscall: missing exit\n");
1152 }
1153 tcp->flags &= ~TCB_INSYSCALL;
1154 }
1155 }
1156#endif /* SUNOS4 */
1157#ifdef LINUX
1158#if defined (I386)
1159 if (upeek(pid, 4*EAX, &eax) < 0)
1160 return -1;
1161 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1162 if (debug)
1163 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1164 return 0;
1165 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001166#elif defined (X86_64)
1167 if (upeek(pid, 8*RAX, &rax) < 0)
1168 return -1;
1169 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1170 if (debug)
1171 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1172 return 0;
1173 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001174#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001175 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1176 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001177 if (syscall_mode != -ENOSYS)
1178 syscall_mode = tcp->scno;
1179 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001180 if (debug)
1181 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1182 return 0;
1183 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184#elif defined (POWERPC)
1185# define SO_MASK 0x10000000
1186 if (upeek(pid, 4*PT_CCR, &flags) < 0)
1187 return -1;
1188 if (upeek(pid, 4*PT_R3, &result) < 0)
1189 return -1;
1190 if (flags & SO_MASK)
1191 result = -result;
1192#elif defined (M68K)
1193 if (upeek(pid, 4*PT_D0, &d0) < 0)
1194 return -1;
1195 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1196 if (debug)
1197 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1198 return 0;
1199 }
1200#elif defined (ARM)
1201 if (upeek(pid, 4*0, (long *)&r0) < 0)
1202 return -1;
1203 if ( 0 && r0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1204 if (debug)
1205 fprintf(stderr, "stray syscall exit: d0 = %ld\n", r0);
1206 return 0;
1207 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001208#elif defined (HPPA)
1209 if (upeek(pid, PT_GR28, &r28) < 0)
1210 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001211#elif defined(IA64)
1212 if (upeek(pid, PT_R10, &r10) < 0)
1213 return -1;
1214 if (upeek(pid, PT_R8, &r8) < 0)
1215 return -1;
1216 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1217 if (debug)
1218 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1219 return 0;
1220 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001221#endif
1222#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001223 return 1;
1224}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001225
Pavel Machek4dc3b142000-02-01 17:58:41 +00001226int
1227get_error(tcp)
1228struct tcb *tcp;
1229{
1230 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001232#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001233 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1234 tcp->u_rval = -1;
1235 u_error = -gpr2;
1236 }
1237 else {
1238 tcp->u_rval = gpr2;
1239 u_error = 0;
1240 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001241#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001242#ifdef I386
1243 if (eax < 0 && -eax < nerrnos) {
1244 tcp->u_rval = -1;
1245 u_error = -eax;
1246 }
1247 else {
1248 tcp->u_rval = eax;
1249 u_error = 0;
1250 }
1251#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001252#ifdef X86_64
1253 if (rax < 0 && -rax < nerrnos) {
1254 tcp->u_rval = -1;
1255 u_error = -rax;
1256 }
1257 else {
1258 tcp->u_rval = rax;
1259 u_error = 0;
1260 }
1261#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001262#ifdef IA64
1263 if (ia32) {
1264 int err;
1265
1266 err = (int)r8;
1267 if (err < 0 && -err < nerrnos) {
1268 tcp->u_rval = -1;
1269 u_error = -err;
1270 }
1271 else {
1272 tcp->u_rval = err;
1273 u_error = 0;
1274 }
1275 } else {
1276 if (r10) {
1277 tcp->u_rval = -1;
1278 u_error = r8;
1279 } else {
1280 tcp->u_rval = r8;
1281 u_error = 0;
1282 }
1283 }
1284#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001285#ifdef MIPS
1286 if (a3) {
1287 tcp->u_rval = -1;
1288 u_error = r2;
1289 } else {
1290 tcp->u_rval = r2;
1291 u_error = 0;
1292 }
1293#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001294#ifdef POWERPC
1295 if (result && (unsigned) -result < nerrnos) {
1296 tcp->u_rval = -1;
1297 u_error = -result;
1298 }
1299 else {
1300 tcp->u_rval = result;
1301 u_error = 0;
1302 }
1303#else /* !POWERPC */
1304#ifdef M68K
1305 if (d0 && (unsigned) -d0 < nerrnos) {
1306 tcp->u_rval = -1;
1307 u_error = -d0;
1308 }
1309 else {
1310 tcp->u_rval = d0;
1311 u_error = 0;
1312 }
1313#else /* !M68K */
1314#ifdef ARM
1315 if (r0 && (unsigned) -r0 < nerrnos) {
1316 tcp->u_rval = -1;
1317 u_error = -r0;
1318 }
1319 else {
1320 tcp->u_rval = r0;
1321 u_error = 0;
1322 }
1323#else /* !ARM */
1324#ifdef ALPHA
1325 if (a3) {
1326 tcp->u_rval = -1;
1327 u_error = r0;
1328 }
1329 else {
1330 tcp->u_rval = r0;
1331 u_error = 0;
1332 }
1333#else /* !ALPHA */
1334#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001335 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001336 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001337 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001338 }
1339 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001340 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001341 u_error = 0;
1342 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001343#else /* !SPARC */
1344#ifdef HPPA
1345 if (r28 && (unsigned) -r28 < nerrnos) {
1346 tcp->u_rval = -1;
1347 u_error = -r28;
1348 }
1349 else {
1350 tcp->u_rval = r28;
1351 u_error = 0;
1352 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001353#else
1354#ifdef SH
1355 /* interpret R0 as return value or error number */
1356 if (r0 && (unsigned) -r0 < nerrnos) {
1357 tcp->u_rval = -1;
1358 u_error = -r0;
1359 }
1360 else {
1361 tcp->u_rval = r0;
1362 u_error = 0;
1363 }
1364#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001365#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001366#endif /* SPARC */
1367#endif /* ALPHA */
1368#endif /* ARM */
1369#endif /* M68K */
1370#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001371#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001372#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001373#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001375#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376#endif /* LINUX */
1377#ifdef SUNOS4
1378 /* get error code from user struct */
1379 if (upeek(pid, uoff(u_error), &u_error) < 0)
1380 return -1;
1381 u_error >>= 24; /* u_error is a char */
1382
1383 /* get system call return value */
1384 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1385 return -1;
1386#endif /* SUNOS4 */
1387#ifdef SVR4
1388#ifdef SPARC
1389 /* Judicious guessing goes a long way. */
1390 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1391 tcp->u_rval = -1;
1392 u_error = tcp->status.pr_reg[R_O0];
1393 }
1394 else {
1395 tcp->u_rval = tcp->status.pr_reg[R_O0];
1396 u_error = 0;
1397 }
1398#endif /* SPARC */
1399#ifdef I386
1400 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001401 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001402 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001403 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001404 }
1405 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001406 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001407#ifdef HAVE_LONG_LONG
1408 tcp->u_lrval =
1409 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1410 tcp->status.PR_REG[EAX];
1411#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001412 u_error = 0;
1413 }
1414#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001415#ifdef X86_64
1416 /* Wanna know how to kill an hour single-stepping? */
1417 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1418 tcp->u_rval = -1;
1419 u_error = tcp->status.PR_REG[RAX];
1420 }
1421 else {
1422 tcp->u_rval = tcp->status.PR_REG[RAX];
1423 u_error = 0;
1424 }
1425#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001426#ifdef MIPS
1427 if (tcp->status.pr_reg[CTX_A3]) {
1428 tcp->u_rval = -1;
1429 u_error = tcp->status.pr_reg[CTX_V0];
1430 }
1431 else {
1432 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1433 u_error = 0;
1434 }
1435#endif /* MIPS */
1436#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001437#ifdef FREEBSD
1438 if (regs.r_eflags & PSL_C) {
1439 tcp->u_rval = -1;
1440 u_error = regs.r_eax;
1441 } else {
1442 tcp->u_rval = regs.r_eax;
1443 tcp->u_lrval =
1444 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1445 u_error = 0;
1446 }
1447#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001448 tcp->u_error = u_error;
1449 return 1;
1450}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451
Pavel Machek4dc3b142000-02-01 17:58:41 +00001452int syscall_enter(tcp)
1453struct tcb *tcp;
1454{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001455#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001456 int pid = tcp->pid;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001457#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001458#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001459#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001460 {
1461 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001462 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1463 tcp->u_nargs = sysent[tcp->scno].nargs;
1464 else
1465 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001466 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001467 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001468 return -1;
1469 }
1470 }
1471#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472 {
1473 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001474 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1475 tcp->u_nargs = sysent[tcp->scno].nargs;
1476 else
1477 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001478 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001479 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1480 * for scno somewhere above here!
1481 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001482 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1483 return -1;
1484 }
1485 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001486#elif defined (IA64)
1487 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001488 if (!ia32) {
1489 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1490 /* be backwards compatible with kernel < 2.4.4... */
1491# ifndef PT_RBS_END
1492# define PT_RBS_END PT_AR_BSP
1493# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001494
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001495 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001496 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001497 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1498 return -1;
1499
1500 sof = (cfm >> 0) & 0x7f;
1501 sol = (cfm >> 7) & 0x7f;
1502 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1503
1504 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1505 && sysent[tcp->scno].nargs != -1)
1506 tcp->u_nargs = sysent[tcp->scno].nargs;
1507 else
1508 tcp->u_nargs = MAX_ARGS;
1509 for (i = 0; i < tcp->u_nargs; ++i) {
1510 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1511 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1512 return -1;
1513 }
1514 } else {
1515 int i;
1516
1517 if (/* EBX = out0 */
1518 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1519 /* ECX = out1 */
1520 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1521 /* EDX = out2 */
1522 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1523 /* ESI = out3 */
1524 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1525 /* EDI = out4 */
1526 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1527 /* EBP = out5 */
1528 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1529 return -1;
1530
1531 for (i = 0; i < 6; ++i)
1532 /* truncate away IVE sign-extension */
1533 tcp->u_arg[i] &= 0xffffffff;
1534
1535 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1536 && sysent[tcp->scno].nargs != -1)
1537 tcp->u_nargs = sysent[tcp->scno].nargs;
1538 else
1539 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001540 }
1541 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001542#elif defined (MIPS)
1543 {
1544 long sp;
1545 int i, nargs;
1546
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001547 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1548 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
1549 else
1550 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001551 if(nargs > 4) {
1552 if(upeek(pid, REG_SP, &sp) < 0)
1553 return -1;
1554 for(i = 0; i < 4; i++) {
1555 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
1556 return -1;
1557 }
1558 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
1559 (char *)(tcp->u_arg + 4));
1560 } else {
1561 for(i = 0; i < nargs; i++) {
1562 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
1563 return -1;
1564 }
1565 }
1566 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001567#elif defined (POWERPC)
1568 {
1569 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001570 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1571 tcp->u_nargs = sysent[tcp->scno].nargs;
1572 else
1573 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001574 for (i = 0; i < tcp->u_nargs; i++) {
1575 if (upeek(pid, (i==0) ? (4*PT_ORIG_R3) : ((i+PT_R3)*4), &tcp->u_arg[i]) < 0)
1576 return -1;
1577 }
1578 }
1579#elif defined (SPARC)
1580 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001581 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001582
1583 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1584 tcp->u_nargs = sysent[tcp->scno].nargs;
1585 else
1586 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001588 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001589 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001590#elif defined (HPPA)
1591 {
1592 int i;
1593
1594 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1595 tcp->u_nargs = sysent[tcp->scno].nargs;
1596 else
1597 tcp->u_nargs = MAX_ARGS;
1598 for (i = 0; i < tcp->u_nargs; i++) {
1599 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1600 return -1;
1601 }
1602 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001603#elif defined(SH)
1604 {
1605 int i;
1606 static int syscall_regs[] = {
1607 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
1608 REG_REG0, REG_REG0+1, REG_REG0+2
1609 };
1610
1611 tcp->u_nargs = sysent[tcp->scno].nargs;
1612 for (i = 0; i < tcp->u_nargs; i++) {
1613 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
1614 return -1;
1615 }
1616 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001617#elif defined(X86_64)
1618 {
1619 int i;
1620 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
1621 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
1622 {RBX,RCX,RDX,RDX,RSI,RDI,RBP} /* i386 ABI */
1623 };
1624
1625 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1626 tcp->u_nargs = sysent[tcp->scno].nargs;
1627 else
1628 tcp->u_nargs = MAX_ARGS;
1629 for (i = 0; i < tcp->u_nargs; i++) {
1630 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
1631 return -1;
1632 }
1633 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001634#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001635 {
1636 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001637 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1638 tcp->u_nargs = sysent[tcp->scno].nargs;
1639 else
1640 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641 for (i = 0; i < tcp->u_nargs; i++) {
1642 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
1643 return -1;
1644 }
1645 }
1646#endif
1647#endif /* LINUX */
1648#ifdef SUNOS4
1649 {
1650 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001651 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1652 tcp->u_nargs = sysent[tcp->scno].nargs;
1653 else
1654 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655 for (i = 0; i < tcp->u_nargs; i++) {
1656 struct user *u;
1657
1658 if (upeek(pid, uoff(u_arg[0]) +
1659 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1660 return -1;
1661 }
1662 }
1663#endif /* SUNOS4 */
1664#ifdef SVR4
1665#ifdef MIPS
1666 /*
1667 * SGI is broken: even though it has pr_sysarg, it doesn't
1668 * set them on system call entry. Get a clue.
1669 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001670 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001671 tcp->u_nargs = sysent[tcp->scno].nargs;
1672 else
1673 tcp->u_nargs = tcp->status.pr_nsysarg;
1674 if (tcp->u_nargs > 4) {
1675 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
1676 4*sizeof(tcp->u_arg[0]));
1677 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
1678 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
1679 }
1680 else {
1681 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
1682 tcp->u_nargs*sizeof(tcp->u_arg[0]));
1683 }
John Hughes25299712001-03-06 10:10:06 +00001684#elif UNIXWARE >= 2
1685 /*
1686 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1687 */
1688 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1689 tcp->u_nargs = sysent[tcp->scno].nargs;
1690 else
1691 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1692 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
1693 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1694#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001695 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696 tcp->u_nargs = sysent[tcp->scno].nargs;
1697 else
1698 tcp->u_nargs = tcp->status.pr_nsysarg;
1699 {
1700 int i;
1701 for (i = 0; i < tcp->u_nargs; i++)
1702 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1703 }
John Hughes25299712001-03-06 10:10:06 +00001704#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001705 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706 tcp->u_nargs = sysent[tcp->scno].nargs;
1707 else
1708 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001709 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00001711#else
1712 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001713#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001715#ifdef FREEBSD
1716 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1717 sysent[tcp->scno].nargs > tcp->status.val)
1718 tcp->u_nargs = sysent[tcp->scno].nargs;
1719 else
1720 tcp->u_nargs = tcp->status.val;
1721 if (tcp->u_nargs < 0)
1722 tcp->u_nargs = 0;
1723 if (tcp->u_nargs > MAX_ARGS)
1724 tcp->u_nargs = MAX_ARGS;
1725 switch(regs.r_eax) {
1726 case SYS___syscall:
1727 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1728 regs.r_esp + sizeof(int) + sizeof(quad_t));
1729 break;
1730 case SYS_syscall:
1731 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1732 regs.r_esp + 2 * sizeof(int));
1733 break;
1734 default:
1735 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1736 regs.r_esp + sizeof(int));
1737 break;
1738 }
1739#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001740 return 1;
1741}
1742
1743int
1744trace_syscall(tcp)
1745struct tcb *tcp;
1746{
1747 int sys_res;
1748 struct timeval tv;
1749 int res;
1750
1751 /* Measure the exit time as early as possible to avoid errors. */
1752 if (dtime && (tcp->flags & TCB_INSYSCALL))
1753 gettimeofday(&tv, NULL);
1754
1755 res = get_scno(tcp);
1756 if (res != 1)
1757 return res;
1758
1759 res = syscall_fixup(tcp);
1760 if (res != 1)
1761 return res;
1762
1763 if (tcp->flags & TCB_INSYSCALL) {
1764 long u_error;
1765 res = get_error(tcp);
1766 if (res != 1)
1767 return res;
1768 u_error = tcp->u_error;
1769
1770
1771 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001772 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1773 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00001774 tcp->flags &= ~TCB_INSYSCALL;
1775 return 0;
1776 }
1777
1778 if (tcp->flags & TCB_REPRINT) {
1779 printleader(tcp);
1780 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001781 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001782 tprintf("syscall_%lu", tcp->scno);
1783 else
1784 tprintf("%s", sysent[tcp->scno].sys_name);
1785 tprintf(" resumed> ");
1786 }
1787
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001788 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00001789 call_count[tcp->scno]++;
1790 if (tcp->u_error)
1791 error_count[tcp->scno]++;
1792 tv_sub(&tv, &tv, &tcp->etime);
1793#ifdef LINUX
1794 if (tv_cmp(&tv, &tcp->dtime) > 0) {
1795 static struct timeval one_tick =
1796 { 0, 1000000 / HZ };
1797
1798 if (tv_nz(&tcp->dtime))
1799 tv = tcp->dtime;
1800 else if (tv_cmp(&tv, &one_tick) > 0) {
1801 if (tv_cmp(&shortest, &one_tick) < 0)
1802 tv = shortest;
1803 else
1804 tv = one_tick;
1805 }
1806 }
1807#endif /* LINUX */
1808 if (tv_cmp(&tv, &shortest) < 0)
1809 shortest = tv;
1810 tv_add(&tv_count[tcp->scno],
1811 &tv_count[tcp->scno], &tv);
1812 tcp->flags &= ~TCB_INSYSCALL;
1813 return 0;
1814 }
1815
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001816 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00001817 || (qual_flags[tcp->scno] & QUAL_RAW))
1818 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00001819 else {
1820 if (not_failing_only && tcp->u_error)
1821 return; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001822 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00001823 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00001824 u_error = tcp->u_error;
1825 tprintf(") ");
1826 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001827 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
1828 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00001829 if (u_error)
1830 tprintf("= -1 (errno %ld)", u_error);
1831 else
1832 tprintf("= %#lx", tcp->u_rval);
1833 }
1834 else if (!(sys_res & RVAL_NONE) && u_error) {
1835 switch (u_error) {
1836#ifdef LINUX
1837 case ERESTARTSYS:
1838 tprintf("= ? ERESTARTSYS (To be restarted)");
1839 break;
1840 case ERESTARTNOINTR:
1841 tprintf("= ? ERESTARTNOINTR (To be restarted)");
1842 break;
1843 case ERESTARTNOHAND:
1844 tprintf("= ? ERESTARTNOHAND (To be restarted)");
1845 break;
1846#endif /* LINUX */
1847 default:
1848 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00001849 if (u_error < 0)
1850 tprintf("E??? (errno %ld)", u_error);
1851 else if (u_error < nerrnos && u_error < sys_nerr)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001852 tprintf("%s (%s)", errnoent[u_error],
1853 sys_errlist[u_error]);
1854 else if (u_error < nerrnos)
1855 tprintf("%s (errno %ld)",
1856 errnoent[u_error], u_error);
1857 else if (u_error < sys_nerr)
1858 tprintf("ERRNO_%ld (%s)", u_error,
1859 sys_errlist[u_error]);
1860 else
1861 tprintf("E??? (errno %ld)", u_error);
1862 break;
1863 }
1864 }
1865 else {
1866 if (sys_res & RVAL_NONE)
1867 tprintf("= ?");
1868 else {
1869 switch (sys_res & RVAL_MASK) {
1870 case RVAL_HEX:
1871 tprintf("= %#lx", tcp->u_rval);
1872 break;
1873 case RVAL_OCTAL:
1874 tprintf("= %#lo", tcp->u_rval);
1875 break;
1876 case RVAL_UDECIMAL:
1877 tprintf("= %lu", tcp->u_rval);
1878 break;
1879 case RVAL_DECIMAL:
1880 tprintf("= %ld", tcp->u_rval);
1881 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001882#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001883 case RVAL_LHEX:
1884 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001885 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001886 case RVAL_LOCTAL:
1887 tprintf("= %#llo", tcp->u_lrval);
1888 break;
1889 case RVAL_LUDECIMAL:
1890 tprintf("= %llu", tcp->u_lrval);
1891 break;
1892 case RVAL_LDECIMAL:
1893 tprintf("= %lld", tcp->u_lrval);
1894 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001895#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00001896 default:
1897 fprintf(stderr,
1898 "invalid rval format\n");
1899 break;
1900 }
1901 }
1902 if ((sys_res & RVAL_STR) && tcp->auxstr)
1903 tprintf(" (%s)", tcp->auxstr);
1904 }
1905 if (dtime) {
1906 tv_sub(&tv, &tv, &tcp->etime);
1907 tprintf(" <%ld.%06ld>",
1908 (long) tv.tv_sec, (long) tv.tv_usec);
1909 }
1910 printtrailer(tcp);
1911
1912 dumpio(tcp);
1913 if (fflush(tcp->outf) == EOF)
1914 return -1;
1915 tcp->flags &= ~TCB_INSYSCALL;
1916 return 0;
1917 }
1918
1919 /* Entering system call */
1920 res = syscall_enter(tcp);
1921 if (res != 1)
1922 return res;
1923
Pavel Machekd8ae7e32000-02-01 17:17:25 +00001924 switch (tcp->scno + NR_SYSCALL_BASE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001925#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00001926#if !defined (ALPHA) && !defined(SPARC) && !defined(MIPS) && !defined(HPPA) && !defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001927 case SYS_socketcall:
1928 decode_subcall(tcp, SYS_socket_subcall,
1929 SYS_socket_nsubcalls, deref_style);
1930 break;
1931 case SYS_ipc:
1932 decode_subcall(tcp, SYS_ipc_subcall,
1933 SYS_ipc_nsubcalls, shift_style);
1934 break;
Michal Ludvig0e035502002-09-23 15:41:01 +00001935#endif /* !ALPHA && !MIPS && !SPARC && !HPPA && !X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001936#ifdef SPARC
1937 case SYS_socketcall:
1938 sparc_socket_decode (tcp);
1939 break;
1940#endif
1941#endif /* LINUX */
1942#ifdef SVR4
1943#ifdef SYS_pgrpsys_subcall
1944 case SYS_pgrpsys:
1945 decode_subcall(tcp, SYS_pgrpsys_subcall,
1946 SYS_pgrpsys_nsubcalls, shift_style);
1947 break;
1948#endif /* SYS_pgrpsys_subcall */
1949#ifdef SYS_sigcall_subcall
1950 case SYS_sigcall:
1951 decode_subcall(tcp, SYS_sigcall_subcall,
1952 SYS_sigcall_nsubcalls, mask_style);
1953 break;
1954#endif /* SYS_sigcall_subcall */
1955 case SYS_msgsys:
1956 decode_subcall(tcp, SYS_msgsys_subcall,
1957 SYS_msgsys_nsubcalls, shift_style);
1958 break;
1959 case SYS_shmsys:
1960 decode_subcall(tcp, SYS_shmsys_subcall,
1961 SYS_shmsys_nsubcalls, shift_style);
1962 break;
1963 case SYS_semsys:
1964 decode_subcall(tcp, SYS_semsys_subcall,
1965 SYS_semsys_nsubcalls, shift_style);
1966 break;
1967#if 0 /* broken */
1968 case SYS_utssys:
1969 decode_subcall(tcp, SYS_utssys_subcall,
1970 SYS_utssys_nsubcalls, shift_style);
1971 break;
1972#endif
1973 case SYS_sysfs:
1974 decode_subcall(tcp, SYS_sysfs_subcall,
1975 SYS_sysfs_nsubcalls, shift_style);
1976 break;
1977 case SYS_spcall:
1978 decode_subcall(tcp, SYS_spcall_subcall,
1979 SYS_spcall_nsubcalls, shift_style);
1980 break;
1981#ifdef SYS_context_subcall
1982 case SYS_context:
1983 decode_subcall(tcp, SYS_context_subcall,
1984 SYS_context_nsubcalls, shift_style);
1985 break;
1986#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00001987#ifdef SYS_door_subcall
1988 case SYS_door:
1989 decode_subcall(tcp, SYS_door_subcall,
1990 SYS_door_nsubcalls, door_style);
1991 break;
1992#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00001993#ifdef SYS_kaio_subcall
1994 case SYS_kaio:
1995 decode_subcall(tcp, SYS_kaio_subcall,
1996 SYS_kaio_nsubcalls, shift_style);
1997 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001998#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001999#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002000#ifdef FREEBSD
2001 case SYS_msgsys:
2002 case SYS_shmsys:
2003 case SYS_semsys:
2004 decode_subcall(tcp, 0, 0, table_style);
2005 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002006#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002007#ifdef SUNOS4
2008 case SYS_semsys:
2009 decode_subcall(tcp, SYS_semsys_subcall,
2010 SYS_semsys_nsubcalls, shift_style);
2011 break;
2012 case SYS_msgsys:
2013 decode_subcall(tcp, SYS_msgsys_subcall,
2014 SYS_msgsys_nsubcalls, shift_style);
2015 break;
2016 case SYS_shmsys:
2017 decode_subcall(tcp, SYS_shmsys_subcall,
2018 SYS_shmsys_nsubcalls, shift_style);
2019 break;
2020#endif
2021 }
2022
2023 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002024 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002025 tcp->flags |= TCB_INSYSCALL;
2026 return 0;
2027 }
2028
2029 if (cflag) {
2030 gettimeofday(&tcp->etime, NULL);
2031 tcp->flags |= TCB_INSYSCALL;
2032 return 0;
2033 }
2034
2035 printleader(tcp);
2036 tcp->flags &= ~TCB_REPRINT;
2037 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002038 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002039 tprintf("syscall_%lu(", tcp->scno);
2040 else
2041 tprintf("%s(", sysent[tcp->scno].sys_name);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002042 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002043 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2044 sys_res = printargs(tcp);
2045 else
2046 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2047 if (fflush(tcp->outf) == EOF)
2048 return -1;
2049 tcp->flags |= TCB_INSYSCALL;
2050 /* Measure the entrance time as late as possible to avoid errors. */
2051 if (dtime)
2052 gettimeofday(&tcp->etime, NULL);
2053 return sys_res;
2054}
2055
2056int
2057printargs(tcp)
2058struct tcb *tcp;
2059{
2060 if (entering(tcp)) {
2061 int i;
2062
2063 for (i = 0; i < tcp->u_nargs; i++)
2064 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2065 }
2066 return 0;
2067}
2068
2069long
2070getrval2(tcp)
2071struct tcb *tcp;
2072{
2073 long val = -1;
2074
2075#ifdef LINUX
2076#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002077 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002078 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2079 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002080 val = regs.r_o1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002081#endif /* SPARC */
2082#endif /* LINUX */
2083
2084#ifdef SUNOS4
2085 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2086 return -1;
2087#endif /* SUNOS4 */
2088
2089#ifdef SVR4
2090#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002091 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002092#endif /* SPARC */
2093#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002094 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002095#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002096#ifdef X86_64
2097 val = tcp->status.PR_REG[RDX];
2098#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002099#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002100 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002101#endif /* MIPS */
2102#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002103#ifdef FREEBSD
2104 struct reg regs;
2105 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2106 val = regs.r_edx;
2107#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002108 return val;
2109}
2110
2111/*
2112 * Apparently, indirect system calls have already be converted by ptrace(2),
2113 * so if you see "indir" this program has gone astray.
2114 */
2115int
2116sys_indir(tcp)
2117struct tcb *tcp;
2118{
2119 int i, scno, nargs;
2120
2121 if (entering(tcp)) {
2122 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2123 fprintf(stderr, "Bogus syscall: %u\n", scno);
2124 return 0;
2125 }
2126 nargs = sysent[scno].nargs;
2127 tprintf("%s", sysent[scno].sys_name);
2128 for (i = 0; i < nargs; i++)
2129 tprintf(", %#lx", tcp->u_arg[i+1]);
2130 }
2131 return 0;
2132}
2133
2134static int
2135time_cmp(a, b)
2136void *a;
2137void *b;
2138{
2139 return -tv_cmp(&tv_count[*((int *) a)], &tv_count[*((int *) b)]);
2140}
2141
2142static int
2143syscall_cmp(a, b)
2144void *a;
2145void *b;
2146{
2147 return strcmp(sysent[*((int *) a)].sys_name,
2148 sysent[*((int *) b)].sys_name);
2149}
2150
2151static int
2152count_cmp(a, b)
2153void *a;
2154void *b;
2155{
2156 int m = call_count[*((int *) a)], n = call_count[*((int *) b)];
2157
2158 return (m < n) ? 1 : (m > n) ? -1 : 0;
2159}
2160
2161static int (*sortfun)();
2162static struct timeval overhead = { -1, -1 };
2163
2164void
2165set_sortby(sortby)
2166char *sortby;
2167{
2168 if (strcmp(sortby, "time") == 0)
2169 sortfun = time_cmp;
2170 else if (strcmp(sortby, "calls") == 0)
2171 sortfun = count_cmp;
2172 else if (strcmp(sortby, "name") == 0)
2173 sortfun = syscall_cmp;
2174 else if (strcmp(sortby, "nothing") == 0)
2175 sortfun = NULL;
2176 else {
2177 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2178 exit(1);
2179 }
2180}
2181
2182void set_overhead(n)
2183int n;
2184{
2185 overhead.tv_sec = n / 1000000;
2186 overhead.tv_usec = n % 1000000;
2187}
2188
2189void
2190call_summary(outf)
2191FILE *outf;
2192{
2193 int i, j;
2194 int call_cum, error_cum;
2195 struct timeval tv_cum, dtv;
2196 double percent;
2197 char *dashes = "-------------------------";
2198 char error_str[16];
2199
2200 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2201 if (overhead.tv_sec == -1) {
2202 tv_mul(&overhead, &shortest, 8);
2203 tv_div(&overhead, &overhead, 10);
2204 }
2205 for (i = 0; i < nsyscalls; i++) {
2206 sorted_count[i] = i;
2207 if (call_count[i] == 0)
2208 continue;
2209 tv_mul(&dtv, &overhead, call_count[i]);
2210 tv_sub(&tv_count[i], &tv_count[i], &dtv);
2211 call_cum += call_count[i];
2212 error_cum += error_count[i];
2213 tv_add(&tv_cum, &tv_cum, &tv_count[i]);
2214 }
2215 if (sortfun)
2216 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2217 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2218 "% time", "seconds", "usecs/call",
2219 "calls", "errors", "syscall");
2220 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2221 dashes, dashes, dashes, dashes, dashes, dashes);
2222 for (i = 0; i < nsyscalls; i++) {
2223 j = sorted_count[i];
2224 if (call_count[j] == 0)
2225 continue;
2226 tv_div(&dtv, &tv_count[j], call_count[j]);
2227 if (error_count[j])
2228 sprintf(error_str, "%d", error_count[j]);
2229 else
2230 error_str[0] = '\0';
2231 percent = 100.0*tv_float(&tv_count[j])/tv_float(&tv_cum);
2232 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2233 percent, (long) tv_count[j].tv_sec,
2234 (long) tv_count[j].tv_usec,
2235 (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2236 call_count[j], error_str, sysent[j].sys_name);
2237 }
2238 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2239 dashes, dashes, dashes, dashes, dashes, dashes);
2240 if (error_cum)
2241 sprintf(error_str, "%d", error_cum);
2242 else
2243 error_str[0] = '\0';
2244 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2245 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2246 call_cum, error_str, "total");
2247}