blob: b7fabe0078559faeb27487ab883c9fc2d3e9dad8 [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};
Roland McGrathee36ce12004-09-04 03:53:10 +0000117static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
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};
Roland McGrathee36ce12004-09-04 03:53:10 +0000124static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
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};
Roland McGrathee36ce12004-09-04 03:53:10 +0000132static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
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};
Roland McGrathee36ce12004-09-04 03:53:10 +0000152static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
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};
Roland McGrathee36ce12004-09-04 03:53:10 +0000158static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
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};
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
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:
599 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
600 if (subcalls_table[i].call == tcp->scno) break;
601 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
602 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
656 if ( sys_waitpid == func
657 || sys_wait4 == func
658#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
659 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000660#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000661#ifdef ALPHA
662 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000663#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000664 )
665 return internal_wait(tcp, 2);
666
667#if defined(LINUX) || defined(SVR4)
668 if (sys_waitid == func)
669 return internal_wait(tcp, 3);
670#endif
671
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000672 return 0;
673}
674
Wichert Akkermanc7926982000-04-10 22:22:31 +0000675
676#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200677# if defined (I386)
678static long eax;
679# elif defined (IA64)
680long r8, r10, psr; /* TODO: make static? */
681long ia32 = 0; /* not static */
682# elif defined (POWERPC)
683static long result, flags;
684# elif defined (M68K)
685static long d0;
686# elif defined(BFIN)
687static long r0;
688# elif defined (ARM)
689static struct pt_regs regs;
690# elif defined (ALPHA)
691static long r0;
692static long a3;
693# elif defined(AVR32)
694static struct pt_regs regs;
695# elif defined (SPARC) || defined (SPARC64)
696static struct pt_regs regs;
697static unsigned long trap;
698# elif defined(LINUX_MIPSN32)
699static long long a3;
700static long long r2;
701# elif defined(MIPS)
702static long a3;
703static long r2;
704# elif defined(S390) || defined(S390X)
705static long gpr2;
706static long pc;
707static long syscall_mode;
708# elif defined(HPPA)
709static long r28;
710# elif defined(SH)
711static long r0;
712# elif defined(SH64)
713static long r9;
714# elif defined(X86_64)
715static long rax;
716# elif defined(CRISV10) || defined(CRISV32)
717static long r10;
718# elif defined(MICROBLAZE)
719static long r3;
720# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000721#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000722#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200723struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000724#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000725
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000726int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000727get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000728{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000729 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000730
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000731#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000732# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000733 if (tcp->flags & TCB_WAITEXECVE) {
734 /*
735 * When the execve system call completes successfully, the
736 * new process still has -ENOSYS (old style) or __NR_execve
737 * (new style) in gpr2. We cannot recover the scno again
738 * by disassembly, because the image that executed the
739 * syscall is gone now. Fortunately, we don't want it. We
740 * leave the flag set so that syscall_fixup can fake the
741 * result.
742 */
743 if (tcp->flags & TCB_INSYSCALL)
744 return 1;
745 /*
746 * This is the SIGTRAP after execve. We cannot try to read
747 * the system call here either.
748 */
749 tcp->flags &= ~TCB_WAITEXECVE;
750 return 0;
751 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000752
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000753 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200754 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000755
756 if (syscall_mode != -ENOSYS) {
757 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000758 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000759 */
760 scno = syscall_mode;
761 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000762 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000763 * Old style of "passing" the scno via the SVC instruction.
764 */
765
766 long opcode, offset_reg, tmp;
767 void * svc_addr;
768 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
769 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
770 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
771 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000772
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000773 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000774 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000775 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000776 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000777 if (errno) {
778 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000779 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000780 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000781
782 /*
783 * We have to check if the SVC got executed directly or via an
784 * EXECUTE instruction. In case of EXECUTE it is necessary to do
785 * instruction decoding to derive the system call number.
786 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
787 * so that this doesn't work if a SVC opcode is part of an EXECUTE
788 * opcode. Since there is no way to find out the opcode size this
789 * is the best we can do...
790 */
791
792 if ((opcode & 0xff00) == 0x0a00) {
793 /* SVC opcode */
794 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000795 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000796 else {
797 /* SVC got executed by EXECUTE instruction */
798
799 /*
800 * Do instruction decoding of EXECUTE. If you really want to
801 * understand this, read the Principles of Operations.
802 */
803 svc_addr = (void *) (opcode & 0xfff);
804
805 tmp = 0;
806 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000807 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000808 return -1;
809 svc_addr += tmp;
810
811 tmp = 0;
812 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000813 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000814 return -1;
815 svc_addr += tmp;
816
Denys Vlasenkofb036672009-01-23 16:30:26 +0000817 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000818 if (errno)
819 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000820# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000821 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000822# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000823 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000824# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000825 tmp = 0;
826 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000827 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000828 return -1;
829
830 scno = (scno | tmp) & 0xff;
831 }
832 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000833# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000834 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000835 return -1;
836 if (!(tcp->flags & TCB_INSYSCALL)) {
837 /* Check if we return from execve. */
838 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
839 tcp->flags &= ~TCB_WAITEXECVE;
840 return 0;
841 }
842 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200843
844# ifdef POWERPC64
845 if (!(tcp->flags & TCB_INSYSCALL)) {
846 static int currpers = -1;
847 long val;
848 int pid = tcp->pid;
849
850 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200851 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200852 return -1;
853 /* SF is bit 0 of MSR */
854 if (val < 0)
855 currpers = 0;
856 else
857 currpers = 1;
858 if (currpers != current_personality) {
859 static const char *const names[] = {"64 bit", "32 bit"};
860 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000861 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200862 pid, names[current_personality]);
863 }
864 }
865# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000866# elif defined(AVR32)
867 /*
868 * Read complete register set in one go.
869 */
870 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
871 return -1;
872
873 /*
874 * We only need to grab the syscall number on syscall entry.
875 */
876 if (!(tcp->flags & TCB_INSYSCALL)) {
877 scno = regs.r8;
878
879 /* Check if we return from execve. */
880 if (tcp->flags & TCB_WAITEXECVE) {
881 tcp->flags &= ~TCB_WAITEXECVE;
882 return 0;
883 }
884 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000885# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000886 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000887 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000888# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000889 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000890 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000891# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000892 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000893 return -1;
894
Roland McGrath761b5d72002-12-15 23:58:31 +0000895 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000896 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000897 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000898 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000899
900 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200901 * 0x33 for long mode (64 bit)
902 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000903 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000904 * to be cached.
905 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000906 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000907 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000908 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000909 case 0x23: currpers = 1; break;
910 case 0x33: currpers = 0; break;
911 default:
912 fprintf(stderr, "Unknown value CS=0x%02X while "
913 "detecting personality of process "
914 "PID=%d\n", (int)val, pid);
915 currpers = current_personality;
916 break;
917 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000918# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000919 /* This version analyzes the opcode of a syscall instruction.
920 * (int 0x80 on i386 vs. syscall on x86-64)
921 * It works, but is too complicated.
922 */
923 unsigned long val, rip, i;
924
Denys Vlasenko8236f252009-01-02 18:10:08 +0000925 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000926 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000927
Michal Ludvig0e035502002-09-23 15:41:01 +0000928 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000929 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000930 errno = 0;
931
Denys Vlasenko8236f252009-01-02 18:10:08 +0000932 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000933 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000934 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000935 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000936 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000937 /* x86-64: syscall = 0x0f 0x05 */
938 case 0x050f: currpers = 0; break;
939 /* i386: int 0x80 = 0xcd 0x80 */
940 case 0x80cd: currpers = 1; break;
941 default:
942 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000943 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000944 "Unknown syscall opcode (0x%04X) while "
945 "detecting personality of process "
946 "PID=%d\n", (int)call, pid);
947 break;
948 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000949# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000950 if (currpers != current_personality) {
951 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000952 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000953 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000954 pid, names[current_personality]);
955 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000956 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000957# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000958# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200959 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000960 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000961 if (!(tcp->flags & TCB_INSYSCALL)) {
962 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000963 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000964 return -1;
965 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200966 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000967 return -1;
968 }
Roland McGrathba954762003-03-05 06:29:06 +0000969 /* Check if we return from execve. */
970 if (tcp->flags & TCB_WAITEXECVE) {
971 tcp->flags &= ~TCB_WAITEXECVE;
972 return 0;
973 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000974 } else {
975 /* syscall in progress */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200976 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000977 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200978 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000979 return -1;
980 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000981# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000982 /*
983 * Read complete register set in one go.
984 */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000985 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000986 return -1;
987
988 /*
989 * We only need to grab the syscall number on syscall entry.
990 */
991 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +0000992 if (!(tcp->flags & TCB_INSYSCALL)) {
993 /* Check if we return from execve. */
994 if (tcp->flags & TCB_WAITEXECVE) {
995 tcp->flags &= ~TCB_WAITEXECVE;
996 return 0;
997 }
998 }
999
Roland McGrath0f87c492003-06-03 23:29:04 +00001000 /*
1001 * Note: we only deal with only 32-bit CPUs here.
1002 */
1003 if (regs.ARM_cpsr & 0x20) {
1004 /*
1005 * Get the Thumb-mode system call number
1006 */
1007 scno = regs.ARM_r7;
1008 } else {
1009 /*
1010 * Get the ARM-mode system call number
1011 */
1012 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001013 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001014 if (errno)
1015 return -1;
1016
1017 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1018 tcp->flags &= ~TCB_WAITEXECVE;
1019 return 0;
1020 }
1021
Roland McGrathf691bd22006-04-25 07:34:41 +00001022 /* Handle the EABI syscall convention. We do not
1023 bother converting structures between the two
1024 ABIs, but basic functionality should work even
1025 if strace and the traced program have different
1026 ABIs. */
1027 if (scno == 0xef000000) {
1028 scno = regs.ARM_r7;
1029 } else {
1030 if ((scno & 0x0ff00000) != 0x0f900000) {
1031 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1032 scno);
1033 return -1;
1034 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001035
Roland McGrathf691bd22006-04-25 07:34:41 +00001036 /*
1037 * Fixup the syscall number
1038 */
1039 scno &= 0x000fffff;
1040 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001041 }
Roland McGrath56703312008-05-20 01:35:55 +00001042 if (scno & 0x0f0000) {
1043 /*
1044 * Handle ARM specific syscall
1045 */
1046 set_personality(1);
1047 scno &= 0x0000ffff;
1048 } else
1049 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001050
1051 if (tcp->flags & TCB_INSYSCALL) {
1052 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1053 tcp->flags &= ~TCB_INSYSCALL;
1054 }
1055 } else {
1056 if (!(tcp->flags & TCB_INSYSCALL)) {
1057 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1058 tcp->flags |= TCB_INSYSCALL;
1059 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001061# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001062 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001064# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001065 unsigned long long regs[38];
1066
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001067 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001068 return -1;
1069 a3 = regs[REG_A3];
1070 r2 = regs[REG_V0];
1071
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001072 if (!(tcp->flags & TCB_INSYSCALL)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001073 scno = r2;
1074
1075 /* Check if we return from execve. */
1076 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1077 tcp->flags &= ~TCB_WAITEXECVE;
1078 return 0;
1079 }
1080
1081 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001082 if (a3 == 0 || a3 == -1) {
1083 if (debug)
1084 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001085 return 0;
1086 }
1087 }
1088 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001089# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001090 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001091 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001092 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001093 if (upeek(tcp, REG_V0, &scno) < 0)
1094 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001095
Roland McGrath542c2c62008-05-20 01:11:56 +00001096 /* Check if we return from execve. */
1097 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1098 tcp->flags &= ~TCB_WAITEXECVE;
1099 return 0;
1100 }
1101
Wichert Akkermanf90da011999-10-31 21:15:38 +00001102 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001103 if (a3 == 0 || a3 == -1) {
1104 if (debug)
1105 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001106 return 0;
1107 }
1108 }
1109 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001110 if (upeek(tcp, REG_V0, &r2) < 0)
1111 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001112 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001113# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001114 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001115 return -1;
1116
1117 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001118 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 return -1;
1120
1121 /* Check if we return from execve. */
1122 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1123 tcp->flags &= ~TCB_WAITEXECVE;
1124 return 0;
1125 }
1126
1127 /*
1128 * Do some sanity checks to figure out if it's
1129 * really a syscall entry
1130 */
1131 if (scno < 0 || scno > nsyscalls) {
1132 if (a3 == 0 || a3 == -1) {
1133 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001134 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 return 0;
1136 }
1137 }
1138 }
1139 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001140 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001141 return -1;
1142 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001143# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001144 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001145 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001146 return -1;
1147
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001148 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149 if (!(tcp->flags & TCB_INSYSCALL)) {
1150 /* Retrieve the syscall trap instruction. */
1151 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001152# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001153 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001154 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001155# else
1156 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001157# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001158 if (errno)
1159 return -1;
1160
1161 /* Disassemble the trap to see what personality to use. */
1162 switch (trap) {
1163 case 0x91d02010:
1164 /* Linux/SPARC syscall trap. */
1165 set_personality(0);
1166 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001167 case 0x91d0206d:
1168 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001169 set_personality(2);
1170 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171 case 0x91d02000:
1172 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001173 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174 return -1;
1175 case 0x91d02008:
1176 /* Solaris 2.x syscall trap. (per 2) */
1177 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001178 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 case 0x91d02009:
1180 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001181 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182 return -1;
1183 case 0x91d02027:
1184 /* Solaris 2.x gettimeofday */
1185 set_personality(1);
1186 break;
1187 default:
1188 /* Unknown syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001189 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190 tcp->flags &= ~TCB_WAITEXECVE;
1191 return 0;
1192 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001193# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001194 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001195# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001196 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001197# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001198 return -1;
1199 }
1200
1201 /* Extract the system call number from the registers. */
1202 if (trap == 0x91d02027)
1203 scno = 156;
1204 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001205 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001206 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001207 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001208 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 +00001209 }
1210 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001211# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001212 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001213 return -1;
1214 if (!(tcp->flags & TCB_INSYSCALL)) {
1215 /* Check if we return from execve. */
1216 if ((tcp->flags & TCB_WAITEXECVE)) {
1217 tcp->flags &= ~TCB_WAITEXECVE;
1218 return 0;
1219 }
1220 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001221# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001222 /*
1223 * In the new syscall ABI, the system call number is in R3.
1224 */
1225 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1226 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001227
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001228 if (scno < 0) {
1229 /* Odd as it may seem, a glibc bug has been known to cause
1230 glibc to issue bogus negative syscall numbers. So for
1231 our purposes, make strace print what it *should* have been */
1232 long correct_scno = (scno & 0xff);
1233 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001234 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001235 "Detected glibc bug: bogus system call"
1236 " number = %ld, correcting to %ld\n",
1237 scno,
1238 correct_scno);
1239 scno = correct_scno;
1240 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001241
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001242 if (!(tcp->flags & TCB_INSYSCALL)) {
1243 /* Check if we return from execve. */
1244 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1245 tcp->flags &= ~TCB_WAITEXECVE;
1246 return 0;
1247 }
1248 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001249# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001250 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001251 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001252 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001253
1254 if (!(tcp->flags & TCB_INSYSCALL)) {
1255 /* Check if we return from execve. */
1256 if (tcp->flags & TCB_WAITEXECVE) {
1257 tcp->flags &= ~TCB_WAITEXECVE;
1258 return 0;
1259 }
1260 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001261# elif defined(CRISV10) || defined(CRISV32)
1262 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1263 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001264# elif defined(TILE)
1265 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1266 return -1;
1267
1268 if (!(tcp->flags & TCB_INSYSCALL)) {
1269 /* Check if we return from execve. */
1270 if (tcp->flags & TCB_WAITEXECVE) {
1271 tcp->flags &= ~TCB_WAITEXECVE;
1272 return 0;
1273 }
1274 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001275# elif defined(MICROBLAZE)
1276 if (upeek(tcp, 0, &scno) < 0)
1277 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001278# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001280
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001281#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001282 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001283 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001284#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001285 /* new syscall ABI returns result in R0 */
1286 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1287 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001288#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001289 /* ABI defines result returned in r9 */
1290 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1291 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001293
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001294#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001295# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001296 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001297# else
1298# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001299 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001300# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001301 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001302 perror("pread");
1303 return -1;
1304 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001305 switch (regs.r_eax) {
1306 case SYS_syscall:
1307 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001308 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1309 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001310 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001311 scno = regs.r_eax;
1312 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001313 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001314# endif /* FREEBSD */
1315# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001316#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001317
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001318 if (!(tcp->flags & TCB_INSYSCALL))
1319 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001320 return 1;
1321}
1322
Pavel Machek4dc3b142000-02-01 17:58:41 +00001323
Roland McGrath17352792005-06-07 23:21:26 +00001324long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001325known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001326{
1327 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001328#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001329 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1330 scno = sysent[scno].native_scno;
1331 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001332#endif
Roland McGrath17352792005-06-07 23:21:26 +00001333 scno += NR_SYSCALL_BASE;
1334 return scno;
1335}
1336
Roland McGratheb9e2e82009-06-02 16:49:22 -07001337/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001338 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001339 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1340 * 1: ok, continue in trace_syscall().
1341 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001342 * ("????" etc) and bail out.
1343 */
Roland McGratha4d48532005-06-08 20:45:28 +00001344static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001345syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001346{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001347#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001348 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001349
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001350 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001351 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001352 if (
1353 scno == SYS_fork
1354#ifdef SYS_vfork
1355 || scno == SYS_vfork
1356#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001357#ifdef SYS_fork1
1358 || scno == SYS_fork1
1359#endif /* SYS_fork1 */
1360#ifdef SYS_forkall
1361 || scno == SYS_forkall
1362#endif /* SYS_forkall */
1363#ifdef SYS_rfork1
1364 || scno == SYS_rfork1
1365#endif /* SYS_fork1 */
1366#ifdef SYS_rforkall
1367 || scno == SYS_rforkall
1368#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 ) {
1370 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001371 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001372 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001373 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374 }
1375 else {
1376 fprintf(stderr, "syscall: missing entry\n");
1377 tcp->flags |= TCB_INSYSCALL;
1378 }
1379 }
1380 }
1381 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001382 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001383 fprintf(stderr, "syscall: missing exit\n");
1384 tcp->flags &= ~TCB_INSYSCALL;
1385 }
1386 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001387#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001388#ifdef SUNOS4
1389 if (!(tcp->flags & TCB_INSYSCALL)) {
1390 if (scno == 0) {
1391 fprintf(stderr, "syscall: missing entry\n");
1392 tcp->flags |= TCB_INSYSCALL;
1393 }
1394 }
1395 else {
1396 if (scno != 0) {
1397 if (debug) {
1398 /*
1399 * This happens when a signal handler
1400 * for a signal which interrupted a
1401 * a system call makes another system call.
1402 */
1403 fprintf(stderr, "syscall: missing exit\n");
1404 }
1405 tcp->flags &= ~TCB_INSYSCALL;
1406 }
1407 }
1408#endif /* SUNOS4 */
1409#ifdef LINUX
1410#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001411 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001412 return -1;
1413 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1414 if (debug)
1415 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1416 return 0;
1417 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001418#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001419 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001420 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001421 if (current_personality == 1)
1422 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001423 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1424 if (debug)
1425 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1426 return 0;
1427 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001428#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001429 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001430 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001431 if (syscall_mode != -ENOSYS)
1432 syscall_mode = tcp->scno;
1433 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001434 if (debug)
1435 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1436 return 0;
1437 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001438 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1439 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1440 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1441 /*
1442 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1443 * flag set for the post-execve SIGTRAP to see and reset.
1444 */
1445 gpr2 = 0;
1446 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001447#elif defined (POWERPC)
1448# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001449 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001450 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001451 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452 return -1;
1453 if (flags & SO_MASK)
1454 result = -result;
1455#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001456 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001457 return -1;
1458 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1459 if (debug)
1460 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1461 return 0;
1462 }
1463#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001464 /*
1465 * Nothing required
1466 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001467#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001468 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001469 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001470#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001471 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001472 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001473#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001474 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001475 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001476 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001477 return -1;
1478 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1479 if (debug)
1480 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1481 return 0;
1482 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001483#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001484 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001485 return -1;
1486 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1487 if (debug)
1488 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1489 return 0;
1490 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001491#elif defined(MICROBLAZE)
1492 if (upeek(tcp, 3 * 4, &r3) < 0)
1493 return -1;
1494 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1495 if (debug)
1496 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1497 return 0;
1498 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001499#endif
1500#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001501 return 1;
1502}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001503
Roland McGrathc1e45922008-05-27 23:18:29 +00001504#ifdef LINUX
1505/*
1506 * Check the syscall return value register value for whether it is
1507 * a negated errno code indicating an error, or a success return value.
1508 */
1509static inline int
1510is_negated_errno(unsigned long int val)
1511{
1512 unsigned long int max = -(long int) nerrnos;
1513 if (personality_wordsize[current_personality] < sizeof(val)) {
1514 val = (unsigned int) val;
1515 max = (unsigned int) max;
1516 }
1517 return val > max;
1518}
1519#endif
1520
Roland McGratha4d48532005-06-08 20:45:28 +00001521static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001522get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001523{
1524 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001525#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001526 int check_errno = 1;
1527 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1528 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1529 check_errno = 0;
1530 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001531# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001532 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001533 tcp->u_rval = -1;
1534 u_error = -gpr2;
1535 }
1536 else {
1537 tcp->u_rval = gpr2;
1538 u_error = 0;
1539 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001540# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001541 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001542 tcp->u_rval = -1;
1543 u_error = -eax;
1544 }
1545 else {
1546 tcp->u_rval = eax;
1547 u_error = 0;
1548 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001549# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001550 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001551 tcp->u_rval = -1;
1552 u_error = -rax;
1553 }
1554 else {
1555 tcp->u_rval = rax;
1556 u_error = 0;
1557 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001558# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001559 if (ia32) {
1560 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001561
Roland McGrathc1e45922008-05-27 23:18:29 +00001562 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001563 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001564 tcp->u_rval = -1;
1565 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001566 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001567 else {
1568 tcp->u_rval = err;
1569 u_error = 0;
1570 }
1571 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001572 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001573 tcp->u_rval = -1;
1574 u_error = r8;
1575 } else {
1576 tcp->u_rval = r8;
1577 u_error = 0;
1578 }
1579 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001580# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001581 if (check_errno && a3) {
1582 tcp->u_rval = -1;
1583 u_error = r2;
1584 } else {
1585 tcp->u_rval = r2;
1586 u_error = 0;
1587 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001588# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001589 if (check_errno && is_negated_errno(result)) {
1590 tcp->u_rval = -1;
1591 u_error = -result;
1592 }
1593 else {
1594 tcp->u_rval = result;
1595 u_error = 0;
1596 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001597# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001598 if (check_errno && is_negated_errno(d0)) {
1599 tcp->u_rval = -1;
1600 u_error = -d0;
1601 }
1602 else {
1603 tcp->u_rval = d0;
1604 u_error = 0;
1605 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001606# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001607 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1608 tcp->u_rval = -1;
1609 u_error = -regs.ARM_r0;
1610 }
1611 else {
1612 tcp->u_rval = regs.ARM_r0;
1613 u_error = 0;
1614 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001615# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001616 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1617 tcp->u_rval = -1;
1618 u_error = -regs.r12;
1619 }
1620 else {
1621 tcp->u_rval = regs.r12;
1622 u_error = 0;
1623 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001624# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001625 if (check_errno && is_negated_errno(r0)) {
1626 tcp->u_rval = -1;
1627 u_error = -r0;
1628 } else {
1629 tcp->u_rval = r0;
1630 u_error = 0;
1631 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001632# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001633 if (check_errno && a3) {
1634 tcp->u_rval = -1;
1635 u_error = r0;
1636 }
1637 else {
1638 tcp->u_rval = r0;
1639 u_error = 0;
1640 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001641# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001642 if (check_errno && regs.psr & PSR_C) {
1643 tcp->u_rval = -1;
1644 u_error = regs.u_regs[U_REG_O0];
1645 }
1646 else {
1647 tcp->u_rval = regs.u_regs[U_REG_O0];
1648 u_error = 0;
1649 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001650# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001651 if (check_errno && regs.tstate & 0x1100000000UL) {
1652 tcp->u_rval = -1;
1653 u_error = regs.u_regs[U_REG_O0];
1654 }
1655 else {
1656 tcp->u_rval = regs.u_regs[U_REG_O0];
1657 u_error = 0;
1658 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001659# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001660 if (check_errno && is_negated_errno(r28)) {
1661 tcp->u_rval = -1;
1662 u_error = -r28;
1663 }
1664 else {
1665 tcp->u_rval = r28;
1666 u_error = 0;
1667 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001668# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001669 /* interpret R0 as return value or error number */
1670 if (check_errno && is_negated_errno(r0)) {
1671 tcp->u_rval = -1;
1672 u_error = -r0;
1673 }
1674 else {
1675 tcp->u_rval = r0;
1676 u_error = 0;
1677 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001678# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001679 /* interpret result as return value or error number */
1680 if (check_errno && is_negated_errno(r9)) {
1681 tcp->u_rval = -1;
1682 u_error = -r9;
1683 }
1684 else {
1685 tcp->u_rval = r9;
1686 u_error = 0;
1687 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001688# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001689 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1690 tcp->u_rval = -1;
1691 u_error = -r10;
1692 }
1693 else {
1694 tcp->u_rval = r10;
1695 u_error = 0;
1696 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001697# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001698 long rval;
1699 /* interpret result as return value or error number */
1700 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1701 return -1;
1702 if (check_errno && rval < 0 && rval > -nerrnos) {
1703 tcp->u_rval = -1;
1704 u_error = -rval;
1705 }
1706 else {
1707 tcp->u_rval = rval;
1708 u_error = 0;
1709 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001710# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001711 /* interpret result as return value or error number */
1712 if (check_errno && is_negated_errno(r3)) {
1713 tcp->u_rval = -1;
1714 u_error = -r3;
1715 }
1716 else {
1717 tcp->u_rval = r3;
1718 u_error = 0;
1719 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001720# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001721#endif /* LINUX */
1722#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001723 /* get error code from user struct */
1724 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1725 return -1;
1726 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001728 /* get system call return value */
1729 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1730 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731#endif /* SUNOS4 */
1732#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001733# ifdef SPARC
1734 /* Judicious guessing goes a long way. */
1735 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1736 tcp->u_rval = -1;
1737 u_error = tcp->status.pr_reg[R_O0];
1738 }
1739 else {
1740 tcp->u_rval = tcp->status.pr_reg[R_O0];
1741 u_error = 0;
1742 }
1743# endif /* SPARC */
1744# ifdef I386
1745 /* Wanna know how to kill an hour single-stepping? */
1746 if (tcp->status.PR_REG[EFL] & 0x1) {
1747 tcp->u_rval = -1;
1748 u_error = tcp->status.PR_REG[EAX];
1749 }
1750 else {
1751 tcp->u_rval = tcp->status.PR_REG[EAX];
1752# ifdef HAVE_LONG_LONG
1753 tcp->u_lrval =
1754 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1755 tcp->status.PR_REG[EAX];
1756# endif
1757 u_error = 0;
1758 }
1759# endif /* I386 */
1760# ifdef X86_64
1761 /* Wanna know how to kill an hour single-stepping? */
1762 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1763 tcp->u_rval = -1;
1764 u_error = tcp->status.PR_REG[RAX];
1765 }
1766 else {
1767 tcp->u_rval = tcp->status.PR_REG[RAX];
1768 u_error = 0;
1769 }
1770# endif /* X86_64 */
1771# ifdef MIPS
1772 if (tcp->status.pr_reg[CTX_A3]) {
1773 tcp->u_rval = -1;
1774 u_error = tcp->status.pr_reg[CTX_V0];
1775 }
1776 else {
1777 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1778 u_error = 0;
1779 }
1780# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001781#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001782#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001783 if (regs.r_eflags & PSL_C) {
1784 tcp->u_rval = -1;
1785 u_error = regs.r_eax;
1786 } else {
1787 tcp->u_rval = regs.r_eax;
1788 tcp->u_lrval =
1789 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1790 u_error = 0;
1791 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001792#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001793 tcp->u_error = u_error;
1794 return 1;
1795}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001796
Roland McGrathb69f81b2002-12-21 23:25:18 +00001797int
Denys Vlasenko12014262011-05-30 14:00:14 +02001798force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001799{
1800#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001801# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001802 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001803 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1804 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001805# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001806 eax = error ? -error : rval;
1807 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1808 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001809# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001810 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001811 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001812 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001813# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001814 if (ia32) {
1815 r8 = error ? -error : rval;
1816 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1817 return -1;
1818 }
1819 else {
1820 if (error) {
1821 r8 = error;
1822 r10 = -1;
1823 }
1824 else {
1825 r8 = rval;
1826 r10 = 0;
1827 }
1828 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1829 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1830 return -1;
1831 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001832# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001833 r0 = error ? -error : rval;
1834 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1835 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001836# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001837 if (error) {
1838 r2 = error;
1839 a3 = -1;
1840 }
1841 else {
1842 r2 = rval;
1843 a3 = 0;
1844 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001845 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001846 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1847 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001848 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001849# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001850 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001851 return -1;
1852 if (error) {
1853 flags |= SO_MASK;
1854 result = error;
1855 }
1856 else {
1857 flags &= ~SO_MASK;
1858 result = rval;
1859 }
Roland McGratheb285352003-01-14 09:59:00 +00001860 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1861 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001862 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001863# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001864 d0 = error ? -error : rval;
1865 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1866 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001867# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001868 regs.ARM_r0 = error ? -error : rval;
1869 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001870 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001871# elif defined(AVR32)
1872 regs.r12 = error ? -error : rval;
1873 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1874 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001875# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001876 if (error) {
1877 a3 = -1;
1878 r0 = error;
1879 }
1880 else {
1881 a3 = 0;
1882 r0 = rval;
1883 }
1884 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1885 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1886 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001887# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001888 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1889 return -1;
1890 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001891 regs.psr |= PSR_C;
1892 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001893 }
1894 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001895 regs.psr &= ~PSR_C;
1896 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001897 }
1898 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1899 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001900# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001901 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1902 return -1;
1903 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001904 regs.tstate |= 0x1100000000UL;
1905 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001906 }
1907 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001908 regs.tstate &= ~0x1100000000UL;
1909 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001910 }
1911 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1912 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001913# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001914 r28 = error ? -error : rval;
1915 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1916 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001917# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001918 r0 = error ? -error : rval;
1919 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1920 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001921# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001922 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001923 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1924 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001925# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001926#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001927
Roland McGrathb69f81b2002-12-21 23:25:18 +00001928#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001929 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1930 error << 24) < 0 ||
1931 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001932 return -1;
1933#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001934
Roland McGrathb69f81b2002-12-21 23:25:18 +00001935#ifdef SVR4
1936 /* XXX no clue */
1937 return -1;
1938#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001939
Roland McGrathb69f81b2002-12-21 23:25:18 +00001940#ifdef FREEBSD
1941 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001942 perror("pread");
1943 return -1;
1944 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001945 if (error) {
1946 regs.r_eflags |= PSL_C;
1947 regs.r_eax = error;
1948 }
1949 else {
1950 regs.r_eflags &= ~PSL_C;
1951 regs.r_eax = rval;
1952 }
1953 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001954 perror("pwrite");
1955 return -1;
1956 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001957#endif /* FREEBSD */
1958
1959 /* All branches reach here on success (only). */
1960 tcp->u_error = error;
1961 tcp->u_rval = rval;
1962 return 0;
1963}
1964
Roland McGratha4d48532005-06-08 20:45:28 +00001965static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001966syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001967{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001968#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001969#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001970 {
1971 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001972 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1973 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001974 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001975 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001976 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001977 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001978 return -1;
1979 }
1980 }
1981#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001982 {
1983 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001984 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1985 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001986 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001987 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001988 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001989 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1990 * for scno somewhere above here!
1991 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001992 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001993 return -1;
1994 }
1995 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001996#elif defined (IA64)
1997 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001998 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001999 unsigned long *out0, cfm, sof, sol, i;
2000 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002001 /* be backwards compatible with kernel < 2.4.4... */
2002# ifndef PT_RBS_END
2003# define PT_RBS_END PT_AR_BSP
2004# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002005
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002006 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002007 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002008 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002009 return -1;
2010
2011 sof = (cfm >> 0) & 0x7f;
2012 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002013 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002014
2015 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2016 && sysent[tcp->scno].nargs != -1)
2017 tcp->u_nargs = sysent[tcp->scno].nargs;
2018 else
2019 tcp->u_nargs = MAX_ARGS;
2020 for (i = 0; i < tcp->u_nargs; ++i) {
2021 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2022 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2023 return -1;
2024 }
2025 } else {
2026 int i;
2027
2028 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002029 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002030 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002031 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002032 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002033 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002034 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002035 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002036 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002037 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002038 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002039 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002040 return -1;
2041
2042 for (i = 0; i < 6; ++i)
2043 /* truncate away IVE sign-extension */
2044 tcp->u_arg[i] &= 0xffffffff;
2045
2046 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2047 && sysent[tcp->scno].nargs != -1)
2048 tcp->u_nargs = sysent[tcp->scno].nargs;
2049 else
2050 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002051 }
2052 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002053#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2054 /* N32 and N64 both use up to six registers. */
2055 {
2056 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002057 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002058
2059 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2060 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002061 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002062 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002063
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002064 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002065 return -1;
2066
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002067 for (i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002068 tcp->u_arg[i] = regs[REG_A0 + i];
2069# if defined (LINUX_MIPSN32)
2070 tcp->ext_arg[i] = regs[REG_A0 + i];
2071# endif
2072 }
2073 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002074#elif defined (MIPS)
2075 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002076 long sp;
2077 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002078
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002079 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2080 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002081 else
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002082 nargs = tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002083 if (nargs > 4) {
2084 if (upeek(tcp, REG_SP, &sp) < 0)
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002085 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002086 for (i = 0; i < 4; i++) {
2087 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002088 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002089 }
2090 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2091 (char *)(tcp->u_arg + 4));
2092 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002093 for (i = 0; i < nargs; i++) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002094 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2095 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002096 }
2097 }
2098 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002099#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002100# ifndef PT_ORIG_R3
2101# define PT_ORIG_R3 34
2102# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002103 {
2104 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002105 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++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002110 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002111 (sizeof(unsigned long)*PT_ORIG_R3) :
2112 ((i+PT_R3)*sizeof(unsigned long)),
2113 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002114 return -1;
2115 }
2116 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002117#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002118 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002119 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002120
2121 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2122 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002123 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002124 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002125 for (i = 0; i < tcp->u_nargs; i++)
Mike Frysinger8566c502009-10-12 11:05:14 -04002126 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002127 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002128#elif defined (HPPA)
2129 {
2130 int i;
2131
2132 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2133 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002134 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002135 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002136 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002137 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002138 return -1;
2139 }
2140 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002141#elif defined(ARM)
2142 {
2143 int i;
2144
2145 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2146 tcp->u_nargs = sysent[tcp->scno].nargs;
2147 else
2148 tcp->u_nargs = MAX_ARGS;
2149 for (i = 0; i < tcp->u_nargs; i++)
2150 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002151 }
2152#elif defined(AVR32)
2153 tcp->u_nargs = sysent[tcp->scno].nargs;
2154 tcp->u_arg[0] = regs.r12;
2155 tcp->u_arg[1] = regs.r11;
2156 tcp->u_arg[2] = regs.r10;
2157 tcp->u_arg[3] = regs.r9;
2158 tcp->u_arg[4] = regs.r5;
2159 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002160#elif defined(BFIN)
2161 {
2162 int i;
2163 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2164
2165 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2166 tcp->u_nargs = sysent[tcp->scno].nargs;
2167 else
2168 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2169
2170 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002171 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002172 return -1;
2173 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002174#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002175 {
2176 int i;
2177 static int syscall_regs[] = {
2178 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2179 REG_REG0, REG_REG0+1, REG_REG0+2
2180 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002181
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002182 tcp->u_nargs = sysent[tcp->scno].nargs;
2183 for (i = 0; i < tcp->u_nargs; i++) {
2184 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2185 return -1;
2186 }
2187 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002188#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002189 {
2190 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002191 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002192 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2193
2194 /*
2195 * TODO: should also check that the number of arguments encoded
2196 * in the trap number matches the number strace expects.
2197 */
2198 /*
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002199 assert(sysent[tcp->scno].nargs <
2200 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
Roland McGrathe1e584b2003-06-02 19:18:58 +00002201 */
2202
2203 tcp->u_nargs = sysent[tcp->scno].nargs;
2204 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002205 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002206 return -1;
2207 }
2208 }
2209
Michal Ludvig0e035502002-09-23 15:41:01 +00002210#elif defined(X86_64)
2211 {
2212 int i;
2213 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2214 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002215 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002216 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002217
Michal Ludvig0e035502002-09-23 15:41:01 +00002218 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2219 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002220 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002221 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002222 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002223 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002224 return -1;
2225 }
2226 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002227#elif defined(MICROBLAZE)
2228 {
2229 int i;
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++) {
2235 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2236 return -1;
2237 }
2238 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002239#elif defined(CRISV10) || defined(CRISV32)
2240 {
2241 int i;
2242 static const int crisregs[] = {
2243 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2244 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2245 };
2246
2247 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2248 tcp->u_nargs = sysent[tcp->scno].nargs;
2249 else
2250 tcp->u_nargs = 0;
2251 for (i = 0; i < tcp->u_nargs; i++) {
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00002252 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002253 return -1;
2254 }
2255 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05002256#elif defined(TILE)
2257 {
2258 int i;
2259 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2260 tcp->u_nargs = sysent[tcp->scno].nargs;
2261 else
2262 tcp->u_nargs = MAX_ARGS;
2263 for (i = 0; i < tcp->u_nargs; ++i) {
2264 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2265 return -1;
2266 }
2267 }
Andreas Schwab246888d2010-06-05 21:50:30 +02002268#elif defined (M68K)
2269 {
2270 int i;
2271 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2272 tcp->u_nargs = sysent[tcp->scno].nargs;
2273 else
2274 tcp->u_nargs = MAX_ARGS;
2275 for (i = 0; i < tcp->u_nargs; i++) {
2276 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2277 return -1;
2278 }
2279 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002280#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002281 {
2282 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002283 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2284 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002285 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002286 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002287 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002288 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002289 return -1;
2290 }
2291 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002292#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293#endif /* LINUX */
2294#ifdef SUNOS4
2295 {
2296 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002297 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2298 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002299 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002300 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002301 for (i = 0; i < tcp->u_nargs; i++) {
2302 struct user *u;
2303
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002304 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002305 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2306 return -1;
2307 }
2308 }
2309#endif /* SUNOS4 */
2310#ifdef SVR4
2311#ifdef MIPS
2312 /*
2313 * SGI is broken: even though it has pr_sysarg, it doesn't
2314 * set them on system call entry. Get a clue.
2315 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002316 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002317 tcp->u_nargs = sysent[tcp->scno].nargs;
2318 else
2319 tcp->u_nargs = tcp->status.pr_nsysarg;
2320 if (tcp->u_nargs > 4) {
2321 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2322 4*sizeof(tcp->u_arg[0]));
2323 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2324 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2325 }
2326 else {
2327 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2328 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2329 }
John Hughes25299712001-03-06 10:10:06 +00002330#elif UNIXWARE >= 2
2331 /*
2332 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2333 */
2334 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2335 tcp->u_nargs = sysent[tcp->scno].nargs;
2336 else
2337 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2338 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2339 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2340#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002341 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002342 tcp->u_nargs = sysent[tcp->scno].nargs;
2343 else
2344 tcp->u_nargs = tcp->status.pr_nsysarg;
2345 {
2346 int i;
2347 for (i = 0; i < tcp->u_nargs; i++)
2348 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2349 }
John Hughes25299712001-03-06 10:10:06 +00002350#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002351 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002352 tcp->u_nargs = sysent[tcp->scno].nargs;
2353 else
2354 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002355 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002356 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002357#else
2358 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002359#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002360#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002361#ifdef FREEBSD
2362 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2363 sysent[tcp->scno].nargs > tcp->status.val)
2364 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002365 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002366 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002367 if (tcp->u_nargs < 0)
2368 tcp->u_nargs = 0;
2369 if (tcp->u_nargs > MAX_ARGS)
2370 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002371 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002372 case SYS___syscall:
2373 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2374 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002375 break;
2376 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002377 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2378 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002379 break;
2380 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002381 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2382 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002383 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002384 }
2385#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002386 return 1;
2387}
2388
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002389static int
2390trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002391{
2392 int sys_res;
2393 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002394 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002395 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002396
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002397 /* Measure the exit time as early as possible to avoid errors. */
2398 if (dtime || cflag)
2399 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002400
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002401 /* BTW, why we don't just memorize syscall no. on entry
2402 * in tcp->something?
2403 */
2404 scno_good = res = get_scno(tcp);
2405 if (res == 0)
2406 return res;
2407 if (res == 1)
2408 res = syscall_fixup(tcp);
2409 if (res == 0)
2410 return res;
2411 if (res == 1)
2412 res = get_error(tcp);
2413 if (res == 0)
2414 return res;
2415 if (res == 1)
2416 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002417
Grant Edwards8a082772011-04-07 20:25:40 +00002418 if (res == 1 && filtered(tcp)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002419 tcp->flags &= ~TCB_INSYSCALL;
2420 return 0;
2421 }
2422
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002423 if (tcp->flags & TCB_REPRINT) {
2424 printleader(tcp);
2425 tprintf("<... ");
2426 if (scno_good != 1)
2427 tprintf("????");
2428 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2429 tprintf("syscall_%lu", tcp->scno);
2430 else
2431 tprintf("%s", sysent[tcp->scno].sys_name);
2432 tprintf(" resumed> ");
2433 }
2434
2435 if (cflag) {
2436 struct timeval t = tv;
2437 int rc = count_syscall(tcp, &t);
2438 if (cflag == CFLAG_ONLY_STATS)
2439 {
2440 tcp->flags &= ~TCB_INSYSCALL;
2441 return rc;
2442 }
2443 }
2444
2445 if (res != 1) {
2446 tprintf(") ");
2447 tabto(acolumn);
2448 tprintf("= ? <unavailable>");
2449 printtrailer();
2450 tcp->flags &= ~TCB_INSYSCALL;
2451 return res;
2452 }
2453
2454 if (tcp->scno >= nsyscalls || tcp->scno < 0
2455 || (qual_flags[tcp->scno] & QUAL_RAW))
2456 sys_res = printargs(tcp);
2457 else {
2458 if (not_failing_only && tcp->u_error)
2459 return 0; /* ignore failed syscalls */
2460 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2461 }
2462
2463 u_error = tcp->u_error;
2464 tprintf(") ");
2465 tabto(acolumn);
2466 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2467 qual_flags[tcp->scno] & QUAL_RAW) {
2468 if (u_error)
2469 tprintf("= -1 (errno %ld)", u_error);
2470 else
2471 tprintf("= %#lx", tcp->u_rval);
2472 }
2473 else if (!(sys_res & RVAL_NONE) && u_error) {
2474 switch (u_error) {
2475#ifdef LINUX
2476 case ERESTARTSYS:
2477 tprintf("= ? ERESTARTSYS (To be restarted)");
2478 break;
2479 case ERESTARTNOINTR:
2480 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2481 break;
2482 case ERESTARTNOHAND:
2483 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2484 break;
2485 case ERESTART_RESTARTBLOCK:
2486 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2487 break;
2488#endif /* LINUX */
2489 default:
2490 tprintf("= -1 ");
2491 if (u_error < 0)
2492 tprintf("E??? (errno %ld)", u_error);
2493 else if (u_error < nerrnos)
2494 tprintf("%s (%s)", errnoent[u_error],
2495 strerror(u_error));
2496 else
2497 tprintf("ERRNO_%ld (%s)", u_error,
2498 strerror(u_error));
2499 break;
2500 }
2501 if ((sys_res & RVAL_STR) && tcp->auxstr)
2502 tprintf(" (%s)", tcp->auxstr);
2503 }
2504 else {
2505 if (sys_res & RVAL_NONE)
2506 tprintf("= ?");
2507 else {
2508 switch (sys_res & RVAL_MASK) {
2509 case RVAL_HEX:
2510 tprintf("= %#lx", tcp->u_rval);
2511 break;
2512 case RVAL_OCTAL:
2513 tprintf("= %#lo", tcp->u_rval);
2514 break;
2515 case RVAL_UDECIMAL:
2516 tprintf("= %lu", tcp->u_rval);
2517 break;
2518 case RVAL_DECIMAL:
2519 tprintf("= %ld", tcp->u_rval);
2520 break;
2521#ifdef HAVE_LONG_LONG
2522 case RVAL_LHEX:
2523 tprintf("= %#llx", tcp->u_lrval);
2524 break;
2525 case RVAL_LOCTAL:
2526 tprintf("= %#llo", tcp->u_lrval);
2527 break;
2528 case RVAL_LUDECIMAL:
2529 tprintf("= %llu", tcp->u_lrval);
2530 break;
2531 case RVAL_LDECIMAL:
2532 tprintf("= %lld", tcp->u_lrval);
2533 break;
2534#endif
2535 default:
2536 fprintf(stderr,
2537 "invalid rval format\n");
2538 break;
2539 }
2540 }
2541 if ((sys_res & RVAL_STR) && tcp->auxstr)
2542 tprintf(" (%s)", tcp->auxstr);
2543 }
2544 if (dtime) {
2545 tv_sub(&tv, &tv, &tcp->etime);
2546 tprintf(" <%ld.%06ld>",
2547 (long) tv.tv_sec, (long) tv.tv_usec);
2548 }
2549 printtrailer();
2550
2551 dumpio(tcp);
2552 if (fflush(tcp->outf) == EOF)
2553 return -1;
2554 tcp->flags &= ~TCB_INSYSCALL;
2555 return 0;
2556}
2557
2558static int
2559trace_syscall_entering(struct tcb *tcp)
2560{
2561 int sys_res;
2562 int res, scno_good;
2563
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002564 scno_good = res = get_scno(tcp);
2565 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002566 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002567 if (res == 1)
2568 res = syscall_fixup(tcp);
2569 if (res == 0)
2570 return res;
2571 if (res == 1)
2572 res = syscall_enter(tcp);
2573 if (res == 0)
2574 return res;
2575
2576 if (res != 1) {
2577 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002578 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002579 tcp_last = tcp;
2580 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002581 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002582 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2583 tprintf("syscall_%lu(", tcp->scno);
2584 else
2585 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002586 /*
2587 * " <unavailable>" will be added later by the code which
2588 * detects ptrace errors.
2589 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002590 tcp->flags |= TCB_INSYSCALL;
2591 return res;
2592 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002593
Roland McGrath17352792005-06-07 23:21:26 +00002594 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002595#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002596 case SYS_socketcall:
2597 decode_subcall(tcp, SYS_socket_subcall,
2598 SYS_socket_nsubcalls, deref_style);
2599 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002600#endif
2601#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002602 case SYS_ipc:
2603 decode_subcall(tcp, SYS_ipc_subcall,
2604 SYS_ipc_nsubcalls, shift_style);
2605 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002606#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002607#ifdef SVR4
2608#ifdef SYS_pgrpsys_subcall
2609 case SYS_pgrpsys:
2610 decode_subcall(tcp, SYS_pgrpsys_subcall,
2611 SYS_pgrpsys_nsubcalls, shift_style);
2612 break;
2613#endif /* SYS_pgrpsys_subcall */
2614#ifdef SYS_sigcall_subcall
2615 case SYS_sigcall:
2616 decode_subcall(tcp, SYS_sigcall_subcall,
2617 SYS_sigcall_nsubcalls, mask_style);
2618 break;
2619#endif /* SYS_sigcall_subcall */
2620 case SYS_msgsys:
2621 decode_subcall(tcp, SYS_msgsys_subcall,
2622 SYS_msgsys_nsubcalls, shift_style);
2623 break;
2624 case SYS_shmsys:
2625 decode_subcall(tcp, SYS_shmsys_subcall,
2626 SYS_shmsys_nsubcalls, shift_style);
2627 break;
2628 case SYS_semsys:
2629 decode_subcall(tcp, SYS_semsys_subcall,
2630 SYS_semsys_nsubcalls, shift_style);
2631 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002632 case SYS_sysfs:
2633 decode_subcall(tcp, SYS_sysfs_subcall,
2634 SYS_sysfs_nsubcalls, shift_style);
2635 break;
2636 case SYS_spcall:
2637 decode_subcall(tcp, SYS_spcall_subcall,
2638 SYS_spcall_nsubcalls, shift_style);
2639 break;
2640#ifdef SYS_context_subcall
2641 case SYS_context:
2642 decode_subcall(tcp, SYS_context_subcall,
2643 SYS_context_nsubcalls, shift_style);
2644 break;
2645#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002646#ifdef SYS_door_subcall
2647 case SYS_door:
2648 decode_subcall(tcp, SYS_door_subcall,
2649 SYS_door_nsubcalls, door_style);
2650 break;
2651#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002652#ifdef SYS_kaio_subcall
2653 case SYS_kaio:
2654 decode_subcall(tcp, SYS_kaio_subcall,
2655 SYS_kaio_nsubcalls, shift_style);
2656 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002657#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002658#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002659#ifdef FREEBSD
2660 case SYS_msgsys:
2661 case SYS_shmsys:
2662 case SYS_semsys:
2663 decode_subcall(tcp, 0, 0, table_style);
2664 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002665#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002666#ifdef SUNOS4
2667 case SYS_semsys:
2668 decode_subcall(tcp, SYS_semsys_subcall,
2669 SYS_semsys_nsubcalls, shift_style);
2670 break;
2671 case SYS_msgsys:
2672 decode_subcall(tcp, SYS_msgsys_subcall,
2673 SYS_msgsys_nsubcalls, shift_style);
2674 break;
2675 case SYS_shmsys:
2676 decode_subcall(tcp, SYS_shmsys_subcall,
2677 SYS_shmsys_nsubcalls, shift_style);
2678 break;
2679#endif
2680 }
2681
2682 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002683
2684 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2685 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2686 (tracing_paths && !pathtrace_match(tcp))) {
2687 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002688 return 0;
2689 }
2690
Grant Edwards8a082772011-04-07 20:25:40 +00002691 tcp->flags &= ~TCB_FILTERED;
2692
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002693 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002695 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002696 return 0;
2697 }
2698
2699 printleader(tcp);
2700 tcp->flags &= ~TCB_REPRINT;
2701 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002702 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002703 tprintf("syscall_%lu(", tcp->scno);
2704 else
2705 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002706 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002707 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2708 sysent[tcp->scno].sys_func != sys_exit))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002709 sys_res = printargs(tcp);
2710 else
2711 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2712 if (fflush(tcp->outf) == EOF)
2713 return -1;
2714 tcp->flags |= TCB_INSYSCALL;
2715 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002716 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002717 gettimeofday(&tcp->etime, NULL);
2718 return sys_res;
2719}
2720
2721int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002722trace_syscall(struct tcb *tcp)
2723{
2724 return exiting(tcp) ?
2725 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2726}
2727
2728int
Denys Vlasenko12014262011-05-30 14:00:14 +02002729printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002730{
2731 if (entering(tcp)) {
2732 int i;
2733
2734 for (i = 0; i < tcp->u_nargs; i++)
2735 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2736 }
2737 return 0;
2738}
2739
2740long
Denys Vlasenko12014262011-05-30 14:00:14 +02002741getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002742{
2743 long val = -1;
2744
2745#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002746#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002747 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002748 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002749 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002750 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002751#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002752 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002753 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002754#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002755 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002756 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002757#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002758#endif /* LINUX */
2759
2760#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002761 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002762 return -1;
2763#endif /* SUNOS4 */
2764
2765#ifdef SVR4
2766#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002767 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002768#endif /* SPARC */
2769#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002770 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002771#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002772#ifdef X86_64
2773 val = tcp->status.PR_REG[RDX];
2774#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002775#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002776 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002777#endif /* MIPS */
2778#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002779
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002780#ifdef FREEBSD
2781 struct reg regs;
2782 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2783 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002784#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002785 return val;
2786}
2787
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002788#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002789/*
2790 * Apparently, indirect system calls have already be converted by ptrace(2),
2791 * so if you see "indir" this program has gone astray.
2792 */
2793int
Denys Vlasenko12014262011-05-30 14:00:14 +02002794sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002795{
2796 int i, scno, nargs;
2797
2798 if (entering(tcp)) {
2799 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2800 fprintf(stderr, "Bogus syscall: %u\n", scno);
2801 return 0;
2802 }
2803 nargs = sysent[scno].nargs;
2804 tprintf("%s", sysent[scno].sys_name);
2805 for (i = 0; i < nargs; i++)
2806 tprintf(", %#lx", tcp->u_arg[i+1]);
2807 }
2808 return 0;
2809}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002810#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002811
2812int
2813is_restart_error(struct tcb *tcp)
2814{
2815#ifdef LINUX
2816 if (!syserror(tcp))
2817 return 0;
2818 switch (tcp->u_error) {
2819 case ERESTARTSYS:
2820 case ERESTARTNOINTR:
2821 case ERESTARTNOHAND:
2822 case ERESTART_RESTARTBLOCK:
2823 return 1;
2824 default:
2825 break;
2826 }
2827#endif /* LINUX */
2828 return 0;
2829}