blob: 128622de934370d119c4b88f66eb9bcb27032c5a [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>
Denys Vlasenko84e20af2009-02-10 16:03:20 +000041#include <sched.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000042#include <sys/user.h>
43#include <sys/syscall.h>
44#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000045
Wichert Akkerman15dea971999-10-06 13:06:34 +000046#if HAVE_ASM_REG_H
Denys Vlasenko84e20af2009-02-10 16:03:20 +000047# if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000048# define fpq kernel_fpq
49# define fq kernel_fq
50# define fpu kernel_fpu
Denys Vlasenko84e20af2009-02-10 16:03:20 +000051# endif
52# include <asm/reg.h>
53# if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000054# undef fpq
55# undef fq
Roland McGrath761b5d72002-12-15 23:58:31 +000056# undef fpu
Denys Vlasenko84e20af2009-02-10 16:03:20 +000057# endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000058#endif
59
Wichert Akkerman15dea971999-10-06 13:06:34 +000060#ifdef HAVE_SYS_REG_H
Denys Vlasenko84e20af2009-02-10 16:03:20 +000061# include <sys/reg.h>
62# ifndef PTRACE_PEEKUSR
63# define PTRACE_PEEKUSR PTRACE_PEEKUSER
64# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000065#elif defined(HAVE_LINUX_PTRACE_H)
Denys Vlasenko84e20af2009-02-10 16:03:20 +000066# undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000067# ifdef HAVE_STRUCT_IA64_FPREG
68# define ia64_fpreg XXX_ia64_fpreg
69# endif
70# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
71# define pt_all_user_regs XXX_pt_all_user_regs
72# endif
Denys Vlasenko84e20af2009-02-10 16:03:20 +000073# include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000074# undef ia64_fpreg
75# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000076#endif
77
Roland McGrath6d1a65c2004-07-12 07:44:08 +000078#if defined (LINUX) && defined (SPARC64)
79# define r_pc r_tpc
80# undef PTRACE_GETREGS
81# define PTRACE_GETREGS PTRACE_GETREGS64
82# undef PTRACE_SETREGS
83# define PTRACE_SETREGS PTRACE_SETREGS64
84#endif /* LINUX && SPARC64 */
85
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000086#if defined(LINUX) && defined(IA64)
87# include <asm/ptrace_offsets.h>
88# include <asm/rse.h>
89#endif
90
Pavel Machekd8ae7e32000-02-01 17:17:25 +000091#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092#ifdef LINUX
93#ifndef ERESTARTSYS
94#define ERESTARTSYS 512
95#endif
96#ifndef ERESTARTNOINTR
97#define ERESTARTNOINTR 513
98#endif
99#ifndef ERESTARTNOHAND
100#define ERESTARTNOHAND 514 /* restart if no handler.. */
101#endif
102#ifndef ENOIOCTLCMD
103#define ENOIOCTLCMD 515 /* No ioctl command */
104#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000105#ifndef ERESTART_RESTARTBLOCK
106#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
107#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000108#ifndef NSIG
109#define NSIG 32
110#endif
111#ifdef ARM
112#undef NSIG
113#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000114#undef NR_SYSCALL_BASE
115#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116#endif
117#endif /* LINUX */
118
119#include "syscall.h"
120
121/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000122#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123#define TF TRACE_FILE
124#define TI TRACE_IPC
125#define TN TRACE_NETWORK
126#define TP TRACE_PROCESS
127#define TS TRACE_SIGNAL
128
Roland McGrathee36ce12004-09-04 03:53:10 +0000129static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000130#include "syscallent.h"
131};
Roland McGrathee36ce12004-09-04 03:53:10 +0000132static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000133int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134
135#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000136static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000137#include "syscallent1.h"
138};
Roland McGrathee36ce12004-09-04 03:53:10 +0000139static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000140int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000141#endif /* SUPPORTED_PERSONALITIES >= 2 */
142
143#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000144static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000145#include "syscallent2.h"
146};
Roland McGrathee36ce12004-09-04 03:53:10 +0000147static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000148int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000149#endif /* SUPPORTED_PERSONALITIES >= 3 */
150
Roland McGrathee36ce12004-09-04 03:53:10 +0000151const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000152int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000153int nsyscalls;
154
155/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000156#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000157#undef TF
158#undef TI
159#undef TN
160#undef TP
161#undef TS
162
Roland McGrathee36ce12004-09-04 03:53:10 +0000163static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000164#include "errnoent.h"
165};
Roland McGrathee36ce12004-09-04 03:53:10 +0000166static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167
168#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000169static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000170#include "errnoent1.h"
171};
Roland McGrathee36ce12004-09-04 03:53:10 +0000172static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000173#endif /* SUPPORTED_PERSONALITIES >= 2 */
174
175#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000176static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000177#include "errnoent2.h"
178};
Roland McGrathee36ce12004-09-04 03:53:10 +0000179static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000180#endif /* SUPPORTED_PERSONALITIES >= 3 */
181
Roland McGrathee36ce12004-09-04 03:53:10 +0000182const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000183int nerrnos;
184
185int current_personality;
186
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000187#ifndef PERSONALITY0_WORDSIZE
188# define PERSONALITY0_WORDSIZE sizeof(long)
189#endif
190const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
191 PERSONALITY0_WORDSIZE,
192#if SUPPORTED_PERSONALITIES > 1
193 PERSONALITY1_WORDSIZE,
194#endif
195#if SUPPORTED_PERSONALITIES > 2
196 PERSONALITY2_WORDSIZE,
197#endif
198};;
199
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000200int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000201set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000202{
203 switch (personality) {
204 case 0:
205 errnoent = errnoent0;
206 nerrnos = nerrnos0;
207 sysent = sysent0;
208 nsyscalls = nsyscalls0;
209 ioctlent = ioctlent0;
210 nioctlents = nioctlents0;
211 signalent = signalent0;
212 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000213 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000214 break;
215
216#if SUPPORTED_PERSONALITIES >= 2
217 case 1:
218 errnoent = errnoent1;
219 nerrnos = nerrnos1;
220 sysent = sysent1;
221 nsyscalls = nsyscalls1;
222 ioctlent = ioctlent1;
223 nioctlents = nioctlents1;
224 signalent = signalent1;
225 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000226 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000227 break;
228#endif /* SUPPORTED_PERSONALITIES >= 2 */
229
230#if SUPPORTED_PERSONALITIES >= 3
231 case 2:
232 errnoent = errnoent2;
233 nerrnos = nerrnos2;
234 sysent = sysent2;
235 nsyscalls = nsyscalls2;
236 ioctlent = ioctlent2;
237 nioctlents = nioctlents2;
238 signalent = signalent2;
239 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000240 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000241 break;
242#endif /* SUPPORTED_PERSONALITIES >= 3 */
243
244 default:
245 return -1;
246 }
247
248 current_personality = personality;
249 return 0;
250}
251
Roland McGrathe10e62a2004-09-04 04:20:43 +0000252
Roland McGrath9797ceb2002-12-30 10:23:00 +0000253static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000254
Roland McGrathe10e62a2004-09-04 04:20:43 +0000255static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000256 int bitflag;
257 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000258 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000259 char *argument_name;
260} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000261 { QUAL_TRACE, "trace", qual_syscall, "system call" },
262 { QUAL_TRACE, "t", qual_syscall, "system call" },
263 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
264 { QUAL_ABBREV, "a", qual_syscall, "system call" },
265 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
266 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
267 { QUAL_RAW, "raw", qual_syscall, "system call" },
268 { QUAL_RAW, "x", qual_syscall, "system call" },
269 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
270 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
271 { QUAL_SIGNAL, "s", qual_signal, "signal" },
272 { QUAL_FAULT, "fault", qual_fault, "fault" },
273 { QUAL_FAULT, "faults", qual_fault, "fault" },
274 { QUAL_FAULT, "m", qual_fault, "fault" },
275 { QUAL_READ, "read", qual_desc, "descriptor" },
276 { QUAL_READ, "reads", qual_desc, "descriptor" },
277 { QUAL_READ, "r", qual_desc, "descriptor" },
278 { QUAL_WRITE, "write", qual_desc, "descriptor" },
279 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
280 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000281 { 0, NULL, NULL, NULL },
282};
283
Roland McGrath9797ceb2002-12-30 10:23:00 +0000284static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000285qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000286 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000287 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000288 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000289 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000290{
Roland McGrath138c6a32006-01-12 09:50:49 +0000291 if (pers == 0 || pers < 0) {
292 if (not)
293 qual_flags0[n] &= ~opt->bitflag;
294 else
295 qual_flags0[n] |= opt->bitflag;
296 }
297
298#if SUPPORTED_PERSONALITIES >= 2
299 if (pers == 1 || pers < 0) {
300 if (not)
301 qual_flags1[n] &= ~opt->bitflag;
302 else
303 qual_flags1[n] |= opt->bitflag;
304 }
305#endif /* SUPPORTED_PERSONALITIES >= 2 */
306
307#if SUPPORTED_PERSONALITIES >= 3
308 if (pers == 2 || pers < 0) {
309 if (not)
310 qual_flags2[n] &= ~opt->bitflag;
311 else
312 qual_flags2[n] |= opt->bitflag;
313 }
314#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000315}
316
317static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000318qual_syscall(s, opt, not)
319 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000320 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000321 int not;
322{
323 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000324 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000325
Roland McGrath48a035f2006-01-12 09:45:56 +0000326 if (isdigit((unsigned char)*s)) {
327 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000328 if (i < 0 || i >= MAX_QUALS)
Roland McGrath48a035f2006-01-12 09:45:56 +0000329 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000330 qualify_one(i, opt, not, -1);
Roland McGrath48a035f2006-01-12 09:45:56 +0000331 return 0;
332 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000333 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000334 if (strcmp(s, sysent0[i].sys_name) == 0) {
335 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000336 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000337 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000338
339#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000340 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000341 if (strcmp(s, sysent1[i].sys_name) == 0) {
342 qualify_one(i, opt, not, 1);
343 rc = 0;
344 }
345#endif /* SUPPORTED_PERSONALITIES >= 2 */
346
347#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000348 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000349 if (strcmp(s, sysent2[i].sys_name) == 0) {
350 qualify_one(i, opt, not, 2);
351 rc = 0;
352 }
353#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000354
Roland McGrathfe6b3522005-02-02 04:40:11 +0000355 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000356}
357
358static int
359qual_signal(s, opt, not)
360 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000361 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000362 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000363{
364 int i;
365 char buf[32];
366
Roland McGrath48a035f2006-01-12 09:45:56 +0000367 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000368 int signo = atoi(s);
369 if (signo < 0 || signo >= MAX_QUALS)
370 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000371 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000372 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000373 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000374 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000375 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000376 strcpy(buf, s);
377 s = buf;
378 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000379 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380 if (strncmp(s, "SIG", 3) == 0)
381 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000382 for (i = 0; i <= NSIG; i++)
383 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000384 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000385 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000386 }
Roland McGrath76421df2005-02-02 03:51:18 +0000387 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000388}
389
390static int
391qual_fault(s, opt, not)
392 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000393 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000394 int not;
395{
396 return -1;
397}
398
399static int
400qual_desc(s, opt, not)
401 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000402 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000403 int not;
404{
Roland McGrath48a035f2006-01-12 09:45:56 +0000405 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000406 int desc = atoi(s);
407 if (desc < 0 || desc >= MAX_QUALS)
408 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000409 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000410 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000411 }
412 return -1;
413}
414
415static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000416lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000417 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000418{
419 if (strcmp(s, "file") == 0)
420 return TRACE_FILE;
421 if (strcmp(s, "ipc") == 0)
422 return TRACE_IPC;
423 if (strcmp(s, "network") == 0)
424 return TRACE_NETWORK;
425 if (strcmp(s, "process") == 0)
426 return TRACE_PROCESS;
427 if (strcmp(s, "signal") == 0)
428 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000429 if (strcmp(s, "desc") == 0)
430 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000431 return -1;
432}
433
434void
435qualify(s)
436char *s;
437{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000438 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000439 int not;
440 char *p;
441 int i, n;
442
443 opt = &qual_options[0];
444 for (i = 0; (p = qual_options[i].option_name); i++) {
445 n = strlen(p);
446 if (strncmp(s, p, n) == 0 && s[n] == '=') {
447 opt = &qual_options[i];
448 s += n + 1;
449 break;
450 }
451 }
452 not = 0;
453 if (*s == '!') {
454 not = 1;
455 s++;
456 }
457 if (strcmp(s, "none") == 0) {
458 not = 1 - not;
459 s = "all";
460 }
461 if (strcmp(s, "all") == 0) {
462 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000463 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 }
465 return;
466 }
467 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000468 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000469 }
470 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
471 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000472 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000473 if (sysent0[i].sys_flags & n)
474 qualify_one(i, opt, not, 0);
475
476#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000477 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000478 if (sysent1[i].sys_flags & n)
479 qualify_one(i, opt, not, 1);
480#endif /* SUPPORTED_PERSONALITIES >= 2 */
481
482#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000483 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000484 if (sysent2[i].sys_flags & n)
485 qualify_one(i, opt, not, 2);
486#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000487
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000488 continue;
489 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000490 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000491 fprintf(stderr, "strace: invalid %s `%s'\n",
492 opt->argument_name, p);
493 exit(1);
494 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000495 }
496 return;
497}
498
499static void
500dumpio(tcp)
501struct tcb *tcp;
502{
503 if (syserror(tcp))
504 return;
505 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
506 return;
Roland McGrath17352792005-06-07 23:21:26 +0000507 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000508 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000509#ifdef SYS_pread64
510 case SYS_pread64:
511#endif
512#if defined SYS_pread && SYS_pread64 != SYS_pread
513 case SYS_pread:
514#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000515#ifdef SYS_recv
516 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000517#elif defined SYS_sub_recv
518 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000519#endif
520#ifdef SYS_recvfrom
521 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000522#elif defined SYS_sub_recvfrom
523 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000524#endif
525 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
526 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
527 break;
528 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000529#ifdef SYS_pwrite64
530 case SYS_pwrite64:
531#endif
532#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
533 case SYS_pwrite:
534#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000535#ifdef SYS_send
536 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000537#elif defined SYS_sub_send
538 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539#endif
540#ifdef SYS_sendto
541 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000542#elif defined SYS_sub_sendto
543 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544#endif
545 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
546 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
547 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000548#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000549 case SYS_readv:
550 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
551 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
552 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000553#endif
554#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000555 case SYS_writev:
556 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
557 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
558 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000559#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
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000585#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
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)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000772 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000773#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000774 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000775#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000776 static long rax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000777#elif defined(CRISV10) || defined(CRISV32)
778 static long r10;
Roland McGrath761b5d72002-12-15 23:58:31 +0000779#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000780#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000781#ifdef FREEBSD
782 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000783#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000784
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000786get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000788 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000791# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000792 if (tcp->flags & TCB_WAITEXECVE) {
793 /*
794 * When the execve system call completes successfully, the
795 * new process still has -ENOSYS (old style) or __NR_execve
796 * (new style) in gpr2. We cannot recover the scno again
797 * by disassembly, because the image that executed the
798 * syscall is gone now. Fortunately, we don't want it. We
799 * leave the flag set so that syscall_fixup can fake the
800 * result.
801 */
802 if (tcp->flags & TCB_INSYSCALL)
803 return 1;
804 /*
805 * This is the SIGTRAP after execve. We cannot try to read
806 * the system call here either.
807 */
808 tcp->flags &= ~TCB_WAITEXECVE;
809 return 0;
810 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000811
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000812 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000813 return -1;
814
815 if (syscall_mode != -ENOSYS) {
816 /*
817 * Since kernel version 2.5.44 the scno gets passed in gpr2.
818 */
819 scno = syscall_mode;
820 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000821 /*
822 * Old style of "passing" the scno via the SVC instruction.
823 */
824
825 long opcode, offset_reg, tmp;
826 void * svc_addr;
827 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
828 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
829 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
830 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000831
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000832 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000833 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000834 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000835 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000836 if (errno) {
837 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000838 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000839 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000840
841 /*
842 * We have to check if the SVC got executed directly or via an
843 * EXECUTE instruction. In case of EXECUTE it is necessary to do
844 * instruction decoding to derive the system call number.
845 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
846 * so that this doesn't work if a SVC opcode is part of an EXECUTE
847 * opcode. Since there is no way to find out the opcode size this
848 * is the best we can do...
849 */
850
851 if ((opcode & 0xff00) == 0x0a00) {
852 /* SVC opcode */
853 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000854 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000855 else {
856 /* SVC got executed by EXECUTE instruction */
857
858 /*
859 * Do instruction decoding of EXECUTE. If you really want to
860 * understand this, read the Principles of Operations.
861 */
862 svc_addr = (void *) (opcode & 0xfff);
863
864 tmp = 0;
865 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000866 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000867 return -1;
868 svc_addr += tmp;
869
870 tmp = 0;
871 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000872 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000873 return -1;
874 svc_addr += tmp;
875
Denys Vlasenkofb036672009-01-23 16:30:26 +0000876 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000877 if (errno)
878 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000879# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000880 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000881# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000882 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000883# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000884 tmp = 0;
885 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000886 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000887 return -1;
888
889 scno = (scno | tmp) & 0xff;
890 }
891 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000892# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000893 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 return -1;
895 if (!(tcp->flags & TCB_INSYSCALL)) {
896 /* Check if we return from execve. */
897 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
898 tcp->flags &= ~TCB_WAITEXECVE;
899 return 0;
900 }
901 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000902# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000903 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000904 return -1;
905 /* Check if we return from execve. */
906 if (tcp->flags & TCB_WAITEXECVE && tcp->flags & TCB_INSYSCALL)
907 tcp->flags &= ~(TCB_INSYSCALL | TCB_WAITEXECVE);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000908# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000909 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000910 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000911# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000912 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000913 return -1;
914
Roland McGrath761b5d72002-12-15 23:58:31 +0000915 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko8236f252009-01-02 18:10:08 +0000916 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000917 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000918 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000919
920 /* Check CS register value. On x86-64 linux it is:
921 * 0x33 for long mode (64 bit)
922 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000923 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000924 * to be cached.
925 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000926 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000927 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000928 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000929 case 0x23: currpers = 1; break;
930 case 0x33: currpers = 0; break;
931 default:
932 fprintf(stderr, "Unknown value CS=0x%02X while "
933 "detecting personality of process "
934 "PID=%d\n", (int)val, pid);
935 currpers = current_personality;
936 break;
937 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000938# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000939 /* This version analyzes the opcode of a syscall instruction.
940 * (int 0x80 on i386 vs. syscall on x86-64)
941 * It works, but is too complicated.
942 */
943 unsigned long val, rip, i;
944
Denys Vlasenko8236f252009-01-02 18:10:08 +0000945 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000946 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000947
Michal Ludvig0e035502002-09-23 15:41:01 +0000948 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000949 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000950 errno = 0;
951
Denys Vlasenko8236f252009-01-02 18:10:08 +0000952 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000953 if (errno)
954 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000955 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000956 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000957 /* x86-64: syscall = 0x0f 0x05 */
958 case 0x050f: currpers = 0; break;
959 /* i386: int 0x80 = 0xcd 0x80 */
960 case 0x80cd: currpers = 1; break;
961 default:
962 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000963 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000964 "Unknown syscall opcode (0x%04X) while "
965 "detecting personality of process "
966 "PID=%d\n", (int)call, pid);
967 break;
968 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000969# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000970 if (currpers != current_personality) {
971 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000972 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000973 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000974 pid, names[current_personality]);
975 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000976 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000977# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000978# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000979 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000980 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000981 if (!(tcp->flags & TCB_INSYSCALL)) {
982 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000983 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000984 return -1;
985 } else {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000986 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000987 return -1;
988 }
Roland McGrathba954762003-03-05 06:29:06 +0000989 /* Check if we return from execve. */
990 if (tcp->flags & TCB_WAITEXECVE) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000991# if defined PTRACE_GETSIGINFO
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000992 siginfo_t si;
993
994 tcp->flags &= ~TCB_WAITEXECVE;
995 /* If SIGTRAP is masked, execve's magic SIGTRAP
996 * is not delivered. We end up here on a subsequent
997 * ptrace stop instead. Luckily, we can check
998 * for the type of this SIGTRAP. execve's magic one
999 * has 0 (SI_USER) in si.si_code, ptrace stop has 5.
1000 * (I don't know why 5).
1001 */
1002 si.si_code = SI_USER;
1003 /* If PTRACE_GETSIGINFO fails, we assume it's
1004 * magic SIGTRAP. Moot anyway, PTRACE_GETSIGINFO
1005 * doesn't fail.
1006 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001007 ptrace(PTRACE_GETSIGINFO, tcp->pid, (void*) 0, (void*) &si);
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001008 if (si.si_code == SI_USER)
1009 return 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001010# else
Roland McGrathba954762003-03-05 06:29:06 +00001011 tcp->flags &= ~TCB_WAITEXECVE;
1012 return 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001013# endif
Roland McGrathba954762003-03-05 06:29:06 +00001014 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001015 } else {
1016 /* syscall in progress */
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001017 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001018 return -1;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001019 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001020 return -1;
1021 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001022# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001023 /*
1024 * Read complete register set in one go.
1025 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001026 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001027 return -1;
1028
1029 /*
1030 * We only need to grab the syscall number on syscall entry.
1031 */
1032 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001033 if (!(tcp->flags & TCB_INSYSCALL)) {
1034 /* Check if we return from execve. */
1035 if (tcp->flags & TCB_WAITEXECVE) {
1036 tcp->flags &= ~TCB_WAITEXECVE;
1037 return 0;
1038 }
1039 }
1040
Roland McGrath0f87c492003-06-03 23:29:04 +00001041 /*
1042 * Note: we only deal with only 32-bit CPUs here.
1043 */
1044 if (regs.ARM_cpsr & 0x20) {
1045 /*
1046 * Get the Thumb-mode system call number
1047 */
1048 scno = regs.ARM_r7;
1049 } else {
1050 /*
1051 * Get the ARM-mode system call number
1052 */
1053 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001054 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001055 if (errno)
1056 return -1;
1057
1058 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1059 tcp->flags &= ~TCB_WAITEXECVE;
1060 return 0;
1061 }
1062
Roland McGrathf691bd22006-04-25 07:34:41 +00001063 /* Handle the EABI syscall convention. We do not
1064 bother converting structures between the two
1065 ABIs, but basic functionality should work even
1066 if strace and the traced program have different
1067 ABIs. */
1068 if (scno == 0xef000000) {
1069 scno = regs.ARM_r7;
1070 } else {
1071 if ((scno & 0x0ff00000) != 0x0f900000) {
1072 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1073 scno);
1074 return -1;
1075 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001076
Roland McGrathf691bd22006-04-25 07:34:41 +00001077 /*
1078 * Fixup the syscall number
1079 */
1080 scno &= 0x000fffff;
1081 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001082 }
Roland McGrath56703312008-05-20 01:35:55 +00001083 if (scno & 0x0f0000) {
1084 /*
1085 * Handle ARM specific syscall
1086 */
1087 set_personality(1);
1088 scno &= 0x0000ffff;
1089 } else
1090 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001091
1092 if (tcp->flags & TCB_INSYSCALL) {
1093 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1094 tcp->flags &= ~TCB_INSYSCALL;
1095 }
1096 } else {
1097 if (!(tcp->flags & TCB_INSYSCALL)) {
1098 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1099 tcp->flags |= TCB_INSYSCALL;
1100 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001102# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001103 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001104 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001105# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001106 unsigned long long regs[38];
1107
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001108 if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001109 return -1;
1110 a3 = regs[REG_A3];
1111 r2 = regs[REG_V0];
1112
1113 if(!(tcp->flags & TCB_INSYSCALL)) {
1114 scno = r2;
1115
1116 /* Check if we return from execve. */
1117 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1118 tcp->flags &= ~TCB_WAITEXECVE;
1119 return 0;
1120 }
1121
1122 if (scno < 0 || scno > nsyscalls) {
1123 if(a3 == 0 || a3 == -1) {
1124 if(debug)
1125 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1126 return 0;
1127 }
1128 }
1129 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001130# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001131 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001132 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001133 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001134 if (upeek(tcp, REG_V0, &scno) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001135 return -1;
1136
Roland McGrath542c2c62008-05-20 01:11:56 +00001137 /* Check if we return from execve. */
1138 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1139 tcp->flags &= ~TCB_WAITEXECVE;
1140 return 0;
1141 }
1142
Wichert Akkermanf90da011999-10-31 21:15:38 +00001143 if (scno < 0 || scno > nsyscalls) {
1144 if(a3 == 0 || a3 == -1) {
1145 if(debug)
1146 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1147 return 0;
1148 }
1149 }
1150 } else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001151 if (upeek(tcp, REG_V0, &r2) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001152 return -1;
1153 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001154# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001155 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001156 return -1;
1157
1158 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001159 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160 return -1;
1161
1162 /* Check if we return from execve. */
1163 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1164 tcp->flags &= ~TCB_WAITEXECVE;
1165 return 0;
1166 }
1167
1168 /*
1169 * Do some sanity checks to figure out if it's
1170 * really a syscall entry
1171 */
1172 if (scno < 0 || scno > nsyscalls) {
1173 if (a3 == 0 || a3 == -1) {
1174 if (debug)
1175 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1176 return 0;
1177 }
1178 }
1179 }
1180 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001181 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182 return -1;
1183 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001184# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001186 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001187 return -1;
1188
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001189 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190 if (!(tcp->flags & TCB_INSYSCALL)) {
1191 /* Retrieve the syscall trap instruction. */
1192 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001193 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.r_pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001194# if defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001195 trap >>= 32;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001196# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197 if (errno)
1198 return -1;
1199
1200 /* Disassemble the trap to see what personality to use. */
1201 switch (trap) {
1202 case 0x91d02010:
1203 /* Linux/SPARC syscall trap. */
1204 set_personality(0);
1205 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001206 case 0x91d0206d:
1207 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001208 set_personality(2);
1209 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210 case 0x91d02000:
1211 /* SunOS syscall trap. (pers 1) */
1212 fprintf(stderr,"syscall: SunOS no support\n");
1213 return -1;
1214 case 0x91d02008:
1215 /* Solaris 2.x syscall trap. (per 2) */
1216 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001217 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001218 case 0x91d02009:
1219 /* NetBSD/FreeBSD syscall trap. */
1220 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1221 return -1;
1222 case 0x91d02027:
1223 /* Solaris 2.x gettimeofday */
1224 set_personality(1);
1225 break;
1226 default:
1227 /* Unknown syscall trap. */
1228 if(tcp->flags & TCB_WAITEXECVE) {
1229 tcp->flags &= ~TCB_WAITEXECVE;
1230 return 0;
1231 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001232# if defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001233 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001234# else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001235 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001236# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001237 return -1;
1238 }
1239
1240 /* Extract the system call number from the registers. */
1241 if (trap == 0x91d02027)
1242 scno = 156;
1243 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001244 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001246 scno = regs.r_o0;
1247 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248 }
1249 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001250# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001251 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001252 return -1;
1253 if (!(tcp->flags & TCB_INSYSCALL)) {
1254 /* Check if we return from execve. */
1255 if ((tcp->flags & TCB_WAITEXECVE)) {
1256 tcp->flags &= ~TCB_WAITEXECVE;
1257 return 0;
1258 }
1259 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001260# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001261 /*
1262 * In the new syscall ABI, the system call number is in R3.
1263 */
1264 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1265 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001266
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001267 if (scno < 0) {
1268 /* Odd as it may seem, a glibc bug has been known to cause
1269 glibc to issue bogus negative syscall numbers. So for
1270 our purposes, make strace print what it *should* have been */
1271 long correct_scno = (scno & 0xff);
1272 if (debug)
1273 fprintf(stderr,
1274 "Detected glibc bug: bogus system call"
1275 " number = %ld, correcting to %ld\n",
1276 scno,
1277 correct_scno);
1278 scno = correct_scno;
1279 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001280
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001281 if (!(tcp->flags & TCB_INSYSCALL)) {
1282 /* Check if we return from execve. */
1283 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1284 tcp->flags &= ~TCB_WAITEXECVE;
1285 return 0;
1286 }
1287 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001288# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001289 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001290 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001291 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001292
1293 if (!(tcp->flags & TCB_INSYSCALL)) {
1294 /* Check if we return from execve. */
1295 if (tcp->flags & TCB_WAITEXECVE) {
1296 tcp->flags &= ~TCB_WAITEXECVE;
1297 return 0;
1298 }
1299 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001300# elif defined(CRISV10) || defined(CRISV32)
1301 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1302 return -1;
1303# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001305
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001306#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001307 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001308 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001309#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001310 /* new syscall ABI returns result in R0 */
1311 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1312 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001313#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001314 /* ABI defines result returned in r9 */
1315 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1316 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001318
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001319#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001320# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001321 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001322# else
1323# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001324 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001325# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001326 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001327 perror("pread");
1328 return -1;
1329 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001330 switch (regs.r_eax) {
1331 case SYS_syscall:
1332 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001333 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1334 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001335 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001336 scno = regs.r_eax;
1337 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001338 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001339# endif /* FREEBSD */
1340# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001341#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001342
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001343 if (!(tcp->flags & TCB_INSYSCALL))
1344 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001345 return 1;
1346}
1347
Pavel Machek4dc3b142000-02-01 17:58:41 +00001348
Roland McGrath17352792005-06-07 23:21:26 +00001349long
1350known_scno(tcp)
1351struct tcb *tcp;
1352{
1353 long scno = tcp->scno;
1354 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1355 scno = sysent[scno].native_scno;
1356 else
1357 scno += NR_SYSCALL_BASE;
1358 return scno;
1359}
1360
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001361/* Called in trace_syscall at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001362 * Returns:
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001363 * 0: "ignore this syscall", bail out of trace_syscall silently.
1364 * 1: ok, continue in trace_syscall.
1365 * other: error, trace_syscall should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001366 * ("????" etc) and bail out.
1367 */
Roland McGratha4d48532005-06-08 20:45:28 +00001368static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001369syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001370{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001371#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001372 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001373
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001375 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376 if (
1377 scno == SYS_fork
1378#ifdef SYS_vfork
1379 || scno == SYS_vfork
1380#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001381#ifdef SYS_fork1
1382 || scno == SYS_fork1
1383#endif /* SYS_fork1 */
1384#ifdef SYS_forkall
1385 || scno == SYS_forkall
1386#endif /* SYS_forkall */
1387#ifdef SYS_rfork1
1388 || scno == SYS_rfork1
1389#endif /* SYS_fork1 */
1390#ifdef SYS_rforkall
1391 || scno == SYS_rforkall
1392#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001393 ) {
1394 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001395 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001396 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001397 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001398 }
1399 else {
1400 fprintf(stderr, "syscall: missing entry\n");
1401 tcp->flags |= TCB_INSYSCALL;
1402 }
1403 }
1404 }
1405 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001406 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001407 fprintf(stderr, "syscall: missing exit\n");
1408 tcp->flags &= ~TCB_INSYSCALL;
1409 }
1410 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001411#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001412#ifdef SUNOS4
1413 if (!(tcp->flags & TCB_INSYSCALL)) {
1414 if (scno == 0) {
1415 fprintf(stderr, "syscall: missing entry\n");
1416 tcp->flags |= TCB_INSYSCALL;
1417 }
1418 }
1419 else {
1420 if (scno != 0) {
1421 if (debug) {
1422 /*
1423 * This happens when a signal handler
1424 * for a signal which interrupted a
1425 * a system call makes another system call.
1426 */
1427 fprintf(stderr, "syscall: missing exit\n");
1428 }
1429 tcp->flags &= ~TCB_INSYSCALL;
1430 }
1431 }
1432#endif /* SUNOS4 */
1433#ifdef LINUX
1434#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001435 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001436 return -1;
1437 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1438 if (debug)
1439 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1440 return 0;
1441 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001442#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001443 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001444 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001445 if (current_personality == 1)
1446 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001447 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1448 if (debug)
1449 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1450 return 0;
1451 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001452#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001453 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001454 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001455 if (syscall_mode != -ENOSYS)
1456 syscall_mode = tcp->scno;
1457 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001458 if (debug)
1459 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1460 return 0;
1461 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001462 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1463 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1464 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1465 /*
1466 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1467 * flag set for the post-execve SIGTRAP to see and reset.
1468 */
1469 gpr2 = 0;
1470 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001471#elif defined (POWERPC)
1472# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001473 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001474 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001475 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001476 return -1;
1477 if (flags & SO_MASK)
1478 result = -result;
1479#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001480 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001481 return -1;
1482 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1483 if (debug)
1484 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1485 return 0;
1486 }
1487#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001488 /*
1489 * Nothing required
1490 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001491#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001492 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001493 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001494#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001495 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001496 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001497#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001498 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001499 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001500 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001501 return -1;
1502 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1503 if (debug)
1504 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1505 return 0;
1506 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001507#elif defined(CRISV10) || defined(CRISV32)
1508 if (upeek(tcp->pid, 4*PT_R10, &r10) < 0)
1509 return -1;
1510 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1511 if (debug)
1512 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1513 return 0;
1514 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001515#endif
1516#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001517 return 1;
1518}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001519
Roland McGrathc1e45922008-05-27 23:18:29 +00001520#ifdef LINUX
1521/*
1522 * Check the syscall return value register value for whether it is
1523 * a negated errno code indicating an error, or a success return value.
1524 */
1525static inline int
1526is_negated_errno(unsigned long int val)
1527{
1528 unsigned long int max = -(long int) nerrnos;
1529 if (personality_wordsize[current_personality] < sizeof(val)) {
1530 val = (unsigned int) val;
1531 max = (unsigned int) max;
1532 }
1533 return val > max;
1534}
1535#endif
1536
Roland McGratha4d48532005-06-08 20:45:28 +00001537static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001538get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001539{
1540 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001541#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001542# if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001543 if (is_negated_errno(gpr2)) {
1544 tcp->u_rval = -1;
1545 u_error = -gpr2;
1546 }
1547 else {
1548 tcp->u_rval = gpr2;
1549 u_error = 0;
1550 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001551# elif defined(I386)
Roland McGrathc1e45922008-05-27 23:18:29 +00001552 if (is_negated_errno(eax)) {
1553 tcp->u_rval = -1;
1554 u_error = -eax;
1555 }
1556 else {
1557 tcp->u_rval = eax;
1558 u_error = 0;
1559 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001560# elif defined(X86_64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001561 if (is_negated_errno(rax)) {
1562 tcp->u_rval = -1;
1563 u_error = -rax;
1564 }
1565 else {
1566 tcp->u_rval = rax;
1567 u_error = 0;
1568 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001569# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001570 if (ia32) {
1571 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001572
Roland McGrathc1e45922008-05-27 23:18:29 +00001573 err = (int)r8;
1574 if (is_negated_errno(err)) {
1575 tcp->u_rval = -1;
1576 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001577 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001578 else {
1579 tcp->u_rval = err;
1580 u_error = 0;
1581 }
1582 } else {
1583 if (r10) {
1584 tcp->u_rval = -1;
1585 u_error = r8;
1586 } else {
1587 tcp->u_rval = r8;
1588 u_error = 0;
1589 }
1590 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001591# elif defined(MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001592 if (a3) {
1593 tcp->u_rval = -1;
1594 u_error = r2;
1595 } else {
1596 tcp->u_rval = r2;
1597 u_error = 0;
1598 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001599# elif defined(POWERPC)
Roland McGrathc1e45922008-05-27 23:18:29 +00001600 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601 tcp->u_rval = -1;
1602 u_error = -result;
1603 }
1604 else {
1605 tcp->u_rval = result;
1606 u_error = 0;
1607 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001608# elif defined(M68K)
Roland McGrathc1e45922008-05-27 23:18:29 +00001609 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001610 tcp->u_rval = -1;
1611 u_error = -d0;
1612 }
1613 else {
1614 tcp->u_rval = d0;
1615 u_error = 0;
1616 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001617# elif defined(ARM)
Roland McGrathc1e45922008-05-27 23:18:29 +00001618 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001620 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 }
1622 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001623 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001624 u_error = 0;
1625 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001626# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001627 if (is_negated_errno(r0)) {
1628 tcp->u_rval = -1;
1629 u_error = -r0;
1630 } else {
1631 tcp->u_rval = r0;
1632 u_error = 0;
1633 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001634# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001635 if (a3) {
1636 tcp->u_rval = -1;
1637 u_error = r0;
1638 }
1639 else {
1640 tcp->u_rval = r0;
1641 u_error = 0;
1642 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001643# elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001644 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001646 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647 }
1648 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001649 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650 u_error = 0;
1651 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001652# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001653 if (regs.r_tstate & 0x1100000000UL) {
1654 tcp->u_rval = -1;
1655 u_error = regs.r_o0;
1656 }
1657 else {
1658 tcp->u_rval = regs.r_o0;
1659 u_error = 0;
1660 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001661# elif defined(HPPA)
Roland McGrathc1e45922008-05-27 23:18:29 +00001662 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001663 tcp->u_rval = -1;
1664 u_error = -r28;
1665 }
1666 else {
1667 tcp->u_rval = r28;
1668 u_error = 0;
1669 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001670# elif defined(SH)
Roland McGrathc1e45922008-05-27 23:18:29 +00001671 /* interpret R0 as return value or error number */
1672 if (is_negated_errno(r0)) {
1673 tcp->u_rval = -1;
1674 u_error = -r0;
1675 }
1676 else {
1677 tcp->u_rval = r0;
1678 u_error = 0;
1679 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001680# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001681 /* interpret result as return value or error number */
1682 if (is_negated_errno(r9)) {
1683 tcp->u_rval = -1;
1684 u_error = -r9;
1685 }
1686 else {
1687 tcp->u_rval = r9;
1688 u_error = 0;
1689 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001690# elif defined(CRISV10) || defined(CRISV32)
1691 if (r10 && (unsigned) -r10 < nerrnos) {
1692 tcp->u_rval = -1;
1693 u_error = -r10;
1694 }
1695 else {
1696 tcp->u_rval = r10;
1697 u_error = 0;
1698 }
1699# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001700#endif /* LINUX */
1701#ifdef SUNOS4
1702 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001703 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001704 return -1;
1705 u_error >>= 24; /* u_error is a char */
1706
1707 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001708 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709 return -1;
1710#endif /* SUNOS4 */
1711#ifdef SVR4
1712#ifdef SPARC
1713 /* Judicious guessing goes a long way. */
1714 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1715 tcp->u_rval = -1;
1716 u_error = tcp->status.pr_reg[R_O0];
1717 }
1718 else {
1719 tcp->u_rval = tcp->status.pr_reg[R_O0];
1720 u_error = 0;
1721 }
1722#endif /* SPARC */
1723#ifdef I386
1724 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001725 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001726 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001727 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 }
1729 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001730 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001731#ifdef HAVE_LONG_LONG
1732 tcp->u_lrval =
1733 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1734 tcp->status.PR_REG[EAX];
1735#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001736 u_error = 0;
1737 }
1738#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001739#ifdef X86_64
1740 /* Wanna know how to kill an hour single-stepping? */
1741 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1742 tcp->u_rval = -1;
1743 u_error = tcp->status.PR_REG[RAX];
1744 }
1745 else {
1746 tcp->u_rval = tcp->status.PR_REG[RAX];
1747 u_error = 0;
1748 }
1749#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001750#ifdef MIPS
1751 if (tcp->status.pr_reg[CTX_A3]) {
1752 tcp->u_rval = -1;
1753 u_error = tcp->status.pr_reg[CTX_V0];
1754 }
1755 else {
1756 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1757 u_error = 0;
1758 }
1759#endif /* MIPS */
1760#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001761#ifdef FREEBSD
1762 if (regs.r_eflags & PSL_C) {
1763 tcp->u_rval = -1;
1764 u_error = regs.r_eax;
1765 } else {
1766 tcp->u_rval = regs.r_eax;
1767 tcp->u_lrval =
1768 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1769 u_error = 0;
1770 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001771#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001772 tcp->u_error = u_error;
1773 return 1;
1774}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001775
Roland McGrathb69f81b2002-12-21 23:25:18 +00001776int
1777force_result(tcp, error, rval)
1778 struct tcb *tcp;
1779 int error;
1780 long rval;
1781{
1782#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001783# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001784 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001785 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1786 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001787# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001788 eax = error ? -error : rval;
1789 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1790 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001791# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001792 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001793 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001794 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001795# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001796 if (ia32) {
1797 r8 = error ? -error : rval;
1798 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1799 return -1;
1800 }
1801 else {
1802 if (error) {
1803 r8 = error;
1804 r10 = -1;
1805 }
1806 else {
1807 r8 = rval;
1808 r10 = 0;
1809 }
1810 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1811 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1812 return -1;
1813 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001814# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001815 r0 = error ? -error : rval;
1816 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1817 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001818# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001819 if (error) {
1820 r2 = error;
1821 a3 = -1;
1822 }
1823 else {
1824 r2 = rval;
1825 a3 = 0;
1826 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001827 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001828 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1829 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1830 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001831# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001832 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001833 return -1;
1834 if (error) {
1835 flags |= SO_MASK;
1836 result = error;
1837 }
1838 else {
1839 flags &= ~SO_MASK;
1840 result = rval;
1841 }
Roland McGratheb285352003-01-14 09:59:00 +00001842 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1843 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001844 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001845# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001846 d0 = error ? -error : rval;
1847 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1848 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001849# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001850 regs.ARM_r0 = error ? -error : rval;
1851 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001852 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001853# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001854 if (error) {
1855 a3 = -1;
1856 r0 = error;
1857 }
1858 else {
1859 a3 = 0;
1860 r0 = rval;
1861 }
1862 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1863 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1864 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001865# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001866 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1867 return -1;
1868 if (error) {
1869 regs.r_psr |= PSR_C;
1870 regs.r_o0 = error;
1871 }
1872 else {
1873 regs.r_psr &= ~PSR_C;
1874 regs.r_o0 = rval;
1875 }
1876 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1877 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001878# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001879 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1880 return -1;
1881 if (error) {
1882 regs.r_tstate |= 0x1100000000UL;
1883 regs.r_o0 = error;
1884 }
1885 else {
1886 regs.r_tstate &= ~0x1100000000UL;
1887 regs.r_o0 = rval;
1888 }
1889 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1890 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001891# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001892 r28 = error ? -error : rval;
1893 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1894 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001895# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001896 r0 = error ? -error : rval;
1897 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1898 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001899# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001900 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001901 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1902 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001903# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001904#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001905
Roland McGrathb69f81b2002-12-21 23:25:18 +00001906#ifdef SUNOS4
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001907 if (do_ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error), error << 24) < 0
1908 || do_ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0
1909 ) {
Roland McGrathb69f81b2002-12-21 23:25:18 +00001910 return -1;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001911 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001912#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001913
Roland McGrathb69f81b2002-12-21 23:25:18 +00001914#ifdef SVR4
1915 /* XXX no clue */
1916 return -1;
1917#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001918
Roland McGrathb69f81b2002-12-21 23:25:18 +00001919#ifdef FREEBSD
1920 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001921 perror("pread");
1922 return -1;
1923 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001924 if (error) {
1925 regs.r_eflags |= PSL_C;
1926 regs.r_eax = error;
1927 }
1928 else {
1929 regs.r_eflags &= ~PSL_C;
1930 regs.r_eax = rval;
1931 }
1932 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001933 perror("pwrite");
1934 return -1;
1935 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001936#endif /* FREEBSD */
1937
1938 /* All branches reach here on success (only). */
1939 tcp->u_error = error;
1940 tcp->u_rval = rval;
1941 return 0;
1942}
1943
Roland McGratha4d48532005-06-08 20:45:28 +00001944static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001945syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001946{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001947#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001948#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001949 {
1950 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001951 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1952 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001953 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001954 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001955 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001956 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001957 return -1;
1958 }
1959 }
1960#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001961 {
1962 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001963 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1964 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001965 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001966 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001967 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001968 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1969 * for scno somewhere above here!
1970 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001971 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001972 return -1;
1973 }
1974 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001975#elif defined (IA64)
1976 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001977 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001978 unsigned long *out0, cfm, sof, sol, i;
1979 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001980 /* be backwards compatible with kernel < 2.4.4... */
1981# ifndef PT_RBS_END
1982# define PT_RBS_END PT_AR_BSP
1983# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001984
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001985 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001986 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001987 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001988 return -1;
1989
1990 sof = (cfm >> 0) & 0x7f;
1991 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001992 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001993
1994 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1995 && sysent[tcp->scno].nargs != -1)
1996 tcp->u_nargs = sysent[tcp->scno].nargs;
1997 else
1998 tcp->u_nargs = MAX_ARGS;
1999 for (i = 0; i < tcp->u_nargs; ++i) {
2000 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2001 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2002 return -1;
2003 }
2004 } else {
2005 int i;
2006
2007 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002008 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002009 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002010 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002011 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002012 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002013 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002014 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002015 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002016 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002017 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002018 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002019 return -1;
2020
2021 for (i = 0; i < 6; ++i)
2022 /* truncate away IVE sign-extension */
2023 tcp->u_arg[i] &= 0xffffffff;
2024
2025 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2026 && sysent[tcp->scno].nargs != -1)
2027 tcp->u_nargs = sysent[tcp->scno].nargs;
2028 else
2029 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002030 }
2031 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002032#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2033 /* N32 and N64 both use up to six registers. */
2034 {
2035 unsigned long long regs[38];
2036 int i, nargs;
2037
2038 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2039 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002040 else
Roland McGrath542c2c62008-05-20 01:11:56 +00002041 nargs = tcp->u_nargs = MAX_ARGS;
2042
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002043 if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002044 return -1;
2045
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002046 for (i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002047 tcp->u_arg[i] = regs[REG_A0 + i];
2048# if defined (LINUX_MIPSN32)
2049 tcp->ext_arg[i] = regs[REG_A0 + i];
2050# endif
2051 }
2052 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002053#elif defined (MIPS)
2054 {
2055 long sp;
2056 int i, nargs;
2057
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002058 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2059 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002060 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002061 nargs = tcp->u_nargs = MAX_ARGS;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002062 if (nargs > 4) {
2063 if (upeek(tcp, REG_SP, &sp) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002064 return -1;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002065 for (i = 0; i < 4; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002066 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002067 return -1;
2068 }
2069 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2070 (char *)(tcp->u_arg + 4));
2071 } else {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002072 for (i = 0; i < nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002073 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002074 return -1;
2075 }
2076 }
2077 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002078#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002079# ifndef PT_ORIG_R3
2080# define PT_ORIG_R3 34
2081# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002082 {
2083 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002084 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2085 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002086 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002087 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002088 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002089 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002090 (sizeof(unsigned long)*PT_ORIG_R3) :
2091 ((i+PT_R3)*sizeof(unsigned long)),
2092 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002093 return -1;
2094 }
2095 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002096#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002097 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002098 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002099
2100 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2101 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002102 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002103 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002104 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002105 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002106 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002107#elif defined (HPPA)
2108 {
2109 int i;
2110
2111 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2112 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002113 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002114 tcp->u_nargs = MAX_ARGS;
2115 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002116 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002117 return -1;
2118 }
2119 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002120#elif defined(ARM)
2121 {
2122 int i;
2123
2124 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2125 tcp->u_nargs = sysent[tcp->scno].nargs;
2126 else
2127 tcp->u_nargs = MAX_ARGS;
2128 for (i = 0; i < tcp->u_nargs; i++)
2129 tcp->u_arg[i] = regs.uregs[i];
2130 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002131#elif defined(BFIN)
2132 {
2133 int i;
2134 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2135
2136 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2137 tcp->u_nargs = sysent[tcp->scno].nargs;
2138 else
2139 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2140
2141 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002142 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002143 return -1;
2144 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002145#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002146 {
2147 int i;
2148 static int syscall_regs[] = {
2149 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2150 REG_REG0, REG_REG0+1, REG_REG0+2
2151 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002152
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002153 tcp->u_nargs = sysent[tcp->scno].nargs;
2154 for (i = 0; i < tcp->u_nargs; i++) {
2155 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2156 return -1;
2157 }
2158 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002159#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002160 {
2161 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002162 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002163 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2164
2165 /*
2166 * TODO: should also check that the number of arguments encoded
2167 * in the trap number matches the number strace expects.
2168 */
2169 /*
2170 assert(sysent[tcp->scno].nargs <
2171 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2172 */
2173
2174 tcp->u_nargs = sysent[tcp->scno].nargs;
2175 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002176 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002177 return -1;
2178 }
2179 }
2180
Michal Ludvig0e035502002-09-23 15:41:01 +00002181#elif defined(X86_64)
2182 {
2183 int i;
2184 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2185 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002186 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002187 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002188
Michal Ludvig0e035502002-09-23 15:41:01 +00002189 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2190 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002191 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002192 tcp->u_nargs = MAX_ARGS;
2193 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002194 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002195 return -1;
2196 }
2197 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002198#elif defined(CRISV10) || defined(CRISV32)
2199 {
2200 int i;
2201 static const int crisregs[] = {
2202 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2203 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2204 };
2205
2206 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2207 tcp->u_nargs = sysent[tcp->scno].nargs;
2208 else
2209 tcp->u_nargs = 0;
2210 for (i = 0; i < tcp->u_nargs; i++) {
2211 if (upeek(tcp->pid, crisregs[i], &tcp->u_arg[i]) < 0)
2212 return -1;
2213 }
2214 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002215#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002216 {
2217 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002218 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2219 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002220 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002221 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002222 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002223 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002224 return -1;
2225 }
2226 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002227#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002228#endif /* LINUX */
2229#ifdef SUNOS4
2230 {
2231 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002232 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2233 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002234 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002235 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002236 for (i = 0; i < tcp->u_nargs; i++) {
2237 struct user *u;
2238
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002239 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002240 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2241 return -1;
2242 }
2243 }
2244#endif /* SUNOS4 */
2245#ifdef SVR4
2246#ifdef MIPS
2247 /*
2248 * SGI is broken: even though it has pr_sysarg, it doesn't
2249 * set them on system call entry. Get a clue.
2250 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002251 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002252 tcp->u_nargs = sysent[tcp->scno].nargs;
2253 else
2254 tcp->u_nargs = tcp->status.pr_nsysarg;
2255 if (tcp->u_nargs > 4) {
2256 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2257 4*sizeof(tcp->u_arg[0]));
2258 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2259 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2260 }
2261 else {
2262 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2263 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2264 }
John Hughes25299712001-03-06 10:10:06 +00002265#elif UNIXWARE >= 2
2266 /*
2267 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2268 */
2269 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2270 tcp->u_nargs = sysent[tcp->scno].nargs;
2271 else
2272 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2273 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2274 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2275#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002276 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002277 tcp->u_nargs = sysent[tcp->scno].nargs;
2278 else
2279 tcp->u_nargs = tcp->status.pr_nsysarg;
2280 {
2281 int i;
2282 for (i = 0; i < tcp->u_nargs; i++)
2283 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2284 }
John Hughes25299712001-03-06 10:10:06 +00002285#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002286 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002287 tcp->u_nargs = sysent[tcp->scno].nargs;
2288 else
2289 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002290 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002291 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002292#else
2293 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002295#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002296#ifdef FREEBSD
2297 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2298 sysent[tcp->scno].nargs > tcp->status.val)
2299 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002300 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002301 tcp->u_nargs = tcp->status.val;
2302 if (tcp->u_nargs < 0)
2303 tcp->u_nargs = 0;
2304 if (tcp->u_nargs > MAX_ARGS)
2305 tcp->u_nargs = MAX_ARGS;
2306 switch(regs.r_eax) {
2307 case SYS___syscall:
2308 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2309 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002310 break;
2311 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002312 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2313 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002314 break;
2315 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002316 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2317 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002318 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002319 }
2320#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002321 return 1;
2322}
2323
2324int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002325trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002326{
2327 int sys_res;
2328 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002329 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002330
2331 if (tcp->flags & TCB_INSYSCALL) {
2332 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002333
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002334 /* Measure the exit time as early as possible to avoid errors. */
2335 if (dtime)
2336 gettimeofday(&tv, NULL);
2337
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002338 /* In code below,
2339 * res = 1: no error, continue
2340 * res = 0: return 0 at once (not an error)
2341 * any other value: error, complain and return the value
2342 *
2343 * BTW, why we don't just memorize syscall no. on entry
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002344 * in tcp->something?
2345 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002346 scno_good = res = get_scno(tcp);
2347 if (res == 0)
2348 return res;
2349 if (res == 1)
2350 res = syscall_fixup(tcp);
2351 if (res == 0)
2352 return res;
2353 if (res == 1)
2354 res = get_error(tcp);
2355 if (res == 0)
2356 return res;
2357 if (res == 1)
2358 internal_syscall(tcp);
2359
2360 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002361 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002362 tcp->flags &= ~TCB_INSYSCALL;
2363 return 0;
2364 }
2365
2366 if (tcp->flags & TCB_REPRINT) {
2367 printleader(tcp);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002368 if (scno_good != 1) {
2369 tprintf("<... syscall_?? resumed> ");
2370 } else {
2371 if (tcp->scno >= nsyscalls || tcp->scno < 0)
2372 tprintf("<... syscall_%lu resumed> ", tcp->scno);
2373 else
2374 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
2375 }
2376 /* [do we need to clear TCB_REPRINT?...] */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002377 }
2378
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002379 if (cflag)
2380 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002381
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002382 if (res != 1) {
2383 tprintf(") ");
2384 tabto(acolumn);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002385 tprintf("= ?");
2386 /* line will be finished by error handling code */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002387 tcp->flags &= ~TCB_INSYSCALL;
2388 return res;
2389 }
2390
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002391 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002392 || (qual_flags[tcp->scno] & QUAL_RAW))
2393 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002394 else {
2395 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002396 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002397 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002398 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002399 u_error = tcp->u_error;
2400 tprintf(") ");
2401 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002402 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2403 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002404 if (u_error)
2405 tprintf("= -1 (errno %ld)", u_error);
2406 else
2407 tprintf("= %#lx", tcp->u_rval);
2408 }
2409 else if (!(sys_res & RVAL_NONE) && u_error) {
2410 switch (u_error) {
2411#ifdef LINUX
2412 case ERESTARTSYS:
2413 tprintf("= ? ERESTARTSYS (To be restarted)");
2414 break;
2415 case ERESTARTNOINTR:
2416 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2417 break;
2418 case ERESTARTNOHAND:
2419 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2420 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002421 case ERESTART_RESTARTBLOCK:
2422 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2423 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002424#endif /* LINUX */
2425 default:
2426 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002427 if (u_error < 0)
2428 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002429 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002430 tprintf("%s (%s)", errnoent[u_error],
2431 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002432 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002433 tprintf("ERRNO_%ld (%s)", u_error,
2434 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002435 break;
2436 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002437 if ((sys_res & RVAL_STR) && tcp->auxstr)
2438 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002439 }
2440 else {
2441 if (sys_res & RVAL_NONE)
2442 tprintf("= ?");
2443 else {
2444 switch (sys_res & RVAL_MASK) {
2445 case RVAL_HEX:
2446 tprintf("= %#lx", tcp->u_rval);
2447 break;
2448 case RVAL_OCTAL:
2449 tprintf("= %#lo", tcp->u_rval);
2450 break;
2451 case RVAL_UDECIMAL:
2452 tprintf("= %lu", tcp->u_rval);
2453 break;
2454 case RVAL_DECIMAL:
2455 tprintf("= %ld", tcp->u_rval);
2456 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002457#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002458 case RVAL_LHEX:
2459 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002460 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002461 case RVAL_LOCTAL:
2462 tprintf("= %#llo", tcp->u_lrval);
2463 break;
2464 case RVAL_LUDECIMAL:
2465 tprintf("= %llu", tcp->u_lrval);
2466 break;
2467 case RVAL_LDECIMAL:
2468 tprintf("= %lld", tcp->u_lrval);
2469 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002470#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002471 default:
2472 fprintf(stderr,
2473 "invalid rval format\n");
2474 break;
2475 }
2476 }
2477 if ((sys_res & RVAL_STR) && tcp->auxstr)
2478 tprintf(" (%s)", tcp->auxstr);
2479 }
2480 if (dtime) {
2481 tv_sub(&tv, &tv, &tcp->etime);
2482 tprintf(" <%ld.%06ld>",
2483 (long) tv.tv_sec, (long) tv.tv_usec);
2484 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002485 printtrailer();
Pavel Machek4dc3b142000-02-01 17:58:41 +00002486
2487 dumpio(tcp);
2488 if (fflush(tcp->outf) == EOF)
2489 return -1;
2490 tcp->flags &= ~TCB_INSYSCALL;
2491 return 0;
2492 }
2493
2494 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002495 scno_good = res = get_scno(tcp);
2496 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002497 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002498 if (res == 1)
2499 res = syscall_fixup(tcp);
2500 if (res == 0)
2501 return res;
2502 if (res == 1)
2503 res = syscall_enter(tcp);
2504 if (res == 0)
2505 return res;
2506
2507 if (res != 1) {
2508 printleader(tcp);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002509 tcp->flags &= ~TCB_REPRINT; /* why? */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002510 tcp_last = tcp;
2511 if (scno_good != 1)
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002512 tprintf("syscall_??" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002513 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2514 tprintf("syscall_%lu(", tcp->scno);
2515 else
2516 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002517 /* Line will be finished by error handling code. */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002518 tcp->flags |= TCB_INSYSCALL;
2519 return res;
2520 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002521
Roland McGrath17352792005-06-07 23:21:26 +00002522 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002523#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002524 case SYS_socketcall:
2525 decode_subcall(tcp, SYS_socket_subcall,
2526 SYS_socket_nsubcalls, deref_style);
2527 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002528#endif
2529#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002530 case SYS_ipc:
2531 decode_subcall(tcp, SYS_ipc_subcall,
2532 SYS_ipc_nsubcalls, shift_style);
2533 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002534#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002535#ifdef SVR4
2536#ifdef SYS_pgrpsys_subcall
2537 case SYS_pgrpsys:
2538 decode_subcall(tcp, SYS_pgrpsys_subcall,
2539 SYS_pgrpsys_nsubcalls, shift_style);
2540 break;
2541#endif /* SYS_pgrpsys_subcall */
2542#ifdef SYS_sigcall_subcall
2543 case SYS_sigcall:
2544 decode_subcall(tcp, SYS_sigcall_subcall,
2545 SYS_sigcall_nsubcalls, mask_style);
2546 break;
2547#endif /* SYS_sigcall_subcall */
2548 case SYS_msgsys:
2549 decode_subcall(tcp, SYS_msgsys_subcall,
2550 SYS_msgsys_nsubcalls, shift_style);
2551 break;
2552 case SYS_shmsys:
2553 decode_subcall(tcp, SYS_shmsys_subcall,
2554 SYS_shmsys_nsubcalls, shift_style);
2555 break;
2556 case SYS_semsys:
2557 decode_subcall(tcp, SYS_semsys_subcall,
2558 SYS_semsys_nsubcalls, shift_style);
2559 break;
2560#if 0 /* broken */
2561 case SYS_utssys:
2562 decode_subcall(tcp, SYS_utssys_subcall,
2563 SYS_utssys_nsubcalls, shift_style);
2564 break;
2565#endif
2566 case SYS_sysfs:
2567 decode_subcall(tcp, SYS_sysfs_subcall,
2568 SYS_sysfs_nsubcalls, shift_style);
2569 break;
2570 case SYS_spcall:
2571 decode_subcall(tcp, SYS_spcall_subcall,
2572 SYS_spcall_nsubcalls, shift_style);
2573 break;
2574#ifdef SYS_context_subcall
2575 case SYS_context:
2576 decode_subcall(tcp, SYS_context_subcall,
2577 SYS_context_nsubcalls, shift_style);
2578 break;
2579#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002580#ifdef SYS_door_subcall
2581 case SYS_door:
2582 decode_subcall(tcp, SYS_door_subcall,
2583 SYS_door_nsubcalls, door_style);
2584 break;
2585#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002586#ifdef SYS_kaio_subcall
2587 case SYS_kaio:
2588 decode_subcall(tcp, SYS_kaio_subcall,
2589 SYS_kaio_nsubcalls, shift_style);
2590 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002591#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002592#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002593#ifdef FREEBSD
2594 case SYS_msgsys:
2595 case SYS_shmsys:
2596 case SYS_semsys:
2597 decode_subcall(tcp, 0, 0, table_style);
2598 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002599#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002600#ifdef SUNOS4
2601 case SYS_semsys:
2602 decode_subcall(tcp, SYS_semsys_subcall,
2603 SYS_semsys_nsubcalls, shift_style);
2604 break;
2605 case SYS_msgsys:
2606 decode_subcall(tcp, SYS_msgsys_subcall,
2607 SYS_msgsys_nsubcalls, shift_style);
2608 break;
2609 case SYS_shmsys:
2610 decode_subcall(tcp, SYS_shmsys_subcall,
2611 SYS_shmsys_nsubcalls, shift_style);
2612 break;
2613#endif
2614 }
2615
2616 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002617 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002618 tcp->flags |= TCB_INSYSCALL;
2619 return 0;
2620 }
2621
2622 if (cflag) {
2623 gettimeofday(&tcp->etime, NULL);
2624 tcp->flags |= TCB_INSYSCALL;
2625 return 0;
2626 }
2627
2628 printleader(tcp);
2629 tcp->flags &= ~TCB_REPRINT;
2630 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002631 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002632 tprintf("syscall_%lu(", tcp->scno);
2633 else
2634 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002635 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002636 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2637 sys_res = printargs(tcp);
2638 else
2639 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2640 if (fflush(tcp->outf) == EOF)
2641 return -1;
2642 tcp->flags |= TCB_INSYSCALL;
2643 /* Measure the entrance time as late as possible to avoid errors. */
2644 if (dtime)
2645 gettimeofday(&tcp->etime, NULL);
2646 return sys_res;
2647}
2648
2649int
2650printargs(tcp)
2651struct tcb *tcp;
2652{
2653 if (entering(tcp)) {
2654 int i;
2655
2656 for (i = 0; i < tcp->u_nargs; i++)
2657 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2658 }
2659 return 0;
2660}
2661
2662long
2663getrval2(tcp)
2664struct tcb *tcp;
2665{
2666 long val = -1;
2667
2668#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002669#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002670 struct regs regs;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002671 if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002672 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002673 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002674#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002675 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002676 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002677#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002678 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002679 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002680#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002681#endif /* LINUX */
2682
2683#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002684 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002685 return -1;
2686#endif /* SUNOS4 */
2687
2688#ifdef SVR4
2689#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002690 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002691#endif /* SPARC */
2692#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002693 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002695#ifdef X86_64
2696 val = tcp->status.PR_REG[RDX];
2697#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002698#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002699 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002700#endif /* MIPS */
2701#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002702
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002703#ifdef FREEBSD
2704 struct reg regs;
2705 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2706 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002707#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002708 return val;
2709}
2710
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002711#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002712/*
2713 * Apparently, indirect system calls have already be converted by ptrace(2),
2714 * so if you see "indir" this program has gone astray.
2715 */
2716int
2717sys_indir(tcp)
2718struct tcb *tcp;
2719{
2720 int i, scno, nargs;
2721
2722 if (entering(tcp)) {
2723 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2724 fprintf(stderr, "Bogus syscall: %u\n", scno);
2725 return 0;
2726 }
2727 nargs = sysent[scno].nargs;
2728 tprintf("%s", sysent[scno].sys_name);
2729 for (i = 0; i < nargs; i++)
2730 tprintf(", %#lx", tcp->u_arg[i+1]);
2731 }
2732 return 0;
2733}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002734#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002735
2736int
2737is_restart_error(struct tcb *tcp)
2738{
2739#ifdef LINUX
2740 if (!syserror(tcp))
2741 return 0;
2742 switch (tcp->u_error) {
2743 case ERESTARTSYS:
2744 case ERESTARTNOINTR:
2745 case ERESTARTNOHAND:
2746 case ERESTART_RESTARTBLOCK:
2747 return 1;
2748 default:
2749 break;
2750 }
2751#endif /* LINUX */
2752 return 0;
2753}