blob: d6d4697f17e687c02d65511f94441c41af4d91fd [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;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200751 static const int gpr_offset[16] = {
752 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
753 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
754 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
755 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
756 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000757
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000758 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000759 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000760 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000761 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000762 if (errno) {
763 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000764 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000765 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000766
767 /*
768 * We have to check if the SVC got executed directly or via an
769 * EXECUTE instruction. In case of EXECUTE it is necessary to do
770 * instruction decoding to derive the system call number.
771 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
772 * so that this doesn't work if a SVC opcode is part of an EXECUTE
773 * opcode. Since there is no way to find out the opcode size this
774 * is the best we can do...
775 */
776
777 if ((opcode & 0xff00) == 0x0a00) {
778 /* SVC opcode */
779 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000780 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000781 else {
782 /* SVC got executed by EXECUTE instruction */
783
784 /*
785 * Do instruction decoding of EXECUTE. If you really want to
786 * understand this, read the Principles of Operations.
787 */
788 svc_addr = (void *) (opcode & 0xfff);
789
790 tmp = 0;
791 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000792 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000793 return -1;
794 svc_addr += tmp;
795
796 tmp = 0;
797 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000798 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000799 return -1;
800 svc_addr += tmp;
801
Denys Vlasenkofb036672009-01-23 16:30:26 +0000802 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000803 if (errno)
804 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000805# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000806 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000807# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000808 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000809# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000810 tmp = 0;
811 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000812 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000813 return -1;
814
815 scno = (scno | tmp) & 0xff;
816 }
817 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000818# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000819 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820 return -1;
821 if (!(tcp->flags & TCB_INSYSCALL)) {
822 /* Check if we return from execve. */
823 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
824 tcp->flags &= ~TCB_WAITEXECVE;
825 return 0;
826 }
827 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200828
829# ifdef POWERPC64
830 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200831 /* TODO: speed up strace by not doing this at every syscall.
832 * We only need to do it after execve.
833 */
834 int currpers;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200835 long val;
836 int pid = tcp->pid;
837
838 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200839 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200840 return -1;
841 /* SF is bit 0 of MSR */
842 if (val < 0)
843 currpers = 0;
844 else
845 currpers = 1;
846 if (currpers != current_personality) {
847 static const char *const names[] = {"64 bit", "32 bit"};
848 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000849 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200850 pid, names[current_personality]);
851 }
852 }
853# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000854# elif defined(AVR32)
855 /*
856 * Read complete register set in one go.
857 */
858 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
859 return -1;
860
861 /*
862 * We only need to grab the syscall number on syscall entry.
863 */
864 if (!(tcp->flags & TCB_INSYSCALL)) {
865 scno = regs.r8;
866
867 /* Check if we return from execve. */
868 if (tcp->flags & TCB_WAITEXECVE) {
869 tcp->flags &= ~TCB_WAITEXECVE;
870 return 0;
871 }
872 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000873# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000874 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000875 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000876# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000877 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000878 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000879# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000880 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000881 return -1;
882
Roland McGrath761b5d72002-12-15 23:58:31 +0000883 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200884 /* TODO: speed up strace by not doing this at every syscall.
885 * We only need to do it after execve.
886 */
887 int currpers;
Michal Ludvig0e035502002-09-23 15:41:01 +0000888 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000889 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000890
891 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200892 * 0x33 for long mode (64 bit)
893 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000894 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000895 * to be cached.
896 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000897 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000898 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000899 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000900 case 0x23: currpers = 1; break;
901 case 0x33: currpers = 0; break;
902 default:
903 fprintf(stderr, "Unknown value CS=0x%02X while "
904 "detecting personality of process "
905 "PID=%d\n", (int)val, pid);
906 currpers = current_personality;
907 break;
908 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000909# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000910 /* This version analyzes the opcode of a syscall instruction.
911 * (int 0x80 on i386 vs. syscall on x86-64)
912 * It works, but is too complicated.
913 */
914 unsigned long val, rip, i;
915
Denys Vlasenko8236f252009-01-02 18:10:08 +0000916 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000917 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000918
Michal Ludvig0e035502002-09-23 15:41:01 +0000919 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000920 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000921 errno = 0;
922
Denys Vlasenko8236f252009-01-02 18:10:08 +0000923 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000924 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000925 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000926 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000927 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000928 /* x86-64: syscall = 0x0f 0x05 */
929 case 0x050f: currpers = 0; break;
930 /* i386: int 0x80 = 0xcd 0x80 */
931 case 0x80cd: currpers = 1; break;
932 default:
933 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000934 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000935 "Unknown syscall opcode (0x%04X) while "
936 "detecting personality of process "
937 "PID=%d\n", (int)call, pid);
938 break;
939 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000940# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000941 if (currpers != current_personality) {
942 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000943 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000944 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000945 pid, names[current_personality]);
946 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000947 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000948# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000949# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200950 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000951 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000952 if (!(tcp->flags & TCB_INSYSCALL)) {
953 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000954 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000955 return -1;
956 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200957 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000958 return -1;
959 }
Roland McGrathba954762003-03-05 06:29:06 +0000960 /* Check if we return from execve. */
961 if (tcp->flags & TCB_WAITEXECVE) {
962 tcp->flags &= ~TCB_WAITEXECVE;
963 return 0;
964 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000965 } else {
966 /* syscall in progress */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200967 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000968 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200969 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000970 return -1;
971 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000972# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000973 /*
974 * Read complete register set in one go.
975 */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000976 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000977 return -1;
978
979 /*
980 * We only need to grab the syscall number on syscall entry.
981 */
982 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +0000983 if (!(tcp->flags & TCB_INSYSCALL)) {
984 /* Check if we return from execve. */
985 if (tcp->flags & TCB_WAITEXECVE) {
986 tcp->flags &= ~TCB_WAITEXECVE;
987 return 0;
988 }
989 }
990
Roland McGrath0f87c492003-06-03 23:29:04 +0000991 /*
992 * Note: we only deal with only 32-bit CPUs here.
993 */
994 if (regs.ARM_cpsr & 0x20) {
995 /*
996 * Get the Thumb-mode system call number
997 */
998 scno = regs.ARM_r7;
999 } else {
1000 /*
1001 * Get the ARM-mode system call number
1002 */
1003 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001004 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001005 if (errno)
1006 return -1;
1007
1008 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1009 tcp->flags &= ~TCB_WAITEXECVE;
1010 return 0;
1011 }
1012
Roland McGrathf691bd22006-04-25 07:34:41 +00001013 /* Handle the EABI syscall convention. We do not
1014 bother converting structures between the two
1015 ABIs, but basic functionality should work even
1016 if strace and the traced program have different
1017 ABIs. */
1018 if (scno == 0xef000000) {
1019 scno = regs.ARM_r7;
1020 } else {
1021 if ((scno & 0x0ff00000) != 0x0f900000) {
1022 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1023 scno);
1024 return -1;
1025 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001026
Roland McGrathf691bd22006-04-25 07:34:41 +00001027 /*
1028 * Fixup the syscall number
1029 */
1030 scno &= 0x000fffff;
1031 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001032 }
Roland McGrath56703312008-05-20 01:35:55 +00001033 if (scno & 0x0f0000) {
1034 /*
1035 * Handle ARM specific syscall
1036 */
1037 set_personality(1);
1038 scno &= 0x0000ffff;
1039 } else
1040 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001041
1042 if (tcp->flags & TCB_INSYSCALL) {
1043 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1044 tcp->flags &= ~TCB_INSYSCALL;
1045 }
1046 } else {
1047 if (!(tcp->flags & TCB_INSYSCALL)) {
1048 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1049 tcp->flags |= TCB_INSYSCALL;
1050 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001052# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001053 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001054 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001055# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001056 unsigned long long regs[38];
1057
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001058 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001059 return -1;
1060 a3 = regs[REG_A3];
1061 r2 = regs[REG_V0];
1062
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001063 if (!(tcp->flags & TCB_INSYSCALL)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001064 scno = r2;
1065
1066 /* Check if we return from execve. */
1067 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1068 tcp->flags &= ~TCB_WAITEXECVE;
1069 return 0;
1070 }
1071
1072 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001073 if (a3 == 0 || a3 == -1) {
1074 if (debug)
1075 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001076 return 0;
1077 }
1078 }
1079 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001080# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001081 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001082 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001083 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001084 if (upeek(tcp, REG_V0, &scno) < 0)
1085 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001086
Roland McGrath542c2c62008-05-20 01:11:56 +00001087 /* Check if we return from execve. */
1088 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1089 tcp->flags &= ~TCB_WAITEXECVE;
1090 return 0;
1091 }
1092
Wichert Akkermanf90da011999-10-31 21:15:38 +00001093 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001094 if (a3 == 0 || a3 == -1) {
1095 if (debug)
1096 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001097 return 0;
1098 }
1099 }
1100 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001101 if (upeek(tcp, REG_V0, &r2) < 0)
1102 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001103 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001104# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001105 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106 return -1;
1107
1108 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001109 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001110 return -1;
1111
1112 /* Check if we return from execve. */
1113 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1114 tcp->flags &= ~TCB_WAITEXECVE;
1115 return 0;
1116 }
1117
1118 /*
1119 * Do some sanity checks to figure out if it's
1120 * really a syscall entry
1121 */
1122 if (scno < 0 || scno > nsyscalls) {
1123 if (a3 == 0 || a3 == -1) {
1124 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001125 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126 return 0;
1127 }
1128 }
1129 }
1130 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001131 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 return -1;
1133 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001134# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001136 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137 return -1;
1138
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001139 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140 if (!(tcp->flags & TCB_INSYSCALL)) {
1141 /* Retrieve the syscall trap instruction. */
1142 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001143# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001144 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001145 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001146# else
1147 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001148# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149 if (errno)
1150 return -1;
1151
1152 /* Disassemble the trap to see what personality to use. */
1153 switch (trap) {
1154 case 0x91d02010:
1155 /* Linux/SPARC syscall trap. */
1156 set_personality(0);
1157 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001158 case 0x91d0206d:
1159 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001160 set_personality(2);
1161 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001162 case 0x91d02000:
1163 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001164 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165 return -1;
1166 case 0x91d02008:
1167 /* Solaris 2.x syscall trap. (per 2) */
1168 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001169 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001170 case 0x91d02009:
1171 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001172 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173 return -1;
1174 case 0x91d02027:
1175 /* Solaris 2.x gettimeofday */
1176 set_personality(1);
1177 break;
1178 default:
1179 /* Unknown syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001180 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 tcp->flags &= ~TCB_WAITEXECVE;
1182 return 0;
1183 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001184# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001185 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001186# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001187 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001188# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189 return -1;
1190 }
1191
1192 /* Extract the system call number from the registers. */
1193 if (trap == 0x91d02027)
1194 scno = 156;
1195 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001196 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001198 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001199 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 +00001200 }
1201 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001202# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001203 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001204 return -1;
1205 if (!(tcp->flags & TCB_INSYSCALL)) {
1206 /* Check if we return from execve. */
1207 if ((tcp->flags & TCB_WAITEXECVE)) {
1208 tcp->flags &= ~TCB_WAITEXECVE;
1209 return 0;
1210 }
1211 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001212# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001213 /*
1214 * In the new syscall ABI, the system call number is in R3.
1215 */
1216 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1217 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001218
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001219 if (scno < 0) {
1220 /* Odd as it may seem, a glibc bug has been known to cause
1221 glibc to issue bogus negative syscall numbers. So for
1222 our purposes, make strace print what it *should* have been */
1223 long correct_scno = (scno & 0xff);
1224 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001225 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001226 "Detected glibc bug: bogus system call"
1227 " number = %ld, correcting to %ld\n",
1228 scno,
1229 correct_scno);
1230 scno = correct_scno;
1231 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001232
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001233 if (!(tcp->flags & TCB_INSYSCALL)) {
1234 /* Check if we return from execve. */
1235 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1236 tcp->flags &= ~TCB_WAITEXECVE;
1237 return 0;
1238 }
1239 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001240# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001241 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001242 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001243 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001244
1245 if (!(tcp->flags & TCB_INSYSCALL)) {
1246 /* Check if we return from execve. */
1247 if (tcp->flags & TCB_WAITEXECVE) {
1248 tcp->flags &= ~TCB_WAITEXECVE;
1249 return 0;
1250 }
1251 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001252# elif defined(CRISV10) || defined(CRISV32)
1253 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1254 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001255# elif defined(TILE)
1256 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1257 return -1;
1258
1259 if (!(tcp->flags & TCB_INSYSCALL)) {
1260 /* Check if we return from execve. */
1261 if (tcp->flags & TCB_WAITEXECVE) {
1262 tcp->flags &= ~TCB_WAITEXECVE;
1263 return 0;
1264 }
1265 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001266# elif defined(MICROBLAZE)
1267 if (upeek(tcp, 0, &scno) < 0)
1268 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001269# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001270#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001271
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001272#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001273 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001274 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001275#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001276 /* new syscall ABI returns result in R0 */
1277 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1278 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001279#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001280 /* ABI defines result returned in r9 */
1281 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1282 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001283#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001284
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001285#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001286# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001287 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001288# else
1289# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001290 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001291# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001292 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001293 perror("pread");
1294 return -1;
1295 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001296 switch (regs.r_eax) {
1297 case SYS_syscall:
1298 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001299 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1300 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001301 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001302 scno = regs.r_eax;
1303 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001304 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001305# endif /* FREEBSD */
1306# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001307#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001308
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001309 if (!(tcp->flags & TCB_INSYSCALL))
1310 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001311 return 1;
1312}
1313
Pavel Machek4dc3b142000-02-01 17:58:41 +00001314
Roland McGrath17352792005-06-07 23:21:26 +00001315long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001316known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001317{
1318 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001319#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001320 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1321 scno = sysent[scno].native_scno;
1322 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001323#endif
Roland McGrath17352792005-06-07 23:21:26 +00001324 scno += NR_SYSCALL_BASE;
1325 return scno;
1326}
1327
Roland McGratheb9e2e82009-06-02 16:49:22 -07001328/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001329 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001330 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1331 * 1: ok, continue in trace_syscall().
1332 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001333 * ("????" etc) and bail out.
1334 */
Roland McGratha4d48532005-06-08 20:45:28 +00001335static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001336syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001337{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001338#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001339 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001340
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001341 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001342 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001343 if (
1344 scno == SYS_fork
1345#ifdef SYS_vfork
1346 || scno == SYS_vfork
1347#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001348#ifdef SYS_fork1
1349 || scno == SYS_fork1
1350#endif /* SYS_fork1 */
1351#ifdef SYS_forkall
1352 || scno == SYS_forkall
1353#endif /* SYS_forkall */
1354#ifdef SYS_rfork1
1355 || scno == SYS_rfork1
1356#endif /* SYS_fork1 */
1357#ifdef SYS_rforkall
1358 || scno == SYS_rforkall
1359#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001360 ) {
1361 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001362 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001363 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001364 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001365 }
1366 else {
1367 fprintf(stderr, "syscall: missing entry\n");
1368 tcp->flags |= TCB_INSYSCALL;
1369 }
1370 }
1371 }
1372 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001373 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374 fprintf(stderr, "syscall: missing exit\n");
1375 tcp->flags &= ~TCB_INSYSCALL;
1376 }
1377 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001378#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001379#ifdef SUNOS4
1380 if (!(tcp->flags & TCB_INSYSCALL)) {
1381 if (scno == 0) {
1382 fprintf(stderr, "syscall: missing entry\n");
1383 tcp->flags |= TCB_INSYSCALL;
1384 }
1385 }
1386 else {
1387 if (scno != 0) {
1388 if (debug) {
1389 /*
1390 * This happens when a signal handler
1391 * for a signal which interrupted a
1392 * a system call makes another system call.
1393 */
1394 fprintf(stderr, "syscall: missing exit\n");
1395 }
1396 tcp->flags &= ~TCB_INSYSCALL;
1397 }
1398 }
1399#endif /* SUNOS4 */
1400#ifdef LINUX
1401#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001402 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001403 return -1;
1404 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1405 if (debug)
1406 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1407 return 0;
1408 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001409#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001410 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001411 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001412 if (current_personality == 1)
1413 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001414 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1415 if (debug)
1416 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1417 return 0;
1418 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001419#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001420 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001421 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001422 if (syscall_mode != -ENOSYS)
1423 syscall_mode = tcp->scno;
1424 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001425 if (debug)
1426 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1427 return 0;
1428 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001429 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1430 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1431 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1432 /*
1433 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1434 * flag set for the post-execve SIGTRAP to see and reset.
1435 */
1436 gpr2 = 0;
1437 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001438#elif defined (POWERPC)
1439# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001440 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001441 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001442 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001443 return -1;
1444 if (flags & SO_MASK)
1445 result = -result;
1446#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001447 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448 return -1;
1449 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1450 if (debug)
1451 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1452 return 0;
1453 }
1454#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001455 /*
1456 * Nothing required
1457 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001458#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001459 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001460 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001461#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001462 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001463 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001464#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001465 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001466 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001467 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001468 return -1;
1469 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1470 if (debug)
1471 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1472 return 0;
1473 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001474#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001475 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001476 return -1;
1477 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1478 if (debug)
1479 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1480 return 0;
1481 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001482#elif defined(MICROBLAZE)
1483 if (upeek(tcp, 3 * 4, &r3) < 0)
1484 return -1;
1485 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1486 if (debug)
1487 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1488 return 0;
1489 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001490#endif
1491#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001492 return 1;
1493}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001494
Roland McGrathc1e45922008-05-27 23:18:29 +00001495#ifdef LINUX
1496/*
1497 * Check the syscall return value register value for whether it is
1498 * a negated errno code indicating an error, or a success return value.
1499 */
1500static inline int
1501is_negated_errno(unsigned long int val)
1502{
1503 unsigned long int max = -(long int) nerrnos;
1504 if (personality_wordsize[current_personality] < sizeof(val)) {
1505 val = (unsigned int) val;
1506 max = (unsigned int) max;
1507 }
1508 return val > max;
1509}
1510#endif
1511
Roland McGratha4d48532005-06-08 20:45:28 +00001512static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001513get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001514{
1515 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001517 int check_errno = 1;
1518 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1519 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1520 check_errno = 0;
1521 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001522# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001523 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001524 tcp->u_rval = -1;
1525 u_error = -gpr2;
1526 }
1527 else {
1528 tcp->u_rval = gpr2;
1529 u_error = 0;
1530 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001531# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001532 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001533 tcp->u_rval = -1;
1534 u_error = -eax;
1535 }
1536 else {
1537 tcp->u_rval = eax;
1538 u_error = 0;
1539 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001540# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001541 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001542 tcp->u_rval = -1;
1543 u_error = -rax;
1544 }
1545 else {
1546 tcp->u_rval = rax;
1547 u_error = 0;
1548 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001549# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001550 if (ia32) {
1551 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001552
Roland McGrathc1e45922008-05-27 23:18:29 +00001553 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001554 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001555 tcp->u_rval = -1;
1556 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001557 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001558 else {
1559 tcp->u_rval = err;
1560 u_error = 0;
1561 }
1562 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001563 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001564 tcp->u_rval = -1;
1565 u_error = r8;
1566 } else {
1567 tcp->u_rval = r8;
1568 u_error = 0;
1569 }
1570 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001571# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001572 if (check_errno && a3) {
1573 tcp->u_rval = -1;
1574 u_error = r2;
1575 } else {
1576 tcp->u_rval = r2;
1577 u_error = 0;
1578 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001579# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001580 if (check_errno && is_negated_errno(result)) {
1581 tcp->u_rval = -1;
1582 u_error = -result;
1583 }
1584 else {
1585 tcp->u_rval = result;
1586 u_error = 0;
1587 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001588# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001589 if (check_errno && is_negated_errno(d0)) {
1590 tcp->u_rval = -1;
1591 u_error = -d0;
1592 }
1593 else {
1594 tcp->u_rval = d0;
1595 u_error = 0;
1596 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001597# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001598 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1599 tcp->u_rval = -1;
1600 u_error = -regs.ARM_r0;
1601 }
1602 else {
1603 tcp->u_rval = regs.ARM_r0;
1604 u_error = 0;
1605 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001606# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001607 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1608 tcp->u_rval = -1;
1609 u_error = -regs.r12;
1610 }
1611 else {
1612 tcp->u_rval = regs.r12;
1613 u_error = 0;
1614 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001615# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001616 if (check_errno && is_negated_errno(r0)) {
1617 tcp->u_rval = -1;
1618 u_error = -r0;
1619 } else {
1620 tcp->u_rval = r0;
1621 u_error = 0;
1622 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001623# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001624 if (check_errno && a3) {
1625 tcp->u_rval = -1;
1626 u_error = r0;
1627 }
1628 else {
1629 tcp->u_rval = r0;
1630 u_error = 0;
1631 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001632# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001633 if (check_errno && regs.psr & PSR_C) {
1634 tcp->u_rval = -1;
1635 u_error = regs.u_regs[U_REG_O0];
1636 }
1637 else {
1638 tcp->u_rval = regs.u_regs[U_REG_O0];
1639 u_error = 0;
1640 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001641# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001642 if (check_errno && regs.tstate & 0x1100000000UL) {
1643 tcp->u_rval = -1;
1644 u_error = regs.u_regs[U_REG_O0];
1645 }
1646 else {
1647 tcp->u_rval = regs.u_regs[U_REG_O0];
1648 u_error = 0;
1649 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001650# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001651 if (check_errno && is_negated_errno(r28)) {
1652 tcp->u_rval = -1;
1653 u_error = -r28;
1654 }
1655 else {
1656 tcp->u_rval = r28;
1657 u_error = 0;
1658 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001659# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001660 /* interpret R0 as return value or error number */
1661 if (check_errno && is_negated_errno(r0)) {
1662 tcp->u_rval = -1;
1663 u_error = -r0;
1664 }
1665 else {
1666 tcp->u_rval = r0;
1667 u_error = 0;
1668 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001669# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001670 /* interpret result as return value or error number */
1671 if (check_errno && is_negated_errno(r9)) {
1672 tcp->u_rval = -1;
1673 u_error = -r9;
1674 }
1675 else {
1676 tcp->u_rval = r9;
1677 u_error = 0;
1678 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001679# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001680 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1681 tcp->u_rval = -1;
1682 u_error = -r10;
1683 }
1684 else {
1685 tcp->u_rval = r10;
1686 u_error = 0;
1687 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001688# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001689 long rval;
1690 /* interpret result as return value or error number */
1691 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1692 return -1;
1693 if (check_errno && rval < 0 && rval > -nerrnos) {
1694 tcp->u_rval = -1;
1695 u_error = -rval;
1696 }
1697 else {
1698 tcp->u_rval = rval;
1699 u_error = 0;
1700 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001701# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001702 /* interpret result as return value or error number */
1703 if (check_errno && is_negated_errno(r3)) {
1704 tcp->u_rval = -1;
1705 u_error = -r3;
1706 }
1707 else {
1708 tcp->u_rval = r3;
1709 u_error = 0;
1710 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001711# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712#endif /* LINUX */
1713#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001714 /* get error code from user struct */
1715 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1716 return -1;
1717 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001719 /* get system call return value */
1720 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1721 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001722#endif /* SUNOS4 */
1723#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001724# ifdef SPARC
1725 /* Judicious guessing goes a long way. */
1726 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1727 tcp->u_rval = -1;
1728 u_error = tcp->status.pr_reg[R_O0];
1729 }
1730 else {
1731 tcp->u_rval = tcp->status.pr_reg[R_O0];
1732 u_error = 0;
1733 }
1734# endif /* SPARC */
1735# ifdef I386
1736 /* Wanna know how to kill an hour single-stepping? */
1737 if (tcp->status.PR_REG[EFL] & 0x1) {
1738 tcp->u_rval = -1;
1739 u_error = tcp->status.PR_REG[EAX];
1740 }
1741 else {
1742 tcp->u_rval = tcp->status.PR_REG[EAX];
1743# ifdef HAVE_LONG_LONG
1744 tcp->u_lrval =
1745 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1746 tcp->status.PR_REG[EAX];
1747# endif
1748 u_error = 0;
1749 }
1750# endif /* I386 */
1751# ifdef X86_64
1752 /* Wanna know how to kill an hour single-stepping? */
1753 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1754 tcp->u_rval = -1;
1755 u_error = tcp->status.PR_REG[RAX];
1756 }
1757 else {
1758 tcp->u_rval = tcp->status.PR_REG[RAX];
1759 u_error = 0;
1760 }
1761# endif /* X86_64 */
1762# ifdef MIPS
1763 if (tcp->status.pr_reg[CTX_A3]) {
1764 tcp->u_rval = -1;
1765 u_error = tcp->status.pr_reg[CTX_V0];
1766 }
1767 else {
1768 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1769 u_error = 0;
1770 }
1771# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001772#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001773#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001774 if (regs.r_eflags & PSL_C) {
1775 tcp->u_rval = -1;
1776 u_error = regs.r_eax;
1777 } else {
1778 tcp->u_rval = regs.r_eax;
1779 tcp->u_lrval =
1780 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1781 u_error = 0;
1782 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001783#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001784 tcp->u_error = u_error;
1785 return 1;
1786}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001787
Roland McGrathb69f81b2002-12-21 23:25:18 +00001788int
Denys Vlasenko12014262011-05-30 14:00:14 +02001789force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001790{
1791#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001792# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001793 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001794 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1795 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001796# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001797 eax = error ? -error : rval;
1798 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1799 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001800# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001801 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001802 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001803 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001804# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001805 if (ia32) {
1806 r8 = error ? -error : rval;
1807 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1808 return -1;
1809 }
1810 else {
1811 if (error) {
1812 r8 = error;
1813 r10 = -1;
1814 }
1815 else {
1816 r8 = rval;
1817 r10 = 0;
1818 }
1819 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1820 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1821 return -1;
1822 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001823# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001824 r0 = error ? -error : rval;
1825 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1826 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001827# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001828 if (error) {
1829 r2 = error;
1830 a3 = -1;
1831 }
1832 else {
1833 r2 = rval;
1834 a3 = 0;
1835 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001836 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001837 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1838 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001839 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001840# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001841 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001842 return -1;
1843 if (error) {
1844 flags |= SO_MASK;
1845 result = error;
1846 }
1847 else {
1848 flags &= ~SO_MASK;
1849 result = rval;
1850 }
Roland McGratheb285352003-01-14 09:59:00 +00001851 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1852 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001853 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001854# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001855 d0 = error ? -error : rval;
1856 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1857 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001858# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001859 regs.ARM_r0 = error ? -error : rval;
1860 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001861 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001862# elif defined(AVR32)
1863 regs.r12 = error ? -error : rval;
1864 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1865 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001866# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001867 if (error) {
1868 a3 = -1;
1869 r0 = error;
1870 }
1871 else {
1872 a3 = 0;
1873 r0 = rval;
1874 }
1875 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1876 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1877 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001878# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001879 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1880 return -1;
1881 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001882 regs.psr |= PSR_C;
1883 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001884 }
1885 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001886 regs.psr &= ~PSR_C;
1887 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001888 }
1889 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1890 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001891# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001892 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1893 return -1;
1894 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001895 regs.tstate |= 0x1100000000UL;
1896 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001897 }
1898 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001899 regs.tstate &= ~0x1100000000UL;
1900 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001901 }
1902 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1903 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001904# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001905 r28 = error ? -error : rval;
1906 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1907 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001908# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001909 r0 = error ? -error : rval;
1910 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1911 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001912# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001913 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001914 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1915 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001916# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001917#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001918
Roland McGrathb69f81b2002-12-21 23:25:18 +00001919#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001920 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1921 error << 24) < 0 ||
1922 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001923 return -1;
1924#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001925
Roland McGrathb69f81b2002-12-21 23:25:18 +00001926#ifdef SVR4
1927 /* XXX no clue */
1928 return -1;
1929#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001930
Roland McGrathb69f81b2002-12-21 23:25:18 +00001931#ifdef FREEBSD
1932 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001933 perror("pread");
1934 return -1;
1935 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001936 if (error) {
1937 regs.r_eflags |= PSL_C;
1938 regs.r_eax = error;
1939 }
1940 else {
1941 regs.r_eflags &= ~PSL_C;
1942 regs.r_eax = rval;
1943 }
1944 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001945 perror("pwrite");
1946 return -1;
1947 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001948#endif /* FREEBSD */
1949
1950 /* All branches reach here on success (only). */
1951 tcp->u_error = error;
1952 tcp->u_rval = rval;
1953 return 0;
1954}
1955
Roland McGratha4d48532005-06-08 20:45:28 +00001956static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001957syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001958{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001959#ifdef LINUX
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001960# if defined(S390) || defined(S390X)
1961 int i;
1962 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1963 tcp->u_nargs = sysent[tcp->scno].nargs;
1964 else
1965 tcp->u_nargs = MAX_ARGS;
1966 for (i = 0; i < tcp->u_nargs; i++) {
1967 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1968 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001969 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001970# elif defined(ALPHA)
1971 int i;
1972 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1973 tcp->u_nargs = sysent[tcp->scno].nargs;
1974 else
1975 tcp->u_nargs = MAX_ARGS;
1976 for (i = 0; i < tcp->u_nargs; i++) {
1977 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1978 * for scno somewhere above here!
1979 */
1980 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1981 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001982 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001983# elif defined(IA64)
1984 if (!ia32) {
1985 unsigned long *out0, cfm, sof, sol, i;
1986 long rbs_end;
1987 /* be backwards compatible with kernel < 2.4.4... */
1988# ifndef PT_RBS_END
1989# define PT_RBS_END PT_AR_BSP
1990# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001991
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001992 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1993 return -1;
1994 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001995 return -1;
1996
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001997 sof = (cfm >> 0) & 0x7f;
1998 sol = (cfm >> 7) & 0x7f;
1999 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
2000
2001 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2002 && sysent[tcp->scno].nargs != -1)
2003 tcp->u_nargs = sysent[tcp->scno].nargs;
2004 else
2005 tcp->u_nargs = MAX_ARGS;
2006 for (i = 0; i < tcp->u_nargs; ++i) {
2007 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2008 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2009 return -1;
2010 }
2011 } else {
2012 int i;
2013
2014 if (/* EBX = out0 */
2015 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
2016 /* ECX = out1 */
2017 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
2018 /* EDX = out2 */
2019 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
2020 /* ESI = out3 */
2021 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
2022 /* EDI = out4 */
2023 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
2024 /* EBP = out5 */
2025 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2026 return -1;
2027
2028 for (i = 0; i < 6; ++i)
2029 /* truncate away IVE sign-extension */
2030 tcp->u_arg[i] &= 0xffffffff;
2031
2032 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2033 && sysent[tcp->scno].nargs != -1)
2034 tcp->u_nargs = sysent[tcp->scno].nargs;
2035 else
2036 tcp->u_nargs = 5;
2037 }
2038# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2039 /* N32 and N64 both use up to six registers. */
2040 unsigned long long regs[38];
2041 int i, nargs;
2042 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2043 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2044 else
2045 nargs = tcp->u_nargs = MAX_ARGS;
2046
2047 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2048 return -1;
2049
2050 for (i = 0; i < nargs; i++) {
2051 tcp->u_arg[i] = regs[REG_A0 + i];
2052# if defined(LINUX_MIPSN32)
2053 tcp->ext_arg[i] = regs[REG_A0 + i];
2054# endif
2055 }
2056# elif defined(MIPS)
2057 long sp;
2058 int i, nargs;
2059
2060 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2061 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2062 else
2063 nargs = tcp->u_nargs = MAX_ARGS;
2064 if (nargs > 4) {
2065 if (upeek(tcp, REG_SP, &sp) < 0)
2066 return -1;
2067 for (i = 0; i < 4; i++) {
2068 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2069 return -1;
2070 }
2071 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2072 (char *)(tcp->u_arg + 4));
2073 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002074 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002075 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002076 return -1;
2077 }
2078 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002079# elif defined(POWERPC)
2080# ifndef PT_ORIG_R3
2081# define PT_ORIG_R3 34
2082# endif
2083 int i;
2084 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2085 tcp->u_nargs = sysent[tcp->scno].nargs;
2086 else
2087 tcp->u_nargs = MAX_ARGS;
2088 for (i = 0; i < tcp->u_nargs; i++) {
2089 if (upeek(tcp, (i==0) ?
2090 (sizeof(unsigned long) * PT_ORIG_R3) :
2091 ((i+PT_R3) * sizeof(unsigned long)),
2092 &tcp->u_arg[i]) < 0)
2093 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002094 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002095# elif defined(SPARC) || defined(SPARC64)
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 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2103# elif defined(HPPA)
2104 int i;
2105 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2106 tcp->u_nargs = sysent[tcp->scno].nargs;
2107 else
2108 tcp->u_nargs = MAX_ARGS;
2109 for (i = 0; i < tcp->u_nargs; i++) {
2110 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2111 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002112 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002113# elif defined(ARM)
2114 int i;
2115 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2116 tcp->u_nargs = sysent[tcp->scno].nargs;
2117 else
2118 tcp->u_nargs = MAX_ARGS;
2119 for (i = 0; i < tcp->u_nargs; i++)
2120 tcp->u_arg[i] = regs.uregs[i];
2121# elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002122 tcp->u_nargs = sysent[tcp->scno].nargs;
2123 tcp->u_arg[0] = regs.r12;
2124 tcp->u_arg[1] = regs.r11;
2125 tcp->u_arg[2] = regs.r10;
2126 tcp->u_arg[3] = regs.r9;
2127 tcp->u_arg[4] = regs.r5;
2128 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002129# elif defined(BFIN)
2130 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002131 static const int argreg[] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002132
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002133 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002134 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002135 else
2136 tcp->u_nargs = ARRAY_SIZE(argreg);
2137
2138 for (i = 0; i < tcp->u_nargs; ++i)
2139 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2140 return -1;
2141# elif defined(SH)
2142 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002143 static const int syscall_regs[] = {
2144 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6), 4 * (REG_REG0+7),
2145 4 * (REG_REG0 ), 4 * (REG_REG0+1), 4 * (REG_REG0+2)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002146 };
2147
2148 tcp->u_nargs = sysent[tcp->scno].nargs;
2149 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002150 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002151 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002152 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002153# elif defined(SH64)
2154 int i;
2155 /* Registers used by SH5 Linux system calls for parameters */
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002156 static const int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002157
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002158 /*
2159 * TODO: should also check that the number of arguments encoded
2160 * in the trap number matches the number strace expects.
2161 */
2162 /*
2163 assert(sysent[tcp->scno].nargs < ARRAY_SIZE(syscall_regs));
2164 */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002165
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002166 tcp->u_nargs = sysent[tcp->scno].nargs;
2167 for (i = 0; i < tcp->u_nargs; i++) {
2168 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2169 return -1;
2170 }
2171# elif defined(X86_64)
2172 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002173 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2174 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2175 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002176 };
2177
2178 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002179 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002180 else
2181 tcp->u_nargs = MAX_ARGS;
2182 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002183 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002184 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00002185 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002186# elif defined(MICROBLAZE)
2187 int i;
2188 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2189 tcp->u_nargs = sysent[tcp->scno].nargs;
2190 else
2191 tcp->u_nargs = 0;
2192 for (i = 0; i < tcp->u_nargs; i++) {
2193 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2194 return -1;
2195 }
2196# elif defined(CRISV10) || defined(CRISV32)
2197 int i;
2198 static const int crisregs[] = {
2199 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002200 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002201 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002202
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002203 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2204 tcp->u_nargs = sysent[tcp->scno].nargs;
2205 else
2206 tcp->u_nargs = 0;
2207 for (i = 0; i < tcp->u_nargs; i++) {
2208 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2209 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00002210 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002211# elif defined(TILE)
2212 int i;
2213 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2214 tcp->u_nargs = sysent[tcp->scno].nargs;
2215 else
2216 tcp->u_nargs = MAX_ARGS;
2217 for (i = 0; i < tcp->u_nargs; ++i) {
2218 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2219 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002220 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002221# elif defined(M68K)
2222 int i;
2223 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2224 tcp->u_nargs = sysent[tcp->scno].nargs;
2225 else
2226 tcp->u_nargs = MAX_ARGS;
2227 for (i = 0; i < tcp->u_nargs; i++) {
2228 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2229 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002230 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002231# else /* Other architecture (like i386) (32bits specific) */
2232 int i;
2233 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2234 tcp->u_nargs = sysent[tcp->scno].nargs;
2235 else
2236 tcp->u_nargs = MAX_ARGS;
2237 for (i = 0; i < tcp->u_nargs; i++) {
2238 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2239 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05002240 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002241# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002242#endif /* LINUX */
2243#ifdef SUNOS4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002244 int i;
2245 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2246 tcp->u_nargs = sysent[tcp->scno].nargs;
2247 else
2248 tcp->u_nargs = MAX_ARGS;
2249 for (i = 0; i < tcp->u_nargs; i++) {
2250 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002251
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002252 if (upeek(tcp, uoff(u_arg[0]) +
2253 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2254 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002255 }
2256#endif /* SUNOS4 */
2257#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002258# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259 /*
2260 * SGI is broken: even though it has pr_sysarg, it doesn't
2261 * set them on system call entry. Get a clue.
2262 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002263 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002264 tcp->u_nargs = sysent[tcp->scno].nargs;
2265 else
2266 tcp->u_nargs = tcp->status.pr_nsysarg;
2267 if (tcp->u_nargs > 4) {
2268 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002269 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002270 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002271 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002272 }
2273 else {
2274 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002275 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002276 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002277# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002278 /*
2279 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2280 */
2281 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2282 tcp->u_nargs = sysent[tcp->scno].nargs;
2283 else
2284 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2285 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002286 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2287# elif defined(HAVE_PR_SYSCALL)
2288 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002289 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002290 tcp->u_nargs = sysent[tcp->scno].nargs;
2291 else
2292 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002293 for (i = 0; i < tcp->u_nargs; i++)
2294 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2295# elif defined(I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002296 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002297 tcp->u_nargs = sysent[tcp->scno].nargs;
2298 else
2299 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002300 if (tcp->u_nargs > 0)
2301 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002302 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2303# else
John Hughes25299712001-03-06 10:10:06 +00002304 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002305# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002306#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002307#ifdef FREEBSD
2308 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2309 sysent[tcp->scno].nargs > tcp->status.val)
2310 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002311 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002312 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002313 if (tcp->u_nargs < 0)
2314 tcp->u_nargs = 0;
2315 if (tcp->u_nargs > MAX_ARGS)
2316 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002317 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002318 case SYS___syscall:
2319 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2320 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002321 break;
2322 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002323 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2324 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002325 break;
2326 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002327 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2328 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002329 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002330 }
2331#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002332 return 1;
2333}
2334
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002335static int
2336trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002337{
2338 int sys_res;
2339 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002340 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002341 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002342
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002343 /* Measure the exit time as early as possible to avoid errors. */
2344 if (dtime || cflag)
2345 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002346
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002347 /* BTW, why we don't just memorize syscall no. on entry
2348 * in tcp->something?
2349 */
2350 scno_good = res = get_scno(tcp);
2351 if (res == 0)
2352 return res;
2353 if (res == 1)
2354 res = syscall_fixup(tcp);
2355 if (res == 0)
2356 return res;
2357 if (res == 1)
2358 res = get_error(tcp);
2359 if (res == 0)
2360 return res;
2361 if (res == 1)
2362 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002363
Grant Edwards8a082772011-04-07 20:25:40 +00002364 if (res == 1 && filtered(tcp)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002365 tcp->flags &= ~TCB_INSYSCALL;
2366 return 0;
2367 }
2368
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002369 if (tcp->flags & TCB_REPRINT) {
2370 printleader(tcp);
2371 tprintf("<... ");
2372 if (scno_good != 1)
2373 tprintf("????");
2374 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2375 tprintf("syscall_%lu", tcp->scno);
2376 else
2377 tprintf("%s", sysent[tcp->scno].sys_name);
2378 tprintf(" resumed> ");
2379 }
2380
2381 if (cflag) {
2382 struct timeval t = tv;
2383 int rc = count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002384 if (cflag == CFLAG_ONLY_STATS) {
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002385 tcp->flags &= ~TCB_INSYSCALL;
2386 return rc;
2387 }
2388 }
2389
2390 if (res != 1) {
2391 tprintf(") ");
2392 tabto(acolumn);
2393 tprintf("= ? <unavailable>");
2394 printtrailer();
2395 tcp->flags &= ~TCB_INSYSCALL;
2396 return res;
2397 }
2398
2399 if (tcp->scno >= nsyscalls || tcp->scno < 0
2400 || (qual_flags[tcp->scno] & QUAL_RAW))
2401 sys_res = printargs(tcp);
2402 else {
2403 if (not_failing_only && tcp->u_error)
2404 return 0; /* ignore failed syscalls */
2405 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2406 }
2407
2408 u_error = tcp->u_error;
2409 tprintf(") ");
2410 tabto(acolumn);
2411 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2412 qual_flags[tcp->scno] & QUAL_RAW) {
2413 if (u_error)
2414 tprintf("= -1 (errno %ld)", u_error);
2415 else
2416 tprintf("= %#lx", tcp->u_rval);
2417 }
2418 else if (!(sys_res & RVAL_NONE) && u_error) {
2419 switch (u_error) {
2420#ifdef LINUX
2421 case ERESTARTSYS:
2422 tprintf("= ? ERESTARTSYS (To be restarted)");
2423 break;
2424 case ERESTARTNOINTR:
2425 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2426 break;
2427 case ERESTARTNOHAND:
2428 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2429 break;
2430 case ERESTART_RESTARTBLOCK:
2431 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2432 break;
2433#endif /* LINUX */
2434 default:
2435 tprintf("= -1 ");
2436 if (u_error < 0)
2437 tprintf("E??? (errno %ld)", u_error);
2438 else if (u_error < nerrnos)
2439 tprintf("%s (%s)", errnoent[u_error],
2440 strerror(u_error));
2441 else
2442 tprintf("ERRNO_%ld (%s)", u_error,
2443 strerror(u_error));
2444 break;
2445 }
2446 if ((sys_res & RVAL_STR) && tcp->auxstr)
2447 tprintf(" (%s)", tcp->auxstr);
2448 }
2449 else {
2450 if (sys_res & RVAL_NONE)
2451 tprintf("= ?");
2452 else {
2453 switch (sys_res & RVAL_MASK) {
2454 case RVAL_HEX:
2455 tprintf("= %#lx", tcp->u_rval);
2456 break;
2457 case RVAL_OCTAL:
2458 tprintf("= %#lo", tcp->u_rval);
2459 break;
2460 case RVAL_UDECIMAL:
2461 tprintf("= %lu", tcp->u_rval);
2462 break;
2463 case RVAL_DECIMAL:
2464 tprintf("= %ld", tcp->u_rval);
2465 break;
2466#ifdef HAVE_LONG_LONG
2467 case RVAL_LHEX:
2468 tprintf("= %#llx", tcp->u_lrval);
2469 break;
2470 case RVAL_LOCTAL:
2471 tprintf("= %#llo", tcp->u_lrval);
2472 break;
2473 case RVAL_LUDECIMAL:
2474 tprintf("= %llu", tcp->u_lrval);
2475 break;
2476 case RVAL_LDECIMAL:
2477 tprintf("= %lld", tcp->u_lrval);
2478 break;
2479#endif
2480 default:
2481 fprintf(stderr,
2482 "invalid rval format\n");
2483 break;
2484 }
2485 }
2486 if ((sys_res & RVAL_STR) && tcp->auxstr)
2487 tprintf(" (%s)", tcp->auxstr);
2488 }
2489 if (dtime) {
2490 tv_sub(&tv, &tv, &tcp->etime);
2491 tprintf(" <%ld.%06ld>",
2492 (long) tv.tv_sec, (long) tv.tv_usec);
2493 }
2494 printtrailer();
2495
2496 dumpio(tcp);
2497 if (fflush(tcp->outf) == EOF)
2498 return -1;
2499 tcp->flags &= ~TCB_INSYSCALL;
2500 return 0;
2501}
2502
2503static int
2504trace_syscall_entering(struct tcb *tcp)
2505{
2506 int sys_res;
2507 int res, scno_good;
2508
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002509 scno_good = res = get_scno(tcp);
2510 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002511 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002512 if (res == 1)
2513 res = syscall_fixup(tcp);
2514 if (res == 0)
2515 return res;
2516 if (res == 1)
2517 res = syscall_enter(tcp);
2518 if (res == 0)
2519 return res;
2520
2521 if (res != 1) {
2522 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002523 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002524 tcp_last = tcp;
2525 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002526 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002527 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2528 tprintf("syscall_%lu(", tcp->scno);
2529 else
2530 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002531 /*
2532 * " <unavailable>" will be added later by the code which
2533 * detects ptrace errors.
2534 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002535 tcp->flags |= TCB_INSYSCALL;
2536 return res;
2537 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002538
Roland McGrath17352792005-06-07 23:21:26 +00002539 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002540#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002541 case SYS_socketcall:
2542 decode_subcall(tcp, SYS_socket_subcall,
2543 SYS_socket_nsubcalls, deref_style);
2544 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002545#endif
2546#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002547 case SYS_ipc:
2548 decode_subcall(tcp, SYS_ipc_subcall,
2549 SYS_ipc_nsubcalls, shift_style);
2550 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002551#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002552#ifdef SVR4
2553#ifdef SYS_pgrpsys_subcall
2554 case SYS_pgrpsys:
2555 decode_subcall(tcp, SYS_pgrpsys_subcall,
2556 SYS_pgrpsys_nsubcalls, shift_style);
2557 break;
2558#endif /* SYS_pgrpsys_subcall */
2559#ifdef SYS_sigcall_subcall
2560 case SYS_sigcall:
2561 decode_subcall(tcp, SYS_sigcall_subcall,
2562 SYS_sigcall_nsubcalls, mask_style);
2563 break;
2564#endif /* SYS_sigcall_subcall */
2565 case SYS_msgsys:
2566 decode_subcall(tcp, SYS_msgsys_subcall,
2567 SYS_msgsys_nsubcalls, shift_style);
2568 break;
2569 case SYS_shmsys:
2570 decode_subcall(tcp, SYS_shmsys_subcall,
2571 SYS_shmsys_nsubcalls, shift_style);
2572 break;
2573 case SYS_semsys:
2574 decode_subcall(tcp, SYS_semsys_subcall,
2575 SYS_semsys_nsubcalls, shift_style);
2576 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002577 case SYS_sysfs:
2578 decode_subcall(tcp, SYS_sysfs_subcall,
2579 SYS_sysfs_nsubcalls, shift_style);
2580 break;
2581 case SYS_spcall:
2582 decode_subcall(tcp, SYS_spcall_subcall,
2583 SYS_spcall_nsubcalls, shift_style);
2584 break;
2585#ifdef SYS_context_subcall
2586 case SYS_context:
2587 decode_subcall(tcp, SYS_context_subcall,
2588 SYS_context_nsubcalls, shift_style);
2589 break;
2590#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002591#ifdef SYS_door_subcall
2592 case SYS_door:
2593 decode_subcall(tcp, SYS_door_subcall,
2594 SYS_door_nsubcalls, door_style);
2595 break;
2596#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002597#ifdef SYS_kaio_subcall
2598 case SYS_kaio:
2599 decode_subcall(tcp, SYS_kaio_subcall,
2600 SYS_kaio_nsubcalls, shift_style);
2601 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002602#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002603#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002604#ifdef FREEBSD
2605 case SYS_msgsys:
2606 case SYS_shmsys:
2607 case SYS_semsys:
2608 decode_subcall(tcp, 0, 0, table_style);
2609 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002610#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002611#ifdef SUNOS4
2612 case SYS_semsys:
2613 decode_subcall(tcp, SYS_semsys_subcall,
2614 SYS_semsys_nsubcalls, shift_style);
2615 break;
2616 case SYS_msgsys:
2617 decode_subcall(tcp, SYS_msgsys_subcall,
2618 SYS_msgsys_nsubcalls, shift_style);
2619 break;
2620 case SYS_shmsys:
2621 decode_subcall(tcp, SYS_shmsys_subcall,
2622 SYS_shmsys_nsubcalls, shift_style);
2623 break;
2624#endif
2625 }
2626
2627 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002628
2629 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2630 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2631 (tracing_paths && !pathtrace_match(tcp))) {
2632 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002633 return 0;
2634 }
2635
Grant Edwards8a082772011-04-07 20:25:40 +00002636 tcp->flags &= ~TCB_FILTERED;
2637
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002638 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002639 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002640 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002641 return 0;
2642 }
2643
2644 printleader(tcp);
2645 tcp->flags &= ~TCB_REPRINT;
2646 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002647 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002648 tprintf("syscall_%lu(", tcp->scno);
2649 else
2650 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002651 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002652 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2653 sysent[tcp->scno].sys_func != sys_exit))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002654 sys_res = printargs(tcp);
2655 else
2656 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2657 if (fflush(tcp->outf) == EOF)
2658 return -1;
2659 tcp->flags |= TCB_INSYSCALL;
2660 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002661 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002662 gettimeofday(&tcp->etime, NULL);
2663 return sys_res;
2664}
2665
2666int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002667trace_syscall(struct tcb *tcp)
2668{
2669 return exiting(tcp) ?
2670 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2671}
2672
2673int
Denys Vlasenko12014262011-05-30 14:00:14 +02002674printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002675{
2676 if (entering(tcp)) {
2677 int i;
2678
2679 for (i = 0; i < tcp->u_nargs; i++)
2680 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2681 }
2682 return 0;
2683}
2684
2685long
Denys Vlasenko12014262011-05-30 14:00:14 +02002686getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002687{
2688 long val = -1;
2689
2690#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002691#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002692 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002693 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002695 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002696#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002697 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002698 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002699#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002700 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002701 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002702#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002703#endif /* LINUX */
2704
2705#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002706 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002707 return -1;
2708#endif /* SUNOS4 */
2709
2710#ifdef SVR4
2711#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002712 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713#endif /* SPARC */
2714#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002715 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002716#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002717#ifdef X86_64
2718 val = tcp->status.PR_REG[RDX];
2719#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002720#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002721 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002722#endif /* MIPS */
2723#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002724
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002725#ifdef FREEBSD
2726 struct reg regs;
2727 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2728 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002729#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002730 return val;
2731}
2732
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002733#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002734/*
2735 * Apparently, indirect system calls have already be converted by ptrace(2),
2736 * so if you see "indir" this program has gone astray.
2737 */
2738int
Denys Vlasenko12014262011-05-30 14:00:14 +02002739sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002740{
2741 int i, scno, nargs;
2742
2743 if (entering(tcp)) {
2744 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2745 fprintf(stderr, "Bogus syscall: %u\n", scno);
2746 return 0;
2747 }
2748 nargs = sysent[scno].nargs;
2749 tprintf("%s", sysent[scno].sys_name);
2750 for (i = 0; i < nargs; i++)
2751 tprintf(", %#lx", tcp->u_arg[i+1]);
2752 }
2753 return 0;
2754}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002755#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002756
2757int
2758is_restart_error(struct tcb *tcp)
2759{
2760#ifdef LINUX
2761 if (!syserror(tcp))
2762 return 0;
2763 switch (tcp->u_error) {
2764 case ERESTARTSYS:
2765 case ERESTARTNOINTR:
2766 case ERESTARTNOHAND:
2767 case ERESTART_RESTARTBLOCK:
2768 return 1;
2769 default:
2770 break;
2771 }
2772#endif /* LINUX */
2773 return 0;
2774}