blob: 5203ef7c30bbcfb5a2e32840cf6d158b4928d15e [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
38#include <signal.h>
39#include <time.h>
40#include <errno.h>
41#include <sys/user.h>
42#include <sys/syscall.h>
43#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044
Wichert Akkerman15dea971999-10-06 13:06:34 +000045#ifdef HAVE_SYS_REG_H
Roland McGratheb9e2e82009-06-02 16:49:22 -070046#include <sys/reg.h>
47#ifndef PTRACE_PEEKUSR
48# define PTRACE_PEEKUSR PTRACE_PEEKUSER
49#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000050#elif defined(HAVE_LINUX_PTRACE_H)
Roland McGratheb9e2e82009-06-02 16:49:22 -070051#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000052# ifdef HAVE_STRUCT_IA64_FPREG
53# define ia64_fpreg XXX_ia64_fpreg
54# endif
55# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
56# define pt_all_user_regs XXX_pt_all_user_regs
57# endif
Roland McGratheb9e2e82009-06-02 16:49:22 -070058#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000059# undef ia64_fpreg
60# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000061#endif
62
Roland McGrath6d1a65c2004-07-12 07:44:08 +000063#if defined (LINUX) && defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000064# undef PTRACE_GETREGS
65# define PTRACE_GETREGS PTRACE_GETREGS64
66# undef PTRACE_SETREGS
67# define PTRACE_SETREGS PTRACE_SETREGS64
68#endif /* LINUX && SPARC64 */
69
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000070#if defined(LINUX) && defined(IA64)
71# include <asm/ptrace_offsets.h>
72# include <asm/rse.h>
73#endif
74
Pavel Machekd8ae7e32000-02-01 17:17:25 +000075#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000076#ifdef LINUX
77#ifndef ERESTARTSYS
78#define ERESTARTSYS 512
79#endif
80#ifndef ERESTARTNOINTR
81#define ERESTARTNOINTR 513
82#endif
83#ifndef ERESTARTNOHAND
84#define ERESTARTNOHAND 514 /* restart if no handler.. */
85#endif
86#ifndef ENOIOCTLCMD
87#define ENOIOCTLCMD 515 /* No ioctl command */
88#endif
Roland McGrath9c555e72003-07-09 09:47:59 +000089#ifndef ERESTART_RESTARTBLOCK
90#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
91#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092#ifndef NSIG
93#define NSIG 32
94#endif
95#ifdef ARM
96#undef NSIG
97#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +000098#undef NR_SYSCALL_BASE
99#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000100#endif
101#endif /* LINUX */
102
103#include "syscall.h"
104
105/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000106#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#define TF TRACE_FILE
108#define TI TRACE_IPC
109#define TN TRACE_NETWORK
110#define TP TRACE_PROCESS
111#define TS TRACE_SIGNAL
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000112#define NF SYSCALL_NEVER_FAILS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000113
Roland McGrathee36ce12004-09-04 03:53:10 +0000114static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#include "syscallent.h"
116};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000117static const int nsyscalls0 = ARRAY_SIZE(sysent0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000118int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000119
120#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000121static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#include "syscallent1.h"
123};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000124static const int nsyscalls1 = ARRAY_SIZE(sysent1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000125int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126#endif /* SUPPORTED_PERSONALITIES >= 2 */
127
128#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000129static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000130#include "syscallent2.h"
131};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000132static const int nsyscalls2 = ARRAY_SIZE(sysent2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000133int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134#endif /* SUPPORTED_PERSONALITIES >= 3 */
135
Roland McGrathee36ce12004-09-04 03:53:10 +0000136const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000137int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000138int nsyscalls;
139
140/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000141#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142#undef TF
143#undef TI
144#undef TN
145#undef TP
146#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000147#undef NF
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148
Roland McGrathee36ce12004-09-04 03:53:10 +0000149static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000150#include "errnoent.h"
151};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000152static const int nerrnos0 = ARRAY_SIZE(errnoent0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000153
154#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000155static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156#include "errnoent1.h"
157};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000158static const int nerrnos1 = ARRAY_SIZE(errnoent1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000159#endif /* SUPPORTED_PERSONALITIES >= 2 */
160
161#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000162static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163#include "errnoent2.h"
164};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000165static const int nerrnos2 = ARRAY_SIZE(errnoent2);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166#endif /* SUPPORTED_PERSONALITIES >= 3 */
167
Roland McGrathee36ce12004-09-04 03:53:10 +0000168const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169int nerrnos;
170
171int current_personality;
172
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000173#ifndef PERSONALITY0_WORDSIZE
174# define PERSONALITY0_WORDSIZE sizeof(long)
175#endif
176const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
177 PERSONALITY0_WORDSIZE,
178#if SUPPORTED_PERSONALITIES > 1
179 PERSONALITY1_WORDSIZE,
180#endif
181#if SUPPORTED_PERSONALITIES > 2
182 PERSONALITY2_WORDSIZE,
183#endif
184};;
185
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000186int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000187set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000188{
189 switch (personality) {
190 case 0:
191 errnoent = errnoent0;
192 nerrnos = nerrnos0;
193 sysent = sysent0;
194 nsyscalls = nsyscalls0;
195 ioctlent = ioctlent0;
196 nioctlents = nioctlents0;
197 signalent = signalent0;
198 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000199 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000200 break;
201
202#if SUPPORTED_PERSONALITIES >= 2
203 case 1:
204 errnoent = errnoent1;
205 nerrnos = nerrnos1;
206 sysent = sysent1;
207 nsyscalls = nsyscalls1;
208 ioctlent = ioctlent1;
209 nioctlents = nioctlents1;
210 signalent = signalent1;
211 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000212 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000213 break;
214#endif /* SUPPORTED_PERSONALITIES >= 2 */
215
216#if SUPPORTED_PERSONALITIES >= 3
217 case 2:
218 errnoent = errnoent2;
219 nerrnos = nerrnos2;
220 sysent = sysent2;
221 nsyscalls = nsyscalls2;
222 ioctlent = ioctlent2;
223 nioctlents = nioctlents2;
224 signalent = signalent2;
225 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000226 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000227 break;
228#endif /* SUPPORTED_PERSONALITIES >= 3 */
229
230 default:
231 return -1;
232 }
233
234 current_personality = personality;
235 return 0;
236}
237
Roland McGrathe10e62a2004-09-04 04:20:43 +0000238
Roland McGrath9797ceb2002-12-30 10:23:00 +0000239static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240
Roland McGrathe10e62a2004-09-04 04:20:43 +0000241static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000242 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000243 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000244 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000245 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000246} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000247 { QUAL_TRACE, "trace", qual_syscall, "system call" },
248 { QUAL_TRACE, "t", qual_syscall, "system call" },
249 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
250 { QUAL_ABBREV, "a", qual_syscall, "system call" },
251 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
252 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
253 { QUAL_RAW, "raw", qual_syscall, "system call" },
254 { QUAL_RAW, "x", qual_syscall, "system call" },
255 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
256 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
257 { QUAL_SIGNAL, "s", qual_signal, "signal" },
258 { QUAL_FAULT, "fault", qual_fault, "fault" },
259 { QUAL_FAULT, "faults", qual_fault, "fault" },
260 { QUAL_FAULT, "m", qual_fault, "fault" },
261 { QUAL_READ, "read", qual_desc, "descriptor" },
262 { QUAL_READ, "reads", qual_desc, "descriptor" },
263 { QUAL_READ, "r", qual_desc, "descriptor" },
264 { QUAL_WRITE, "write", qual_desc, "descriptor" },
265 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
266 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000267 { 0, NULL, NULL, NULL },
268};
269
Roland McGrath9797ceb2002-12-30 10:23:00 +0000270static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000271qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000272{
Roland McGrath138c6a32006-01-12 09:50:49 +0000273 if (pers == 0 || pers < 0) {
274 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000275 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000276 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000277 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000278 }
279
280#if SUPPORTED_PERSONALITIES >= 2
281 if (pers == 1 || pers < 0) {
282 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000283 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000284 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000285 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000286 }
287#endif /* SUPPORTED_PERSONALITIES >= 2 */
288
289#if SUPPORTED_PERSONALITIES >= 3
290 if (pers == 2 || pers < 0) {
291 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000292 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000293 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000294 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000295 }
296#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000297}
298
299static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000300qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000301{
302 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000303 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000304
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000305 if (isdigit((unsigned char)*s)) {
306 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000307 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000308 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000309 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000310 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000311 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000312 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000313 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000314 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000315 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000316 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000317
318#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000319 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000320 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000321 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000322 rc = 0;
323 }
324#endif /* SUPPORTED_PERSONALITIES >= 2 */
325
326#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000327 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000328 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000329 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000330 rc = 0;
331 }
332#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000333
Roland McGrathfe6b3522005-02-02 04:40:11 +0000334 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000335}
336
337static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000338qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000339{
340 int i;
341 char buf[32];
342
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000343 if (isdigit((unsigned char)*s)) {
344 int signo = atoi(s);
345 if (signo < 0 || signo >= MAX_QUALS)
346 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000347 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000348 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000349 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000350 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000351 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000352 strcpy(buf, s);
353 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000354 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000355 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000356 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000357 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000358 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000359 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000360 }
Roland McGrath76421df2005-02-02 03:51:18 +0000361 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000362}
363
364static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000365qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000366{
367 return -1;
368}
369
370static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000371qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372{
Roland McGrath48a035f2006-01-12 09:45:56 +0000373 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000374 int desc = atoi(s);
375 if (desc < 0 || desc >= MAX_QUALS)
376 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000377 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000378 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379 }
380 return -1;
381}
382
383static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000384lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000385{
386 if (strcmp(s, "file") == 0)
387 return TRACE_FILE;
388 if (strcmp(s, "ipc") == 0)
389 return TRACE_IPC;
390 if (strcmp(s, "network") == 0)
391 return TRACE_NETWORK;
392 if (strcmp(s, "process") == 0)
393 return TRACE_PROCESS;
394 if (strcmp(s, "signal") == 0)
395 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000396 if (strcmp(s, "desc") == 0)
397 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000398 return -1;
399}
400
401void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000402qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000403{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000404 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000405 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000406 char *copy;
407 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000408 int i, n;
409
410 opt = &qual_options[0];
411 for (i = 0; (p = qual_options[i].option_name); i++) {
412 n = strlen(p);
413 if (strncmp(s, p, n) == 0 && s[n] == '=') {
414 opt = &qual_options[i];
415 s += n + 1;
416 break;
417 }
418 }
419 not = 0;
420 if (*s == '!') {
421 not = 1;
422 s++;
423 }
424 if (strcmp(s, "none") == 0) {
425 not = 1 - not;
426 s = "all";
427 }
428 if (strcmp(s, "all") == 0) {
429 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000430 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000431 }
432 return;
433 }
434 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000435 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000436 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000437 if (!(copy = strdup(s))) {
438 fprintf(stderr, "out of memory\n");
439 exit(1);
440 }
441 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000442 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000443 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000444 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000445 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000446
447#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000448 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000449 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000450 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000451#endif /* SUPPORTED_PERSONALITIES >= 2 */
452
453#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000454 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000455 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000456 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000457#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000458
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000459 continue;
460 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000461 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000462 fprintf(stderr, "strace: invalid %s `%s'\n",
463 opt->argument_name, p);
464 exit(1);
465 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000466 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000467 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000468 return;
469}
470
471static void
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000472dumpio(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000473{
474 if (syserror(tcp))
475 return;
476 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
477 return;
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000478 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
479 return;
480 if (sysent[tcp->scno].sys_func == printargs)
481 return;
482 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
483 if (sysent[tcp->scno].sys_func == sys_read ||
484 sysent[tcp->scno].sys_func == sys_pread ||
485 sysent[tcp->scno].sys_func == sys_pread64 ||
486 sysent[tcp->scno].sys_func == sys_recv ||
487 sysent[tcp->scno].sys_func == sys_recvfrom)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000488 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000489 else if (sysent[tcp->scno].sys_func == sys_readv)
490 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
491 return;
492 }
493 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
494 if (sysent[tcp->scno].sys_func == sys_write ||
495 sysent[tcp->scno].sys_func == sys_pwrite ||
496 sysent[tcp->scno].sys_func == sys_pwrite64 ||
497 sysent[tcp->scno].sys_func == sys_send ||
498 sysent[tcp->scno].sys_func == sys_sendto)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000499 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000500 else if (sysent[tcp->scno].sys_func == sys_writev)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000501 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000502 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503 }
504}
505
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000506#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000507enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000508#else /* FREEBSD */
509enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
510
511struct subcall {
512 int call;
513 int nsubcalls;
514 int subcalls[5];
515};
516
Roland McGratha4d48532005-06-08 20:45:28 +0000517static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000518 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000519#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000520 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000521#else
522 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
523#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000524 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
525};
526#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000528#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000529
Roland McGratha4d48532005-06-08 20:45:28 +0000530static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200531decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000532{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000533 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000534 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000535 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000536
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000537 switch (style) {
538 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000539 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
540 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000541 tcp->scno = subcall + tcp->u_arg[0];
542 if (sysent[tcp->scno].nargs != -1)
543 tcp->u_nargs = sysent[tcp->scno].nargs;
544 else
545 tcp->u_nargs--;
546 for (i = 0; i < tcp->u_nargs; i++)
547 tcp->u_arg[i] = tcp->u_arg[i + 1];
548 break;
549 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000550 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
551 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000552 tcp->scno = subcall + tcp->u_arg[0];
553 addr = tcp->u_arg[1];
554 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000555 if (size == sizeof(int)) {
556 unsigned int arg;
557 if (umove(tcp, addr, &arg) < 0)
558 arg = 0;
559 tcp->u_arg[i] = arg;
560 }
561 else if (size == sizeof(long)) {
562 unsigned long arg;
563 if (umove(tcp, addr, &arg) < 0)
564 arg = 0;
565 tcp->u_arg[i] = arg;
566 }
567 else
568 abort();
569 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570 }
571 tcp->u_nargs = sysent[tcp->scno].nargs;
572 break;
573 case mask_style:
574 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000575 for (i = 0; mask; i++)
576 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000577 if (i >= nsubcalls)
578 return;
579 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000580 tcp->scno = subcall + i;
581 if (sysent[tcp->scno].nargs != -1)
582 tcp->u_nargs = sysent[tcp->scno].nargs;
583 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000584 case door_style:
585 /*
586 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000587 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000588 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000589 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
590 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000591 tcp->scno = subcall + tcp->u_arg[5];
592 if (sysent[tcp->scno].nargs != -1)
593 tcp->u_nargs = sysent[tcp->scno].nargs;
594 else
595 tcp->u_nargs--;
596 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000597#ifdef FREEBSD
598 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000599 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000600 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000601 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000602 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
603 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
604 for (i = 0; i < tcp->u_nargs; i++)
605 tcp->u_arg[i] = tcp->u_arg[i + 1];
606 }
607 break;
608#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000609 }
610}
611#endif
612
613struct tcb *tcp_last = NULL;
614
615static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000616internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617{
618 /*
619 * We must always trace a few critical system calls in order to
620 * correctly support following forks in the presence of tracing
621 * qualifiers.
622 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000623 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000624
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000625 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
626 return 0;
627
628 func = sysent[tcp->scno].sys_func;
629
630 if (sys_exit == func)
631 return internal_exit(tcp);
632
633 if ( sys_fork == func
634#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
635 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000636#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000637#ifdef LINUX
638 || sys_clone == func
639#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000640#if UNIXWARE > 2
641 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000642#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000643 )
644 return internal_fork(tcp);
645
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000646 if ( sys_execve == func
647#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
648 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000650#if UNIXWARE > 2
651 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000652#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000653 )
654 return internal_exec(tcp);
655
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000656 return 0;
657}
658
Wichert Akkermanc7926982000-04-10 22:22:31 +0000659
660#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200661# if defined (I386)
662static long eax;
663# elif defined (IA64)
664long r8, r10, psr; /* TODO: make static? */
665long ia32 = 0; /* not static */
666# elif defined (POWERPC)
667static long result, flags;
668# elif defined (M68K)
669static long d0;
670# elif defined(BFIN)
671static long r0;
672# elif defined (ARM)
673static struct pt_regs regs;
674# elif defined (ALPHA)
675static long r0;
676static long a3;
677# elif defined(AVR32)
678static struct pt_regs regs;
679# elif defined (SPARC) || defined (SPARC64)
680static struct pt_regs regs;
681static unsigned long trap;
682# elif defined(LINUX_MIPSN32)
683static long long a3;
684static long long r2;
685# elif defined(MIPS)
686static long a3;
687static long r2;
688# elif defined(S390) || defined(S390X)
689static long gpr2;
690static long pc;
691static long syscall_mode;
692# elif defined(HPPA)
693static long r28;
694# elif defined(SH)
695static long r0;
696# elif defined(SH64)
697static long r9;
698# elif defined(X86_64)
699static long rax;
700# elif defined(CRISV10) || defined(CRISV32)
701static long r10;
702# elif defined(MICROBLAZE)
703static long r3;
704# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000705#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000706#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200707struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000708#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000709
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000710int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000711get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000713 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000714
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000715#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000716# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000717 if (tcp->flags & TCB_WAITEXECVE) {
718 /*
719 * When the execve system call completes successfully, the
720 * new process still has -ENOSYS (old style) or __NR_execve
721 * (new style) in gpr2. We cannot recover the scno again
722 * by disassembly, because the image that executed the
723 * syscall is gone now. Fortunately, we don't want it. We
724 * leave the flag set so that syscall_fixup can fake the
725 * result.
726 */
727 if (tcp->flags & TCB_INSYSCALL)
728 return 1;
729 /*
730 * This is the SIGTRAP after execve. We cannot try to read
731 * the system call here either.
732 */
733 tcp->flags &= ~TCB_WAITEXECVE;
734 return 0;
735 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000736
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000737 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200738 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000739
740 if (syscall_mode != -ENOSYS) {
741 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000742 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000743 */
744 scno = syscall_mode;
745 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000746 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000747 * Old style of "passing" the scno via the SVC instruction.
748 */
749
750 long opcode, offset_reg, tmp;
751 void * svc_addr;
752 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
753 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
754 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
755 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000756
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000757 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000758 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000759 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000760 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000761 if (errno) {
762 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000763 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000764 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000765
766 /*
767 * We have to check if the SVC got executed directly or via an
768 * EXECUTE instruction. In case of EXECUTE it is necessary to do
769 * instruction decoding to derive the system call number.
770 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
771 * so that this doesn't work if a SVC opcode is part of an EXECUTE
772 * opcode. Since there is no way to find out the opcode size this
773 * is the best we can do...
774 */
775
776 if ((opcode & 0xff00) == 0x0a00) {
777 /* SVC opcode */
778 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000779 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000780 else {
781 /* SVC got executed by EXECUTE instruction */
782
783 /*
784 * Do instruction decoding of EXECUTE. If you really want to
785 * understand this, read the Principles of Operations.
786 */
787 svc_addr = (void *) (opcode & 0xfff);
788
789 tmp = 0;
790 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000791 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000792 return -1;
793 svc_addr += tmp;
794
795 tmp = 0;
796 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000797 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000798 return -1;
799 svc_addr += tmp;
800
Denys Vlasenkofb036672009-01-23 16:30:26 +0000801 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000802 if (errno)
803 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000804# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000805 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000806# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000807 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000808# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000809 tmp = 0;
810 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000811 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000812 return -1;
813
814 scno = (scno | tmp) & 0xff;
815 }
816 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000817# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000818 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819 return -1;
820 if (!(tcp->flags & TCB_INSYSCALL)) {
821 /* Check if we return from execve. */
822 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
823 tcp->flags &= ~TCB_WAITEXECVE;
824 return 0;
825 }
826 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200827
828# ifdef POWERPC64
829 if (!(tcp->flags & TCB_INSYSCALL)) {
830 static int currpers = -1;
831 long val;
832 int pid = tcp->pid;
833
834 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200835 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200836 return -1;
837 /* SF is bit 0 of MSR */
838 if (val < 0)
839 currpers = 0;
840 else
841 currpers = 1;
842 if (currpers != current_personality) {
843 static const char *const names[] = {"64 bit", "32 bit"};
844 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000845 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200846 pid, names[current_personality]);
847 }
848 }
849# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000850# elif defined(AVR32)
851 /*
852 * Read complete register set in one go.
853 */
854 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
855 return -1;
856
857 /*
858 * We only need to grab the syscall number on syscall entry.
859 */
860 if (!(tcp->flags & TCB_INSYSCALL)) {
861 scno = regs.r8;
862
863 /* Check if we return from execve. */
864 if (tcp->flags & TCB_WAITEXECVE) {
865 tcp->flags &= ~TCB_WAITEXECVE;
866 return 0;
867 }
868 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000869# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000870 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000871 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000872# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000873 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000874 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000875# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000876 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000877 return -1;
878
Roland McGrath761b5d72002-12-15 23:58:31 +0000879 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000880 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000881 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000882 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000883
884 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200885 * 0x33 for long mode (64 bit)
886 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000887 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000888 * to be cached.
889 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000890 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000891 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000892 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000893 case 0x23: currpers = 1; break;
894 case 0x33: currpers = 0; break;
895 default:
896 fprintf(stderr, "Unknown value CS=0x%02X while "
897 "detecting personality of process "
898 "PID=%d\n", (int)val, pid);
899 currpers = current_personality;
900 break;
901 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000902# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000903 /* This version analyzes the opcode of a syscall instruction.
904 * (int 0x80 on i386 vs. syscall on x86-64)
905 * It works, but is too complicated.
906 */
907 unsigned long val, rip, i;
908
Denys Vlasenko8236f252009-01-02 18:10:08 +0000909 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000910 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000911
Michal Ludvig0e035502002-09-23 15:41:01 +0000912 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000913 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000914 errno = 0;
915
Denys Vlasenko8236f252009-01-02 18:10:08 +0000916 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000917 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000918 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000919 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000920 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000921 /* x86-64: syscall = 0x0f 0x05 */
922 case 0x050f: currpers = 0; break;
923 /* i386: int 0x80 = 0xcd 0x80 */
924 case 0x80cd: currpers = 1; break;
925 default:
926 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000927 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000928 "Unknown syscall opcode (0x%04X) while "
929 "detecting personality of process "
930 "PID=%d\n", (int)call, pid);
931 break;
932 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000933# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000934 if (currpers != current_personality) {
935 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000936 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000937 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000938 pid, names[current_personality]);
939 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000940 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000941# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000942# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200943 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000944 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000945 if (!(tcp->flags & TCB_INSYSCALL)) {
946 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000947 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000948 return -1;
949 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200950 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000951 return -1;
952 }
Roland McGrathba954762003-03-05 06:29:06 +0000953 /* Check if we return from execve. */
954 if (tcp->flags & TCB_WAITEXECVE) {
955 tcp->flags &= ~TCB_WAITEXECVE;
956 return 0;
957 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000958 } else {
959 /* syscall in progress */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200960 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000961 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200962 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000963 return -1;
964 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000965# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000966 /*
967 * Read complete register set in one go.
968 */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000969 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000970 return -1;
971
972 /*
973 * We only need to grab the syscall number on syscall entry.
974 */
975 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +0000976 if (!(tcp->flags & TCB_INSYSCALL)) {
977 /* Check if we return from execve. */
978 if (tcp->flags & TCB_WAITEXECVE) {
979 tcp->flags &= ~TCB_WAITEXECVE;
980 return 0;
981 }
982 }
983
Roland McGrath0f87c492003-06-03 23:29:04 +0000984 /*
985 * Note: we only deal with only 32-bit CPUs here.
986 */
987 if (regs.ARM_cpsr & 0x20) {
988 /*
989 * Get the Thumb-mode system call number
990 */
991 scno = regs.ARM_r7;
992 } else {
993 /*
994 * Get the ARM-mode system call number
995 */
996 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000997 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +0000998 if (errno)
999 return -1;
1000
1001 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1002 tcp->flags &= ~TCB_WAITEXECVE;
1003 return 0;
1004 }
1005
Roland McGrathf691bd22006-04-25 07:34:41 +00001006 /* Handle the EABI syscall convention. We do not
1007 bother converting structures between the two
1008 ABIs, but basic functionality should work even
1009 if strace and the traced program have different
1010 ABIs. */
1011 if (scno == 0xef000000) {
1012 scno = regs.ARM_r7;
1013 } else {
1014 if ((scno & 0x0ff00000) != 0x0f900000) {
1015 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1016 scno);
1017 return -1;
1018 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001019
Roland McGrathf691bd22006-04-25 07:34:41 +00001020 /*
1021 * Fixup the syscall number
1022 */
1023 scno &= 0x000fffff;
1024 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001025 }
Roland McGrath56703312008-05-20 01:35:55 +00001026 if (scno & 0x0f0000) {
1027 /*
1028 * Handle ARM specific syscall
1029 */
1030 set_personality(1);
1031 scno &= 0x0000ffff;
1032 } else
1033 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001034
1035 if (tcp->flags & TCB_INSYSCALL) {
1036 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1037 tcp->flags &= ~TCB_INSYSCALL;
1038 }
1039 } else {
1040 if (!(tcp->flags & TCB_INSYSCALL)) {
1041 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1042 tcp->flags |= TCB_INSYSCALL;
1043 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001045# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001046 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001048# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001049 unsigned long long regs[38];
1050
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001051 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001052 return -1;
1053 a3 = regs[REG_A3];
1054 r2 = regs[REG_V0];
1055
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001056 if (!(tcp->flags & TCB_INSYSCALL)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001057 scno = r2;
1058
1059 /* Check if we return from execve. */
1060 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1061 tcp->flags &= ~TCB_WAITEXECVE;
1062 return 0;
1063 }
1064
1065 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001066 if (a3 == 0 || a3 == -1) {
1067 if (debug)
1068 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001069 return 0;
1070 }
1071 }
1072 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001073# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001074 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001075 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001076 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001077 if (upeek(tcp, REG_V0, &scno) < 0)
1078 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001079
Roland McGrath542c2c62008-05-20 01:11:56 +00001080 /* Check if we return from execve. */
1081 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1082 tcp->flags &= ~TCB_WAITEXECVE;
1083 return 0;
1084 }
1085
Wichert Akkermanf90da011999-10-31 21:15:38 +00001086 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001087 if (a3 == 0 || a3 == -1) {
1088 if (debug)
1089 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001090 return 0;
1091 }
1092 }
1093 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001094 if (upeek(tcp, REG_V0, &r2) < 0)
1095 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001096 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001097# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001098 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001099 return -1;
1100
1101 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001102 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103 return -1;
1104
1105 /* Check if we return from execve. */
1106 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1107 tcp->flags &= ~TCB_WAITEXECVE;
1108 return 0;
1109 }
1110
1111 /*
1112 * Do some sanity checks to figure out if it's
1113 * really a syscall entry
1114 */
1115 if (scno < 0 || scno > nsyscalls) {
1116 if (a3 == 0 || a3 == -1) {
1117 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001118 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 return 0;
1120 }
1121 }
1122 }
1123 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001124 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 return -1;
1126 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001127# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001129 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001130 return -1;
1131
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001132 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001133 if (!(tcp->flags & TCB_INSYSCALL)) {
1134 /* Retrieve the syscall trap instruction. */
1135 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001136# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001137 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001138 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001139# else
1140 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001141# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001142 if (errno)
1143 return -1;
1144
1145 /* Disassemble the trap to see what personality to use. */
1146 switch (trap) {
1147 case 0x91d02010:
1148 /* Linux/SPARC syscall trap. */
1149 set_personality(0);
1150 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001151 case 0x91d0206d:
1152 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001153 set_personality(2);
1154 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155 case 0x91d02000:
1156 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001157 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001158 return -1;
1159 case 0x91d02008:
1160 /* Solaris 2.x syscall trap. (per 2) */
1161 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001162 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001163 case 0x91d02009:
1164 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001165 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 return -1;
1167 case 0x91d02027:
1168 /* Solaris 2.x gettimeofday */
1169 set_personality(1);
1170 break;
1171 default:
1172 /* Unknown syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001173 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174 tcp->flags &= ~TCB_WAITEXECVE;
1175 return 0;
1176 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001177# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001178 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001179# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001180 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001181# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182 return -1;
1183 }
1184
1185 /* Extract the system call number from the registers. */
1186 if (trap == 0x91d02027)
1187 scno = 156;
1188 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001189 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001191 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001192 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 }
1194 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001195# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001196 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001197 return -1;
1198 if (!(tcp->flags & TCB_INSYSCALL)) {
1199 /* Check if we return from execve. */
1200 if ((tcp->flags & TCB_WAITEXECVE)) {
1201 tcp->flags &= ~TCB_WAITEXECVE;
1202 return 0;
1203 }
1204 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001205# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001206 /*
1207 * In the new syscall ABI, the system call number is in R3.
1208 */
1209 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1210 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001211
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001212 if (scno < 0) {
1213 /* Odd as it may seem, a glibc bug has been known to cause
1214 glibc to issue bogus negative syscall numbers. So for
1215 our purposes, make strace print what it *should* have been */
1216 long correct_scno = (scno & 0xff);
1217 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001218 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001219 "Detected glibc bug: bogus system call"
1220 " number = %ld, correcting to %ld\n",
1221 scno,
1222 correct_scno);
1223 scno = correct_scno;
1224 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001225
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001226 if (!(tcp->flags & TCB_INSYSCALL)) {
1227 /* Check if we return from execve. */
1228 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1229 tcp->flags &= ~TCB_WAITEXECVE;
1230 return 0;
1231 }
1232 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001233# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001234 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001235 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001236 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001237
1238 if (!(tcp->flags & TCB_INSYSCALL)) {
1239 /* Check if we return from execve. */
1240 if (tcp->flags & TCB_WAITEXECVE) {
1241 tcp->flags &= ~TCB_WAITEXECVE;
1242 return 0;
1243 }
1244 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001245# elif defined(CRISV10) || defined(CRISV32)
1246 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1247 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001248# elif defined(TILE)
1249 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1250 return -1;
1251
1252 if (!(tcp->flags & TCB_INSYSCALL)) {
1253 /* Check if we return from execve. */
1254 if (tcp->flags & TCB_WAITEXECVE) {
1255 tcp->flags &= ~TCB_WAITEXECVE;
1256 return 0;
1257 }
1258 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001259# elif defined(MICROBLAZE)
1260 if (upeek(tcp, 0, &scno) < 0)
1261 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001262# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001263#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001264
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001265#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001266 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001267 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001268#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001269 /* new syscall ABI returns result in R0 */
1270 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1271 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001272#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001273 /* ABI defines result returned in r9 */
1274 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1275 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001276#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001277
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001278#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001279# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001280 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001281# else
1282# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001283 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001284# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001285 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001286 perror("pread");
1287 return -1;
1288 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001289 switch (regs.r_eax) {
1290 case SYS_syscall:
1291 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001292 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1293 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001294 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001295 scno = regs.r_eax;
1296 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001297 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001298# endif /* FREEBSD */
1299# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001300#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001301
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001302 if (!(tcp->flags & TCB_INSYSCALL))
1303 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001304 return 1;
1305}
1306
Pavel Machek4dc3b142000-02-01 17:58:41 +00001307
Roland McGrath17352792005-06-07 23:21:26 +00001308long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001309known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001310{
1311 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001312#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001313 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1314 scno = sysent[scno].native_scno;
1315 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001316#endif
Roland McGrath17352792005-06-07 23:21:26 +00001317 scno += NR_SYSCALL_BASE;
1318 return scno;
1319}
1320
Roland McGratheb9e2e82009-06-02 16:49:22 -07001321/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001322 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001323 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1324 * 1: ok, continue in trace_syscall().
1325 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001326 * ("????" etc) and bail out.
1327 */
Roland McGratha4d48532005-06-08 20:45:28 +00001328static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001329syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001330{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001331#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001332 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001333
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001334 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001335 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001336 if (
1337 scno == SYS_fork
1338#ifdef SYS_vfork
1339 || scno == SYS_vfork
1340#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001341#ifdef SYS_fork1
1342 || scno == SYS_fork1
1343#endif /* SYS_fork1 */
1344#ifdef SYS_forkall
1345 || scno == SYS_forkall
1346#endif /* SYS_forkall */
1347#ifdef SYS_rfork1
1348 || scno == SYS_rfork1
1349#endif /* SYS_fork1 */
1350#ifdef SYS_rforkall
1351 || scno == SYS_rforkall
1352#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001353 ) {
1354 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001355 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001356 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001357 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001358 }
1359 else {
1360 fprintf(stderr, "syscall: missing entry\n");
1361 tcp->flags |= TCB_INSYSCALL;
1362 }
1363 }
1364 }
1365 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001366 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367 fprintf(stderr, "syscall: missing exit\n");
1368 tcp->flags &= ~TCB_INSYSCALL;
1369 }
1370 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001371#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001372#ifdef SUNOS4
1373 if (!(tcp->flags & TCB_INSYSCALL)) {
1374 if (scno == 0) {
1375 fprintf(stderr, "syscall: missing entry\n");
1376 tcp->flags |= TCB_INSYSCALL;
1377 }
1378 }
1379 else {
1380 if (scno != 0) {
1381 if (debug) {
1382 /*
1383 * This happens when a signal handler
1384 * for a signal which interrupted a
1385 * a system call makes another system call.
1386 */
1387 fprintf(stderr, "syscall: missing exit\n");
1388 }
1389 tcp->flags &= ~TCB_INSYSCALL;
1390 }
1391 }
1392#endif /* SUNOS4 */
1393#ifdef LINUX
1394#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001395 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001396 return -1;
1397 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1398 if (debug)
1399 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1400 return 0;
1401 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001402#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001403 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001404 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001405 if (current_personality == 1)
1406 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001407 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1408 if (debug)
1409 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1410 return 0;
1411 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001412#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001413 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001414 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001415 if (syscall_mode != -ENOSYS)
1416 syscall_mode = tcp->scno;
1417 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001418 if (debug)
1419 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1420 return 0;
1421 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001422 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1423 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1424 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1425 /*
1426 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1427 * flag set for the post-execve SIGTRAP to see and reset.
1428 */
1429 gpr2 = 0;
1430 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001431#elif defined (POWERPC)
1432# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001433 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001434 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001435 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001436 return -1;
1437 if (flags & SO_MASK)
1438 result = -result;
1439#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001440 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001441 return -1;
1442 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1443 if (debug)
1444 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1445 return 0;
1446 }
1447#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001448 /*
1449 * Nothing required
1450 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001451#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001452 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001453 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001454#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001455 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001456 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001457#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001458 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001459 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001460 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001461 return -1;
1462 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1463 if (debug)
1464 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1465 return 0;
1466 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001467#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001468 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001469 return -1;
1470 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1471 if (debug)
1472 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1473 return 0;
1474 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001475#elif defined(MICROBLAZE)
1476 if (upeek(tcp, 3 * 4, &r3) < 0)
1477 return -1;
1478 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1479 if (debug)
1480 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1481 return 0;
1482 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483#endif
1484#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001485 return 1;
1486}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001487
Roland McGrathc1e45922008-05-27 23:18:29 +00001488#ifdef LINUX
1489/*
1490 * Check the syscall return value register value for whether it is
1491 * a negated errno code indicating an error, or a success return value.
1492 */
1493static inline int
1494is_negated_errno(unsigned long int val)
1495{
1496 unsigned long int max = -(long int) nerrnos;
1497 if (personality_wordsize[current_personality] < sizeof(val)) {
1498 val = (unsigned int) val;
1499 max = (unsigned int) max;
1500 }
1501 return val > max;
1502}
1503#endif
1504
Roland McGratha4d48532005-06-08 20:45:28 +00001505static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001506get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001507{
1508 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001509#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001510 int check_errno = 1;
1511 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1512 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1513 check_errno = 0;
1514 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001515# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001516 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001517 tcp->u_rval = -1;
1518 u_error = -gpr2;
1519 }
1520 else {
1521 tcp->u_rval = gpr2;
1522 u_error = 0;
1523 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001524# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001525 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001526 tcp->u_rval = -1;
1527 u_error = -eax;
1528 }
1529 else {
1530 tcp->u_rval = eax;
1531 u_error = 0;
1532 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001533# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001534 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001535 tcp->u_rval = -1;
1536 u_error = -rax;
1537 }
1538 else {
1539 tcp->u_rval = rax;
1540 u_error = 0;
1541 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001542# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001543 if (ia32) {
1544 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001545
Roland McGrathc1e45922008-05-27 23:18:29 +00001546 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001547 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001548 tcp->u_rval = -1;
1549 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001550 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001551 else {
1552 tcp->u_rval = err;
1553 u_error = 0;
1554 }
1555 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001556 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001557 tcp->u_rval = -1;
1558 u_error = r8;
1559 } else {
1560 tcp->u_rval = r8;
1561 u_error = 0;
1562 }
1563 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001564# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001565 if (check_errno && a3) {
1566 tcp->u_rval = -1;
1567 u_error = r2;
1568 } else {
1569 tcp->u_rval = r2;
1570 u_error = 0;
1571 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001572# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001573 if (check_errno && is_negated_errno(result)) {
1574 tcp->u_rval = -1;
1575 u_error = -result;
1576 }
1577 else {
1578 tcp->u_rval = result;
1579 u_error = 0;
1580 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001581# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001582 if (check_errno && is_negated_errno(d0)) {
1583 tcp->u_rval = -1;
1584 u_error = -d0;
1585 }
1586 else {
1587 tcp->u_rval = d0;
1588 u_error = 0;
1589 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001590# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001591 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1592 tcp->u_rval = -1;
1593 u_error = -regs.ARM_r0;
1594 }
1595 else {
1596 tcp->u_rval = regs.ARM_r0;
1597 u_error = 0;
1598 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001599# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001600 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1601 tcp->u_rval = -1;
1602 u_error = -regs.r12;
1603 }
1604 else {
1605 tcp->u_rval = regs.r12;
1606 u_error = 0;
1607 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001608# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001609 if (check_errno && is_negated_errno(r0)) {
1610 tcp->u_rval = -1;
1611 u_error = -r0;
1612 } else {
1613 tcp->u_rval = r0;
1614 u_error = 0;
1615 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001616# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001617 if (check_errno && a3) {
1618 tcp->u_rval = -1;
1619 u_error = r0;
1620 }
1621 else {
1622 tcp->u_rval = r0;
1623 u_error = 0;
1624 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001625# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001626 if (check_errno && regs.psr & PSR_C) {
1627 tcp->u_rval = -1;
1628 u_error = regs.u_regs[U_REG_O0];
1629 }
1630 else {
1631 tcp->u_rval = regs.u_regs[U_REG_O0];
1632 u_error = 0;
1633 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001634# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001635 if (check_errno && regs.tstate & 0x1100000000UL) {
1636 tcp->u_rval = -1;
1637 u_error = regs.u_regs[U_REG_O0];
1638 }
1639 else {
1640 tcp->u_rval = regs.u_regs[U_REG_O0];
1641 u_error = 0;
1642 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001643# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001644 if (check_errno && is_negated_errno(r28)) {
1645 tcp->u_rval = -1;
1646 u_error = -r28;
1647 }
1648 else {
1649 tcp->u_rval = r28;
1650 u_error = 0;
1651 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001652# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001653 /* interpret R0 as return value or error number */
1654 if (check_errno && is_negated_errno(r0)) {
1655 tcp->u_rval = -1;
1656 u_error = -r0;
1657 }
1658 else {
1659 tcp->u_rval = r0;
1660 u_error = 0;
1661 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001662# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001663 /* interpret result as return value or error number */
1664 if (check_errno && is_negated_errno(r9)) {
1665 tcp->u_rval = -1;
1666 u_error = -r9;
1667 }
1668 else {
1669 tcp->u_rval = r9;
1670 u_error = 0;
1671 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001672# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001673 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1674 tcp->u_rval = -1;
1675 u_error = -r10;
1676 }
1677 else {
1678 tcp->u_rval = r10;
1679 u_error = 0;
1680 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001681# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001682 long rval;
1683 /* interpret result as return value or error number */
1684 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1685 return -1;
1686 if (check_errno && rval < 0 && rval > -nerrnos) {
1687 tcp->u_rval = -1;
1688 u_error = -rval;
1689 }
1690 else {
1691 tcp->u_rval = rval;
1692 u_error = 0;
1693 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001694# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001695 /* interpret result as return value or error number */
1696 if (check_errno && is_negated_errno(r3)) {
1697 tcp->u_rval = -1;
1698 u_error = -r3;
1699 }
1700 else {
1701 tcp->u_rval = r3;
1702 u_error = 0;
1703 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001704# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001705#endif /* LINUX */
1706#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001707 /* get error code from user struct */
1708 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1709 return -1;
1710 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001712 /* get system call return value */
1713 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1714 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715#endif /* SUNOS4 */
1716#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001717# ifdef SPARC
1718 /* Judicious guessing goes a long way. */
1719 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1720 tcp->u_rval = -1;
1721 u_error = tcp->status.pr_reg[R_O0];
1722 }
1723 else {
1724 tcp->u_rval = tcp->status.pr_reg[R_O0];
1725 u_error = 0;
1726 }
1727# endif /* SPARC */
1728# ifdef I386
1729 /* Wanna know how to kill an hour single-stepping? */
1730 if (tcp->status.PR_REG[EFL] & 0x1) {
1731 tcp->u_rval = -1;
1732 u_error = tcp->status.PR_REG[EAX];
1733 }
1734 else {
1735 tcp->u_rval = tcp->status.PR_REG[EAX];
1736# ifdef HAVE_LONG_LONG
1737 tcp->u_lrval =
1738 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1739 tcp->status.PR_REG[EAX];
1740# endif
1741 u_error = 0;
1742 }
1743# endif /* I386 */
1744# ifdef X86_64
1745 /* Wanna know how to kill an hour single-stepping? */
1746 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1747 tcp->u_rval = -1;
1748 u_error = tcp->status.PR_REG[RAX];
1749 }
1750 else {
1751 tcp->u_rval = tcp->status.PR_REG[RAX];
1752 u_error = 0;
1753 }
1754# endif /* X86_64 */
1755# ifdef MIPS
1756 if (tcp->status.pr_reg[CTX_A3]) {
1757 tcp->u_rval = -1;
1758 u_error = tcp->status.pr_reg[CTX_V0];
1759 }
1760 else {
1761 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1762 u_error = 0;
1763 }
1764# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001765#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001766#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001767 if (regs.r_eflags & PSL_C) {
1768 tcp->u_rval = -1;
1769 u_error = regs.r_eax;
1770 } else {
1771 tcp->u_rval = regs.r_eax;
1772 tcp->u_lrval =
1773 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1774 u_error = 0;
1775 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001776#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001777 tcp->u_error = u_error;
1778 return 1;
1779}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780
Roland McGrathb69f81b2002-12-21 23:25:18 +00001781int
Denys Vlasenko12014262011-05-30 14:00:14 +02001782force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001783{
1784#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001785# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001786 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001787 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1788 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001789# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001790 eax = error ? -error : rval;
1791 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1792 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001793# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001794 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001795 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001796 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001797# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001798 if (ia32) {
1799 r8 = error ? -error : rval;
1800 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1801 return -1;
1802 }
1803 else {
1804 if (error) {
1805 r8 = error;
1806 r10 = -1;
1807 }
1808 else {
1809 r8 = rval;
1810 r10 = 0;
1811 }
1812 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1813 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1814 return -1;
1815 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001816# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001817 r0 = error ? -error : rval;
1818 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1819 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001820# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001821 if (error) {
1822 r2 = error;
1823 a3 = -1;
1824 }
1825 else {
1826 r2 = rval;
1827 a3 = 0;
1828 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001829 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001830 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1831 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001832 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001833# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001834 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001835 return -1;
1836 if (error) {
1837 flags |= SO_MASK;
1838 result = error;
1839 }
1840 else {
1841 flags &= ~SO_MASK;
1842 result = rval;
1843 }
Roland McGratheb285352003-01-14 09:59:00 +00001844 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1845 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001846 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001847# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001848 d0 = error ? -error : rval;
1849 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1850 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001851# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001852 regs.ARM_r0 = error ? -error : rval;
1853 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001854 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001855# elif defined(AVR32)
1856 regs.r12 = error ? -error : rval;
1857 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1858 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001859# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001860 if (error) {
1861 a3 = -1;
1862 r0 = error;
1863 }
1864 else {
1865 a3 = 0;
1866 r0 = rval;
1867 }
1868 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1869 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1870 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001871# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001872 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1873 return -1;
1874 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001875 regs.psr |= PSR_C;
1876 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001877 }
1878 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001879 regs.psr &= ~PSR_C;
1880 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001881 }
1882 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1883 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001884# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001885 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1886 return -1;
1887 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001888 regs.tstate |= 0x1100000000UL;
1889 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001890 }
1891 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001892 regs.tstate &= ~0x1100000000UL;
1893 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001894 }
1895 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1896 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001897# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001898 r28 = error ? -error : rval;
1899 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1900 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001901# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001902 r0 = error ? -error : rval;
1903 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1904 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001905# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001906 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001907 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1908 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001909# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001910#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001911
Roland McGrathb69f81b2002-12-21 23:25:18 +00001912#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001913 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1914 error << 24) < 0 ||
1915 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001916 return -1;
1917#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001918
Roland McGrathb69f81b2002-12-21 23:25:18 +00001919#ifdef SVR4
1920 /* XXX no clue */
1921 return -1;
1922#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001923
Roland McGrathb69f81b2002-12-21 23:25:18 +00001924#ifdef FREEBSD
1925 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001926 perror("pread");
1927 return -1;
1928 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001929 if (error) {
1930 regs.r_eflags |= PSL_C;
1931 regs.r_eax = error;
1932 }
1933 else {
1934 regs.r_eflags &= ~PSL_C;
1935 regs.r_eax = rval;
1936 }
1937 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001938 perror("pwrite");
1939 return -1;
1940 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001941#endif /* FREEBSD */
1942
1943 /* All branches reach here on success (only). */
1944 tcp->u_error = error;
1945 tcp->u_rval = rval;
1946 return 0;
1947}
1948
Roland McGratha4d48532005-06-08 20:45:28 +00001949static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001950syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001951{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001952#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001953#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001954 {
1955 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001956 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1957 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001958 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001959 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001960 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001961 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001962 return -1;
1963 }
1964 }
1965#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001966 {
1967 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001968 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1969 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001970 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001971 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001972 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001973 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1974 * for scno somewhere above here!
1975 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001976 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001977 return -1;
1978 }
1979 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001980#elif defined (IA64)
1981 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001982 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001983 unsigned long *out0, cfm, sof, sol, i;
1984 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001985 /* be backwards compatible with kernel < 2.4.4... */
1986# ifndef PT_RBS_END
1987# define PT_RBS_END PT_AR_BSP
1988# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001989
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001990 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001991 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001992 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001993 return -1;
1994
1995 sof = (cfm >> 0) & 0x7f;
1996 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001997 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001998
1999 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2000 && sysent[tcp->scno].nargs != -1)
2001 tcp->u_nargs = sysent[tcp->scno].nargs;
2002 else
2003 tcp->u_nargs = MAX_ARGS;
2004 for (i = 0; i < tcp->u_nargs; ++i) {
2005 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2006 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2007 return -1;
2008 }
2009 } else {
2010 int i;
2011
2012 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002013 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002014 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002015 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002016 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002017 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002018 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002019 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002020 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002021 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002022 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002023 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002024 return -1;
2025
2026 for (i = 0; i < 6; ++i)
2027 /* truncate away IVE sign-extension */
2028 tcp->u_arg[i] &= 0xffffffff;
2029
2030 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2031 && sysent[tcp->scno].nargs != -1)
2032 tcp->u_nargs = sysent[tcp->scno].nargs;
2033 else
2034 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002035 }
2036 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002037#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2038 /* N32 and N64 both use up to six registers. */
2039 {
2040 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002041 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002042
2043 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2044 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002045 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002046 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002047
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002048 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002049 return -1;
2050
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002051 for (i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002052 tcp->u_arg[i] = regs[REG_A0 + i];
2053# if defined (LINUX_MIPSN32)
2054 tcp->ext_arg[i] = regs[REG_A0 + i];
2055# endif
2056 }
2057 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002058#elif defined (MIPS)
2059 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002060 long sp;
2061 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002062
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002063 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2064 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002065 else
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002066 nargs = tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002067 if (nargs > 4) {
2068 if (upeek(tcp, REG_SP, &sp) < 0)
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002069 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002070 for (i = 0; i < 4; i++) {
2071 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002072 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002073 }
2074 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2075 (char *)(tcp->u_arg + 4));
2076 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002077 for (i = 0; i < nargs; i++) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002078 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2079 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002080 }
2081 }
2082 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002083#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002084# ifndef PT_ORIG_R3
2085# define PT_ORIG_R3 34
2086# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002087 {
2088 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002089 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2090 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002091 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002092 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002093 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002094 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002095 (sizeof(unsigned long)*PT_ORIG_R3) :
2096 ((i+PT_R3)*sizeof(unsigned long)),
2097 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002098 return -1;
2099 }
2100 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002101#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002102 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002103 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002104
2105 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2106 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002107 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002108 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002109 for (i = 0; i < tcp->u_nargs; i++)
Mike Frysinger8566c502009-10-12 11:05:14 -04002110 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002111 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002112#elif defined (HPPA)
2113 {
2114 int i;
2115
2116 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2117 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002118 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002119 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002120 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002121 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002122 return -1;
2123 }
2124 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002125#elif defined(ARM)
2126 {
2127 int i;
2128
2129 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2130 tcp->u_nargs = sysent[tcp->scno].nargs;
2131 else
2132 tcp->u_nargs = MAX_ARGS;
2133 for (i = 0; i < tcp->u_nargs; i++)
2134 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002135 }
2136#elif defined(AVR32)
2137 tcp->u_nargs = sysent[tcp->scno].nargs;
2138 tcp->u_arg[0] = regs.r12;
2139 tcp->u_arg[1] = regs.r11;
2140 tcp->u_arg[2] = regs.r10;
2141 tcp->u_arg[3] = regs.r9;
2142 tcp->u_arg[4] = regs.r5;
2143 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002144#elif defined(BFIN)
2145 {
2146 int i;
2147 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2148
2149 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2150 tcp->u_nargs = sysent[tcp->scno].nargs;
2151 else
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +00002152 tcp->u_nargs = ARRAY_SIZE(argreg);
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002153
2154 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002155 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002156 return -1;
2157 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002158#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002159 {
2160 int i;
2161 static int syscall_regs[] = {
2162 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2163 REG_REG0, REG_REG0+1, REG_REG0+2
2164 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002165
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002166 tcp->u_nargs = sysent[tcp->scno].nargs;
2167 for (i = 0; i < tcp->u_nargs; i++) {
2168 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2169 return -1;
2170 }
2171 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002172#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002173 {
2174 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002175 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002176 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2177
2178 /*
2179 * TODO: should also check that the number of arguments encoded
2180 * in the trap number matches the number strace expects.
2181 */
2182 /*
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +00002183 assert(sysent[tcp->scno].nargs < ARRAY_SIZE(syscall_regs));
Roland McGrathe1e584b2003-06-02 19:18:58 +00002184 */
2185
2186 tcp->u_nargs = sysent[tcp->scno].nargs;
2187 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002188 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002189 return -1;
2190 }
2191 }
2192
Michal Ludvig0e035502002-09-23 15:41:01 +00002193#elif defined(X86_64)
2194 {
2195 int i;
2196 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2197 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002198 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002199 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002200
Michal Ludvig0e035502002-09-23 15:41:01 +00002201 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2202 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002203 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002204 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002205 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002206 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002207 return -1;
2208 }
2209 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002210#elif defined(MICROBLAZE)
2211 {
2212 int i;
2213 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2214 tcp->u_nargs = sysent[tcp->scno].nargs;
2215 else
2216 tcp->u_nargs = 0;
2217 for (i = 0; i < tcp->u_nargs; i++) {
2218 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2219 return -1;
2220 }
2221 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002222#elif defined(CRISV10) || defined(CRISV32)
2223 {
2224 int i;
2225 static const int crisregs[] = {
2226 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2227 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2228 };
2229
2230 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2231 tcp->u_nargs = sysent[tcp->scno].nargs;
2232 else
2233 tcp->u_nargs = 0;
2234 for (i = 0; i < tcp->u_nargs; i++) {
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00002235 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002236 return -1;
2237 }
2238 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05002239#elif defined(TILE)
2240 {
2241 int i;
2242 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2243 tcp->u_nargs = sysent[tcp->scno].nargs;
2244 else
2245 tcp->u_nargs = MAX_ARGS;
2246 for (i = 0; i < tcp->u_nargs; ++i) {
2247 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2248 return -1;
2249 }
2250 }
Andreas Schwab246888d2010-06-05 21:50:30 +02002251#elif defined (M68K)
2252 {
2253 int i;
2254 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2255 tcp->u_nargs = sysent[tcp->scno].nargs;
2256 else
2257 tcp->u_nargs = MAX_ARGS;
2258 for (i = 0; i < tcp->u_nargs; i++) {
2259 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2260 return -1;
2261 }
2262 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002263#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002264 {
2265 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002266 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2267 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002268 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002269 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002270 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002271 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002272 return -1;
2273 }
2274 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002275#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002276#endif /* LINUX */
2277#ifdef SUNOS4
2278 {
2279 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002280 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2281 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002282 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002283 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002284 for (i = 0; i < tcp->u_nargs; i++) {
2285 struct user *u;
2286
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002287 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002288 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2289 return -1;
2290 }
2291 }
2292#endif /* SUNOS4 */
2293#ifdef SVR4
2294#ifdef MIPS
2295 /*
2296 * SGI is broken: even though it has pr_sysarg, it doesn't
2297 * set them on system call entry. Get a clue.
2298 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002299 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002300 tcp->u_nargs = sysent[tcp->scno].nargs;
2301 else
2302 tcp->u_nargs = tcp->status.pr_nsysarg;
2303 if (tcp->u_nargs > 4) {
2304 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2305 4*sizeof(tcp->u_arg[0]));
2306 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2307 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2308 }
2309 else {
2310 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2311 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2312 }
John Hughes25299712001-03-06 10:10:06 +00002313#elif UNIXWARE >= 2
2314 /*
2315 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2316 */
2317 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2318 tcp->u_nargs = sysent[tcp->scno].nargs;
2319 else
2320 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2321 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2322 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2323#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002324 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002325 tcp->u_nargs = sysent[tcp->scno].nargs;
2326 else
2327 tcp->u_nargs = tcp->status.pr_nsysarg;
2328 {
2329 int i;
2330 for (i = 0; i < tcp->u_nargs; i++)
2331 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2332 }
John Hughes25299712001-03-06 10:10:06 +00002333#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002334 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002335 tcp->u_nargs = sysent[tcp->scno].nargs;
2336 else
2337 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002338 if (tcp->u_nargs > 0)
2339 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2340 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002341#else
2342 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002343#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002344#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002345#ifdef FREEBSD
2346 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2347 sysent[tcp->scno].nargs > tcp->status.val)
2348 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002349 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002350 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002351 if (tcp->u_nargs < 0)
2352 tcp->u_nargs = 0;
2353 if (tcp->u_nargs > MAX_ARGS)
2354 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002355 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002356 case SYS___syscall:
2357 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2358 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002359 break;
2360 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002361 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2362 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002363 break;
2364 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002365 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2366 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002367 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002368 }
2369#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002370 return 1;
2371}
2372
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002373static int
2374trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002375{
2376 int sys_res;
2377 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002378 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002379 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002380
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002381 /* Measure the exit time as early as possible to avoid errors. */
2382 if (dtime || cflag)
2383 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002384
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002385 /* BTW, why we don't just memorize syscall no. on entry
2386 * in tcp->something?
2387 */
2388 scno_good = res = get_scno(tcp);
2389 if (res == 0)
2390 return res;
2391 if (res == 1)
2392 res = syscall_fixup(tcp);
2393 if (res == 0)
2394 return res;
2395 if (res == 1)
2396 res = get_error(tcp);
2397 if (res == 0)
2398 return res;
2399 if (res == 1)
2400 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002401
Grant Edwards8a082772011-04-07 20:25:40 +00002402 if (res == 1 && filtered(tcp)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002403 tcp->flags &= ~TCB_INSYSCALL;
2404 return 0;
2405 }
2406
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002407 if (tcp->flags & TCB_REPRINT) {
2408 printleader(tcp);
2409 tprintf("<... ");
2410 if (scno_good != 1)
2411 tprintf("????");
2412 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2413 tprintf("syscall_%lu", tcp->scno);
2414 else
2415 tprintf("%s", sysent[tcp->scno].sys_name);
2416 tprintf(" resumed> ");
2417 }
2418
2419 if (cflag) {
2420 struct timeval t = tv;
2421 int rc = count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002422 if (cflag == CFLAG_ONLY_STATS) {
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002423 tcp->flags &= ~TCB_INSYSCALL;
2424 return rc;
2425 }
2426 }
2427
2428 if (res != 1) {
2429 tprintf(") ");
2430 tabto(acolumn);
2431 tprintf("= ? <unavailable>");
2432 printtrailer();
2433 tcp->flags &= ~TCB_INSYSCALL;
2434 return res;
2435 }
2436
2437 if (tcp->scno >= nsyscalls || tcp->scno < 0
2438 || (qual_flags[tcp->scno] & QUAL_RAW))
2439 sys_res = printargs(tcp);
2440 else {
2441 if (not_failing_only && tcp->u_error)
2442 return 0; /* ignore failed syscalls */
2443 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2444 }
2445
2446 u_error = tcp->u_error;
2447 tprintf(") ");
2448 tabto(acolumn);
2449 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2450 qual_flags[tcp->scno] & QUAL_RAW) {
2451 if (u_error)
2452 tprintf("= -1 (errno %ld)", u_error);
2453 else
2454 tprintf("= %#lx", tcp->u_rval);
2455 }
2456 else if (!(sys_res & RVAL_NONE) && u_error) {
2457 switch (u_error) {
2458#ifdef LINUX
2459 case ERESTARTSYS:
2460 tprintf("= ? ERESTARTSYS (To be restarted)");
2461 break;
2462 case ERESTARTNOINTR:
2463 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2464 break;
2465 case ERESTARTNOHAND:
2466 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2467 break;
2468 case ERESTART_RESTARTBLOCK:
2469 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2470 break;
2471#endif /* LINUX */
2472 default:
2473 tprintf("= -1 ");
2474 if (u_error < 0)
2475 tprintf("E??? (errno %ld)", u_error);
2476 else if (u_error < nerrnos)
2477 tprintf("%s (%s)", errnoent[u_error],
2478 strerror(u_error));
2479 else
2480 tprintf("ERRNO_%ld (%s)", u_error,
2481 strerror(u_error));
2482 break;
2483 }
2484 if ((sys_res & RVAL_STR) && tcp->auxstr)
2485 tprintf(" (%s)", tcp->auxstr);
2486 }
2487 else {
2488 if (sys_res & RVAL_NONE)
2489 tprintf("= ?");
2490 else {
2491 switch (sys_res & RVAL_MASK) {
2492 case RVAL_HEX:
2493 tprintf("= %#lx", tcp->u_rval);
2494 break;
2495 case RVAL_OCTAL:
2496 tprintf("= %#lo", tcp->u_rval);
2497 break;
2498 case RVAL_UDECIMAL:
2499 tprintf("= %lu", tcp->u_rval);
2500 break;
2501 case RVAL_DECIMAL:
2502 tprintf("= %ld", tcp->u_rval);
2503 break;
2504#ifdef HAVE_LONG_LONG
2505 case RVAL_LHEX:
2506 tprintf("= %#llx", tcp->u_lrval);
2507 break;
2508 case RVAL_LOCTAL:
2509 tprintf("= %#llo", tcp->u_lrval);
2510 break;
2511 case RVAL_LUDECIMAL:
2512 tprintf("= %llu", tcp->u_lrval);
2513 break;
2514 case RVAL_LDECIMAL:
2515 tprintf("= %lld", tcp->u_lrval);
2516 break;
2517#endif
2518 default:
2519 fprintf(stderr,
2520 "invalid rval format\n");
2521 break;
2522 }
2523 }
2524 if ((sys_res & RVAL_STR) && tcp->auxstr)
2525 tprintf(" (%s)", tcp->auxstr);
2526 }
2527 if (dtime) {
2528 tv_sub(&tv, &tv, &tcp->etime);
2529 tprintf(" <%ld.%06ld>",
2530 (long) tv.tv_sec, (long) tv.tv_usec);
2531 }
2532 printtrailer();
2533
2534 dumpio(tcp);
2535 if (fflush(tcp->outf) == EOF)
2536 return -1;
2537 tcp->flags &= ~TCB_INSYSCALL;
2538 return 0;
2539}
2540
2541static int
2542trace_syscall_entering(struct tcb *tcp)
2543{
2544 int sys_res;
2545 int res, scno_good;
2546
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002547 scno_good = res = get_scno(tcp);
2548 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002549 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002550 if (res == 1)
2551 res = syscall_fixup(tcp);
2552 if (res == 0)
2553 return res;
2554 if (res == 1)
2555 res = syscall_enter(tcp);
2556 if (res == 0)
2557 return res;
2558
2559 if (res != 1) {
2560 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002561 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002562 tcp_last = tcp;
2563 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002564 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002565 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2566 tprintf("syscall_%lu(", tcp->scno);
2567 else
2568 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002569 /*
2570 * " <unavailable>" will be added later by the code which
2571 * detects ptrace errors.
2572 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002573 tcp->flags |= TCB_INSYSCALL;
2574 return res;
2575 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002576
Roland McGrath17352792005-06-07 23:21:26 +00002577 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002578#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002579 case SYS_socketcall:
2580 decode_subcall(tcp, SYS_socket_subcall,
2581 SYS_socket_nsubcalls, deref_style);
2582 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002583#endif
2584#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002585 case SYS_ipc:
2586 decode_subcall(tcp, SYS_ipc_subcall,
2587 SYS_ipc_nsubcalls, shift_style);
2588 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002589#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002590#ifdef SVR4
2591#ifdef SYS_pgrpsys_subcall
2592 case SYS_pgrpsys:
2593 decode_subcall(tcp, SYS_pgrpsys_subcall,
2594 SYS_pgrpsys_nsubcalls, shift_style);
2595 break;
2596#endif /* SYS_pgrpsys_subcall */
2597#ifdef SYS_sigcall_subcall
2598 case SYS_sigcall:
2599 decode_subcall(tcp, SYS_sigcall_subcall,
2600 SYS_sigcall_nsubcalls, mask_style);
2601 break;
2602#endif /* SYS_sigcall_subcall */
2603 case SYS_msgsys:
2604 decode_subcall(tcp, SYS_msgsys_subcall,
2605 SYS_msgsys_nsubcalls, shift_style);
2606 break;
2607 case SYS_shmsys:
2608 decode_subcall(tcp, SYS_shmsys_subcall,
2609 SYS_shmsys_nsubcalls, shift_style);
2610 break;
2611 case SYS_semsys:
2612 decode_subcall(tcp, SYS_semsys_subcall,
2613 SYS_semsys_nsubcalls, shift_style);
2614 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615 case SYS_sysfs:
2616 decode_subcall(tcp, SYS_sysfs_subcall,
2617 SYS_sysfs_nsubcalls, shift_style);
2618 break;
2619 case SYS_spcall:
2620 decode_subcall(tcp, SYS_spcall_subcall,
2621 SYS_spcall_nsubcalls, shift_style);
2622 break;
2623#ifdef SYS_context_subcall
2624 case SYS_context:
2625 decode_subcall(tcp, SYS_context_subcall,
2626 SYS_context_nsubcalls, shift_style);
2627 break;
2628#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002629#ifdef SYS_door_subcall
2630 case SYS_door:
2631 decode_subcall(tcp, SYS_door_subcall,
2632 SYS_door_nsubcalls, door_style);
2633 break;
2634#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002635#ifdef SYS_kaio_subcall
2636 case SYS_kaio:
2637 decode_subcall(tcp, SYS_kaio_subcall,
2638 SYS_kaio_nsubcalls, shift_style);
2639 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002640#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002641#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002642#ifdef FREEBSD
2643 case SYS_msgsys:
2644 case SYS_shmsys:
2645 case SYS_semsys:
2646 decode_subcall(tcp, 0, 0, table_style);
2647 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002648#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002649#ifdef SUNOS4
2650 case SYS_semsys:
2651 decode_subcall(tcp, SYS_semsys_subcall,
2652 SYS_semsys_nsubcalls, shift_style);
2653 break;
2654 case SYS_msgsys:
2655 decode_subcall(tcp, SYS_msgsys_subcall,
2656 SYS_msgsys_nsubcalls, shift_style);
2657 break;
2658 case SYS_shmsys:
2659 decode_subcall(tcp, SYS_shmsys_subcall,
2660 SYS_shmsys_nsubcalls, shift_style);
2661 break;
2662#endif
2663 }
2664
2665 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002666
2667 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2668 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2669 (tracing_paths && !pathtrace_match(tcp))) {
2670 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002671 return 0;
2672 }
2673
Grant Edwards8a082772011-04-07 20:25:40 +00002674 tcp->flags &= ~TCB_FILTERED;
2675
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002676 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002677 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002678 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002679 return 0;
2680 }
2681
2682 printleader(tcp);
2683 tcp->flags &= ~TCB_REPRINT;
2684 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002685 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002686 tprintf("syscall_%lu(", tcp->scno);
2687 else
2688 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002689 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002690 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2691 sysent[tcp->scno].sys_func != sys_exit))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002692 sys_res = printargs(tcp);
2693 else
2694 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2695 if (fflush(tcp->outf) == EOF)
2696 return -1;
2697 tcp->flags |= TCB_INSYSCALL;
2698 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002699 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002700 gettimeofday(&tcp->etime, NULL);
2701 return sys_res;
2702}
2703
2704int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002705trace_syscall(struct tcb *tcp)
2706{
2707 return exiting(tcp) ?
2708 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2709}
2710
2711int
Denys Vlasenko12014262011-05-30 14:00:14 +02002712printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713{
2714 if (entering(tcp)) {
2715 int i;
2716
2717 for (i = 0; i < tcp->u_nargs; i++)
2718 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2719 }
2720 return 0;
2721}
2722
2723long
Denys Vlasenko12014262011-05-30 14:00:14 +02002724getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002725{
2726 long val = -1;
2727
2728#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002729#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002730 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002731 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002732 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002733 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002734#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002735 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002736 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002737#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002738 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002739 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002740#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741#endif /* LINUX */
2742
2743#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002744 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002745 return -1;
2746#endif /* SUNOS4 */
2747
2748#ifdef SVR4
2749#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002750 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002751#endif /* SPARC */
2752#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002753 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002754#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002755#ifdef X86_64
2756 val = tcp->status.PR_REG[RDX];
2757#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002758#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002759 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002760#endif /* MIPS */
2761#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002762
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002763#ifdef FREEBSD
2764 struct reg regs;
2765 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2766 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002767#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002768 return val;
2769}
2770
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002771#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002772/*
2773 * Apparently, indirect system calls have already be converted by ptrace(2),
2774 * so if you see "indir" this program has gone astray.
2775 */
2776int
Denys Vlasenko12014262011-05-30 14:00:14 +02002777sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002778{
2779 int i, scno, nargs;
2780
2781 if (entering(tcp)) {
2782 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2783 fprintf(stderr, "Bogus syscall: %u\n", scno);
2784 return 0;
2785 }
2786 nargs = sysent[scno].nargs;
2787 tprintf("%s", sysent[scno].sys_name);
2788 for (i = 0; i < nargs; i++)
2789 tprintf(", %#lx", tcp->u_arg[i+1]);
2790 }
2791 return 0;
2792}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002793#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002794
2795int
2796is_restart_error(struct tcb *tcp)
2797{
2798#ifdef LINUX
2799 if (!syserror(tcp))
2800 return 0;
2801 switch (tcp->u_error) {
2802 case ERESTARTSYS:
2803 case ERESTARTNOINTR:
2804 case ERESTARTNOHAND:
2805 case ERESTART_RESTARTBLOCK:
2806 return 1;
2807 default:
2808 break;
2809 }
2810#endif /* LINUX */
2811 return 0;
2812}