blob: 16d6288d7057d6bd78d950d09138080836d26852 [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
Roland McGrath6d1a65c2004-07-12 07:44:08 +000046#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000047# 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>
Roland McGrath6d1a65c2004-07-12 07:44:08 +000052#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000053# 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
Roland McGrath6d1a65c2004-07-12 07:44:08 +000077#if defined (LINUX) && defined (SPARC64)
78# define r_pc r_tpc
79# undef PTRACE_GETREGS
80# define PTRACE_GETREGS PTRACE_GETREGS64
81# undef PTRACE_SETREGS
82# define PTRACE_SETREGS PTRACE_SETREGS64
83#endif /* LINUX && SPARC64 */
84
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000085#if defined(LINUX) && defined(IA64)
86# include <asm/ptrace_offsets.h>
87# include <asm/rse.h>
88#endif
89
Pavel Machekd8ae7e32000-02-01 17:17:25 +000090#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifdef LINUX
92#ifndef ERESTARTSYS
93#define ERESTARTSYS 512
94#endif
95#ifndef ERESTARTNOINTR
96#define ERESTARTNOINTR 513
97#endif
98#ifndef ERESTARTNOHAND
99#define ERESTARTNOHAND 514 /* restart if no handler.. */
100#endif
101#ifndef ENOIOCTLCMD
102#define ENOIOCTLCMD 515 /* No ioctl command */
103#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000104#ifndef ERESTART_RESTARTBLOCK
105#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
106#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#ifndef NSIG
108#define NSIG 32
109#endif
110#ifdef ARM
111#undef NSIG
112#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000113#undef NR_SYSCALL_BASE
114#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#endif
116#endif /* LINUX */
117
118#include "syscall.h"
119
120/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000121#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#define TF TRACE_FILE
123#define TI TRACE_IPC
124#define TN TRACE_NETWORK
125#define TP TRACE_PROCESS
126#define TS TRACE_SIGNAL
127
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000132int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133
134#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000135static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000136#include "syscallent1.h"
137};
Roland McGrathee36ce12004-09-04 03:53:10 +0000138static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000139int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140#endif /* SUPPORTED_PERSONALITIES >= 2 */
141
142#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000143static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#include "syscallent2.h"
145};
Roland McGrathee36ce12004-09-04 03:53:10 +0000146static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000147int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148#endif /* SUPPORTED_PERSONALITIES >= 3 */
149
Roland McGrathee36ce12004-09-04 03:53:10 +0000150const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000151int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152int nsyscalls;
153
154/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000155#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156#undef TF
157#undef TI
158#undef TN
159#undef TP
160#undef TS
161
Roland McGrathee36ce12004-09-04 03:53:10 +0000162static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163#include "errnoent.h"
164};
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166
167#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000168static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169#include "errnoent1.h"
170};
Roland McGrathee36ce12004-09-04 03:53:10 +0000171static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000172#endif /* SUPPORTED_PERSONALITIES >= 2 */
173
174#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000175static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176#include "errnoent2.h"
177};
Roland McGrathee36ce12004-09-04 03:53:10 +0000178static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000179#endif /* SUPPORTED_PERSONALITIES >= 3 */
180
Roland McGrathee36ce12004-09-04 03:53:10 +0000181const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182int nerrnos;
183
184int current_personality;
185
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000186#ifndef PERSONALITY0_WORDSIZE
187# define PERSONALITY0_WORDSIZE sizeof(long)
188#endif
189const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
190 PERSONALITY0_WORDSIZE,
191#if SUPPORTED_PERSONALITIES > 1
192 PERSONALITY1_WORDSIZE,
193#endif
194#if SUPPORTED_PERSONALITIES > 2
195 PERSONALITY2_WORDSIZE,
196#endif
197};;
198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000200set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201{
202 switch (personality) {
203 case 0:
204 errnoent = errnoent0;
205 nerrnos = nerrnos0;
206 sysent = sysent0;
207 nsyscalls = nsyscalls0;
208 ioctlent = ioctlent0;
209 nioctlents = nioctlents0;
210 signalent = signalent0;
211 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000212 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000213 break;
214
215#if SUPPORTED_PERSONALITIES >= 2
216 case 1:
217 errnoent = errnoent1;
218 nerrnos = nerrnos1;
219 sysent = sysent1;
220 nsyscalls = nsyscalls1;
221 ioctlent = ioctlent1;
222 nioctlents = nioctlents1;
223 signalent = signalent1;
224 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000225 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000226 break;
227#endif /* SUPPORTED_PERSONALITIES >= 2 */
228
229#if SUPPORTED_PERSONALITIES >= 3
230 case 2:
231 errnoent = errnoent2;
232 nerrnos = nerrnos2;
233 sysent = sysent2;
234 nsyscalls = nsyscalls2;
235 ioctlent = ioctlent2;
236 nioctlents = nioctlents2;
237 signalent = signalent2;
238 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000239 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 break;
241#endif /* SUPPORTED_PERSONALITIES >= 3 */
242
243 default:
244 return -1;
245 }
246
247 current_personality = personality;
248 return 0;
249}
250
Roland McGrathe10e62a2004-09-04 04:20:43 +0000251
Roland McGrath9797ceb2002-12-30 10:23:00 +0000252static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253
Roland McGrathe10e62a2004-09-04 04:20:43 +0000254static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 int bitflag;
256 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000257 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000258 char *argument_name;
259} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000260 { QUAL_TRACE, "trace", qual_syscall, "system call" },
261 { QUAL_TRACE, "t", qual_syscall, "system call" },
262 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
263 { QUAL_ABBREV, "a", qual_syscall, "system call" },
264 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
265 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
266 { QUAL_RAW, "raw", qual_syscall, "system call" },
267 { QUAL_RAW, "x", qual_syscall, "system call" },
268 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
269 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
270 { QUAL_SIGNAL, "s", qual_signal, "signal" },
271 { QUAL_FAULT, "fault", qual_fault, "fault" },
272 { QUAL_FAULT, "faults", qual_fault, "fault" },
273 { QUAL_FAULT, "m", qual_fault, "fault" },
274 { QUAL_READ, "read", qual_desc, "descriptor" },
275 { QUAL_READ, "reads", qual_desc, "descriptor" },
276 { QUAL_READ, "r", qual_desc, "descriptor" },
277 { QUAL_WRITE, "write", qual_desc, "descriptor" },
278 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
279 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 { 0, NULL, NULL, NULL },
281};
282
Roland McGrath9797ceb2002-12-30 10:23:00 +0000283static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000284qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000285 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000286 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000287 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000288 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000289{
Roland McGrath138c6a32006-01-12 09:50:49 +0000290 if (pers == 0 || pers < 0) {
291 if (not)
292 qual_flags0[n] &= ~opt->bitflag;
293 else
294 qual_flags0[n] |= opt->bitflag;
295 }
296
297#if SUPPORTED_PERSONALITIES >= 2
298 if (pers == 1 || pers < 0) {
299 if (not)
300 qual_flags1[n] &= ~opt->bitflag;
301 else
302 qual_flags1[n] |= opt->bitflag;
303 }
304#endif /* SUPPORTED_PERSONALITIES >= 2 */
305
306#if SUPPORTED_PERSONALITIES >= 3
307 if (pers == 2 || pers < 0) {
308 if (not)
309 qual_flags2[n] &= ~opt->bitflag;
310 else
311 qual_flags2[n] |= opt->bitflag;
312 }
313#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000314}
315
316static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000317qual_syscall(s, opt, not)
318 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000319 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000320 int not;
321{
322 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000323 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000324
Roland McGrath48a035f2006-01-12 09:45:56 +0000325 if (isdigit((unsigned char)*s)) {
326 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000327 if (i < 0 || i >= MAX_QUALS)
Roland McGrath48a035f2006-01-12 09:45:56 +0000328 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000329 qualify_one(i, opt, not, -1);
Roland McGrath48a035f2006-01-12 09:45:56 +0000330 return 0;
331 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000332 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 if (strcmp(s, sysent0[i].sys_name) == 0) {
334 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000335 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000336 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000337
338#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000339 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000340 if (strcmp(s, sysent1[i].sys_name) == 0) {
341 qualify_one(i, opt, not, 1);
342 rc = 0;
343 }
344#endif /* SUPPORTED_PERSONALITIES >= 2 */
345
346#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000347 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000348 if (strcmp(s, sysent2[i].sys_name) == 0) {
349 qualify_one(i, opt, not, 2);
350 rc = 0;
351 }
352#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000353
Roland McGrathfe6b3522005-02-02 04:40:11 +0000354 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000355}
356
357static int
358qual_signal(s, opt, not)
359 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000360 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000361 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000362{
363 int i;
364 char buf[32];
365
Roland McGrath48a035f2006-01-12 09:45:56 +0000366 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000367 int signo = atoi(s);
368 if (signo < 0 || signo >= MAX_QUALS)
369 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000370 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000371 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000373 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000374 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375 strcpy(buf, s);
376 s = buf;
377 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000378 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379 if (strncmp(s, "SIG", 3) == 0)
380 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000381 for (i = 0; i <= NSIG; i++)
382 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000383 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000384 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000385 }
Roland McGrath76421df2005-02-02 03:51:18 +0000386 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387}
388
389static int
390qual_fault(s, opt, not)
391 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000392 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000393 int not;
394{
395 return -1;
396}
397
398static int
399qual_desc(s, opt, not)
400 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000401 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000402 int not;
403{
Roland McGrath48a035f2006-01-12 09:45:56 +0000404 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000405 int desc = atoi(s);
406 if (desc < 0 || desc >= MAX_QUALS)
407 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000408 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000409 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 }
411 return -1;
412}
413
414static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000416 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417{
418 if (strcmp(s, "file") == 0)
419 return TRACE_FILE;
420 if (strcmp(s, "ipc") == 0)
421 return TRACE_IPC;
422 if (strcmp(s, "network") == 0)
423 return TRACE_NETWORK;
424 if (strcmp(s, "process") == 0)
425 return TRACE_PROCESS;
426 if (strcmp(s, "signal") == 0)
427 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000428 if (strcmp(s, "desc") == 0)
429 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430 return -1;
431}
432
433void
434qualify(s)
435char *s;
436{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000437 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 int not;
439 char *p;
440 int i, n;
441
442 opt = &qual_options[0];
443 for (i = 0; (p = qual_options[i].option_name); i++) {
444 n = strlen(p);
445 if (strncmp(s, p, n) == 0 && s[n] == '=') {
446 opt = &qual_options[i];
447 s += n + 1;
448 break;
449 }
450 }
451 not = 0;
452 if (*s == '!') {
453 not = 1;
454 s++;
455 }
456 if (strcmp(s, "none") == 0) {
457 not = 1 - not;
458 s = "all";
459 }
460 if (strcmp(s, "all") == 0) {
461 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000462 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 }
464 return;
465 }
466 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000467 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000468 }
469 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
470 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000471 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000472 if (sysent0[i].sys_flags & n)
473 qualify_one(i, opt, not, 0);
474
475#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000476 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000477 if (sysent1[i].sys_flags & n)
478 qualify_one(i, opt, not, 1);
479#endif /* SUPPORTED_PERSONALITIES >= 2 */
480
481#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000482 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000483 if (sysent2[i].sys_flags & n)
484 qualify_one(i, opt, not, 2);
485#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000486
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487 continue;
488 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000489 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 fprintf(stderr, "strace: invalid %s `%s'\n",
491 opt->argument_name, p);
492 exit(1);
493 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000494 }
495 return;
496}
497
498static void
499dumpio(tcp)
500struct tcb *tcp;
501{
502 if (syserror(tcp))
503 return;
504 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
505 return;
Roland McGrath17352792005-06-07 23:21:26 +0000506 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000508#ifdef SYS_pread64
509 case SYS_pread64:
510#endif
511#if defined SYS_pread && SYS_pread64 != SYS_pread
512 case SYS_pread:
513#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514#ifdef SYS_recv
515 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000516#elif defined SYS_sub_recv
517 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000518#endif
519#ifdef SYS_recvfrom
520 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000521#elif defined SYS_sub_recvfrom
522 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523#endif
524 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
525 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
526 break;
527 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000528#ifdef SYS_pwrite64
529 case SYS_pwrite64:
530#endif
531#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
532 case SYS_pwrite:
533#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534#ifdef SYS_send
535 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000536#elif defined SYS_sub_send
537 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538#endif
539#ifdef SYS_sendto
540 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000541#elif defined SYS_sub_sendto
542 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543#endif
544 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
545 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
546 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000547#ifdef SYS_readv
548 case SYS_readv:
549 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
550 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
551 break;
552#endif
553#ifdef SYS_writev
554 case SYS_writev:
555
556 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
557 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
558 break;
559#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560 }
561}
562
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000563#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000564enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000565#else /* FREEBSD */
566enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
567
568struct subcall {
569 int call;
570 int nsubcalls;
571 int subcalls[5];
572};
573
Roland McGratha4d48532005-06-08 20:45:28 +0000574static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000575 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000576#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000577 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000578#else
579 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
580#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000581 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
582};
583#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000584
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000585#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586
Roland McGratha4d48532005-06-08 20:45:28 +0000587static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588decode_subcall(tcp, subcall, nsubcalls, style)
589struct tcb *tcp;
590int subcall;
591int nsubcalls;
592enum subcall_style style;
593{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000594 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000595 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000596 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000597
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000598 switch (style) {
599 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000600 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
601 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 tcp->scno = subcall + tcp->u_arg[0];
603 if (sysent[tcp->scno].nargs != -1)
604 tcp->u_nargs = sysent[tcp->scno].nargs;
605 else
606 tcp->u_nargs--;
607 for (i = 0; i < tcp->u_nargs; i++)
608 tcp->u_arg[i] = tcp->u_arg[i + 1];
609 break;
610 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000611 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
612 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000613 tcp->scno = subcall + tcp->u_arg[0];
614 addr = tcp->u_arg[1];
615 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000616 if (size == sizeof(int)) {
617 unsigned int arg;
618 if (umove(tcp, addr, &arg) < 0)
619 arg = 0;
620 tcp->u_arg[i] = arg;
621 }
622 else if (size == sizeof(long)) {
623 unsigned long arg;
624 if (umove(tcp, addr, &arg) < 0)
625 arg = 0;
626 tcp->u_arg[i] = arg;
627 }
628 else
629 abort();
630 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 }
632 tcp->u_nargs = sysent[tcp->scno].nargs;
633 break;
634 case mask_style:
635 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000636 for (i = 0; mask; i++)
637 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000638 if (i >= nsubcalls)
639 return;
640 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 tcp->scno = subcall + i;
642 if (sysent[tcp->scno].nargs != -1)
643 tcp->u_nargs = sysent[tcp->scno].nargs;
644 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000645 case door_style:
646 /*
647 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000648 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000649 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000650 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
651 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000652 tcp->scno = subcall + tcp->u_arg[5];
653 if (sysent[tcp->scno].nargs != -1)
654 tcp->u_nargs = sysent[tcp->scno].nargs;
655 else
656 tcp->u_nargs--;
657 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000658#ifdef FREEBSD
659 case table_style:
660 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
661 if (subcalls_table[i].call == tcp->scno) break;
662 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
663 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
664 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
665 for (i = 0; i < tcp->u_nargs; i++)
666 tcp->u_arg[i] = tcp->u_arg[i + 1];
667 }
668 break;
669#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670 }
671}
672#endif
673
674struct tcb *tcp_last = NULL;
675
676static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000677internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000678{
679 /*
680 * We must always trace a few critical system calls in order to
681 * correctly support following forks in the presence of tracing
682 * qualifiers.
683 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000684 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000685
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000686 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
687 return 0;
688
689 func = sysent[tcp->scno].sys_func;
690
691 if (sys_exit == func)
692 return internal_exit(tcp);
693
694 if ( sys_fork == func
695#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
696 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000697#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000698#if UNIXWARE > 2
699 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000701 )
702 return internal_fork(tcp);
703
704#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
705 if (sys_clone == func)
706 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000707#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000708
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000709 if ( sys_execve == func
710#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
711 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000713#if UNIXWARE > 2
714 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000715#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000716 )
717 return internal_exec(tcp);
718
719 if ( sys_waitpid == func
720 || sys_wait4 == func
721#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
722 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000723#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000724#ifdef ALPHA
725 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000726#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000727 )
728 return internal_wait(tcp, 2);
729
730#if defined(LINUX) || defined(SVR4)
731 if (sys_waitid == func)
732 return internal_wait(tcp, 3);
733#endif
734
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000735 return 0;
736}
737
Wichert Akkermanc7926982000-04-10 22:22:31 +0000738
739#ifdef LINUX
740#if defined (I386)
741 static long eax;
742#elif defined (IA64)
743 long r8, r10, psr;
744 long ia32 = 0;
745#elif defined (POWERPC)
746 static long result,flags;
747#elif defined (M68K)
748 static int d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000749#elif defined(BFIN)
750 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000751#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000752 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000753#elif defined (ALPHA)
754 static long r0;
755 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000756#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000757 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000758 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000759#elif defined(LINUX_MIPSN32)
760 static long long a3;
761 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000762#elif defined(MIPS)
763 static long a3;
764 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000765#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000766 static long gpr2;
767 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000768 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000769#elif defined(HPPA)
770 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000771#elif defined(SH)
772 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000773#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000774 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000775#elif defined(X86_64)
776 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000777#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000778#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000779#ifdef FREEBSD
780 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000781#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000782
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000784get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785struct tcb *tcp;
786{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000788#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000790#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000793#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000794 if (tcp->flags & TCB_WAITEXECVE) {
795 /*
796 * When the execve system call completes successfully, the
797 * new process still has -ENOSYS (old style) or __NR_execve
798 * (new style) in gpr2. We cannot recover the scno again
799 * by disassembly, because the image that executed the
800 * syscall is gone now. Fortunately, we don't want it. We
801 * leave the flag set so that syscall_fixup can fake the
802 * result.
803 */
804 if (tcp->flags & TCB_INSYSCALL)
805 return 1;
806 /*
807 * This is the SIGTRAP after execve. We cannot try to read
808 * the system call here either.
809 */
810 tcp->flags &= ~TCB_WAITEXECVE;
811 return 0;
812 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000813
814 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
815 return -1;
816
817 if (syscall_mode != -ENOSYS) {
818 /*
819 * Since kernel version 2.5.44 the scno gets passed in gpr2.
820 */
821 scno = syscall_mode;
822 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000823 /*
824 * Old style of "passing" the scno via the SVC instruction.
825 */
826
827 long opcode, offset_reg, tmp;
828 void * svc_addr;
829 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
830 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
831 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
832 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000833
Michal Ludvig882eda82002-11-11 12:50:47 +0000834 if (upeek(pid, PT_PSWADDR, &pc) < 0)
835 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000836 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000837 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000838 if (errno) {
839 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000840 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000841 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000842
843 /*
844 * We have to check if the SVC got executed directly or via an
845 * EXECUTE instruction. In case of EXECUTE it is necessary to do
846 * instruction decoding to derive the system call number.
847 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
848 * so that this doesn't work if a SVC opcode is part of an EXECUTE
849 * opcode. Since there is no way to find out the opcode size this
850 * is the best we can do...
851 */
852
853 if ((opcode & 0xff00) == 0x0a00) {
854 /* SVC opcode */
855 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000856 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000857 else {
858 /* SVC got executed by EXECUTE instruction */
859
860 /*
861 * Do instruction decoding of EXECUTE. If you really want to
862 * understand this, read the Principles of Operations.
863 */
864 svc_addr = (void *) (opcode & 0xfff);
865
866 tmp = 0;
867 offset_reg = (opcode & 0x000f0000) >> 16;
868 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
869 return -1;
870 svc_addr += tmp;
871
872 tmp = 0;
873 offset_reg = (opcode & 0x0000f000) >> 12;
874 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
875 return -1;
876 svc_addr += tmp;
877
878 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
879 if (errno)
880 return -1;
881#if defined(S390X)
882 scno >>= 48;
883#else
884 scno >>= 16;
885#endif
886 tmp = 0;
887 offset_reg = (opcode & 0x00f00000) >> 20;
888 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
889 return -1;
890
891 scno = (scno | tmp) & 0xff;
892 }
893 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000894#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000895 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000896 return -1;
897 if (!(tcp->flags & TCB_INSYSCALL)) {
898 /* Check if we return from execve. */
899 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
900 tcp->flags &= ~TCB_WAITEXECVE;
901 return 0;
902 }
903 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000904#elif defined(BFIN)
905 if (upeek(pid, PT_ORIG_P0, &scno))
906 return -1;
907 /* Check if we return from execve. */
908 if (tcp->flags & TCB_WAITEXECVE && tcp->flags & TCB_INSYSCALL)
909 tcp->flags &= ~(TCB_INSYSCALL | TCB_WAITEXECVE);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000910#elif defined (I386)
911 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
912 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000913#elif defined (X86_64)
914 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
915 return -1;
916
Roland McGrath761b5d72002-12-15 23:58:31 +0000917 if (!(tcp->flags & TCB_INSYSCALL)) {
918 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000919 long val;
920
921 /* Check CS register value. On x86-64 linux it is:
922 * 0x33 for long mode (64 bit)
923 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000924 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000925 * to be cached.
926 */
927 if (upeek(pid, 8*CS, &val) < 0)
928 return -1;
929 switch(val)
930 {
931 case 0x23: currpers = 1; break;
932 case 0x33: currpers = 0; break;
933 default:
934 fprintf(stderr, "Unknown value CS=0x%02X while "
935 "detecting personality of process "
936 "PID=%d\n", (int)val, pid);
937 currpers = current_personality;
938 break;
939 }
940#if 0
941 /* This version analyzes the opcode of a syscall instruction.
942 * (int 0x80 on i386 vs. syscall on x86-64)
943 * It works, but is too complicated.
944 */
945 unsigned long val, rip, i;
946
947 if(upeek(pid, 8*RIP, &rip)<0)
948 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000949
Michal Ludvig0e035502002-09-23 15:41:01 +0000950 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
951 rip-=2;
952 errno = 0;
953
Roland McGrath761b5d72002-12-15 23:58:31 +0000954 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
955 if (errno)
956 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000957 strerror(errno));
958 switch (call & 0xffff)
959 {
960 /* x86-64: syscall = 0x0f 0x05 */
961 case 0x050f: currpers = 0; break;
962 /* i386: int 0x80 = 0xcd 0x80 */
963 case 0x80cd: currpers = 1; break;
964 default:
965 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000966 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000967 "Unknown syscall opcode (0x%04X) while "
968 "detecting personality of process "
969 "PID=%d\n", (int)call, pid);
970 break;
971 }
972#endif
973 if(currpers != current_personality)
974 {
975 char *names[]={"64 bit", "32 bit"};
976 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000977 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000978 pid, names[current_personality]);
979 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000980 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000981#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000982# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000983 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000984 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000985 if (!(tcp->flags & TCB_INSYSCALL)) {
986 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000987 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000988 return -1;
989 } else {
990 if (upeek (pid, PT_R15, &scno) < 0)
991 return -1;
992 }
Roland McGrathba954762003-03-05 06:29:06 +0000993 /* Check if we return from execve. */
994 if (tcp->flags & TCB_WAITEXECVE) {
995 tcp->flags &= ~TCB_WAITEXECVE;
996 return 0;
997 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000998 } else {
999 /* syscall in progress */
1000 if (upeek (pid, PT_R8, &r8) < 0)
1001 return -1;
1002 if (upeek (pid, PT_R10, &r10) < 0)
1003 return -1;
1004 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001005#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001006 /*
1007 * Read complete register set in one go.
1008 */
1009 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1010 return -1;
1011
1012 /*
1013 * We only need to grab the syscall number on syscall entry.
1014 */
1015 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001016 if (!(tcp->flags & TCB_INSYSCALL)) {
1017 /* Check if we return from execve. */
1018 if (tcp->flags & TCB_WAITEXECVE) {
1019 tcp->flags &= ~TCB_WAITEXECVE;
1020 return 0;
1021 }
1022 }
1023
Roland McGrath0f87c492003-06-03 23:29:04 +00001024 /*
1025 * Note: we only deal with only 32-bit CPUs here.
1026 */
1027 if (regs.ARM_cpsr & 0x20) {
1028 /*
1029 * Get the Thumb-mode system call number
1030 */
1031 scno = regs.ARM_r7;
1032 } else {
1033 /*
1034 * Get the ARM-mode system call number
1035 */
1036 errno = 0;
1037 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1038 if (errno)
1039 return -1;
1040
1041 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1042 tcp->flags &= ~TCB_WAITEXECVE;
1043 return 0;
1044 }
1045
Roland McGrathf691bd22006-04-25 07:34:41 +00001046 /* Handle the EABI syscall convention. We do not
1047 bother converting structures between the two
1048 ABIs, but basic functionality should work even
1049 if strace and the traced program have different
1050 ABIs. */
1051 if (scno == 0xef000000) {
1052 scno = regs.ARM_r7;
1053 } else {
1054 if ((scno & 0x0ff00000) != 0x0f900000) {
1055 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1056 scno);
1057 return -1;
1058 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001059
Roland McGrathf691bd22006-04-25 07:34:41 +00001060 /*
1061 * Fixup the syscall number
1062 */
1063 scno &= 0x000fffff;
1064 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001065 }
Roland McGrath56703312008-05-20 01:35:55 +00001066 if (scno & 0x0f0000) {
1067 /*
1068 * Handle ARM specific syscall
1069 */
1070 set_personality(1);
1071 scno &= 0x0000ffff;
1072 } else
1073 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001074
1075 if (tcp->flags & TCB_INSYSCALL) {
1076 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1077 tcp->flags &= ~TCB_INSYSCALL;
1078 }
1079 } else {
1080 if (!(tcp->flags & TCB_INSYSCALL)) {
1081 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1082 tcp->flags |= TCB_INSYSCALL;
1083 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001084 }
1085#elif defined (M68K)
1086 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1087 return -1;
Roland McGrath542c2c62008-05-20 01:11:56 +00001088#elif defined (LINUX_MIPSN32)
1089 unsigned long long regs[38];
1090
1091 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
1092 return -1;
1093 a3 = regs[REG_A3];
1094 r2 = regs[REG_V0];
1095
1096 if(!(tcp->flags & TCB_INSYSCALL)) {
1097 scno = r2;
1098
1099 /* Check if we return from execve. */
1100 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1101 tcp->flags &= ~TCB_WAITEXECVE;
1102 return 0;
1103 }
1104
1105 if (scno < 0 || scno > nsyscalls) {
1106 if(a3 == 0 || a3 == -1) {
1107 if(debug)
1108 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1109 return 0;
1110 }
1111 }
1112 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001113#elif defined (MIPS)
1114 if (upeek(pid, REG_A3, &a3) < 0)
1115 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001116 if(!(tcp->flags & TCB_INSYSCALL)) {
1117 if (upeek(pid, REG_V0, &scno) < 0)
1118 return -1;
1119
Roland McGrath542c2c62008-05-20 01:11:56 +00001120 /* Check if we return from execve. */
1121 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1122 tcp->flags &= ~TCB_WAITEXECVE;
1123 return 0;
1124 }
1125
Wichert Akkermanf90da011999-10-31 21:15:38 +00001126 if (scno < 0 || scno > nsyscalls) {
1127 if(a3 == 0 || a3 == -1) {
1128 if(debug)
1129 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1130 return 0;
1131 }
1132 }
1133 } else {
1134 if (upeek(pid, REG_V0, &r2) < 0)
1135 return -1;
1136 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137#elif defined (ALPHA)
1138 if (upeek(pid, REG_A3, &a3) < 0)
1139 return -1;
1140
1141 if (!(tcp->flags & TCB_INSYSCALL)) {
1142 if (upeek(pid, REG_R0, &scno) < 0)
1143 return -1;
1144
1145 /* Check if we return from execve. */
1146 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1147 tcp->flags &= ~TCB_WAITEXECVE;
1148 return 0;
1149 }
1150
1151 /*
1152 * Do some sanity checks to figure out if it's
1153 * really a syscall entry
1154 */
1155 if (scno < 0 || scno > nsyscalls) {
1156 if (a3 == 0 || a3 == -1) {
1157 if (debug)
1158 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1159 return 0;
1160 }
1161 }
1162 }
1163 else {
1164 if (upeek(pid, REG_R0, &r0) < 0)
1165 return -1;
1166 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001167#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001168 /* Everything we need is in the current register set. */
1169 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1170 return -1;
1171
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 /* If we are entering, then disassemble the syscall trap. */
1173 if (!(tcp->flags & TCB_INSYSCALL)) {
1174 /* Retrieve the syscall trap instruction. */
1175 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001176 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001177#if defined(SPARC64)
1178 trap >>= 32;
1179#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001180 if (errno)
1181 return -1;
1182
1183 /* Disassemble the trap to see what personality to use. */
1184 switch (trap) {
1185 case 0x91d02010:
1186 /* Linux/SPARC syscall trap. */
1187 set_personality(0);
1188 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001189 case 0x91d0206d:
1190 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001191 set_personality(2);
1192 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 case 0x91d02000:
1194 /* SunOS syscall trap. (pers 1) */
1195 fprintf(stderr,"syscall: SunOS no support\n");
1196 return -1;
1197 case 0x91d02008:
1198 /* Solaris 2.x syscall trap. (per 2) */
1199 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001200 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001201 case 0x91d02009:
1202 /* NetBSD/FreeBSD syscall trap. */
1203 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1204 return -1;
1205 case 0x91d02027:
1206 /* Solaris 2.x gettimeofday */
1207 set_personality(1);
1208 break;
1209 default:
1210 /* Unknown syscall trap. */
1211 if(tcp->flags & TCB_WAITEXECVE) {
1212 tcp->flags &= ~TCB_WAITEXECVE;
1213 return 0;
1214 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001215#if defined (SPARC64)
1216 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1217#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001218 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001219#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001220 return -1;
1221 }
1222
1223 /* Extract the system call number from the registers. */
1224 if (trap == 0x91d02027)
1225 scno = 156;
1226 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001227 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001228 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001229 scno = regs.r_o0;
1230 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231 }
1232 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001233#elif defined(HPPA)
1234 if (upeek(pid, PT_GR20, &scno) < 0)
1235 return -1;
1236 if (!(tcp->flags & TCB_INSYSCALL)) {
1237 /* Check if we return from execve. */
1238 if ((tcp->flags & TCB_WAITEXECVE)) {
1239 tcp->flags &= ~TCB_WAITEXECVE;
1240 return 0;
1241 }
1242 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001243#elif defined(SH)
1244 /*
1245 * In the new syscall ABI, the system call number is in R3.
1246 */
1247 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1248 return -1;
1249
1250 if (scno < 0) {
1251 /* Odd as it may seem, a glibc bug has been known to cause
1252 glibc to issue bogus negative syscall numbers. So for
1253 our purposes, make strace print what it *should* have been */
1254 long correct_scno = (scno & 0xff);
1255 if (debug)
1256 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001257 "Detected glibc bug: bogus system call number = %ld, "
1258 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001259 scno,
1260 correct_scno);
1261 scno = correct_scno;
1262 }
1263
1264
1265 if (!(tcp->flags & TCB_INSYSCALL)) {
1266 /* Check if we return from execve. */
1267 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1268 tcp->flags &= ~TCB_WAITEXECVE;
1269 return 0;
1270 }
1271 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001272#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001273 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1274 return -1;
1275 scno &= 0xFFFF;
1276
1277 if (!(tcp->flags & TCB_INSYSCALL)) {
1278 /* Check if we return from execve. */
1279 if (tcp->flags & TCB_WAITEXECVE) {
1280 tcp->flags &= ~TCB_WAITEXECVE;
1281 return 0;
1282 }
1283 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001284#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001285#endif /* LINUX */
1286#ifdef SUNOS4
1287 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1288 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001289#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001290 /* new syscall ABI returns result in R0 */
1291 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1292 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001293#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001294 /* ABI defines result returned in r9 */
1295 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1296 return -1;
1297
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001298#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001299#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001301 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001302#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001303#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001304 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001305#else /* FREEBSD */
1306 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1307 perror("pread");
1308 return -1;
1309 }
1310 switch (regs.r_eax) {
1311 case SYS_syscall:
1312 case SYS___syscall:
1313 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1314 break;
1315 default:
1316 scno = regs.r_eax;
1317 break;
1318 }
1319#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001320#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001321#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001322 if (!(tcp->flags & TCB_INSYSCALL))
1323 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001324 return 1;
1325}
1326
Pavel Machek4dc3b142000-02-01 17:58:41 +00001327
Roland McGrath17352792005-06-07 23:21:26 +00001328long
1329known_scno(tcp)
1330struct tcb *tcp;
1331{
1332 long scno = tcp->scno;
1333 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1334 scno = sysent[scno].native_scno;
1335 else
1336 scno += NR_SYSCALL_BASE;
1337 return scno;
1338}
1339
Roland McGratha4d48532005-06-08 20:45:28 +00001340static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001341syscall_fixup(tcp)
1342struct tcb *tcp;
1343{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001344#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001345 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001346#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001347 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001348
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001349 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001350 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001351 if (
1352 scno == SYS_fork
1353#ifdef SYS_vfork
1354 || scno == SYS_vfork
1355#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001356#ifdef SYS_fork1
1357 || scno == SYS_fork1
1358#endif /* SYS_fork1 */
1359#ifdef SYS_forkall
1360 || scno == SYS_forkall
1361#endif /* SYS_forkall */
1362#ifdef SYS_rfork1
1363 || scno == SYS_rfork1
1364#endif /* SYS_fork1 */
1365#ifdef SYS_rforkall
1366 || scno == SYS_rforkall
1367#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 ) {
1369 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001370 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001372 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373 }
1374 else {
1375 fprintf(stderr, "syscall: missing entry\n");
1376 tcp->flags |= TCB_INSYSCALL;
1377 }
1378 }
1379 }
1380 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001381 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001382 fprintf(stderr, "syscall: missing exit\n");
1383 tcp->flags &= ~TCB_INSYSCALL;
1384 }
1385 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001386#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001387#ifdef SUNOS4
1388 if (!(tcp->flags & TCB_INSYSCALL)) {
1389 if (scno == 0) {
1390 fprintf(stderr, "syscall: missing entry\n");
1391 tcp->flags |= TCB_INSYSCALL;
1392 }
1393 }
1394 else {
1395 if (scno != 0) {
1396 if (debug) {
1397 /*
1398 * This happens when a signal handler
1399 * for a signal which interrupted a
1400 * a system call makes another system call.
1401 */
1402 fprintf(stderr, "syscall: missing exit\n");
1403 }
1404 tcp->flags &= ~TCB_INSYSCALL;
1405 }
1406 }
1407#endif /* SUNOS4 */
1408#ifdef LINUX
1409#if defined (I386)
1410 if (upeek(pid, 4*EAX, &eax) < 0)
1411 return -1;
1412 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1413 if (debug)
1414 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1415 return 0;
1416 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001417#elif defined (X86_64)
1418 if (upeek(pid, 8*RAX, &rax) < 0)
1419 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001420 if (current_personality == 1)
1421 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001422 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1423 if (debug)
1424 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1425 return 0;
1426 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001427#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001428 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1429 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001430 if (syscall_mode != -ENOSYS)
1431 syscall_mode = tcp->scno;
1432 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001433 if (debug)
1434 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1435 return 0;
1436 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001437 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1438 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1439 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1440 /*
1441 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1442 * flag set for the post-execve SIGTRAP to see and reset.
1443 */
1444 gpr2 = 0;
1445 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001446#elif defined (POWERPC)
1447# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001448 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001449 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001450 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451 return -1;
1452 if (flags & SO_MASK)
1453 result = -result;
1454#elif defined (M68K)
1455 if (upeek(pid, 4*PT_D0, &d0) < 0)
1456 return -1;
1457 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1458 if (debug)
1459 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1460 return 0;
1461 }
1462#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001463 /*
1464 * Nothing required
1465 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001466#elif defined(BFIN)
1467 if (upeek(pid, PT_R0, &r0) < 0)
1468 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001469#elif defined (HPPA)
1470 if (upeek(pid, PT_GR28, &r28) < 0)
1471 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001472#elif defined(IA64)
1473 if (upeek(pid, PT_R10, &r10) < 0)
1474 return -1;
1475 if (upeek(pid, PT_R8, &r8) < 0)
1476 return -1;
1477 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1478 if (debug)
1479 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1480 return 0;
1481 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001482#endif
1483#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001484 return 1;
1485}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486
Roland McGrathc1e45922008-05-27 23:18:29 +00001487#ifdef LINUX
1488/*
1489 * Check the syscall return value register value for whether it is
1490 * a negated errno code indicating an error, or a success return value.
1491 */
1492static inline int
1493is_negated_errno(unsigned long int val)
1494{
1495 unsigned long int max = -(long int) nerrnos;
1496 if (personality_wordsize[current_personality] < sizeof(val)) {
1497 val = (unsigned int) val;
1498 max = (unsigned int) max;
1499 }
1500 return val > max;
1501}
1502#endif
1503
Roland McGratha4d48532005-06-08 20:45:28 +00001504static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001505get_error(tcp)
1506struct tcb *tcp;
1507{
1508 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001509#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001510#if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001511 if (is_negated_errno(gpr2)) {
1512 tcp->u_rval = -1;
1513 u_error = -gpr2;
1514 }
1515 else {
1516 tcp->u_rval = gpr2;
1517 u_error = 0;
1518 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001519#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001520#ifdef I386
Roland McGrathc1e45922008-05-27 23:18:29 +00001521 if (is_negated_errno(eax)) {
1522 tcp->u_rval = -1;
1523 u_error = -eax;
1524 }
1525 else {
1526 tcp->u_rval = eax;
1527 u_error = 0;
1528 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001529#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001530#ifdef X86_64
Roland McGrathc1e45922008-05-27 23:18:29 +00001531 if (is_negated_errno(rax)) {
1532 tcp->u_rval = -1;
1533 u_error = -rax;
1534 }
1535 else {
1536 tcp->u_rval = rax;
1537 u_error = 0;
1538 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001539#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001540#ifdef IA64
Roland McGrathc1e45922008-05-27 23:18:29 +00001541 if (ia32) {
1542 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001543
Roland McGrathc1e45922008-05-27 23:18:29 +00001544 err = (int)r8;
1545 if (is_negated_errno(err)) {
1546 tcp->u_rval = -1;
1547 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001548 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001549 else {
1550 tcp->u_rval = err;
1551 u_error = 0;
1552 }
1553 } else {
1554 if (r10) {
1555 tcp->u_rval = -1;
1556 u_error = r8;
1557 } else {
1558 tcp->u_rval = r8;
1559 u_error = 0;
1560 }
1561 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001562#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001563#ifdef MIPS
1564 if (a3) {
1565 tcp->u_rval = -1;
1566 u_error = r2;
1567 } else {
1568 tcp->u_rval = r2;
1569 u_error = 0;
1570 }
1571#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001572#ifdef POWERPC
Roland McGrathc1e45922008-05-27 23:18:29 +00001573 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001574 tcp->u_rval = -1;
1575 u_error = -result;
1576 }
1577 else {
1578 tcp->u_rval = result;
1579 u_error = 0;
1580 }
1581#else /* !POWERPC */
1582#ifdef M68K
Roland McGrathc1e45922008-05-27 23:18:29 +00001583 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001584 tcp->u_rval = -1;
1585 u_error = -d0;
1586 }
1587 else {
1588 tcp->u_rval = d0;
1589 u_error = 0;
1590 }
1591#else /* !M68K */
1592#ifdef ARM
Roland McGrathc1e45922008-05-27 23:18:29 +00001593 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001595 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596 }
1597 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001598 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599 u_error = 0;
1600 }
1601#else /* !ARM */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001602#ifdef BFIN
1603 if (is_negated_errno(r0)) {
1604 tcp->u_rval = -1;
1605 u_error = -r0;
1606 } else {
1607 tcp->u_rval = r0;
1608 u_error = 0;
1609 }
1610#else /* !BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001611#ifdef ALPHA
1612 if (a3) {
1613 tcp->u_rval = -1;
1614 u_error = r0;
1615 }
1616 else {
1617 tcp->u_rval = r0;
1618 u_error = 0;
1619 }
1620#else /* !ALPHA */
1621#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001622 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001624 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625 }
1626 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001627 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 u_error = 0;
1629 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001630#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001631#ifdef SPARC64
1632 if (regs.r_tstate & 0x1100000000UL) {
1633 tcp->u_rval = -1;
1634 u_error = regs.r_o0;
1635 }
1636 else {
1637 tcp->u_rval = regs.r_o0;
1638 u_error = 0;
1639 }
1640#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001641#ifdef HPPA
Roland McGrathc1e45922008-05-27 23:18:29 +00001642 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001643 tcp->u_rval = -1;
1644 u_error = -r28;
1645 }
1646 else {
1647 tcp->u_rval = r28;
1648 u_error = 0;
1649 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001650#else
1651#ifdef SH
Roland McGrathc1e45922008-05-27 23:18:29 +00001652 /* interpret R0 as return value or error number */
1653 if (is_negated_errno(r0)) {
1654 tcp->u_rval = -1;
1655 u_error = -r0;
1656 }
1657 else {
1658 tcp->u_rval = r0;
1659 u_error = 0;
1660 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001661#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001662#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001663 /* interpret result as return value or error number */
Roland McGrathc1e45922008-05-27 23:18:29 +00001664 if (is_negated_errno(r9)) {
Roland McGrathe1e584b2003-06-02 19:18:58 +00001665 tcp->u_rval = -1;
1666 u_error = -r9;
1667 }
1668 else {
1669 tcp->u_rval = r9;
1670 u_error = 0;
1671 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001672#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001673#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001674#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001676#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677#endif /* ALPHA */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001678#endif /* BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001679#endif /* ARM */
1680#endif /* M68K */
1681#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001682#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001683#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001684#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001686#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687#endif /* LINUX */
1688#ifdef SUNOS4
1689 /* get error code from user struct */
1690 if (upeek(pid, uoff(u_error), &u_error) < 0)
1691 return -1;
1692 u_error >>= 24; /* u_error is a char */
1693
1694 /* get system call return value */
1695 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1696 return -1;
1697#endif /* SUNOS4 */
1698#ifdef SVR4
1699#ifdef SPARC
1700 /* Judicious guessing goes a long way. */
1701 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1702 tcp->u_rval = -1;
1703 u_error = tcp->status.pr_reg[R_O0];
1704 }
1705 else {
1706 tcp->u_rval = tcp->status.pr_reg[R_O0];
1707 u_error = 0;
1708 }
1709#endif /* SPARC */
1710#ifdef I386
1711 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001712 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001713 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001714 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715 }
1716 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001717 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001718#ifdef HAVE_LONG_LONG
1719 tcp->u_lrval =
1720 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1721 tcp->status.PR_REG[EAX];
1722#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001723 u_error = 0;
1724 }
1725#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001726#ifdef X86_64
1727 /* Wanna know how to kill an hour single-stepping? */
1728 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1729 tcp->u_rval = -1;
1730 u_error = tcp->status.PR_REG[RAX];
1731 }
1732 else {
1733 tcp->u_rval = tcp->status.PR_REG[RAX];
1734 u_error = 0;
1735 }
1736#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001737#ifdef MIPS
1738 if (tcp->status.pr_reg[CTX_A3]) {
1739 tcp->u_rval = -1;
1740 u_error = tcp->status.pr_reg[CTX_V0];
1741 }
1742 else {
1743 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1744 u_error = 0;
1745 }
1746#endif /* MIPS */
1747#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001748#ifdef FREEBSD
1749 if (regs.r_eflags & PSL_C) {
1750 tcp->u_rval = -1;
1751 u_error = regs.r_eax;
1752 } else {
1753 tcp->u_rval = regs.r_eax;
1754 tcp->u_lrval =
1755 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1756 u_error = 0;
1757 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001758#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001759 tcp->u_error = u_error;
1760 return 1;
1761}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001762
Roland McGrathb69f81b2002-12-21 23:25:18 +00001763int
1764force_result(tcp, error, rval)
1765 struct tcb *tcp;
1766 int error;
1767 long rval;
1768{
1769#ifdef LINUX
1770#if defined(S390) || defined(S390X)
1771 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001772 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1773 return -1;
1774#else /* !S390 && !S390X */
1775#ifdef I386
1776 eax = error ? -error : rval;
1777 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1778 return -1;
1779#else /* !I386 */
1780#ifdef X86_64
1781 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001782 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001783 return -1;
1784#else
1785#ifdef IA64
1786 if (ia32) {
1787 r8 = error ? -error : rval;
1788 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1789 return -1;
1790 }
1791 else {
1792 if (error) {
1793 r8 = error;
1794 r10 = -1;
1795 }
1796 else {
1797 r8 = rval;
1798 r10 = 0;
1799 }
1800 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1801 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1802 return -1;
1803 }
1804#else /* !IA64 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001805#ifdef BFIN
1806 r0 = error ? -error : rval;
1807 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1808 return -1;
1809#else /* !BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001810#ifdef MIPS
1811 if (error) {
1812 r2 = error;
1813 a3 = -1;
1814 }
1815 else {
1816 r2 = rval;
1817 a3 = 0;
1818 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001819 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001820 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1821 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1822 return -1;
1823#else
1824#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001825 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001826 return -1;
1827 if (error) {
1828 flags |= SO_MASK;
1829 result = error;
1830 }
1831 else {
1832 flags &= ~SO_MASK;
1833 result = rval;
1834 }
Roland McGratheb285352003-01-14 09:59:00 +00001835 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1836 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001837 return -1;
1838#else /* !POWERPC */
1839#ifdef M68K
1840 d0 = error ? -error : rval;
1841 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1842 return -1;
1843#else /* !M68K */
1844#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001845 regs.ARM_r0 = error ? -error : rval;
1846 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001847 return -1;
1848#else /* !ARM */
1849#ifdef ALPHA
1850 if (error) {
1851 a3 = -1;
1852 r0 = error;
1853 }
1854 else {
1855 a3 = 0;
1856 r0 = rval;
1857 }
1858 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1859 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1860 return -1;
1861#else /* !ALPHA */
1862#ifdef SPARC
1863 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1864 return -1;
1865 if (error) {
1866 regs.r_psr |= PSR_C;
1867 regs.r_o0 = error;
1868 }
1869 else {
1870 regs.r_psr &= ~PSR_C;
1871 regs.r_o0 = rval;
1872 }
1873 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1874 return -1;
1875#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001876#ifdef SPARC64
1877 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1878 return -1;
1879 if (error) {
1880 regs.r_tstate |= 0x1100000000UL;
1881 regs.r_o0 = error;
1882 }
1883 else {
1884 regs.r_tstate &= ~0x1100000000UL;
1885 regs.r_o0 = rval;
1886 }
1887 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1888 return -1;
1889#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001890#ifdef HPPA
1891 r28 = error ? -error : rval;
1892 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1893 return -1;
1894#else
1895#ifdef SH
1896 r0 = error ? -error : rval;
1897 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1898 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001899#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001900#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001901 r9 = error ? -error : rval;
1902 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1903 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001904#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001905#endif /* SH */
1906#endif /* HPPA */
1907#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001908#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001909#endif /* ALPHA */
1910#endif /* ARM */
1911#endif /* M68K */
1912#endif /* POWERPC */
1913#endif /* MIPS */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001914#endif /* BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001915#endif /* IA64 */
1916#endif /* X86_64 */
1917#endif /* I386 */
1918#endif /* S390 || S390X */
1919#endif /* LINUX */
1920#ifdef SUNOS4
1921 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1922 error << 24) < 0 ||
1923 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1924 return -1;
1925#endif /* SUNOS4 */
1926#ifdef SVR4
1927 /* XXX no clue */
1928 return -1;
1929#endif /* SVR4 */
1930#ifdef FREEBSD
1931 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1932 perror("pread");
1933 return -1;
1934 }
1935 if (error) {
1936 regs.r_eflags |= PSL_C;
1937 regs.r_eax = error;
1938 }
1939 else {
1940 regs.r_eflags &= ~PSL_C;
1941 regs.r_eax = rval;
1942 }
1943 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1944 perror("pwrite");
1945 return -1;
1946 }
1947#endif /* FREEBSD */
1948
1949 /* All branches reach here on success (only). */
1950 tcp->u_error = error;
1951 tcp->u_rval = rval;
1952 return 0;
1953}
1954
Roland McGratha4d48532005-06-08 20:45:28 +00001955static int
1956syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001957struct tcb *tcp;
1958{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001959#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001960 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001961#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001962#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001963#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001964 {
1965 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001966 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1967 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001968 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001969 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001970 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001971 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001972 return -1;
1973 }
1974 }
1975#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001976 {
1977 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001978 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1979 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001980 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001981 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001982 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001983 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1984 * for scno somewhere above here!
1985 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001986 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1987 return -1;
1988 }
1989 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001990#elif defined (IA64)
1991 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001992 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001993 unsigned long *out0, cfm, sof, sol, i;
1994 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001995 /* be backwards compatible with kernel < 2.4.4... */
1996# ifndef PT_RBS_END
1997# define PT_RBS_END PT_AR_BSP
1998# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001999
Jan Kratochvil1f942712008-08-06 21:38:52 +00002000 if (upeek(pid, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002001 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002002 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
2003 return -1;
2004
2005 sof = (cfm >> 0) & 0x7f;
2006 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002007 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002008
2009 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2010 && sysent[tcp->scno].nargs != -1)
2011 tcp->u_nargs = sysent[tcp->scno].nargs;
2012 else
2013 tcp->u_nargs = MAX_ARGS;
2014 for (i = 0; i < tcp->u_nargs; ++i) {
2015 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2016 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2017 return -1;
2018 }
2019 } else {
2020 int i;
2021
2022 if (/* EBX = out0 */
2023 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
2024 /* ECX = out1 */
2025 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
2026 /* EDX = out2 */
2027 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
2028 /* ESI = out3 */
2029 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
2030 /* EDI = out4 */
2031 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
2032 /* EBP = out5 */
2033 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2034 return -1;
2035
2036 for (i = 0; i < 6; ++i)
2037 /* truncate away IVE sign-extension */
2038 tcp->u_arg[i] &= 0xffffffff;
2039
2040 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2041 && sysent[tcp->scno].nargs != -1)
2042 tcp->u_nargs = sysent[tcp->scno].nargs;
2043 else
2044 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002045 }
2046 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002047#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2048 /* N32 and N64 both use up to six registers. */
2049 {
2050 unsigned long long regs[38];
2051 int i, nargs;
2052
2053 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2054 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002055 else
Roland McGrath542c2c62008-05-20 01:11:56 +00002056 nargs = tcp->u_nargs = MAX_ARGS;
2057
2058 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
2059 return -1;
2060
2061 for(i = 0; i < nargs; i++) {
2062 tcp->u_arg[i] = regs[REG_A0 + i];
2063# if defined (LINUX_MIPSN32)
2064 tcp->ext_arg[i] = regs[REG_A0 + i];
2065# endif
2066 }
2067 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002068#elif defined (MIPS)
2069 {
2070 long sp;
2071 int i, nargs;
2072
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002073 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2074 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002075 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002076 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002077 if(nargs > 4) {
2078 if(upeek(pid, REG_SP, &sp) < 0)
2079 return -1;
2080 for(i = 0; i < 4; i++) {
2081 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
2082 return -1;
2083 }
2084 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2085 (char *)(tcp->u_arg + 4));
2086 } else {
2087 for(i = 0; i < nargs; i++) {
2088 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
2089 return -1;
2090 }
2091 }
2092 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002093#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002094#ifndef PT_ORIG_R3
2095#define PT_ORIG_R3 34
2096#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002097 {
2098 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002099 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2100 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002101 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002102 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002103 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00002104 if (upeek(pid, (i==0) ?
2105 (sizeof(unsigned long)*PT_ORIG_R3) :
2106 ((i+PT_R3)*sizeof(unsigned long)),
2107 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002108 return -1;
2109 }
2110 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002111#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002112 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002113 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002114
2115 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2116 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002117 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002118 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002119 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002120 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002121 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002122#elif defined (HPPA)
2123 {
2124 int i;
2125
2126 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2127 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002128 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002129 tcp->u_nargs = MAX_ARGS;
2130 for (i = 0; i < tcp->u_nargs; i++) {
2131 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2132 return -1;
2133 }
2134 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002135#elif defined(ARM)
2136 {
2137 int i;
2138
2139 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2140 tcp->u_nargs = sysent[tcp->scno].nargs;
2141 else
2142 tcp->u_nargs = MAX_ARGS;
2143 for (i = 0; i < tcp->u_nargs; i++)
2144 tcp->u_arg[i] = regs.uregs[i];
2145 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002146#elif defined(BFIN)
2147 {
2148 int i;
2149 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2150
2151 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2152 tcp->u_nargs = sysent[tcp->scno].nargs;
2153 else
2154 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2155
2156 for (i = 0; i < tcp->u_nargs; ++i)
2157 if (upeek(pid, argreg[i], &tcp->u_arg[i]) < 0)
2158 return -1;
2159 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002160#elif defined(SH)
2161 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002162 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002163 static int syscall_regs[] = {
2164 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2165 REG_REG0, REG_REG0+1, REG_REG0+2
2166 };
2167
2168 tcp->u_nargs = sysent[tcp->scno].nargs;
2169 for (i = 0; i < tcp->u_nargs; i++) {
2170 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2171 return -1;
2172 }
2173 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002174#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002175 {
2176 int i;
2177 /* Registers used by SH5 Linux system calls for parameters */
2178 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2179
2180 /*
2181 * TODO: should also check that the number of arguments encoded
2182 * in the trap number matches the number strace expects.
2183 */
2184 /*
2185 assert(sysent[tcp->scno].nargs <
2186 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2187 */
2188
2189 tcp->u_nargs = sysent[tcp->scno].nargs;
2190 for (i = 0; i < tcp->u_nargs; i++) {
2191 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2192 return -1;
2193 }
2194 }
2195
Michal Ludvig0e035502002-09-23 15:41:01 +00002196#elif defined(X86_64)
2197 {
2198 int i;
2199 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2200 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002201 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002202 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002203
Michal Ludvig0e035502002-09-23 15:41:01 +00002204 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2205 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002206 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002207 tcp->u_nargs = MAX_ARGS;
2208 for (i = 0; i < tcp->u_nargs; i++) {
2209 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2210 return -1;
2211 }
2212 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002213#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002214 {
2215 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002216 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2217 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002218 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002219 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002220 for (i = 0; i < tcp->u_nargs; i++) {
2221 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2222 return -1;
2223 }
2224 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002225#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002226#endif /* LINUX */
2227#ifdef SUNOS4
2228 {
2229 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002230 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2231 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002232 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002233 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002234 for (i = 0; i < tcp->u_nargs; i++) {
2235 struct user *u;
2236
2237 if (upeek(pid, uoff(u_arg[0]) +
2238 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2239 return -1;
2240 }
2241 }
2242#endif /* SUNOS4 */
2243#ifdef SVR4
2244#ifdef MIPS
2245 /*
2246 * SGI is broken: even though it has pr_sysarg, it doesn't
2247 * set them on system call entry. Get a clue.
2248 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002249 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002250 tcp->u_nargs = sysent[tcp->scno].nargs;
2251 else
2252 tcp->u_nargs = tcp->status.pr_nsysarg;
2253 if (tcp->u_nargs > 4) {
2254 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2255 4*sizeof(tcp->u_arg[0]));
2256 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2257 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2258 }
2259 else {
2260 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2261 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2262 }
John Hughes25299712001-03-06 10:10:06 +00002263#elif UNIXWARE >= 2
2264 /*
2265 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2266 */
2267 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2268 tcp->u_nargs = sysent[tcp->scno].nargs;
2269 else
2270 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2271 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2272 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2273#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002274 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002275 tcp->u_nargs = sysent[tcp->scno].nargs;
2276 else
2277 tcp->u_nargs = tcp->status.pr_nsysarg;
2278 {
2279 int i;
2280 for (i = 0; i < tcp->u_nargs; i++)
2281 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2282 }
John Hughes25299712001-03-06 10:10:06 +00002283#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002284 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002285 tcp->u_nargs = sysent[tcp->scno].nargs;
2286 else
2287 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002288 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002289 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002290#else
2291 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002292#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002294#ifdef FREEBSD
2295 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2296 sysent[tcp->scno].nargs > tcp->status.val)
2297 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002298 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002299 tcp->u_nargs = tcp->status.val;
2300 if (tcp->u_nargs < 0)
2301 tcp->u_nargs = 0;
2302 if (tcp->u_nargs > MAX_ARGS)
2303 tcp->u_nargs = MAX_ARGS;
2304 switch(regs.r_eax) {
2305 case SYS___syscall:
2306 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2307 regs.r_esp + sizeof(int) + sizeof(quad_t));
2308 break;
2309 case SYS_syscall:
2310 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2311 regs.r_esp + 2 * sizeof(int));
2312 break;
2313 default:
2314 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2315 regs.r_esp + sizeof(int));
2316 break;
2317 }
2318#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002319 return 1;
2320}
2321
2322int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002323trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002324{
2325 int sys_res;
2326 struct timeval tv;
2327 int res;
2328
2329 /* Measure the exit time as early as possible to avoid errors. */
2330 if (dtime && (tcp->flags & TCB_INSYSCALL))
2331 gettimeofday(&tv, NULL);
2332
2333 res = get_scno(tcp);
2334 if (res != 1)
2335 return res;
2336
2337 res = syscall_fixup(tcp);
2338 if (res != 1)
2339 return res;
2340
2341 if (tcp->flags & TCB_INSYSCALL) {
2342 long u_error;
2343 res = get_error(tcp);
2344 if (res != 1)
2345 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002346
2347 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002348 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2349 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002350 tcp->flags &= ~TCB_INSYSCALL;
2351 return 0;
2352 }
2353
2354 if (tcp->flags & TCB_REPRINT) {
2355 printleader(tcp);
2356 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002357 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002358 tprintf("syscall_%lu", tcp->scno);
2359 else
2360 tprintf("%s", sysent[tcp->scno].sys_name);
2361 tprintf(" resumed> ");
2362 }
2363
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002364 if (cflag)
2365 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002366
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002367 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002368 || (qual_flags[tcp->scno] & QUAL_RAW))
2369 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002370 else {
2371 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002372 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002373 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002374 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002375 u_error = tcp->u_error;
2376 tprintf(") ");
2377 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002378 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2379 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002380 if (u_error)
2381 tprintf("= -1 (errno %ld)", u_error);
2382 else
2383 tprintf("= %#lx", tcp->u_rval);
2384 }
2385 else if (!(sys_res & RVAL_NONE) && u_error) {
2386 switch (u_error) {
2387#ifdef LINUX
2388 case ERESTARTSYS:
2389 tprintf("= ? ERESTARTSYS (To be restarted)");
2390 break;
2391 case ERESTARTNOINTR:
2392 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2393 break;
2394 case ERESTARTNOHAND:
2395 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2396 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002397 case ERESTART_RESTARTBLOCK:
2398 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2399 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002400#endif /* LINUX */
2401 default:
2402 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002403 if (u_error < 0)
2404 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002405 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002406 tprintf("%s (%s)", errnoent[u_error],
2407 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002408 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002409 tprintf("ERRNO_%ld (%s)", u_error,
2410 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002411 break;
2412 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002413 if ((sys_res & RVAL_STR) && tcp->auxstr)
2414 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002415 }
2416 else {
2417 if (sys_res & RVAL_NONE)
2418 tprintf("= ?");
2419 else {
2420 switch (sys_res & RVAL_MASK) {
2421 case RVAL_HEX:
2422 tprintf("= %#lx", tcp->u_rval);
2423 break;
2424 case RVAL_OCTAL:
2425 tprintf("= %#lo", tcp->u_rval);
2426 break;
2427 case RVAL_UDECIMAL:
2428 tprintf("= %lu", tcp->u_rval);
2429 break;
2430 case RVAL_DECIMAL:
2431 tprintf("= %ld", tcp->u_rval);
2432 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002433#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002434 case RVAL_LHEX:
2435 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002436 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002437 case RVAL_LOCTAL:
2438 tprintf("= %#llo", tcp->u_lrval);
2439 break;
2440 case RVAL_LUDECIMAL:
2441 tprintf("= %llu", tcp->u_lrval);
2442 break;
2443 case RVAL_LDECIMAL:
2444 tprintf("= %lld", tcp->u_lrval);
2445 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002446#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002447 default:
2448 fprintf(stderr,
2449 "invalid rval format\n");
2450 break;
2451 }
2452 }
2453 if ((sys_res & RVAL_STR) && tcp->auxstr)
2454 tprintf(" (%s)", tcp->auxstr);
2455 }
2456 if (dtime) {
2457 tv_sub(&tv, &tv, &tcp->etime);
2458 tprintf(" <%ld.%06ld>",
2459 (long) tv.tv_sec, (long) tv.tv_usec);
2460 }
2461 printtrailer(tcp);
2462
2463 dumpio(tcp);
2464 if (fflush(tcp->outf) == EOF)
2465 return -1;
2466 tcp->flags &= ~TCB_INSYSCALL;
2467 return 0;
2468 }
2469
2470 /* Entering system call */
2471 res = syscall_enter(tcp);
2472 if (res != 1)
2473 return res;
2474
Roland McGrath17352792005-06-07 23:21:26 +00002475 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002476#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002477 case SYS_socketcall:
2478 decode_subcall(tcp, SYS_socket_subcall,
2479 SYS_socket_nsubcalls, deref_style);
2480 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002481#endif
2482#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002483 case SYS_ipc:
2484 decode_subcall(tcp, SYS_ipc_subcall,
2485 SYS_ipc_nsubcalls, shift_style);
2486 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002487#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002488#ifdef SVR4
2489#ifdef SYS_pgrpsys_subcall
2490 case SYS_pgrpsys:
2491 decode_subcall(tcp, SYS_pgrpsys_subcall,
2492 SYS_pgrpsys_nsubcalls, shift_style);
2493 break;
2494#endif /* SYS_pgrpsys_subcall */
2495#ifdef SYS_sigcall_subcall
2496 case SYS_sigcall:
2497 decode_subcall(tcp, SYS_sigcall_subcall,
2498 SYS_sigcall_nsubcalls, mask_style);
2499 break;
2500#endif /* SYS_sigcall_subcall */
2501 case SYS_msgsys:
2502 decode_subcall(tcp, SYS_msgsys_subcall,
2503 SYS_msgsys_nsubcalls, shift_style);
2504 break;
2505 case SYS_shmsys:
2506 decode_subcall(tcp, SYS_shmsys_subcall,
2507 SYS_shmsys_nsubcalls, shift_style);
2508 break;
2509 case SYS_semsys:
2510 decode_subcall(tcp, SYS_semsys_subcall,
2511 SYS_semsys_nsubcalls, shift_style);
2512 break;
2513#if 0 /* broken */
2514 case SYS_utssys:
2515 decode_subcall(tcp, SYS_utssys_subcall,
2516 SYS_utssys_nsubcalls, shift_style);
2517 break;
2518#endif
2519 case SYS_sysfs:
2520 decode_subcall(tcp, SYS_sysfs_subcall,
2521 SYS_sysfs_nsubcalls, shift_style);
2522 break;
2523 case SYS_spcall:
2524 decode_subcall(tcp, SYS_spcall_subcall,
2525 SYS_spcall_nsubcalls, shift_style);
2526 break;
2527#ifdef SYS_context_subcall
2528 case SYS_context:
2529 decode_subcall(tcp, SYS_context_subcall,
2530 SYS_context_nsubcalls, shift_style);
2531 break;
2532#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002533#ifdef SYS_door_subcall
2534 case SYS_door:
2535 decode_subcall(tcp, SYS_door_subcall,
2536 SYS_door_nsubcalls, door_style);
2537 break;
2538#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002539#ifdef SYS_kaio_subcall
2540 case SYS_kaio:
2541 decode_subcall(tcp, SYS_kaio_subcall,
2542 SYS_kaio_nsubcalls, shift_style);
2543 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002544#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002545#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002546#ifdef FREEBSD
2547 case SYS_msgsys:
2548 case SYS_shmsys:
2549 case SYS_semsys:
2550 decode_subcall(tcp, 0, 0, table_style);
2551 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002552#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002553#ifdef SUNOS4
2554 case SYS_semsys:
2555 decode_subcall(tcp, SYS_semsys_subcall,
2556 SYS_semsys_nsubcalls, shift_style);
2557 break;
2558 case SYS_msgsys:
2559 decode_subcall(tcp, SYS_msgsys_subcall,
2560 SYS_msgsys_nsubcalls, shift_style);
2561 break;
2562 case SYS_shmsys:
2563 decode_subcall(tcp, SYS_shmsys_subcall,
2564 SYS_shmsys_nsubcalls, shift_style);
2565 break;
2566#endif
2567 }
2568
2569 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002570 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002571 tcp->flags |= TCB_INSYSCALL;
2572 return 0;
2573 }
2574
2575 if (cflag) {
2576 gettimeofday(&tcp->etime, NULL);
2577 tcp->flags |= TCB_INSYSCALL;
2578 return 0;
2579 }
2580
2581 printleader(tcp);
2582 tcp->flags &= ~TCB_REPRINT;
2583 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002584 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002585 tprintf("syscall_%lu(", tcp->scno);
2586 else
2587 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002588 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002589 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2590 sys_res = printargs(tcp);
2591 else
2592 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2593 if (fflush(tcp->outf) == EOF)
2594 return -1;
2595 tcp->flags |= TCB_INSYSCALL;
2596 /* Measure the entrance time as late as possible to avoid errors. */
2597 if (dtime)
2598 gettimeofday(&tcp->etime, NULL);
2599 return sys_res;
2600}
2601
2602int
2603printargs(tcp)
2604struct tcb *tcp;
2605{
2606 if (entering(tcp)) {
2607 int i;
2608
2609 for (i = 0; i < tcp->u_nargs; i++)
2610 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2611 }
2612 return 0;
2613}
2614
2615long
2616getrval2(tcp)
2617struct tcb *tcp;
2618{
2619 long val = -1;
2620
2621#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002622#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002623 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002624 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2625 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002626 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002627#elif defined(SH)
2628 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2629 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002630#elif defined(IA64)
2631 if (upeek(tcp->pid, PT_R9, &val) < 0)
2632 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002633#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002634#endif /* LINUX */
2635
2636#ifdef SUNOS4
2637 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2638 return -1;
2639#endif /* SUNOS4 */
2640
2641#ifdef SVR4
2642#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002643 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002644#endif /* SPARC */
2645#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002646 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002647#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002648#ifdef X86_64
2649 val = tcp->status.PR_REG[RDX];
2650#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002652 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002653#endif /* MIPS */
2654#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002655#ifdef FREEBSD
2656 struct reg regs;
2657 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2658 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002659#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002660 return val;
2661}
2662
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002663#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002664/*
2665 * Apparently, indirect system calls have already be converted by ptrace(2),
2666 * so if you see "indir" this program has gone astray.
2667 */
2668int
2669sys_indir(tcp)
2670struct tcb *tcp;
2671{
2672 int i, scno, nargs;
2673
2674 if (entering(tcp)) {
2675 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2676 fprintf(stderr, "Bogus syscall: %u\n", scno);
2677 return 0;
2678 }
2679 nargs = sysent[scno].nargs;
2680 tprintf("%s", sysent[scno].sys_name);
2681 for (i = 0; i < nargs; i++)
2682 tprintf(", %#lx", tcp->u_arg[i+1]);
2683 }
2684 return 0;
2685}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002686#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002687
2688int
2689is_restart_error(struct tcb *tcp)
2690{
2691#ifdef LINUX
2692 if (!syserror(tcp))
2693 return 0;
2694 switch (tcp->u_error) {
2695 case ERESTARTSYS:
2696 case ERESTARTNOINTR:
2697 case ERESTARTNOHAND:
2698 case ERESTART_RESTARTBLOCK:
2699 return 1;
2700 default:
2701 break;
2702 }
2703#endif /* LINUX */
2704 return 0;
2705}