blob: 8a77ec2e2d34abe41cc10d5807d95e1330980c55 [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
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020093#warning: NSIG is not defined, using 32
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000094#define NSIG 32
95#endif
96#ifdef ARM
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020097/* Ugh. Is this really correct? ARM has no RT signals?! */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098#undef NSIG
99#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000100#undef NR_SYSCALL_BASE
101#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102#endif
103#endif /* LINUX */
104
105#include "syscall.h"
106
107/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000108#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000109#define TF TRACE_FILE
110#define TI TRACE_IPC
111#define TN TRACE_NETWORK
112#define TP TRACE_PROCESS
113#define TS TRACE_SIGNAL
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000114#define NF SYSCALL_NEVER_FAILS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115
Roland McGrathee36ce12004-09-04 03:53:10 +0000116static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117#include "syscallent.h"
118};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000119static const int nsyscalls0 = ARRAY_SIZE(sysent0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000120int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000121
122#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000123static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000124#include "syscallent1.h"
125};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000126static const int nsyscalls1 = ARRAY_SIZE(sysent1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000127int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000128#endif /* SUPPORTED_PERSONALITIES >= 2 */
129
130#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000132#include "syscallent2.h"
133};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000134static const int nsyscalls2 = ARRAY_SIZE(sysent2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000135int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000136#endif /* SUPPORTED_PERSONALITIES >= 3 */
137
Roland McGrathee36ce12004-09-04 03:53:10 +0000138const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000139int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140int nsyscalls;
141
142/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000143#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#undef TF
145#undef TI
146#undef TN
147#undef TP
148#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000149#undef NF
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000150
Roland McGrathee36ce12004-09-04 03:53:10 +0000151static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152#include "errnoent.h"
153};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000154static const int nerrnos0 = ARRAY_SIZE(errnoent0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000155
156#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000157static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000158#include "errnoent1.h"
159};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000160static const int nerrnos1 = ARRAY_SIZE(errnoent1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000161#endif /* SUPPORTED_PERSONALITIES >= 2 */
162
163#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000164static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000165#include "errnoent2.h"
166};
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000167static const int nerrnos2 = ARRAY_SIZE(errnoent2);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000168#endif /* SUPPORTED_PERSONALITIES >= 3 */
169
Roland McGrathee36ce12004-09-04 03:53:10 +0000170const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000171int nerrnos;
172
173int current_personality;
174
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000175#ifndef PERSONALITY0_WORDSIZE
176# define PERSONALITY0_WORDSIZE sizeof(long)
177#endif
178const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
179 PERSONALITY0_WORDSIZE,
180#if SUPPORTED_PERSONALITIES > 1
181 PERSONALITY1_WORDSIZE,
182#endif
183#if SUPPORTED_PERSONALITIES > 2
184 PERSONALITY2_WORDSIZE,
185#endif
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200186};
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000187
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200188void
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000189set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000190{
191 switch (personality) {
192 case 0:
193 errnoent = errnoent0;
194 nerrnos = nerrnos0;
195 sysent = sysent0;
196 nsyscalls = nsyscalls0;
197 ioctlent = ioctlent0;
198 nioctlents = nioctlents0;
199 signalent = signalent0;
200 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000201 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000202 break;
203
204#if SUPPORTED_PERSONALITIES >= 2
205 case 1:
206 errnoent = errnoent1;
207 nerrnos = nerrnos1;
208 sysent = sysent1;
209 nsyscalls = nsyscalls1;
210 ioctlent = ioctlent1;
211 nioctlents = nioctlents1;
212 signalent = signalent1;
213 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000214 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000215 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200216#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000217
218#if SUPPORTED_PERSONALITIES >= 3
219 case 2:
220 errnoent = errnoent2;
221 nerrnos = nerrnos2;
222 sysent = sysent2;
223 nsyscalls = nsyscalls2;
224 ioctlent = ioctlent2;
225 nioctlents = nioctlents2;
226 signalent = signalent2;
227 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000228 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000229 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200230#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000231 }
232
233 current_personality = personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000234}
235
Roland McGrathe10e62a2004-09-04 04:20:43 +0000236
Roland McGrath9797ceb2002-12-30 10:23:00 +0000237static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000238
Roland McGrathe10e62a2004-09-04 04:20:43 +0000239static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000241 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000242 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000243 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000244} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000245 { QUAL_TRACE, "trace", qual_syscall, "system call" },
246 { QUAL_TRACE, "t", qual_syscall, "system call" },
247 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
248 { QUAL_ABBREV, "a", qual_syscall, "system call" },
249 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
250 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
251 { QUAL_RAW, "raw", qual_syscall, "system call" },
252 { QUAL_RAW, "x", qual_syscall, "system call" },
253 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
254 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
255 { QUAL_SIGNAL, "s", qual_signal, "signal" },
256 { QUAL_FAULT, "fault", qual_fault, "fault" },
257 { QUAL_FAULT, "faults", qual_fault, "fault" },
258 { QUAL_FAULT, "m", qual_fault, "fault" },
259 { QUAL_READ, "read", qual_desc, "descriptor" },
260 { QUAL_READ, "reads", qual_desc, "descriptor" },
261 { QUAL_READ, "r", qual_desc, "descriptor" },
262 { QUAL_WRITE, "write", qual_desc, "descriptor" },
263 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
264 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000265 { 0, NULL, NULL, NULL },
266};
267
Roland McGrath9797ceb2002-12-30 10:23:00 +0000268static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000269qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000270{
Roland McGrath138c6a32006-01-12 09:50:49 +0000271 if (pers == 0 || pers < 0) {
272 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000273 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000274 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000275 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000276 }
277
278#if SUPPORTED_PERSONALITIES >= 2
279 if (pers == 1 || pers < 0) {
280 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000281 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000282 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000283 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000284 }
285#endif /* SUPPORTED_PERSONALITIES >= 2 */
286
287#if SUPPORTED_PERSONALITIES >= 3
288 if (pers == 2 || pers < 0) {
289 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000290 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000291 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000292 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000293 }
294#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000295}
296
297static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000298qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000299{
300 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000301 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000302
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000303 if (isdigit((unsigned char)*s)) {
304 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000305 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000306 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000307 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000308 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000309 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000310 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000311 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000312 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000313 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000314 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000315
316#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000317 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000318 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000319 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000320 rc = 0;
321 }
322#endif /* SUPPORTED_PERSONALITIES >= 2 */
323
324#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000325 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000326 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000327 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000328 rc = 0;
329 }
330#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000331
Roland McGrathfe6b3522005-02-02 04:40:11 +0000332 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000333}
334
335static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000336qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000337{
338 int i;
339 char buf[32];
340
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000341 if (isdigit((unsigned char)*s)) {
342 int signo = atoi(s);
343 if (signo < 0 || signo >= MAX_QUALS)
344 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000345 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000346 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000347 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000348 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000349 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000350 strcpy(buf, s);
351 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000352 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000353 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000354 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000355 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000356 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000357 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000358 }
Roland McGrath76421df2005-02-02 03:51:18 +0000359 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000360}
361
362static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000363qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000364{
365 return -1;
366}
367
368static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000369qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000370{
Roland McGrath48a035f2006-01-12 09:45:56 +0000371 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000372 int desc = atoi(s);
373 if (desc < 0 || desc >= MAX_QUALS)
374 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000375 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000376 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000377 }
378 return -1;
379}
380
381static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000382lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000383{
384 if (strcmp(s, "file") == 0)
385 return TRACE_FILE;
386 if (strcmp(s, "ipc") == 0)
387 return TRACE_IPC;
388 if (strcmp(s, "network") == 0)
389 return TRACE_NETWORK;
390 if (strcmp(s, "process") == 0)
391 return TRACE_PROCESS;
392 if (strcmp(s, "signal") == 0)
393 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000394 if (strcmp(s, "desc") == 0)
395 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000396 return -1;
397}
398
399void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000400qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000401{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000402 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000403 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000404 char *copy;
405 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000406 int i, n;
407
408 opt = &qual_options[0];
409 for (i = 0; (p = qual_options[i].option_name); i++) {
410 n = strlen(p);
411 if (strncmp(s, p, n) == 0 && s[n] == '=') {
412 opt = &qual_options[i];
413 s += n + 1;
414 break;
415 }
416 }
417 not = 0;
418 if (*s == '!') {
419 not = 1;
420 s++;
421 }
422 if (strcmp(s, "none") == 0) {
423 not = 1 - not;
424 s = "all";
425 }
426 if (strcmp(s, "all") == 0) {
427 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000428 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000429 }
430 return;
431 }
432 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000433 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000434 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000435 if (!(copy = strdup(s))) {
436 fprintf(stderr, "out of memory\n");
437 exit(1);
438 }
439 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000440 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000441 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000442 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000443 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000444
445#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000446 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000447 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000448 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000449#endif /* SUPPORTED_PERSONALITIES >= 2 */
450
451#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000452 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000453 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000454 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000455#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000456
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000457 continue;
458 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000459 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000460 fprintf(stderr, "strace: invalid %s `%s'\n",
461 opt->argument_name, p);
462 exit(1);
463 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000465 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000466 return;
467}
468
469static void
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000470dumpio(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000471{
472 if (syserror(tcp))
473 return;
474 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
475 return;
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000476 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
477 return;
478 if (sysent[tcp->scno].sys_func == printargs)
479 return;
480 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
481 if (sysent[tcp->scno].sys_func == sys_read ||
482 sysent[tcp->scno].sys_func == sys_pread ||
483 sysent[tcp->scno].sys_func == sys_pread64 ||
484 sysent[tcp->scno].sys_func == sys_recv ||
485 sysent[tcp->scno].sys_func == sys_recvfrom)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000486 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000487 else if (sysent[tcp->scno].sys_func == sys_readv)
488 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
489 return;
490 }
491 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
492 if (sysent[tcp->scno].sys_func == sys_write ||
493 sysent[tcp->scno].sys_func == sys_pwrite ||
494 sysent[tcp->scno].sys_func == sys_pwrite64 ||
495 sysent[tcp->scno].sys_func == sys_send ||
496 sysent[tcp->scno].sys_func == sys_sendto)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000497 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000498 else if (sysent[tcp->scno].sys_func == sys_writev)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000499 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000500 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000501 }
502}
503
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000504#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000505enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000506#else /* FREEBSD */
507enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
508
509struct subcall {
510 int call;
511 int nsubcalls;
512 int subcalls[5];
513};
514
Roland McGratha4d48532005-06-08 20:45:28 +0000515static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000516 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000517#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000518 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000519#else
520 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
521#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000522 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
523};
524#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000525
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000526#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527
Roland McGratha4d48532005-06-08 20:45:28 +0000528static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200529decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000530{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000531 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000532 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000533 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000534
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000535 switch (style) {
536 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000537 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
538 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539 tcp->scno = subcall + tcp->u_arg[0];
540 if (sysent[tcp->scno].nargs != -1)
541 tcp->u_nargs = sysent[tcp->scno].nargs;
542 else
543 tcp->u_nargs--;
544 for (i = 0; i < tcp->u_nargs; i++)
545 tcp->u_arg[i] = tcp->u_arg[i + 1];
546 break;
547 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000548 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
549 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000550 tcp->scno = subcall + tcp->u_arg[0];
551 addr = tcp->u_arg[1];
552 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000553 if (size == sizeof(int)) {
554 unsigned int arg;
555 if (umove(tcp, addr, &arg) < 0)
556 arg = 0;
557 tcp->u_arg[i] = arg;
558 }
559 else if (size == sizeof(long)) {
560 unsigned long arg;
561 if (umove(tcp, addr, &arg) < 0)
562 arg = 0;
563 tcp->u_arg[i] = arg;
564 }
565 else
566 abort();
567 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568 }
569 tcp->u_nargs = sysent[tcp->scno].nargs;
570 break;
571 case mask_style:
572 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000573 for (i = 0; mask; i++)
574 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000575 if (i >= nsubcalls)
576 return;
577 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000578 tcp->scno = subcall + i;
579 if (sysent[tcp->scno].nargs != -1)
580 tcp->u_nargs = sysent[tcp->scno].nargs;
581 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000582 case door_style:
583 /*
584 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000585 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000586 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000587 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
588 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000589 tcp->scno = subcall + tcp->u_arg[5];
590 if (sysent[tcp->scno].nargs != -1)
591 tcp->u_nargs = sysent[tcp->scno].nargs;
592 else
593 tcp->u_nargs--;
594 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000595#ifdef FREEBSD
596 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000597 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000598 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000599 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000600 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
601 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
602 for (i = 0; i < tcp->u_nargs; i++)
603 tcp->u_arg[i] = tcp->u_arg[i + 1];
604 }
605 break;
606#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 }
608}
609#endif
610
611struct tcb *tcp_last = NULL;
612
613static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000614internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615{
616 /*
617 * We must always trace a few critical system calls in order to
618 * correctly support following forks in the presence of tracing
619 * qualifiers.
620 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000621 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000622
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000623 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
624 return 0;
625
626 func = sysent[tcp->scno].sys_func;
627
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000628 if ( sys_fork == func
629#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
630 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000632#ifdef LINUX
633 || sys_clone == func
634#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000635#if UNIXWARE > 2
636 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000637#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000638 )
639 return internal_fork(tcp);
640
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000641 if ( sys_execve == func
642#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
643 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000644#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000645#if UNIXWARE > 2
646 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000647#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000648 )
649 return internal_exec(tcp);
650
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000651 return 0;
652}
653
Wichert Akkermanc7926982000-04-10 22:22:31 +0000654
655#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200656# if defined (I386)
657static long eax;
658# elif defined (IA64)
659long r8, r10, psr; /* TODO: make static? */
660long ia32 = 0; /* not static */
661# elif defined (POWERPC)
662static long result, flags;
663# elif defined (M68K)
664static long d0;
665# elif defined(BFIN)
666static long r0;
667# elif defined (ARM)
668static struct pt_regs regs;
669# elif defined (ALPHA)
670static long r0;
671static long a3;
672# elif defined(AVR32)
673static struct pt_regs regs;
674# elif defined (SPARC) || defined (SPARC64)
675static struct pt_regs regs;
676static unsigned long trap;
677# elif defined(LINUX_MIPSN32)
678static long long a3;
679static long long r2;
680# elif defined(MIPS)
681static long a3;
682static long r2;
683# elif defined(S390) || defined(S390X)
684static long gpr2;
685static long pc;
686static long syscall_mode;
687# elif defined(HPPA)
688static long r28;
689# elif defined(SH)
690static long r0;
691# elif defined(SH64)
692static long r9;
693# elif defined(X86_64)
694static long rax;
695# elif defined(CRISV10) || defined(CRISV32)
696static long r10;
697# elif defined(MICROBLAZE)
698static long r3;
699# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000700#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000701#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200702struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000703#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000704
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000705int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000706get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000707{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000708 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000709
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000710#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000711# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000712 if (tcp->flags & TCB_WAITEXECVE) {
713 /*
714 * When the execve system call completes successfully, the
715 * new process still has -ENOSYS (old style) or __NR_execve
716 * (new style) in gpr2. We cannot recover the scno again
717 * by disassembly, because the image that executed the
718 * syscall is gone now. Fortunately, we don't want it. We
719 * leave the flag set so that syscall_fixup can fake the
720 * result.
721 */
722 if (tcp->flags & TCB_INSYSCALL)
723 return 1;
724 /*
725 * This is the SIGTRAP after execve. We cannot try to read
726 * the system call here either.
727 */
728 tcp->flags &= ~TCB_WAITEXECVE;
729 return 0;
730 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000731
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000732 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200733 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000734
735 if (syscall_mode != -ENOSYS) {
736 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000737 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000738 */
739 scno = syscall_mode;
740 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000741 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000742 * Old style of "passing" the scno via the SVC instruction.
743 */
744
745 long opcode, offset_reg, tmp;
746 void * svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200747 static const int gpr_offset[16] = {
748 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
749 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
750 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
751 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
752 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000753
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000754 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000755 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000756 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000757 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000758 if (errno) {
759 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000760 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000761 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000762
763 /*
764 * We have to check if the SVC got executed directly or via an
765 * EXECUTE instruction. In case of EXECUTE it is necessary to do
766 * instruction decoding to derive the system call number.
767 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
768 * so that this doesn't work if a SVC opcode is part of an EXECUTE
769 * opcode. Since there is no way to find out the opcode size this
770 * is the best we can do...
771 */
772
773 if ((opcode & 0xff00) == 0x0a00) {
774 /* SVC opcode */
775 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000776 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000777 else {
778 /* SVC got executed by EXECUTE instruction */
779
780 /*
781 * Do instruction decoding of EXECUTE. If you really want to
782 * understand this, read the Principles of Operations.
783 */
784 svc_addr = (void *) (opcode & 0xfff);
785
786 tmp = 0;
787 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000788 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000789 return -1;
790 svc_addr += tmp;
791
792 tmp = 0;
793 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000794 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000795 return -1;
796 svc_addr += tmp;
797
Denys Vlasenkofb036672009-01-23 16:30:26 +0000798 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000799 if (errno)
800 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000801# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000802 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000803# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000804 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000805# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000806 tmp = 0;
807 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000808 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000809 return -1;
810
811 scno = (scno | tmp) & 0xff;
812 }
813 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000814# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000815 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816 return -1;
817 if (!(tcp->flags & TCB_INSYSCALL)) {
818 /* Check if we return from execve. */
819 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
820 tcp->flags &= ~TCB_WAITEXECVE;
821 return 0;
822 }
823 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200824
825# ifdef POWERPC64
826 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200827 /* TODO: speed up strace by not doing this at every syscall.
828 * We only need to do it after execve.
829 */
830 int currpers;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200831 long val;
832 int pid = tcp->pid;
833
834 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200835 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200836 return -1;
837 /* SF is bit 0 of MSR */
838 if (val < 0)
839 currpers = 0;
840 else
841 currpers = 1;
842 if (currpers != current_personality) {
843 static const char *const names[] = {"64 bit", "32 bit"};
844 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000845 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200846 pid, names[current_personality]);
847 }
848 }
849# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000850# elif defined(AVR32)
851 /*
852 * Read complete register set in one go.
853 */
854 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
855 return -1;
856
857 /*
858 * We only need to grab the syscall number on syscall entry.
859 */
860 if (!(tcp->flags & TCB_INSYSCALL)) {
861 scno = regs.r8;
862
863 /* Check if we return from execve. */
864 if (tcp->flags & TCB_WAITEXECVE) {
865 tcp->flags &= ~TCB_WAITEXECVE;
866 return 0;
867 }
868 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000869# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000870 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000871 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000872# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000873 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000874 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000875# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000876 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000877 return -1;
878
Roland McGrath761b5d72002-12-15 23:58:31 +0000879 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200880 /* TODO: speed up strace by not doing this at every syscall.
881 * We only need to do it after execve.
882 */
883 int currpers;
Michal Ludvig0e035502002-09-23 15:41:01 +0000884 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000885 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000886
887 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200888 * 0x33 for long mode (64 bit)
889 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000890 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000891 * to be cached.
892 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000893 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000894 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000895 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000896 case 0x23: currpers = 1; break;
897 case 0x33: currpers = 0; break;
898 default:
899 fprintf(stderr, "Unknown value CS=0x%02X while "
900 "detecting personality of process "
901 "PID=%d\n", (int)val, pid);
902 currpers = current_personality;
903 break;
904 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000905# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000906 /* This version analyzes the opcode of a syscall instruction.
907 * (int 0x80 on i386 vs. syscall on x86-64)
908 * It works, but is too complicated.
909 */
910 unsigned long val, rip, i;
911
Denys Vlasenko8236f252009-01-02 18:10:08 +0000912 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000913 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000914
Michal Ludvig0e035502002-09-23 15:41:01 +0000915 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000916 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000917 errno = 0;
918
Denys Vlasenko8236f252009-01-02 18:10:08 +0000919 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000920 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000921 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000922 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000923 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000924 /* x86-64: syscall = 0x0f 0x05 */
925 case 0x050f: currpers = 0; break;
926 /* i386: int 0x80 = 0xcd 0x80 */
927 case 0x80cd: currpers = 1; break;
928 default:
929 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000930 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000931 "Unknown syscall opcode (0x%04X) while "
932 "detecting personality of process "
933 "PID=%d\n", (int)call, pid);
934 break;
935 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000936# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000937 if (currpers != current_personality) {
938 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000939 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000940 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000941 pid, names[current_personality]);
942 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000943 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000944# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000945# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200946 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000947 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000948 if (!(tcp->flags & TCB_INSYSCALL)) {
949 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000950 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000951 return -1;
952 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200953 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000954 return -1;
955 }
Roland McGrathba954762003-03-05 06:29:06 +0000956 /* Check if we return from execve. */
957 if (tcp->flags & TCB_WAITEXECVE) {
958 tcp->flags &= ~TCB_WAITEXECVE;
959 return 0;
960 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000961 } else {
962 /* syscall in progress */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200963 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000964 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200965 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000966 return -1;
967 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000968# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000969 /*
970 * Read complete register set in one go.
971 */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000972 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000973 return -1;
974
975 /*
976 * We only need to grab the syscall number on syscall entry.
977 */
978 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +0000979 if (!(tcp->flags & TCB_INSYSCALL)) {
980 /* Check if we return from execve. */
981 if (tcp->flags & TCB_WAITEXECVE) {
982 tcp->flags &= ~TCB_WAITEXECVE;
983 return 0;
984 }
985 }
986
Roland McGrath0f87c492003-06-03 23:29:04 +0000987 /*
988 * Note: we only deal with only 32-bit CPUs here.
989 */
990 if (regs.ARM_cpsr & 0x20) {
991 /*
992 * Get the Thumb-mode system call number
993 */
994 scno = regs.ARM_r7;
995 } else {
996 /*
997 * Get the ARM-mode system call number
998 */
999 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001000 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001001 if (errno)
1002 return -1;
1003
1004 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1005 tcp->flags &= ~TCB_WAITEXECVE;
1006 return 0;
1007 }
1008
Roland McGrathf691bd22006-04-25 07:34:41 +00001009 /* Handle the EABI syscall convention. We do not
1010 bother converting structures between the two
1011 ABIs, but basic functionality should work even
1012 if strace and the traced program have different
1013 ABIs. */
1014 if (scno == 0xef000000) {
1015 scno = regs.ARM_r7;
1016 } else {
1017 if ((scno & 0x0ff00000) != 0x0f900000) {
1018 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1019 scno);
1020 return -1;
1021 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001022
Roland McGrathf691bd22006-04-25 07:34:41 +00001023 /*
1024 * Fixup the syscall number
1025 */
1026 scno &= 0x000fffff;
1027 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001028 }
Roland McGrath56703312008-05-20 01:35:55 +00001029 if (scno & 0x0f0000) {
1030 /*
1031 * Handle ARM specific syscall
1032 */
1033 set_personality(1);
1034 scno &= 0x0000ffff;
1035 } else
1036 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001037
1038 if (tcp->flags & TCB_INSYSCALL) {
1039 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1040 tcp->flags &= ~TCB_INSYSCALL;
1041 }
1042 } else {
1043 if (!(tcp->flags & TCB_INSYSCALL)) {
1044 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1045 tcp->flags |= TCB_INSYSCALL;
1046 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001048# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001049 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001051# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001052 unsigned long long regs[38];
1053
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001054 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001055 return -1;
1056 a3 = regs[REG_A3];
1057 r2 = regs[REG_V0];
1058
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001059 if (!(tcp->flags & TCB_INSYSCALL)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001060 scno = r2;
1061
1062 /* Check if we return from execve. */
1063 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1064 tcp->flags &= ~TCB_WAITEXECVE;
1065 return 0;
1066 }
1067
1068 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001069 if (a3 == 0 || a3 == -1) {
1070 if (debug)
1071 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001072 return 0;
1073 }
1074 }
1075 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001076# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001077 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001078 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001079 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001080 if (upeek(tcp, REG_V0, &scno) < 0)
1081 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001082
Roland McGrath542c2c62008-05-20 01:11:56 +00001083 /* Check if we return from execve. */
1084 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1085 tcp->flags &= ~TCB_WAITEXECVE;
1086 return 0;
1087 }
1088
Wichert Akkermanf90da011999-10-31 21:15:38 +00001089 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001090 if (a3 == 0 || a3 == -1) {
1091 if (debug)
1092 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001093 return 0;
1094 }
1095 }
1096 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001097 if (upeek(tcp, REG_V0, &r2) < 0)
1098 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001099 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001100# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001101 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102 return -1;
1103
1104 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001105 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106 return -1;
1107
1108 /* Check if we return from execve. */
1109 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1110 tcp->flags &= ~TCB_WAITEXECVE;
1111 return 0;
1112 }
1113
1114 /*
1115 * Do some sanity checks to figure out if it's
1116 * really a syscall entry
1117 */
1118 if (scno < 0 || scno > nsyscalls) {
1119 if (a3 == 0 || a3 == -1) {
1120 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001121 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 return 0;
1123 }
1124 }
1125 }
1126 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001127 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128 return -1;
1129 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001130# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001132 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001133 return -1;
1134
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001135 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001136 if (!(tcp->flags & TCB_INSYSCALL)) {
1137 /* Retrieve the syscall trap instruction. */
1138 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001139# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001140 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001141 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001142# else
1143 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001144# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145 if (errno)
1146 return -1;
1147
1148 /* Disassemble the trap to see what personality to use. */
1149 switch (trap) {
1150 case 0x91d02010:
1151 /* Linux/SPARC syscall trap. */
1152 set_personality(0);
1153 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001154 case 0x91d0206d:
1155 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001156 set_personality(2);
1157 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001158 case 0x91d02000:
1159 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001160 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161 return -1;
1162 case 0x91d02008:
1163 /* Solaris 2.x syscall trap. (per 2) */
1164 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001165 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 case 0x91d02009:
1167 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001168 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169 return -1;
1170 case 0x91d02027:
1171 /* Solaris 2.x gettimeofday */
1172 set_personality(1);
1173 break;
1174 default:
1175 /* Unknown syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001176 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 tcp->flags &= ~TCB_WAITEXECVE;
1178 return 0;
1179 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001180# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001181 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001182# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001183 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001184# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185 return -1;
1186 }
1187
1188 /* Extract the system call number from the registers. */
1189 if (trap == 0x91d02027)
1190 scno = 156;
1191 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001192 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001194 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001195 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 +00001196 }
1197 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001198# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001199 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001200 return -1;
1201 if (!(tcp->flags & TCB_INSYSCALL)) {
1202 /* Check if we return from execve. */
1203 if ((tcp->flags & TCB_WAITEXECVE)) {
1204 tcp->flags &= ~TCB_WAITEXECVE;
1205 return 0;
1206 }
1207 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001208# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001209 /*
1210 * In the new syscall ABI, the system call number is in R3.
1211 */
1212 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1213 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001214
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001215 if (scno < 0) {
1216 /* Odd as it may seem, a glibc bug has been known to cause
1217 glibc to issue bogus negative syscall numbers. So for
1218 our purposes, make strace print what it *should* have been */
1219 long correct_scno = (scno & 0xff);
1220 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001221 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001222 "Detected glibc bug: bogus system call"
1223 " number = %ld, correcting to %ld\n",
1224 scno,
1225 correct_scno);
1226 scno = correct_scno;
1227 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001228
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001229 if (!(tcp->flags & TCB_INSYSCALL)) {
1230 /* Check if we return from execve. */
1231 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1232 tcp->flags &= ~TCB_WAITEXECVE;
1233 return 0;
1234 }
1235 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001236# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001237 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001238 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001239 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001240
1241 if (!(tcp->flags & TCB_INSYSCALL)) {
1242 /* Check if we return from execve. */
1243 if (tcp->flags & TCB_WAITEXECVE) {
1244 tcp->flags &= ~TCB_WAITEXECVE;
1245 return 0;
1246 }
1247 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001248# elif defined(CRISV10) || defined(CRISV32)
1249 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1250 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001251# elif defined(TILE)
1252 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1253 return -1;
1254
1255 if (!(tcp->flags & TCB_INSYSCALL)) {
1256 /* Check if we return from execve. */
1257 if (tcp->flags & TCB_WAITEXECVE) {
1258 tcp->flags &= ~TCB_WAITEXECVE;
1259 return 0;
1260 }
1261 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001262# elif defined(MICROBLAZE)
1263 if (upeek(tcp, 0, &scno) < 0)
1264 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001265# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001267
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001269 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001270 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001271#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001272 /* new syscall ABI returns result in R0 */
1273 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1274 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001275#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001276 /* ABI defines result returned in r9 */
1277 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1278 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001280
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001281#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001282# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001283 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001284# else
1285# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001286 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001287# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001288 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001289 perror("pread");
1290 return -1;
1291 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001292 switch (regs.r_eax) {
1293 case SYS_syscall:
1294 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001295 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1296 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001297 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001298 scno = regs.r_eax;
1299 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001300 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001301# endif /* FREEBSD */
1302# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001303#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001304
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001305 if (!(tcp->flags & TCB_INSYSCALL))
1306 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001307 return 1;
1308}
1309
Pavel Machek4dc3b142000-02-01 17:58:41 +00001310
Roland McGrath17352792005-06-07 23:21:26 +00001311long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001312known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001313{
1314 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001315#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001316 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1317 scno = sysent[scno].native_scno;
1318 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001319#endif
Roland McGrath17352792005-06-07 23:21:26 +00001320 scno += NR_SYSCALL_BASE;
1321 return scno;
1322}
1323
Roland McGratheb9e2e82009-06-02 16:49:22 -07001324/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001325 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001326 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1327 * 1: ok, continue in trace_syscall().
1328 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001329 * ("????" etc) and bail out.
1330 */
Roland McGratha4d48532005-06-08 20:45:28 +00001331static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001332syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001333{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001334#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001335 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001336
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001337 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001338 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001339 if (
1340 scno == SYS_fork
1341#ifdef SYS_vfork
1342 || scno == SYS_vfork
1343#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001344#ifdef SYS_fork1
1345 || scno == SYS_fork1
1346#endif /* SYS_fork1 */
1347#ifdef SYS_forkall
1348 || scno == SYS_forkall
1349#endif /* SYS_forkall */
1350#ifdef SYS_rfork1
1351 || scno == SYS_rfork1
1352#endif /* SYS_fork1 */
1353#ifdef SYS_rforkall
1354 || scno == SYS_rforkall
1355#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001356 ) {
1357 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001358 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001360 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001361 }
1362 else {
1363 fprintf(stderr, "syscall: missing entry\n");
1364 tcp->flags |= TCB_INSYSCALL;
1365 }
1366 }
1367 }
1368 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001369 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370 fprintf(stderr, "syscall: missing exit\n");
1371 tcp->flags &= ~TCB_INSYSCALL;
1372 }
1373 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001374#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375#ifdef SUNOS4
1376 if (!(tcp->flags & TCB_INSYSCALL)) {
1377 if (scno == 0) {
1378 fprintf(stderr, "syscall: missing entry\n");
1379 tcp->flags |= TCB_INSYSCALL;
1380 }
1381 }
1382 else {
1383 if (scno != 0) {
1384 if (debug) {
1385 /*
1386 * This happens when a signal handler
1387 * for a signal which interrupted a
1388 * a system call makes another system call.
1389 */
1390 fprintf(stderr, "syscall: missing exit\n");
1391 }
1392 tcp->flags &= ~TCB_INSYSCALL;
1393 }
1394 }
1395#endif /* SUNOS4 */
1396#ifdef LINUX
1397#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001398 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001399 return -1;
1400 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1401 if (debug)
1402 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1403 return 0;
1404 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001405#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001406 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001407 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001408 if (current_personality == 1)
1409 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001410 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1411 if (debug)
1412 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1413 return 0;
1414 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001415#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001416 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001417 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001418 if (syscall_mode != -ENOSYS)
1419 syscall_mode = tcp->scno;
1420 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001421 if (debug)
1422 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1423 return 0;
1424 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001425 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1426 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1427 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1428 /*
1429 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1430 * flag set for the post-execve SIGTRAP to see and reset.
1431 */
1432 gpr2 = 0;
1433 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001434#elif defined (POWERPC)
1435# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001436 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001437 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001438 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001439 return -1;
1440 if (flags & SO_MASK)
1441 result = -result;
1442#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001443 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001444 return -1;
1445 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1446 if (debug)
1447 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1448 return 0;
1449 }
1450#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001451 /*
1452 * Nothing required
1453 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001454#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001455 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001456 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001457#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001458 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001459 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001460#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001461 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001462 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001463 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001464 return -1;
1465 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1466 if (debug)
1467 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1468 return 0;
1469 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001470#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001471 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001472 return -1;
1473 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1474 if (debug)
1475 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1476 return 0;
1477 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001478#elif defined(MICROBLAZE)
1479 if (upeek(tcp, 3 * 4, &r3) < 0)
1480 return -1;
1481 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1482 if (debug)
1483 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1484 return 0;
1485 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486#endif
1487#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001488 return 1;
1489}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001490
Roland McGrathc1e45922008-05-27 23:18:29 +00001491#ifdef LINUX
1492/*
1493 * Check the syscall return value register value for whether it is
1494 * a negated errno code indicating an error, or a success return value.
1495 */
1496static inline int
1497is_negated_errno(unsigned long int val)
1498{
1499 unsigned long int max = -(long int) nerrnos;
1500 if (personality_wordsize[current_personality] < sizeof(val)) {
1501 val = (unsigned int) val;
1502 max = (unsigned int) max;
1503 }
1504 return val > max;
1505}
1506#endif
1507
Roland McGratha4d48532005-06-08 20:45:28 +00001508static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001509get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001510{
1511 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001512#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001513 int check_errno = 1;
1514 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1515 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1516 check_errno = 0;
1517 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001518# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001519 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001520 tcp->u_rval = -1;
1521 u_error = -gpr2;
1522 }
1523 else {
1524 tcp->u_rval = gpr2;
1525 u_error = 0;
1526 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001527# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001528 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001529 tcp->u_rval = -1;
1530 u_error = -eax;
1531 }
1532 else {
1533 tcp->u_rval = eax;
1534 u_error = 0;
1535 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001536# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001537 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001538 tcp->u_rval = -1;
1539 u_error = -rax;
1540 }
1541 else {
1542 tcp->u_rval = rax;
1543 u_error = 0;
1544 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001545# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001546 if (ia32) {
1547 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001548
Roland McGrathc1e45922008-05-27 23:18:29 +00001549 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001550 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001551 tcp->u_rval = -1;
1552 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001553 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001554 else {
1555 tcp->u_rval = err;
1556 u_error = 0;
1557 }
1558 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001559 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001560 tcp->u_rval = -1;
1561 u_error = r8;
1562 } else {
1563 tcp->u_rval = r8;
1564 u_error = 0;
1565 }
1566 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001567# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001568 if (check_errno && a3) {
1569 tcp->u_rval = -1;
1570 u_error = r2;
1571 } else {
1572 tcp->u_rval = r2;
1573 u_error = 0;
1574 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001575# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001576 if (check_errno && is_negated_errno(result)) {
1577 tcp->u_rval = -1;
1578 u_error = -result;
1579 }
1580 else {
1581 tcp->u_rval = result;
1582 u_error = 0;
1583 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001584# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001585 if (check_errno && is_negated_errno(d0)) {
1586 tcp->u_rval = -1;
1587 u_error = -d0;
1588 }
1589 else {
1590 tcp->u_rval = d0;
1591 u_error = 0;
1592 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001593# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001594 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1595 tcp->u_rval = -1;
1596 u_error = -regs.ARM_r0;
1597 }
1598 else {
1599 tcp->u_rval = regs.ARM_r0;
1600 u_error = 0;
1601 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001602# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001603 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1604 tcp->u_rval = -1;
1605 u_error = -regs.r12;
1606 }
1607 else {
1608 tcp->u_rval = regs.r12;
1609 u_error = 0;
1610 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001611# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001612 if (check_errno && is_negated_errno(r0)) {
1613 tcp->u_rval = -1;
1614 u_error = -r0;
1615 } else {
1616 tcp->u_rval = r0;
1617 u_error = 0;
1618 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001619# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001620 if (check_errno && a3) {
1621 tcp->u_rval = -1;
1622 u_error = r0;
1623 }
1624 else {
1625 tcp->u_rval = r0;
1626 u_error = 0;
1627 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001628# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001629 if (check_errno && regs.psr & PSR_C) {
1630 tcp->u_rval = -1;
1631 u_error = regs.u_regs[U_REG_O0];
1632 }
1633 else {
1634 tcp->u_rval = regs.u_regs[U_REG_O0];
1635 u_error = 0;
1636 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001637# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001638 if (check_errno && regs.tstate & 0x1100000000UL) {
1639 tcp->u_rval = -1;
1640 u_error = regs.u_regs[U_REG_O0];
1641 }
1642 else {
1643 tcp->u_rval = regs.u_regs[U_REG_O0];
1644 u_error = 0;
1645 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001646# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001647 if (check_errno && is_negated_errno(r28)) {
1648 tcp->u_rval = -1;
1649 u_error = -r28;
1650 }
1651 else {
1652 tcp->u_rval = r28;
1653 u_error = 0;
1654 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001655# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001656 /* interpret R0 as return value or error number */
1657 if (check_errno && is_negated_errno(r0)) {
1658 tcp->u_rval = -1;
1659 u_error = -r0;
1660 }
1661 else {
1662 tcp->u_rval = r0;
1663 u_error = 0;
1664 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001665# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001666 /* interpret result as return value or error number */
1667 if (check_errno && is_negated_errno(r9)) {
1668 tcp->u_rval = -1;
1669 u_error = -r9;
1670 }
1671 else {
1672 tcp->u_rval = r9;
1673 u_error = 0;
1674 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001675# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001676 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1677 tcp->u_rval = -1;
1678 u_error = -r10;
1679 }
1680 else {
1681 tcp->u_rval = r10;
1682 u_error = 0;
1683 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001684# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001685 long rval;
1686 /* interpret result as return value or error number */
1687 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1688 return -1;
1689 if (check_errno && rval < 0 && rval > -nerrnos) {
1690 tcp->u_rval = -1;
1691 u_error = -rval;
1692 }
1693 else {
1694 tcp->u_rval = rval;
1695 u_error = 0;
1696 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001697# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001698 /* interpret result as return value or error number */
1699 if (check_errno && is_negated_errno(r3)) {
1700 tcp->u_rval = -1;
1701 u_error = -r3;
1702 }
1703 else {
1704 tcp->u_rval = r3;
1705 u_error = 0;
1706 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001707# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708#endif /* LINUX */
1709#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001710 /* get error code from user struct */
1711 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1712 return -1;
1713 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001715 /* get system call return value */
1716 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1717 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718#endif /* SUNOS4 */
1719#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001720# ifdef SPARC
1721 /* Judicious guessing goes a long way. */
1722 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1723 tcp->u_rval = -1;
1724 u_error = tcp->status.pr_reg[R_O0];
1725 }
1726 else {
1727 tcp->u_rval = tcp->status.pr_reg[R_O0];
1728 u_error = 0;
1729 }
1730# endif /* SPARC */
1731# ifdef I386
1732 /* Wanna know how to kill an hour single-stepping? */
1733 if (tcp->status.PR_REG[EFL] & 0x1) {
1734 tcp->u_rval = -1;
1735 u_error = tcp->status.PR_REG[EAX];
1736 }
1737 else {
1738 tcp->u_rval = tcp->status.PR_REG[EAX];
1739# ifdef HAVE_LONG_LONG
1740 tcp->u_lrval =
1741 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1742 tcp->status.PR_REG[EAX];
1743# endif
1744 u_error = 0;
1745 }
1746# endif /* I386 */
1747# ifdef X86_64
1748 /* Wanna know how to kill an hour single-stepping? */
1749 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1750 tcp->u_rval = -1;
1751 u_error = tcp->status.PR_REG[RAX];
1752 }
1753 else {
1754 tcp->u_rval = tcp->status.PR_REG[RAX];
1755 u_error = 0;
1756 }
1757# endif /* X86_64 */
1758# ifdef MIPS
1759 if (tcp->status.pr_reg[CTX_A3]) {
1760 tcp->u_rval = -1;
1761 u_error = tcp->status.pr_reg[CTX_V0];
1762 }
1763 else {
1764 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1765 u_error = 0;
1766 }
1767# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001768#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001769#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001770 if (regs.r_eflags & PSL_C) {
1771 tcp->u_rval = -1;
1772 u_error = regs.r_eax;
1773 } else {
1774 tcp->u_rval = regs.r_eax;
1775 tcp->u_lrval =
1776 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1777 u_error = 0;
1778 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001779#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001780 tcp->u_error = u_error;
1781 return 1;
1782}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001783
Roland McGrathb69f81b2002-12-21 23:25:18 +00001784int
Denys Vlasenko12014262011-05-30 14:00:14 +02001785force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001786{
1787#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001788# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001789 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001790 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1791 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001792# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001793 eax = error ? -error : rval;
1794 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1795 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001796# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001797 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001798 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001799 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001800# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001801 if (ia32) {
1802 r8 = error ? -error : rval;
1803 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1804 return -1;
1805 }
1806 else {
1807 if (error) {
1808 r8 = error;
1809 r10 = -1;
1810 }
1811 else {
1812 r8 = rval;
1813 r10 = 0;
1814 }
1815 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1816 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1817 return -1;
1818 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001819# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001820 r0 = error ? -error : rval;
1821 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1822 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001823# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001824 if (error) {
1825 r2 = error;
1826 a3 = -1;
1827 }
1828 else {
1829 r2 = rval;
1830 a3 = 0;
1831 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001832 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001833 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1834 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001835 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001836# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001837 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001838 return -1;
1839 if (error) {
1840 flags |= SO_MASK;
1841 result = error;
1842 }
1843 else {
1844 flags &= ~SO_MASK;
1845 result = rval;
1846 }
Roland McGratheb285352003-01-14 09:59:00 +00001847 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1848 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001849 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001850# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001851 d0 = error ? -error : rval;
1852 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1853 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001854# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001855 regs.ARM_r0 = error ? -error : rval;
1856 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001857 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001858# elif defined(AVR32)
1859 regs.r12 = error ? -error : rval;
1860 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1861 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001862# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001863 if (error) {
1864 a3 = -1;
1865 r0 = error;
1866 }
1867 else {
1868 a3 = 0;
1869 r0 = rval;
1870 }
1871 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1872 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1873 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001874# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001875 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1876 return -1;
1877 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001878 regs.psr |= PSR_C;
1879 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001880 }
1881 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001882 regs.psr &= ~PSR_C;
1883 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001884 }
1885 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1886 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001887# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001888 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1889 return -1;
1890 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001891 regs.tstate |= 0x1100000000UL;
1892 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001893 }
1894 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001895 regs.tstate &= ~0x1100000000UL;
1896 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001897 }
1898 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1899 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001900# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001901 r28 = error ? -error : rval;
1902 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1903 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001904# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001905 r0 = error ? -error : rval;
1906 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1907 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001908# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001909 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001910 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1911 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001912# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001913#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001914
Roland McGrathb69f81b2002-12-21 23:25:18 +00001915#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001916 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1917 error << 24) < 0 ||
1918 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001919 return -1;
1920#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001921
Roland McGrathb69f81b2002-12-21 23:25:18 +00001922#ifdef SVR4
1923 /* XXX no clue */
1924 return -1;
1925#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001926
Roland McGrathb69f81b2002-12-21 23:25:18 +00001927#ifdef FREEBSD
1928 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001929 perror("pread");
1930 return -1;
1931 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001932 if (error) {
1933 regs.r_eflags |= PSL_C;
1934 regs.r_eax = error;
1935 }
1936 else {
1937 regs.r_eflags &= ~PSL_C;
1938 regs.r_eax = rval;
1939 }
1940 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001941 perror("pwrite");
1942 return -1;
1943 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001944#endif /* FREEBSD */
1945
1946 /* All branches reach here on success (only). */
1947 tcp->u_error = error;
1948 tcp->u_rval = rval;
1949 return 0;
1950}
1951
Roland McGratha4d48532005-06-08 20:45:28 +00001952static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001953syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001954{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001955#ifdef LINUX
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001956# if defined(S390) || defined(S390X)
1957 int i;
1958 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1959 tcp->u_nargs = sysent[tcp->scno].nargs;
1960 else
1961 tcp->u_nargs = MAX_ARGS;
1962 for (i = 0; i < tcp->u_nargs; i++) {
1963 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1964 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001965 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001966# elif defined(ALPHA)
1967 int i;
1968 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1969 tcp->u_nargs = sysent[tcp->scno].nargs;
1970 else
1971 tcp->u_nargs = MAX_ARGS;
1972 for (i = 0; i < tcp->u_nargs; i++) {
1973 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1974 * for scno somewhere above here!
1975 */
1976 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1977 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001978 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001979# elif defined(IA64)
1980 if (!ia32) {
1981 unsigned long *out0, cfm, sof, sol, i;
1982 long rbs_end;
1983 /* be backwards compatible with kernel < 2.4.4... */
1984# ifndef PT_RBS_END
1985# define PT_RBS_END PT_AR_BSP
1986# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001987
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001988 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1989 return -1;
1990 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001991 return -1;
1992
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001993 sof = (cfm >> 0) & 0x7f;
1994 sol = (cfm >> 7) & 0x7f;
1995 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1996
1997 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1998 && sysent[tcp->scno].nargs != -1)
1999 tcp->u_nargs = sysent[tcp->scno].nargs;
2000 else
2001 tcp->u_nargs = MAX_ARGS;
2002 for (i = 0; i < tcp->u_nargs; ++i) {
2003 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2004 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2005 return -1;
2006 }
2007 } else {
2008 int i;
2009
2010 if (/* EBX = out0 */
2011 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
2012 /* ECX = out1 */
2013 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
2014 /* EDX = out2 */
2015 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
2016 /* ESI = out3 */
2017 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
2018 /* EDI = out4 */
2019 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
2020 /* EBP = out5 */
2021 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2022 return -1;
2023
2024 for (i = 0; i < 6; ++i)
2025 /* truncate away IVE sign-extension */
2026 tcp->u_arg[i] &= 0xffffffff;
2027
2028 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2029 && sysent[tcp->scno].nargs != -1)
2030 tcp->u_nargs = sysent[tcp->scno].nargs;
2031 else
2032 tcp->u_nargs = 5;
2033 }
2034# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2035 /* N32 and N64 both use up to six registers. */
2036 unsigned long long regs[38];
2037 int i, nargs;
2038 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2039 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2040 else
2041 nargs = tcp->u_nargs = MAX_ARGS;
2042
2043 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2044 return -1;
2045
2046 for (i = 0; i < nargs; i++) {
2047 tcp->u_arg[i] = regs[REG_A0 + i];
2048# if defined(LINUX_MIPSN32)
2049 tcp->ext_arg[i] = regs[REG_A0 + i];
2050# endif
2051 }
2052# elif defined(MIPS)
2053 long sp;
2054 int i, nargs;
2055
2056 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2057 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2058 else
2059 nargs = tcp->u_nargs = MAX_ARGS;
2060 if (nargs > 4) {
2061 if (upeek(tcp, REG_SP, &sp) < 0)
2062 return -1;
2063 for (i = 0; i < 4; i++) {
2064 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2065 return -1;
2066 }
2067 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2068 (char *)(tcp->u_arg + 4));
2069 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002070 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002071 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002072 return -1;
2073 }
2074 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002075# elif defined(POWERPC)
2076# ifndef PT_ORIG_R3
2077# define PT_ORIG_R3 34
2078# endif
2079 int i;
2080 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2081 tcp->u_nargs = sysent[tcp->scno].nargs;
2082 else
2083 tcp->u_nargs = MAX_ARGS;
2084 for (i = 0; i < tcp->u_nargs; i++) {
2085 if (upeek(tcp, (i==0) ?
2086 (sizeof(unsigned long) * PT_ORIG_R3) :
2087 ((i+PT_R3) * sizeof(unsigned long)),
2088 &tcp->u_arg[i]) < 0)
2089 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002090 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002091# elif defined(SPARC) || defined(SPARC64)
2092 int i;
2093 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2094 tcp->u_nargs = sysent[tcp->scno].nargs;
2095 else
2096 tcp->u_nargs = MAX_ARGS;
2097 for (i = 0; i < tcp->u_nargs; i++)
2098 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2099# elif defined(HPPA)
2100 int i;
2101 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2102 tcp->u_nargs = sysent[tcp->scno].nargs;
2103 else
2104 tcp->u_nargs = MAX_ARGS;
2105 for (i = 0; i < tcp->u_nargs; i++) {
2106 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2107 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002108 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002109# elif defined(ARM)
2110 int i;
2111 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2112 tcp->u_nargs = sysent[tcp->scno].nargs;
2113 else
2114 tcp->u_nargs = MAX_ARGS;
2115 for (i = 0; i < tcp->u_nargs; i++)
2116 tcp->u_arg[i] = regs.uregs[i];
2117# elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002118 tcp->u_nargs = sysent[tcp->scno].nargs;
2119 tcp->u_arg[0] = regs.r12;
2120 tcp->u_arg[1] = regs.r11;
2121 tcp->u_arg[2] = regs.r10;
2122 tcp->u_arg[3] = regs.r9;
2123 tcp->u_arg[4] = regs.r5;
2124 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002125# elif defined(BFIN)
2126 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002127 static const int argreg[] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002128
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002129 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002130 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002131 else
2132 tcp->u_nargs = ARRAY_SIZE(argreg);
2133
2134 for (i = 0; i < tcp->u_nargs; ++i)
2135 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2136 return -1;
2137# elif defined(SH)
2138 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002139 static const int syscall_regs[] = {
2140 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6), 4 * (REG_REG0+7),
2141 4 * (REG_REG0 ), 4 * (REG_REG0+1), 4 * (REG_REG0+2)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002142 };
2143
2144 tcp->u_nargs = sysent[tcp->scno].nargs;
2145 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002146 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002147 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002148 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002149# elif defined(SH64)
2150 int i;
2151 /* Registers used by SH5 Linux system calls for parameters */
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002152 static const int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002153
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002154 /*
2155 * TODO: should also check that the number of arguments encoded
2156 * in the trap number matches the number strace expects.
2157 */
2158 /*
2159 assert(sysent[tcp->scno].nargs < ARRAY_SIZE(syscall_regs));
2160 */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002161
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002162 tcp->u_nargs = sysent[tcp->scno].nargs;
2163 for (i = 0; i < tcp->u_nargs; i++) {
2164 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2165 return -1;
2166 }
2167# elif defined(X86_64)
2168 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002169 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2170 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2171 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002172 };
2173
2174 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002175 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002176 else
2177 tcp->u_nargs = MAX_ARGS;
2178 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002179 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002180 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00002181 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002182# elif defined(MICROBLAZE)
2183 int i;
2184 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2185 tcp->u_nargs = sysent[tcp->scno].nargs;
2186 else
2187 tcp->u_nargs = 0;
2188 for (i = 0; i < tcp->u_nargs; i++) {
2189 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2190 return -1;
2191 }
2192# elif defined(CRISV10) || defined(CRISV32)
2193 int i;
2194 static const int crisregs[] = {
2195 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002196 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002197 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002198
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002199 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2200 tcp->u_nargs = sysent[tcp->scno].nargs;
2201 else
2202 tcp->u_nargs = 0;
2203 for (i = 0; i < tcp->u_nargs; i++) {
2204 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2205 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00002206 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002207# elif defined(TILE)
2208 int i;
2209 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2210 tcp->u_nargs = sysent[tcp->scno].nargs;
2211 else
2212 tcp->u_nargs = MAX_ARGS;
2213 for (i = 0; i < tcp->u_nargs; ++i) {
2214 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2215 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002216 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002217# elif defined(M68K)
2218 int i;
2219 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2220 tcp->u_nargs = sysent[tcp->scno].nargs;
2221 else
2222 tcp->u_nargs = MAX_ARGS;
2223 for (i = 0; i < tcp->u_nargs; i++) {
2224 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2225 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002226 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002227# else /* Other architecture (like i386) (32bits specific) */
2228 int i;
2229 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2230 tcp->u_nargs = sysent[tcp->scno].nargs;
2231 else
2232 tcp->u_nargs = MAX_ARGS;
2233 for (i = 0; i < tcp->u_nargs; i++) {
2234 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2235 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05002236 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002237# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002238#endif /* LINUX */
2239#ifdef SUNOS4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002240 int i;
2241 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2242 tcp->u_nargs = sysent[tcp->scno].nargs;
2243 else
2244 tcp->u_nargs = MAX_ARGS;
2245 for (i = 0; i < tcp->u_nargs; i++) {
2246 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002248 if (upeek(tcp, uoff(u_arg[0]) +
2249 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2250 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002251 }
2252#endif /* SUNOS4 */
2253#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002254# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002255 /*
2256 * SGI is broken: even though it has pr_sysarg, it doesn't
2257 * set them on system call entry. Get a clue.
2258 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002259 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002260 tcp->u_nargs = sysent[tcp->scno].nargs;
2261 else
2262 tcp->u_nargs = tcp->status.pr_nsysarg;
2263 if (tcp->u_nargs > 4) {
2264 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002265 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002266 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002267 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002268 }
2269 else {
2270 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002271 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002272 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002273# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002274 /*
2275 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2276 */
2277 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2278 tcp->u_nargs = sysent[tcp->scno].nargs;
2279 else
2280 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2281 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002282 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2283# elif defined(HAVE_PR_SYSCALL)
2284 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002285 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002286 tcp->u_nargs = sysent[tcp->scno].nargs;
2287 else
2288 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002289 for (i = 0; i < tcp->u_nargs; i++)
2290 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2291# elif defined(I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002292 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293 tcp->u_nargs = sysent[tcp->scno].nargs;
2294 else
2295 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002296 if (tcp->u_nargs > 0)
2297 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002298 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2299# else
John Hughes25299712001-03-06 10:10:06 +00002300 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002301# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002302#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002303#ifdef FREEBSD
2304 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2305 sysent[tcp->scno].nargs > tcp->status.val)
2306 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002307 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002308 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002309 if (tcp->u_nargs < 0)
2310 tcp->u_nargs = 0;
2311 if (tcp->u_nargs > MAX_ARGS)
2312 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002313 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002314 case SYS___syscall:
2315 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2316 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002317 break;
2318 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002319 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2320 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002321 break;
2322 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002323 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2324 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002325 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002326 }
2327#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002328 return 1;
2329}
2330
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002331static int
2332trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002333{
2334 int sys_res;
2335 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002336 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002337 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002338
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002339 /* Measure the exit time as early as possible to avoid errors. */
2340 if (dtime || cflag)
2341 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002342
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002343 /* BTW, why we don't just memorize syscall no. on entry
2344 * in tcp->something?
2345 */
2346 scno_good = res = get_scno(tcp);
2347 if (res == 0)
2348 return res;
2349 if (res == 1)
2350 res = syscall_fixup(tcp);
2351 if (res == 0)
2352 return res;
2353 if (res == 1)
2354 res = get_error(tcp);
2355 if (res == 0)
2356 return res;
2357 if (res == 1)
2358 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002359
Grant Edwards8a082772011-04-07 20:25:40 +00002360 if (res == 1 && filtered(tcp)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002361 tcp->flags &= ~TCB_INSYSCALL;
2362 return 0;
2363 }
2364
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002365 if (tcp->flags & TCB_REPRINT) {
2366 printleader(tcp);
2367 tprintf("<... ");
2368 if (scno_good != 1)
2369 tprintf("????");
2370 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2371 tprintf("syscall_%lu", tcp->scno);
2372 else
2373 tprintf("%s", sysent[tcp->scno].sys_name);
2374 tprintf(" resumed> ");
2375 }
2376
2377 if (cflag) {
2378 struct timeval t = tv;
2379 int rc = count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002380 if (cflag == CFLAG_ONLY_STATS) {
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002381 tcp->flags &= ~TCB_INSYSCALL;
2382 return rc;
2383 }
2384 }
2385
2386 if (res != 1) {
2387 tprintf(") ");
2388 tabto(acolumn);
2389 tprintf("= ? <unavailable>");
2390 printtrailer();
2391 tcp->flags &= ~TCB_INSYSCALL;
2392 return res;
2393 }
2394
2395 if (tcp->scno >= nsyscalls || tcp->scno < 0
2396 || (qual_flags[tcp->scno] & QUAL_RAW))
2397 sys_res = printargs(tcp);
2398 else {
2399 if (not_failing_only && tcp->u_error)
2400 return 0; /* ignore failed syscalls */
2401 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2402 }
2403
2404 u_error = tcp->u_error;
2405 tprintf(") ");
2406 tabto(acolumn);
2407 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2408 qual_flags[tcp->scno] & QUAL_RAW) {
2409 if (u_error)
2410 tprintf("= -1 (errno %ld)", u_error);
2411 else
2412 tprintf("= %#lx", tcp->u_rval);
2413 }
2414 else if (!(sys_res & RVAL_NONE) && u_error) {
2415 switch (u_error) {
2416#ifdef LINUX
2417 case ERESTARTSYS:
2418 tprintf("= ? ERESTARTSYS (To be restarted)");
2419 break;
2420 case ERESTARTNOINTR:
2421 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2422 break;
2423 case ERESTARTNOHAND:
2424 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2425 break;
2426 case ERESTART_RESTARTBLOCK:
2427 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2428 break;
2429#endif /* LINUX */
2430 default:
2431 tprintf("= -1 ");
2432 if (u_error < 0)
2433 tprintf("E??? (errno %ld)", u_error);
2434 else if (u_error < nerrnos)
2435 tprintf("%s (%s)", errnoent[u_error],
2436 strerror(u_error));
2437 else
2438 tprintf("ERRNO_%ld (%s)", u_error,
2439 strerror(u_error));
2440 break;
2441 }
2442 if ((sys_res & RVAL_STR) && tcp->auxstr)
2443 tprintf(" (%s)", tcp->auxstr);
2444 }
2445 else {
2446 if (sys_res & RVAL_NONE)
2447 tprintf("= ?");
2448 else {
2449 switch (sys_res & RVAL_MASK) {
2450 case RVAL_HEX:
2451 tprintf("= %#lx", tcp->u_rval);
2452 break;
2453 case RVAL_OCTAL:
2454 tprintf("= %#lo", tcp->u_rval);
2455 break;
2456 case RVAL_UDECIMAL:
2457 tprintf("= %lu", tcp->u_rval);
2458 break;
2459 case RVAL_DECIMAL:
2460 tprintf("= %ld", tcp->u_rval);
2461 break;
2462#ifdef HAVE_LONG_LONG
2463 case RVAL_LHEX:
2464 tprintf("= %#llx", tcp->u_lrval);
2465 break;
2466 case RVAL_LOCTAL:
2467 tprintf("= %#llo", tcp->u_lrval);
2468 break;
2469 case RVAL_LUDECIMAL:
2470 tprintf("= %llu", tcp->u_lrval);
2471 break;
2472 case RVAL_LDECIMAL:
2473 tprintf("= %lld", tcp->u_lrval);
2474 break;
2475#endif
2476 default:
2477 fprintf(stderr,
2478 "invalid rval format\n");
2479 break;
2480 }
2481 }
2482 if ((sys_res & RVAL_STR) && tcp->auxstr)
2483 tprintf(" (%s)", tcp->auxstr);
2484 }
2485 if (dtime) {
2486 tv_sub(&tv, &tv, &tcp->etime);
2487 tprintf(" <%ld.%06ld>",
2488 (long) tv.tv_sec, (long) tv.tv_usec);
2489 }
2490 printtrailer();
2491
2492 dumpio(tcp);
2493 if (fflush(tcp->outf) == EOF)
2494 return -1;
2495 tcp->flags &= ~TCB_INSYSCALL;
2496 return 0;
2497}
2498
2499static int
2500trace_syscall_entering(struct tcb *tcp)
2501{
2502 int sys_res;
2503 int res, scno_good;
2504
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002505 scno_good = res = get_scno(tcp);
2506 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002507 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002508 if (res == 1)
2509 res = syscall_fixup(tcp);
2510 if (res == 0)
2511 return res;
2512 if (res == 1)
2513 res = syscall_enter(tcp);
2514 if (res == 0)
2515 return res;
2516
2517 if (res != 1) {
2518 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002519 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002520 tcp_last = tcp;
2521 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002522 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002523 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2524 tprintf("syscall_%lu(", tcp->scno);
2525 else
2526 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002527 /*
2528 * " <unavailable>" will be added later by the code which
2529 * detects ptrace errors.
2530 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002531 tcp->flags |= TCB_INSYSCALL;
2532 return res;
2533 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002534
Roland McGrath17352792005-06-07 23:21:26 +00002535 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002536#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002537 case SYS_socketcall:
2538 decode_subcall(tcp, SYS_socket_subcall,
2539 SYS_socket_nsubcalls, deref_style);
2540 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002541#endif
2542#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002543 case SYS_ipc:
2544 decode_subcall(tcp, SYS_ipc_subcall,
2545 SYS_ipc_nsubcalls, shift_style);
2546 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002547#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002548#ifdef SVR4
2549#ifdef SYS_pgrpsys_subcall
2550 case SYS_pgrpsys:
2551 decode_subcall(tcp, SYS_pgrpsys_subcall,
2552 SYS_pgrpsys_nsubcalls, shift_style);
2553 break;
2554#endif /* SYS_pgrpsys_subcall */
2555#ifdef SYS_sigcall_subcall
2556 case SYS_sigcall:
2557 decode_subcall(tcp, SYS_sigcall_subcall,
2558 SYS_sigcall_nsubcalls, mask_style);
2559 break;
2560#endif /* SYS_sigcall_subcall */
2561 case SYS_msgsys:
2562 decode_subcall(tcp, SYS_msgsys_subcall,
2563 SYS_msgsys_nsubcalls, shift_style);
2564 break;
2565 case SYS_shmsys:
2566 decode_subcall(tcp, SYS_shmsys_subcall,
2567 SYS_shmsys_nsubcalls, shift_style);
2568 break;
2569 case SYS_semsys:
2570 decode_subcall(tcp, SYS_semsys_subcall,
2571 SYS_semsys_nsubcalls, shift_style);
2572 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002573 case SYS_sysfs:
2574 decode_subcall(tcp, SYS_sysfs_subcall,
2575 SYS_sysfs_nsubcalls, shift_style);
2576 break;
2577 case SYS_spcall:
2578 decode_subcall(tcp, SYS_spcall_subcall,
2579 SYS_spcall_nsubcalls, shift_style);
2580 break;
2581#ifdef SYS_context_subcall
2582 case SYS_context:
2583 decode_subcall(tcp, SYS_context_subcall,
2584 SYS_context_nsubcalls, shift_style);
2585 break;
2586#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002587#ifdef SYS_door_subcall
2588 case SYS_door:
2589 decode_subcall(tcp, SYS_door_subcall,
2590 SYS_door_nsubcalls, door_style);
2591 break;
2592#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002593#ifdef SYS_kaio_subcall
2594 case SYS_kaio:
2595 decode_subcall(tcp, SYS_kaio_subcall,
2596 SYS_kaio_nsubcalls, shift_style);
2597 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002598#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002599#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002600#ifdef FREEBSD
2601 case SYS_msgsys:
2602 case SYS_shmsys:
2603 case SYS_semsys:
2604 decode_subcall(tcp, 0, 0, table_style);
2605 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002606#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002607#ifdef SUNOS4
2608 case SYS_semsys:
2609 decode_subcall(tcp, SYS_semsys_subcall,
2610 SYS_semsys_nsubcalls, shift_style);
2611 break;
2612 case SYS_msgsys:
2613 decode_subcall(tcp, SYS_msgsys_subcall,
2614 SYS_msgsys_nsubcalls, shift_style);
2615 break;
2616 case SYS_shmsys:
2617 decode_subcall(tcp, SYS_shmsys_subcall,
2618 SYS_shmsys_nsubcalls, shift_style);
2619 break;
2620#endif
2621 }
2622
2623 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002624
2625 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2626 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2627 (tracing_paths && !pathtrace_match(tcp))) {
2628 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002629 return 0;
2630 }
2631
Grant Edwards8a082772011-04-07 20:25:40 +00002632 tcp->flags &= ~TCB_FILTERED;
2633
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002634 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002635 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002636 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002637 return 0;
2638 }
2639
2640 printleader(tcp);
2641 tcp->flags &= ~TCB_REPRINT;
2642 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002643 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002644 tprintf("syscall_%lu(", tcp->scno);
2645 else
2646 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002647 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002648 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2649 sysent[tcp->scno].sys_func != sys_exit))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002650 sys_res = printargs(tcp);
2651 else
2652 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2653 if (fflush(tcp->outf) == EOF)
2654 return -1;
2655 tcp->flags |= TCB_INSYSCALL;
2656 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002657 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002658 gettimeofday(&tcp->etime, NULL);
2659 return sys_res;
2660}
2661
2662int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002663trace_syscall(struct tcb *tcp)
2664{
2665 return exiting(tcp) ?
2666 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2667}
2668
2669int
Denys Vlasenko12014262011-05-30 14:00:14 +02002670printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002671{
2672 if (entering(tcp)) {
2673 int i;
2674
2675 for (i = 0; i < tcp->u_nargs; i++)
2676 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2677 }
2678 return 0;
2679}
2680
2681long
Denys Vlasenko12014262011-05-30 14:00:14 +02002682getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002683{
2684 long val = -1;
2685
2686#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002687#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002688 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002689 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002690 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002691 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002692#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002693 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002694 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002695#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002696 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002697 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002698#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002699#endif /* LINUX */
2700
2701#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002702 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002703 return -1;
2704#endif /* SUNOS4 */
2705
2706#ifdef SVR4
2707#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002708 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002709#endif /* SPARC */
2710#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002711 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002712#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002713#ifdef X86_64
2714 val = tcp->status.PR_REG[RDX];
2715#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002716#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002717 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002718#endif /* MIPS */
2719#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002720
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002721#ifdef FREEBSD
2722 struct reg regs;
2723 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2724 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002725#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002726 return val;
2727}
2728
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002729#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002730/*
2731 * Apparently, indirect system calls have already be converted by ptrace(2),
2732 * so if you see "indir" this program has gone astray.
2733 */
2734int
Denys Vlasenko12014262011-05-30 14:00:14 +02002735sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002736{
2737 int i, scno, nargs;
2738
2739 if (entering(tcp)) {
2740 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2741 fprintf(stderr, "Bogus syscall: %u\n", scno);
2742 return 0;
2743 }
2744 nargs = sysent[scno].nargs;
2745 tprintf("%s", sysent[scno].sys_name);
2746 for (i = 0; i < nargs; i++)
2747 tprintf(", %#lx", tcp->u_arg[i+1]);
2748 }
2749 return 0;
2750}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002751#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002752
2753int
2754is_restart_error(struct tcb *tcp)
2755{
2756#ifdef LINUX
2757 if (!syserror(tcp))
2758 return 0;
2759 switch (tcp->u_error) {
2760 case ERESTARTSYS:
2761 case ERESTARTNOINTR:
2762 case ERESTARTNOHAND:
2763 case ERESTART_RESTARTBLOCK:
2764 return 1;
2765 default:
2766 break;
2767 }
2768#endif /* LINUX */
2769 return 0;
2770}