blob: fed2fa829b729c024a526b26979b1dfbcd44bc01 [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 (!(copy = strdup(s))) {
440 fprintf(stderr, "out of memory\n");
441 exit(1);
442 }
443 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000444 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000445 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000446 if (sysent0[i].sys_flags & n)
447 qualify_one(i, opt, not, 0);
448
449#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000450 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000451 if (sysent1[i].sys_flags & n)
452 qualify_one(i, opt, not, 1);
453#endif /* SUPPORTED_PERSONALITIES >= 2 */
454
455#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000456 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000457 if (sysent2[i].sys_flags & n)
458 qualify_one(i, opt, not, 2);
459#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000460
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000461 continue;
462 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000463 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 fprintf(stderr, "strace: invalid %s `%s'\n",
465 opt->argument_name, p);
466 exit(1);
467 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000468 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000469 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000470 return;
471}
472
473static void
474dumpio(tcp)
475struct tcb *tcp;
476{
477 if (syserror(tcp))
478 return;
479 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
480 return;
Roland McGrath17352792005-06-07 23:21:26 +0000481 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000482 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000483#ifdef SYS_pread64
484 case SYS_pread64:
485#endif
486#if defined SYS_pread && SYS_pread64 != SYS_pread
487 case SYS_pread:
488#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000489#ifdef SYS_recv
490 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000491#elif defined SYS_sub_recv
492 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000493#endif
494#ifdef SYS_recvfrom
495 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000496#elif defined SYS_sub_recvfrom
497 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000498#endif
499 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
500 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
501 break;
502 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000503#ifdef SYS_pwrite64
504 case SYS_pwrite64:
505#endif
506#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
507 case SYS_pwrite:
508#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000509#ifdef SYS_send
510 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000511#elif defined SYS_sub_send
512 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000513#endif
514#ifdef SYS_sendto
515 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000516#elif defined SYS_sub_sendto
517 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000518#endif
519 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
520 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
521 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000522#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000523 case SYS_readv:
524 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
525 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
526 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000527#endif
528#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000529 case SYS_writev:
530 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
531 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
532 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000533#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534 }
535}
536
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000537#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000538enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000539#else /* FREEBSD */
540enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
541
542struct subcall {
543 int call;
544 int nsubcalls;
545 int subcalls[5];
546};
547
Roland McGratha4d48532005-06-08 20:45:28 +0000548static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000549 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000550#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000551 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000552#else
553 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
554#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000555 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
556};
557#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000558
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000559#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560
Roland McGratha4d48532005-06-08 20:45:28 +0000561static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000562decode_subcall(tcp, subcall, nsubcalls, style)
563struct tcb *tcp;
564int subcall;
565int nsubcalls;
566enum subcall_style style;
567{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000568 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000569 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000570 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000571
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572 switch (style) {
573 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000574 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
575 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 tcp->scno = subcall + tcp->u_arg[0];
577 if (sysent[tcp->scno].nargs != -1)
578 tcp->u_nargs = sysent[tcp->scno].nargs;
579 else
580 tcp->u_nargs--;
581 for (i = 0; i < tcp->u_nargs; i++)
582 tcp->u_arg[i] = tcp->u_arg[i + 1];
583 break;
584 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000585 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
586 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000587 tcp->scno = subcall + tcp->u_arg[0];
588 addr = tcp->u_arg[1];
589 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000590 if (size == sizeof(int)) {
591 unsigned int arg;
592 if (umove(tcp, addr, &arg) < 0)
593 arg = 0;
594 tcp->u_arg[i] = arg;
595 }
596 else if (size == sizeof(long)) {
597 unsigned long arg;
598 if (umove(tcp, addr, &arg) < 0)
599 arg = 0;
600 tcp->u_arg[i] = arg;
601 }
602 else
603 abort();
604 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000605 }
606 tcp->u_nargs = sysent[tcp->scno].nargs;
607 break;
608 case mask_style:
609 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000610 for (i = 0; mask; i++)
611 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000612 if (i >= nsubcalls)
613 return;
614 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615 tcp->scno = subcall + i;
616 if (sysent[tcp->scno].nargs != -1)
617 tcp->u_nargs = sysent[tcp->scno].nargs;
618 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000619 case door_style:
620 /*
621 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000622 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000623 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000624 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
625 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000626 tcp->scno = subcall + tcp->u_arg[5];
627 if (sysent[tcp->scno].nargs != -1)
628 tcp->u_nargs = sysent[tcp->scno].nargs;
629 else
630 tcp->u_nargs--;
631 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000632#ifdef FREEBSD
633 case table_style:
634 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
635 if (subcalls_table[i].call == tcp->scno) break;
636 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
637 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
638 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
639 for (i = 0; i < tcp->u_nargs; i++)
640 tcp->u_arg[i] = tcp->u_arg[i + 1];
641 }
642 break;
643#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000644 }
645}
646#endif
647
648struct tcb *tcp_last = NULL;
649
650static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000651internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000652{
653 /*
654 * We must always trace a few critical system calls in order to
655 * correctly support following forks in the presence of tracing
656 * qualifiers.
657 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000658 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000659
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000660 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
661 return 0;
662
663 func = sysent[tcp->scno].sys_func;
664
665 if (sys_exit == func)
666 return internal_exit(tcp);
667
668 if ( sys_fork == func
669#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
670 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000671#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000672#ifdef LINUX
673 || sys_clone == func
674#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000675#if UNIXWARE > 2
676 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000677#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000678 )
679 return internal_fork(tcp);
680
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000681 if ( sys_execve == func
682#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
683 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000685#if UNIXWARE > 2
686 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000687#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000688 )
689 return internal_exec(tcp);
690
691 if ( sys_waitpid == func
692 || sys_wait4 == func
693#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
694 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000695#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000696#ifdef ALPHA
697 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000698#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000699 )
700 return internal_wait(tcp, 2);
701
702#if defined(LINUX) || defined(SVR4)
703 if (sys_waitid == func)
704 return internal_wait(tcp, 3);
705#endif
706
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000707 return 0;
708}
709
Wichert Akkermanc7926982000-04-10 22:22:31 +0000710
711#ifdef LINUX
712#if defined (I386)
713 static long eax;
714#elif defined (IA64)
715 long r8, r10, psr;
716 long ia32 = 0;
717#elif defined (POWERPC)
718 static long result,flags;
719#elif defined (M68K)
Andreas Schwabffca9e32010-05-28 20:53:14 +0200720 static long d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000721#elif defined(BFIN)
722 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000723#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000724 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000725#elif defined (ALPHA)
726 static long r0;
727 static long a3;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000728#elif defined(AVR32)
729 static struct pt_regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000730#elif defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -0400731 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000732 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000733#elif defined(LINUX_MIPSN32)
734 static long long a3;
735 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000736#elif defined(MIPS)
737 static long a3;
738 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000739#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000740 static long gpr2;
741 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000742 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000743#elif defined(HPPA)
744 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000745#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000746 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000747#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000748 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000749#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000750 static long rax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000751#elif defined(CRISV10) || defined(CRISV32)
752 static long r10;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +0200753#elif defined(MICROBLAZE)
754 static long r3;
Roland McGrath761b5d72002-12-15 23:58:31 +0000755#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000756#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000757#ifdef FREEBSD
758 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000759#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000760
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000761int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000762get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000764 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000765
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000766#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000767# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000768 if (tcp->flags & TCB_WAITEXECVE) {
769 /*
770 * When the execve system call completes successfully, the
771 * new process still has -ENOSYS (old style) or __NR_execve
772 * (new style) in gpr2. We cannot recover the scno again
773 * by disassembly, because the image that executed the
774 * syscall is gone now. Fortunately, we don't want it. We
775 * leave the flag set so that syscall_fixup can fake the
776 * result.
777 */
778 if (tcp->flags & TCB_INSYSCALL)
779 return 1;
780 /*
781 * This is the SIGTRAP after execve. We cannot try to read
782 * the system call here either.
783 */
784 tcp->flags &= ~TCB_WAITEXECVE;
785 return 0;
786 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000787
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000788 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000789 return -1;
790
791 if (syscall_mode != -ENOSYS) {
792 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000793 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000794 */
795 scno = syscall_mode;
796 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000797 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000798 * Old style of "passing" the scno via the SVC instruction.
799 */
800
801 long opcode, offset_reg, tmp;
802 void * svc_addr;
803 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
804 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
805 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
806 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000807
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000808 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000809 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000810 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000811 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000812 if (errno) {
813 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000814 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000815 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000816
817 /*
818 * We have to check if the SVC got executed directly or via an
819 * EXECUTE instruction. In case of EXECUTE it is necessary to do
820 * instruction decoding to derive the system call number.
821 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
822 * so that this doesn't work if a SVC opcode is part of an EXECUTE
823 * opcode. Since there is no way to find out the opcode size this
824 * is the best we can do...
825 */
826
827 if ((opcode & 0xff00) == 0x0a00) {
828 /* SVC opcode */
829 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000830 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000831 else {
832 /* SVC got executed by EXECUTE instruction */
833
834 /*
835 * Do instruction decoding of EXECUTE. If you really want to
836 * understand this, read the Principles of Operations.
837 */
838 svc_addr = (void *) (opcode & 0xfff);
839
840 tmp = 0;
841 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000842 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000843 return -1;
844 svc_addr += tmp;
845
846 tmp = 0;
847 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000848 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000849 return -1;
850 svc_addr += tmp;
851
Denys Vlasenkofb036672009-01-23 16:30:26 +0000852 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000853 if (errno)
854 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000855# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000856 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000857# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000858 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000859# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000860 tmp = 0;
861 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000862 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000863 return -1;
864
865 scno = (scno | tmp) & 0xff;
866 }
867 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000868# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000869 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000870 return -1;
871 if (!(tcp->flags & TCB_INSYSCALL)) {
872 /* Check if we return from execve. */
873 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
874 tcp->flags &= ~TCB_WAITEXECVE;
875 return 0;
876 }
877 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200878
879# ifdef POWERPC64
880 if (!(tcp->flags & TCB_INSYSCALL)) {
881 static int currpers = -1;
882 long val;
883 int pid = tcp->pid;
884
885 /* Check for 64/32 bit mode. */
886 if (upeek(tcp, sizeof (unsigned long)*PT_MSR, &val) < 0)
887 return -1;
888 /* SF is bit 0 of MSR */
889 if (val < 0)
890 currpers = 0;
891 else
892 currpers = 1;
893 if (currpers != current_personality) {
894 static const char *const names[] = {"64 bit", "32 bit"};
895 set_personality(currpers);
896 printf("[ Process PID=%d runs in %s mode. ]\n",
897 pid, names[current_personality]);
898 }
899 }
900# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000901# elif defined(AVR32)
902 /*
903 * Read complete register set in one go.
904 */
905 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
906 return -1;
907
908 /*
909 * We only need to grab the syscall number on syscall entry.
910 */
911 if (!(tcp->flags & TCB_INSYSCALL)) {
912 scno = regs.r8;
913
914 /* Check if we return from execve. */
915 if (tcp->flags & TCB_WAITEXECVE) {
916 tcp->flags &= ~TCB_WAITEXECVE;
917 return 0;
918 }
919 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000920# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000921 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000922 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000923# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000924 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000926# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000927 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000928 return -1;
929
Roland McGrath761b5d72002-12-15 23:58:31 +0000930 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000931 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000932 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000933 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000934
935 /* Check CS register value. On x86-64 linux it is:
936 * 0x33 for long mode (64 bit)
937 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000938 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000939 * to be cached.
940 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000941 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000942 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000943 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000944 case 0x23: currpers = 1; break;
945 case 0x33: currpers = 0; break;
946 default:
947 fprintf(stderr, "Unknown value CS=0x%02X while "
948 "detecting personality of process "
949 "PID=%d\n", (int)val, pid);
950 currpers = current_personality;
951 break;
952 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000953# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000954 /* This version analyzes the opcode of a syscall instruction.
955 * (int 0x80 on i386 vs. syscall on x86-64)
956 * It works, but is too complicated.
957 */
958 unsigned long val, rip, i;
959
Denys Vlasenko8236f252009-01-02 18:10:08 +0000960 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000961 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000962
Michal Ludvig0e035502002-09-23 15:41:01 +0000963 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000964 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000965 errno = 0;
966
Denys Vlasenko8236f252009-01-02 18:10:08 +0000967 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000968 if (errno)
969 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000970 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000971 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000972 /* x86-64: syscall = 0x0f 0x05 */
973 case 0x050f: currpers = 0; break;
974 /* i386: int 0x80 = 0xcd 0x80 */
975 case 0x80cd: currpers = 1; break;
976 default:
977 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000978 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000979 "Unknown syscall opcode (0x%04X) while "
980 "detecting personality of process "
981 "PID=%d\n", (int)call, pid);
982 break;
983 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000984# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000985 if (currpers != current_personality) {
986 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000987 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000988 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000989 pid, names[current_personality]);
990 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000991 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000992# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000993# define IA64_PSR_IS ((long)1 << 34)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700994 if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000995 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000996 if (!(tcp->flags & TCB_INSYSCALL)) {
997 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000998 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000999 return -1;
1000 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001001 if (upeek (tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001002 return -1;
1003 }
Roland McGrathba954762003-03-05 06:29:06 +00001004 /* Check if we return from execve. */
1005 if (tcp->flags & TCB_WAITEXECVE) {
1006 tcp->flags &= ~TCB_WAITEXECVE;
1007 return 0;
1008 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001009 } else {
1010 /* syscall in progress */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001011 if (upeek (tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001012 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001013 if (upeek (tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001014 return -1;
1015 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001016# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001017 /*
1018 * Read complete register set in one go.
1019 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001020 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001021 return -1;
1022
1023 /*
1024 * We only need to grab the syscall number on syscall entry.
1025 */
1026 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001027 if (!(tcp->flags & TCB_INSYSCALL)) {
1028 /* Check if we return from execve. */
1029 if (tcp->flags & TCB_WAITEXECVE) {
1030 tcp->flags &= ~TCB_WAITEXECVE;
1031 return 0;
1032 }
1033 }
1034
Roland McGrath0f87c492003-06-03 23:29:04 +00001035 /*
1036 * Note: we only deal with only 32-bit CPUs here.
1037 */
1038 if (regs.ARM_cpsr & 0x20) {
1039 /*
1040 * Get the Thumb-mode system call number
1041 */
1042 scno = regs.ARM_r7;
1043 } else {
1044 /*
1045 * Get the ARM-mode system call number
1046 */
1047 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001048 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001049 if (errno)
1050 return -1;
1051
1052 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1053 tcp->flags &= ~TCB_WAITEXECVE;
1054 return 0;
1055 }
1056
Roland McGrathf691bd22006-04-25 07:34:41 +00001057 /* Handle the EABI syscall convention. We do not
1058 bother converting structures between the two
1059 ABIs, but basic functionality should work even
1060 if strace and the traced program have different
1061 ABIs. */
1062 if (scno == 0xef000000) {
1063 scno = regs.ARM_r7;
1064 } else {
1065 if ((scno & 0x0ff00000) != 0x0f900000) {
1066 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1067 scno);
1068 return -1;
1069 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001070
Roland McGrathf691bd22006-04-25 07:34:41 +00001071 /*
1072 * Fixup the syscall number
1073 */
1074 scno &= 0x000fffff;
1075 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001076 }
Roland McGrath56703312008-05-20 01:35:55 +00001077 if (scno & 0x0f0000) {
1078 /*
1079 * Handle ARM specific syscall
1080 */
1081 set_personality(1);
1082 scno &= 0x0000ffff;
1083 } else
1084 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001085
1086 if (tcp->flags & TCB_INSYSCALL) {
1087 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1088 tcp->flags &= ~TCB_INSYSCALL;
1089 }
1090 } else {
1091 if (!(tcp->flags & TCB_INSYSCALL)) {
1092 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1093 tcp->flags |= TCB_INSYSCALL;
1094 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001095 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001096# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001097 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001099# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001100 unsigned long long regs[38];
1101
Roland McGratheb9e2e82009-06-02 16:49:22 -07001102 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001103 return -1;
1104 a3 = regs[REG_A3];
1105 r2 = regs[REG_V0];
1106
1107 if(!(tcp->flags & TCB_INSYSCALL)) {
1108 scno = r2;
1109
1110 /* Check if we return from execve. */
1111 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1112 tcp->flags &= ~TCB_WAITEXECVE;
1113 return 0;
1114 }
1115
1116 if (scno < 0 || scno > nsyscalls) {
1117 if(a3 == 0 || a3 == -1) {
1118 if(debug)
1119 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1120 return 0;
1121 }
1122 }
1123 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001124# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001125 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001126 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001127 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001128 if (upeek(tcp, REG_V0, &scno) < 0)
1129 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001130
Roland McGrath542c2c62008-05-20 01:11:56 +00001131 /* Check if we return from execve. */
1132 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1133 tcp->flags &= ~TCB_WAITEXECVE;
1134 return 0;
1135 }
1136
Wichert Akkermanf90da011999-10-31 21:15:38 +00001137 if (scno < 0 || scno > nsyscalls) {
1138 if(a3 == 0 || a3 == -1) {
1139 if(debug)
1140 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1141 return 0;
1142 }
1143 }
1144 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001145 if (upeek(tcp, REG_V0, &r2) < 0)
1146 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001147 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001148# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001149 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150 return -1;
1151
1152 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001153 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001154 return -1;
1155
1156 /* Check if we return from execve. */
1157 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1158 tcp->flags &= ~TCB_WAITEXECVE;
1159 return 0;
1160 }
1161
1162 /*
1163 * Do some sanity checks to figure out if it's
1164 * really a syscall entry
1165 */
1166 if (scno < 0 || scno > nsyscalls) {
1167 if (a3 == 0 || a3 == -1) {
1168 if (debug)
1169 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1170 return 0;
1171 }
1172 }
1173 }
1174 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001175 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 return -1;
1177 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001178# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001180 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 return -1;
1182
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001183 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184 if (!(tcp->flags & TCB_INSYSCALL)) {
1185 /* Retrieve the syscall trap instruction. */
1186 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001187# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001188 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001189 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001190# else
1191 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001192# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 if (errno)
1194 return -1;
1195
1196 /* Disassemble the trap to see what personality to use. */
1197 switch (trap) {
1198 case 0x91d02010:
1199 /* Linux/SPARC syscall trap. */
1200 set_personality(0);
1201 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001202 case 0x91d0206d:
1203 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001204 set_personality(2);
1205 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001206 case 0x91d02000:
1207 /* SunOS syscall trap. (pers 1) */
1208 fprintf(stderr,"syscall: SunOS no support\n");
1209 return -1;
1210 case 0x91d02008:
1211 /* Solaris 2.x syscall trap. (per 2) */
1212 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001213 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001214 case 0x91d02009:
1215 /* NetBSD/FreeBSD syscall trap. */
1216 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1217 return -1;
1218 case 0x91d02027:
1219 /* Solaris 2.x gettimeofday */
1220 set_personality(1);
1221 break;
1222 default:
1223 /* Unknown syscall trap. */
1224 if(tcp->flags & TCB_WAITEXECVE) {
1225 tcp->flags &= ~TCB_WAITEXECVE;
1226 return 0;
1227 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001228# if defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001229 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001230# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001231 fprintf(stderr,"syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001232# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233 return -1;
1234 }
1235
1236 /* Extract the system call number from the registers. */
1237 if (trap == 0x91d02027)
1238 scno = 156;
1239 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001240 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001241 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001242 scno = regs.u_regs[U_REG_O0];
1243 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 +00001244 }
1245 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001246# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001247 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001248 return -1;
1249 if (!(tcp->flags & TCB_INSYSCALL)) {
1250 /* Check if we return from execve. */
1251 if ((tcp->flags & TCB_WAITEXECVE)) {
1252 tcp->flags &= ~TCB_WAITEXECVE;
1253 return 0;
1254 }
1255 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001256# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001257 /*
1258 * In the new syscall ABI, the system call number is in R3.
1259 */
1260 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1261 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001262
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001263 if (scno < 0) {
1264 /* Odd as it may seem, a glibc bug has been known to cause
1265 glibc to issue bogus negative syscall numbers. So for
1266 our purposes, make strace print what it *should* have been */
1267 long correct_scno = (scno & 0xff);
1268 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001269 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001270 "Detected glibc bug: bogus system call"
1271 " number = %ld, correcting to %ld\n",
1272 scno,
1273 correct_scno);
1274 scno = correct_scno;
1275 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001276
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001277 if (!(tcp->flags & TCB_INSYSCALL)) {
1278 /* Check if we return from execve. */
1279 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1280 tcp->flags &= ~TCB_WAITEXECVE;
1281 return 0;
1282 }
1283 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001284# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001285 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001286 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001287 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001288
1289 if (!(tcp->flags & TCB_INSYSCALL)) {
1290 /* Check if we return from execve. */
1291 if (tcp->flags & TCB_WAITEXECVE) {
1292 tcp->flags &= ~TCB_WAITEXECVE;
1293 return 0;
1294 }
1295 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001296# elif defined(CRISV10) || defined(CRISV32)
1297 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1298 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001299# elif defined(TILE)
1300 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1301 return -1;
1302
1303 if (!(tcp->flags & TCB_INSYSCALL)) {
1304 /* Check if we return from execve. */
1305 if (tcp->flags & TCB_WAITEXECVE) {
1306 tcp->flags &= ~TCB_WAITEXECVE;
1307 return 0;
1308 }
1309 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001310# elif defined(MICROBLAZE)
1311 if (upeek(tcp, 0, &scno) < 0)
1312 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001313# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001315
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001317 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001319#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001320 /* new syscall ABI returns result in R0 */
1321 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1322 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001323#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001324 /* ABI defines result returned in r9 */
1325 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1326 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001328
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001329#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001330# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001331 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001332# else
1333# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001334 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001335# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001336 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001337 perror("pread");
1338 return -1;
1339 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001340 switch (regs.r_eax) {
1341 case SYS_syscall:
1342 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001343 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1344 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001345 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001346 scno = regs.r_eax;
1347 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001348 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001349# endif /* FREEBSD */
1350# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001351#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001352
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001353 if (!(tcp->flags & TCB_INSYSCALL))
1354 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001355 return 1;
1356}
1357
Pavel Machek4dc3b142000-02-01 17:58:41 +00001358
Roland McGrath17352792005-06-07 23:21:26 +00001359long
1360known_scno(tcp)
1361struct tcb *tcp;
1362{
1363 long scno = tcp->scno;
1364 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1365 scno = sysent[scno].native_scno;
1366 else
1367 scno += NR_SYSCALL_BASE;
1368 return scno;
1369}
1370
Roland McGratheb9e2e82009-06-02 16:49:22 -07001371/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001372 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001373 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1374 * 1: ok, continue in trace_syscall().
1375 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001376 * ("????" etc) and bail out.
1377 */
Roland McGratha4d48532005-06-08 20:45:28 +00001378static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001379syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001380{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001381#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001382 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001383
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001384 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001385 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001386 if (
1387 scno == SYS_fork
1388#ifdef SYS_vfork
1389 || scno == SYS_vfork
1390#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001391#ifdef SYS_fork1
1392 || scno == SYS_fork1
1393#endif /* SYS_fork1 */
1394#ifdef SYS_forkall
1395 || scno == SYS_forkall
1396#endif /* SYS_forkall */
1397#ifdef SYS_rfork1
1398 || scno == SYS_rfork1
1399#endif /* SYS_fork1 */
1400#ifdef SYS_rforkall
1401 || scno == SYS_rforkall
1402#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001403 ) {
1404 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001405 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001406 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001407 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001408 }
1409 else {
1410 fprintf(stderr, "syscall: missing entry\n");
1411 tcp->flags |= TCB_INSYSCALL;
1412 }
1413 }
1414 }
1415 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001416 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001417 fprintf(stderr, "syscall: missing exit\n");
1418 tcp->flags &= ~TCB_INSYSCALL;
1419 }
1420 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001421#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001422#ifdef SUNOS4
1423 if (!(tcp->flags & TCB_INSYSCALL)) {
1424 if (scno == 0) {
1425 fprintf(stderr, "syscall: missing entry\n");
1426 tcp->flags |= TCB_INSYSCALL;
1427 }
1428 }
1429 else {
1430 if (scno != 0) {
1431 if (debug) {
1432 /*
1433 * This happens when a signal handler
1434 * for a signal which interrupted a
1435 * a system call makes another system call.
1436 */
1437 fprintf(stderr, "syscall: missing exit\n");
1438 }
1439 tcp->flags &= ~TCB_INSYSCALL;
1440 }
1441 }
1442#endif /* SUNOS4 */
1443#ifdef LINUX
1444#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001445 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001446 return -1;
1447 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1448 if (debug)
1449 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1450 return 0;
1451 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001452#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001453 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001454 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001455 if (current_personality == 1)
1456 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001457 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1458 if (debug)
1459 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1460 return 0;
1461 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001462#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001463 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001464 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001465 if (syscall_mode != -ENOSYS)
1466 syscall_mode = tcp->scno;
1467 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001468 if (debug)
1469 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1470 return 0;
1471 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001472 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1473 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1474 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1475 /*
1476 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1477 * flag set for the post-execve SIGTRAP to see and reset.
1478 */
1479 gpr2 = 0;
1480 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001481#elif defined (POWERPC)
1482# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001483 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001484 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001485 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486 return -1;
1487 if (flags & SO_MASK)
1488 result = -result;
1489#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001490 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001491 return -1;
1492 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1493 if (debug)
1494 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1495 return 0;
1496 }
1497#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001498 /*
1499 * Nothing required
1500 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001501#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001502 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001503 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001504#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001505 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001506 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001507#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001508 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001509 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001510 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001511 return -1;
1512 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1513 if (debug)
1514 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1515 return 0;
1516 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001517#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001518 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001519 return -1;
1520 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1521 if (debug)
1522 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1523 return 0;
1524 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001525#elif defined(MICROBLAZE)
1526 if (upeek(tcp, 3 * 4, &r3) < 0)
1527 return -1;
1528 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1529 if (debug)
1530 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1531 return 0;
1532 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001533#endif
1534#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001535 return 1;
1536}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001537
Roland McGrathc1e45922008-05-27 23:18:29 +00001538#ifdef LINUX
1539/*
1540 * Check the syscall return value register value for whether it is
1541 * a negated errno code indicating an error, or a success return value.
1542 */
1543static inline int
1544is_negated_errno(unsigned long int val)
1545{
1546 unsigned long int max = -(long int) nerrnos;
1547 if (personality_wordsize[current_personality] < sizeof(val)) {
1548 val = (unsigned int) val;
1549 max = (unsigned int) max;
1550 }
1551 return val > max;
1552}
1553#endif
1554
Roland McGratha4d48532005-06-08 20:45:28 +00001555static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001556get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001557{
1558 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001559#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001560# if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001561 if (is_negated_errno(gpr2)) {
1562 tcp->u_rval = -1;
1563 u_error = -gpr2;
1564 }
1565 else {
1566 tcp->u_rval = gpr2;
1567 u_error = 0;
1568 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001569# elif defined(I386)
Roland McGrathc1e45922008-05-27 23:18:29 +00001570 if (is_negated_errno(eax)) {
1571 tcp->u_rval = -1;
1572 u_error = -eax;
1573 }
1574 else {
1575 tcp->u_rval = eax;
1576 u_error = 0;
1577 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001578# elif defined(X86_64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001579 if (is_negated_errno(rax)) {
1580 tcp->u_rval = -1;
1581 u_error = -rax;
1582 }
1583 else {
1584 tcp->u_rval = rax;
1585 u_error = 0;
1586 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001587# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001588 if (ia32) {
1589 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001590
Roland McGrathc1e45922008-05-27 23:18:29 +00001591 err = (int)r8;
1592 if (is_negated_errno(err)) {
1593 tcp->u_rval = -1;
1594 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001595 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001596 else {
1597 tcp->u_rval = err;
1598 u_error = 0;
1599 }
1600 } else {
1601 if (r10) {
1602 tcp->u_rval = -1;
1603 u_error = r8;
1604 } else {
1605 tcp->u_rval = r8;
1606 u_error = 0;
1607 }
1608 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001609# elif defined(MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001610 if (a3) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001611 tcp->u_rval = -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001612 u_error = r2;
1613 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001614 tcp->u_rval = r2;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001615 u_error = 0;
1616 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001617# elif defined(POWERPC)
Roland McGrathc1e45922008-05-27 23:18:29 +00001618 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619 tcp->u_rval = -1;
1620 u_error = -result;
1621 }
1622 else {
1623 tcp->u_rval = result;
1624 u_error = 0;
1625 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001626# elif defined(M68K)
Roland McGrathc1e45922008-05-27 23:18:29 +00001627 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 tcp->u_rval = -1;
1629 u_error = -d0;
1630 }
1631 else {
1632 tcp->u_rval = d0;
1633 u_error = 0;
1634 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001635# elif defined(ARM)
Roland McGrathc1e45922008-05-27 23:18:29 +00001636 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001637 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001638 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639 }
1640 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001641 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642 u_error = 0;
1643 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001644# elif defined(AVR32)
1645 if (regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1646 tcp->u_rval = -1;
1647 u_error = -regs.r12;
1648 }
1649 else {
1650 tcp->u_rval = regs.r12;
1651 u_error = 0;
1652 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001653# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001654 if (is_negated_errno(r0)) {
1655 tcp->u_rval = -1;
1656 u_error = -r0;
1657 } else {
1658 tcp->u_rval = r0;
1659 u_error = 0;
1660 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001661# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001662 if (a3) {
1663 tcp->u_rval = -1;
1664 u_error = r0;
1665 }
1666 else {
1667 tcp->u_rval = r0;
1668 u_error = 0;
1669 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001670# elif defined(SPARC)
Mike Frysinger8566c502009-10-12 11:05:14 -04001671 if (regs.psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001672 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001673 u_error = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674 }
1675 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001676 tcp->u_rval = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677 u_error = 0;
1678 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001679# elif defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001680 if (regs.tstate & 0x1100000000UL) {
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001681 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001682 u_error = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001683 }
1684 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001685 tcp->u_rval = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001686 u_error = 0;
1687 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001688# elif defined(HPPA)
Roland McGrathc1e45922008-05-27 23:18:29 +00001689 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001690 tcp->u_rval = -1;
1691 u_error = -r28;
1692 }
1693 else {
1694 tcp->u_rval = r28;
1695 u_error = 0;
1696 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001697# elif defined(SH)
Roland McGrathc1e45922008-05-27 23:18:29 +00001698 /* interpret R0 as return value or error number */
1699 if (is_negated_errno(r0)) {
1700 tcp->u_rval = -1;
1701 u_error = -r0;
1702 }
1703 else {
1704 tcp->u_rval = r0;
1705 u_error = 0;
1706 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001707# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001708 /* interpret result as return value or error number */
1709 if (is_negated_errno(r9)) {
1710 tcp->u_rval = -1;
1711 u_error = -r9;
1712 }
1713 else {
1714 tcp->u_rval = r9;
1715 u_error = 0;
1716 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001717# elif defined(CRISV10) || defined(CRISV32)
1718 if (r10 && (unsigned) -r10 < nerrnos) {
1719 tcp->u_rval = -1;
1720 u_error = -r10;
1721 }
1722 else {
1723 tcp->u_rval = r10;
1724 u_error = 0;
1725 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001726# elif defined(TILE)
1727 long rval;
1728 /* interpret result as return value or error number */
1729 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1730 return -1;
1731 if (rval < 0 && rval > -nerrnos) {
1732 tcp->u_rval = -1;
1733 u_error = -rval;
1734 }
1735 else {
1736 tcp->u_rval = rval;
1737 u_error = 0;
1738 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001739# elif defined(MICROBLAZE)
1740 /* interpret result as return value or error number */
1741 if (is_negated_errno(r3)) {
1742 tcp->u_rval = -1;
1743 u_error = -r3;
1744 }
1745 else {
1746 tcp->u_rval = r3;
1747 u_error = 0;
1748 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001749# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001750#endif /* LINUX */
1751#ifdef SUNOS4
1752 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001753 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001754 return -1;
1755 u_error >>= 24; /* u_error is a char */
1756
1757 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001758 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001759 return -1;
1760#endif /* SUNOS4 */
1761#ifdef SVR4
1762#ifdef SPARC
1763 /* Judicious guessing goes a long way. */
1764 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1765 tcp->u_rval = -1;
1766 u_error = tcp->status.pr_reg[R_O0];
1767 }
1768 else {
1769 tcp->u_rval = tcp->status.pr_reg[R_O0];
1770 u_error = 0;
1771 }
1772#endif /* SPARC */
1773#ifdef I386
1774 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001775 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001776 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001777 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001778 }
1779 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001780 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001781#ifdef HAVE_LONG_LONG
1782 tcp->u_lrval =
1783 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1784 tcp->status.PR_REG[EAX];
1785#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001786 u_error = 0;
1787 }
1788#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001789#ifdef X86_64
1790 /* Wanna know how to kill an hour single-stepping? */
1791 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1792 tcp->u_rval = -1;
1793 u_error = tcp->status.PR_REG[RAX];
1794 }
1795 else {
1796 tcp->u_rval = tcp->status.PR_REG[RAX];
1797 u_error = 0;
1798 }
1799#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001800#ifdef MIPS
1801 if (tcp->status.pr_reg[CTX_A3]) {
1802 tcp->u_rval = -1;
1803 u_error = tcp->status.pr_reg[CTX_V0];
1804 }
1805 else {
1806 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1807 u_error = 0;
1808 }
1809#endif /* MIPS */
1810#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001811#ifdef FREEBSD
1812 if (regs.r_eflags & PSL_C) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001813 tcp->u_rval = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001814 u_error = regs.r_eax;
1815 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001816 tcp->u_rval = regs.r_eax;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001817 tcp->u_lrval =
1818 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1819 u_error = 0;
1820 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001821#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001822 tcp->u_error = u_error;
1823 return 1;
1824}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001825
Roland McGrathb69f81b2002-12-21 23:25:18 +00001826int
1827force_result(tcp, error, rval)
1828 struct tcb *tcp;
1829 int error;
1830 long rval;
1831{
1832#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001833# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001834 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001835 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1836 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001837# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001838 eax = error ? -error : rval;
1839 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1840 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001841# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001842 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001843 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001844 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001845# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001846 if (ia32) {
1847 r8 = error ? -error : rval;
1848 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1849 return -1;
1850 }
1851 else {
1852 if (error) {
1853 r8 = error;
1854 r10 = -1;
1855 }
1856 else {
1857 r8 = rval;
1858 r10 = 0;
1859 }
1860 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1861 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1862 return -1;
1863 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001864# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001865 r0 = error ? -error : rval;
1866 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1867 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001868# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001869 if (error) {
1870 r2 = error;
1871 a3 = -1;
1872 }
1873 else {
1874 r2 = rval;
1875 a3 = 0;
1876 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001877 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001878 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1879 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001880 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001881# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001882 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001883 return -1;
1884 if (error) {
1885 flags |= SO_MASK;
1886 result = error;
1887 }
1888 else {
1889 flags &= ~SO_MASK;
1890 result = rval;
1891 }
Roland McGratheb285352003-01-14 09:59:00 +00001892 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1893 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001894 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001895# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001896 d0 = error ? -error : rval;
1897 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1898 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001899# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001900 regs.ARM_r0 = error ? -error : rval;
1901 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001902 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001903# elif defined(AVR32)
1904 regs.r12 = error ? -error : rval;
1905 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1906 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001907# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001908 if (error) {
1909 a3 = -1;
1910 r0 = error;
1911 }
1912 else {
1913 a3 = 0;
1914 r0 = rval;
1915 }
1916 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1917 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1918 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001919# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001920 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1921 return -1;
1922 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001923 regs.psr |= PSR_C;
1924 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001925 }
1926 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001927 regs.psr &= ~PSR_C;
1928 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001929 }
1930 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1931 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001932# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001933 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1934 return -1;
1935 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001936 regs.tstate |= 0x1100000000UL;
1937 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001938 }
1939 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001940 regs.tstate &= ~0x1100000000UL;
1941 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001942 }
1943 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1944 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001945# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001946 r28 = error ? -error : rval;
1947 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1948 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001949# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001950 r0 = error ? -error : rval;
1951 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1952 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001953# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001954 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001955 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1956 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001957# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001958#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001959
Roland McGrathb69f81b2002-12-21 23:25:18 +00001960#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001961 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1962 error << 24) < 0 ||
1963 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001964 return -1;
1965#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001966
Roland McGrathb69f81b2002-12-21 23:25:18 +00001967#ifdef SVR4
1968 /* XXX no clue */
1969 return -1;
1970#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001971
Roland McGrathb69f81b2002-12-21 23:25:18 +00001972#ifdef FREEBSD
1973 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001974 perror("pread");
1975 return -1;
1976 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001977 if (error) {
1978 regs.r_eflags |= PSL_C;
1979 regs.r_eax = error;
1980 }
1981 else {
1982 regs.r_eflags &= ~PSL_C;
1983 regs.r_eax = rval;
1984 }
1985 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001986 perror("pwrite");
1987 return -1;
1988 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001989#endif /* FREEBSD */
1990
1991 /* All branches reach here on success (only). */
1992 tcp->u_error = error;
1993 tcp->u_rval = rval;
1994 return 0;
1995}
1996
Roland McGratha4d48532005-06-08 20:45:28 +00001997static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001998syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001999{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002000#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00002001#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002002 {
2003 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002004 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2005 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002006 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002007 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002008 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002009 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002010 return -1;
2011 }
2012 }
2013#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002014 {
2015 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002016 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2017 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002018 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002019 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002020 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00002021 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2022 * for scno somewhere above here!
2023 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002024 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002025 return -1;
2026 }
2027 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002028#elif defined (IA64)
2029 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002030 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002031 unsigned long *out0, cfm, sof, sol, i;
2032 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002033 /* be backwards compatible with kernel < 2.4.4... */
2034# ifndef PT_RBS_END
2035# define PT_RBS_END PT_AR_BSP
2036# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002037
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002038 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002039 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002040 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002041 return -1;
2042
2043 sof = (cfm >> 0) & 0x7f;
2044 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002045 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002046
2047 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2048 && sysent[tcp->scno].nargs != -1)
2049 tcp->u_nargs = sysent[tcp->scno].nargs;
2050 else
2051 tcp->u_nargs = MAX_ARGS;
2052 for (i = 0; i < tcp->u_nargs; ++i) {
2053 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2054 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2055 return -1;
2056 }
2057 } else {
2058 int i;
2059
2060 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002061 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002062 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002063 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002064 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002065 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002066 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002067 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002068 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002069 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002070 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002071 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002072 return -1;
2073
2074 for (i = 0; i < 6; ++i)
2075 /* truncate away IVE sign-extension */
2076 tcp->u_arg[i] &= 0xffffffff;
2077
2078 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2079 && sysent[tcp->scno].nargs != -1)
2080 tcp->u_nargs = sysent[tcp->scno].nargs;
2081 else
2082 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002083 }
2084 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002085#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2086 /* N32 and N64 both use up to six registers. */
2087 {
2088 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002089 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002090
2091 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2092 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002093 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002094 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002095
David Daney20037042010-02-09 21:22:30 +00002096 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002097 return -1;
2098
Roland McGratheb9e2e82009-06-02 16:49:22 -07002099 for(i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002100 tcp->u_arg[i] = regs[REG_A0 + i];
2101# if defined (LINUX_MIPSN32)
2102 tcp->ext_arg[i] = regs[REG_A0 + i];
2103# endif
2104 }
2105 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002106#elif defined (MIPS)
2107 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002108 long sp;
2109 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002110
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002111 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2112 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002113 else
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002114 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002115 if(nargs > 4) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002116 if(upeek(tcp, REG_SP, &sp) < 0)
2117 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002118 for(i = 0; i < 4; i++) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002119 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
2120 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002121 }
2122 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2123 (char *)(tcp->u_arg + 4));
2124 } else {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002125 for(i = 0; i < nargs; i++) {
2126 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2127 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002128 }
2129 }
2130 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002131#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002132# ifndef PT_ORIG_R3
2133# define PT_ORIG_R3 34
2134# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002135 {
2136 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002137 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2138 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002139 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002140 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002141 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002142 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002143 (sizeof(unsigned long)*PT_ORIG_R3) :
2144 ((i+PT_R3)*sizeof(unsigned long)),
2145 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002146 return -1;
2147 }
2148 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002149#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002150 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002151 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002152
2153 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2154 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002155 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002156 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002157 for (i = 0; i < tcp->u_nargs; i++)
Mike Frysinger8566c502009-10-12 11:05:14 -04002158 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002159 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002160#elif defined (HPPA)
2161 {
2162 int i;
2163
2164 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2165 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002166 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002167 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002168 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002169 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002170 return -1;
2171 }
2172 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002173#elif defined(ARM)
2174 {
2175 int i;
2176
2177 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2178 tcp->u_nargs = sysent[tcp->scno].nargs;
2179 else
2180 tcp->u_nargs = MAX_ARGS;
2181 for (i = 0; i < tcp->u_nargs; i++)
2182 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002183 }
2184#elif defined(AVR32)
2185 tcp->u_nargs = sysent[tcp->scno].nargs;
2186 tcp->u_arg[0] = regs.r12;
2187 tcp->u_arg[1] = regs.r11;
2188 tcp->u_arg[2] = regs.r10;
2189 tcp->u_arg[3] = regs.r9;
2190 tcp->u_arg[4] = regs.r5;
2191 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002192#elif defined(BFIN)
2193 {
2194 int i;
2195 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2196
2197 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2198 tcp->u_nargs = sysent[tcp->scno].nargs;
2199 else
2200 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2201
2202 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002203 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002204 return -1;
2205 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002206#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002207 {
2208 int i;
2209 static int syscall_regs[] = {
2210 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2211 REG_REG0, REG_REG0+1, REG_REG0+2
2212 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002213
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002214 tcp->u_nargs = sysent[tcp->scno].nargs;
2215 for (i = 0; i < tcp->u_nargs; i++) {
2216 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2217 return -1;
2218 }
2219 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002220#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002221 {
2222 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002223 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002224 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2225
2226 /*
2227 * TODO: should also check that the number of arguments encoded
2228 * in the trap number matches the number strace expects.
2229 */
2230 /*
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002231 assert(sysent[tcp->scno].nargs <
2232 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
Roland McGrathe1e584b2003-06-02 19:18:58 +00002233 */
2234
2235 tcp->u_nargs = sysent[tcp->scno].nargs;
2236 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002237 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002238 return -1;
2239 }
2240 }
2241
Michal Ludvig0e035502002-09-23 15:41:01 +00002242#elif defined(X86_64)
2243 {
2244 int i;
2245 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2246 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002247 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002248 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002249
Michal Ludvig0e035502002-09-23 15:41:01 +00002250 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2251 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002252 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002253 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002254 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002255 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002256 return -1;
2257 }
2258 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002259#elif defined(MICROBLAZE)
2260 {
2261 int i;
2262 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2263 tcp->u_nargs = sysent[tcp->scno].nargs;
2264 else
2265 tcp->u_nargs = 0;
2266 for (i = 0; i < tcp->u_nargs; i++) {
2267 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2268 return -1;
2269 }
2270 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002271#elif defined(CRISV10) || defined(CRISV32)
2272 {
2273 int i;
2274 static const int crisregs[] = {
2275 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2276 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2277 };
2278
2279 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2280 tcp->u_nargs = sysent[tcp->scno].nargs;
2281 else
2282 tcp->u_nargs = 0;
2283 for (i = 0; i < tcp->u_nargs; i++) {
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00002284 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002285 return -1;
2286 }
2287 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05002288#elif defined(TILE)
2289 {
2290 int i;
2291 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2292 tcp->u_nargs = sysent[tcp->scno].nargs;
2293 else
2294 tcp->u_nargs = MAX_ARGS;
2295 for (i = 0; i < tcp->u_nargs; ++i) {
2296 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2297 return -1;
2298 }
2299 }
Andreas Schwab246888d2010-06-05 21:50:30 +02002300#elif defined (M68K)
2301 {
2302 int i;
2303 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2304 tcp->u_nargs = sysent[tcp->scno].nargs;
2305 else
2306 tcp->u_nargs = MAX_ARGS;
2307 for (i = 0; i < tcp->u_nargs; i++) {
2308 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2309 return -1;
2310 }
2311 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002312#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002313 {
2314 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002315 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2316 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002317 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002318 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002319 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002320 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002321 return -1;
2322 }
2323 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002324#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002325#endif /* LINUX */
2326#ifdef SUNOS4
2327 {
2328 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002329 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2330 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002331 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002332 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002333 for (i = 0; i < tcp->u_nargs; i++) {
2334 struct user *u;
2335
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002336 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002337 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2338 return -1;
2339 }
2340 }
2341#endif /* SUNOS4 */
2342#ifdef SVR4
2343#ifdef MIPS
2344 /*
2345 * SGI is broken: even though it has pr_sysarg, it doesn't
2346 * set them on system call entry. Get a clue.
2347 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002348 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002349 tcp->u_nargs = sysent[tcp->scno].nargs;
2350 else
2351 tcp->u_nargs = tcp->status.pr_nsysarg;
2352 if (tcp->u_nargs > 4) {
2353 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2354 4*sizeof(tcp->u_arg[0]));
2355 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2356 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2357 }
2358 else {
2359 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2360 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2361 }
John Hughes25299712001-03-06 10:10:06 +00002362#elif UNIXWARE >= 2
2363 /*
2364 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2365 */
2366 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2367 tcp->u_nargs = sysent[tcp->scno].nargs;
2368 else
2369 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2370 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2371 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2372#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002373 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002374 tcp->u_nargs = sysent[tcp->scno].nargs;
2375 else
2376 tcp->u_nargs = tcp->status.pr_nsysarg;
2377 {
2378 int i;
2379 for (i = 0; i < tcp->u_nargs; i++)
2380 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2381 }
John Hughes25299712001-03-06 10:10:06 +00002382#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002383 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002384 tcp->u_nargs = sysent[tcp->scno].nargs;
2385 else
2386 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002387 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002388 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002389#else
2390 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002391#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002392#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002393#ifdef FREEBSD
2394 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2395 sysent[tcp->scno].nargs > tcp->status.val)
2396 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002397 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002398 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002399 if (tcp->u_nargs < 0)
2400 tcp->u_nargs = 0;
2401 if (tcp->u_nargs > MAX_ARGS)
2402 tcp->u_nargs = MAX_ARGS;
2403 switch(regs.r_eax) {
2404 case SYS___syscall:
2405 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2406 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002407 break;
2408 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002409 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2410 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002411 break;
2412 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002413 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2414 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002415 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002416 }
2417#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002418 return 1;
2419}
2420
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002421static int
2422trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002423{
2424 int sys_res;
2425 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002426 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002427 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002428
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002429 /* Measure the exit time as early as possible to avoid errors. */
2430 if (dtime || cflag)
2431 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002432
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002433 /* BTW, why we don't just memorize syscall no. on entry
2434 * in tcp->something?
2435 */
2436 scno_good = res = get_scno(tcp);
2437 if (res == 0)
2438 return res;
2439 if (res == 1)
2440 res = syscall_fixup(tcp);
2441 if (res == 0)
2442 return res;
2443 if (res == 1)
2444 res = get_error(tcp);
2445 if (res == 0)
2446 return res;
2447 if (res == 1)
2448 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002449
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002450 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
2451 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002452 tcp->flags &= ~TCB_INSYSCALL;
2453 return 0;
2454 }
2455
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002456 if (tcp->flags & TCB_REPRINT) {
2457 printleader(tcp);
2458 tprintf("<... ");
2459 if (scno_good != 1)
2460 tprintf("????");
2461 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2462 tprintf("syscall_%lu", tcp->scno);
2463 else
2464 tprintf("%s", sysent[tcp->scno].sys_name);
2465 tprintf(" resumed> ");
2466 }
2467
2468 if (cflag) {
2469 struct timeval t = tv;
2470 int rc = count_syscall(tcp, &t);
2471 if (cflag == CFLAG_ONLY_STATS)
2472 {
2473 tcp->flags &= ~TCB_INSYSCALL;
2474 return rc;
2475 }
2476 }
2477
2478 if (res != 1) {
2479 tprintf(") ");
2480 tabto(acolumn);
2481 tprintf("= ? <unavailable>");
2482 printtrailer();
2483 tcp->flags &= ~TCB_INSYSCALL;
2484 return res;
2485 }
2486
2487 if (tcp->scno >= nsyscalls || tcp->scno < 0
2488 || (qual_flags[tcp->scno] & QUAL_RAW))
2489 sys_res = printargs(tcp);
2490 else {
2491 if (not_failing_only && tcp->u_error)
2492 return 0; /* ignore failed syscalls */
2493 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2494 }
2495
2496 u_error = tcp->u_error;
2497 tprintf(") ");
2498 tabto(acolumn);
2499 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2500 qual_flags[tcp->scno] & QUAL_RAW) {
2501 if (u_error)
2502 tprintf("= -1 (errno %ld)", u_error);
2503 else
2504 tprintf("= %#lx", tcp->u_rval);
2505 }
2506 else if (!(sys_res & RVAL_NONE) && u_error) {
2507 switch (u_error) {
2508#ifdef LINUX
2509 case ERESTARTSYS:
2510 tprintf("= ? ERESTARTSYS (To be restarted)");
2511 break;
2512 case ERESTARTNOINTR:
2513 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2514 break;
2515 case ERESTARTNOHAND:
2516 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2517 break;
2518 case ERESTART_RESTARTBLOCK:
2519 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2520 break;
2521#endif /* LINUX */
2522 default:
2523 tprintf("= -1 ");
2524 if (u_error < 0)
2525 tprintf("E??? (errno %ld)", u_error);
2526 else if (u_error < nerrnos)
2527 tprintf("%s (%s)", errnoent[u_error],
2528 strerror(u_error));
2529 else
2530 tprintf("ERRNO_%ld (%s)", u_error,
2531 strerror(u_error));
2532 break;
2533 }
2534 if ((sys_res & RVAL_STR) && tcp->auxstr)
2535 tprintf(" (%s)", tcp->auxstr);
2536 }
2537 else {
2538 if (sys_res & RVAL_NONE)
2539 tprintf("= ?");
2540 else {
2541 switch (sys_res & RVAL_MASK) {
2542 case RVAL_HEX:
2543 tprintf("= %#lx", tcp->u_rval);
2544 break;
2545 case RVAL_OCTAL:
2546 tprintf("= %#lo", tcp->u_rval);
2547 break;
2548 case RVAL_UDECIMAL:
2549 tprintf("= %lu", tcp->u_rval);
2550 break;
2551 case RVAL_DECIMAL:
2552 tprintf("= %ld", tcp->u_rval);
2553 break;
2554#ifdef HAVE_LONG_LONG
2555 case RVAL_LHEX:
2556 tprintf("= %#llx", tcp->u_lrval);
2557 break;
2558 case RVAL_LOCTAL:
2559 tprintf("= %#llo", tcp->u_lrval);
2560 break;
2561 case RVAL_LUDECIMAL:
2562 tprintf("= %llu", tcp->u_lrval);
2563 break;
2564 case RVAL_LDECIMAL:
2565 tprintf("= %lld", tcp->u_lrval);
2566 break;
2567#endif
2568 default:
2569 fprintf(stderr,
2570 "invalid rval format\n");
2571 break;
2572 }
2573 }
2574 if ((sys_res & RVAL_STR) && tcp->auxstr)
2575 tprintf(" (%s)", tcp->auxstr);
2576 }
2577 if (dtime) {
2578 tv_sub(&tv, &tv, &tcp->etime);
2579 tprintf(" <%ld.%06ld>",
2580 (long) tv.tv_sec, (long) tv.tv_usec);
2581 }
2582 printtrailer();
2583
2584 dumpio(tcp);
2585 if (fflush(tcp->outf) == EOF)
2586 return -1;
2587 tcp->flags &= ~TCB_INSYSCALL;
2588 return 0;
2589}
2590
2591static int
2592trace_syscall_entering(struct tcb *tcp)
2593{
2594 int sys_res;
2595 int res, scno_good;
2596
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002597 scno_good = res = get_scno(tcp);
2598 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002599 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002600 if (res == 1)
2601 res = syscall_fixup(tcp);
2602 if (res == 0)
2603 return res;
2604 if (res == 1)
2605 res = syscall_enter(tcp);
2606 if (res == 0)
2607 return res;
2608
2609 if (res != 1) {
2610 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002611 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002612 tcp_last = tcp;
2613 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002614 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002615 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2616 tprintf("syscall_%lu(", tcp->scno);
2617 else
2618 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002619 /*
2620 * " <unavailable>" will be added later by the code which
2621 * detects ptrace errors.
2622 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002623 tcp->flags |= TCB_INSYSCALL;
2624 return res;
2625 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002626
Roland McGrath17352792005-06-07 23:21:26 +00002627 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002628#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002629 case SYS_socketcall:
2630 decode_subcall(tcp, SYS_socket_subcall,
2631 SYS_socket_nsubcalls, deref_style);
2632 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002633#endif
2634#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002635 case SYS_ipc:
2636 decode_subcall(tcp, SYS_ipc_subcall,
2637 SYS_ipc_nsubcalls, shift_style);
2638 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002639#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002640#ifdef SVR4
2641#ifdef SYS_pgrpsys_subcall
2642 case SYS_pgrpsys:
2643 decode_subcall(tcp, SYS_pgrpsys_subcall,
2644 SYS_pgrpsys_nsubcalls, shift_style);
2645 break;
2646#endif /* SYS_pgrpsys_subcall */
2647#ifdef SYS_sigcall_subcall
2648 case SYS_sigcall:
2649 decode_subcall(tcp, SYS_sigcall_subcall,
2650 SYS_sigcall_nsubcalls, mask_style);
2651 break;
2652#endif /* SYS_sigcall_subcall */
2653 case SYS_msgsys:
2654 decode_subcall(tcp, SYS_msgsys_subcall,
2655 SYS_msgsys_nsubcalls, shift_style);
2656 break;
2657 case SYS_shmsys:
2658 decode_subcall(tcp, SYS_shmsys_subcall,
2659 SYS_shmsys_nsubcalls, shift_style);
2660 break;
2661 case SYS_semsys:
2662 decode_subcall(tcp, SYS_semsys_subcall,
2663 SYS_semsys_nsubcalls, shift_style);
2664 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002665 case SYS_sysfs:
2666 decode_subcall(tcp, SYS_sysfs_subcall,
2667 SYS_sysfs_nsubcalls, shift_style);
2668 break;
2669 case SYS_spcall:
2670 decode_subcall(tcp, SYS_spcall_subcall,
2671 SYS_spcall_nsubcalls, shift_style);
2672 break;
2673#ifdef SYS_context_subcall
2674 case SYS_context:
2675 decode_subcall(tcp, SYS_context_subcall,
2676 SYS_context_nsubcalls, shift_style);
2677 break;
2678#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002679#ifdef SYS_door_subcall
2680 case SYS_door:
2681 decode_subcall(tcp, SYS_door_subcall,
2682 SYS_door_nsubcalls, door_style);
2683 break;
2684#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002685#ifdef SYS_kaio_subcall
2686 case SYS_kaio:
2687 decode_subcall(tcp, SYS_kaio_subcall,
2688 SYS_kaio_nsubcalls, shift_style);
2689 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002690#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002691#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002692#ifdef FREEBSD
2693 case SYS_msgsys:
2694 case SYS_shmsys:
2695 case SYS_semsys:
2696 decode_subcall(tcp, 0, 0, table_style);
2697 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002698#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002699#ifdef SUNOS4
2700 case SYS_semsys:
2701 decode_subcall(tcp, SYS_semsys_subcall,
2702 SYS_semsys_nsubcalls, shift_style);
2703 break;
2704 case SYS_msgsys:
2705 decode_subcall(tcp, SYS_msgsys_subcall,
2706 SYS_msgsys_nsubcalls, shift_style);
2707 break;
2708 case SYS_shmsys:
2709 decode_subcall(tcp, SYS_shmsys_subcall,
2710 SYS_shmsys_nsubcalls, shift_style);
2711 break;
2712#endif
2713 }
2714
2715 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002716 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002717 tcp->flags |= TCB_INSYSCALL;
2718 return 0;
2719 }
2720
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002721 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002722 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002723 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002724 return 0;
2725 }
2726
2727 printleader(tcp);
2728 tcp->flags &= ~TCB_REPRINT;
2729 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002730 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002731 tprintf("syscall_%lu(", tcp->scno);
2732 else
2733 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002734 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002735 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2736 sys_res = printargs(tcp);
2737 else
2738 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2739 if (fflush(tcp->outf) == EOF)
2740 return -1;
2741 tcp->flags |= TCB_INSYSCALL;
2742 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002743 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002744 gettimeofday(&tcp->etime, NULL);
2745 return sys_res;
2746}
2747
2748int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002749trace_syscall(struct tcb *tcp)
2750{
2751 return exiting(tcp) ?
2752 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2753}
2754
2755int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002756printargs(tcp)
2757struct tcb *tcp;
2758{
2759 if (entering(tcp)) {
2760 int i;
2761
2762 for (i = 0; i < tcp->u_nargs; i++)
2763 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2764 }
2765 return 0;
2766}
2767
2768long
2769getrval2(tcp)
2770struct tcb *tcp;
2771{
2772 long val = -1;
2773
2774#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002775#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002776 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002777 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002778 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002779 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002780#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002781 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002782 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002783#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002784 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002785 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002786#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002787#endif /* LINUX */
2788
2789#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002790 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002791 return -1;
2792#endif /* SUNOS4 */
2793
2794#ifdef SVR4
2795#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002796 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002797#endif /* SPARC */
2798#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002799 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002800#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002801#ifdef X86_64
2802 val = tcp->status.PR_REG[RDX];
2803#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002804#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002805 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002806#endif /* MIPS */
2807#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002808
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002809#ifdef FREEBSD
2810 struct reg regs;
2811 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2812 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002813#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002814 return val;
2815}
2816
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002817#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002818/*
2819 * Apparently, indirect system calls have already be converted by ptrace(2),
2820 * so if you see "indir" this program has gone astray.
2821 */
2822int
2823sys_indir(tcp)
2824struct tcb *tcp;
2825{
2826 int i, scno, nargs;
2827
2828 if (entering(tcp)) {
2829 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2830 fprintf(stderr, "Bogus syscall: %u\n", scno);
2831 return 0;
2832 }
2833 nargs = sysent[scno].nargs;
2834 tprintf("%s", sysent[scno].sys_name);
2835 for (i = 0; i < nargs; i++)
2836 tprintf(", %#lx", tcp->u_arg[i+1]);
2837 }
2838 return 0;
2839}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002840#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002841
2842int
2843is_restart_error(struct tcb *tcp)
2844{
2845#ifdef LINUX
2846 if (!syserror(tcp))
2847 return 0;
2848 switch (tcp->u_error) {
2849 case ERESTARTSYS:
2850 case ERESTARTNOINTR:
2851 case ERESTARTNOHAND:
2852 case ERESTART_RESTARTBLOCK:
2853 return 1;
2854 default:
2855 break;
2856 }
2857#endif /* LINUX */
2858 return 0;
2859}