blob: 38f628b682575998397f0fa434888c022122c7e7 [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;
241 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000242 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000243 char *argument_name;
244} 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
Roland McGrath9797ceb2002-12-30 10:23:00 +0000302qual_syscall(s, opt, not)
303 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000304 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000305 int not;
306{
307 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000308 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000309
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000310 if (isdigit((unsigned char)*s)) {
311 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000312 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000313 return -1;
314 qualify_one(i, opt, not, -1);
315 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000316 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000317 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000318 if (strcmp(s, sysent0[i].sys_name) == 0) {
319 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000320 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000321 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000322
323#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000324 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000325 if (strcmp(s, sysent1[i].sys_name) == 0) {
326 qualify_one(i, opt, not, 1);
327 rc = 0;
328 }
329#endif /* SUPPORTED_PERSONALITIES >= 2 */
330
331#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000332 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 if (strcmp(s, sysent2[i].sys_name) == 0) {
334 qualify_one(i, opt, not, 2);
335 rc = 0;
336 }
337#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000338
Roland McGrathfe6b3522005-02-02 04:40:11 +0000339 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000340}
341
342static int
343qual_signal(s, opt, not)
344 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000345 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000346 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000347{
348 int i;
349 char buf[32];
350
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000351 if (isdigit((unsigned char)*s)) {
352 int signo = atoi(s);
353 if (signo < 0 || signo >= MAX_QUALS)
354 return -1;
355 qualify_one(signo, opt, not, -1);
356 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000357 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000358 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000359 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000360 strcpy(buf, s);
361 s = buf;
362 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000363 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000364 if (strncmp(s, "SIG", 3) == 0)
365 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000366 for (i = 0; i <= NSIG; i++)
367 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000368 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000369 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000370 }
Roland McGrath76421df2005-02-02 03:51:18 +0000371 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372}
373
374static int
375qual_fault(s, opt, not)
376 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000377 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000378 int not;
379{
380 return -1;
381}
382
383static int
384qual_desc(s, opt, not)
385 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000386 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387 int not;
388{
Roland McGrath48a035f2006-01-12 09:45:56 +0000389 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000390 int desc = atoi(s);
391 if (desc < 0 || desc >= MAX_QUALS)
392 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000393 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000394 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000395 }
396 return -1;
397}
398
399static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000400lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000401 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000402{
403 if (strcmp(s, "file") == 0)
404 return TRACE_FILE;
405 if (strcmp(s, "ipc") == 0)
406 return TRACE_IPC;
407 if (strcmp(s, "network") == 0)
408 return TRACE_NETWORK;
409 if (strcmp(s, "process") == 0)
410 return TRACE_PROCESS;
411 if (strcmp(s, "signal") == 0)
412 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000413 if (strcmp(s, "desc") == 0)
414 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415 return -1;
416}
417
418void
419qualify(s)
420char *s;
421{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000422 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000423 int not;
424 char *p;
425 int i, n;
426
427 opt = &qual_options[0];
428 for (i = 0; (p = qual_options[i].option_name); i++) {
429 n = strlen(p);
430 if (strncmp(s, p, n) == 0 && s[n] == '=') {
431 opt = &qual_options[i];
432 s += n + 1;
433 break;
434 }
435 }
436 not = 0;
437 if (*s == '!') {
438 not = 1;
439 s++;
440 }
441 if (strcmp(s, "none") == 0) {
442 not = 1 - not;
443 s = "all";
444 }
445 if (strcmp(s, "all") == 0) {
446 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000447 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000448 }
449 return;
450 }
451 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000452 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000453 }
454 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
455 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000456 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000457 if (sysent0[i].sys_flags & n)
458 qualify_one(i, opt, not, 0);
459
460#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000461 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000462 if (sysent1[i].sys_flags & n)
463 qualify_one(i, opt, not, 1);
464#endif /* SUPPORTED_PERSONALITIES >= 2 */
465
466#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000467 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000468 if (sysent2[i].sys_flags & n)
469 qualify_one(i, opt, not, 2);
470#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000471
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000472 continue;
473 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000474 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000475 fprintf(stderr, "strace: invalid %s `%s'\n",
476 opt->argument_name, p);
477 exit(1);
478 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000479 }
480 return;
481}
482
483static void
484dumpio(tcp)
485struct tcb *tcp;
486{
487 if (syserror(tcp))
488 return;
489 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
490 return;
Roland McGrath17352792005-06-07 23:21:26 +0000491 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000492 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000493#ifdef SYS_pread64
494 case SYS_pread64:
495#endif
496#if defined SYS_pread && SYS_pread64 != SYS_pread
497 case SYS_pread:
498#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000499#ifdef SYS_recv
500 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000501#elif defined SYS_sub_recv
502 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503#endif
504#ifdef SYS_recvfrom
505 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000506#elif defined SYS_sub_recvfrom
507 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000508#endif
509 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
510 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
511 break;
512 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000513#ifdef SYS_pwrite64
514 case SYS_pwrite64:
515#endif
516#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
517 case SYS_pwrite:
518#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000519#ifdef SYS_send
520 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000521#elif defined SYS_sub_send
522 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523#endif
524#ifdef SYS_sendto
525 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000526#elif defined SYS_sub_sendto
527 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000528#endif
529 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
530 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
531 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000532#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000533 case SYS_readv:
534 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
535 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
536 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000537#endif
538#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000539 case SYS_writev:
540 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
541 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
542 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000543#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544 }
545}
546
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000547#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000548enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000549#else /* FREEBSD */
550enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
551
552struct subcall {
553 int call;
554 int nsubcalls;
555 int subcalls[5];
556};
557
Roland McGratha4d48532005-06-08 20:45:28 +0000558static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000559 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000560#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000561 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000562#else
563 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
564#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000565 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
566};
567#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000569#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570
Roland McGratha4d48532005-06-08 20:45:28 +0000571static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572decode_subcall(tcp, subcall, nsubcalls, style)
573struct tcb *tcp;
574int subcall;
575int nsubcalls;
576enum subcall_style style;
577{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000578 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000579 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000580 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000581
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000582 switch (style) {
583 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000584 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
585 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586 tcp->scno = subcall + tcp->u_arg[0];
587 if (sysent[tcp->scno].nargs != -1)
588 tcp->u_nargs = sysent[tcp->scno].nargs;
589 else
590 tcp->u_nargs--;
591 for (i = 0; i < tcp->u_nargs; i++)
592 tcp->u_arg[i] = tcp->u_arg[i + 1];
593 break;
594 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000595 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
596 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597 tcp->scno = subcall + tcp->u_arg[0];
598 addr = tcp->u_arg[1];
599 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000600 if (size == sizeof(int)) {
601 unsigned int arg;
602 if (umove(tcp, addr, &arg) < 0)
603 arg = 0;
604 tcp->u_arg[i] = arg;
605 }
606 else if (size == sizeof(long)) {
607 unsigned long arg;
608 if (umove(tcp, addr, &arg) < 0)
609 arg = 0;
610 tcp->u_arg[i] = arg;
611 }
612 else
613 abort();
614 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615 }
616 tcp->u_nargs = sysent[tcp->scno].nargs;
617 break;
618 case mask_style:
619 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000620 for (i = 0; mask; i++)
621 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000622 if (i >= nsubcalls)
623 return;
624 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000625 tcp->scno = subcall + i;
626 if (sysent[tcp->scno].nargs != -1)
627 tcp->u_nargs = sysent[tcp->scno].nargs;
628 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000629 case door_style:
630 /*
631 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000632 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000633 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000634 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
635 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000636 tcp->scno = subcall + tcp->u_arg[5];
637 if (sysent[tcp->scno].nargs != -1)
638 tcp->u_nargs = sysent[tcp->scno].nargs;
639 else
640 tcp->u_nargs--;
641 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000642#ifdef FREEBSD
643 case table_style:
644 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
645 if (subcalls_table[i].call == tcp->scno) break;
646 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
647 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
648 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
649 for (i = 0; i < tcp->u_nargs; i++)
650 tcp->u_arg[i] = tcp->u_arg[i + 1];
651 }
652 break;
653#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000654 }
655}
656#endif
657
658struct tcb *tcp_last = NULL;
659
660static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000661internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000662{
663 /*
664 * We must always trace a few critical system calls in order to
665 * correctly support following forks in the presence of tracing
666 * qualifiers.
667 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000668 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000669
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000670 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
671 return 0;
672
673 func = sysent[tcp->scno].sys_func;
674
675 if (sys_exit == func)
676 return internal_exit(tcp);
677
678 if ( sys_fork == func
679#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
680 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000681#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000682#ifdef LINUX
683 || sys_clone == func
684#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000685#if UNIXWARE > 2
686 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000687#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000688 )
689 return internal_fork(tcp);
690
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000691 if ( sys_execve == func
692#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
693 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000694#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000695#if UNIXWARE > 2
696 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000697#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000698 )
699 return internal_exec(tcp);
700
701 if ( sys_waitpid == func
702 || sys_wait4 == func
703#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
704 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000705#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000706#ifdef ALPHA
707 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000708#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000709 )
710 return internal_wait(tcp, 2);
711
712#if defined(LINUX) || defined(SVR4)
713 if (sys_waitid == func)
714 return internal_wait(tcp, 3);
715#endif
716
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000717 return 0;
718}
719
Wichert Akkermanc7926982000-04-10 22:22:31 +0000720
721#ifdef LINUX
722#if defined (I386)
723 static long eax;
724#elif defined (IA64)
725 long r8, r10, psr;
726 long ia32 = 0;
727#elif defined (POWERPC)
728 static long result,flags;
729#elif defined (M68K)
Andreas Schwabffca9e32010-05-28 20:53:14 +0200730 static long d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000731#elif defined(BFIN)
732 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000733#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000734 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000735#elif defined (ALPHA)
736 static long r0;
737 static long a3;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000738#elif defined(AVR32)
739 static struct pt_regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000740#elif defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -0400741 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000742 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000743#elif defined(LINUX_MIPSN32)
744 static long long a3;
745 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000746#elif defined(MIPS)
747 static long a3;
748 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000749#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000750 static long gpr2;
751 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000752 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000753#elif defined(HPPA)
754 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000755#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000756 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000757#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000758 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000759#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000760 static long rax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000761#elif defined(CRISV10) || defined(CRISV32)
762 static long r10;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +0200763#elif defined(MICROBLAZE)
764 static long r3;
Roland McGrath761b5d72002-12-15 23:58:31 +0000765#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000766#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000767#ifdef FREEBSD
768 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000769#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000770
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000771int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000772get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000777# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000778 if (tcp->flags & TCB_WAITEXECVE) {
779 /*
780 * When the execve system call completes successfully, the
781 * new process still has -ENOSYS (old style) or __NR_execve
782 * (new style) in gpr2. We cannot recover the scno again
783 * by disassembly, because the image that executed the
784 * syscall is gone now. Fortunately, we don't want it. We
785 * leave the flag set so that syscall_fixup can fake the
786 * result.
787 */
788 if (tcp->flags & TCB_INSYSCALL)
789 return 1;
790 /*
791 * This is the SIGTRAP after execve. We cannot try to read
792 * the system call here either.
793 */
794 tcp->flags &= ~TCB_WAITEXECVE;
795 return 0;
796 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000797
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000798 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000799 return -1;
800
801 if (syscall_mode != -ENOSYS) {
802 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000803 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000804 */
805 scno = syscall_mode;
806 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000807 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000808 * Old style of "passing" the scno via the SVC instruction.
809 */
810
811 long opcode, offset_reg, tmp;
812 void * svc_addr;
813 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
814 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
815 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
816 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000817
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000818 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000819 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000820 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000821 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000822 if (errno) {
823 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000824 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000825 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000826
827 /*
828 * We have to check if the SVC got executed directly or via an
829 * EXECUTE instruction. In case of EXECUTE it is necessary to do
830 * instruction decoding to derive the system call number.
831 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
832 * so that this doesn't work if a SVC opcode is part of an EXECUTE
833 * opcode. Since there is no way to find out the opcode size this
834 * is the best we can do...
835 */
836
837 if ((opcode & 0xff00) == 0x0a00) {
838 /* SVC opcode */
839 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000840 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000841 else {
842 /* SVC got executed by EXECUTE instruction */
843
844 /*
845 * Do instruction decoding of EXECUTE. If you really want to
846 * understand this, read the Principles of Operations.
847 */
848 svc_addr = (void *) (opcode & 0xfff);
849
850 tmp = 0;
851 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000852 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000853 return -1;
854 svc_addr += tmp;
855
856 tmp = 0;
857 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000858 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000859 return -1;
860 svc_addr += tmp;
861
Denys Vlasenkofb036672009-01-23 16:30:26 +0000862 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000863 if (errno)
864 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000865# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000866 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000867# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000868 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000869# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000870 tmp = 0;
871 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000872 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000873 return -1;
874
875 scno = (scno | tmp) & 0xff;
876 }
877 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000878# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000879 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000880 return -1;
881 if (!(tcp->flags & TCB_INSYSCALL)) {
882 /* Check if we return from execve. */
883 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
884 tcp->flags &= ~TCB_WAITEXECVE;
885 return 0;
886 }
887 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200888
889# ifdef POWERPC64
890 if (!(tcp->flags & TCB_INSYSCALL)) {
891 static int currpers = -1;
892 long val;
893 int pid = tcp->pid;
894
895 /* Check for 64/32 bit mode. */
896 if (upeek(tcp, sizeof (unsigned long)*PT_MSR, &val) < 0)
897 return -1;
898 /* SF is bit 0 of MSR */
899 if (val < 0)
900 currpers = 0;
901 else
902 currpers = 1;
903 if (currpers != current_personality) {
904 static const char *const names[] = {"64 bit", "32 bit"};
905 set_personality(currpers);
906 printf("[ Process PID=%d runs in %s mode. ]\n",
907 pid, names[current_personality]);
908 }
909 }
910# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000911# elif defined(AVR32)
912 /*
913 * Read complete register set in one go.
914 */
915 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
916 return -1;
917
918 /*
919 * We only need to grab the syscall number on syscall entry.
920 */
921 if (!(tcp->flags & TCB_INSYSCALL)) {
922 scno = regs.r8;
923
924 /* Check if we return from execve. */
925 if (tcp->flags & TCB_WAITEXECVE) {
926 tcp->flags &= ~TCB_WAITEXECVE;
927 return 0;
928 }
929 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000930# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000931 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000932 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000933# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000934 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000935 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000936# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000937 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000938 return -1;
939
Roland McGrath761b5d72002-12-15 23:58:31 +0000940 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000941 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000942 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000943 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000944
945 /* Check CS register value. On x86-64 linux it is:
946 * 0x33 for long mode (64 bit)
947 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000948 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000949 * to be cached.
950 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000951 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000952 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000953 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000954 case 0x23: currpers = 1; break;
955 case 0x33: currpers = 0; break;
956 default:
957 fprintf(stderr, "Unknown value CS=0x%02X while "
958 "detecting personality of process "
959 "PID=%d\n", (int)val, pid);
960 currpers = current_personality;
961 break;
962 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000963# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000964 /* This version analyzes the opcode of a syscall instruction.
965 * (int 0x80 on i386 vs. syscall on x86-64)
966 * It works, but is too complicated.
967 */
968 unsigned long val, rip, i;
969
Denys Vlasenko8236f252009-01-02 18:10:08 +0000970 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000971 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000972
Michal Ludvig0e035502002-09-23 15:41:01 +0000973 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000974 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000975 errno = 0;
976
Denys Vlasenko8236f252009-01-02 18:10:08 +0000977 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000978 if (errno)
979 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000980 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000981 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000982 /* x86-64: syscall = 0x0f 0x05 */
983 case 0x050f: currpers = 0; break;
984 /* i386: int 0x80 = 0xcd 0x80 */
985 case 0x80cd: currpers = 1; break;
986 default:
987 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000988 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000989 "Unknown syscall opcode (0x%04X) while "
990 "detecting personality of process "
991 "PID=%d\n", (int)call, pid);
992 break;
993 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000994# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000995 if (currpers != current_personality) {
996 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000997 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000998 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000999 pid, names[current_personality]);
1000 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001001 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001002# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001003# define IA64_PSR_IS ((long)1 << 34)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001004 if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001005 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001006 if (!(tcp->flags & TCB_INSYSCALL)) {
1007 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001008 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001009 return -1;
1010 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001011 if (upeek (tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001012 return -1;
1013 }
Roland McGrathba954762003-03-05 06:29:06 +00001014 /* Check if we return from execve. */
1015 if (tcp->flags & TCB_WAITEXECVE) {
1016 tcp->flags &= ~TCB_WAITEXECVE;
1017 return 0;
1018 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001019 } else {
1020 /* syscall in progress */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001021 if (upeek (tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001022 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001023 if (upeek (tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001024 return -1;
1025 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001026# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001027 /*
1028 * Read complete register set in one go.
1029 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001030 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001031 return -1;
1032
1033 /*
1034 * We only need to grab the syscall number on syscall entry.
1035 */
1036 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001037 if (!(tcp->flags & TCB_INSYSCALL)) {
1038 /* Check if we return from execve. */
1039 if (tcp->flags & TCB_WAITEXECVE) {
1040 tcp->flags &= ~TCB_WAITEXECVE;
1041 return 0;
1042 }
1043 }
1044
Roland McGrath0f87c492003-06-03 23:29:04 +00001045 /*
1046 * Note: we only deal with only 32-bit CPUs here.
1047 */
1048 if (regs.ARM_cpsr & 0x20) {
1049 /*
1050 * Get the Thumb-mode system call number
1051 */
1052 scno = regs.ARM_r7;
1053 } else {
1054 /*
1055 * Get the ARM-mode system call number
1056 */
1057 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001058 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001059 if (errno)
1060 return -1;
1061
1062 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1063 tcp->flags &= ~TCB_WAITEXECVE;
1064 return 0;
1065 }
1066
Roland McGrathf691bd22006-04-25 07:34:41 +00001067 /* Handle the EABI syscall convention. We do not
1068 bother converting structures between the two
1069 ABIs, but basic functionality should work even
1070 if strace and the traced program have different
1071 ABIs. */
1072 if (scno == 0xef000000) {
1073 scno = regs.ARM_r7;
1074 } else {
1075 if ((scno & 0x0ff00000) != 0x0f900000) {
1076 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1077 scno);
1078 return -1;
1079 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001080
Roland McGrathf691bd22006-04-25 07:34:41 +00001081 /*
1082 * Fixup the syscall number
1083 */
1084 scno &= 0x000fffff;
1085 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001086 }
Roland McGrath56703312008-05-20 01:35:55 +00001087 if (scno & 0x0f0000) {
1088 /*
1089 * Handle ARM specific syscall
1090 */
1091 set_personality(1);
1092 scno &= 0x0000ffff;
1093 } else
1094 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001095
1096 if (tcp->flags & TCB_INSYSCALL) {
1097 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1098 tcp->flags &= ~TCB_INSYSCALL;
1099 }
1100 } else {
1101 if (!(tcp->flags & TCB_INSYSCALL)) {
1102 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1103 tcp->flags |= TCB_INSYSCALL;
1104 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001105 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001106# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001107 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001108 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001109# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001110 unsigned long long regs[38];
1111
Roland McGratheb9e2e82009-06-02 16:49:22 -07001112 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001113 return -1;
1114 a3 = regs[REG_A3];
1115 r2 = regs[REG_V0];
1116
1117 if(!(tcp->flags & TCB_INSYSCALL)) {
1118 scno = r2;
1119
1120 /* Check if we return from execve. */
1121 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1122 tcp->flags &= ~TCB_WAITEXECVE;
1123 return 0;
1124 }
1125
1126 if (scno < 0 || scno > nsyscalls) {
1127 if(a3 == 0 || a3 == -1) {
1128 if(debug)
1129 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1130 return 0;
1131 }
1132 }
1133 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001134# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001135 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001136 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001137 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001138 if (upeek(tcp, REG_V0, &scno) < 0)
1139 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001140
Roland McGrath542c2c62008-05-20 01:11:56 +00001141 /* Check if we return from execve. */
1142 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1143 tcp->flags &= ~TCB_WAITEXECVE;
1144 return 0;
1145 }
1146
Wichert Akkermanf90da011999-10-31 21:15:38 +00001147 if (scno < 0 || scno > nsyscalls) {
1148 if(a3 == 0 || a3 == -1) {
1149 if(debug)
1150 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1151 return 0;
1152 }
1153 }
1154 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001155 if (upeek(tcp, REG_V0, &r2) < 0)
1156 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001157 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001158# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001159 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160 return -1;
1161
1162 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001163 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 return -1;
1165
1166 /* Check if we return from execve. */
1167 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1168 tcp->flags &= ~TCB_WAITEXECVE;
1169 return 0;
1170 }
1171
1172 /*
1173 * Do some sanity checks to figure out if it's
1174 * really a syscall entry
1175 */
1176 if (scno < 0 || scno > nsyscalls) {
1177 if (a3 == 0 || a3 == -1) {
1178 if (debug)
1179 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1180 return 0;
1181 }
1182 }
1183 }
1184 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001185 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186 return -1;
1187 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001188# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001190 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 return -1;
1192
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001193 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001194 if (!(tcp->flags & TCB_INSYSCALL)) {
1195 /* Retrieve the syscall trap instruction. */
1196 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001197# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001198 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001199 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001200# else
1201 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001202# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203 if (errno)
1204 return -1;
1205
1206 /* Disassemble the trap to see what personality to use. */
1207 switch (trap) {
1208 case 0x91d02010:
1209 /* Linux/SPARC syscall trap. */
1210 set_personality(0);
1211 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001212 case 0x91d0206d:
1213 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001214 set_personality(2);
1215 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216 case 0x91d02000:
1217 /* SunOS syscall trap. (pers 1) */
1218 fprintf(stderr,"syscall: SunOS no support\n");
1219 return -1;
1220 case 0x91d02008:
1221 /* Solaris 2.x syscall trap. (per 2) */
1222 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001223 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224 case 0x91d02009:
1225 /* NetBSD/FreeBSD syscall trap. */
1226 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1227 return -1;
1228 case 0x91d02027:
1229 /* Solaris 2.x gettimeofday */
1230 set_personality(1);
1231 break;
1232 default:
1233 /* Unknown syscall trap. */
1234 if(tcp->flags & TCB_WAITEXECVE) {
1235 tcp->flags &= ~TCB_WAITEXECVE;
1236 return 0;
1237 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001238# if defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001239 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001240# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001241 fprintf(stderr,"syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001242# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243 return -1;
1244 }
1245
1246 /* Extract the system call number from the registers. */
1247 if (trap == 0x91d02027)
1248 scno = 156;
1249 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001250 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001252 scno = regs.u_regs[U_REG_O0];
1253 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 +00001254 }
1255 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001256# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001257 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001258 return -1;
1259 if (!(tcp->flags & TCB_INSYSCALL)) {
1260 /* Check if we return from execve. */
1261 if ((tcp->flags & TCB_WAITEXECVE)) {
1262 tcp->flags &= ~TCB_WAITEXECVE;
1263 return 0;
1264 }
1265 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001266# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001267 /*
1268 * In the new syscall ABI, the system call number is in R3.
1269 */
1270 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1271 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001272
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001273 if (scno < 0) {
1274 /* Odd as it may seem, a glibc bug has been known to cause
1275 glibc to issue bogus negative syscall numbers. So for
1276 our purposes, make strace print what it *should* have been */
1277 long correct_scno = (scno & 0xff);
1278 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001279 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001280 "Detected glibc bug: bogus system call"
1281 " number = %ld, correcting to %ld\n",
1282 scno,
1283 correct_scno);
1284 scno = correct_scno;
1285 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001286
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001287 if (!(tcp->flags & TCB_INSYSCALL)) {
1288 /* Check if we return from execve. */
1289 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1290 tcp->flags &= ~TCB_WAITEXECVE;
1291 return 0;
1292 }
1293 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001294# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001295 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001296 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001297 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001298
1299 if (!(tcp->flags & TCB_INSYSCALL)) {
1300 /* Check if we return from execve. */
1301 if (tcp->flags & TCB_WAITEXECVE) {
1302 tcp->flags &= ~TCB_WAITEXECVE;
1303 return 0;
1304 }
1305 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001306# elif defined(CRISV10) || defined(CRISV32)
1307 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1308 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001309# elif defined(TILE)
1310 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1311 return -1;
1312
1313 if (!(tcp->flags & TCB_INSYSCALL)) {
1314 /* Check if we return from execve. */
1315 if (tcp->flags & TCB_WAITEXECVE) {
1316 tcp->flags &= ~TCB_WAITEXECVE;
1317 return 0;
1318 }
1319 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001320# elif defined(MICROBLAZE)
1321 if (upeek(tcp, 0, &scno) < 0)
1322 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001323# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001324#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001325
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001326#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001327 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001328 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001329#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001330 /* new syscall ABI returns result in R0 */
1331 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1332 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001333#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001334 /* ABI defines result returned in r9 */
1335 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1336 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001337#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001338
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001339#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001340# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001341 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001342# else
1343# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001344 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001345# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001346 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001347 perror("pread");
1348 return -1;
1349 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001350 switch (regs.r_eax) {
1351 case SYS_syscall:
1352 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001353 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1354 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001355 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001356 scno = regs.r_eax;
1357 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001358 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001359# endif /* FREEBSD */
1360# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001361#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001362
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001363 if (!(tcp->flags & TCB_INSYSCALL))
1364 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001365 return 1;
1366}
1367
Pavel Machek4dc3b142000-02-01 17:58:41 +00001368
Roland McGrath17352792005-06-07 23:21:26 +00001369long
1370known_scno(tcp)
1371struct tcb *tcp;
1372{
1373 long scno = tcp->scno;
1374 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1375 scno = sysent[scno].native_scno;
1376 else
1377 scno += NR_SYSCALL_BASE;
1378 return scno;
1379}
1380
Roland McGratheb9e2e82009-06-02 16:49:22 -07001381/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001382 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001383 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1384 * 1: ok, continue in trace_syscall().
1385 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001386 * ("????" etc) and bail out.
1387 */
Roland McGratha4d48532005-06-08 20:45:28 +00001388static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001389syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001390{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001391#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001392 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001393
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001394 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001395 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001396 if (
1397 scno == SYS_fork
1398#ifdef SYS_vfork
1399 || scno == SYS_vfork
1400#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001401#ifdef SYS_fork1
1402 || scno == SYS_fork1
1403#endif /* SYS_fork1 */
1404#ifdef SYS_forkall
1405 || scno == SYS_forkall
1406#endif /* SYS_forkall */
1407#ifdef SYS_rfork1
1408 || scno == SYS_rfork1
1409#endif /* SYS_fork1 */
1410#ifdef SYS_rforkall
1411 || scno == SYS_rforkall
1412#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001413 ) {
1414 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001415 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001416 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001417 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001418 }
1419 else {
1420 fprintf(stderr, "syscall: missing entry\n");
1421 tcp->flags |= TCB_INSYSCALL;
1422 }
1423 }
1424 }
1425 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001426 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001427 fprintf(stderr, "syscall: missing exit\n");
1428 tcp->flags &= ~TCB_INSYSCALL;
1429 }
1430 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001431#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001432#ifdef SUNOS4
1433 if (!(tcp->flags & TCB_INSYSCALL)) {
1434 if (scno == 0) {
1435 fprintf(stderr, "syscall: missing entry\n");
1436 tcp->flags |= TCB_INSYSCALL;
1437 }
1438 }
1439 else {
1440 if (scno != 0) {
1441 if (debug) {
1442 /*
1443 * This happens when a signal handler
1444 * for a signal which interrupted a
1445 * a system call makes another system call.
1446 */
1447 fprintf(stderr, "syscall: missing exit\n");
1448 }
1449 tcp->flags &= ~TCB_INSYSCALL;
1450 }
1451 }
1452#endif /* SUNOS4 */
1453#ifdef LINUX
1454#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001455 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001456 return -1;
1457 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1458 if (debug)
1459 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1460 return 0;
1461 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001462#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001463 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001464 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001465 if (current_personality == 1)
1466 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001467 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1468 if (debug)
1469 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1470 return 0;
1471 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001472#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001473 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001474 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001475 if (syscall_mode != -ENOSYS)
1476 syscall_mode = tcp->scno;
1477 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001478 if (debug)
1479 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1480 return 0;
1481 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001482 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1483 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1484 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1485 /*
1486 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1487 * flag set for the post-execve SIGTRAP to see and reset.
1488 */
1489 gpr2 = 0;
1490 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001491#elif defined (POWERPC)
1492# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001493 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001494 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001495 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001496 return -1;
1497 if (flags & SO_MASK)
1498 result = -result;
1499#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001500 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001501 return -1;
1502 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1503 if (debug)
1504 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1505 return 0;
1506 }
1507#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001508 /*
1509 * Nothing required
1510 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001511#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001512 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001513 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001514#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001515 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001516 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001517#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001518 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001519 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001520 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001521 return -1;
1522 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1523 if (debug)
1524 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1525 return 0;
1526 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001527#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001528 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001529 return -1;
1530 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1531 if (debug)
1532 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1533 return 0;
1534 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001535#elif defined(MICROBLAZE)
1536 if (upeek(tcp, 3 * 4, &r3) < 0)
1537 return -1;
1538 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1539 if (debug)
1540 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1541 return 0;
1542 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001543#endif
1544#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001545 return 1;
1546}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547
Roland McGrathc1e45922008-05-27 23:18:29 +00001548#ifdef LINUX
1549/*
1550 * Check the syscall return value register value for whether it is
1551 * a negated errno code indicating an error, or a success return value.
1552 */
1553static inline int
1554is_negated_errno(unsigned long int val)
1555{
1556 unsigned long int max = -(long int) nerrnos;
1557 if (personality_wordsize[current_personality] < sizeof(val)) {
1558 val = (unsigned int) val;
1559 max = (unsigned int) max;
1560 }
1561 return val > max;
1562}
1563#endif
1564
Roland McGratha4d48532005-06-08 20:45:28 +00001565static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001566get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001567{
1568 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001569#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001570# if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001571 if (is_negated_errno(gpr2)) {
1572 tcp->u_rval = -1;
1573 u_error = -gpr2;
1574 }
1575 else {
1576 tcp->u_rval = gpr2;
1577 u_error = 0;
1578 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001579# elif defined(I386)
Roland McGrathc1e45922008-05-27 23:18:29 +00001580 if (is_negated_errno(eax)) {
1581 tcp->u_rval = -1;
1582 u_error = -eax;
1583 }
1584 else {
1585 tcp->u_rval = eax;
1586 u_error = 0;
1587 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001588# elif defined(X86_64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001589 if (is_negated_errno(rax)) {
1590 tcp->u_rval = -1;
1591 u_error = -rax;
1592 }
1593 else {
1594 tcp->u_rval = rax;
1595 u_error = 0;
1596 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001597# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001598 if (ia32) {
1599 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001600
Roland McGrathc1e45922008-05-27 23:18:29 +00001601 err = (int)r8;
1602 if (is_negated_errno(err)) {
1603 tcp->u_rval = -1;
1604 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001605 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001606 else {
1607 tcp->u_rval = err;
1608 u_error = 0;
1609 }
1610 } else {
1611 if (r10) {
1612 tcp->u_rval = -1;
1613 u_error = r8;
1614 } else {
1615 tcp->u_rval = r8;
1616 u_error = 0;
1617 }
1618 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001619# elif defined(MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001620 if (a3) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001621 tcp->u_rval = -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001622 u_error = r2;
1623 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001624 tcp->u_rval = r2;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001625 u_error = 0;
1626 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001627# elif defined(POWERPC)
Roland McGrathc1e45922008-05-27 23:18:29 +00001628 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629 tcp->u_rval = -1;
1630 u_error = -result;
1631 }
1632 else {
1633 tcp->u_rval = result;
1634 u_error = 0;
1635 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001636# elif defined(M68K)
Roland McGrathc1e45922008-05-27 23:18:29 +00001637 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001638 tcp->u_rval = -1;
1639 u_error = -d0;
1640 }
1641 else {
1642 tcp->u_rval = d0;
1643 u_error = 0;
1644 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001645# elif defined(ARM)
Roland McGrathc1e45922008-05-27 23:18:29 +00001646 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001648 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649 }
1650 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001651 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652 u_error = 0;
1653 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001654# elif defined(AVR32)
1655 if (regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1656 tcp->u_rval = -1;
1657 u_error = -regs.r12;
1658 }
1659 else {
1660 tcp->u_rval = regs.r12;
1661 u_error = 0;
1662 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001663# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001664 if (is_negated_errno(r0)) {
1665 tcp->u_rval = -1;
1666 u_error = -r0;
1667 } else {
1668 tcp->u_rval = r0;
1669 u_error = 0;
1670 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001671# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001672 if (a3) {
1673 tcp->u_rval = -1;
1674 u_error = r0;
1675 }
1676 else {
1677 tcp->u_rval = r0;
1678 u_error = 0;
1679 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001680# elif defined(SPARC)
Mike Frysinger8566c502009-10-12 11:05:14 -04001681 if (regs.psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001682 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001683 u_error = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684 }
1685 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001686 tcp->u_rval = regs.u_regs[U_REG_O0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687 u_error = 0;
1688 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001689# elif defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001690 if (regs.tstate & 0x1100000000UL) {
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001691 tcp->u_rval = -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04001692 u_error = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001693 }
1694 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001695 tcp->u_rval = regs.u_regs[U_REG_O0];
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001696 u_error = 0;
1697 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001698# elif defined(HPPA)
Roland McGrathc1e45922008-05-27 23:18:29 +00001699 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001700 tcp->u_rval = -1;
1701 u_error = -r28;
1702 }
1703 else {
1704 tcp->u_rval = r28;
1705 u_error = 0;
1706 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001707# elif defined(SH)
Roland McGrathc1e45922008-05-27 23:18:29 +00001708 /* interpret R0 as return value or error number */
1709 if (is_negated_errno(r0)) {
1710 tcp->u_rval = -1;
1711 u_error = -r0;
1712 }
1713 else {
1714 tcp->u_rval = r0;
1715 u_error = 0;
1716 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001717# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001718 /* interpret result as return value or error number */
1719 if (is_negated_errno(r9)) {
1720 tcp->u_rval = -1;
1721 u_error = -r9;
1722 }
1723 else {
1724 tcp->u_rval = r9;
1725 u_error = 0;
1726 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001727# elif defined(CRISV10) || defined(CRISV32)
1728 if (r10 && (unsigned) -r10 < nerrnos) {
1729 tcp->u_rval = -1;
1730 u_error = -r10;
1731 }
1732 else {
1733 tcp->u_rval = r10;
1734 u_error = 0;
1735 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001736# elif defined(TILE)
1737 long rval;
1738 /* interpret result as return value or error number */
1739 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1740 return -1;
1741 if (rval < 0 && rval > -nerrnos) {
1742 tcp->u_rval = -1;
1743 u_error = -rval;
1744 }
1745 else {
1746 tcp->u_rval = rval;
1747 u_error = 0;
1748 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001749# elif defined(MICROBLAZE)
1750 /* interpret result as return value or error number */
1751 if (is_negated_errno(r3)) {
1752 tcp->u_rval = -1;
1753 u_error = -r3;
1754 }
1755 else {
1756 tcp->u_rval = r3;
1757 u_error = 0;
1758 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001759# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001760#endif /* LINUX */
1761#ifdef SUNOS4
1762 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001763 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764 return -1;
1765 u_error >>= 24; /* u_error is a char */
1766
1767 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001768 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001769 return -1;
1770#endif /* SUNOS4 */
1771#ifdef SVR4
1772#ifdef SPARC
1773 /* Judicious guessing goes a long way. */
1774 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1775 tcp->u_rval = -1;
1776 u_error = tcp->status.pr_reg[R_O0];
1777 }
1778 else {
1779 tcp->u_rval = tcp->status.pr_reg[R_O0];
1780 u_error = 0;
1781 }
1782#endif /* SPARC */
1783#ifdef I386
1784 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001785 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001786 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001787 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001788 }
1789 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001790 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001791#ifdef HAVE_LONG_LONG
1792 tcp->u_lrval =
1793 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1794 tcp->status.PR_REG[EAX];
1795#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001796 u_error = 0;
1797 }
1798#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001799#ifdef X86_64
1800 /* Wanna know how to kill an hour single-stepping? */
1801 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1802 tcp->u_rval = -1;
1803 u_error = tcp->status.PR_REG[RAX];
1804 }
1805 else {
1806 tcp->u_rval = tcp->status.PR_REG[RAX];
1807 u_error = 0;
1808 }
1809#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001810#ifdef MIPS
1811 if (tcp->status.pr_reg[CTX_A3]) {
1812 tcp->u_rval = -1;
1813 u_error = tcp->status.pr_reg[CTX_V0];
1814 }
1815 else {
1816 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1817 u_error = 0;
1818 }
1819#endif /* MIPS */
1820#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001821#ifdef FREEBSD
1822 if (regs.r_eflags & PSL_C) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001823 tcp->u_rval = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001824 u_error = regs.r_eax;
1825 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001826 tcp->u_rval = regs.r_eax;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001827 tcp->u_lrval =
1828 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1829 u_error = 0;
1830 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001831#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001832 tcp->u_error = u_error;
1833 return 1;
1834}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001835
Roland McGrathb69f81b2002-12-21 23:25:18 +00001836int
1837force_result(tcp, error, rval)
1838 struct tcb *tcp;
1839 int error;
1840 long rval;
1841{
1842#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001843# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001844 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001845 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1846 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001847# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001848 eax = error ? -error : rval;
1849 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1850 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001851# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001852 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001853 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001854 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001855# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001856 if (ia32) {
1857 r8 = error ? -error : rval;
1858 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1859 return -1;
1860 }
1861 else {
1862 if (error) {
1863 r8 = error;
1864 r10 = -1;
1865 }
1866 else {
1867 r8 = rval;
1868 r10 = 0;
1869 }
1870 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1871 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1872 return -1;
1873 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001874# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001875 r0 = error ? -error : rval;
1876 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1877 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001878# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001879 if (error) {
1880 r2 = error;
1881 a3 = -1;
1882 }
1883 else {
1884 r2 = rval;
1885 a3 = 0;
1886 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001887 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001888 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1889 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001890 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001891# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001892 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001893 return -1;
1894 if (error) {
1895 flags |= SO_MASK;
1896 result = error;
1897 }
1898 else {
1899 flags &= ~SO_MASK;
1900 result = rval;
1901 }
Roland McGratheb285352003-01-14 09:59:00 +00001902 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1903 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001904 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001905# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001906 d0 = error ? -error : rval;
1907 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1908 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001909# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001910 regs.ARM_r0 = error ? -error : rval;
1911 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001912 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001913# elif defined(AVR32)
1914 regs.r12 = error ? -error : rval;
1915 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1916 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001917# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001918 if (error) {
1919 a3 = -1;
1920 r0 = error;
1921 }
1922 else {
1923 a3 = 0;
1924 r0 = rval;
1925 }
1926 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1927 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1928 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001929# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001930 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1931 return -1;
1932 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001933 regs.psr |= PSR_C;
1934 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001935 }
1936 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001937 regs.psr &= ~PSR_C;
1938 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001939 }
1940 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1941 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001942# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001943 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1944 return -1;
1945 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001946 regs.tstate |= 0x1100000000UL;
1947 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001948 }
1949 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001950 regs.tstate &= ~0x1100000000UL;
1951 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001952 }
1953 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1954 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001955# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001956 r28 = error ? -error : rval;
1957 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1958 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001959# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001960 r0 = error ? -error : rval;
1961 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1962 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001963# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001964 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001965 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1966 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001967# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001968#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001969
Roland McGrathb69f81b2002-12-21 23:25:18 +00001970#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001971 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1972 error << 24) < 0 ||
1973 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001974 return -1;
1975#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001976
Roland McGrathb69f81b2002-12-21 23:25:18 +00001977#ifdef SVR4
1978 /* XXX no clue */
1979 return -1;
1980#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001981
Roland McGrathb69f81b2002-12-21 23:25:18 +00001982#ifdef FREEBSD
1983 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001984 perror("pread");
1985 return -1;
1986 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001987 if (error) {
1988 regs.r_eflags |= PSL_C;
1989 regs.r_eax = error;
1990 }
1991 else {
1992 regs.r_eflags &= ~PSL_C;
1993 regs.r_eax = rval;
1994 }
1995 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001996 perror("pwrite");
1997 return -1;
1998 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001999#endif /* FREEBSD */
2000
2001 /* All branches reach here on success (only). */
2002 tcp->u_error = error;
2003 tcp->u_rval = rval;
2004 return 0;
2005}
2006
Roland McGratha4d48532005-06-08 20:45:28 +00002007static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002008syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002009{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002010#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00002011#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002012 {
2013 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002014 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2015 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002016 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002017 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002018 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002019 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002020 return -1;
2021 }
2022 }
2023#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002024 {
2025 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002026 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2027 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002028 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002029 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002030 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00002031 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2032 * for scno somewhere above here!
2033 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002034 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002035 return -1;
2036 }
2037 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002038#elif defined (IA64)
2039 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002040 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002041 unsigned long *out0, cfm, sof, sol, i;
2042 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002043 /* be backwards compatible with kernel < 2.4.4... */
2044# ifndef PT_RBS_END
2045# define PT_RBS_END PT_AR_BSP
2046# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002047
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002048 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002049 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002050 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002051 return -1;
2052
2053 sof = (cfm >> 0) & 0x7f;
2054 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002055 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002056
2057 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2058 && sysent[tcp->scno].nargs != -1)
2059 tcp->u_nargs = sysent[tcp->scno].nargs;
2060 else
2061 tcp->u_nargs = MAX_ARGS;
2062 for (i = 0; i < tcp->u_nargs; ++i) {
2063 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2064 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2065 return -1;
2066 }
2067 } else {
2068 int i;
2069
2070 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002071 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002072 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002073 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002074 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002075 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002076 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002077 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002078 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002079 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002080 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002081 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002082 return -1;
2083
2084 for (i = 0; i < 6; ++i)
2085 /* truncate away IVE sign-extension */
2086 tcp->u_arg[i] &= 0xffffffff;
2087
2088 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2089 && sysent[tcp->scno].nargs != -1)
2090 tcp->u_nargs = sysent[tcp->scno].nargs;
2091 else
2092 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002093 }
2094 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002095#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2096 /* N32 and N64 both use up to six registers. */
2097 {
2098 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002099 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002100
2101 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2102 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002103 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002104 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002105
David Daney20037042010-02-09 21:22:30 +00002106 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002107 return -1;
2108
Roland McGratheb9e2e82009-06-02 16:49:22 -07002109 for(i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002110 tcp->u_arg[i] = regs[REG_A0 + i];
2111# if defined (LINUX_MIPSN32)
2112 tcp->ext_arg[i] = regs[REG_A0 + i];
2113# endif
2114 }
2115 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002116#elif defined (MIPS)
2117 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002118 long sp;
2119 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002120
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002121 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2122 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002123 else
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002124 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002125 if(nargs > 4) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002126 if(upeek(tcp, REG_SP, &sp) < 0)
2127 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002128 for(i = 0; i < 4; i++) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002129 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
2130 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002131 }
2132 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2133 (char *)(tcp->u_arg + 4));
2134 } else {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002135 for(i = 0; i < nargs; i++) {
2136 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2137 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002138 }
2139 }
2140 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002141#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002142# ifndef PT_ORIG_R3
2143# define PT_ORIG_R3 34
2144# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002145 {
2146 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002147 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2148 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002149 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002150 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002151 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002152 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002153 (sizeof(unsigned long)*PT_ORIG_R3) :
2154 ((i+PT_R3)*sizeof(unsigned long)),
2155 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002156 return -1;
2157 }
2158 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002159#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002160 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002161 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002162
2163 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2164 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002165 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002166 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002167 for (i = 0; i < tcp->u_nargs; i++)
Mike Frysinger8566c502009-10-12 11:05:14 -04002168 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002169 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002170#elif defined (HPPA)
2171 {
2172 int i;
2173
2174 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2175 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002176 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002177 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002178 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002179 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002180 return -1;
2181 }
2182 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002183#elif defined(ARM)
2184 {
2185 int i;
2186
2187 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2188 tcp->u_nargs = sysent[tcp->scno].nargs;
2189 else
2190 tcp->u_nargs = MAX_ARGS;
2191 for (i = 0; i < tcp->u_nargs; i++)
2192 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002193 }
2194#elif defined(AVR32)
2195 tcp->u_nargs = sysent[tcp->scno].nargs;
2196 tcp->u_arg[0] = regs.r12;
2197 tcp->u_arg[1] = regs.r11;
2198 tcp->u_arg[2] = regs.r10;
2199 tcp->u_arg[3] = regs.r9;
2200 tcp->u_arg[4] = regs.r5;
2201 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002202#elif defined(BFIN)
2203 {
2204 int i;
2205 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2206
2207 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2208 tcp->u_nargs = sysent[tcp->scno].nargs;
2209 else
2210 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2211
2212 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002213 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002214 return -1;
2215 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002216#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002217 {
2218 int i;
2219 static int syscall_regs[] = {
2220 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2221 REG_REG0, REG_REG0+1, REG_REG0+2
2222 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002223
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002224 tcp->u_nargs = sysent[tcp->scno].nargs;
2225 for (i = 0; i < tcp->u_nargs; i++) {
2226 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2227 return -1;
2228 }
2229 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002230#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002231 {
2232 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002233 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002234 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2235
2236 /*
2237 * TODO: should also check that the number of arguments encoded
2238 * in the trap number matches the number strace expects.
2239 */
2240 /*
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002241 assert(sysent[tcp->scno].nargs <
2242 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
Roland McGrathe1e584b2003-06-02 19:18:58 +00002243 */
2244
2245 tcp->u_nargs = sysent[tcp->scno].nargs;
2246 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002247 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002248 return -1;
2249 }
2250 }
2251
Michal Ludvig0e035502002-09-23 15:41:01 +00002252#elif defined(X86_64)
2253 {
2254 int i;
2255 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2256 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002257 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002258 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002259
Michal Ludvig0e035502002-09-23 15:41:01 +00002260 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2261 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002262 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002263 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002264 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002265 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002266 return -1;
2267 }
2268 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002269#elif defined(MICROBLAZE)
2270 {
2271 int i;
2272 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2273 tcp->u_nargs = sysent[tcp->scno].nargs;
2274 else
2275 tcp->u_nargs = 0;
2276 for (i = 0; i < tcp->u_nargs; i++) {
2277 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2278 return -1;
2279 }
2280 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002281#elif defined(CRISV10) || defined(CRISV32)
2282 {
2283 int i;
2284 static const int crisregs[] = {
2285 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2286 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2287 };
2288
2289 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2290 tcp->u_nargs = sysent[tcp->scno].nargs;
2291 else
2292 tcp->u_nargs = 0;
2293 for (i = 0; i < tcp->u_nargs; i++) {
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00002294 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002295 return -1;
2296 }
2297 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05002298#elif defined(TILE)
2299 {
2300 int i;
2301 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2302 tcp->u_nargs = sysent[tcp->scno].nargs;
2303 else
2304 tcp->u_nargs = MAX_ARGS;
2305 for (i = 0; i < tcp->u_nargs; ++i) {
2306 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2307 return -1;
2308 }
2309 }
Andreas Schwab246888d2010-06-05 21:50:30 +02002310#elif defined (M68K)
2311 {
2312 int i;
2313 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2314 tcp->u_nargs = sysent[tcp->scno].nargs;
2315 else
2316 tcp->u_nargs = MAX_ARGS;
2317 for (i = 0; i < tcp->u_nargs; i++) {
2318 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2319 return -1;
2320 }
2321 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002322#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002323 {
2324 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002325 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2326 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002327 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002328 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002329 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002330 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002331 return -1;
2332 }
2333 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002334#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002335#endif /* LINUX */
2336#ifdef SUNOS4
2337 {
2338 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002339 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2340 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002341 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002342 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002343 for (i = 0; i < tcp->u_nargs; i++) {
2344 struct user *u;
2345
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002346 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002347 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2348 return -1;
2349 }
2350 }
2351#endif /* SUNOS4 */
2352#ifdef SVR4
2353#ifdef MIPS
2354 /*
2355 * SGI is broken: even though it has pr_sysarg, it doesn't
2356 * set them on system call entry. Get a clue.
2357 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002358 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002359 tcp->u_nargs = sysent[tcp->scno].nargs;
2360 else
2361 tcp->u_nargs = tcp->status.pr_nsysarg;
2362 if (tcp->u_nargs > 4) {
2363 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2364 4*sizeof(tcp->u_arg[0]));
2365 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2366 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2367 }
2368 else {
2369 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2370 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2371 }
John Hughes25299712001-03-06 10:10:06 +00002372#elif UNIXWARE >= 2
2373 /*
2374 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2375 */
2376 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2377 tcp->u_nargs = sysent[tcp->scno].nargs;
2378 else
2379 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2380 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2381 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2382#elif defined (HAVE_PR_SYSCALL)
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 = tcp->status.pr_nsysarg;
2387 {
2388 int i;
2389 for (i = 0; i < tcp->u_nargs; i++)
2390 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2391 }
John Hughes25299712001-03-06 10:10:06 +00002392#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002393 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002394 tcp->u_nargs = sysent[tcp->scno].nargs;
2395 else
2396 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002397 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002398 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002399#else
2400 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002401#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002402#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002403#ifdef FREEBSD
2404 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2405 sysent[tcp->scno].nargs > tcp->status.val)
2406 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002407 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002408 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002409 if (tcp->u_nargs < 0)
2410 tcp->u_nargs = 0;
2411 if (tcp->u_nargs > MAX_ARGS)
2412 tcp->u_nargs = MAX_ARGS;
2413 switch(regs.r_eax) {
2414 case SYS___syscall:
2415 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2416 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002417 break;
2418 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002419 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2420 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002421 break;
2422 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002423 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2424 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002425 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002426 }
2427#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002428 return 1;
2429}
2430
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002431static int
2432trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002433{
2434 int sys_res;
2435 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002436 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002437 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002438
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002439 /* Measure the exit time as early as possible to avoid errors. */
2440 if (dtime || cflag)
2441 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002442
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002443 /* BTW, why we don't just memorize syscall no. on entry
2444 * in tcp->something?
2445 */
2446 scno_good = res = get_scno(tcp);
2447 if (res == 0)
2448 return res;
2449 if (res == 1)
2450 res = syscall_fixup(tcp);
2451 if (res == 0)
2452 return res;
2453 if (res == 1)
2454 res = get_error(tcp);
2455 if (res == 0)
2456 return res;
2457 if (res == 1)
2458 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002459
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002460 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
2461 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002462 tcp->flags &= ~TCB_INSYSCALL;
2463 return 0;
2464 }
2465
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002466 if (tcp->flags & TCB_REPRINT) {
2467 printleader(tcp);
2468 tprintf("<... ");
2469 if (scno_good != 1)
2470 tprintf("????");
2471 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2472 tprintf("syscall_%lu", tcp->scno);
2473 else
2474 tprintf("%s", sysent[tcp->scno].sys_name);
2475 tprintf(" resumed> ");
2476 }
2477
2478 if (cflag) {
2479 struct timeval t = tv;
2480 int rc = count_syscall(tcp, &t);
2481 if (cflag == CFLAG_ONLY_STATS)
2482 {
2483 tcp->flags &= ~TCB_INSYSCALL;
2484 return rc;
2485 }
2486 }
2487
2488 if (res != 1) {
2489 tprintf(") ");
2490 tabto(acolumn);
2491 tprintf("= ? <unavailable>");
2492 printtrailer();
2493 tcp->flags &= ~TCB_INSYSCALL;
2494 return res;
2495 }
2496
2497 if (tcp->scno >= nsyscalls || tcp->scno < 0
2498 || (qual_flags[tcp->scno] & QUAL_RAW))
2499 sys_res = printargs(tcp);
2500 else {
2501 if (not_failing_only && tcp->u_error)
2502 return 0; /* ignore failed syscalls */
2503 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2504 }
2505
2506 u_error = tcp->u_error;
2507 tprintf(") ");
2508 tabto(acolumn);
2509 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2510 qual_flags[tcp->scno] & QUAL_RAW) {
2511 if (u_error)
2512 tprintf("= -1 (errno %ld)", u_error);
2513 else
2514 tprintf("= %#lx", tcp->u_rval);
2515 }
2516 else if (!(sys_res & RVAL_NONE) && u_error) {
2517 switch (u_error) {
2518#ifdef LINUX
2519 case ERESTARTSYS:
2520 tprintf("= ? ERESTARTSYS (To be restarted)");
2521 break;
2522 case ERESTARTNOINTR:
2523 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2524 break;
2525 case ERESTARTNOHAND:
2526 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2527 break;
2528 case ERESTART_RESTARTBLOCK:
2529 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2530 break;
2531#endif /* LINUX */
2532 default:
2533 tprintf("= -1 ");
2534 if (u_error < 0)
2535 tprintf("E??? (errno %ld)", u_error);
2536 else if (u_error < nerrnos)
2537 tprintf("%s (%s)", errnoent[u_error],
2538 strerror(u_error));
2539 else
2540 tprintf("ERRNO_%ld (%s)", u_error,
2541 strerror(u_error));
2542 break;
2543 }
2544 if ((sys_res & RVAL_STR) && tcp->auxstr)
2545 tprintf(" (%s)", tcp->auxstr);
2546 }
2547 else {
2548 if (sys_res & RVAL_NONE)
2549 tprintf("= ?");
2550 else {
2551 switch (sys_res & RVAL_MASK) {
2552 case RVAL_HEX:
2553 tprintf("= %#lx", tcp->u_rval);
2554 break;
2555 case RVAL_OCTAL:
2556 tprintf("= %#lo", tcp->u_rval);
2557 break;
2558 case RVAL_UDECIMAL:
2559 tprintf("= %lu", tcp->u_rval);
2560 break;
2561 case RVAL_DECIMAL:
2562 tprintf("= %ld", tcp->u_rval);
2563 break;
2564#ifdef HAVE_LONG_LONG
2565 case RVAL_LHEX:
2566 tprintf("= %#llx", tcp->u_lrval);
2567 break;
2568 case RVAL_LOCTAL:
2569 tprintf("= %#llo", tcp->u_lrval);
2570 break;
2571 case RVAL_LUDECIMAL:
2572 tprintf("= %llu", tcp->u_lrval);
2573 break;
2574 case RVAL_LDECIMAL:
2575 tprintf("= %lld", tcp->u_lrval);
2576 break;
2577#endif
2578 default:
2579 fprintf(stderr,
2580 "invalid rval format\n");
2581 break;
2582 }
2583 }
2584 if ((sys_res & RVAL_STR) && tcp->auxstr)
2585 tprintf(" (%s)", tcp->auxstr);
2586 }
2587 if (dtime) {
2588 tv_sub(&tv, &tv, &tcp->etime);
2589 tprintf(" <%ld.%06ld>",
2590 (long) tv.tv_sec, (long) tv.tv_usec);
2591 }
2592 printtrailer();
2593
2594 dumpio(tcp);
2595 if (fflush(tcp->outf) == EOF)
2596 return -1;
2597 tcp->flags &= ~TCB_INSYSCALL;
2598 return 0;
2599}
2600
2601static int
2602trace_syscall_entering(struct tcb *tcp)
2603{
2604 int sys_res;
2605 int res, scno_good;
2606
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002607 scno_good = res = get_scno(tcp);
2608 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002609 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002610 if (res == 1)
2611 res = syscall_fixup(tcp);
2612 if (res == 0)
2613 return res;
2614 if (res == 1)
2615 res = syscall_enter(tcp);
2616 if (res == 0)
2617 return res;
2618
2619 if (res != 1) {
2620 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002621 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002622 tcp_last = tcp;
2623 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002624 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002625 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2626 tprintf("syscall_%lu(", tcp->scno);
2627 else
2628 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002629 /*
2630 * " <unavailable>" will be added later by the code which
2631 * detects ptrace errors.
2632 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002633 tcp->flags |= TCB_INSYSCALL;
2634 return res;
2635 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002636
Roland McGrath17352792005-06-07 23:21:26 +00002637 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002638#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002639 case SYS_socketcall:
2640 decode_subcall(tcp, SYS_socket_subcall,
2641 SYS_socket_nsubcalls, deref_style);
2642 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002643#endif
2644#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002645 case SYS_ipc:
2646 decode_subcall(tcp, SYS_ipc_subcall,
2647 SYS_ipc_nsubcalls, shift_style);
2648 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002649#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002650#ifdef SVR4
2651#ifdef SYS_pgrpsys_subcall
2652 case SYS_pgrpsys:
2653 decode_subcall(tcp, SYS_pgrpsys_subcall,
2654 SYS_pgrpsys_nsubcalls, shift_style);
2655 break;
2656#endif /* SYS_pgrpsys_subcall */
2657#ifdef SYS_sigcall_subcall
2658 case SYS_sigcall:
2659 decode_subcall(tcp, SYS_sigcall_subcall,
2660 SYS_sigcall_nsubcalls, mask_style);
2661 break;
2662#endif /* SYS_sigcall_subcall */
2663 case SYS_msgsys:
2664 decode_subcall(tcp, SYS_msgsys_subcall,
2665 SYS_msgsys_nsubcalls, shift_style);
2666 break;
2667 case SYS_shmsys:
2668 decode_subcall(tcp, SYS_shmsys_subcall,
2669 SYS_shmsys_nsubcalls, shift_style);
2670 break;
2671 case SYS_semsys:
2672 decode_subcall(tcp, SYS_semsys_subcall,
2673 SYS_semsys_nsubcalls, shift_style);
2674 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002675 case SYS_sysfs:
2676 decode_subcall(tcp, SYS_sysfs_subcall,
2677 SYS_sysfs_nsubcalls, shift_style);
2678 break;
2679 case SYS_spcall:
2680 decode_subcall(tcp, SYS_spcall_subcall,
2681 SYS_spcall_nsubcalls, shift_style);
2682 break;
2683#ifdef SYS_context_subcall
2684 case SYS_context:
2685 decode_subcall(tcp, SYS_context_subcall,
2686 SYS_context_nsubcalls, shift_style);
2687 break;
2688#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002689#ifdef SYS_door_subcall
2690 case SYS_door:
2691 decode_subcall(tcp, SYS_door_subcall,
2692 SYS_door_nsubcalls, door_style);
2693 break;
2694#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002695#ifdef SYS_kaio_subcall
2696 case SYS_kaio:
2697 decode_subcall(tcp, SYS_kaio_subcall,
2698 SYS_kaio_nsubcalls, shift_style);
2699 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002700#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002701#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002702#ifdef FREEBSD
2703 case SYS_msgsys:
2704 case SYS_shmsys:
2705 case SYS_semsys:
2706 decode_subcall(tcp, 0, 0, table_style);
2707 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002708#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002709#ifdef SUNOS4
2710 case SYS_semsys:
2711 decode_subcall(tcp, SYS_semsys_subcall,
2712 SYS_semsys_nsubcalls, shift_style);
2713 break;
2714 case SYS_msgsys:
2715 decode_subcall(tcp, SYS_msgsys_subcall,
2716 SYS_msgsys_nsubcalls, shift_style);
2717 break;
2718 case SYS_shmsys:
2719 decode_subcall(tcp, SYS_shmsys_subcall,
2720 SYS_shmsys_nsubcalls, shift_style);
2721 break;
2722#endif
2723 }
2724
2725 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002726 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002727 tcp->flags |= TCB_INSYSCALL;
2728 return 0;
2729 }
2730
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002731 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002732 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002733 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002734 return 0;
2735 }
2736
2737 printleader(tcp);
2738 tcp->flags &= ~TCB_REPRINT;
2739 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002740 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741 tprintf("syscall_%lu(", tcp->scno);
2742 else
2743 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002744 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002745 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2746 sys_res = printargs(tcp);
2747 else
2748 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2749 if (fflush(tcp->outf) == EOF)
2750 return -1;
2751 tcp->flags |= TCB_INSYSCALL;
2752 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002753 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002754 gettimeofday(&tcp->etime, NULL);
2755 return sys_res;
2756}
2757
2758int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002759trace_syscall(struct tcb *tcp)
2760{
2761 return exiting(tcp) ?
2762 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2763}
2764
2765int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002766printargs(tcp)
2767struct tcb *tcp;
2768{
2769 if (entering(tcp)) {
2770 int i;
2771
2772 for (i = 0; i < tcp->u_nargs; i++)
2773 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2774 }
2775 return 0;
2776}
2777
2778long
2779getrval2(tcp)
2780struct tcb *tcp;
2781{
2782 long val = -1;
2783
2784#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002785#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002786 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002787 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002788 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002789 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002790#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002791 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002792 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002793#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002794 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002795 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002796#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002797#endif /* LINUX */
2798
2799#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002800 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002801 return -1;
2802#endif /* SUNOS4 */
2803
2804#ifdef SVR4
2805#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002806 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002807#endif /* SPARC */
2808#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002809 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002810#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002811#ifdef X86_64
2812 val = tcp->status.PR_REG[RDX];
2813#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002814#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002815 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002816#endif /* MIPS */
2817#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002818
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002819#ifdef FREEBSD
2820 struct reg regs;
2821 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2822 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002823#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002824 return val;
2825}
2826
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002827#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002828/*
2829 * Apparently, indirect system calls have already be converted by ptrace(2),
2830 * so if you see "indir" this program has gone astray.
2831 */
2832int
2833sys_indir(tcp)
2834struct tcb *tcp;
2835{
2836 int i, scno, nargs;
2837
2838 if (entering(tcp)) {
2839 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2840 fprintf(stderr, "Bogus syscall: %u\n", scno);
2841 return 0;
2842 }
2843 nargs = sysent[scno].nargs;
2844 tprintf("%s", sysent[scno].sys_name);
2845 for (i = 0; i < nargs; i++)
2846 tprintf(", %#lx", tcp->u_arg[i+1]);
2847 }
2848 return 0;
2849}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002850#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002851
2852int
2853is_restart_error(struct tcb *tcp)
2854{
2855#ifdef LINUX
2856 if (!syserror(tcp))
2857 return 0;
2858 switch (tcp->u_error) {
2859 case ERESTARTSYS:
2860 case ERESTARTNOINTR:
2861 case ERESTARTNOHAND:
2862 case ERESTART_RESTARTBLOCK:
2863 return 1;
2864 default:
2865 break;
2866 }
2867#endif /* LINUX */
2868 return 0;
2869}