blob: 2fd5bb4952b615427affdf76ec3bf2709612d69c [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
186};;
187
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000188int
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;
216#endif /* SUPPORTED_PERSONALITIES >= 2 */
217
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;
230#endif /* SUPPORTED_PERSONALITIES >= 3 */
231
232 default:
233 return -1;
234 }
235
236 current_personality = personality;
237 return 0;
238}
239
Roland McGrathe10e62a2004-09-04 04:20:43 +0000240
Roland McGrath9797ceb2002-12-30 10:23:00 +0000241static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000242
Roland McGrathe10e62a2004-09-04 04:20:43 +0000243static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000244 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000245 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000246 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000247 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000248} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000249 { QUAL_TRACE, "trace", qual_syscall, "system call" },
250 { QUAL_TRACE, "t", qual_syscall, "system call" },
251 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
252 { QUAL_ABBREV, "a", qual_syscall, "system call" },
253 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
254 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
255 { QUAL_RAW, "raw", qual_syscall, "system call" },
256 { QUAL_RAW, "x", qual_syscall, "system call" },
257 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
258 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
259 { QUAL_SIGNAL, "s", qual_signal, "signal" },
260 { QUAL_FAULT, "fault", qual_fault, "fault" },
261 { QUAL_FAULT, "faults", qual_fault, "fault" },
262 { QUAL_FAULT, "m", qual_fault, "fault" },
263 { QUAL_READ, "read", qual_desc, "descriptor" },
264 { QUAL_READ, "reads", qual_desc, "descriptor" },
265 { QUAL_READ, "r", qual_desc, "descriptor" },
266 { QUAL_WRITE, "write", qual_desc, "descriptor" },
267 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
268 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000269 { 0, NULL, NULL, NULL },
270};
271
Roland McGrath9797ceb2002-12-30 10:23:00 +0000272static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000273qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000274{
Roland McGrath138c6a32006-01-12 09:50:49 +0000275 if (pers == 0 || pers < 0) {
276 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000277 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000278 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000279 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000280 }
281
282#if SUPPORTED_PERSONALITIES >= 2
283 if (pers == 1 || pers < 0) {
284 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000285 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000286 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000287 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000288 }
289#endif /* SUPPORTED_PERSONALITIES >= 2 */
290
291#if SUPPORTED_PERSONALITIES >= 3
292 if (pers == 2 || pers < 0) {
293 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000294 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000295 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000296 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000297 }
298#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299}
300
301static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000302qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000303{
304 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000305 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000306
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000307 if (isdigit((unsigned char)*s)) {
308 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000309 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000310 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000311 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000312 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000313 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000314 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000315 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000316 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000317 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000318 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000319
320#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000321 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000322 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000323 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000324 rc = 0;
325 }
326#endif /* SUPPORTED_PERSONALITIES >= 2 */
327
328#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000329 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000330 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000331 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000332 rc = 0;
333 }
334#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000335
Roland McGrathfe6b3522005-02-02 04:40:11 +0000336 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000337}
338
339static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000340qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000341{
342 int i;
343 char buf[32];
344
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000345 if (isdigit((unsigned char)*s)) {
346 int signo = atoi(s);
347 if (signo < 0 || signo >= MAX_QUALS)
348 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000349 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000350 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000351 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000352 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000353 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000354 strcpy(buf, s);
355 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000356 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000357 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000358 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000359 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000360 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000361 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000362 }
Roland McGrath76421df2005-02-02 03:51:18 +0000363 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000364}
365
366static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000367qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000368{
369 return -1;
370}
371
372static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000373qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000374{
Roland McGrath48a035f2006-01-12 09:45:56 +0000375 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000376 int desc = atoi(s);
377 if (desc < 0 || desc >= MAX_QUALS)
378 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000379 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000380 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000381 }
382 return -1;
383}
384
385static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000386lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000387{
388 if (strcmp(s, "file") == 0)
389 return TRACE_FILE;
390 if (strcmp(s, "ipc") == 0)
391 return TRACE_IPC;
392 if (strcmp(s, "network") == 0)
393 return TRACE_NETWORK;
394 if (strcmp(s, "process") == 0)
395 return TRACE_PROCESS;
396 if (strcmp(s, "signal") == 0)
397 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000398 if (strcmp(s, "desc") == 0)
399 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000400 return -1;
401}
402
403void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000404qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000405{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000406 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000407 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000408 char *copy;
409 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 int i, n;
411
412 opt = &qual_options[0];
413 for (i = 0; (p = qual_options[i].option_name); i++) {
414 n = strlen(p);
415 if (strncmp(s, p, n) == 0 && s[n] == '=') {
416 opt = &qual_options[i];
417 s += n + 1;
418 break;
419 }
420 }
421 not = 0;
422 if (*s == '!') {
423 not = 1;
424 s++;
425 }
426 if (strcmp(s, "none") == 0) {
427 not = 1 - not;
428 s = "all";
429 }
430 if (strcmp(s, "all") == 0) {
431 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000432 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000433 }
434 return;
435 }
436 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000437 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000439 if (!(copy = strdup(s))) {
440 fprintf(stderr, "out of memory\n");
441 exit(1);
442 }
443 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000444 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000445 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000446 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000447 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000448
449#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000450 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000451 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000452 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000453#endif /* SUPPORTED_PERSONALITIES >= 2 */
454
455#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000456 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000457 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000458 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000459#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000460
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000461 continue;
462 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000463 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 fprintf(stderr, "strace: invalid %s `%s'\n",
465 opt->argument_name, p);
466 exit(1);
467 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000468 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000469 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000470 return;
471}
472
473static void
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000474dumpio(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000475{
476 if (syserror(tcp))
477 return;
478 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
479 return;
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000480 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
481 return;
482 if (sysent[tcp->scno].sys_func == printargs)
483 return;
484 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
485 if (sysent[tcp->scno].sys_func == sys_read ||
486 sysent[tcp->scno].sys_func == sys_pread ||
487 sysent[tcp->scno].sys_func == sys_pread64 ||
488 sysent[tcp->scno].sys_func == sys_recv ||
489 sysent[tcp->scno].sys_func == sys_recvfrom)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000491 else if (sysent[tcp->scno].sys_func == sys_readv)
492 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
493 return;
494 }
495 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
496 if (sysent[tcp->scno].sys_func == sys_write ||
497 sysent[tcp->scno].sys_func == sys_pwrite ||
498 sysent[tcp->scno].sys_func == sys_pwrite64 ||
499 sysent[tcp->scno].sys_func == sys_send ||
500 sysent[tcp->scno].sys_func == sys_sendto)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000501 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000502 else if (sysent[tcp->scno].sys_func == sys_writev)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000503 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000504 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000505 }
506}
507
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000508#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000509enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000510#else /* FREEBSD */
511enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
512
513struct subcall {
514 int call;
515 int nsubcalls;
516 int subcalls[5];
517};
518
Roland McGratha4d48532005-06-08 20:45:28 +0000519static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000520 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000521#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000522 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000523#else
524 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
525#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000526 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
527};
528#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000529
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000530#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000531
Roland McGratha4d48532005-06-08 20:45:28 +0000532static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200533decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000535 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000536 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000537 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000538
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539 switch (style) {
540 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000541 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
542 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543 tcp->scno = subcall + tcp->u_arg[0];
544 if (sysent[tcp->scno].nargs != -1)
545 tcp->u_nargs = sysent[tcp->scno].nargs;
546 else
547 tcp->u_nargs--;
548 for (i = 0; i < tcp->u_nargs; i++)
549 tcp->u_arg[i] = tcp->u_arg[i + 1];
550 break;
551 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000552 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
553 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000554 tcp->scno = subcall + tcp->u_arg[0];
555 addr = tcp->u_arg[1];
556 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000557 if (size == sizeof(int)) {
558 unsigned int arg;
559 if (umove(tcp, addr, &arg) < 0)
560 arg = 0;
561 tcp->u_arg[i] = arg;
562 }
563 else if (size == sizeof(long)) {
564 unsigned long arg;
565 if (umove(tcp, addr, &arg) < 0)
566 arg = 0;
567 tcp->u_arg[i] = arg;
568 }
569 else
570 abort();
571 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572 }
573 tcp->u_nargs = sysent[tcp->scno].nargs;
574 break;
575 case mask_style:
576 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000577 for (i = 0; mask; i++)
578 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000579 if (i >= nsubcalls)
580 return;
581 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000582 tcp->scno = subcall + i;
583 if (sysent[tcp->scno].nargs != -1)
584 tcp->u_nargs = sysent[tcp->scno].nargs;
585 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000586 case door_style:
587 /*
588 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000589 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000590 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000591 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
592 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000593 tcp->scno = subcall + tcp->u_arg[5];
594 if (sysent[tcp->scno].nargs != -1)
595 tcp->u_nargs = sysent[tcp->scno].nargs;
596 else
597 tcp->u_nargs--;
598 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000599#ifdef FREEBSD
600 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000601 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000602 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000603 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000604 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
605 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
606 for (i = 0; i < tcp->u_nargs; i++)
607 tcp->u_arg[i] = tcp->u_arg[i + 1];
608 }
609 break;
610#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000611 }
612}
613#endif
614
615struct tcb *tcp_last = NULL;
616
617static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000618internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000619{
620 /*
621 * We must always trace a few critical system calls in order to
622 * correctly support following forks in the presence of tracing
623 * qualifiers.
624 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000625 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000626
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000627 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
628 return 0;
629
630 func = sysent[tcp->scno].sys_func;
631
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000632 if ( sys_fork == func
633#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
634 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000635#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000636#ifdef LINUX
637 || sys_clone == func
638#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000639#if UNIXWARE > 2
640 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000642 )
643 return internal_fork(tcp);
644
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000645 if ( sys_execve == func
646#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
647 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000648#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000649#if UNIXWARE > 2
650 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000651#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000652 )
653 return internal_exec(tcp);
654
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000655 return 0;
656}
657
Wichert Akkermanc7926982000-04-10 22:22:31 +0000658
659#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200660# if defined (I386)
661static long eax;
662# elif defined (IA64)
663long r8, r10, psr; /* TODO: make static? */
664long ia32 = 0; /* not static */
665# elif defined (POWERPC)
666static long result, flags;
667# elif defined (M68K)
668static long d0;
669# elif defined(BFIN)
670static long r0;
671# elif defined (ARM)
672static struct pt_regs regs;
673# elif defined (ALPHA)
674static long r0;
675static long a3;
676# elif defined(AVR32)
677static struct pt_regs regs;
678# elif defined (SPARC) || defined (SPARC64)
679static struct pt_regs regs;
680static unsigned long trap;
681# elif defined(LINUX_MIPSN32)
682static long long a3;
683static long long r2;
684# elif defined(MIPS)
685static long a3;
686static long r2;
687# elif defined(S390) || defined(S390X)
688static long gpr2;
689static long pc;
690static long syscall_mode;
691# elif defined(HPPA)
692static long r28;
693# elif defined(SH)
694static long r0;
695# elif defined(SH64)
696static long r9;
697# elif defined(X86_64)
698static long rax;
699# elif defined(CRISV10) || defined(CRISV32)
700static long r10;
701# elif defined(MICROBLAZE)
702static long r3;
703# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000704#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000705#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200706struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000707#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000708
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000709int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000710get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000713
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000714#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000715# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000716 if (tcp->flags & TCB_WAITEXECVE) {
717 /*
718 * When the execve system call completes successfully, the
719 * new process still has -ENOSYS (old style) or __NR_execve
720 * (new style) in gpr2. We cannot recover the scno again
721 * by disassembly, because the image that executed the
722 * syscall is gone now. Fortunately, we don't want it. We
723 * leave the flag set so that syscall_fixup can fake the
724 * result.
725 */
726 if (tcp->flags & TCB_INSYSCALL)
727 return 1;
728 /*
729 * This is the SIGTRAP after execve. We cannot try to read
730 * the system call here either.
731 */
732 tcp->flags &= ~TCB_WAITEXECVE;
733 return 0;
734 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000735
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000736 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200737 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000738
739 if (syscall_mode != -ENOSYS) {
740 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000741 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000742 */
743 scno = syscall_mode;
744 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000745 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000746 * Old style of "passing" the scno via the SVC instruction.
747 */
748
749 long opcode, offset_reg, tmp;
750 void * svc_addr;
751 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
752 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
753 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
754 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000755
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000756 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000757 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000758 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000759 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000760 if (errno) {
761 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000762 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000763 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000764
765 /*
766 * We have to check if the SVC got executed directly or via an
767 * EXECUTE instruction. In case of EXECUTE it is necessary to do
768 * instruction decoding to derive the system call number.
769 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
770 * so that this doesn't work if a SVC opcode is part of an EXECUTE
771 * opcode. Since there is no way to find out the opcode size this
772 * is the best we can do...
773 */
774
775 if ((opcode & 0xff00) == 0x0a00) {
776 /* SVC opcode */
777 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000778 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000779 else {
780 /* SVC got executed by EXECUTE instruction */
781
782 /*
783 * Do instruction decoding of EXECUTE. If you really want to
784 * understand this, read the Principles of Operations.
785 */
786 svc_addr = (void *) (opcode & 0xfff);
787
788 tmp = 0;
789 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000790 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000791 return -1;
792 svc_addr += tmp;
793
794 tmp = 0;
795 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000796 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000797 return -1;
798 svc_addr += tmp;
799
Denys Vlasenkofb036672009-01-23 16:30:26 +0000800 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000801 if (errno)
802 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000803# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000804 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000805# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000806 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000807# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000808 tmp = 0;
809 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000810 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000811 return -1;
812
813 scno = (scno | tmp) & 0xff;
814 }
815 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000816# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000817 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000818 return -1;
819 if (!(tcp->flags & TCB_INSYSCALL)) {
820 /* Check if we return from execve. */
821 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
822 tcp->flags &= ~TCB_WAITEXECVE;
823 return 0;
824 }
825 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200826
827# ifdef POWERPC64
828 if (!(tcp->flags & TCB_INSYSCALL)) {
829 static int currpers = -1;
830 long val;
831 int pid = tcp->pid;
832
833 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200834 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200835 return -1;
836 /* SF is bit 0 of MSR */
837 if (val < 0)
838 currpers = 0;
839 else
840 currpers = 1;
841 if (currpers != current_personality) {
842 static const char *const names[] = {"64 bit", "32 bit"};
843 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000844 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200845 pid, names[current_personality]);
846 }
847 }
848# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000849# elif defined(AVR32)
850 /*
851 * Read complete register set in one go.
852 */
853 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
854 return -1;
855
856 /*
857 * We only need to grab the syscall number on syscall entry.
858 */
859 if (!(tcp->flags & TCB_INSYSCALL)) {
860 scno = regs.r8;
861
862 /* Check if we return from execve. */
863 if (tcp->flags & TCB_WAITEXECVE) {
864 tcp->flags &= ~TCB_WAITEXECVE;
865 return 0;
866 }
867 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000868# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000869 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000870 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000871# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000872 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000873 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000874# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000875 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000876 return -1;
877
Roland McGrath761b5d72002-12-15 23:58:31 +0000878 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000879 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000880 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000881 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000882
883 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200884 * 0x33 for long mode (64 bit)
885 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000886 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000887 * to be cached.
888 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000889 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000890 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000891 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000892 case 0x23: currpers = 1; break;
893 case 0x33: currpers = 0; break;
894 default:
895 fprintf(stderr, "Unknown value CS=0x%02X while "
896 "detecting personality of process "
897 "PID=%d\n", (int)val, pid);
898 currpers = current_personality;
899 break;
900 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000901# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000902 /* This version analyzes the opcode of a syscall instruction.
903 * (int 0x80 on i386 vs. syscall on x86-64)
904 * It works, but is too complicated.
905 */
906 unsigned long val, rip, i;
907
Denys Vlasenko8236f252009-01-02 18:10:08 +0000908 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000909 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000910
Michal Ludvig0e035502002-09-23 15:41:01 +0000911 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000912 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000913 errno = 0;
914
Denys Vlasenko8236f252009-01-02 18:10:08 +0000915 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000916 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000917 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000918 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000919 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000920 /* x86-64: syscall = 0x0f 0x05 */
921 case 0x050f: currpers = 0; break;
922 /* i386: int 0x80 = 0xcd 0x80 */
923 case 0x80cd: currpers = 1; break;
924 default:
925 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000926 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000927 "Unknown syscall opcode (0x%04X) while "
928 "detecting personality of process "
929 "PID=%d\n", (int)call, pid);
930 break;
931 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000932# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000933 if (currpers != current_personality) {
934 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000935 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000936 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000937 pid, names[current_personality]);
938 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000939 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000940# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000941# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200942 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000943 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000944 if (!(tcp->flags & TCB_INSYSCALL)) {
945 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000946 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000947 return -1;
948 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200949 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000950 return -1;
951 }
Roland McGrathba954762003-03-05 06:29:06 +0000952 /* Check if we return from execve. */
953 if (tcp->flags & TCB_WAITEXECVE) {
954 tcp->flags &= ~TCB_WAITEXECVE;
955 return 0;
956 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000957 } else {
958 /* syscall in progress */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200959 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000960 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200961 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000962 return -1;
963 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000964# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000965 /*
966 * Read complete register set in one go.
967 */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000968 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000969 return -1;
970
971 /*
972 * We only need to grab the syscall number on syscall entry.
973 */
974 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +0000975 if (!(tcp->flags & TCB_INSYSCALL)) {
976 /* Check if we return from execve. */
977 if (tcp->flags & TCB_WAITEXECVE) {
978 tcp->flags &= ~TCB_WAITEXECVE;
979 return 0;
980 }
981 }
982
Roland McGrath0f87c492003-06-03 23:29:04 +0000983 /*
984 * Note: we only deal with only 32-bit CPUs here.
985 */
986 if (regs.ARM_cpsr & 0x20) {
987 /*
988 * Get the Thumb-mode system call number
989 */
990 scno = regs.ARM_r7;
991 } else {
992 /*
993 * Get the ARM-mode system call number
994 */
995 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000996 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +0000997 if (errno)
998 return -1;
999
1000 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1001 tcp->flags &= ~TCB_WAITEXECVE;
1002 return 0;
1003 }
1004
Roland McGrathf691bd22006-04-25 07:34:41 +00001005 /* Handle the EABI syscall convention. We do not
1006 bother converting structures between the two
1007 ABIs, but basic functionality should work even
1008 if strace and the traced program have different
1009 ABIs. */
1010 if (scno == 0xef000000) {
1011 scno = regs.ARM_r7;
1012 } else {
1013 if ((scno & 0x0ff00000) != 0x0f900000) {
1014 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1015 scno);
1016 return -1;
1017 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001018
Roland McGrathf691bd22006-04-25 07:34:41 +00001019 /*
1020 * Fixup the syscall number
1021 */
1022 scno &= 0x000fffff;
1023 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001024 }
Roland McGrath56703312008-05-20 01:35:55 +00001025 if (scno & 0x0f0000) {
1026 /*
1027 * Handle ARM specific syscall
1028 */
1029 set_personality(1);
1030 scno &= 0x0000ffff;
1031 } else
1032 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001033
1034 if (tcp->flags & TCB_INSYSCALL) {
1035 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1036 tcp->flags &= ~TCB_INSYSCALL;
1037 }
1038 } else {
1039 if (!(tcp->flags & TCB_INSYSCALL)) {
1040 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1041 tcp->flags |= TCB_INSYSCALL;
1042 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001043 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001044# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001045 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001046 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001047# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001048 unsigned long long regs[38];
1049
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001050 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001051 return -1;
1052 a3 = regs[REG_A3];
1053 r2 = regs[REG_V0];
1054
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001055 if (!(tcp->flags & TCB_INSYSCALL)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001056 scno = r2;
1057
1058 /* Check if we return from execve. */
1059 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1060 tcp->flags &= ~TCB_WAITEXECVE;
1061 return 0;
1062 }
1063
1064 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001065 if (a3 == 0 || a3 == -1) {
1066 if (debug)
1067 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001068 return 0;
1069 }
1070 }
1071 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001072# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001073 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001074 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001075 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001076 if (upeek(tcp, REG_V0, &scno) < 0)
1077 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001078
Roland McGrath542c2c62008-05-20 01:11:56 +00001079 /* Check if we return from execve. */
1080 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1081 tcp->flags &= ~TCB_WAITEXECVE;
1082 return 0;
1083 }
1084
Wichert Akkermanf90da011999-10-31 21:15:38 +00001085 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001086 if (a3 == 0 || a3 == -1) {
1087 if (debug)
1088 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001089 return 0;
1090 }
1091 }
1092 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001093 if (upeek(tcp, REG_V0, &r2) < 0)
1094 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001095 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001096# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001097 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 return -1;
1099
1100 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001101 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102 return -1;
1103
1104 /* Check if we return from execve. */
1105 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1106 tcp->flags &= ~TCB_WAITEXECVE;
1107 return 0;
1108 }
1109
1110 /*
1111 * Do some sanity checks to figure out if it's
1112 * really a syscall entry
1113 */
1114 if (scno < 0 || scno > nsyscalls) {
1115 if (a3 == 0 || a3 == -1) {
1116 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001117 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 return 0;
1119 }
1120 }
1121 }
1122 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001123 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001124 return -1;
1125 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001126# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001127 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001128 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129 return -1;
1130
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001131 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 if (!(tcp->flags & TCB_INSYSCALL)) {
1133 /* Retrieve the syscall trap instruction. */
1134 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001135# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001136 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001137 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001138# else
1139 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001140# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001141 if (errno)
1142 return -1;
1143
1144 /* Disassemble the trap to see what personality to use. */
1145 switch (trap) {
1146 case 0x91d02010:
1147 /* Linux/SPARC syscall trap. */
1148 set_personality(0);
1149 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001150 case 0x91d0206d:
1151 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001152 set_personality(2);
1153 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001154 case 0x91d02000:
1155 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001156 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157 return -1;
1158 case 0x91d02008:
1159 /* Solaris 2.x syscall trap. (per 2) */
1160 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001161 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001162 case 0x91d02009:
1163 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001164 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165 return -1;
1166 case 0x91d02027:
1167 /* Solaris 2.x gettimeofday */
1168 set_personality(1);
1169 break;
1170 default:
1171 /* Unknown syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001172 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173 tcp->flags &= ~TCB_WAITEXECVE;
1174 return 0;
1175 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001176# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001177 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001178# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001179 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001180# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 return -1;
1182 }
1183
1184 /* Extract the system call number from the registers. */
1185 if (trap == 0x91d02027)
1186 scno = 156;
1187 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001188 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001190 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001191 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 +00001192 }
1193 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001194# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001195 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001196 return -1;
1197 if (!(tcp->flags & TCB_INSYSCALL)) {
1198 /* Check if we return from execve. */
1199 if ((tcp->flags & TCB_WAITEXECVE)) {
1200 tcp->flags &= ~TCB_WAITEXECVE;
1201 return 0;
1202 }
1203 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001204# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001205 /*
1206 * In the new syscall ABI, the system call number is in R3.
1207 */
1208 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1209 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001210
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001211 if (scno < 0) {
1212 /* Odd as it may seem, a glibc bug has been known to cause
1213 glibc to issue bogus negative syscall numbers. So for
1214 our purposes, make strace print what it *should* have been */
1215 long correct_scno = (scno & 0xff);
1216 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001217 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001218 "Detected glibc bug: bogus system call"
1219 " number = %ld, correcting to %ld\n",
1220 scno,
1221 correct_scno);
1222 scno = correct_scno;
1223 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001224
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001225 if (!(tcp->flags & TCB_INSYSCALL)) {
1226 /* Check if we return from execve. */
1227 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1228 tcp->flags &= ~TCB_WAITEXECVE;
1229 return 0;
1230 }
1231 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001232# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001233 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001234 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001235 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001236
1237 if (!(tcp->flags & TCB_INSYSCALL)) {
1238 /* Check if we return from execve. */
1239 if (tcp->flags & TCB_WAITEXECVE) {
1240 tcp->flags &= ~TCB_WAITEXECVE;
1241 return 0;
1242 }
1243 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001244# elif defined(CRISV10) || defined(CRISV32)
1245 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1246 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001247# elif defined(TILE)
1248 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1249 return -1;
1250
1251 if (!(tcp->flags & TCB_INSYSCALL)) {
1252 /* Check if we return from execve. */
1253 if (tcp->flags & TCB_WAITEXECVE) {
1254 tcp->flags &= ~TCB_WAITEXECVE;
1255 return 0;
1256 }
1257 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001258# elif defined(MICROBLAZE)
1259 if (upeek(tcp, 0, &scno) < 0)
1260 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001261# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001263
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001264#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001265 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001267#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001268 /* new syscall ABI returns result in R0 */
1269 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1270 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001271#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001272 /* ABI defines result returned in r9 */
1273 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1274 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001276
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001277#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001278# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001279 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001280# else
1281# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001282 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001283# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001284 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001285 perror("pread");
1286 return -1;
1287 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001288 switch (regs.r_eax) {
1289 case SYS_syscall:
1290 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001291 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1292 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001293 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001294 scno = regs.r_eax;
1295 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001296 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001297# endif /* FREEBSD */
1298# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001299#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001300
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001301 if (!(tcp->flags & TCB_INSYSCALL))
1302 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001303 return 1;
1304}
1305
Pavel Machek4dc3b142000-02-01 17:58:41 +00001306
Roland McGrath17352792005-06-07 23:21:26 +00001307long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001308known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001309{
1310 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001311#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001312 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1313 scno = sysent[scno].native_scno;
1314 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001315#endif
Roland McGrath17352792005-06-07 23:21:26 +00001316 scno += NR_SYSCALL_BASE;
1317 return scno;
1318}
1319
Roland McGratheb9e2e82009-06-02 16:49:22 -07001320/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001321 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001322 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1323 * 1: ok, continue in trace_syscall().
1324 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001325 * ("????" etc) and bail out.
1326 */
Roland McGratha4d48532005-06-08 20:45:28 +00001327static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001328syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001329{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001330#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001331 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001332
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001334 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 if (
1336 scno == SYS_fork
1337#ifdef SYS_vfork
1338 || scno == SYS_vfork
1339#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001340#ifdef SYS_fork1
1341 || scno == SYS_fork1
1342#endif /* SYS_fork1 */
1343#ifdef SYS_forkall
1344 || scno == SYS_forkall
1345#endif /* SYS_forkall */
1346#ifdef SYS_rfork1
1347 || scno == SYS_rfork1
1348#endif /* SYS_fork1 */
1349#ifdef SYS_rforkall
1350 || scno == SYS_rforkall
1351#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001352 ) {
1353 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001354 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001355 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001356 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357 }
1358 else {
1359 fprintf(stderr, "syscall: missing entry\n");
1360 tcp->flags |= TCB_INSYSCALL;
1361 }
1362 }
1363 }
1364 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001365 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001366 fprintf(stderr, "syscall: missing exit\n");
1367 tcp->flags &= ~TCB_INSYSCALL;
1368 }
1369 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001370#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371#ifdef SUNOS4
1372 if (!(tcp->flags & TCB_INSYSCALL)) {
1373 if (scno == 0) {
1374 fprintf(stderr, "syscall: missing entry\n");
1375 tcp->flags |= TCB_INSYSCALL;
1376 }
1377 }
1378 else {
1379 if (scno != 0) {
1380 if (debug) {
1381 /*
1382 * This happens when a signal handler
1383 * for a signal which interrupted a
1384 * a system call makes another system call.
1385 */
1386 fprintf(stderr, "syscall: missing exit\n");
1387 }
1388 tcp->flags &= ~TCB_INSYSCALL;
1389 }
1390 }
1391#endif /* SUNOS4 */
1392#ifdef LINUX
1393#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001394 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001395 return -1;
1396 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1397 if (debug)
1398 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1399 return 0;
1400 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001401#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001402 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001403 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001404 if (current_personality == 1)
1405 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001406 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1407 if (debug)
1408 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1409 return 0;
1410 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001411#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001412 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001413 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001414 if (syscall_mode != -ENOSYS)
1415 syscall_mode = tcp->scno;
1416 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001417 if (debug)
1418 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1419 return 0;
1420 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001421 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1422 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1423 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1424 /*
1425 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1426 * flag set for the post-execve SIGTRAP to see and reset.
1427 */
1428 gpr2 = 0;
1429 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001430#elif defined (POWERPC)
1431# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001432 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001433 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001434 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435 return -1;
1436 if (flags & SO_MASK)
1437 result = -result;
1438#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001439 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001440 return -1;
1441 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1442 if (debug)
1443 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1444 return 0;
1445 }
1446#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001447 /*
1448 * Nothing required
1449 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001450#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001451 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001452 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001453#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001454 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001455 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001456#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001457 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001458 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001459 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001460 return -1;
1461 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1462 if (debug)
1463 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1464 return 0;
1465 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001466#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001467 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001468 return -1;
1469 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1470 if (debug)
1471 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1472 return 0;
1473 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001474#elif defined(MICROBLAZE)
1475 if (upeek(tcp, 3 * 4, &r3) < 0)
1476 return -1;
1477 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1478 if (debug)
1479 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1480 return 0;
1481 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001482#endif
1483#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001484 return 1;
1485}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486
Roland McGrathc1e45922008-05-27 23:18:29 +00001487#ifdef LINUX
1488/*
1489 * Check the syscall return value register value for whether it is
1490 * a negated errno code indicating an error, or a success return value.
1491 */
1492static inline int
1493is_negated_errno(unsigned long int val)
1494{
1495 unsigned long int max = -(long int) nerrnos;
1496 if (personality_wordsize[current_personality] < sizeof(val)) {
1497 val = (unsigned int) val;
1498 max = (unsigned int) max;
1499 }
1500 return val > max;
1501}
1502#endif
1503
Roland McGratha4d48532005-06-08 20:45:28 +00001504static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001505get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001506{
1507 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001508#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001509 int check_errno = 1;
1510 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1511 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1512 check_errno = 0;
1513 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001514# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001515 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001516 tcp->u_rval = -1;
1517 u_error = -gpr2;
1518 }
1519 else {
1520 tcp->u_rval = gpr2;
1521 u_error = 0;
1522 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001523# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001524 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001525 tcp->u_rval = -1;
1526 u_error = -eax;
1527 }
1528 else {
1529 tcp->u_rval = eax;
1530 u_error = 0;
1531 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001532# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001533 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001534 tcp->u_rval = -1;
1535 u_error = -rax;
1536 }
1537 else {
1538 tcp->u_rval = rax;
1539 u_error = 0;
1540 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001541# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001542 if (ia32) {
1543 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001544
Roland McGrathc1e45922008-05-27 23:18:29 +00001545 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001546 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001547 tcp->u_rval = -1;
1548 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001549 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001550 else {
1551 tcp->u_rval = err;
1552 u_error = 0;
1553 }
1554 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001555 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001556 tcp->u_rval = -1;
1557 u_error = r8;
1558 } else {
1559 tcp->u_rval = r8;
1560 u_error = 0;
1561 }
1562 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001563# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001564 if (check_errno && a3) {
1565 tcp->u_rval = -1;
1566 u_error = r2;
1567 } else {
1568 tcp->u_rval = r2;
1569 u_error = 0;
1570 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001571# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001572 if (check_errno && is_negated_errno(result)) {
1573 tcp->u_rval = -1;
1574 u_error = -result;
1575 }
1576 else {
1577 tcp->u_rval = result;
1578 u_error = 0;
1579 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001580# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001581 if (check_errno && is_negated_errno(d0)) {
1582 tcp->u_rval = -1;
1583 u_error = -d0;
1584 }
1585 else {
1586 tcp->u_rval = d0;
1587 u_error = 0;
1588 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001589# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001590 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1591 tcp->u_rval = -1;
1592 u_error = -regs.ARM_r0;
1593 }
1594 else {
1595 tcp->u_rval = regs.ARM_r0;
1596 u_error = 0;
1597 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001598# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001599 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1600 tcp->u_rval = -1;
1601 u_error = -regs.r12;
1602 }
1603 else {
1604 tcp->u_rval = regs.r12;
1605 u_error = 0;
1606 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001607# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001608 if (check_errno && is_negated_errno(r0)) {
1609 tcp->u_rval = -1;
1610 u_error = -r0;
1611 } else {
1612 tcp->u_rval = r0;
1613 u_error = 0;
1614 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001615# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001616 if (check_errno && a3) {
1617 tcp->u_rval = -1;
1618 u_error = r0;
1619 }
1620 else {
1621 tcp->u_rval = r0;
1622 u_error = 0;
1623 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001624# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001625 if (check_errno && regs.psr & PSR_C) {
1626 tcp->u_rval = -1;
1627 u_error = regs.u_regs[U_REG_O0];
1628 }
1629 else {
1630 tcp->u_rval = regs.u_regs[U_REG_O0];
1631 u_error = 0;
1632 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001633# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001634 if (check_errno && regs.tstate & 0x1100000000UL) {
1635 tcp->u_rval = -1;
1636 u_error = regs.u_regs[U_REG_O0];
1637 }
1638 else {
1639 tcp->u_rval = regs.u_regs[U_REG_O0];
1640 u_error = 0;
1641 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001642# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001643 if (check_errno && is_negated_errno(r28)) {
1644 tcp->u_rval = -1;
1645 u_error = -r28;
1646 }
1647 else {
1648 tcp->u_rval = r28;
1649 u_error = 0;
1650 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001651# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001652 /* interpret R0 as return value or error number */
1653 if (check_errno && is_negated_errno(r0)) {
1654 tcp->u_rval = -1;
1655 u_error = -r0;
1656 }
1657 else {
1658 tcp->u_rval = r0;
1659 u_error = 0;
1660 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001661# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001662 /* interpret result as return value or error number */
1663 if (check_errno && is_negated_errno(r9)) {
1664 tcp->u_rval = -1;
1665 u_error = -r9;
1666 }
1667 else {
1668 tcp->u_rval = r9;
1669 u_error = 0;
1670 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001671# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001672 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1673 tcp->u_rval = -1;
1674 u_error = -r10;
1675 }
1676 else {
1677 tcp->u_rval = r10;
1678 u_error = 0;
1679 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001680# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001681 long rval;
1682 /* interpret result as return value or error number */
1683 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1684 return -1;
1685 if (check_errno && rval < 0 && rval > -nerrnos) {
1686 tcp->u_rval = -1;
1687 u_error = -rval;
1688 }
1689 else {
1690 tcp->u_rval = rval;
1691 u_error = 0;
1692 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001693# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001694 /* interpret result as return value or error number */
1695 if (check_errno && is_negated_errno(r3)) {
1696 tcp->u_rval = -1;
1697 u_error = -r3;
1698 }
1699 else {
1700 tcp->u_rval = r3;
1701 u_error = 0;
1702 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001703# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001704#endif /* LINUX */
1705#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001706 /* get error code from user struct */
1707 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1708 return -1;
1709 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001711 /* get system call return value */
1712 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1713 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714#endif /* SUNOS4 */
1715#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001716# ifdef SPARC
1717 /* Judicious guessing goes a long way. */
1718 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1719 tcp->u_rval = -1;
1720 u_error = tcp->status.pr_reg[R_O0];
1721 }
1722 else {
1723 tcp->u_rval = tcp->status.pr_reg[R_O0];
1724 u_error = 0;
1725 }
1726# endif /* SPARC */
1727# ifdef I386
1728 /* Wanna know how to kill an hour single-stepping? */
1729 if (tcp->status.PR_REG[EFL] & 0x1) {
1730 tcp->u_rval = -1;
1731 u_error = tcp->status.PR_REG[EAX];
1732 }
1733 else {
1734 tcp->u_rval = tcp->status.PR_REG[EAX];
1735# ifdef HAVE_LONG_LONG
1736 tcp->u_lrval =
1737 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1738 tcp->status.PR_REG[EAX];
1739# endif
1740 u_error = 0;
1741 }
1742# endif /* I386 */
1743# ifdef X86_64
1744 /* Wanna know how to kill an hour single-stepping? */
1745 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1746 tcp->u_rval = -1;
1747 u_error = tcp->status.PR_REG[RAX];
1748 }
1749 else {
1750 tcp->u_rval = tcp->status.PR_REG[RAX];
1751 u_error = 0;
1752 }
1753# endif /* X86_64 */
1754# ifdef MIPS
1755 if (tcp->status.pr_reg[CTX_A3]) {
1756 tcp->u_rval = -1;
1757 u_error = tcp->status.pr_reg[CTX_V0];
1758 }
1759 else {
1760 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1761 u_error = 0;
1762 }
1763# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001765#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001766 if (regs.r_eflags & PSL_C) {
1767 tcp->u_rval = -1;
1768 u_error = regs.r_eax;
1769 } else {
1770 tcp->u_rval = regs.r_eax;
1771 tcp->u_lrval =
1772 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1773 u_error = 0;
1774 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001775#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001776 tcp->u_error = u_error;
1777 return 1;
1778}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001779
Roland McGrathb69f81b2002-12-21 23:25:18 +00001780int
Denys Vlasenko12014262011-05-30 14:00:14 +02001781force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001782{
1783#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001784# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001785 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001786 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1787 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001788# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001789 eax = error ? -error : rval;
1790 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1791 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001792# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001793 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001794 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001795 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001796# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001797 if (ia32) {
1798 r8 = error ? -error : rval;
1799 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1800 return -1;
1801 }
1802 else {
1803 if (error) {
1804 r8 = error;
1805 r10 = -1;
1806 }
1807 else {
1808 r8 = rval;
1809 r10 = 0;
1810 }
1811 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1812 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1813 return -1;
1814 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001815# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001816 r0 = error ? -error : rval;
1817 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1818 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001819# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001820 if (error) {
1821 r2 = error;
1822 a3 = -1;
1823 }
1824 else {
1825 r2 = rval;
1826 a3 = 0;
1827 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001828 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001829 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1830 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001831 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001832# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001833 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001834 return -1;
1835 if (error) {
1836 flags |= SO_MASK;
1837 result = error;
1838 }
1839 else {
1840 flags &= ~SO_MASK;
1841 result = rval;
1842 }
Roland McGratheb285352003-01-14 09:59:00 +00001843 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1844 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001845 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001846# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001847 d0 = error ? -error : rval;
1848 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1849 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001850# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001851 regs.ARM_r0 = error ? -error : rval;
1852 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001853 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001854# elif defined(AVR32)
1855 regs.r12 = error ? -error : rval;
1856 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1857 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001858# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001859 if (error) {
1860 a3 = -1;
1861 r0 = error;
1862 }
1863 else {
1864 a3 = 0;
1865 r0 = rval;
1866 }
1867 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1868 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1869 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001870# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001871 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1872 return -1;
1873 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001874 regs.psr |= PSR_C;
1875 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001876 }
1877 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001878 regs.psr &= ~PSR_C;
1879 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001880 }
1881 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1882 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001883# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001884 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1885 return -1;
1886 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001887 regs.tstate |= 0x1100000000UL;
1888 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001889 }
1890 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001891 regs.tstate &= ~0x1100000000UL;
1892 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001893 }
1894 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1895 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001896# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001897 r28 = error ? -error : rval;
1898 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1899 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001900# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001901 r0 = error ? -error : rval;
1902 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1903 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001904# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001905 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001906 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1907 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001908# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001909#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001910
Roland McGrathb69f81b2002-12-21 23:25:18 +00001911#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001912 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1913 error << 24) < 0 ||
1914 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001915 return -1;
1916#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001917
Roland McGrathb69f81b2002-12-21 23:25:18 +00001918#ifdef SVR4
1919 /* XXX no clue */
1920 return -1;
1921#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001922
Roland McGrathb69f81b2002-12-21 23:25:18 +00001923#ifdef FREEBSD
1924 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001925 perror("pread");
1926 return -1;
1927 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001928 if (error) {
1929 regs.r_eflags |= PSL_C;
1930 regs.r_eax = error;
1931 }
1932 else {
1933 regs.r_eflags &= ~PSL_C;
1934 regs.r_eax = rval;
1935 }
1936 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001937 perror("pwrite");
1938 return -1;
1939 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001940#endif /* FREEBSD */
1941
1942 /* All branches reach here on success (only). */
1943 tcp->u_error = error;
1944 tcp->u_rval = rval;
1945 return 0;
1946}
1947
Roland McGratha4d48532005-06-08 20:45:28 +00001948static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001949syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001950{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001951#ifdef LINUX
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001952# if defined(S390) || defined(S390X)
1953 int i;
1954 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1955 tcp->u_nargs = sysent[tcp->scno].nargs;
1956 else
1957 tcp->u_nargs = MAX_ARGS;
1958 for (i = 0; i < tcp->u_nargs; i++) {
1959 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1960 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001961 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001962# elif defined(ALPHA)
1963 int i;
1964 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1965 tcp->u_nargs = sysent[tcp->scno].nargs;
1966 else
1967 tcp->u_nargs = MAX_ARGS;
1968 for (i = 0; i < tcp->u_nargs; i++) {
1969 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1970 * for scno somewhere above here!
1971 */
1972 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1973 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001974 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001975# elif defined(IA64)
1976 if (!ia32) {
1977 unsigned long *out0, cfm, sof, sol, i;
1978 long rbs_end;
1979 /* be backwards compatible with kernel < 2.4.4... */
1980# ifndef PT_RBS_END
1981# define PT_RBS_END PT_AR_BSP
1982# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001983
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001984 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1985 return -1;
1986 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001987 return -1;
1988
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001989 sof = (cfm >> 0) & 0x7f;
1990 sol = (cfm >> 7) & 0x7f;
1991 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1992
1993 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1994 && sysent[tcp->scno].nargs != -1)
1995 tcp->u_nargs = sysent[tcp->scno].nargs;
1996 else
1997 tcp->u_nargs = MAX_ARGS;
1998 for (i = 0; i < tcp->u_nargs; ++i) {
1999 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2000 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2001 return -1;
2002 }
2003 } else {
2004 int i;
2005
2006 if (/* EBX = out0 */
2007 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
2008 /* ECX = out1 */
2009 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
2010 /* EDX = out2 */
2011 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
2012 /* ESI = out3 */
2013 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
2014 /* EDI = out4 */
2015 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
2016 /* EBP = out5 */
2017 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2018 return -1;
2019
2020 for (i = 0; i < 6; ++i)
2021 /* truncate away IVE sign-extension */
2022 tcp->u_arg[i] &= 0xffffffff;
2023
2024 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2025 && sysent[tcp->scno].nargs != -1)
2026 tcp->u_nargs = sysent[tcp->scno].nargs;
2027 else
2028 tcp->u_nargs = 5;
2029 }
2030# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2031 /* N32 and N64 both use up to six registers. */
2032 unsigned long long regs[38];
2033 int i, nargs;
2034 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2035 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2036 else
2037 nargs = tcp->u_nargs = MAX_ARGS;
2038
2039 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2040 return -1;
2041
2042 for (i = 0; i < nargs; i++) {
2043 tcp->u_arg[i] = regs[REG_A0 + i];
2044# if defined(LINUX_MIPSN32)
2045 tcp->ext_arg[i] = regs[REG_A0 + i];
2046# endif
2047 }
2048# elif defined(MIPS)
2049 long sp;
2050 int i, nargs;
2051
2052 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2053 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2054 else
2055 nargs = tcp->u_nargs = MAX_ARGS;
2056 if (nargs > 4) {
2057 if (upeek(tcp, REG_SP, &sp) < 0)
2058 return -1;
2059 for (i = 0; i < 4; i++) {
2060 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2061 return -1;
2062 }
2063 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2064 (char *)(tcp->u_arg + 4));
2065 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002066 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002067 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002068 return -1;
2069 }
2070 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002071# elif defined(POWERPC)
2072# ifndef PT_ORIG_R3
2073# define PT_ORIG_R3 34
2074# endif
2075 int i;
2076 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2077 tcp->u_nargs = sysent[tcp->scno].nargs;
2078 else
2079 tcp->u_nargs = MAX_ARGS;
2080 for (i = 0; i < tcp->u_nargs; i++) {
2081 if (upeek(tcp, (i==0) ?
2082 (sizeof(unsigned long) * PT_ORIG_R3) :
2083 ((i+PT_R3) * sizeof(unsigned long)),
2084 &tcp->u_arg[i]) < 0)
2085 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002086 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002087# elif defined(SPARC) || defined(SPARC64)
2088 int i;
2089 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2090 tcp->u_nargs = sysent[tcp->scno].nargs;
2091 else
2092 tcp->u_nargs = MAX_ARGS;
2093 for (i = 0; i < tcp->u_nargs; i++)
2094 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2095# elif defined(HPPA)
2096 int i;
2097 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2098 tcp->u_nargs = sysent[tcp->scno].nargs;
2099 else
2100 tcp->u_nargs = MAX_ARGS;
2101 for (i = 0; i < tcp->u_nargs; i++) {
2102 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2103 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002104 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002105# elif defined(ARM)
2106 int i;
2107 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2108 tcp->u_nargs = sysent[tcp->scno].nargs;
2109 else
2110 tcp->u_nargs = MAX_ARGS;
2111 for (i = 0; i < tcp->u_nargs; i++)
2112 tcp->u_arg[i] = regs.uregs[i];
2113# elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002114 tcp->u_nargs = sysent[tcp->scno].nargs;
2115 tcp->u_arg[0] = regs.r12;
2116 tcp->u_arg[1] = regs.r11;
2117 tcp->u_arg[2] = regs.r10;
2118 tcp->u_arg[3] = regs.r9;
2119 tcp->u_arg[4] = regs.r5;
2120 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002121# elif defined(BFIN)
2122 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002123 static const int argreg[] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002124
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002125 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002126 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002127 else
2128 tcp->u_nargs = ARRAY_SIZE(argreg);
2129
2130 for (i = 0; i < tcp->u_nargs; ++i)
2131 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2132 return -1;
2133# elif defined(SH)
2134 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002135 static const int syscall_regs[] = {
2136 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6), 4 * (REG_REG0+7),
2137 4 * (REG_REG0 ), 4 * (REG_REG0+1), 4 * (REG_REG0+2)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002138 };
2139
2140 tcp->u_nargs = sysent[tcp->scno].nargs;
2141 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002142 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002143 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002144 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002145# elif defined(SH64)
2146 int i;
2147 /* Registers used by SH5 Linux system calls for parameters */
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002148 static const int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002149
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002150 /*
2151 * TODO: should also check that the number of arguments encoded
2152 * in the trap number matches the number strace expects.
2153 */
2154 /*
2155 assert(sysent[tcp->scno].nargs < ARRAY_SIZE(syscall_regs));
2156 */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002157
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002158 tcp->u_nargs = sysent[tcp->scno].nargs;
2159 for (i = 0; i < tcp->u_nargs; i++) {
2160 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2161 return -1;
2162 }
2163# elif defined(X86_64)
2164 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002165 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2166 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2167 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002168 };
2169
2170 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002171 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002172 else
2173 tcp->u_nargs = MAX_ARGS;
2174 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002175 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002176 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00002177 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002178# elif defined(MICROBLAZE)
2179 int i;
2180 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2181 tcp->u_nargs = sysent[tcp->scno].nargs;
2182 else
2183 tcp->u_nargs = 0;
2184 for (i = 0; i < tcp->u_nargs; i++) {
2185 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2186 return -1;
2187 }
2188# elif defined(CRISV10) || defined(CRISV32)
2189 int i;
2190 static const int crisregs[] = {
2191 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002192 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002193 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002194
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002195 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2196 tcp->u_nargs = sysent[tcp->scno].nargs;
2197 else
2198 tcp->u_nargs = 0;
2199 for (i = 0; i < tcp->u_nargs; i++) {
2200 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2201 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00002202 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002203# elif defined(TILE)
2204 int i;
2205 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2206 tcp->u_nargs = sysent[tcp->scno].nargs;
2207 else
2208 tcp->u_nargs = MAX_ARGS;
2209 for (i = 0; i < tcp->u_nargs; ++i) {
2210 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2211 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002212 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002213# elif defined(M68K)
2214 int i;
2215 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2216 tcp->u_nargs = sysent[tcp->scno].nargs;
2217 else
2218 tcp->u_nargs = MAX_ARGS;
2219 for (i = 0; i < tcp->u_nargs; i++) {
2220 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2221 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002222 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002223# else /* Other architecture (like i386) (32bits specific) */
2224 int i;
2225 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2226 tcp->u_nargs = sysent[tcp->scno].nargs;
2227 else
2228 tcp->u_nargs = MAX_ARGS;
2229 for (i = 0; i < tcp->u_nargs; i++) {
2230 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2231 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05002232 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002233# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002234#endif /* LINUX */
2235#ifdef SUNOS4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002236 int i;
2237 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2238 tcp->u_nargs = sysent[tcp->scno].nargs;
2239 else
2240 tcp->u_nargs = MAX_ARGS;
2241 for (i = 0; i < tcp->u_nargs; i++) {
2242 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002243
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002244 if (upeek(tcp, uoff(u_arg[0]) +
2245 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2246 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247 }
2248#endif /* SUNOS4 */
2249#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002250# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002251 /*
2252 * SGI is broken: even though it has pr_sysarg, it doesn't
2253 * set them on system call entry. Get a clue.
2254 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002255 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002256 tcp->u_nargs = sysent[tcp->scno].nargs;
2257 else
2258 tcp->u_nargs = tcp->status.pr_nsysarg;
2259 if (tcp->u_nargs > 4) {
2260 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002261 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002262 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002263 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002264 }
2265 else {
2266 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002267 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002268 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002269# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002270 /*
2271 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2272 */
2273 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2274 tcp->u_nargs = sysent[tcp->scno].nargs;
2275 else
2276 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2277 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002278 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2279# elif defined(HAVE_PR_SYSCALL)
2280 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002281 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002282 tcp->u_nargs = sysent[tcp->scno].nargs;
2283 else
2284 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002285 for (i = 0; i < tcp->u_nargs; i++)
2286 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2287# elif defined(I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002288 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002289 tcp->u_nargs = sysent[tcp->scno].nargs;
2290 else
2291 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002292 if (tcp->u_nargs > 0)
2293 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002294 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2295# else
John Hughes25299712001-03-06 10:10:06 +00002296 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002297# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002298#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002299#ifdef FREEBSD
2300 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2301 sysent[tcp->scno].nargs > tcp->status.val)
2302 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002303 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002304 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002305 if (tcp->u_nargs < 0)
2306 tcp->u_nargs = 0;
2307 if (tcp->u_nargs > MAX_ARGS)
2308 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002309 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002310 case SYS___syscall:
2311 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2312 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002313 break;
2314 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002315 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2316 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002317 break;
2318 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002319 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2320 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002321 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002322 }
2323#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002324 return 1;
2325}
2326
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002327static int
2328trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002329{
2330 int sys_res;
2331 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002332 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002333 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002334
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002335 /* Measure the exit time as early as possible to avoid errors. */
2336 if (dtime || cflag)
2337 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002338
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002339 /* BTW, why we don't just memorize syscall no. on entry
2340 * in tcp->something?
2341 */
2342 scno_good = res = get_scno(tcp);
2343 if (res == 0)
2344 return res;
2345 if (res == 1)
2346 res = syscall_fixup(tcp);
2347 if (res == 0)
2348 return res;
2349 if (res == 1)
2350 res = get_error(tcp);
2351 if (res == 0)
2352 return res;
2353 if (res == 1)
2354 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002355
Grant Edwards8a082772011-04-07 20:25:40 +00002356 if (res == 1 && filtered(tcp)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002357 tcp->flags &= ~TCB_INSYSCALL;
2358 return 0;
2359 }
2360
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002361 if (tcp->flags & TCB_REPRINT) {
2362 printleader(tcp);
2363 tprintf("<... ");
2364 if (scno_good != 1)
2365 tprintf("????");
2366 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2367 tprintf("syscall_%lu", tcp->scno);
2368 else
2369 tprintf("%s", sysent[tcp->scno].sys_name);
2370 tprintf(" resumed> ");
2371 }
2372
2373 if (cflag) {
2374 struct timeval t = tv;
2375 int rc = count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002376 if (cflag == CFLAG_ONLY_STATS) {
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002377 tcp->flags &= ~TCB_INSYSCALL;
2378 return rc;
2379 }
2380 }
2381
2382 if (res != 1) {
2383 tprintf(") ");
2384 tabto(acolumn);
2385 tprintf("= ? <unavailable>");
2386 printtrailer();
2387 tcp->flags &= ~TCB_INSYSCALL;
2388 return res;
2389 }
2390
2391 if (tcp->scno >= nsyscalls || tcp->scno < 0
2392 || (qual_flags[tcp->scno] & QUAL_RAW))
2393 sys_res = printargs(tcp);
2394 else {
2395 if (not_failing_only && tcp->u_error)
2396 return 0; /* ignore failed syscalls */
2397 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2398 }
2399
2400 u_error = tcp->u_error;
2401 tprintf(") ");
2402 tabto(acolumn);
2403 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2404 qual_flags[tcp->scno] & QUAL_RAW) {
2405 if (u_error)
2406 tprintf("= -1 (errno %ld)", u_error);
2407 else
2408 tprintf("= %#lx", tcp->u_rval);
2409 }
2410 else if (!(sys_res & RVAL_NONE) && u_error) {
2411 switch (u_error) {
2412#ifdef LINUX
2413 case ERESTARTSYS:
2414 tprintf("= ? ERESTARTSYS (To be restarted)");
2415 break;
2416 case ERESTARTNOINTR:
2417 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2418 break;
2419 case ERESTARTNOHAND:
2420 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2421 break;
2422 case ERESTART_RESTARTBLOCK:
2423 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2424 break;
2425#endif /* LINUX */
2426 default:
2427 tprintf("= -1 ");
2428 if (u_error < 0)
2429 tprintf("E??? (errno %ld)", u_error);
2430 else if (u_error < nerrnos)
2431 tprintf("%s (%s)", errnoent[u_error],
2432 strerror(u_error));
2433 else
2434 tprintf("ERRNO_%ld (%s)", u_error,
2435 strerror(u_error));
2436 break;
2437 }
2438 if ((sys_res & RVAL_STR) && tcp->auxstr)
2439 tprintf(" (%s)", tcp->auxstr);
2440 }
2441 else {
2442 if (sys_res & RVAL_NONE)
2443 tprintf("= ?");
2444 else {
2445 switch (sys_res & RVAL_MASK) {
2446 case RVAL_HEX:
2447 tprintf("= %#lx", tcp->u_rval);
2448 break;
2449 case RVAL_OCTAL:
2450 tprintf("= %#lo", tcp->u_rval);
2451 break;
2452 case RVAL_UDECIMAL:
2453 tprintf("= %lu", tcp->u_rval);
2454 break;
2455 case RVAL_DECIMAL:
2456 tprintf("= %ld", tcp->u_rval);
2457 break;
2458#ifdef HAVE_LONG_LONG
2459 case RVAL_LHEX:
2460 tprintf("= %#llx", tcp->u_lrval);
2461 break;
2462 case RVAL_LOCTAL:
2463 tprintf("= %#llo", tcp->u_lrval);
2464 break;
2465 case RVAL_LUDECIMAL:
2466 tprintf("= %llu", tcp->u_lrval);
2467 break;
2468 case RVAL_LDECIMAL:
2469 tprintf("= %lld", tcp->u_lrval);
2470 break;
2471#endif
2472 default:
2473 fprintf(stderr,
2474 "invalid rval format\n");
2475 break;
2476 }
2477 }
2478 if ((sys_res & RVAL_STR) && tcp->auxstr)
2479 tprintf(" (%s)", tcp->auxstr);
2480 }
2481 if (dtime) {
2482 tv_sub(&tv, &tv, &tcp->etime);
2483 tprintf(" <%ld.%06ld>",
2484 (long) tv.tv_sec, (long) tv.tv_usec);
2485 }
2486 printtrailer();
2487
2488 dumpio(tcp);
2489 if (fflush(tcp->outf) == EOF)
2490 return -1;
2491 tcp->flags &= ~TCB_INSYSCALL;
2492 return 0;
2493}
2494
2495static int
2496trace_syscall_entering(struct tcb *tcp)
2497{
2498 int sys_res;
2499 int res, scno_good;
2500
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002501 scno_good = res = get_scno(tcp);
2502 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002503 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002504 if (res == 1)
2505 res = syscall_fixup(tcp);
2506 if (res == 0)
2507 return res;
2508 if (res == 1)
2509 res = syscall_enter(tcp);
2510 if (res == 0)
2511 return res;
2512
2513 if (res != 1) {
2514 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002515 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002516 tcp_last = tcp;
2517 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002518 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002519 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2520 tprintf("syscall_%lu(", tcp->scno);
2521 else
2522 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002523 /*
2524 * " <unavailable>" will be added later by the code which
2525 * detects ptrace errors.
2526 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002527 tcp->flags |= TCB_INSYSCALL;
2528 return res;
2529 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002530
Roland McGrath17352792005-06-07 23:21:26 +00002531 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002532#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002533 case SYS_socketcall:
2534 decode_subcall(tcp, SYS_socket_subcall,
2535 SYS_socket_nsubcalls, deref_style);
2536 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002537#endif
2538#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002539 case SYS_ipc:
2540 decode_subcall(tcp, SYS_ipc_subcall,
2541 SYS_ipc_nsubcalls, shift_style);
2542 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002543#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002544#ifdef SVR4
2545#ifdef SYS_pgrpsys_subcall
2546 case SYS_pgrpsys:
2547 decode_subcall(tcp, SYS_pgrpsys_subcall,
2548 SYS_pgrpsys_nsubcalls, shift_style);
2549 break;
2550#endif /* SYS_pgrpsys_subcall */
2551#ifdef SYS_sigcall_subcall
2552 case SYS_sigcall:
2553 decode_subcall(tcp, SYS_sigcall_subcall,
2554 SYS_sigcall_nsubcalls, mask_style);
2555 break;
2556#endif /* SYS_sigcall_subcall */
2557 case SYS_msgsys:
2558 decode_subcall(tcp, SYS_msgsys_subcall,
2559 SYS_msgsys_nsubcalls, shift_style);
2560 break;
2561 case SYS_shmsys:
2562 decode_subcall(tcp, SYS_shmsys_subcall,
2563 SYS_shmsys_nsubcalls, shift_style);
2564 break;
2565 case SYS_semsys:
2566 decode_subcall(tcp, SYS_semsys_subcall,
2567 SYS_semsys_nsubcalls, shift_style);
2568 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002569 case SYS_sysfs:
2570 decode_subcall(tcp, SYS_sysfs_subcall,
2571 SYS_sysfs_nsubcalls, shift_style);
2572 break;
2573 case SYS_spcall:
2574 decode_subcall(tcp, SYS_spcall_subcall,
2575 SYS_spcall_nsubcalls, shift_style);
2576 break;
2577#ifdef SYS_context_subcall
2578 case SYS_context:
2579 decode_subcall(tcp, SYS_context_subcall,
2580 SYS_context_nsubcalls, shift_style);
2581 break;
2582#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002583#ifdef SYS_door_subcall
2584 case SYS_door:
2585 decode_subcall(tcp, SYS_door_subcall,
2586 SYS_door_nsubcalls, door_style);
2587 break;
2588#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002589#ifdef SYS_kaio_subcall
2590 case SYS_kaio:
2591 decode_subcall(tcp, SYS_kaio_subcall,
2592 SYS_kaio_nsubcalls, shift_style);
2593 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002594#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002595#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002596#ifdef FREEBSD
2597 case SYS_msgsys:
2598 case SYS_shmsys:
2599 case SYS_semsys:
2600 decode_subcall(tcp, 0, 0, table_style);
2601 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002602#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002603#ifdef SUNOS4
2604 case SYS_semsys:
2605 decode_subcall(tcp, SYS_semsys_subcall,
2606 SYS_semsys_nsubcalls, shift_style);
2607 break;
2608 case SYS_msgsys:
2609 decode_subcall(tcp, SYS_msgsys_subcall,
2610 SYS_msgsys_nsubcalls, shift_style);
2611 break;
2612 case SYS_shmsys:
2613 decode_subcall(tcp, SYS_shmsys_subcall,
2614 SYS_shmsys_nsubcalls, shift_style);
2615 break;
2616#endif
2617 }
2618
2619 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002620
2621 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2622 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2623 (tracing_paths && !pathtrace_match(tcp))) {
2624 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002625 return 0;
2626 }
2627
Grant Edwards8a082772011-04-07 20:25:40 +00002628 tcp->flags &= ~TCB_FILTERED;
2629
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002630 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002631 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002632 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002633 return 0;
2634 }
2635
2636 printleader(tcp);
2637 tcp->flags &= ~TCB_REPRINT;
2638 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002639 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002640 tprintf("syscall_%lu(", tcp->scno);
2641 else
2642 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002643 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002644 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2645 sysent[tcp->scno].sys_func != sys_exit))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002646 sys_res = printargs(tcp);
2647 else
2648 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2649 if (fflush(tcp->outf) == EOF)
2650 return -1;
2651 tcp->flags |= TCB_INSYSCALL;
2652 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002653 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002654 gettimeofday(&tcp->etime, NULL);
2655 return sys_res;
2656}
2657
2658int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002659trace_syscall(struct tcb *tcp)
2660{
2661 return exiting(tcp) ?
2662 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2663}
2664
2665int
Denys Vlasenko12014262011-05-30 14:00:14 +02002666printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002667{
2668 if (entering(tcp)) {
2669 int i;
2670
2671 for (i = 0; i < tcp->u_nargs; i++)
2672 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2673 }
2674 return 0;
2675}
2676
2677long
Denys Vlasenko12014262011-05-30 14:00:14 +02002678getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002679{
2680 long val = -1;
2681
2682#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002683#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002684 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002685 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002686 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002687 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002688#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002689 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002690 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002691#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002692 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002693 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002694#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002695#endif /* LINUX */
2696
2697#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002698 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002699 return -1;
2700#endif /* SUNOS4 */
2701
2702#ifdef SVR4
2703#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002704 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002705#endif /* SPARC */
2706#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002707 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002708#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002709#ifdef X86_64
2710 val = tcp->status.PR_REG[RDX];
2711#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002712#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002713 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002714#endif /* MIPS */
2715#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002716
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002717#ifdef FREEBSD
2718 struct reg regs;
2719 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2720 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002721#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002722 return val;
2723}
2724
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002725#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002726/*
2727 * Apparently, indirect system calls have already be converted by ptrace(2),
2728 * so if you see "indir" this program has gone astray.
2729 */
2730int
Denys Vlasenko12014262011-05-30 14:00:14 +02002731sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002732{
2733 int i, scno, nargs;
2734
2735 if (entering(tcp)) {
2736 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2737 fprintf(stderr, "Bogus syscall: %u\n", scno);
2738 return 0;
2739 }
2740 nargs = sysent[scno].nargs;
2741 tprintf("%s", sysent[scno].sys_name);
2742 for (i = 0; i < nargs; i++)
2743 tprintf(", %#lx", tcp->u_arg[i+1]);
2744 }
2745 return 0;
2746}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002747#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002748
2749int
2750is_restart_error(struct tcb *tcp)
2751{
2752#ifdef LINUX
2753 if (!syserror(tcp))
2754 return 0;
2755 switch (tcp->u_error) {
2756 case ERESTARTSYS:
2757 case ERESTARTNOINTR:
2758 case ERESTARTNOHAND:
2759 case ERESTART_RESTARTBLOCK:
2760 return 1;
2761 default:
2762 break;
2763 }
2764#endif /* LINUX */
2765 return 0;
2766}