blob: 87f7a82920bef5da1fc8c09e0e0fb70b9bf76852 [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
Roland McGrath761b5d72002-12-15 23:58:31 +000055# undef fpu
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000056#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
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000075#endif
76
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000077#if defined(LINUX) && defined(IA64)
78# include <asm/ptrace_offsets.h>
79# include <asm/rse.h>
80#endif
81
Pavel Machekd8ae7e32000-02-01 17:17:25 +000082#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000083#ifdef LINUX
84#ifndef ERESTARTSYS
85#define ERESTARTSYS 512
86#endif
87#ifndef ERESTARTNOINTR
88#define ERESTARTNOINTR 513
89#endif
90#ifndef ERESTARTNOHAND
91#define ERESTARTNOHAND 514 /* restart if no handler.. */
92#endif
93#ifndef ENOIOCTLCMD
94#define ENOIOCTLCMD 515 /* No ioctl command */
95#endif
Roland McGrath9c555e72003-07-09 09:47:59 +000096#ifndef ERESTART_RESTARTBLOCK
97#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
98#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000099#ifndef NSIG
100#define NSIG 32
101#endif
102#ifdef ARM
103#undef NSIG
104#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000105#undef NR_SYSCALL_BASE
106#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#endif
108#endif /* LINUX */
109
110#include "syscall.h"
111
112/* Define these shorthand notations to simplify the syscallent files. */
113#define TF TRACE_FILE
114#define TI TRACE_IPC
115#define TN TRACE_NETWORK
116#define TP TRACE_PROCESS
117#define TS TRACE_SIGNAL
118
119struct sysent sysent0[] = {
120#include "syscallent.h"
121};
122int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
123
124#if SUPPORTED_PERSONALITIES >= 2
125struct sysent sysent1[] = {
126#include "syscallent1.h"
127};
128int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
129#endif /* SUPPORTED_PERSONALITIES >= 2 */
130
131#if SUPPORTED_PERSONALITIES >= 3
132struct sysent sysent2[] = {
133#include "syscallent2.h"
134};
135int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
136#endif /* SUPPORTED_PERSONALITIES >= 3 */
137
138struct sysent *sysent;
139int nsyscalls;
140
141/* Now undef them since short defines cause wicked namespace pollution. */
142#undef TF
143#undef TI
144#undef TN
145#undef TP
146#undef TS
147
148char *errnoent0[] = {
149#include "errnoent.h"
150};
151int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
152
153#if SUPPORTED_PERSONALITIES >= 2
154char *errnoent1[] = {
155#include "errnoent1.h"
156};
157int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
158#endif /* SUPPORTED_PERSONALITIES >= 2 */
159
160#if SUPPORTED_PERSONALITIES >= 3
161char *errnoent2[] = {
162#include "errnoent2.h"
163};
164int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
165#endif /* SUPPORTED_PERSONALITIES >= 3 */
166
167char **errnoent;
168int nerrnos;
169
170int current_personality;
171
172int
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000173set_personality(personality)
174int personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000175{
176 switch (personality) {
177 case 0:
178 errnoent = errnoent0;
179 nerrnos = nerrnos0;
180 sysent = sysent0;
181 nsyscalls = nsyscalls0;
182 ioctlent = ioctlent0;
183 nioctlents = nioctlents0;
184 signalent = signalent0;
185 nsignals = nsignals0;
186 break;
187
188#if SUPPORTED_PERSONALITIES >= 2
189 case 1:
190 errnoent = errnoent1;
191 nerrnos = nerrnos1;
192 sysent = sysent1;
193 nsyscalls = nsyscalls1;
194 ioctlent = ioctlent1;
195 nioctlents = nioctlents1;
196 signalent = signalent1;
197 nsignals = nsignals1;
198 break;
199#endif /* SUPPORTED_PERSONALITIES >= 2 */
200
201#if SUPPORTED_PERSONALITIES >= 3
202 case 2:
203 errnoent = errnoent2;
204 nerrnos = nerrnos2;
205 sysent = sysent2;
206 nsyscalls = nsyscalls2;
207 ioctlent = ioctlent2;
208 nioctlents = nioctlents2;
209 signalent = signalent2;
210 nsignals = nsignals2;
211 break;
212#endif /* SUPPORTED_PERSONALITIES >= 3 */
213
214 default:
215 return -1;
216 }
217
218 current_personality = personality;
219 return 0;
220}
221
222int qual_flags[MAX_QUALS];
223
224static int call_count[MAX_QUALS];
225static int error_count[MAX_QUALS];
226static struct timeval tv_count[MAX_QUALS];
227static int sorted_count[MAX_QUALS];
228
229static struct timeval shortest = { 1000000, 0 };
230
Roland McGrath9797ceb2002-12-30 10:23:00 +0000231static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000232
233static struct qual_options {
234 int bitflag;
235 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000236 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000237 char *argument_name;
238} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000239 { QUAL_TRACE, "trace", qual_syscall, "system call" },
240 { QUAL_TRACE, "t", qual_syscall, "system call" },
241 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
242 { QUAL_ABBREV, "a", qual_syscall, "system call" },
243 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
244 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
245 { QUAL_RAW, "raw", qual_syscall, "system call" },
246 { QUAL_RAW, "x", qual_syscall, "system call" },
247 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
248 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
249 { QUAL_SIGNAL, "s", qual_signal, "signal" },
250 { QUAL_FAULT, "fault", qual_fault, "fault" },
251 { QUAL_FAULT, "faults", qual_fault, "fault" },
252 { QUAL_FAULT, "m", qual_fault, "fault" },
253 { QUAL_READ, "read", qual_desc, "descriptor" },
254 { QUAL_READ, "reads", qual_desc, "descriptor" },
255 { QUAL_READ, "r", qual_desc, "descriptor" },
256 { QUAL_WRITE, "write", qual_desc, "descriptor" },
257 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
258 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000259 { 0, NULL, NULL, NULL },
260};
261
Roland McGrath9797ceb2002-12-30 10:23:00 +0000262static void
263qualify_one(n, opt, not)
264 int n;
265 struct qual_options *opt;
266 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000267{
Roland McGrath9797ceb2002-12-30 10:23:00 +0000268 if (not)
269 qual_flags[n] &= ~opt->bitflag;
270 else
271 qual_flags[n] |= opt->bitflag;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000272}
273
274static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000275qual_syscall(s, opt, not)
276 char *s;
277 struct qual_options *opt;
278 int not;
279{
280 int i;
281 int any = 0;
282
283 for (i = 0; i < nsyscalls; i++) {
284 if (strcmp(s, sysent[i].sys_name) == 0) {
285 qualify_one(i, opt, not);
286 any = 1;
287 }
288 }
289 return !any;
290}
291
292static int
293qual_signal(s, opt, not)
294 char *s;
295 struct qual_options *opt;
296 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000297{
298 int i;
299 char buf[32];
300
Roland McGrath9797ceb2002-12-30 10:23:00 +0000301 if (s && *s && isdigit((unsigned char)*s)) {
302 qualify_one(atoi(s), opt, not);
303 return 1;
304 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000305 strcpy(buf, s);
306 s = buf;
307 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000308 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000309 if (strncmp(s, "SIG", 3) == 0)
310 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000311 for (i = 0; i <= NSIG; i++)
312 if (strcmp(s, signame(i) + 3) == 0) {
313 qualify_one(atoi(s), opt, not);
314 return 1;
315 }
316 return 0;
317}
318
319static int
320qual_fault(s, opt, not)
321 char *s;
322 struct qual_options *opt;
323 int not;
324{
325 return -1;
326}
327
328static int
329qual_desc(s, opt, not)
330 char *s;
331 struct qual_options *opt;
332 int not;
333{
334 if (s && *s && isdigit((unsigned char)*s)) {
335 qualify_one(atoi(s), opt, not);
Roland McGrath2b619022003-04-10 18:58:20 +0000336 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000337 }
338 return -1;
339}
340
341static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000342lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000343 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000344{
345 if (strcmp(s, "file") == 0)
346 return TRACE_FILE;
347 if (strcmp(s, "ipc") == 0)
348 return TRACE_IPC;
349 if (strcmp(s, "network") == 0)
350 return TRACE_NETWORK;
351 if (strcmp(s, "process") == 0)
352 return TRACE_PROCESS;
353 if (strcmp(s, "signal") == 0)
354 return TRACE_SIGNAL;
355 return -1;
356}
357
358void
359qualify(s)
360char *s;
361{
362 struct qual_options *opt;
363 int not;
364 char *p;
365 int i, n;
366
367 opt = &qual_options[0];
368 for (i = 0; (p = qual_options[i].option_name); i++) {
369 n = strlen(p);
370 if (strncmp(s, p, n) == 0 && s[n] == '=') {
371 opt = &qual_options[i];
372 s += n + 1;
373 break;
374 }
375 }
376 not = 0;
377 if (*s == '!') {
378 not = 1;
379 s++;
380 }
381 if (strcmp(s, "none") == 0) {
382 not = 1 - not;
383 s = "all";
384 }
385 if (strcmp(s, "all") == 0) {
386 for (i = 0; i < MAX_QUALS; i++) {
387 if (not)
388 qual_flags[i] &= ~opt->bitflag;
389 else
390 qual_flags[i] |= opt->bitflag;
391 }
392 return;
393 }
394 for (i = 0; i < MAX_QUALS; i++) {
395 if (not)
396 qual_flags[i] |= opt->bitflag;
397 else
398 qual_flags[i] &= ~opt->bitflag;
399 }
400 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
401 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
402 for (i = 0; i < MAX_QUALS; i++) {
403 if (sysent[i].sys_flags & n) {
404 if (not)
405 qual_flags[i] &= ~opt->bitflag;
406 else
407 qual_flags[i] |= opt->bitflag;
408 }
409 }
410 continue;
411 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000412 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000413 fprintf(stderr, "strace: invalid %s `%s'\n",
414 opt->argument_name, p);
415 exit(1);
416 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417 }
418 return;
419}
420
421static void
422dumpio(tcp)
423struct tcb *tcp;
424{
425 if (syserror(tcp))
426 return;
427 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
428 return;
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000429 switch (tcp->scno + NR_SYSCALL_BASE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430 case SYS_read:
431#ifdef SYS_recv
432 case SYS_recv:
433#endif
434#ifdef SYS_recvfrom
435 case SYS_recvfrom:
436#endif
437 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
438 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
439 break;
440 case SYS_write:
441#ifdef SYS_send
442 case SYS_send:
443#endif
444#ifdef SYS_sendto
445 case SYS_sendto:
446#endif
447 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
448 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
449 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000450#ifdef SYS_readv
451 case SYS_readv:
452 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
453 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
454 break;
455#endif
456#ifdef SYS_writev
457 case SYS_writev:
458
459 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
460 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
461 break;
462#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 }
464}
465
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000466#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000467enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000468#else /* FREEBSD */
469enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
470
471struct subcall {
472 int call;
473 int nsubcalls;
474 int subcalls[5];
475};
476
477const struct subcall subcalls_table[] = {
478 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000479#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000480 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000481#else
482 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
483#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000484 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
485};
486#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000488#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000489
490const int socket_map [] = {
491 /* SYS_SOCKET */ 97,
492 /* SYS_BIND */ 104,
493 /* SYS_CONNECT */ 98,
494 /* SYS_LISTEN */ 106,
495 /* SYS_ACCEPT */ 99,
496 /* SYS_GETSOCKNAME */ 150,
497 /* SYS_GETPEERNAME */ 141,
498 /* SYS_SOCKETPAIR */ 135,
499 /* SYS_SEND */ 101,
500 /* SYS_RECV */ 102,
501 /* SYS_SENDTO */ 133,
502 /* SYS_RECVFROM */ 125,
503 /* SYS_SHUTDOWN */ 134,
504 /* SYS_SETSOCKOPT */ 105,
505 /* SYS_GETSOCKOPT */ 118,
506 /* SYS_SENDMSG */ 114,
507 /* SYS_RECVMSG */ 113
508};
509
510void
Wichert Akkermane6f876c1999-06-22 15:28:30 +0000511sparc_socket_decode (tcp)
512struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000513{
514 volatile long addr;
515 volatile int i, n;
516
517 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){
518 return;
519 }
520 tcp->scno = socket_map [tcp->u_arg [0]-1];
521 n = tcp->u_nargs = sysent [tcp->scno].nargs;
522 addr = tcp->u_arg [1];
523 for (i = 0; i < n; i++){
524 int arg;
525 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0)
526 arg = 0;
527 tcp->u_arg [i] = arg;
528 addr += sizeof (arg);
529 }
530}
531
Michal Ludvig0e035502002-09-23 15:41:01 +0000532void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000533decode_subcall(tcp, subcall, nsubcalls, style)
534struct tcb *tcp;
535int subcall;
536int nsubcalls;
537enum subcall_style style;
538{
Michal Ludvig10a88d02002-10-07 14:31:00 +0000539 long addr, mask, arg;
540 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000541
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000542 switch (style) {
543 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000544 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
545 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000546 tcp->scno = subcall + tcp->u_arg[0];
547 if (sysent[tcp->scno].nargs != -1)
548 tcp->u_nargs = sysent[tcp->scno].nargs;
549 else
550 tcp->u_nargs--;
551 for (i = 0; i < tcp->u_nargs; i++)
552 tcp->u_arg[i] = tcp->u_arg[i + 1];
553 break;
554 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000555 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
556 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000557 tcp->scno = subcall + tcp->u_arg[0];
558 addr = tcp->u_arg[1];
559 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
560 if (umove(tcp, addr, &arg) < 0)
561 arg = 0;
562 tcp->u_arg[i] = arg;
563 addr += sizeof(arg);
564 }
565 tcp->u_nargs = sysent[tcp->scno].nargs;
566 break;
567 case mask_style:
568 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569 for (i = 0; mask; i++)
570 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000571 if (i >= nsubcalls)
572 return;
573 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000574 tcp->scno = subcall + i;
575 if (sysent[tcp->scno].nargs != -1)
576 tcp->u_nargs = sysent[tcp->scno].nargs;
577 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000578 case door_style:
579 /*
580 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000581 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000582 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000583 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
584 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000585 tcp->scno = subcall + tcp->u_arg[5];
586 if (sysent[tcp->scno].nargs != -1)
587 tcp->u_nargs = sysent[tcp->scno].nargs;
588 else
589 tcp->u_nargs--;
590 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000591#ifdef FREEBSD
592 case table_style:
593 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
594 if (subcalls_table[i].call == tcp->scno) break;
595 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
596 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
597 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
598 for (i = 0; i < tcp->u_nargs; i++)
599 tcp->u_arg[i] = tcp->u_arg[i + 1];
600 }
601 break;
602#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000603 }
604}
605#endif
606
607struct tcb *tcp_last = NULL;
608
609static int
610internal_syscall(tcp)
611struct tcb *tcp;
612{
613 /*
614 * We must always trace a few critical system calls in order to
615 * correctly support following forks in the presence of tracing
616 * qualifiers.
617 */
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000618 switch (tcp->scno + NR_SYSCALL_BASE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000619#ifdef SYS_fork
620 case SYS_fork:
621#endif
622#ifdef SYS_vfork
623 case SYS_vfork:
624#endif
John Hughes4e36a812001-04-18 15:11:51 +0000625#ifdef SYS_fork1
626 case SYS_fork1:
627#endif
628#ifdef SYS_forkall
629 case SYS_forkall:
630#endif
631#ifdef SYS_rfork1
632 case SYS_rfork1:
633#endif
634#ifdef SYS_rforkall
635 case SYS_rforkall:
636#endif
Roland McGrathf3a0e1b2003-02-20 02:45:22 +0000637#ifdef SYS_rfork
638 case SYS_rfork:
639#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640 internal_fork(tcp);
641 break;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000642#ifdef SYS_clone
643 case SYS_clone:
644 internal_clone(tcp);
645 break;
646#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000647#ifdef SYS_clone2
648 case SYS_clone2:
649 internal_clone(tcp);
650 break;
651#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000652#ifdef SYS_execv
653 case SYS_execv:
654#endif
655#ifdef SYS_execve
656 case SYS_execve:
657#endif
John Hughes4e36a812001-04-18 15:11:51 +0000658#ifdef SYS_rexecve
659 case SYS_rexecve:
660#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661 internal_exec(tcp);
662 break;
663
664#ifdef SYS_wait
665 case SYS_wait:
666#endif
667#ifdef SYS_wait4
668 case SYS_wait4:
669#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000670#ifdef SYS32_wait4
671 case SYS32_wait4:
672#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000673#ifdef SYS_waitpid
674 case SYS_waitpid:
675#endif
676#ifdef SYS_waitsys
677 case SYS_waitsys:
678#endif
679 internal_wait(tcp);
680 break;
681
682#ifdef SYS_exit
683 case SYS_exit:
684#endif
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000685#ifdef SYS32_exit
686 case SYS32_exit:
687#endif
Roland McGrath923f7502003-01-09 06:53:27 +0000688#ifdef __NR_exit_group
689 case __NR_exit_group:
690#endif
Roland McGrath08267b82004-02-20 22:56:43 +0000691#ifdef IA64
692 case 252: /* IA-32 __NR_exit_group */
693#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000694 internal_exit(tcp);
695 break;
696 }
697 return 0;
698}
699
Wichert Akkermanc7926982000-04-10 22:22:31 +0000700
701#ifdef LINUX
702#if defined (I386)
703 static long eax;
704#elif defined (IA64)
705 long r8, r10, psr;
706 long ia32 = 0;
707#elif defined (POWERPC)
708 static long result,flags;
709#elif defined (M68K)
710 static int d0;
711#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000712 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000713#elif defined (ALPHA)
714 static long r0;
715 static long a3;
716#elif defined (SPARC)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000717 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000718 static unsigned long trap;
719#elif defined(MIPS)
720 static long a3;
721 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000722#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000723 static long gpr2;
724 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000725 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000726#elif defined(HPPA)
727 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000728#elif defined(SH)
729 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000730#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000731 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000732#elif defined(X86_64)
733 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000734#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000735#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000736#ifdef FREEBSD
737 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000738#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000739
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000740int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000741get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000742struct tcb *tcp;
743{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000744 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000745#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000747#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000748
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000749#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000750#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000751 if (tcp->flags & TCB_WAITEXECVE) {
752 /*
753 * When the execve system call completes successfully, the
754 * new process still has -ENOSYS (old style) or __NR_execve
755 * (new style) in gpr2. We cannot recover the scno again
756 * by disassembly, because the image that executed the
757 * syscall is gone now. Fortunately, we don't want it. We
758 * leave the flag set so that syscall_fixup can fake the
759 * result.
760 */
761 if (tcp->flags & TCB_INSYSCALL)
762 return 1;
763 /*
764 * This is the SIGTRAP after execve. We cannot try to read
765 * the system call here either.
766 */
767 tcp->flags &= ~TCB_WAITEXECVE;
768 return 0;
769 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000770
771 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
772 return -1;
773
774 if (syscall_mode != -ENOSYS) {
775 /*
776 * Since kernel version 2.5.44 the scno gets passed in gpr2.
777 */
778 scno = syscall_mode;
779 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000780 /*
781 * Old style of "passing" the scno via the SVC instruction.
782 */
783
784 long opcode, offset_reg, tmp;
785 void * svc_addr;
786 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
787 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
788 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
789 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000790
Michal Ludvig882eda82002-11-11 12:50:47 +0000791 if (upeek(pid, PT_PSWADDR, &pc) < 0)
792 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000793 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000794 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000795 if (errno) {
796 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000797 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000798 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000799
800 /*
801 * We have to check if the SVC got executed directly or via an
802 * EXECUTE instruction. In case of EXECUTE it is necessary to do
803 * instruction decoding to derive the system call number.
804 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
805 * so that this doesn't work if a SVC opcode is part of an EXECUTE
806 * opcode. Since there is no way to find out the opcode size this
807 * is the best we can do...
808 */
809
810 if ((opcode & 0xff00) == 0x0a00) {
811 /* SVC opcode */
812 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000813 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000814 else {
815 /* SVC got executed by EXECUTE instruction */
816
817 /*
818 * Do instruction decoding of EXECUTE. If you really want to
819 * understand this, read the Principles of Operations.
820 */
821 svc_addr = (void *) (opcode & 0xfff);
822
823 tmp = 0;
824 offset_reg = (opcode & 0x000f0000) >> 16;
825 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
826 return -1;
827 svc_addr += tmp;
828
829 tmp = 0;
830 offset_reg = (opcode & 0x0000f000) >> 12;
831 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
832 return -1;
833 svc_addr += tmp;
834
835 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
836 if (errno)
837 return -1;
838#if defined(S390X)
839 scno >>= 48;
840#else
841 scno >>= 16;
842#endif
843 tmp = 0;
844 offset_reg = (opcode & 0x00f00000) >> 20;
845 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
846 return -1;
847
848 scno = (scno | tmp) & 0xff;
849 }
850 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000851#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000852 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000853 return -1;
854 if (!(tcp->flags & TCB_INSYSCALL)) {
855 /* Check if we return from execve. */
856 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
857 tcp->flags &= ~TCB_WAITEXECVE;
858 return 0;
859 }
860 }
861#elif defined (I386)
862 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
863 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000864#elif defined (X86_64)
865 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
866 return -1;
867
Roland McGrath761b5d72002-12-15 23:58:31 +0000868 if (!(tcp->flags & TCB_INSYSCALL)) {
869 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000870 long val;
871
872 /* Check CS register value. On x86-64 linux it is:
873 * 0x33 for long mode (64 bit)
874 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000875 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000876 * to be cached.
877 */
878 if (upeek(pid, 8*CS, &val) < 0)
879 return -1;
880 switch(val)
881 {
882 case 0x23: currpers = 1; break;
883 case 0x33: currpers = 0; break;
884 default:
885 fprintf(stderr, "Unknown value CS=0x%02X while "
886 "detecting personality of process "
887 "PID=%d\n", (int)val, pid);
888 currpers = current_personality;
889 break;
890 }
891#if 0
892 /* This version analyzes the opcode of a syscall instruction.
893 * (int 0x80 on i386 vs. syscall on x86-64)
894 * It works, but is too complicated.
895 */
896 unsigned long val, rip, i;
897
898 if(upeek(pid, 8*RIP, &rip)<0)
899 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000900
Michal Ludvig0e035502002-09-23 15:41:01 +0000901 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
902 rip-=2;
903 errno = 0;
904
Roland McGrath761b5d72002-12-15 23:58:31 +0000905 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
906 if (errno)
907 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000908 strerror(errno));
909 switch (call & 0xffff)
910 {
911 /* x86-64: syscall = 0x0f 0x05 */
912 case 0x050f: currpers = 0; break;
913 /* i386: int 0x80 = 0xcd 0x80 */
914 case 0x80cd: currpers = 1; break;
915 default:
916 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000917 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000918 "Unknown syscall opcode (0x%04X) while "
919 "detecting personality of process "
920 "PID=%d\n", (int)call, pid);
921 break;
922 }
923#endif
924 if(currpers != current_personality)
925 {
926 char *names[]={"64 bit", "32 bit"};
927 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000928 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000929 pid, names[current_personality]);
930 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000931 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000932#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000933# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000934 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000935 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000936 if (!(tcp->flags & TCB_INSYSCALL)) {
937 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000938 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000939 return -1;
940 } else {
941 if (upeek (pid, PT_R15, &scno) < 0)
942 return -1;
943 }
Roland McGrathba954762003-03-05 06:29:06 +0000944 /* Check if we return from execve. */
945 if (tcp->flags & TCB_WAITEXECVE) {
946 tcp->flags &= ~TCB_WAITEXECVE;
947 return 0;
948 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000949 } else {
950 /* syscall in progress */
951 if (upeek (pid, PT_R8, &r8) < 0)
952 return -1;
953 if (upeek (pid, PT_R10, &r10) < 0)
954 return -1;
955 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000956#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000957 /*
958 * Read complete register set in one go.
959 */
960 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
961 return -1;
962
963 /*
964 * We only need to grab the syscall number on syscall entry.
965 */
966 if (regs.ARM_ip == 0) {
967 /*
968 * Note: we only deal with only 32-bit CPUs here.
969 */
970 if (regs.ARM_cpsr & 0x20) {
971 /*
972 * Get the Thumb-mode system call number
973 */
974 scno = regs.ARM_r7;
975 } else {
976 /*
977 * Get the ARM-mode system call number
978 */
979 errno = 0;
980 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
981 if (errno)
982 return -1;
983
984 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
985 tcp->flags &= ~TCB_WAITEXECVE;
986 return 0;
987 }
988
989 if ((scno & 0x0ff00000) != 0x0f900000) {
990 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
991 scno);
992 return -1;
993 }
994
995 /*
996 * Fixup the syscall number
997 */
998 scno &= 0x000fffff;
999 }
1000
1001 if (tcp->flags & TCB_INSYSCALL) {
1002 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1003 tcp->flags &= ~TCB_INSYSCALL;
1004 }
1005 } else {
1006 if (!(tcp->flags & TCB_INSYSCALL)) {
1007 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1008 tcp->flags |= TCB_INSYSCALL;
1009 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001010 }
1011#elif defined (M68K)
1012 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1013 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001014#elif defined (MIPS)
1015 if (upeek(pid, REG_A3, &a3) < 0)
1016 return -1;
1017
1018 if(!(tcp->flags & TCB_INSYSCALL)) {
1019 if (upeek(pid, REG_V0, &scno) < 0)
1020 return -1;
1021
1022 if (scno < 0 || scno > nsyscalls) {
1023 if(a3 == 0 || a3 == -1) {
1024 if(debug)
1025 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1026 return 0;
1027 }
1028 }
1029 } else {
1030 if (upeek(pid, REG_V0, &r2) < 0)
1031 return -1;
1032 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033#elif defined (ALPHA)
1034 if (upeek(pid, REG_A3, &a3) < 0)
1035 return -1;
1036
1037 if (!(tcp->flags & TCB_INSYSCALL)) {
1038 if (upeek(pid, REG_R0, &scno) < 0)
1039 return -1;
1040
1041 /* Check if we return from execve. */
1042 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1043 tcp->flags &= ~TCB_WAITEXECVE;
1044 return 0;
1045 }
1046
1047 /*
1048 * Do some sanity checks to figure out if it's
1049 * really a syscall entry
1050 */
1051 if (scno < 0 || scno > nsyscalls) {
1052 if (a3 == 0 || a3 == -1) {
1053 if (debug)
1054 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1055 return 0;
1056 }
1057 }
1058 }
1059 else {
1060 if (upeek(pid, REG_R0, &r0) < 0)
1061 return -1;
1062 }
1063#elif defined (SPARC)
1064 /* Everything we need is in the current register set. */
1065 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1066 return -1;
1067
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001068 /* If we are entering, then disassemble the syscall trap. */
1069 if (!(tcp->flags & TCB_INSYSCALL)) {
1070 /* Retrieve the syscall trap instruction. */
1071 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001072 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073 if (errno)
1074 return -1;
1075
1076 /* Disassemble the trap to see what personality to use. */
1077 switch (trap) {
1078 case 0x91d02010:
1079 /* Linux/SPARC syscall trap. */
1080 set_personality(0);
1081 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001082 case 0x91d0206d:
1083 /* Linux/SPARC64 syscall trap. */
1084 fprintf(stderr,"syscall: Linux/SPARC64 not supported yet\n");
1085 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 case 0x91d02000:
1087 /* SunOS syscall trap. (pers 1) */
1088 fprintf(stderr,"syscall: SunOS no support\n");
1089 return -1;
1090 case 0x91d02008:
1091 /* Solaris 2.x syscall trap. (per 2) */
1092 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001093 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094 case 0x91d02009:
1095 /* NetBSD/FreeBSD syscall trap. */
1096 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1097 return -1;
1098 case 0x91d02027:
1099 /* Solaris 2.x gettimeofday */
1100 set_personality(1);
1101 break;
1102 default:
1103 /* Unknown syscall trap. */
1104 if(tcp->flags & TCB_WAITEXECVE) {
1105 tcp->flags &= ~TCB_WAITEXECVE;
1106 return 0;
1107 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001108 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001109 return -1;
1110 }
1111
1112 /* Extract the system call number from the registers. */
1113 if (trap == 0x91d02027)
1114 scno = 156;
1115 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001116 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001118 scno = regs.r_o0;
1119 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 }
1121 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001122#elif defined(HPPA)
1123 if (upeek(pid, PT_GR20, &scno) < 0)
1124 return -1;
1125 if (!(tcp->flags & TCB_INSYSCALL)) {
1126 /* Check if we return from execve. */
1127 if ((tcp->flags & TCB_WAITEXECVE)) {
1128 tcp->flags &= ~TCB_WAITEXECVE;
1129 return 0;
1130 }
1131 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001132#elif defined(SH)
1133 /*
1134 * In the new syscall ABI, the system call number is in R3.
1135 */
1136 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1137 return -1;
1138
1139 if (scno < 0) {
1140 /* Odd as it may seem, a glibc bug has been known to cause
1141 glibc to issue bogus negative syscall numbers. So for
1142 our purposes, make strace print what it *should* have been */
1143 long correct_scno = (scno & 0xff);
1144 if (debug)
1145 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001146 "Detected glibc bug: bogus system call number = %ld, "
1147 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001148 scno,
1149 correct_scno);
1150 scno = correct_scno;
1151 }
1152
1153
1154 if (!(tcp->flags & TCB_INSYSCALL)) {
1155 /* Check if we return from execve. */
1156 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1157 tcp->flags &= ~TCB_WAITEXECVE;
1158 return 0;
1159 }
1160 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001161#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001162 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1163 return -1;
1164 scno &= 0xFFFF;
1165
1166 if (!(tcp->flags & TCB_INSYSCALL)) {
1167 /* Check if we return from execve. */
1168 if (tcp->flags & TCB_WAITEXECVE) {
1169 tcp->flags &= ~TCB_WAITEXECVE;
1170 return 0;
1171 }
1172 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001173#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174#endif /* LINUX */
1175#ifdef SUNOS4
1176 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1177 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001178#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001179 /* new syscall ABI returns result in R0 */
1180 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1181 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001182#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001183 /* ABI defines result returned in r9 */
1184 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1185 return -1;
1186
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001187#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001188#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001190 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001192#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001193 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001194#else /* FREEBSD */
1195 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1196 perror("pread");
1197 return -1;
1198 }
1199 switch (regs.r_eax) {
1200 case SYS_syscall:
1201 case SYS___syscall:
1202 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1203 break;
1204 default:
1205 scno = regs.r_eax;
1206 break;
1207 }
1208#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001209#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001210#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001211 if (!(tcp->flags & TCB_INSYSCALL))
1212 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001213 return 1;
1214}
1215
Pavel Machek4dc3b142000-02-01 17:58:41 +00001216
1217int
1218syscall_fixup(tcp)
1219struct tcb *tcp;
1220{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001221#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001222 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001223#else /* USE_PROCFS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001224 int scno = tcp->scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001225
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001226 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001227 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001228 if (
1229 scno == SYS_fork
1230#ifdef SYS_vfork
1231 || scno == SYS_vfork
1232#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001233#ifdef SYS_fork1
1234 || scno == SYS_fork1
1235#endif /* SYS_fork1 */
1236#ifdef SYS_forkall
1237 || scno == SYS_forkall
1238#endif /* SYS_forkall */
1239#ifdef SYS_rfork1
1240 || scno == SYS_rfork1
1241#endif /* SYS_fork1 */
1242#ifdef SYS_rforkall
1243 || scno == SYS_rforkall
1244#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245 ) {
1246 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001247 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001249 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250 }
1251 else {
1252 fprintf(stderr, "syscall: missing entry\n");
1253 tcp->flags |= TCB_INSYSCALL;
1254 }
1255 }
1256 }
1257 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001258 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001259 fprintf(stderr, "syscall: missing exit\n");
1260 tcp->flags &= ~TCB_INSYSCALL;
1261 }
1262 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001263#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001264#ifdef SUNOS4
1265 if (!(tcp->flags & TCB_INSYSCALL)) {
1266 if (scno == 0) {
1267 fprintf(stderr, "syscall: missing entry\n");
1268 tcp->flags |= TCB_INSYSCALL;
1269 }
1270 }
1271 else {
1272 if (scno != 0) {
1273 if (debug) {
1274 /*
1275 * This happens when a signal handler
1276 * for a signal which interrupted a
1277 * a system call makes another system call.
1278 */
1279 fprintf(stderr, "syscall: missing exit\n");
1280 }
1281 tcp->flags &= ~TCB_INSYSCALL;
1282 }
1283 }
1284#endif /* SUNOS4 */
1285#ifdef LINUX
1286#if defined (I386)
1287 if (upeek(pid, 4*EAX, &eax) < 0)
1288 return -1;
1289 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1290 if (debug)
1291 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1292 return 0;
1293 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001294#elif defined (X86_64)
1295 if (upeek(pid, 8*RAX, &rax) < 0)
1296 return -1;
1297 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1298 if (debug)
1299 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1300 return 0;
1301 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001302#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001303 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1304 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001305 if (syscall_mode != -ENOSYS)
1306 syscall_mode = tcp->scno;
1307 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001308 if (debug)
1309 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1310 return 0;
1311 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001312 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1313 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1314 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1315 /*
1316 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1317 * flag set for the post-execve SIGTRAP to see and reset.
1318 */
1319 gpr2 = 0;
1320 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001321#elif defined (POWERPC)
1322# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001323 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001324 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001325 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001326 return -1;
1327 if (flags & SO_MASK)
1328 result = -result;
1329#elif defined (M68K)
1330 if (upeek(pid, 4*PT_D0, &d0) < 0)
1331 return -1;
1332 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1333 if (debug)
1334 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1335 return 0;
1336 }
1337#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001338 /*
1339 * Nothing required
1340 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001341#elif defined (HPPA)
1342 if (upeek(pid, PT_GR28, &r28) < 0)
1343 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001344#elif defined(IA64)
1345 if (upeek(pid, PT_R10, &r10) < 0)
1346 return -1;
1347 if (upeek(pid, PT_R8, &r8) < 0)
1348 return -1;
1349 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1350 if (debug)
1351 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1352 return 0;
1353 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354#endif
1355#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001356 return 1;
1357}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001358
Pavel Machek4dc3b142000-02-01 17:58:41 +00001359int
1360get_error(tcp)
1361struct tcb *tcp;
1362{
1363 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001364#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001365#if defined(S390) || defined(S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001366 if (gpr2 && (unsigned) -gpr2 < nerrnos) {
1367 tcp->u_rval = -1;
1368 u_error = -gpr2;
1369 }
1370 else {
1371 tcp->u_rval = gpr2;
1372 u_error = 0;
1373 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001374#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375#ifdef I386
1376 if (eax < 0 && -eax < nerrnos) {
1377 tcp->u_rval = -1;
1378 u_error = -eax;
1379 }
1380 else {
1381 tcp->u_rval = eax;
1382 u_error = 0;
1383 }
1384#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001385#ifdef X86_64
1386 if (rax < 0 && -rax < nerrnos) {
1387 tcp->u_rval = -1;
1388 u_error = -rax;
1389 }
1390 else {
1391 tcp->u_rval = rax;
1392 u_error = 0;
1393 }
1394#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001395#ifdef IA64
1396 if (ia32) {
1397 int err;
1398
1399 err = (int)r8;
1400 if (err < 0 && -err < nerrnos) {
1401 tcp->u_rval = -1;
1402 u_error = -err;
1403 }
1404 else {
1405 tcp->u_rval = err;
1406 u_error = 0;
1407 }
1408 } else {
1409 if (r10) {
1410 tcp->u_rval = -1;
1411 u_error = r8;
1412 } else {
1413 tcp->u_rval = r8;
1414 u_error = 0;
1415 }
1416 }
1417#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001418#ifdef MIPS
1419 if (a3) {
1420 tcp->u_rval = -1;
1421 u_error = r2;
1422 } else {
1423 tcp->u_rval = r2;
1424 u_error = 0;
1425 }
1426#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001427#ifdef POWERPC
Roland McGrath190f8dd2004-01-13 10:13:44 +00001428 if (result && (unsigned long) -result < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001429 tcp->u_rval = -1;
1430 u_error = -result;
1431 }
1432 else {
1433 tcp->u_rval = result;
1434 u_error = 0;
1435 }
1436#else /* !POWERPC */
1437#ifdef M68K
1438 if (d0 && (unsigned) -d0 < nerrnos) {
1439 tcp->u_rval = -1;
1440 u_error = -d0;
1441 }
1442 else {
1443 tcp->u_rval = d0;
1444 u_error = 0;
1445 }
1446#else /* !M68K */
1447#ifdef ARM
Roland McGrath0f87c492003-06-03 23:29:04 +00001448 if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001449 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001450 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451 }
1452 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001453 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454 u_error = 0;
1455 }
1456#else /* !ARM */
1457#ifdef ALPHA
1458 if (a3) {
1459 tcp->u_rval = -1;
1460 u_error = r0;
1461 }
1462 else {
1463 tcp->u_rval = r0;
1464 u_error = 0;
1465 }
1466#else /* !ALPHA */
1467#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001468 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001469 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001470 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001471 }
1472 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001473 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001474 u_error = 0;
1475 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001476#else /* !SPARC */
1477#ifdef HPPA
1478 if (r28 && (unsigned) -r28 < nerrnos) {
1479 tcp->u_rval = -1;
1480 u_error = -r28;
1481 }
1482 else {
1483 tcp->u_rval = r28;
1484 u_error = 0;
1485 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001486#else
1487#ifdef SH
1488 /* interpret R0 as return value or error number */
1489 if (r0 && (unsigned) -r0 < nerrnos) {
1490 tcp->u_rval = -1;
1491 u_error = -r0;
1492 }
1493 else {
1494 tcp->u_rval = r0;
1495 u_error = 0;
1496 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001497#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001498#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001499 /* interpret result as return value or error number */
1500 if (r9 && (unsigned) -r9 < nerrnos) {
1501 tcp->u_rval = -1;
1502 u_error = -r9;
1503 }
1504 else {
1505 tcp->u_rval = r9;
1506 u_error = 0;
1507 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001508#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001509#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001510#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001511#endif /* SPARC */
1512#endif /* ALPHA */
1513#endif /* ARM */
1514#endif /* M68K */
1515#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001516#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001517#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001518#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001519#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001520#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001521#endif /* LINUX */
1522#ifdef SUNOS4
1523 /* get error code from user struct */
1524 if (upeek(pid, uoff(u_error), &u_error) < 0)
1525 return -1;
1526 u_error >>= 24; /* u_error is a char */
1527
1528 /* get system call return value */
1529 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1530 return -1;
1531#endif /* SUNOS4 */
1532#ifdef SVR4
1533#ifdef SPARC
1534 /* Judicious guessing goes a long way. */
1535 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1536 tcp->u_rval = -1;
1537 u_error = tcp->status.pr_reg[R_O0];
1538 }
1539 else {
1540 tcp->u_rval = tcp->status.pr_reg[R_O0];
1541 u_error = 0;
1542 }
1543#endif /* SPARC */
1544#ifdef I386
1545 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001546 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001548 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001549 }
1550 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001551 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001552#ifdef HAVE_LONG_LONG
1553 tcp->u_lrval =
1554 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1555 tcp->status.PR_REG[EAX];
1556#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001557 u_error = 0;
1558 }
1559#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001560#ifdef X86_64
1561 /* Wanna know how to kill an hour single-stepping? */
1562 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1563 tcp->u_rval = -1;
1564 u_error = tcp->status.PR_REG[RAX];
1565 }
1566 else {
1567 tcp->u_rval = tcp->status.PR_REG[RAX];
1568 u_error = 0;
1569 }
1570#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001571#ifdef MIPS
1572 if (tcp->status.pr_reg[CTX_A3]) {
1573 tcp->u_rval = -1;
1574 u_error = tcp->status.pr_reg[CTX_V0];
1575 }
1576 else {
1577 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1578 u_error = 0;
1579 }
1580#endif /* MIPS */
1581#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001582#ifdef FREEBSD
1583 if (regs.r_eflags & PSL_C) {
1584 tcp->u_rval = -1;
1585 u_error = regs.r_eax;
1586 } else {
1587 tcp->u_rval = regs.r_eax;
1588 tcp->u_lrval =
1589 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1590 u_error = 0;
1591 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001592#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001593 tcp->u_error = u_error;
1594 return 1;
1595}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596
Roland McGrathb69f81b2002-12-21 23:25:18 +00001597int
1598force_result(tcp, error, rval)
1599 struct tcb *tcp;
1600 int error;
1601 long rval;
1602{
1603#ifdef LINUX
1604#if defined(S390) || defined(S390X)
1605 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001606 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1607 return -1;
1608#else /* !S390 && !S390X */
1609#ifdef I386
1610 eax = error ? -error : rval;
1611 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1612 return -1;
1613#else /* !I386 */
1614#ifdef X86_64
1615 rax = error ? -error : rval;
1616 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 4), rax) < 0)
1617 return -1;
1618#else
1619#ifdef IA64
1620 if (ia32) {
1621 r8 = error ? -error : rval;
1622 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1623 return -1;
1624 }
1625 else {
1626 if (error) {
1627 r8 = error;
1628 r10 = -1;
1629 }
1630 else {
1631 r8 = rval;
1632 r10 = 0;
1633 }
1634 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1635 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1636 return -1;
1637 }
1638#else /* !IA64 */
1639#ifdef MIPS
1640 if (error) {
1641 r2 = error;
1642 a3 = -1;
1643 }
1644 else {
1645 r2 = rval;
1646 a3 = 0;
1647 }
1648 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1649 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1650 return -1;
1651#else
1652#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001653 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001654 return -1;
1655 if (error) {
1656 flags |= SO_MASK;
1657 result = error;
1658 }
1659 else {
1660 flags &= ~SO_MASK;
1661 result = rval;
1662 }
Roland McGratheb285352003-01-14 09:59:00 +00001663 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1664 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001665 return -1;
1666#else /* !POWERPC */
1667#ifdef M68K
1668 d0 = error ? -error : rval;
1669 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1670 return -1;
1671#else /* !M68K */
1672#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001673 regs.ARM_r0 = error ? -error : rval;
1674 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001675 return -1;
1676#else /* !ARM */
1677#ifdef ALPHA
1678 if (error) {
1679 a3 = -1;
1680 r0 = error;
1681 }
1682 else {
1683 a3 = 0;
1684 r0 = rval;
1685 }
1686 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1687 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1688 return -1;
1689#else /* !ALPHA */
1690#ifdef SPARC
1691 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1692 return -1;
1693 if (error) {
1694 regs.r_psr |= PSR_C;
1695 regs.r_o0 = error;
1696 }
1697 else {
1698 regs.r_psr &= ~PSR_C;
1699 regs.r_o0 = rval;
1700 }
1701 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1702 return -1;
1703#else /* !SPARC */
1704#ifdef HPPA
1705 r28 = error ? -error : rval;
1706 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1707 return -1;
1708#else
1709#ifdef SH
1710 r0 = error ? -error : rval;
1711 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1712 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001713#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001714#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001715 r9 = error ? -error : rval;
1716 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1717 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001718#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001719#endif /* SH */
1720#endif /* HPPA */
1721#endif /* SPARC */
1722#endif /* ALPHA */
1723#endif /* ARM */
1724#endif /* M68K */
1725#endif /* POWERPC */
1726#endif /* MIPS */
1727#endif /* IA64 */
1728#endif /* X86_64 */
1729#endif /* I386 */
1730#endif /* S390 || S390X */
1731#endif /* LINUX */
1732#ifdef SUNOS4
1733 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1734 error << 24) < 0 ||
1735 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1736 return -1;
1737#endif /* SUNOS4 */
1738#ifdef SVR4
1739 /* XXX no clue */
1740 return -1;
1741#endif /* SVR4 */
1742#ifdef FREEBSD
1743 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1744 perror("pread");
1745 return -1;
1746 }
1747 if (error) {
1748 regs.r_eflags |= PSL_C;
1749 regs.r_eax = error;
1750 }
1751 else {
1752 regs.r_eflags &= ~PSL_C;
1753 regs.r_eax = rval;
1754 }
1755 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1756 perror("pwrite");
1757 return -1;
1758 }
1759#endif /* FREEBSD */
1760
1761 /* All branches reach here on success (only). */
1762 tcp->u_error = error;
1763 tcp->u_rval = rval;
1764 return 0;
1765}
1766
Pavel Machek4dc3b142000-02-01 17:58:41 +00001767int syscall_enter(tcp)
1768struct tcb *tcp;
1769{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001770#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001771 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001772#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001773#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001774#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001775 {
1776 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001777 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1778 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001779 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001780 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001781 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001782 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001783 return -1;
1784 }
1785 }
1786#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001787 {
1788 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001789 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1790 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001791 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001792 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001793 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001794 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1795 * for scno somewhere above here!
1796 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001797 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1798 return -1;
1799 }
1800 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001801#elif defined (IA64)
1802 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001803 if (!ia32) {
1804 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1805 /* be backwards compatible with kernel < 2.4.4... */
1806# ifndef PT_RBS_END
1807# define PT_RBS_END PT_AR_BSP
1808# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001809
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001810 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001811 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001812 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1813 return -1;
1814
1815 sof = (cfm >> 0) & 0x7f;
1816 sol = (cfm >> 7) & 0x7f;
1817 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1818
1819 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1820 && sysent[tcp->scno].nargs != -1)
1821 tcp->u_nargs = sysent[tcp->scno].nargs;
1822 else
1823 tcp->u_nargs = MAX_ARGS;
1824 for (i = 0; i < tcp->u_nargs; ++i) {
1825 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1826 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1827 return -1;
1828 }
1829 } else {
1830 int i;
1831
1832 if (/* EBX = out0 */
1833 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1834 /* ECX = out1 */
1835 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1836 /* EDX = out2 */
1837 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
1838 /* ESI = out3 */
1839 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
1840 /* EDI = out4 */
1841 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
1842 /* EBP = out5 */
1843 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
1844 return -1;
1845
1846 for (i = 0; i < 6; ++i)
1847 /* truncate away IVE sign-extension */
1848 tcp->u_arg[i] &= 0xffffffff;
1849
1850 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1851 && sysent[tcp->scno].nargs != -1)
1852 tcp->u_nargs = sysent[tcp->scno].nargs;
1853 else
1854 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001855 }
1856 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001857#elif defined (MIPS)
1858 {
1859 long sp;
1860 int i, nargs;
1861
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001862 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1863 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001864 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001865 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001866 if(nargs > 4) {
1867 if(upeek(pid, REG_SP, &sp) < 0)
1868 return -1;
1869 for(i = 0; i < 4; i++) {
1870 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
1871 return -1;
1872 }
1873 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
1874 (char *)(tcp->u_arg + 4));
1875 } else {
1876 for(i = 0; i < nargs; i++) {
1877 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
1878 return -1;
1879 }
1880 }
1881 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001882#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00001883#ifndef PT_ORIG_R3
1884#define PT_ORIG_R3 34
1885#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001886 {
1887 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001888 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1889 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001890 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001891 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001892 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00001893 if (upeek(pid, (i==0) ?
1894 (sizeof(unsigned long)*PT_ORIG_R3) :
1895 ((i+PT_R3)*sizeof(unsigned long)),
1896 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001897 return -1;
1898 }
1899 }
1900#elif defined (SPARC)
1901 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001902 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001903
1904 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1905 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001906 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001907 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001908 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001909 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001910 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001911#elif defined (HPPA)
1912 {
1913 int i;
1914
1915 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1916 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001917 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001918 tcp->u_nargs = MAX_ARGS;
1919 for (i = 0; i < tcp->u_nargs; i++) {
1920 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1921 return -1;
1922 }
1923 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001924#elif defined(ARM)
1925 {
1926 int i;
1927
1928 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1929 tcp->u_nargs = sysent[tcp->scno].nargs;
1930 else
1931 tcp->u_nargs = MAX_ARGS;
1932 for (i = 0; i < tcp->u_nargs; i++)
1933 tcp->u_arg[i] = regs.uregs[i];
1934 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001935#elif defined(SH)
1936 {
Roland McGrath761b5d72002-12-15 23:58:31 +00001937 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001938 static int syscall_regs[] = {
1939 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
1940 REG_REG0, REG_REG0+1, REG_REG0+2
1941 };
1942
1943 tcp->u_nargs = sysent[tcp->scno].nargs;
1944 for (i = 0; i < tcp->u_nargs; i++) {
1945 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
1946 return -1;
1947 }
1948 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001949#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001950 {
1951 int i;
1952 /* Registers used by SH5 Linux system calls for parameters */
1953 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
1954
1955 /*
1956 * TODO: should also check that the number of arguments encoded
1957 * in the trap number matches the number strace expects.
1958 */
1959 /*
1960 assert(sysent[tcp->scno].nargs <
1961 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
1962 */
1963
1964 tcp->u_nargs = sysent[tcp->scno].nargs;
1965 for (i = 0; i < tcp->u_nargs; i++) {
1966 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1967 return -1;
1968 }
1969 }
1970
Michal Ludvig0e035502002-09-23 15:41:01 +00001971#elif defined(X86_64)
1972 {
1973 int i;
1974 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
1975 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
1976 {RBX,RCX,RDX,RDX,RSI,RDI,RBP} /* i386 ABI */
1977 };
Roland McGrath761b5d72002-12-15 23:58:31 +00001978
Michal Ludvig0e035502002-09-23 15:41:01 +00001979 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1980 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001981 else
Michal Ludvig0e035502002-09-23 15:41:01 +00001982 tcp->u_nargs = MAX_ARGS;
1983 for (i = 0; i < tcp->u_nargs; i++) {
1984 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
1985 return -1;
1986 }
1987 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001988#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001989 {
1990 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001991 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1992 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001993 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001994 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001995 for (i = 0; i < tcp->u_nargs; i++) {
1996 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
1997 return -1;
1998 }
1999 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002000#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002001#endif /* LINUX */
2002#ifdef SUNOS4
2003 {
2004 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002005 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2006 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002007 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002008 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002009 for (i = 0; i < tcp->u_nargs; i++) {
2010 struct user *u;
2011
2012 if (upeek(pid, uoff(u_arg[0]) +
2013 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2014 return -1;
2015 }
2016 }
2017#endif /* SUNOS4 */
2018#ifdef SVR4
2019#ifdef MIPS
2020 /*
2021 * SGI is broken: even though it has pr_sysarg, it doesn't
2022 * set them on system call entry. Get a clue.
2023 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002024 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002025 tcp->u_nargs = sysent[tcp->scno].nargs;
2026 else
2027 tcp->u_nargs = tcp->status.pr_nsysarg;
2028 if (tcp->u_nargs > 4) {
2029 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2030 4*sizeof(tcp->u_arg[0]));
2031 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2032 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2033 }
2034 else {
2035 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2036 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2037 }
John Hughes25299712001-03-06 10:10:06 +00002038#elif UNIXWARE >= 2
2039 /*
2040 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2041 */
2042 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2043 tcp->u_nargs = sysent[tcp->scno].nargs;
2044 else
2045 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2046 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2047 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2048#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002049 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002050 tcp->u_nargs = sysent[tcp->scno].nargs;
2051 else
2052 tcp->u_nargs = tcp->status.pr_nsysarg;
2053 {
2054 int i;
2055 for (i = 0; i < tcp->u_nargs; i++)
2056 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2057 }
John Hughes25299712001-03-06 10:10:06 +00002058#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002059 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002060 tcp->u_nargs = sysent[tcp->scno].nargs;
2061 else
2062 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002063 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002064 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002065#else
2066 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002068#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002069#ifdef FREEBSD
2070 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2071 sysent[tcp->scno].nargs > tcp->status.val)
2072 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002073 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002074 tcp->u_nargs = tcp->status.val;
2075 if (tcp->u_nargs < 0)
2076 tcp->u_nargs = 0;
2077 if (tcp->u_nargs > MAX_ARGS)
2078 tcp->u_nargs = MAX_ARGS;
2079 switch(regs.r_eax) {
2080 case SYS___syscall:
2081 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2082 regs.r_esp + sizeof(int) + sizeof(quad_t));
2083 break;
2084 case SYS_syscall:
2085 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2086 regs.r_esp + 2 * sizeof(int));
2087 break;
2088 default:
2089 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2090 regs.r_esp + sizeof(int));
2091 break;
2092 }
2093#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002094 return 1;
2095}
2096
2097int
2098trace_syscall(tcp)
2099struct tcb *tcp;
2100{
2101 int sys_res;
2102 struct timeval tv;
2103 int res;
2104
2105 /* Measure the exit time as early as possible to avoid errors. */
2106 if (dtime && (tcp->flags & TCB_INSYSCALL))
2107 gettimeofday(&tv, NULL);
2108
2109 res = get_scno(tcp);
2110 if (res != 1)
2111 return res;
2112
2113 res = syscall_fixup(tcp);
2114 if (res != 1)
2115 return res;
2116
2117 if (tcp->flags & TCB_INSYSCALL) {
2118 long u_error;
2119 res = get_error(tcp);
2120 if (res != 1)
2121 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002122
2123 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002124 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2125 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002126 tcp->flags &= ~TCB_INSYSCALL;
2127 return 0;
2128 }
2129
2130 if (tcp->flags & TCB_REPRINT) {
2131 printleader(tcp);
2132 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002133 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002134 tprintf("syscall_%lu", tcp->scno);
2135 else
2136 tprintf("%s", sysent[tcp->scno].sys_name);
2137 tprintf(" resumed> ");
2138 }
2139
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002140 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002141 call_count[tcp->scno]++;
2142 if (tcp->u_error)
2143 error_count[tcp->scno]++;
2144 tv_sub(&tv, &tv, &tcp->etime);
2145#ifdef LINUX
2146 if (tv_cmp(&tv, &tcp->dtime) > 0) {
Roland McGrathee9c5b52003-11-01 22:11:22 +00002147 static struct timeval one_tick;
2148 if (one_tick.tv_usec == 0) {
2149 /* Initialize it. */
2150 struct itimerval it;
2151 memset(&it, 0, sizeof it);
2152 it.it_interval.tv_usec = 1;
2153 setitimer(ITIMER_REAL, &it, NULL);
2154 getitimer(ITIMER_REAL, &it);
2155 one_tick = it.it_interval;
2156 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002157
2158 if (tv_nz(&tcp->dtime))
2159 tv = tcp->dtime;
2160 else if (tv_cmp(&tv, &one_tick) > 0) {
2161 if (tv_cmp(&shortest, &one_tick) < 0)
2162 tv = shortest;
2163 else
2164 tv = one_tick;
2165 }
2166 }
2167#endif /* LINUX */
2168 if (tv_cmp(&tv, &shortest) < 0)
2169 shortest = tv;
2170 tv_add(&tv_count[tcp->scno],
2171 &tv_count[tcp->scno], &tv);
2172 tcp->flags &= ~TCB_INSYSCALL;
2173 return 0;
2174 }
2175
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002176 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002177 || (qual_flags[tcp->scno] & QUAL_RAW))
2178 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002179 else {
2180 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002181 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002182 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002183 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002184 u_error = tcp->u_error;
2185 tprintf(") ");
2186 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002187 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2188 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002189 if (u_error)
2190 tprintf("= -1 (errno %ld)", u_error);
2191 else
2192 tprintf("= %#lx", tcp->u_rval);
2193 }
2194 else if (!(sys_res & RVAL_NONE) && u_error) {
2195 switch (u_error) {
2196#ifdef LINUX
2197 case ERESTARTSYS:
2198 tprintf("= ? ERESTARTSYS (To be restarted)");
2199 break;
2200 case ERESTARTNOINTR:
2201 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2202 break;
2203 case ERESTARTNOHAND:
2204 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2205 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002206 case ERESTART_RESTARTBLOCK:
2207 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2208 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002209#endif /* LINUX */
2210 default:
2211 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002212 if (u_error < 0)
2213 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002214 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002215 tprintf("%s (%s)", errnoent[u_error],
2216 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002217 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002218 tprintf("ERRNO_%ld (%s)", u_error,
2219 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002220 break;
2221 }
2222 }
2223 else {
2224 if (sys_res & RVAL_NONE)
2225 tprintf("= ?");
2226 else {
2227 switch (sys_res & RVAL_MASK) {
2228 case RVAL_HEX:
2229 tprintf("= %#lx", tcp->u_rval);
2230 break;
2231 case RVAL_OCTAL:
2232 tprintf("= %#lo", tcp->u_rval);
2233 break;
2234 case RVAL_UDECIMAL:
2235 tprintf("= %lu", tcp->u_rval);
2236 break;
2237 case RVAL_DECIMAL:
2238 tprintf("= %ld", tcp->u_rval);
2239 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002240#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002241 case RVAL_LHEX:
2242 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002243 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002244 case RVAL_LOCTAL:
2245 tprintf("= %#llo", tcp->u_lrval);
2246 break;
2247 case RVAL_LUDECIMAL:
2248 tprintf("= %llu", tcp->u_lrval);
2249 break;
2250 case RVAL_LDECIMAL:
2251 tprintf("= %lld", tcp->u_lrval);
2252 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002253#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002254 default:
2255 fprintf(stderr,
2256 "invalid rval format\n");
2257 break;
2258 }
2259 }
2260 if ((sys_res & RVAL_STR) && tcp->auxstr)
2261 tprintf(" (%s)", tcp->auxstr);
2262 }
2263 if (dtime) {
2264 tv_sub(&tv, &tv, &tcp->etime);
2265 tprintf(" <%ld.%06ld>",
2266 (long) tv.tv_sec, (long) tv.tv_usec);
2267 }
2268 printtrailer(tcp);
2269
2270 dumpio(tcp);
2271 if (fflush(tcp->outf) == EOF)
2272 return -1;
2273 tcp->flags &= ~TCB_INSYSCALL;
2274 return 0;
2275 }
2276
2277 /* Entering system call */
2278 res = syscall_enter(tcp);
2279 if (res != 1)
2280 return res;
2281
Pavel Machekd8ae7e32000-02-01 17:17:25 +00002282 switch (tcp->scno + NR_SYSCALL_BASE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002283#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00002284#if !defined (ALPHA) && !defined(SPARC) && !defined(MIPS) && !defined(HPPA) && !defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002285 case SYS_socketcall:
2286 decode_subcall(tcp, SYS_socket_subcall,
2287 SYS_socket_nsubcalls, deref_style);
2288 break;
2289 case SYS_ipc:
2290 decode_subcall(tcp, SYS_ipc_subcall,
2291 SYS_ipc_nsubcalls, shift_style);
2292 break;
Michal Ludvig0e035502002-09-23 15:41:01 +00002293#endif /* !ALPHA && !MIPS && !SPARC && !HPPA && !X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294#ifdef SPARC
2295 case SYS_socketcall:
2296 sparc_socket_decode (tcp);
2297 break;
2298#endif
2299#endif /* LINUX */
2300#ifdef SVR4
2301#ifdef SYS_pgrpsys_subcall
2302 case SYS_pgrpsys:
2303 decode_subcall(tcp, SYS_pgrpsys_subcall,
2304 SYS_pgrpsys_nsubcalls, shift_style);
2305 break;
2306#endif /* SYS_pgrpsys_subcall */
2307#ifdef SYS_sigcall_subcall
2308 case SYS_sigcall:
2309 decode_subcall(tcp, SYS_sigcall_subcall,
2310 SYS_sigcall_nsubcalls, mask_style);
2311 break;
2312#endif /* SYS_sigcall_subcall */
2313 case SYS_msgsys:
2314 decode_subcall(tcp, SYS_msgsys_subcall,
2315 SYS_msgsys_nsubcalls, shift_style);
2316 break;
2317 case SYS_shmsys:
2318 decode_subcall(tcp, SYS_shmsys_subcall,
2319 SYS_shmsys_nsubcalls, shift_style);
2320 break;
2321 case SYS_semsys:
2322 decode_subcall(tcp, SYS_semsys_subcall,
2323 SYS_semsys_nsubcalls, shift_style);
2324 break;
2325#if 0 /* broken */
2326 case SYS_utssys:
2327 decode_subcall(tcp, SYS_utssys_subcall,
2328 SYS_utssys_nsubcalls, shift_style);
2329 break;
2330#endif
2331 case SYS_sysfs:
2332 decode_subcall(tcp, SYS_sysfs_subcall,
2333 SYS_sysfs_nsubcalls, shift_style);
2334 break;
2335 case SYS_spcall:
2336 decode_subcall(tcp, SYS_spcall_subcall,
2337 SYS_spcall_nsubcalls, shift_style);
2338 break;
2339#ifdef SYS_context_subcall
2340 case SYS_context:
2341 decode_subcall(tcp, SYS_context_subcall,
2342 SYS_context_nsubcalls, shift_style);
2343 break;
2344#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002345#ifdef SYS_door_subcall
2346 case SYS_door:
2347 decode_subcall(tcp, SYS_door_subcall,
2348 SYS_door_nsubcalls, door_style);
2349 break;
2350#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002351#ifdef SYS_kaio_subcall
2352 case SYS_kaio:
2353 decode_subcall(tcp, SYS_kaio_subcall,
2354 SYS_kaio_nsubcalls, shift_style);
2355 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002356#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002357#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002358#ifdef FREEBSD
2359 case SYS_msgsys:
2360 case SYS_shmsys:
2361 case SYS_semsys:
2362 decode_subcall(tcp, 0, 0, table_style);
2363 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002364#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002365#ifdef SUNOS4
2366 case SYS_semsys:
2367 decode_subcall(tcp, SYS_semsys_subcall,
2368 SYS_semsys_nsubcalls, shift_style);
2369 break;
2370 case SYS_msgsys:
2371 decode_subcall(tcp, SYS_msgsys_subcall,
2372 SYS_msgsys_nsubcalls, shift_style);
2373 break;
2374 case SYS_shmsys:
2375 decode_subcall(tcp, SYS_shmsys_subcall,
2376 SYS_shmsys_nsubcalls, shift_style);
2377 break;
2378#endif
2379 }
2380
2381 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002382 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002383 tcp->flags |= TCB_INSYSCALL;
2384 return 0;
2385 }
2386
2387 if (cflag) {
2388 gettimeofday(&tcp->etime, NULL);
2389 tcp->flags |= TCB_INSYSCALL;
2390 return 0;
2391 }
2392
2393 printleader(tcp);
2394 tcp->flags &= ~TCB_REPRINT;
2395 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002396 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002397 tprintf("syscall_%lu(", tcp->scno);
2398 else
2399 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002400 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002401 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2402 sys_res = printargs(tcp);
2403 else
2404 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2405 if (fflush(tcp->outf) == EOF)
2406 return -1;
2407 tcp->flags |= TCB_INSYSCALL;
2408 /* Measure the entrance time as late as possible to avoid errors. */
2409 if (dtime)
2410 gettimeofday(&tcp->etime, NULL);
2411 return sys_res;
2412}
2413
2414int
2415printargs(tcp)
2416struct tcb *tcp;
2417{
2418 if (entering(tcp)) {
2419 int i;
2420
2421 for (i = 0; i < tcp->u_nargs; i++)
2422 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2423 }
2424 return 0;
2425}
2426
2427long
2428getrval2(tcp)
2429struct tcb *tcp;
2430{
2431 long val = -1;
2432
2433#ifdef LINUX
2434#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002435 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002436 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2437 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002438 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002439#elif defined(SH)
2440 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2441 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002442#endif /* SPARC */
Roland McGrathb4ce1762004-03-01 20:30:48 +00002443#elif defined(IA64)
2444 if (upeek(tcp->pid, PT_R9, &val) < 0)
2445 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002446#endif /* LINUX */
2447
2448#ifdef SUNOS4
2449 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2450 return -1;
2451#endif /* SUNOS4 */
2452
2453#ifdef SVR4
2454#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002455 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002456#endif /* SPARC */
2457#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002458 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002459#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002460#ifdef X86_64
2461 val = tcp->status.PR_REG[RDX];
2462#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002463#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002464 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002465#endif /* MIPS */
2466#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002467#ifdef FREEBSD
2468 struct reg regs;
2469 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2470 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002471#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002472 return val;
2473}
2474
2475/*
2476 * Apparently, indirect system calls have already be converted by ptrace(2),
2477 * so if you see "indir" this program has gone astray.
2478 */
2479int
2480sys_indir(tcp)
2481struct tcb *tcp;
2482{
2483 int i, scno, nargs;
2484
2485 if (entering(tcp)) {
2486 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2487 fprintf(stderr, "Bogus syscall: %u\n", scno);
2488 return 0;
2489 }
2490 nargs = sysent[scno].nargs;
2491 tprintf("%s", sysent[scno].sys_name);
2492 for (i = 0; i < nargs; i++)
2493 tprintf(", %#lx", tcp->u_arg[i+1]);
2494 }
2495 return 0;
2496}
2497
2498static int
2499time_cmp(a, b)
2500void *a;
2501void *b;
2502{
2503 return -tv_cmp(&tv_count[*((int *) a)], &tv_count[*((int *) b)]);
2504}
2505
2506static int
2507syscall_cmp(a, b)
2508void *a;
2509void *b;
2510{
2511 return strcmp(sysent[*((int *) a)].sys_name,
2512 sysent[*((int *) b)].sys_name);
2513}
2514
2515static int
2516count_cmp(a, b)
2517void *a;
2518void *b;
2519{
2520 int m = call_count[*((int *) a)], n = call_count[*((int *) b)];
2521
2522 return (m < n) ? 1 : (m > n) ? -1 : 0;
2523}
2524
2525static int (*sortfun)();
2526static struct timeval overhead = { -1, -1 };
2527
2528void
2529set_sortby(sortby)
2530char *sortby;
2531{
2532 if (strcmp(sortby, "time") == 0)
2533 sortfun = time_cmp;
2534 else if (strcmp(sortby, "calls") == 0)
2535 sortfun = count_cmp;
2536 else if (strcmp(sortby, "name") == 0)
2537 sortfun = syscall_cmp;
2538 else if (strcmp(sortby, "nothing") == 0)
2539 sortfun = NULL;
2540 else {
2541 fprintf(stderr, "invalid sortby: `%s'\n", sortby);
2542 exit(1);
2543 }
2544}
2545
2546void set_overhead(n)
2547int n;
2548{
2549 overhead.tv_sec = n / 1000000;
2550 overhead.tv_usec = n % 1000000;
2551}
2552
2553void
2554call_summary(outf)
2555FILE *outf;
2556{
2557 int i, j;
2558 int call_cum, error_cum;
2559 struct timeval tv_cum, dtv;
2560 double percent;
2561 char *dashes = "-------------------------";
2562 char error_str[16];
2563
2564 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
2565 if (overhead.tv_sec == -1) {
2566 tv_mul(&overhead, &shortest, 8);
2567 tv_div(&overhead, &overhead, 10);
2568 }
2569 for (i = 0; i < nsyscalls; i++) {
2570 sorted_count[i] = i;
2571 if (call_count[i] == 0)
2572 continue;
2573 tv_mul(&dtv, &overhead, call_count[i]);
2574 tv_sub(&tv_count[i], &tv_count[i], &dtv);
2575 call_cum += call_count[i];
2576 error_cum += error_count[i];
2577 tv_add(&tv_cum, &tv_cum, &tv_count[i]);
2578 }
2579 if (sortfun)
2580 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
2581 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
2582 "% time", "seconds", "usecs/call",
2583 "calls", "errors", "syscall");
2584 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2585 dashes, dashes, dashes, dashes, dashes, dashes);
2586 for (i = 0; i < nsyscalls; i++) {
2587 j = sorted_count[i];
2588 if (call_count[j] == 0)
2589 continue;
2590 tv_div(&dtv, &tv_count[j], call_count[j]);
2591 if (error_count[j])
2592 sprintf(error_str, "%d", error_count[j]);
2593 else
2594 error_str[0] = '\0';
2595 percent = 100.0*tv_float(&tv_count[j])/tv_float(&tv_cum);
2596 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
2597 percent, (long) tv_count[j].tv_sec,
2598 (long) tv_count[j].tv_usec,
2599 (long) 1000000 * dtv.tv_sec + dtv.tv_usec,
2600 call_count[j], error_str, sysent[j].sys_name);
2601 }
2602 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
2603 dashes, dashes, dashes, dashes, dashes, dashes);
2604 if (error_cum)
2605 sprintf(error_str, "%d", error_cum);
2606 else
2607 error_str[0] = '\0';
2608 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
2609 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
2610 call_cum, error_str, "total");
2611}