blob: f3f6d0e55689ec2e202a4140e49e6276174f0eee [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
112
Roland McGrathee36ce12004-09-04 03:53:10 +0000113static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000114#include "syscallent.h"
115};
Roland McGrathee36ce12004-09-04 03:53:10 +0000116static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000117int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118
119#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000120static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000121#include "syscallent1.h"
122};
Roland McGrathee36ce12004-09-04 03:53:10 +0000123static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000124int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000125#endif /* SUPPORTED_PERSONALITIES >= 2 */
126
127#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent2.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000132int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133#endif /* SUPPORTED_PERSONALITIES >= 3 */
134
Roland McGrathee36ce12004-09-04 03:53:10 +0000135const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000136int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000137int nsyscalls;
138
139/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000140#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000141#undef TF
142#undef TI
143#undef TN
144#undef TP
145#undef TS
146
Roland McGrathee36ce12004-09-04 03:53:10 +0000147static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148#include "errnoent.h"
149};
Roland McGrathee36ce12004-09-04 03:53:10 +0000150static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000151
152#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000153static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000154#include "errnoent1.h"
155};
Roland McGrathee36ce12004-09-04 03:53:10 +0000156static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000157#endif /* SUPPORTED_PERSONALITIES >= 2 */
158
159#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000160static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000161#include "errnoent2.h"
162};
Roland McGrathee36ce12004-09-04 03:53:10 +0000163static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000164#endif /* SUPPORTED_PERSONALITIES >= 3 */
165
Roland McGrathee36ce12004-09-04 03:53:10 +0000166const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167int nerrnos;
168
169int current_personality;
170
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000171#ifndef PERSONALITY0_WORDSIZE
172# define PERSONALITY0_WORDSIZE sizeof(long)
173#endif
174const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
175 PERSONALITY0_WORDSIZE,
176#if SUPPORTED_PERSONALITIES > 1
177 PERSONALITY1_WORDSIZE,
178#endif
179#if SUPPORTED_PERSONALITIES > 2
180 PERSONALITY2_WORDSIZE,
181#endif
182};;
183
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000185set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000186{
187 switch (personality) {
188 case 0:
189 errnoent = errnoent0;
190 nerrnos = nerrnos0;
191 sysent = sysent0;
192 nsyscalls = nsyscalls0;
193 ioctlent = ioctlent0;
194 nioctlents = nioctlents0;
195 signalent = signalent0;
196 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000197 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000198 break;
199
200#if SUPPORTED_PERSONALITIES >= 2
201 case 1:
202 errnoent = errnoent1;
203 nerrnos = nerrnos1;
204 sysent = sysent1;
205 nsyscalls = nsyscalls1;
206 ioctlent = ioctlent1;
207 nioctlents = nioctlents1;
208 signalent = signalent1;
209 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000210 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000211 break;
212#endif /* SUPPORTED_PERSONALITIES >= 2 */
213
214#if SUPPORTED_PERSONALITIES >= 3
215 case 2:
216 errnoent = errnoent2;
217 nerrnos = nerrnos2;
218 sysent = sysent2;
219 nsyscalls = nsyscalls2;
220 ioctlent = ioctlent2;
221 nioctlents = nioctlents2;
222 signalent = signalent2;
223 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000224 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000225 break;
226#endif /* SUPPORTED_PERSONALITIES >= 3 */
227
228 default:
229 return -1;
230 }
231
232 current_personality = personality;
233 return 0;
234}
235
Roland McGrathe10e62a2004-09-04 04:20:43 +0000236
Roland McGrath9797ceb2002-12-30 10:23:00 +0000237static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000238
Roland McGrathe10e62a2004-09-04 04:20:43 +0000239static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000241 const char *option_name;
242 int (*qualify)(const char *, const struct qual_options *, int);
243 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000244} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000245 { QUAL_TRACE, "trace", qual_syscall, "system call" },
246 { QUAL_TRACE, "t", qual_syscall, "system call" },
247 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
248 { QUAL_ABBREV, "a", qual_syscall, "system call" },
249 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
250 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
251 { QUAL_RAW, "raw", qual_syscall, "system call" },
252 { QUAL_RAW, "x", qual_syscall, "system call" },
253 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
254 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
255 { QUAL_SIGNAL, "s", qual_signal, "signal" },
256 { QUAL_FAULT, "fault", qual_fault, "fault" },
257 { QUAL_FAULT, "faults", qual_fault, "fault" },
258 { QUAL_FAULT, "m", qual_fault, "fault" },
259 { QUAL_READ, "read", qual_desc, "descriptor" },
260 { QUAL_READ, "reads", qual_desc, "descriptor" },
261 { QUAL_READ, "r", qual_desc, "descriptor" },
262 { QUAL_WRITE, "write", qual_desc, "descriptor" },
263 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
264 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000265 { 0, NULL, NULL, NULL },
266};
267
Roland McGrath9797ceb2002-12-30 10:23:00 +0000268static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000269qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000270 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000271 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000272 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000273 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000274{
Roland McGrath138c6a32006-01-12 09:50:49 +0000275 if (pers == 0 || pers < 0) {
276 if (not)
277 qual_flags0[n] &= ~opt->bitflag;
278 else
279 qual_flags0[n] |= opt->bitflag;
280 }
281
282#if SUPPORTED_PERSONALITIES >= 2
283 if (pers == 1 || pers < 0) {
284 if (not)
285 qual_flags1[n] &= ~opt->bitflag;
286 else
287 qual_flags1[n] |= opt->bitflag;
288 }
289#endif /* SUPPORTED_PERSONALITIES >= 2 */
290
291#if SUPPORTED_PERSONALITIES >= 3
292 if (pers == 2 || pers < 0) {
293 if (not)
294 qual_flags2[n] &= ~opt->bitflag;
295 else
296 qual_flags2[n] |= opt->bitflag;
297 }
298#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299}
300
301static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000302qual_syscall(const char *s, const struct qual_options *opt, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000303{
304 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000305 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000306
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000307 if (isdigit((unsigned char)*s)) {
308 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000309 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000310 return -1;
311 qualify_one(i, opt, not, -1);
312 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000313 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000314 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000315 if (strcmp(s, sysent0[i].sys_name) == 0) {
316 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000317 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000318 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000319
320#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000321 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000322 if (strcmp(s, sysent1[i].sys_name) == 0) {
323 qualify_one(i, opt, not, 1);
324 rc = 0;
325 }
326#endif /* SUPPORTED_PERSONALITIES >= 2 */
327
328#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000329 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000330 if (strcmp(s, sysent2[i].sys_name) == 0) {
331 qualify_one(i, opt, not, 2);
332 rc = 0;
333 }
334#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000335
Roland McGrathfe6b3522005-02-02 04:40:11 +0000336 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000337}
338
339static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000340qual_signal(const char *s, const struct qual_options *opt, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000341{
342 int i;
343 char buf[32];
344
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000345 if (isdigit((unsigned char)*s)) {
346 int signo = atoi(s);
347 if (signo < 0 || signo >= MAX_QUALS)
348 return -1;
349 qualify_one(signo, opt, not, -1);
350 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000351 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000352 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000353 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000354 strcpy(buf, s);
355 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000356 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000357 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000358 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000359 if (strcasecmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000360 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000361 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000362 }
Roland McGrath76421df2005-02-02 03:51:18 +0000363 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000364}
365
366static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000367qual_fault(const char *s, const struct qual_options *opt, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000368{
369 return -1;
370}
371
372static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000373qual_desc(const char *s, const struct qual_options *opt, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000374{
Roland McGrath48a035f2006-01-12 09:45:56 +0000375 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000376 int desc = atoi(s);
377 if (desc < 0 || desc >= MAX_QUALS)
378 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000379 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000380 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000381 }
382 return -1;
383}
384
385static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000386lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000387{
388 if (strcmp(s, "file") == 0)
389 return TRACE_FILE;
390 if (strcmp(s, "ipc") == 0)
391 return TRACE_IPC;
392 if (strcmp(s, "network") == 0)
393 return TRACE_NETWORK;
394 if (strcmp(s, "process") == 0)
395 return TRACE_PROCESS;
396 if (strcmp(s, "signal") == 0)
397 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000398 if (strcmp(s, "desc") == 0)
399 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000400 return -1;
401}
402
403void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000404qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000405{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000406 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000407 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000408 char *copy;
409 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 int i, n;
411
412 opt = &qual_options[0];
413 for (i = 0; (p = qual_options[i].option_name); i++) {
414 n = strlen(p);
415 if (strncmp(s, p, n) == 0 && s[n] == '=') {
416 opt = &qual_options[i];
417 s += n + 1;
418 break;
419 }
420 }
421 not = 0;
422 if (*s == '!') {
423 not = 1;
424 s++;
425 }
426 if (strcmp(s, "none") == 0) {
427 not = 1 - not;
428 s = "all";
429 }
430 if (strcmp(s, "all") == 0) {
431 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000432 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000433 }
434 return;
435 }
436 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000437 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000439 if (!strchr(s, ','))
440 return;
441 if (!(copy = strdup(s))) {
442 fprintf(stderr, "out of memory\n");
443 exit(1);
444 }
445 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000446 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000447 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000448 if (sysent0[i].sys_flags & n)
449 qualify_one(i, opt, not, 0);
450
451#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000452 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000453 if (sysent1[i].sys_flags & n)
454 qualify_one(i, opt, not, 1);
455#endif /* SUPPORTED_PERSONALITIES >= 2 */
456
457#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000458 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000459 if (sysent2[i].sys_flags & n)
460 qualify_one(i, opt, not, 2);
461#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000462
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 continue;
464 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000465 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000466 fprintf(stderr, "strace: invalid %s `%s'\n",
467 opt->argument_name, p);
468 exit(1);
469 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000470 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000471 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000472 return;
473}
474
475static void
476dumpio(tcp)
477struct tcb *tcp;
478{
479 if (syserror(tcp))
480 return;
481 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
482 return;
Roland McGrath17352792005-06-07 23:21:26 +0000483 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000484 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000485#ifdef SYS_pread64
486 case SYS_pread64:
487#endif
488#if defined SYS_pread && SYS_pread64 != SYS_pread
489 case SYS_pread:
490#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000491#ifdef SYS_recv
492 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000493#elif defined SYS_sub_recv
494 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000495#endif
496#ifdef SYS_recvfrom
497 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000498#elif defined SYS_sub_recvfrom
499 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000500#endif
501 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
502 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
503 break;
504 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000505#ifdef SYS_pwrite64
506 case SYS_pwrite64:
507#endif
508#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
509 case SYS_pwrite:
510#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000511#ifdef SYS_send
512 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000513#elif defined SYS_sub_send
514 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000515#endif
516#ifdef SYS_sendto
517 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000518#elif defined SYS_sub_sendto
519 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000520#endif
521 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
522 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
523 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000524#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000525 case SYS_readv:
526 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
527 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
528 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000529#endif
530#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000531 case SYS_writev:
532 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
533 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
534 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000535#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536 }
537}
538
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000539#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000540enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000541#else /* FREEBSD */
542enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
543
544struct subcall {
545 int call;
546 int nsubcalls;
547 int subcalls[5];
548};
549
Roland McGratha4d48532005-06-08 20:45:28 +0000550static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000551 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000552#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000553 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000554#else
555 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
556#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000557 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
558};
559#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000561#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000562
Roland McGratha4d48532005-06-08 20:45:28 +0000563static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000564decode_subcall(tcp, subcall, nsubcalls, style)
565struct tcb *tcp;
566int subcall;
567int nsubcalls;
568enum subcall_style style;
569{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000570 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000571 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000572 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000573
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000574 switch (style) {
575 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000576 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
577 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000578 tcp->scno = subcall + tcp->u_arg[0];
579 if (sysent[tcp->scno].nargs != -1)
580 tcp->u_nargs = sysent[tcp->scno].nargs;
581 else
582 tcp->u_nargs--;
583 for (i = 0; i < tcp->u_nargs; i++)
584 tcp->u_arg[i] = tcp->u_arg[i + 1];
585 break;
586 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000587 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
588 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 tcp->scno = subcall + tcp->u_arg[0];
590 addr = tcp->u_arg[1];
591 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000592 if (size == sizeof(int)) {
593 unsigned int arg;
594 if (umove(tcp, addr, &arg) < 0)
595 arg = 0;
596 tcp->u_arg[i] = arg;
597 }
598 else if (size == sizeof(long)) {
599 unsigned long arg;
600 if (umove(tcp, addr, &arg) < 0)
601 arg = 0;
602 tcp->u_arg[i] = arg;
603 }
604 else
605 abort();
606 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 }
608 tcp->u_nargs = sysent[tcp->scno].nargs;
609 break;
610 case mask_style:
611 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 for (i = 0; mask; i++)
613 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000614 if (i >= nsubcalls)
615 return;
616 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617 tcp->scno = subcall + i;
618 if (sysent[tcp->scno].nargs != -1)
619 tcp->u_nargs = sysent[tcp->scno].nargs;
620 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000621 case door_style:
622 /*
623 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000624 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000625 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000626 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
627 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000628 tcp->scno = subcall + tcp->u_arg[5];
629 if (sysent[tcp->scno].nargs != -1)
630 tcp->u_nargs = sysent[tcp->scno].nargs;
631 else
632 tcp->u_nargs--;
633 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000634#ifdef FREEBSD
635 case table_style:
636 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
637 if (subcalls_table[i].call == tcp->scno) break;
638 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
639 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
640 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
641 for (i = 0; i < tcp->u_nargs; i++)
642 tcp->u_arg[i] = tcp->u_arg[i + 1];
643 }
644 break;
645#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000646 }
647}
648#endif
649
650struct tcb *tcp_last = NULL;
651
652static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000653internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000654{
655 /*
656 * We must always trace a few critical system calls in order to
657 * correctly support following forks in the presence of tracing
658 * qualifiers.
659 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000660 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000662 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
663 return 0;
664
665 func = sysent[tcp->scno].sys_func;
666
667 if (sys_exit == func)
668 return internal_exit(tcp);
669
670 if ( sys_fork == func
671#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
672 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000673#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000674#ifdef LINUX
675 || sys_clone == func
676#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000677#if UNIXWARE > 2
678 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000679#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000680 )
681 return internal_fork(tcp);
682
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683 if ( sys_execve == func
684#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
685 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000686#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000687#if UNIXWARE > 2
688 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000689#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000690 )
691 return internal_exec(tcp);
692
693 if ( sys_waitpid == func
694 || sys_wait4 == func
695#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
696 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000697#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000698#ifdef ALPHA
699 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000700#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000701 )
702 return internal_wait(tcp, 2);
703
704#if defined(LINUX) || defined(SVR4)
705 if (sys_waitid == func)
706 return internal_wait(tcp, 3);
707#endif
708
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000709 return 0;
710}
711
Wichert Akkermanc7926982000-04-10 22:22:31 +0000712
713#ifdef LINUX
714#if defined (I386)
715 static long eax;
716#elif defined (IA64)
717 long r8, r10, psr;
718 long ia32 = 0;
719#elif defined (POWERPC)
720 static long result,flags;
721#elif defined (M68K)
Andreas Schwabffca9e32010-05-28 20:53:14 +0200722 static long d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000723#elif defined(BFIN)
724 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000725#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000726 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000727#elif defined (ALPHA)
728 static long r0;
729 static long a3;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000730#elif defined(AVR32)
731 static struct pt_regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000732#elif defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -0400733 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000734 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000735#elif defined(LINUX_MIPSN32)
736 static long long a3;
737 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000738#elif defined(MIPS)
739 static long a3;
740 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000741#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000742 static long gpr2;
743 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000744 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000745#elif defined(HPPA)
746 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000747#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000748 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000749#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000750 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000751#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000752 static long rax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000753#elif defined(CRISV10) || defined(CRISV32)
754 static long r10;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +0200755#elif defined(MICROBLAZE)
756 static long r3;
Roland McGrath761b5d72002-12-15 23:58:31 +0000757#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000758#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000759#ifdef FREEBSD
760 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000761#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000762
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000764get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000765{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000766 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000767
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000768#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000769# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000770 if (tcp->flags & TCB_WAITEXECVE) {
771 /*
772 * When the execve system call completes successfully, the
773 * new process still has -ENOSYS (old style) or __NR_execve
774 * (new style) in gpr2. We cannot recover the scno again
775 * by disassembly, because the image that executed the
776 * syscall is gone now. Fortunately, we don't want it. We
777 * leave the flag set so that syscall_fixup can fake the
778 * result.
779 */
780 if (tcp->flags & TCB_INSYSCALL)
781 return 1;
782 /*
783 * This is the SIGTRAP after execve. We cannot try to read
784 * the system call here either.
785 */
786 tcp->flags &= ~TCB_WAITEXECVE;
787 return 0;
788 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000789
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000790 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000791 return -1;
792
793 if (syscall_mode != -ENOSYS) {
794 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000795 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000796 */
797 scno = syscall_mode;
798 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000799 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000800 * Old style of "passing" the scno via the SVC instruction.
801 */
802
803 long opcode, offset_reg, tmp;
804 void * svc_addr;
805 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
806 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
807 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
808 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000809
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000810 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000811 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000812 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000813 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000814 if (errno) {
815 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000816 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000817 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000818
819 /*
820 * We have to check if the SVC got executed directly or via an
821 * EXECUTE instruction. In case of EXECUTE it is necessary to do
822 * instruction decoding to derive the system call number.
823 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
824 * so that this doesn't work if a SVC opcode is part of an EXECUTE
825 * opcode. Since there is no way to find out the opcode size this
826 * is the best we can do...
827 */
828
829 if ((opcode & 0xff00) == 0x0a00) {
830 /* SVC opcode */
831 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000832 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000833 else {
834 /* SVC got executed by EXECUTE instruction */
835
836 /*
837 * Do instruction decoding of EXECUTE. If you really want to
838 * understand this, read the Principles of Operations.
839 */
840 svc_addr = (void *) (opcode & 0xfff);
841
842 tmp = 0;
843 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000844 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000845 return -1;
846 svc_addr += tmp;
847
848 tmp = 0;
849 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000850 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000851 return -1;
852 svc_addr += tmp;
853
Denys Vlasenkofb036672009-01-23 16:30:26 +0000854 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000855 if (errno)
856 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000857# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000858 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000859# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000860 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000861# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000862 tmp = 0;
863 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000864 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000865 return -1;
866
867 scno = (scno | tmp) & 0xff;
868 }
869 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000870# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000871 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000872 return -1;
873 if (!(tcp->flags & TCB_INSYSCALL)) {
874 /* Check if we return from execve. */
875 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
876 tcp->flags &= ~TCB_WAITEXECVE;
877 return 0;
878 }
879 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200880
881# ifdef POWERPC64
882 if (!(tcp->flags & TCB_INSYSCALL)) {
883 static int currpers = -1;
884 long val;
885 int pid = tcp->pid;
886
887 /* Check for 64/32 bit mode. */
888 if (upeek(tcp, sizeof (unsigned long)*PT_MSR, &val) < 0)
889 return -1;
890 /* SF is bit 0 of MSR */
891 if (val < 0)
892 currpers = 0;
893 else
894 currpers = 1;
895 if (currpers != current_personality) {
896 static const char *const names[] = {"64 bit", "32 bit"};
897 set_personality(currpers);
898 printf("[ Process PID=%d runs in %s mode. ]\n",
899 pid, names[current_personality]);
900 }
901 }
902# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000903# elif defined(AVR32)
904 /*
905 * Read complete register set in one go.
906 */
907 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
908 return -1;
909
910 /*
911 * We only need to grab the syscall number on syscall entry.
912 */
913 if (!(tcp->flags & TCB_INSYSCALL)) {
914 scno = regs.r8;
915
916 /* Check if we return from execve. */
917 if (tcp->flags & TCB_WAITEXECVE) {
918 tcp->flags &= ~TCB_WAITEXECVE;
919 return 0;
920 }
921 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000922# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000923 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000924 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000925# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000926 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000927 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000928# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000929 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000930 return -1;
931
Roland McGrath761b5d72002-12-15 23:58:31 +0000932 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000933 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000934 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000935 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000936
937 /* Check CS register value. On x86-64 linux it is:
938 * 0x33 for long mode (64 bit)
939 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000940 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000941 * to be cached.
942 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000943 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000944 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000945 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000946 case 0x23: currpers = 1; break;
947 case 0x33: currpers = 0; break;
948 default:
949 fprintf(stderr, "Unknown value CS=0x%02X while "
950 "detecting personality of process "
951 "PID=%d\n", (int)val, pid);
952 currpers = current_personality;
953 break;
954 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000955# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000956 /* This version analyzes the opcode of a syscall instruction.
957 * (int 0x80 on i386 vs. syscall on x86-64)
958 * It works, but is too complicated.
959 */
960 unsigned long val, rip, i;
961
Denys Vlasenko8236f252009-01-02 18:10:08 +0000962 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000963 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000964
Michal Ludvig0e035502002-09-23 15:41:01 +0000965 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000966 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000967 errno = 0;
968
Denys Vlasenko8236f252009-01-02 18:10:08 +0000969 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000970 if (errno)
971 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000972 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000973 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000974 /* x86-64: syscall = 0x0f 0x05 */
975 case 0x050f: currpers = 0; break;
976 /* i386: int 0x80 = 0xcd 0x80 */
977 case 0x80cd: currpers = 1; break;
978 default:
979 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000980 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000981 "Unknown syscall opcode (0x%04X) while "
982 "detecting personality of process "
983 "PID=%d\n", (int)call, pid);
984 break;
985 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000986# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000987 if (currpers != current_personality) {
988 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000989 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000990 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000991 pid, names[current_personality]);
992 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000993 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000994# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000995# define IA64_PSR_IS ((long)1 << 34)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700996 if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000997 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000998 if (!(tcp->flags & TCB_INSYSCALL)) {
999 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001000 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001001 return -1;
1002 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001003 if (upeek (tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001004 return -1;
1005 }
Roland McGrathba954762003-03-05 06:29:06 +00001006 /* Check if we return from execve. */
1007 if (tcp->flags & TCB_WAITEXECVE) {
1008 tcp->flags &= ~TCB_WAITEXECVE;
1009 return 0;
1010 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001011 } else {
1012 /* syscall in progress */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001013 if (upeek (tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001014 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001015 if (upeek (tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001016 return -1;
1017 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001018# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001019 /*
1020 * Read complete register set in one go.
1021 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001022 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001023 return -1;
1024
1025 /*
1026 * We only need to grab the syscall number on syscall entry.
1027 */
1028 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001029 if (!(tcp->flags & TCB_INSYSCALL)) {
1030 /* Check if we return from execve. */
1031 if (tcp->flags & TCB_WAITEXECVE) {
1032 tcp->flags &= ~TCB_WAITEXECVE;
1033 return 0;
1034 }
1035 }
1036
Roland McGrath0f87c492003-06-03 23:29:04 +00001037 /*
1038 * Note: we only deal with only 32-bit CPUs here.
1039 */
1040 if (regs.ARM_cpsr & 0x20) {
1041 /*
1042 * Get the Thumb-mode system call number
1043 */
1044 scno = regs.ARM_r7;
1045 } else {
1046 /*
1047 * Get the ARM-mode system call number
1048 */
1049 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001050 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001051 if (errno)
1052 return -1;
1053
1054 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1055 tcp->flags &= ~TCB_WAITEXECVE;
1056 return 0;
1057 }
1058
Roland McGrathf691bd22006-04-25 07:34:41 +00001059 /* Handle the EABI syscall convention. We do not
1060 bother converting structures between the two
1061 ABIs, but basic functionality should work even
1062 if strace and the traced program have different
1063 ABIs. */
1064 if (scno == 0xef000000) {
1065 scno = regs.ARM_r7;
1066 } else {
1067 if ((scno & 0x0ff00000) != 0x0f900000) {
1068 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1069 scno);
1070 return -1;
1071 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001072
Roland McGrathf691bd22006-04-25 07:34:41 +00001073 /*
1074 * Fixup the syscall number
1075 */
1076 scno &= 0x000fffff;
1077 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001078 }
Roland McGrath56703312008-05-20 01:35:55 +00001079 if (scno & 0x0f0000) {
1080 /*
1081 * Handle ARM specific syscall
1082 */
1083 set_personality(1);
1084 scno &= 0x0000ffff;
1085 } else
1086 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001087
1088 if (tcp->flags & TCB_INSYSCALL) {
1089 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1090 tcp->flags &= ~TCB_INSYSCALL;
1091 }
1092 } else {
1093 if (!(tcp->flags & TCB_INSYSCALL)) {
1094 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1095 tcp->flags |= TCB_INSYSCALL;
1096 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001097 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001098# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001099 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001101# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001102 unsigned long long regs[38];
1103
Roland McGratheb9e2e82009-06-02 16:49:22 -07001104 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001105 return -1;
1106 a3 = regs[REG_A3];
1107 r2 = regs[REG_V0];
1108
1109 if(!(tcp->flags & TCB_INSYSCALL)) {
1110 scno = r2;
1111
1112 /* Check if we return from execve. */
1113 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1114 tcp->flags &= ~TCB_WAITEXECVE;
1115 return 0;
1116 }
1117
1118 if (scno < 0 || scno > nsyscalls) {
1119 if(a3 == 0 || a3 == -1) {
1120 if(debug)
1121 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1122 return 0;
1123 }
1124 }
1125 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001126# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001127 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001128 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001129 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001130 if (upeek(tcp, REG_V0, &scno) < 0)
1131 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001132
Roland McGrath542c2c62008-05-20 01:11:56 +00001133 /* Check if we return from execve. */
1134 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1135 tcp->flags &= ~TCB_WAITEXECVE;
1136 return 0;
1137 }
1138
Wichert Akkermanf90da011999-10-31 21:15:38 +00001139 if (scno < 0 || scno > nsyscalls) {
1140 if(a3 == 0 || a3 == -1) {
1141 if(debug)
1142 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1143 return 0;
1144 }
1145 }
1146 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001147 if (upeek(tcp, REG_V0, &r2) < 0)
1148 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001149 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001150# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001151 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001152 return -1;
1153
1154 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001155 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001156 return -1;
1157
1158 /* Check if we return from execve. */
1159 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1160 tcp->flags &= ~TCB_WAITEXECVE;
1161 return 0;
1162 }
1163
1164 /*
1165 * Do some sanity checks to figure out if it's
1166 * really a syscall entry
1167 */
1168 if (scno < 0 || scno > nsyscalls) {
1169 if (a3 == 0 || a3 == -1) {
1170 if (debug)
1171 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1172 return 0;
1173 }
1174 }
1175 }
1176 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001177 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001178 return -1;
1179 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001180# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001182 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183 return -1;
1184
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001185 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186 if (!(tcp->flags & TCB_INSYSCALL)) {
1187 /* Retrieve the syscall trap instruction. */
1188 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001189# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001190 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001191 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001192# else
1193 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001194# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001195 if (errno)
1196 return -1;
1197
1198 /* Disassemble the trap to see what personality to use. */
1199 switch (trap) {
1200 case 0x91d02010:
1201 /* Linux/SPARC syscall trap. */
1202 set_personality(0);
1203 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001204 case 0x91d0206d:
1205 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001206 set_personality(2);
1207 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001208 case 0x91d02000:
1209 /* SunOS syscall trap. (pers 1) */
1210 fprintf(stderr,"syscall: SunOS no support\n");
1211 return -1;
1212 case 0x91d02008:
1213 /* Solaris 2.x syscall trap. (per 2) */
1214 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001215 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216 case 0x91d02009:
1217 /* NetBSD/FreeBSD syscall trap. */
1218 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1219 return -1;
1220 case 0x91d02027:
1221 /* Solaris 2.x gettimeofday */
1222 set_personality(1);
1223 break;
1224 default:
1225 /* Unknown syscall trap. */
1226 if(tcp->flags & TCB_WAITEXECVE) {
1227 tcp->flags &= ~TCB_WAITEXECVE;
1228 return 0;
1229 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001230# if defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001231 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001232# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001233 fprintf(stderr,"syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001234# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 return -1;
1236 }
1237
1238 /* Extract the system call number from the registers. */
1239 if (trap == 0x91d02027)
1240 scno = 156;
1241 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001242 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001244 scno = regs.u_regs[U_REG_O0];
1245 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 +00001246 }
1247 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001248# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001249 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001250 return -1;
1251 if (!(tcp->flags & TCB_INSYSCALL)) {
1252 /* Check if we return from execve. */
1253 if ((tcp->flags & TCB_WAITEXECVE)) {
1254 tcp->flags &= ~TCB_WAITEXECVE;
1255 return 0;
1256 }
1257 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001258# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001259 /*
1260 * In the new syscall ABI, the system call number is in R3.
1261 */
1262 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1263 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001264
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001265 if (scno < 0) {
1266 /* Odd as it may seem, a glibc bug has been known to cause
1267 glibc to issue bogus negative syscall numbers. So for
1268 our purposes, make strace print what it *should* have been */
1269 long correct_scno = (scno & 0xff);
1270 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001271 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001272 "Detected glibc bug: bogus system call"
1273 " number = %ld, correcting to %ld\n",
1274 scno,
1275 correct_scno);
1276 scno = correct_scno;
1277 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001278
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001279 if (!(tcp->flags & TCB_INSYSCALL)) {
1280 /* Check if we return from execve. */
1281 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1282 tcp->flags &= ~TCB_WAITEXECVE;
1283 return 0;
1284 }
1285 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001286# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001287 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001288 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001289 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001290
1291 if (!(tcp->flags & TCB_INSYSCALL)) {
1292 /* Check if we return from execve. */
1293 if (tcp->flags & TCB_WAITEXECVE) {
1294 tcp->flags &= ~TCB_WAITEXECVE;
1295 return 0;
1296 }
1297 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001298# elif defined(CRISV10) || defined(CRISV32)
1299 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1300 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001301# elif defined(TILE)
1302 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1303 return -1;
1304
1305 if (!(tcp->flags & TCB_INSYSCALL)) {
1306 /* Check if we return from execve. */
1307 if (tcp->flags & TCB_WAITEXECVE) {
1308 tcp->flags &= ~TCB_WAITEXECVE;
1309 return 0;
1310 }
1311 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001312# elif defined(MICROBLAZE)
1313 if (upeek(tcp, 0, &scno) < 0)
1314 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001315# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001317
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001319 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001320 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001321#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001322 /* new syscall ABI returns result in R0 */
1323 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1324 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001325#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001326 /* ABI defines result returned in r9 */
1327 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1328 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001330
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001331#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001332# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001333 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001334# else
1335# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001336 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001337# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001338 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001339 perror("pread");
1340 return -1;
1341 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001342 switch (regs.r_eax) {
1343 case SYS_syscall:
1344 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001345 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1346 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001347 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001348 scno = regs.r_eax;
1349 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001350 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001351# endif /* FREEBSD */
1352# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001353#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001354
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001355 if (!(tcp->flags & TCB_INSYSCALL))
1356 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001357 return 1;
1358}
1359
Pavel Machek4dc3b142000-02-01 17:58:41 +00001360
Roland McGrath17352792005-06-07 23:21:26 +00001361long
1362known_scno(tcp)
1363struct tcb *tcp;
1364{
1365 long scno = tcp->scno;
1366 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1367 scno = sysent[scno].native_scno;
1368 else
1369 scno += NR_SYSCALL_BASE;
1370 return scno;
1371}
1372
Roland McGratheb9e2e82009-06-02 16:49:22 -07001373/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001374 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001375 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1376 * 1: ok, continue in trace_syscall().
1377 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001378 * ("????" etc) and bail out.
1379 */
Roland McGratha4d48532005-06-08 20:45:28 +00001380static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001381syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001382{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001383#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001384 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001385
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001386 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001387 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001388 if (
1389 scno == SYS_fork
1390#ifdef SYS_vfork
1391 || scno == SYS_vfork
1392#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001393#ifdef SYS_fork1
1394 || scno == SYS_fork1
1395#endif /* SYS_fork1 */
1396#ifdef SYS_forkall
1397 || scno == SYS_forkall
1398#endif /* SYS_forkall */
1399#ifdef SYS_rfork1
1400 || scno == SYS_rfork1
1401#endif /* SYS_fork1 */
1402#ifdef SYS_rforkall
1403 || scno == SYS_rforkall
1404#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001405 ) {
1406 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001407 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001408 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001409 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001410 }
1411 else {
1412 fprintf(stderr, "syscall: missing entry\n");
1413 tcp->flags |= TCB_INSYSCALL;
1414 }
1415 }
1416 }
1417 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001418 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001419 fprintf(stderr, "syscall: missing exit\n");
1420 tcp->flags &= ~TCB_INSYSCALL;
1421 }
1422 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001423#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001424#ifdef SUNOS4
1425 if (!(tcp->flags & TCB_INSYSCALL)) {
1426 if (scno == 0) {
1427 fprintf(stderr, "syscall: missing entry\n");
1428 tcp->flags |= TCB_INSYSCALL;
1429 }
1430 }
1431 else {
1432 if (scno != 0) {
1433 if (debug) {
1434 /*
1435 * This happens when a signal handler
1436 * for a signal which interrupted a
1437 * a system call makes another system call.
1438 */
1439 fprintf(stderr, "syscall: missing exit\n");
1440 }
1441 tcp->flags &= ~TCB_INSYSCALL;
1442 }
1443 }
1444#endif /* SUNOS4 */
1445#ifdef LINUX
1446#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001447 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448 return -1;
1449 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1450 if (debug)
1451 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1452 return 0;
1453 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001454#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001455 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001456 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001457 if (current_personality == 1)
1458 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001459 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1460 if (debug)
1461 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1462 return 0;
1463 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001464#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001465 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001466 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001467 if (syscall_mode != -ENOSYS)
1468 syscall_mode = tcp->scno;
1469 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001470 if (debug)
1471 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1472 return 0;
1473 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001474 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1475 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1476 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1477 /*
1478 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1479 * flag set for the post-execve SIGTRAP to see and reset.
1480 */
1481 gpr2 = 0;
1482 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483#elif defined (POWERPC)
1484# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001485 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001487 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001488 return -1;
1489 if (flags & SO_MASK)
1490 result = -result;
1491#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001492 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001493 return -1;
1494 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1495 if (debug)
1496 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1497 return 0;
1498 }
1499#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001500 /*
1501 * Nothing required
1502 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001503#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001504 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001505 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001506#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001507 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001508 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001509#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001510 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001511 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001512 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001513 return -1;
1514 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1515 if (debug)
1516 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1517 return 0;
1518 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001519#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001520 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001521 return -1;
1522 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1523 if (debug)
1524 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1525 return 0;
1526 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001527#elif defined(MICROBLAZE)
1528 if (upeek(tcp, 3 * 4, &r3) < 0)
1529 return -1;
1530 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1531 if (debug)
1532 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1533 return 0;
1534 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001535#endif
1536#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001537 return 1;
1538}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001539
Roland McGrathc1e45922008-05-27 23:18:29 +00001540#ifdef LINUX
1541/*
1542 * Check the syscall return value register value for whether it is
1543 * a negated errno code indicating an error, or a success return value.
1544 */
1545static inline int
1546is_negated_errno(unsigned long int val)
1547{
1548 unsigned long int max = -(long int) nerrnos;
1549 if (personality_wordsize[current_personality] < sizeof(val)) {
1550 val = (unsigned int) val;
1551 max = (unsigned int) max;
1552 }
1553 return val > max;
1554}
1555#endif
1556
Roland McGratha4d48532005-06-08 20:45:28 +00001557static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001558get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001559{
1560 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001561#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001562# if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001563 if (is_negated_errno(gpr2)) {
1564 tcp->u_rval = -1;
1565 u_error = -gpr2;
1566 }
1567 else {
1568 tcp->u_rval = gpr2;
1569 u_error = 0;
1570 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001571# elif defined(I386)
Roland McGrathc1e45922008-05-27 23:18:29 +00001572 if (is_negated_errno(eax)) {
1573 tcp->u_rval = -1;
1574 u_error = -eax;
1575 }
1576 else {
1577 tcp->u_rval = eax;
1578 u_error = 0;
1579 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001580# elif defined(X86_64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001581 if (is_negated_errno(rax)) {
1582 tcp->u_rval = -1;
1583 u_error = -rax;
1584 }
1585 else {
1586 tcp->u_rval = rax;
1587 u_error = 0;
1588 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001589# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001590 if (ia32) {
1591 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001592
Roland McGrathc1e45922008-05-27 23:18:29 +00001593 err = (int)r8;
1594 if (is_negated_errno(err)) {
1595 tcp->u_rval = -1;
1596 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001597 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001598 else {
1599 tcp->u_rval = err;
1600 u_error = 0;
1601 }
1602 } else {
1603 if (r10) {
1604 tcp->u_rval = -1;
1605 u_error = r8;
1606 } else {
1607 tcp->u_rval = r8;
1608 u_error = 0;
1609 }
1610 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001611# elif defined(MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001612 if (a3) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001613 tcp->u_rval = -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001614 u_error = r2;
1615 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001616 tcp->u_rval = r2;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001617 u_error = 0;
1618 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001619# elif defined(POWERPC)
Roland McGrathc1e45922008-05-27 23:18:29 +00001620 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 tcp->u_rval = -1;
1622 u_error = -result;
1623 }
1624 else {
1625 tcp->u_rval = result;
1626 u_error = 0;
1627 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001628# elif defined(M68K)
Roland McGrathc1e45922008-05-27 23:18:29 +00001629 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630 tcp->u_rval = -1;
1631 u_error = -d0;
1632 }
1633 else {
1634 tcp->u_rval = d0;
1635 u_error = 0;
1636 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001637# elif defined(ARM)
Roland McGrathc1e45922008-05-27 23:18:29 +00001638 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001640 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641 }
1642 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001643 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644 u_error = 0;
1645 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001646# elif defined(AVR32)
1647 if (regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1648 tcp->u_rval = -1;
1649 u_error = -regs.r12;
1650 }
1651 else {
1652 tcp->u_rval = regs.r12;
1653 u_error = 0;
1654 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001655# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001656 if (is_negated_errno(r0)) {
1657 tcp->u_rval = -1;
1658 u_error = -r0;
1659 } else {
1660 tcp->u_rval = r0;
1661 u_error = 0;
1662 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001663# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664 if (a3) {
1665 tcp->u_rval = -1;
1666 u_error = r0;
1667 }
1668 else {
1669 tcp->u_rval = r0;
1670 u_error = 0;
1671 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001672# elif defined(SPARC)
Mike Frysinger8566c502009-10-12 11:05:14 -04001673 if (regs.psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001675 u_error = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001676 }
1677 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001678 tcp->u_rval = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001679 u_error = 0;
1680 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001681# elif defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001682 if (regs.tstate & 0x1100000000UL) {
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001683 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001684 u_error = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001685 }
1686 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001687 tcp->u_rval = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001688 u_error = 0;
1689 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001690# elif defined(HPPA)
Roland McGrathc1e45922008-05-27 23:18:29 +00001691 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001692 tcp->u_rval = -1;
1693 u_error = -r28;
1694 }
1695 else {
1696 tcp->u_rval = r28;
1697 u_error = 0;
1698 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001699# elif defined(SH)
Roland McGrathc1e45922008-05-27 23:18:29 +00001700 /* interpret R0 as return value or error number */
1701 if (is_negated_errno(r0)) {
1702 tcp->u_rval = -1;
1703 u_error = -r0;
1704 }
1705 else {
1706 tcp->u_rval = r0;
1707 u_error = 0;
1708 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001709# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001710 /* interpret result as return value or error number */
1711 if (is_negated_errno(r9)) {
1712 tcp->u_rval = -1;
1713 u_error = -r9;
1714 }
1715 else {
1716 tcp->u_rval = r9;
1717 u_error = 0;
1718 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001719# elif defined(CRISV10) || defined(CRISV32)
1720 if (r10 && (unsigned) -r10 < nerrnos) {
1721 tcp->u_rval = -1;
1722 u_error = -r10;
1723 }
1724 else {
1725 tcp->u_rval = r10;
1726 u_error = 0;
1727 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001728# elif defined(TILE)
1729 long rval;
1730 /* interpret result as return value or error number */
1731 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1732 return -1;
1733 if (rval < 0 && rval > -nerrnos) {
1734 tcp->u_rval = -1;
1735 u_error = -rval;
1736 }
1737 else {
1738 tcp->u_rval = rval;
1739 u_error = 0;
1740 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001741# elif defined(MICROBLAZE)
1742 /* interpret result as return value or error number */
1743 if (is_negated_errno(r3)) {
1744 tcp->u_rval = -1;
1745 u_error = -r3;
1746 }
1747 else {
1748 tcp->u_rval = r3;
1749 u_error = 0;
1750 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001751# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001752#endif /* LINUX */
1753#ifdef SUNOS4
1754 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001755 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001756 return -1;
1757 u_error >>= 24; /* u_error is a char */
1758
1759 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001760 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001761 return -1;
1762#endif /* SUNOS4 */
1763#ifdef SVR4
1764#ifdef SPARC
1765 /* Judicious guessing goes a long way. */
1766 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1767 tcp->u_rval = -1;
1768 u_error = tcp->status.pr_reg[R_O0];
1769 }
1770 else {
1771 tcp->u_rval = tcp->status.pr_reg[R_O0];
1772 u_error = 0;
1773 }
1774#endif /* SPARC */
1775#ifdef I386
1776 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001777 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001778 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001779 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780 }
1781 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001782 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001783#ifdef HAVE_LONG_LONG
1784 tcp->u_lrval =
1785 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1786 tcp->status.PR_REG[EAX];
1787#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001788 u_error = 0;
1789 }
1790#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001791#ifdef X86_64
1792 /* Wanna know how to kill an hour single-stepping? */
1793 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1794 tcp->u_rval = -1;
1795 u_error = tcp->status.PR_REG[RAX];
1796 }
1797 else {
1798 tcp->u_rval = tcp->status.PR_REG[RAX];
1799 u_error = 0;
1800 }
1801#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001802#ifdef MIPS
1803 if (tcp->status.pr_reg[CTX_A3]) {
1804 tcp->u_rval = -1;
1805 u_error = tcp->status.pr_reg[CTX_V0];
1806 }
1807 else {
1808 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1809 u_error = 0;
1810 }
1811#endif /* MIPS */
1812#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001813#ifdef FREEBSD
1814 if (regs.r_eflags & PSL_C) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001815 tcp->u_rval = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001816 u_error = regs.r_eax;
1817 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001818 tcp->u_rval = regs.r_eax;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001819 tcp->u_lrval =
1820 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1821 u_error = 0;
1822 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001823#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001824 tcp->u_error = u_error;
1825 return 1;
1826}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001827
Roland McGrathb69f81b2002-12-21 23:25:18 +00001828int
1829force_result(tcp, error, rval)
1830 struct tcb *tcp;
1831 int error;
1832 long rval;
1833{
1834#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001835# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001836 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001837 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1838 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001839# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001840 eax = error ? -error : rval;
1841 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1842 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001843# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001844 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001845 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001846 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001847# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001848 if (ia32) {
1849 r8 = error ? -error : rval;
1850 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1851 return -1;
1852 }
1853 else {
1854 if (error) {
1855 r8 = error;
1856 r10 = -1;
1857 }
1858 else {
1859 r8 = rval;
1860 r10 = 0;
1861 }
1862 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1863 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1864 return -1;
1865 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001866# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001867 r0 = error ? -error : rval;
1868 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1869 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001870# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001871 if (error) {
1872 r2 = error;
1873 a3 = -1;
1874 }
1875 else {
1876 r2 = rval;
1877 a3 = 0;
1878 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001879 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001880 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1881 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001882 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001883# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001884 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001885 return -1;
1886 if (error) {
1887 flags |= SO_MASK;
1888 result = error;
1889 }
1890 else {
1891 flags &= ~SO_MASK;
1892 result = rval;
1893 }
Roland McGratheb285352003-01-14 09:59:00 +00001894 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1895 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001896 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001897# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001898 d0 = error ? -error : rval;
1899 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1900 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001901# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001902 regs.ARM_r0 = error ? -error : rval;
1903 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001904 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001905# elif defined(AVR32)
1906 regs.r12 = error ? -error : rval;
1907 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1908 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001909# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001910 if (error) {
1911 a3 = -1;
1912 r0 = error;
1913 }
1914 else {
1915 a3 = 0;
1916 r0 = rval;
1917 }
1918 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1919 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1920 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001921# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001922 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1923 return -1;
1924 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001925 regs.psr |= PSR_C;
1926 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001927 }
1928 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001929 regs.psr &= ~PSR_C;
1930 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001931 }
1932 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1933 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001934# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001935 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1936 return -1;
1937 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001938 regs.tstate |= 0x1100000000UL;
1939 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001940 }
1941 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001942 regs.tstate &= ~0x1100000000UL;
1943 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001944 }
1945 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1946 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001947# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001948 r28 = error ? -error : rval;
1949 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1950 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001951# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001952 r0 = error ? -error : rval;
1953 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1954 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001955# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001956 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001957 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1958 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001959# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001960#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001961
Roland McGrathb69f81b2002-12-21 23:25:18 +00001962#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001963 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1964 error << 24) < 0 ||
1965 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001966 return -1;
1967#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001968
Roland McGrathb69f81b2002-12-21 23:25:18 +00001969#ifdef SVR4
1970 /* XXX no clue */
1971 return -1;
1972#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001973
Roland McGrathb69f81b2002-12-21 23:25:18 +00001974#ifdef FREEBSD
1975 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001976 perror("pread");
1977 return -1;
1978 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001979 if (error) {
1980 regs.r_eflags |= PSL_C;
1981 regs.r_eax = error;
1982 }
1983 else {
1984 regs.r_eflags &= ~PSL_C;
1985 regs.r_eax = rval;
1986 }
1987 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001988 perror("pwrite");
1989 return -1;
1990 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001991#endif /* FREEBSD */
1992
1993 /* All branches reach here on success (only). */
1994 tcp->u_error = error;
1995 tcp->u_rval = rval;
1996 return 0;
1997}
1998
Roland McGratha4d48532005-06-08 20:45:28 +00001999static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002000syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002001{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002002#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00002003#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002004 {
2005 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002006 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2007 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002008 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002009 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002010 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002011 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002012 return -1;
2013 }
2014 }
2015#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002016 {
2017 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002018 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2019 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002020 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002021 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002022 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00002023 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2024 * for scno somewhere above here!
2025 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002026 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002027 return -1;
2028 }
2029 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002030#elif defined (IA64)
2031 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002032 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002033 unsigned long *out0, cfm, sof, sol, i;
2034 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002035 /* be backwards compatible with kernel < 2.4.4... */
2036# ifndef PT_RBS_END
2037# define PT_RBS_END PT_AR_BSP
2038# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002039
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002040 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002041 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002042 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002043 return -1;
2044
2045 sof = (cfm >> 0) & 0x7f;
2046 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002047 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002048
2049 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2050 && sysent[tcp->scno].nargs != -1)
2051 tcp->u_nargs = sysent[tcp->scno].nargs;
2052 else
2053 tcp->u_nargs = MAX_ARGS;
2054 for (i = 0; i < tcp->u_nargs; ++i) {
2055 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2056 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2057 return -1;
2058 }
2059 } else {
2060 int i;
2061
2062 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002063 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002064 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002065 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002066 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002067 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002068 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002069 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002070 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002071 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002072 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002073 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002074 return -1;
2075
2076 for (i = 0; i < 6; ++i)
2077 /* truncate away IVE sign-extension */
2078 tcp->u_arg[i] &= 0xffffffff;
2079
2080 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2081 && sysent[tcp->scno].nargs != -1)
2082 tcp->u_nargs = sysent[tcp->scno].nargs;
2083 else
2084 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002085 }
2086 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002087#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2088 /* N32 and N64 both use up to six registers. */
2089 {
2090 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002091 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002092
2093 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2094 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002095 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002096 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002097
David Daney20037042010-02-09 21:22:30 +00002098 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002099 return -1;
2100
Roland McGratheb9e2e82009-06-02 16:49:22 -07002101 for(i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002102 tcp->u_arg[i] = regs[REG_A0 + i];
2103# if defined (LINUX_MIPSN32)
2104 tcp->ext_arg[i] = regs[REG_A0 + i];
2105# endif
2106 }
2107 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002108#elif defined (MIPS)
2109 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002110 long sp;
2111 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002112
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002113 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2114 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002115 else
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002116 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002117 if(nargs > 4) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002118 if(upeek(tcp, REG_SP, &sp) < 0)
2119 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002120 for(i = 0; i < 4; i++) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002121 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
2122 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002123 }
2124 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2125 (char *)(tcp->u_arg + 4));
2126 } else {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002127 for(i = 0; i < nargs; i++) {
2128 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2129 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002130 }
2131 }
2132 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002133#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002134# ifndef PT_ORIG_R3
2135# define PT_ORIG_R3 34
2136# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002137 {
2138 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002139 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2140 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002141 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002142 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002143 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002144 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002145 (sizeof(unsigned long)*PT_ORIG_R3) :
2146 ((i+PT_R3)*sizeof(unsigned long)),
2147 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002148 return -1;
2149 }
2150 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002151#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002152 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002153 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002154
2155 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2156 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002157 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002158 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002159 for (i = 0; i < tcp->u_nargs; i++)
Mike Frysinger8566c502009-10-12 11:05:14 -04002160 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002161 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002162#elif defined (HPPA)
2163 {
2164 int i;
2165
2166 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2167 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002168 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002169 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002170 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002171 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002172 return -1;
2173 }
2174 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002175#elif defined(ARM)
2176 {
2177 int i;
2178
2179 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2180 tcp->u_nargs = sysent[tcp->scno].nargs;
2181 else
2182 tcp->u_nargs = MAX_ARGS;
2183 for (i = 0; i < tcp->u_nargs; i++)
2184 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002185 }
2186#elif defined(AVR32)
2187 tcp->u_nargs = sysent[tcp->scno].nargs;
2188 tcp->u_arg[0] = regs.r12;
2189 tcp->u_arg[1] = regs.r11;
2190 tcp->u_arg[2] = regs.r10;
2191 tcp->u_arg[3] = regs.r9;
2192 tcp->u_arg[4] = regs.r5;
2193 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002194#elif defined(BFIN)
2195 {
2196 int i;
2197 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2198
2199 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2200 tcp->u_nargs = sysent[tcp->scno].nargs;
2201 else
2202 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2203
2204 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002205 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002206 return -1;
2207 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002208#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002209 {
2210 int i;
2211 static int syscall_regs[] = {
2212 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2213 REG_REG0, REG_REG0+1, REG_REG0+2
2214 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002215
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002216 tcp->u_nargs = sysent[tcp->scno].nargs;
2217 for (i = 0; i < tcp->u_nargs; i++) {
2218 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2219 return -1;
2220 }
2221 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002222#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002223 {
2224 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002225 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002226 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2227
2228 /*
2229 * TODO: should also check that the number of arguments encoded
2230 * in the trap number matches the number strace expects.
2231 */
2232 /*
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002233 assert(sysent[tcp->scno].nargs <
2234 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
Roland McGrathe1e584b2003-06-02 19:18:58 +00002235 */
2236
2237 tcp->u_nargs = sysent[tcp->scno].nargs;
2238 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002239 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002240 return -1;
2241 }
2242 }
2243
Michal Ludvig0e035502002-09-23 15:41:01 +00002244#elif defined(X86_64)
2245 {
2246 int i;
2247 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2248 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002249 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002250 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002251
Michal Ludvig0e035502002-09-23 15:41:01 +00002252 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2253 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002254 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002255 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002256 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002257 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002258 return -1;
2259 }
2260 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002261#elif defined(MICROBLAZE)
2262 {
2263 int i;
2264 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2265 tcp->u_nargs = sysent[tcp->scno].nargs;
2266 else
2267 tcp->u_nargs = 0;
2268 for (i = 0; i < tcp->u_nargs; i++) {
2269 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2270 return -1;
2271 }
2272 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002273#elif defined(CRISV10) || defined(CRISV32)
2274 {
2275 int i;
2276 static const int crisregs[] = {
2277 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2278 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2279 };
2280
2281 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2282 tcp->u_nargs = sysent[tcp->scno].nargs;
2283 else
2284 tcp->u_nargs = 0;
2285 for (i = 0; i < tcp->u_nargs; i++) {
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00002286 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002287 return -1;
2288 }
2289 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05002290#elif defined(TILE)
2291 {
2292 int i;
2293 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2294 tcp->u_nargs = sysent[tcp->scno].nargs;
2295 else
2296 tcp->u_nargs = MAX_ARGS;
2297 for (i = 0; i < tcp->u_nargs; ++i) {
2298 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2299 return -1;
2300 }
2301 }
Andreas Schwab246888d2010-06-05 21:50:30 +02002302#elif defined (M68K)
2303 {
2304 int i;
2305 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2306 tcp->u_nargs = sysent[tcp->scno].nargs;
2307 else
2308 tcp->u_nargs = MAX_ARGS;
2309 for (i = 0; i < tcp->u_nargs; i++) {
2310 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2311 return -1;
2312 }
2313 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002314#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002315 {
2316 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002317 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2318 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002319 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002320 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002321 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002322 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002323 return -1;
2324 }
2325 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002326#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002327#endif /* LINUX */
2328#ifdef SUNOS4
2329 {
2330 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002331 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2332 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002333 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002334 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002335 for (i = 0; i < tcp->u_nargs; i++) {
2336 struct user *u;
2337
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002338 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002339 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2340 return -1;
2341 }
2342 }
2343#endif /* SUNOS4 */
2344#ifdef SVR4
2345#ifdef MIPS
2346 /*
2347 * SGI is broken: even though it has pr_sysarg, it doesn't
2348 * set them on system call entry. Get a clue.
2349 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002350 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002351 tcp->u_nargs = sysent[tcp->scno].nargs;
2352 else
2353 tcp->u_nargs = tcp->status.pr_nsysarg;
2354 if (tcp->u_nargs > 4) {
2355 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2356 4*sizeof(tcp->u_arg[0]));
2357 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2358 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2359 }
2360 else {
2361 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2362 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2363 }
John Hughes25299712001-03-06 10:10:06 +00002364#elif UNIXWARE >= 2
2365 /*
2366 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2367 */
2368 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2369 tcp->u_nargs = sysent[tcp->scno].nargs;
2370 else
2371 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2372 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2373 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2374#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002375 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002376 tcp->u_nargs = sysent[tcp->scno].nargs;
2377 else
2378 tcp->u_nargs = tcp->status.pr_nsysarg;
2379 {
2380 int i;
2381 for (i = 0; i < tcp->u_nargs; i++)
2382 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2383 }
John Hughes25299712001-03-06 10:10:06 +00002384#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002385 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002386 tcp->u_nargs = sysent[tcp->scno].nargs;
2387 else
2388 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002389 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002390 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002391#else
2392 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002393#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002394#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002395#ifdef FREEBSD
2396 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2397 sysent[tcp->scno].nargs > tcp->status.val)
2398 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002399 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002400 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002401 if (tcp->u_nargs < 0)
2402 tcp->u_nargs = 0;
2403 if (tcp->u_nargs > MAX_ARGS)
2404 tcp->u_nargs = MAX_ARGS;
2405 switch(regs.r_eax) {
2406 case SYS___syscall:
2407 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2408 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002409 break;
2410 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002411 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2412 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002413 break;
2414 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002415 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2416 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002417 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002418 }
2419#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002420 return 1;
2421}
2422
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002423static int
2424trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002425{
2426 int sys_res;
2427 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002428 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002429 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002430
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002431 /* Measure the exit time as early as possible to avoid errors. */
2432 if (dtime || cflag)
2433 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002434
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002435 /* BTW, why we don't just memorize syscall no. on entry
2436 * in tcp->something?
2437 */
2438 scno_good = res = get_scno(tcp);
2439 if (res == 0)
2440 return res;
2441 if (res == 1)
2442 res = syscall_fixup(tcp);
2443 if (res == 0)
2444 return res;
2445 if (res == 1)
2446 res = get_error(tcp);
2447 if (res == 0)
2448 return res;
2449 if (res == 1)
2450 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002451
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002452 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
2453 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002454 tcp->flags &= ~TCB_INSYSCALL;
2455 return 0;
2456 }
2457
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002458 if (tcp->flags & TCB_REPRINT) {
2459 printleader(tcp);
2460 tprintf("<... ");
2461 if (scno_good != 1)
2462 tprintf("????");
2463 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2464 tprintf("syscall_%lu", tcp->scno);
2465 else
2466 tprintf("%s", sysent[tcp->scno].sys_name);
2467 tprintf(" resumed> ");
2468 }
2469
2470 if (cflag) {
2471 struct timeval t = tv;
2472 int rc = count_syscall(tcp, &t);
2473 if (cflag == CFLAG_ONLY_STATS)
2474 {
2475 tcp->flags &= ~TCB_INSYSCALL;
2476 return rc;
2477 }
2478 }
2479
2480 if (res != 1) {
2481 tprintf(") ");
2482 tabto(acolumn);
2483 tprintf("= ? <unavailable>");
2484 printtrailer();
2485 tcp->flags &= ~TCB_INSYSCALL;
2486 return res;
2487 }
2488
2489 if (tcp->scno >= nsyscalls || tcp->scno < 0
2490 || (qual_flags[tcp->scno] & QUAL_RAW))
2491 sys_res = printargs(tcp);
2492 else {
2493 if (not_failing_only && tcp->u_error)
2494 return 0; /* ignore failed syscalls */
2495 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2496 }
2497
2498 u_error = tcp->u_error;
2499 tprintf(") ");
2500 tabto(acolumn);
2501 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2502 qual_flags[tcp->scno] & QUAL_RAW) {
2503 if (u_error)
2504 tprintf("= -1 (errno %ld)", u_error);
2505 else
2506 tprintf("= %#lx", tcp->u_rval);
2507 }
2508 else if (!(sys_res & RVAL_NONE) && u_error) {
2509 switch (u_error) {
2510#ifdef LINUX
2511 case ERESTARTSYS:
2512 tprintf("= ? ERESTARTSYS (To be restarted)");
2513 break;
2514 case ERESTARTNOINTR:
2515 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2516 break;
2517 case ERESTARTNOHAND:
2518 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2519 break;
2520 case ERESTART_RESTARTBLOCK:
2521 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2522 break;
2523#endif /* LINUX */
2524 default:
2525 tprintf("= -1 ");
2526 if (u_error < 0)
2527 tprintf("E??? (errno %ld)", u_error);
2528 else if (u_error < nerrnos)
2529 tprintf("%s (%s)", errnoent[u_error],
2530 strerror(u_error));
2531 else
2532 tprintf("ERRNO_%ld (%s)", u_error,
2533 strerror(u_error));
2534 break;
2535 }
2536 if ((sys_res & RVAL_STR) && tcp->auxstr)
2537 tprintf(" (%s)", tcp->auxstr);
2538 }
2539 else {
2540 if (sys_res & RVAL_NONE)
2541 tprintf("= ?");
2542 else {
2543 switch (sys_res & RVAL_MASK) {
2544 case RVAL_HEX:
2545 tprintf("= %#lx", tcp->u_rval);
2546 break;
2547 case RVAL_OCTAL:
2548 tprintf("= %#lo", tcp->u_rval);
2549 break;
2550 case RVAL_UDECIMAL:
2551 tprintf("= %lu", tcp->u_rval);
2552 break;
2553 case RVAL_DECIMAL:
2554 tprintf("= %ld", tcp->u_rval);
2555 break;
2556#ifdef HAVE_LONG_LONG
2557 case RVAL_LHEX:
2558 tprintf("= %#llx", tcp->u_lrval);
2559 break;
2560 case RVAL_LOCTAL:
2561 tprintf("= %#llo", tcp->u_lrval);
2562 break;
2563 case RVAL_LUDECIMAL:
2564 tprintf("= %llu", tcp->u_lrval);
2565 break;
2566 case RVAL_LDECIMAL:
2567 tprintf("= %lld", tcp->u_lrval);
2568 break;
2569#endif
2570 default:
2571 fprintf(stderr,
2572 "invalid rval format\n");
2573 break;
2574 }
2575 }
2576 if ((sys_res & RVAL_STR) && tcp->auxstr)
2577 tprintf(" (%s)", tcp->auxstr);
2578 }
2579 if (dtime) {
2580 tv_sub(&tv, &tv, &tcp->etime);
2581 tprintf(" <%ld.%06ld>",
2582 (long) tv.tv_sec, (long) tv.tv_usec);
2583 }
2584 printtrailer();
2585
2586 dumpio(tcp);
2587 if (fflush(tcp->outf) == EOF)
2588 return -1;
2589 tcp->flags &= ~TCB_INSYSCALL;
2590 return 0;
2591}
2592
2593static int
2594trace_syscall_entering(struct tcb *tcp)
2595{
2596 int sys_res;
2597 int res, scno_good;
2598
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002599 scno_good = res = get_scno(tcp);
2600 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002601 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002602 if (res == 1)
2603 res = syscall_fixup(tcp);
2604 if (res == 0)
2605 return res;
2606 if (res == 1)
2607 res = syscall_enter(tcp);
2608 if (res == 0)
2609 return res;
2610
2611 if (res != 1) {
2612 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002613 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002614 tcp_last = tcp;
2615 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002616 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002617 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2618 tprintf("syscall_%lu(", tcp->scno);
2619 else
2620 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002621 /*
2622 * " <unavailable>" will be added later by the code which
2623 * detects ptrace errors.
2624 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002625 tcp->flags |= TCB_INSYSCALL;
2626 return res;
2627 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002628
Roland McGrath17352792005-06-07 23:21:26 +00002629 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002630#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002631 case SYS_socketcall:
2632 decode_subcall(tcp, SYS_socket_subcall,
2633 SYS_socket_nsubcalls, deref_style);
2634 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002635#endif
2636#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002637 case SYS_ipc:
2638 decode_subcall(tcp, SYS_ipc_subcall,
2639 SYS_ipc_nsubcalls, shift_style);
2640 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002641#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002642#ifdef SVR4
2643#ifdef SYS_pgrpsys_subcall
2644 case SYS_pgrpsys:
2645 decode_subcall(tcp, SYS_pgrpsys_subcall,
2646 SYS_pgrpsys_nsubcalls, shift_style);
2647 break;
2648#endif /* SYS_pgrpsys_subcall */
2649#ifdef SYS_sigcall_subcall
2650 case SYS_sigcall:
2651 decode_subcall(tcp, SYS_sigcall_subcall,
2652 SYS_sigcall_nsubcalls, mask_style);
2653 break;
2654#endif /* SYS_sigcall_subcall */
2655 case SYS_msgsys:
2656 decode_subcall(tcp, SYS_msgsys_subcall,
2657 SYS_msgsys_nsubcalls, shift_style);
2658 break;
2659 case SYS_shmsys:
2660 decode_subcall(tcp, SYS_shmsys_subcall,
2661 SYS_shmsys_nsubcalls, shift_style);
2662 break;
2663 case SYS_semsys:
2664 decode_subcall(tcp, SYS_semsys_subcall,
2665 SYS_semsys_nsubcalls, shift_style);
2666 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002667 case SYS_sysfs:
2668 decode_subcall(tcp, SYS_sysfs_subcall,
2669 SYS_sysfs_nsubcalls, shift_style);
2670 break;
2671 case SYS_spcall:
2672 decode_subcall(tcp, SYS_spcall_subcall,
2673 SYS_spcall_nsubcalls, shift_style);
2674 break;
2675#ifdef SYS_context_subcall
2676 case SYS_context:
2677 decode_subcall(tcp, SYS_context_subcall,
2678 SYS_context_nsubcalls, shift_style);
2679 break;
2680#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002681#ifdef SYS_door_subcall
2682 case SYS_door:
2683 decode_subcall(tcp, SYS_door_subcall,
2684 SYS_door_nsubcalls, door_style);
2685 break;
2686#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002687#ifdef SYS_kaio_subcall
2688 case SYS_kaio:
2689 decode_subcall(tcp, SYS_kaio_subcall,
2690 SYS_kaio_nsubcalls, shift_style);
2691 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002692#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002693#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002694#ifdef FREEBSD
2695 case SYS_msgsys:
2696 case SYS_shmsys:
2697 case SYS_semsys:
2698 decode_subcall(tcp, 0, 0, table_style);
2699 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002700#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002701#ifdef SUNOS4
2702 case SYS_semsys:
2703 decode_subcall(tcp, SYS_semsys_subcall,
2704 SYS_semsys_nsubcalls, shift_style);
2705 break;
2706 case SYS_msgsys:
2707 decode_subcall(tcp, SYS_msgsys_subcall,
2708 SYS_msgsys_nsubcalls, shift_style);
2709 break;
2710 case SYS_shmsys:
2711 decode_subcall(tcp, SYS_shmsys_subcall,
2712 SYS_shmsys_nsubcalls, shift_style);
2713 break;
2714#endif
2715 }
2716
2717 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002718 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002719 tcp->flags |= TCB_INSYSCALL;
2720 return 0;
2721 }
2722
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002723 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002724 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002725 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002726 return 0;
2727 }
2728
2729 printleader(tcp);
2730 tcp->flags &= ~TCB_REPRINT;
2731 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002732 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002733 tprintf("syscall_%lu(", tcp->scno);
2734 else
2735 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002736 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002737 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2738 sys_res = printargs(tcp);
2739 else
2740 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2741 if (fflush(tcp->outf) == EOF)
2742 return -1;
2743 tcp->flags |= TCB_INSYSCALL;
2744 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002745 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002746 gettimeofday(&tcp->etime, NULL);
2747 return sys_res;
2748}
2749
2750int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002751trace_syscall(struct tcb *tcp)
2752{
2753 return exiting(tcp) ?
2754 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2755}
2756
2757int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002758printargs(tcp)
2759struct tcb *tcp;
2760{
2761 if (entering(tcp)) {
2762 int i;
2763
2764 for (i = 0; i < tcp->u_nargs; i++)
2765 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2766 }
2767 return 0;
2768}
2769
2770long
2771getrval2(tcp)
2772struct tcb *tcp;
2773{
2774 long val = -1;
2775
2776#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002777#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002778 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002779 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002780 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002781 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002782#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002783 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002784 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002785#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002786 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002787 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002788#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002789#endif /* LINUX */
2790
2791#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002792 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002793 return -1;
2794#endif /* SUNOS4 */
2795
2796#ifdef SVR4
2797#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002798 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002799#endif /* SPARC */
2800#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002801 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002802#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002803#ifdef X86_64
2804 val = tcp->status.PR_REG[RDX];
2805#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002806#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002807 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002808#endif /* MIPS */
2809#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002810
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002811#ifdef FREEBSD
2812 struct reg regs;
2813 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2814 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002815#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002816 return val;
2817}
2818
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002819#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002820/*
2821 * Apparently, indirect system calls have already be converted by ptrace(2),
2822 * so if you see "indir" this program has gone astray.
2823 */
2824int
2825sys_indir(tcp)
2826struct tcb *tcp;
2827{
2828 int i, scno, nargs;
2829
2830 if (entering(tcp)) {
2831 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2832 fprintf(stderr, "Bogus syscall: %u\n", scno);
2833 return 0;
2834 }
2835 nargs = sysent[scno].nargs;
2836 tprintf("%s", sysent[scno].sys_name);
2837 for (i = 0; i < nargs; i++)
2838 tprintf(", %#lx", tcp->u_arg[i+1]);
2839 }
2840 return 0;
2841}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002842#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002843
2844int
2845is_restart_error(struct tcb *tcp)
2846{
2847#ifdef LINUX
2848 if (!syserror(tcp))
2849 return 0;
2850 switch (tcp->u_error) {
2851 case ERESTARTSYS:
2852 case ERESTARTNOINTR:
2853 case ERESTARTNOHAND:
2854 case ERESTART_RESTARTBLOCK:
2855 return 1;
2856 default:
2857 break;
2858 }
2859#endif /* LINUX */
2860 return 0;
2861}