blob: ed7c4b4427d8e7e0a412fec50ceae9c4d6d43ad1 [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)) {
831 static int currpers = -1;
832 long val;
833 int pid = tcp->pid;
834
835 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200836 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200837 return -1;
838 /* SF is bit 0 of MSR */
839 if (val < 0)
840 currpers = 0;
841 else
842 currpers = 1;
843 if (currpers != current_personality) {
844 static const char *const names[] = {"64 bit", "32 bit"};
845 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000846 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200847 pid, names[current_personality]);
848 }
849 }
850# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000851# elif defined(AVR32)
852 /*
853 * Read complete register set in one go.
854 */
855 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
856 return -1;
857
858 /*
859 * We only need to grab the syscall number on syscall entry.
860 */
861 if (!(tcp->flags & TCB_INSYSCALL)) {
862 scno = regs.r8;
863
864 /* Check if we return from execve. */
865 if (tcp->flags & TCB_WAITEXECVE) {
866 tcp->flags &= ~TCB_WAITEXECVE;
867 return 0;
868 }
869 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000870# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000871 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000872 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000873# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000874 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000875 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000876# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000877 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000878 return -1;
879
Roland McGrath761b5d72002-12-15 23:58:31 +0000880 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000881 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000882 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000883 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000884
885 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200886 * 0x33 for long mode (64 bit)
887 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000888 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000889 * to be cached.
890 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000891 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000892 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000893 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000894 case 0x23: currpers = 1; break;
895 case 0x33: currpers = 0; break;
896 default:
897 fprintf(stderr, "Unknown value CS=0x%02X while "
898 "detecting personality of process "
899 "PID=%d\n", (int)val, pid);
900 currpers = current_personality;
901 break;
902 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000903# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000904 /* This version analyzes the opcode of a syscall instruction.
905 * (int 0x80 on i386 vs. syscall on x86-64)
906 * It works, but is too complicated.
907 */
908 unsigned long val, rip, i;
909
Denys Vlasenko8236f252009-01-02 18:10:08 +0000910 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000911 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000912
Michal Ludvig0e035502002-09-23 15:41:01 +0000913 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000914 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000915 errno = 0;
916
Denys Vlasenko8236f252009-01-02 18:10:08 +0000917 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000918 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000919 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000920 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000921 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000922 /* x86-64: syscall = 0x0f 0x05 */
923 case 0x050f: currpers = 0; break;
924 /* i386: int 0x80 = 0xcd 0x80 */
925 case 0x80cd: currpers = 1; break;
926 default:
927 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000928 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000929 "Unknown syscall opcode (0x%04X) while "
930 "detecting personality of process "
931 "PID=%d\n", (int)call, pid);
932 break;
933 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000934# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000935 if (currpers != current_personality) {
936 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000937 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000938 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000939 pid, names[current_personality]);
940 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000941 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000942# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000943# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200944 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000945 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000946 if (!(tcp->flags & TCB_INSYSCALL)) {
947 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000948 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000949 return -1;
950 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200951 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000952 return -1;
953 }
Roland McGrathba954762003-03-05 06:29:06 +0000954 /* Check if we return from execve. */
955 if (tcp->flags & TCB_WAITEXECVE) {
956 tcp->flags &= ~TCB_WAITEXECVE;
957 return 0;
958 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000959 } else {
960 /* syscall in progress */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200961 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000962 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200963 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000964 return -1;
965 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000966# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000967 /*
968 * Read complete register set in one go.
969 */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000970 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000971 return -1;
972
973 /*
974 * We only need to grab the syscall number on syscall entry.
975 */
976 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +0000977 if (!(tcp->flags & TCB_INSYSCALL)) {
978 /* Check if we return from execve. */
979 if (tcp->flags & TCB_WAITEXECVE) {
980 tcp->flags &= ~TCB_WAITEXECVE;
981 return 0;
982 }
983 }
984
Roland McGrath0f87c492003-06-03 23:29:04 +0000985 /*
986 * Note: we only deal with only 32-bit CPUs here.
987 */
988 if (regs.ARM_cpsr & 0x20) {
989 /*
990 * Get the Thumb-mode system call number
991 */
992 scno = regs.ARM_r7;
993 } else {
994 /*
995 * Get the ARM-mode system call number
996 */
997 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000998 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +0000999 if (errno)
1000 return -1;
1001
1002 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1003 tcp->flags &= ~TCB_WAITEXECVE;
1004 return 0;
1005 }
1006
Roland McGrathf691bd22006-04-25 07:34:41 +00001007 /* Handle the EABI syscall convention. We do not
1008 bother converting structures between the two
1009 ABIs, but basic functionality should work even
1010 if strace and the traced program have different
1011 ABIs. */
1012 if (scno == 0xef000000) {
1013 scno = regs.ARM_r7;
1014 } else {
1015 if ((scno & 0x0ff00000) != 0x0f900000) {
1016 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1017 scno);
1018 return -1;
1019 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001020
Roland McGrathf691bd22006-04-25 07:34:41 +00001021 /*
1022 * Fixup the syscall number
1023 */
1024 scno &= 0x000fffff;
1025 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001026 }
Roland McGrath56703312008-05-20 01:35:55 +00001027 if (scno & 0x0f0000) {
1028 /*
1029 * Handle ARM specific syscall
1030 */
1031 set_personality(1);
1032 scno &= 0x0000ffff;
1033 } else
1034 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001035
1036 if (tcp->flags & TCB_INSYSCALL) {
1037 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1038 tcp->flags &= ~TCB_INSYSCALL;
1039 }
1040 } else {
1041 if (!(tcp->flags & TCB_INSYSCALL)) {
1042 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1043 tcp->flags |= TCB_INSYSCALL;
1044 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001045 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001046# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001047 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001049# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001050 unsigned long long regs[38];
1051
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001052 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001053 return -1;
1054 a3 = regs[REG_A3];
1055 r2 = regs[REG_V0];
1056
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001057 if (!(tcp->flags & TCB_INSYSCALL)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001058 scno = r2;
1059
1060 /* Check if we return from execve. */
1061 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1062 tcp->flags &= ~TCB_WAITEXECVE;
1063 return 0;
1064 }
1065
1066 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001067 if (a3 == 0 || a3 == -1) {
1068 if (debug)
1069 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001070 return 0;
1071 }
1072 }
1073 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001074# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001075 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001076 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001077 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001078 if (upeek(tcp, REG_V0, &scno) < 0)
1079 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001080
Roland McGrath542c2c62008-05-20 01:11:56 +00001081 /* Check if we return from execve. */
1082 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1083 tcp->flags &= ~TCB_WAITEXECVE;
1084 return 0;
1085 }
1086
Wichert Akkermanf90da011999-10-31 21:15:38 +00001087 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001088 if (a3 == 0 || a3 == -1) {
1089 if (debug)
1090 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001091 return 0;
1092 }
1093 }
1094 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001095 if (upeek(tcp, REG_V0, &r2) < 0)
1096 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001097 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001098# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001099 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100 return -1;
1101
1102 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001103 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001104 return -1;
1105
1106 /* Check if we return from execve. */
1107 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1108 tcp->flags &= ~TCB_WAITEXECVE;
1109 return 0;
1110 }
1111
1112 /*
1113 * Do some sanity checks to figure out if it's
1114 * really a syscall entry
1115 */
1116 if (scno < 0 || scno > nsyscalls) {
1117 if (a3 == 0 || a3 == -1) {
1118 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001119 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 return 0;
1121 }
1122 }
1123 }
1124 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001125 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126 return -1;
1127 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001128# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001130 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 return -1;
1132
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001133 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134 if (!(tcp->flags & TCB_INSYSCALL)) {
1135 /* Retrieve the syscall trap instruction. */
1136 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001137# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001138 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001139 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001140# else
1141 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001142# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143 if (errno)
1144 return -1;
1145
1146 /* Disassemble the trap to see what personality to use. */
1147 switch (trap) {
1148 case 0x91d02010:
1149 /* Linux/SPARC syscall trap. */
1150 set_personality(0);
1151 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001152 case 0x91d0206d:
1153 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001154 set_personality(2);
1155 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001156 case 0x91d02000:
1157 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001158 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159 return -1;
1160 case 0x91d02008:
1161 /* Solaris 2.x syscall trap. (per 2) */
1162 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001163 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 case 0x91d02009:
1165 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001166 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167 return -1;
1168 case 0x91d02027:
1169 /* Solaris 2.x gettimeofday */
1170 set_personality(1);
1171 break;
1172 default:
1173 /* Unknown syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001174 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175 tcp->flags &= ~TCB_WAITEXECVE;
1176 return 0;
1177 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001178# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001179 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001180# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001181 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001182# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183 return -1;
1184 }
1185
1186 /* Extract the system call number from the registers. */
1187 if (trap == 0x91d02027)
1188 scno = 156;
1189 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001190 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001192 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001193 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 +00001194 }
1195 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001196# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001197 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001198 return -1;
1199 if (!(tcp->flags & TCB_INSYSCALL)) {
1200 /* Check if we return from execve. */
1201 if ((tcp->flags & TCB_WAITEXECVE)) {
1202 tcp->flags &= ~TCB_WAITEXECVE;
1203 return 0;
1204 }
1205 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001206# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001207 /*
1208 * In the new syscall ABI, the system call number is in R3.
1209 */
1210 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1211 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001212
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001213 if (scno < 0) {
1214 /* Odd as it may seem, a glibc bug has been known to cause
1215 glibc to issue bogus negative syscall numbers. So for
1216 our purposes, make strace print what it *should* have been */
1217 long correct_scno = (scno & 0xff);
1218 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001219 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001220 "Detected glibc bug: bogus system call"
1221 " number = %ld, correcting to %ld\n",
1222 scno,
1223 correct_scno);
1224 scno = correct_scno;
1225 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001226
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001227 if (!(tcp->flags & TCB_INSYSCALL)) {
1228 /* Check if we return from execve. */
1229 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1230 tcp->flags &= ~TCB_WAITEXECVE;
1231 return 0;
1232 }
1233 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001234# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001235 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001236 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001237 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001238
1239 if (!(tcp->flags & TCB_INSYSCALL)) {
1240 /* Check if we return from execve. */
1241 if (tcp->flags & TCB_WAITEXECVE) {
1242 tcp->flags &= ~TCB_WAITEXECVE;
1243 return 0;
1244 }
1245 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001246# elif defined(CRISV10) || defined(CRISV32)
1247 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1248 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001249# elif defined(TILE)
1250 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1251 return -1;
1252
1253 if (!(tcp->flags & TCB_INSYSCALL)) {
1254 /* Check if we return from execve. */
1255 if (tcp->flags & TCB_WAITEXECVE) {
1256 tcp->flags &= ~TCB_WAITEXECVE;
1257 return 0;
1258 }
1259 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001260# elif defined(MICROBLAZE)
1261 if (upeek(tcp, 0, &scno) < 0)
1262 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001263# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001264#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001265
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001267 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001269#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001270 /* new syscall ABI returns result in R0 */
1271 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1272 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001273#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001274 /* ABI defines result returned in r9 */
1275 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1276 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001277#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001278
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001279#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001280# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001281 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001282# else
1283# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001284 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001285# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001286 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001287 perror("pread");
1288 return -1;
1289 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001290 switch (regs.r_eax) {
1291 case SYS_syscall:
1292 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001293 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1294 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001295 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001296 scno = regs.r_eax;
1297 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001298 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001299# endif /* FREEBSD */
1300# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001301#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001302
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001303 if (!(tcp->flags & TCB_INSYSCALL))
1304 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001305 return 1;
1306}
1307
Pavel Machek4dc3b142000-02-01 17:58:41 +00001308
Roland McGrath17352792005-06-07 23:21:26 +00001309long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001310known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001311{
1312 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001313#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001314 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1315 scno = sysent[scno].native_scno;
1316 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001317#endif
Roland McGrath17352792005-06-07 23:21:26 +00001318 scno += NR_SYSCALL_BASE;
1319 return scno;
1320}
1321
Roland McGratheb9e2e82009-06-02 16:49:22 -07001322/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001323 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001324 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1325 * 1: ok, continue in trace_syscall().
1326 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001327 * ("????" etc) and bail out.
1328 */
Roland McGratha4d48532005-06-08 20:45:28 +00001329static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001330syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001331{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001332#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001333 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001334
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001336 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001337 if (
1338 scno == SYS_fork
1339#ifdef SYS_vfork
1340 || scno == SYS_vfork
1341#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001342#ifdef SYS_fork1
1343 || scno == SYS_fork1
1344#endif /* SYS_fork1 */
1345#ifdef SYS_forkall
1346 || scno == SYS_forkall
1347#endif /* SYS_forkall */
1348#ifdef SYS_rfork1
1349 || scno == SYS_rfork1
1350#endif /* SYS_fork1 */
1351#ifdef SYS_rforkall
1352 || scno == SYS_rforkall
1353#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354 ) {
1355 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001356 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001358 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359 }
1360 else {
1361 fprintf(stderr, "syscall: missing entry\n");
1362 tcp->flags |= TCB_INSYSCALL;
1363 }
1364 }
1365 }
1366 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001367 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 fprintf(stderr, "syscall: missing exit\n");
1369 tcp->flags &= ~TCB_INSYSCALL;
1370 }
1371 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001372#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373#ifdef SUNOS4
1374 if (!(tcp->flags & TCB_INSYSCALL)) {
1375 if (scno == 0) {
1376 fprintf(stderr, "syscall: missing entry\n");
1377 tcp->flags |= TCB_INSYSCALL;
1378 }
1379 }
1380 else {
1381 if (scno != 0) {
1382 if (debug) {
1383 /*
1384 * This happens when a signal handler
1385 * for a signal which interrupted a
1386 * a system call makes another system call.
1387 */
1388 fprintf(stderr, "syscall: missing exit\n");
1389 }
1390 tcp->flags &= ~TCB_INSYSCALL;
1391 }
1392 }
1393#endif /* SUNOS4 */
1394#ifdef LINUX
1395#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001396 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001397 return -1;
1398 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1399 if (debug)
1400 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1401 return 0;
1402 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001403#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001404 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001405 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001406 if (current_personality == 1)
1407 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001408 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1409 if (debug)
1410 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1411 return 0;
1412 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001413#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001414 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001415 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001416 if (syscall_mode != -ENOSYS)
1417 syscall_mode = tcp->scno;
1418 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001419 if (debug)
1420 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1421 return 0;
1422 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001423 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1424 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1425 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1426 /*
1427 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1428 * flag set for the post-execve SIGTRAP to see and reset.
1429 */
1430 gpr2 = 0;
1431 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001432#elif defined (POWERPC)
1433# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001434 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001436 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001437 return -1;
1438 if (flags & SO_MASK)
1439 result = -result;
1440#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001441 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001442 return -1;
1443 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1444 if (debug)
1445 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1446 return 0;
1447 }
1448#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001449 /*
1450 * Nothing required
1451 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001452#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001453 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001454 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001455#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001456 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001457 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001458#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001459 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001460 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001461 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001462 return -1;
1463 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1464 if (debug)
1465 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1466 return 0;
1467 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001468#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001469 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001470 return -1;
1471 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1472 if (debug)
1473 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1474 return 0;
1475 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001476#elif defined(MICROBLAZE)
1477 if (upeek(tcp, 3 * 4, &r3) < 0)
1478 return -1;
1479 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1480 if (debug)
1481 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1482 return 0;
1483 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001484#endif
1485#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001486 return 1;
1487}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001488
Roland McGrathc1e45922008-05-27 23:18:29 +00001489#ifdef LINUX
1490/*
1491 * Check the syscall return value register value for whether it is
1492 * a negated errno code indicating an error, or a success return value.
1493 */
1494static inline int
1495is_negated_errno(unsigned long int val)
1496{
1497 unsigned long int max = -(long int) nerrnos;
1498 if (personality_wordsize[current_personality] < sizeof(val)) {
1499 val = (unsigned int) val;
1500 max = (unsigned int) max;
1501 }
1502 return val > max;
1503}
1504#endif
1505
Roland McGratha4d48532005-06-08 20:45:28 +00001506static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001507get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001508{
1509 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001510#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001511 int check_errno = 1;
1512 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1513 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1514 check_errno = 0;
1515 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001516# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001517 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001518 tcp->u_rval = -1;
1519 u_error = -gpr2;
1520 }
1521 else {
1522 tcp->u_rval = gpr2;
1523 u_error = 0;
1524 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001525# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001526 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001527 tcp->u_rval = -1;
1528 u_error = -eax;
1529 }
1530 else {
1531 tcp->u_rval = eax;
1532 u_error = 0;
1533 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001534# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001535 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001536 tcp->u_rval = -1;
1537 u_error = -rax;
1538 }
1539 else {
1540 tcp->u_rval = rax;
1541 u_error = 0;
1542 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001543# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001544 if (ia32) {
1545 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001546
Roland McGrathc1e45922008-05-27 23:18:29 +00001547 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001548 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001549 tcp->u_rval = -1;
1550 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001551 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001552 else {
1553 tcp->u_rval = err;
1554 u_error = 0;
1555 }
1556 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001557 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001558 tcp->u_rval = -1;
1559 u_error = r8;
1560 } else {
1561 tcp->u_rval = r8;
1562 u_error = 0;
1563 }
1564 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001565# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001566 if (check_errno && a3) {
1567 tcp->u_rval = -1;
1568 u_error = r2;
1569 } else {
1570 tcp->u_rval = r2;
1571 u_error = 0;
1572 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001573# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001574 if (check_errno && is_negated_errno(result)) {
1575 tcp->u_rval = -1;
1576 u_error = -result;
1577 }
1578 else {
1579 tcp->u_rval = result;
1580 u_error = 0;
1581 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001582# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001583 if (check_errno && is_negated_errno(d0)) {
1584 tcp->u_rval = -1;
1585 u_error = -d0;
1586 }
1587 else {
1588 tcp->u_rval = d0;
1589 u_error = 0;
1590 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001591# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001592 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1593 tcp->u_rval = -1;
1594 u_error = -regs.ARM_r0;
1595 }
1596 else {
1597 tcp->u_rval = regs.ARM_r0;
1598 u_error = 0;
1599 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001600# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001601 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1602 tcp->u_rval = -1;
1603 u_error = -regs.r12;
1604 }
1605 else {
1606 tcp->u_rval = regs.r12;
1607 u_error = 0;
1608 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001609# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001610 if (check_errno && is_negated_errno(r0)) {
1611 tcp->u_rval = -1;
1612 u_error = -r0;
1613 } else {
1614 tcp->u_rval = r0;
1615 u_error = 0;
1616 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001617# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001618 if (check_errno && a3) {
1619 tcp->u_rval = -1;
1620 u_error = r0;
1621 }
1622 else {
1623 tcp->u_rval = r0;
1624 u_error = 0;
1625 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001626# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001627 if (check_errno && regs.psr & PSR_C) {
1628 tcp->u_rval = -1;
1629 u_error = regs.u_regs[U_REG_O0];
1630 }
1631 else {
1632 tcp->u_rval = regs.u_regs[U_REG_O0];
1633 u_error = 0;
1634 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001635# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001636 if (check_errno && regs.tstate & 0x1100000000UL) {
1637 tcp->u_rval = -1;
1638 u_error = regs.u_regs[U_REG_O0];
1639 }
1640 else {
1641 tcp->u_rval = regs.u_regs[U_REG_O0];
1642 u_error = 0;
1643 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001644# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001645 if (check_errno && is_negated_errno(r28)) {
1646 tcp->u_rval = -1;
1647 u_error = -r28;
1648 }
1649 else {
1650 tcp->u_rval = r28;
1651 u_error = 0;
1652 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001653# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001654 /* interpret R0 as return value or error number */
1655 if (check_errno && is_negated_errno(r0)) {
1656 tcp->u_rval = -1;
1657 u_error = -r0;
1658 }
1659 else {
1660 tcp->u_rval = r0;
1661 u_error = 0;
1662 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001663# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001664 /* interpret result as return value or error number */
1665 if (check_errno && is_negated_errno(r9)) {
1666 tcp->u_rval = -1;
1667 u_error = -r9;
1668 }
1669 else {
1670 tcp->u_rval = r9;
1671 u_error = 0;
1672 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001673# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001674 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1675 tcp->u_rval = -1;
1676 u_error = -r10;
1677 }
1678 else {
1679 tcp->u_rval = r10;
1680 u_error = 0;
1681 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001682# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001683 long rval;
1684 /* interpret result as return value or error number */
1685 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1686 return -1;
1687 if (check_errno && rval < 0 && rval > -nerrnos) {
1688 tcp->u_rval = -1;
1689 u_error = -rval;
1690 }
1691 else {
1692 tcp->u_rval = rval;
1693 u_error = 0;
1694 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001695# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001696 /* interpret result as return value or error number */
1697 if (check_errno && is_negated_errno(r3)) {
1698 tcp->u_rval = -1;
1699 u_error = -r3;
1700 }
1701 else {
1702 tcp->u_rval = r3;
1703 u_error = 0;
1704 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001705# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706#endif /* LINUX */
1707#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001708 /* get error code from user struct */
1709 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1710 return -1;
1711 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001713 /* get system call return value */
1714 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1715 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716#endif /* SUNOS4 */
1717#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001718# ifdef SPARC
1719 /* Judicious guessing goes a long way. */
1720 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1721 tcp->u_rval = -1;
1722 u_error = tcp->status.pr_reg[R_O0];
1723 }
1724 else {
1725 tcp->u_rval = tcp->status.pr_reg[R_O0];
1726 u_error = 0;
1727 }
1728# endif /* SPARC */
1729# ifdef I386
1730 /* Wanna know how to kill an hour single-stepping? */
1731 if (tcp->status.PR_REG[EFL] & 0x1) {
1732 tcp->u_rval = -1;
1733 u_error = tcp->status.PR_REG[EAX];
1734 }
1735 else {
1736 tcp->u_rval = tcp->status.PR_REG[EAX];
1737# ifdef HAVE_LONG_LONG
1738 tcp->u_lrval =
1739 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1740 tcp->status.PR_REG[EAX];
1741# endif
1742 u_error = 0;
1743 }
1744# endif /* I386 */
1745# ifdef X86_64
1746 /* Wanna know how to kill an hour single-stepping? */
1747 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1748 tcp->u_rval = -1;
1749 u_error = tcp->status.PR_REG[RAX];
1750 }
1751 else {
1752 tcp->u_rval = tcp->status.PR_REG[RAX];
1753 u_error = 0;
1754 }
1755# endif /* X86_64 */
1756# ifdef MIPS
1757 if (tcp->status.pr_reg[CTX_A3]) {
1758 tcp->u_rval = -1;
1759 u_error = tcp->status.pr_reg[CTX_V0];
1760 }
1761 else {
1762 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1763 u_error = 0;
1764 }
1765# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001766#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001767#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001768 if (regs.r_eflags & PSL_C) {
1769 tcp->u_rval = -1;
1770 u_error = regs.r_eax;
1771 } else {
1772 tcp->u_rval = regs.r_eax;
1773 tcp->u_lrval =
1774 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1775 u_error = 0;
1776 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001777#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001778 tcp->u_error = u_error;
1779 return 1;
1780}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001781
Roland McGrathb69f81b2002-12-21 23:25:18 +00001782int
Denys Vlasenko12014262011-05-30 14:00:14 +02001783force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001784{
1785#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001786# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001787 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001788 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1789 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001790# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001791 eax = error ? -error : rval;
1792 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1793 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001794# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001795 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001796 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001797 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001798# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001799 if (ia32) {
1800 r8 = error ? -error : rval;
1801 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1802 return -1;
1803 }
1804 else {
1805 if (error) {
1806 r8 = error;
1807 r10 = -1;
1808 }
1809 else {
1810 r8 = rval;
1811 r10 = 0;
1812 }
1813 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1814 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1815 return -1;
1816 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001817# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001818 r0 = error ? -error : rval;
1819 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1820 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001821# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001822 if (error) {
1823 r2 = error;
1824 a3 = -1;
1825 }
1826 else {
1827 r2 = rval;
1828 a3 = 0;
1829 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001830 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001831 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1832 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001833 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001834# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001835 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001836 return -1;
1837 if (error) {
1838 flags |= SO_MASK;
1839 result = error;
1840 }
1841 else {
1842 flags &= ~SO_MASK;
1843 result = rval;
1844 }
Roland McGratheb285352003-01-14 09:59:00 +00001845 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1846 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001847 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001848# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001849 d0 = error ? -error : rval;
1850 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1851 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001852# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001853 regs.ARM_r0 = error ? -error : rval;
1854 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001855 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001856# elif defined(AVR32)
1857 regs.r12 = error ? -error : rval;
1858 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1859 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001860# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001861 if (error) {
1862 a3 = -1;
1863 r0 = error;
1864 }
1865 else {
1866 a3 = 0;
1867 r0 = rval;
1868 }
1869 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1870 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1871 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001872# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001873 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1874 return -1;
1875 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001876 regs.psr |= PSR_C;
1877 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001878 }
1879 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001880 regs.psr &= ~PSR_C;
1881 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001882 }
1883 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1884 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001885# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001886 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1887 return -1;
1888 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001889 regs.tstate |= 0x1100000000UL;
1890 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001891 }
1892 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001893 regs.tstate &= ~0x1100000000UL;
1894 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001895 }
1896 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1897 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001898# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001899 r28 = error ? -error : rval;
1900 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1901 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001902# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001903 r0 = error ? -error : rval;
1904 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1905 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001906# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001907 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001908 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1909 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001910# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001911#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001912
Roland McGrathb69f81b2002-12-21 23:25:18 +00001913#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001914 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1915 error << 24) < 0 ||
1916 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001917 return -1;
1918#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001919
Roland McGrathb69f81b2002-12-21 23:25:18 +00001920#ifdef SVR4
1921 /* XXX no clue */
1922 return -1;
1923#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001924
Roland McGrathb69f81b2002-12-21 23:25:18 +00001925#ifdef FREEBSD
1926 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001927 perror("pread");
1928 return -1;
1929 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001930 if (error) {
1931 regs.r_eflags |= PSL_C;
1932 regs.r_eax = error;
1933 }
1934 else {
1935 regs.r_eflags &= ~PSL_C;
1936 regs.r_eax = rval;
1937 }
1938 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001939 perror("pwrite");
1940 return -1;
1941 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001942#endif /* FREEBSD */
1943
1944 /* All branches reach here on success (only). */
1945 tcp->u_error = error;
1946 tcp->u_rval = rval;
1947 return 0;
1948}
1949
Roland McGratha4d48532005-06-08 20:45:28 +00001950static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001951syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001952{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001953#ifdef LINUX
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001954# if defined(S390) || defined(S390X)
1955 int i;
1956 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1957 tcp->u_nargs = sysent[tcp->scno].nargs;
1958 else
1959 tcp->u_nargs = MAX_ARGS;
1960 for (i = 0; i < tcp->u_nargs; i++) {
1961 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1962 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001963 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001964# elif defined(ALPHA)
1965 int i;
1966 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1967 tcp->u_nargs = sysent[tcp->scno].nargs;
1968 else
1969 tcp->u_nargs = MAX_ARGS;
1970 for (i = 0; i < tcp->u_nargs; i++) {
1971 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1972 * for scno somewhere above here!
1973 */
1974 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1975 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001976 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001977# elif defined(IA64)
1978 if (!ia32) {
1979 unsigned long *out0, cfm, sof, sol, i;
1980 long rbs_end;
1981 /* be backwards compatible with kernel < 2.4.4... */
1982# ifndef PT_RBS_END
1983# define PT_RBS_END PT_AR_BSP
1984# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001985
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001986 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1987 return -1;
1988 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001989 return -1;
1990
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001991 sof = (cfm >> 0) & 0x7f;
1992 sol = (cfm >> 7) & 0x7f;
1993 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1994
1995 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1996 && sysent[tcp->scno].nargs != -1)
1997 tcp->u_nargs = sysent[tcp->scno].nargs;
1998 else
1999 tcp->u_nargs = MAX_ARGS;
2000 for (i = 0; i < tcp->u_nargs; ++i) {
2001 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2002 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2003 return -1;
2004 }
2005 } else {
2006 int i;
2007
2008 if (/* EBX = out0 */
2009 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
2010 /* ECX = out1 */
2011 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
2012 /* EDX = out2 */
2013 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
2014 /* ESI = out3 */
2015 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
2016 /* EDI = out4 */
2017 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
2018 /* EBP = out5 */
2019 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2020 return -1;
2021
2022 for (i = 0; i < 6; ++i)
2023 /* truncate away IVE sign-extension */
2024 tcp->u_arg[i] &= 0xffffffff;
2025
2026 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2027 && sysent[tcp->scno].nargs != -1)
2028 tcp->u_nargs = sysent[tcp->scno].nargs;
2029 else
2030 tcp->u_nargs = 5;
2031 }
2032# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2033 /* N32 and N64 both use up to six registers. */
2034 unsigned long long regs[38];
2035 int i, nargs;
2036 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2037 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2038 else
2039 nargs = tcp->u_nargs = MAX_ARGS;
2040
2041 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2042 return -1;
2043
2044 for (i = 0; i < nargs; i++) {
2045 tcp->u_arg[i] = regs[REG_A0 + i];
2046# if defined(LINUX_MIPSN32)
2047 tcp->ext_arg[i] = regs[REG_A0 + i];
2048# endif
2049 }
2050# elif defined(MIPS)
2051 long sp;
2052 int i, nargs;
2053
2054 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2055 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2056 else
2057 nargs = tcp->u_nargs = MAX_ARGS;
2058 if (nargs > 4) {
2059 if (upeek(tcp, REG_SP, &sp) < 0)
2060 return -1;
2061 for (i = 0; i < 4; i++) {
2062 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2063 return -1;
2064 }
2065 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2066 (char *)(tcp->u_arg + 4));
2067 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002068 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002069 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002070 return -1;
2071 }
2072 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002073# elif defined(POWERPC)
2074# ifndef PT_ORIG_R3
2075# define PT_ORIG_R3 34
2076# endif
2077 int i;
2078 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2079 tcp->u_nargs = sysent[tcp->scno].nargs;
2080 else
2081 tcp->u_nargs = MAX_ARGS;
2082 for (i = 0; i < tcp->u_nargs; i++) {
2083 if (upeek(tcp, (i==0) ?
2084 (sizeof(unsigned long) * PT_ORIG_R3) :
2085 ((i+PT_R3) * sizeof(unsigned long)),
2086 &tcp->u_arg[i]) < 0)
2087 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002088 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002089# elif defined(SPARC) || defined(SPARC64)
2090 int i;
2091 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2092 tcp->u_nargs = sysent[tcp->scno].nargs;
2093 else
2094 tcp->u_nargs = MAX_ARGS;
2095 for (i = 0; i < tcp->u_nargs; i++)
2096 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2097# elif defined(HPPA)
2098 int i;
2099 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2100 tcp->u_nargs = sysent[tcp->scno].nargs;
2101 else
2102 tcp->u_nargs = MAX_ARGS;
2103 for (i = 0; i < tcp->u_nargs; i++) {
2104 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2105 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002106 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002107# elif defined(ARM)
2108 int i;
2109 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2110 tcp->u_nargs = sysent[tcp->scno].nargs;
2111 else
2112 tcp->u_nargs = MAX_ARGS;
2113 for (i = 0; i < tcp->u_nargs; i++)
2114 tcp->u_arg[i] = regs.uregs[i];
2115# elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002116 tcp->u_nargs = sysent[tcp->scno].nargs;
2117 tcp->u_arg[0] = regs.r12;
2118 tcp->u_arg[1] = regs.r11;
2119 tcp->u_arg[2] = regs.r10;
2120 tcp->u_arg[3] = regs.r9;
2121 tcp->u_arg[4] = regs.r5;
2122 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002123# elif defined(BFIN)
2124 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002125 static const int argreg[] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002126
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002127 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002128 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002129 else
2130 tcp->u_nargs = ARRAY_SIZE(argreg);
2131
2132 for (i = 0; i < tcp->u_nargs; ++i)
2133 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2134 return -1;
2135# elif defined(SH)
2136 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002137 static const int syscall_regs[] = {
2138 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6), 4 * (REG_REG0+7),
2139 4 * (REG_REG0 ), 4 * (REG_REG0+1), 4 * (REG_REG0+2)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002140 };
2141
2142 tcp->u_nargs = sysent[tcp->scno].nargs;
2143 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002144 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002145 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002146 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002147# elif defined(SH64)
2148 int i;
2149 /* Registers used by SH5 Linux system calls for parameters */
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002150 static const int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002151
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002152 /*
2153 * TODO: should also check that the number of arguments encoded
2154 * in the trap number matches the number strace expects.
2155 */
2156 /*
2157 assert(sysent[tcp->scno].nargs < ARRAY_SIZE(syscall_regs));
2158 */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002159
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002160 tcp->u_nargs = sysent[tcp->scno].nargs;
2161 for (i = 0; i < tcp->u_nargs; i++) {
2162 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2163 return -1;
2164 }
2165# elif defined(X86_64)
2166 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002167 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2168 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2169 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002170 };
2171
2172 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002173 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002174 else
2175 tcp->u_nargs = MAX_ARGS;
2176 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002177 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002178 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00002179 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002180# elif defined(MICROBLAZE)
2181 int i;
2182 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2183 tcp->u_nargs = sysent[tcp->scno].nargs;
2184 else
2185 tcp->u_nargs = 0;
2186 for (i = 0; i < tcp->u_nargs; i++) {
2187 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2188 return -1;
2189 }
2190# elif defined(CRISV10) || defined(CRISV32)
2191 int i;
2192 static const int crisregs[] = {
2193 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002194 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002195 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002196
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002197 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2198 tcp->u_nargs = sysent[tcp->scno].nargs;
2199 else
2200 tcp->u_nargs = 0;
2201 for (i = 0; i < tcp->u_nargs; i++) {
2202 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2203 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00002204 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002205# elif defined(TILE)
2206 int i;
2207 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2208 tcp->u_nargs = sysent[tcp->scno].nargs;
2209 else
2210 tcp->u_nargs = MAX_ARGS;
2211 for (i = 0; i < tcp->u_nargs; ++i) {
2212 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2213 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002214 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002215# elif defined(M68K)
2216 int i;
2217 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2218 tcp->u_nargs = sysent[tcp->scno].nargs;
2219 else
2220 tcp->u_nargs = MAX_ARGS;
2221 for (i = 0; i < tcp->u_nargs; i++) {
2222 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2223 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002224 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002225# else /* Other architecture (like i386) (32bits specific) */
2226 int i;
2227 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2228 tcp->u_nargs = sysent[tcp->scno].nargs;
2229 else
2230 tcp->u_nargs = MAX_ARGS;
2231 for (i = 0; i < tcp->u_nargs; i++) {
2232 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2233 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05002234 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002235# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002236#endif /* LINUX */
2237#ifdef SUNOS4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002238 int i;
2239 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2240 tcp->u_nargs = sysent[tcp->scno].nargs;
2241 else
2242 tcp->u_nargs = MAX_ARGS;
2243 for (i = 0; i < tcp->u_nargs; i++) {
2244 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002245
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002246 if (upeek(tcp, uoff(u_arg[0]) +
2247 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2248 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002249 }
2250#endif /* SUNOS4 */
2251#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002252# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253 /*
2254 * SGI is broken: even though it has pr_sysarg, it doesn't
2255 * set them on system call entry. Get a clue.
2256 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002257 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002258 tcp->u_nargs = sysent[tcp->scno].nargs;
2259 else
2260 tcp->u_nargs = tcp->status.pr_nsysarg;
2261 if (tcp->u_nargs > 4) {
2262 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002263 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002264 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002265 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002266 }
2267 else {
2268 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002269 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002270 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002271# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002272 /*
2273 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2274 */
2275 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2276 tcp->u_nargs = sysent[tcp->scno].nargs;
2277 else
2278 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2279 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002280 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2281# elif defined(HAVE_PR_SYSCALL)
2282 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002283 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002284 tcp->u_nargs = sysent[tcp->scno].nargs;
2285 else
2286 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002287 for (i = 0; i < tcp->u_nargs; i++)
2288 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2289# elif defined(I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002290 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002291 tcp->u_nargs = sysent[tcp->scno].nargs;
2292 else
2293 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002294 if (tcp->u_nargs > 0)
2295 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002296 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2297# else
John Hughes25299712001-03-06 10:10:06 +00002298 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002299# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002300#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002301#ifdef FREEBSD
2302 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2303 sysent[tcp->scno].nargs > tcp->status.val)
2304 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002305 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002306 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002307 if (tcp->u_nargs < 0)
2308 tcp->u_nargs = 0;
2309 if (tcp->u_nargs > MAX_ARGS)
2310 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002311 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002312 case SYS___syscall:
2313 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2314 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002315 break;
2316 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002317 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2318 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002319 break;
2320 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002321 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2322 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002323 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002324 }
2325#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002326 return 1;
2327}
2328
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002329static int
2330trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002331{
2332 int sys_res;
2333 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002334 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002335 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002336
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002337 /* Measure the exit time as early as possible to avoid errors. */
2338 if (dtime || cflag)
2339 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002340
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002341 /* BTW, why we don't just memorize syscall no. on entry
2342 * in tcp->something?
2343 */
2344 scno_good = res = get_scno(tcp);
2345 if (res == 0)
2346 return res;
2347 if (res == 1)
2348 res = syscall_fixup(tcp);
2349 if (res == 0)
2350 return res;
2351 if (res == 1)
2352 res = get_error(tcp);
2353 if (res == 0)
2354 return res;
2355 if (res == 1)
2356 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002357
Grant Edwards8a082772011-04-07 20:25:40 +00002358 if (res == 1 && filtered(tcp)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002359 tcp->flags &= ~TCB_INSYSCALL;
2360 return 0;
2361 }
2362
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002363 if (tcp->flags & TCB_REPRINT) {
2364 printleader(tcp);
2365 tprintf("<... ");
2366 if (scno_good != 1)
2367 tprintf("????");
2368 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2369 tprintf("syscall_%lu", tcp->scno);
2370 else
2371 tprintf("%s", sysent[tcp->scno].sys_name);
2372 tprintf(" resumed> ");
2373 }
2374
2375 if (cflag) {
2376 struct timeval t = tv;
2377 int rc = count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002378 if (cflag == CFLAG_ONLY_STATS) {
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002379 tcp->flags &= ~TCB_INSYSCALL;
2380 return rc;
2381 }
2382 }
2383
2384 if (res != 1) {
2385 tprintf(") ");
2386 tabto(acolumn);
2387 tprintf("= ? <unavailable>");
2388 printtrailer();
2389 tcp->flags &= ~TCB_INSYSCALL;
2390 return res;
2391 }
2392
2393 if (tcp->scno >= nsyscalls || tcp->scno < 0
2394 || (qual_flags[tcp->scno] & QUAL_RAW))
2395 sys_res = printargs(tcp);
2396 else {
2397 if (not_failing_only && tcp->u_error)
2398 return 0; /* ignore failed syscalls */
2399 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2400 }
2401
2402 u_error = tcp->u_error;
2403 tprintf(") ");
2404 tabto(acolumn);
2405 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2406 qual_flags[tcp->scno] & QUAL_RAW) {
2407 if (u_error)
2408 tprintf("= -1 (errno %ld)", u_error);
2409 else
2410 tprintf("= %#lx", tcp->u_rval);
2411 }
2412 else if (!(sys_res & RVAL_NONE) && u_error) {
2413 switch (u_error) {
2414#ifdef LINUX
2415 case ERESTARTSYS:
2416 tprintf("= ? ERESTARTSYS (To be restarted)");
2417 break;
2418 case ERESTARTNOINTR:
2419 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2420 break;
2421 case ERESTARTNOHAND:
2422 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2423 break;
2424 case ERESTART_RESTARTBLOCK:
2425 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2426 break;
2427#endif /* LINUX */
2428 default:
2429 tprintf("= -1 ");
2430 if (u_error < 0)
2431 tprintf("E??? (errno %ld)", u_error);
2432 else if (u_error < nerrnos)
2433 tprintf("%s (%s)", errnoent[u_error],
2434 strerror(u_error));
2435 else
2436 tprintf("ERRNO_%ld (%s)", u_error,
2437 strerror(u_error));
2438 break;
2439 }
2440 if ((sys_res & RVAL_STR) && tcp->auxstr)
2441 tprintf(" (%s)", tcp->auxstr);
2442 }
2443 else {
2444 if (sys_res & RVAL_NONE)
2445 tprintf("= ?");
2446 else {
2447 switch (sys_res & RVAL_MASK) {
2448 case RVAL_HEX:
2449 tprintf("= %#lx", tcp->u_rval);
2450 break;
2451 case RVAL_OCTAL:
2452 tprintf("= %#lo", tcp->u_rval);
2453 break;
2454 case RVAL_UDECIMAL:
2455 tprintf("= %lu", tcp->u_rval);
2456 break;
2457 case RVAL_DECIMAL:
2458 tprintf("= %ld", tcp->u_rval);
2459 break;
2460#ifdef HAVE_LONG_LONG
2461 case RVAL_LHEX:
2462 tprintf("= %#llx", tcp->u_lrval);
2463 break;
2464 case RVAL_LOCTAL:
2465 tprintf("= %#llo", tcp->u_lrval);
2466 break;
2467 case RVAL_LUDECIMAL:
2468 tprintf("= %llu", tcp->u_lrval);
2469 break;
2470 case RVAL_LDECIMAL:
2471 tprintf("= %lld", tcp->u_lrval);
2472 break;
2473#endif
2474 default:
2475 fprintf(stderr,
2476 "invalid rval format\n");
2477 break;
2478 }
2479 }
2480 if ((sys_res & RVAL_STR) && tcp->auxstr)
2481 tprintf(" (%s)", tcp->auxstr);
2482 }
2483 if (dtime) {
2484 tv_sub(&tv, &tv, &tcp->etime);
2485 tprintf(" <%ld.%06ld>",
2486 (long) tv.tv_sec, (long) tv.tv_usec);
2487 }
2488 printtrailer();
2489
2490 dumpio(tcp);
2491 if (fflush(tcp->outf) == EOF)
2492 return -1;
2493 tcp->flags &= ~TCB_INSYSCALL;
2494 return 0;
2495}
2496
2497static int
2498trace_syscall_entering(struct tcb *tcp)
2499{
2500 int sys_res;
2501 int res, scno_good;
2502
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002503 scno_good = res = get_scno(tcp);
2504 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002505 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002506 if (res == 1)
2507 res = syscall_fixup(tcp);
2508 if (res == 0)
2509 return res;
2510 if (res == 1)
2511 res = syscall_enter(tcp);
2512 if (res == 0)
2513 return res;
2514
2515 if (res != 1) {
2516 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002517 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002518 tcp_last = tcp;
2519 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002520 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002521 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2522 tprintf("syscall_%lu(", tcp->scno);
2523 else
2524 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002525 /*
2526 * " <unavailable>" will be added later by the code which
2527 * detects ptrace errors.
2528 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002529 tcp->flags |= TCB_INSYSCALL;
2530 return res;
2531 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002532
Roland McGrath17352792005-06-07 23:21:26 +00002533 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002534#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002535 case SYS_socketcall:
2536 decode_subcall(tcp, SYS_socket_subcall,
2537 SYS_socket_nsubcalls, deref_style);
2538 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002539#endif
2540#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002541 case SYS_ipc:
2542 decode_subcall(tcp, SYS_ipc_subcall,
2543 SYS_ipc_nsubcalls, shift_style);
2544 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002545#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002546#ifdef SVR4
2547#ifdef SYS_pgrpsys_subcall
2548 case SYS_pgrpsys:
2549 decode_subcall(tcp, SYS_pgrpsys_subcall,
2550 SYS_pgrpsys_nsubcalls, shift_style);
2551 break;
2552#endif /* SYS_pgrpsys_subcall */
2553#ifdef SYS_sigcall_subcall
2554 case SYS_sigcall:
2555 decode_subcall(tcp, SYS_sigcall_subcall,
2556 SYS_sigcall_nsubcalls, mask_style);
2557 break;
2558#endif /* SYS_sigcall_subcall */
2559 case SYS_msgsys:
2560 decode_subcall(tcp, SYS_msgsys_subcall,
2561 SYS_msgsys_nsubcalls, shift_style);
2562 break;
2563 case SYS_shmsys:
2564 decode_subcall(tcp, SYS_shmsys_subcall,
2565 SYS_shmsys_nsubcalls, shift_style);
2566 break;
2567 case SYS_semsys:
2568 decode_subcall(tcp, SYS_semsys_subcall,
2569 SYS_semsys_nsubcalls, shift_style);
2570 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002571 case SYS_sysfs:
2572 decode_subcall(tcp, SYS_sysfs_subcall,
2573 SYS_sysfs_nsubcalls, shift_style);
2574 break;
2575 case SYS_spcall:
2576 decode_subcall(tcp, SYS_spcall_subcall,
2577 SYS_spcall_nsubcalls, shift_style);
2578 break;
2579#ifdef SYS_context_subcall
2580 case SYS_context:
2581 decode_subcall(tcp, SYS_context_subcall,
2582 SYS_context_nsubcalls, shift_style);
2583 break;
2584#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002585#ifdef SYS_door_subcall
2586 case SYS_door:
2587 decode_subcall(tcp, SYS_door_subcall,
2588 SYS_door_nsubcalls, door_style);
2589 break;
2590#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002591#ifdef SYS_kaio_subcall
2592 case SYS_kaio:
2593 decode_subcall(tcp, SYS_kaio_subcall,
2594 SYS_kaio_nsubcalls, shift_style);
2595 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002596#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002597#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002598#ifdef FREEBSD
2599 case SYS_msgsys:
2600 case SYS_shmsys:
2601 case SYS_semsys:
2602 decode_subcall(tcp, 0, 0, table_style);
2603 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002604#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002605#ifdef SUNOS4
2606 case SYS_semsys:
2607 decode_subcall(tcp, SYS_semsys_subcall,
2608 SYS_semsys_nsubcalls, shift_style);
2609 break;
2610 case SYS_msgsys:
2611 decode_subcall(tcp, SYS_msgsys_subcall,
2612 SYS_msgsys_nsubcalls, shift_style);
2613 break;
2614 case SYS_shmsys:
2615 decode_subcall(tcp, SYS_shmsys_subcall,
2616 SYS_shmsys_nsubcalls, shift_style);
2617 break;
2618#endif
2619 }
2620
2621 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002622
2623 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2624 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2625 (tracing_paths && !pathtrace_match(tcp))) {
2626 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002627 return 0;
2628 }
2629
Grant Edwards8a082772011-04-07 20:25:40 +00002630 tcp->flags &= ~TCB_FILTERED;
2631
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002632 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002633 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002634 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002635 return 0;
2636 }
2637
2638 printleader(tcp);
2639 tcp->flags &= ~TCB_REPRINT;
2640 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002641 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002642 tprintf("syscall_%lu(", tcp->scno);
2643 else
2644 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002645 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002646 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2647 sysent[tcp->scno].sys_func != sys_exit))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002648 sys_res = printargs(tcp);
2649 else
2650 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2651 if (fflush(tcp->outf) == EOF)
2652 return -1;
2653 tcp->flags |= TCB_INSYSCALL;
2654 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002655 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002656 gettimeofday(&tcp->etime, NULL);
2657 return sys_res;
2658}
2659
2660int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002661trace_syscall(struct tcb *tcp)
2662{
2663 return exiting(tcp) ?
2664 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2665}
2666
2667int
Denys Vlasenko12014262011-05-30 14:00:14 +02002668printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002669{
2670 if (entering(tcp)) {
2671 int i;
2672
2673 for (i = 0; i < tcp->u_nargs; i++)
2674 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2675 }
2676 return 0;
2677}
2678
2679long
Denys Vlasenko12014262011-05-30 14:00:14 +02002680getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002681{
2682 long val = -1;
2683
2684#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002685#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002686 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002687 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002688 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002689 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002690#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002691 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002692 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002693#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002694 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002695 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002696#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002697#endif /* LINUX */
2698
2699#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002700 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002701 return -1;
2702#endif /* SUNOS4 */
2703
2704#ifdef SVR4
2705#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002706 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002707#endif /* SPARC */
2708#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002709 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002711#ifdef X86_64
2712 val = tcp->status.PR_REG[RDX];
2713#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002714#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002715 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002716#endif /* MIPS */
2717#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002718
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002719#ifdef FREEBSD
2720 struct reg regs;
2721 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2722 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002723#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002724 return val;
2725}
2726
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002727#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002728/*
2729 * Apparently, indirect system calls have already be converted by ptrace(2),
2730 * so if you see "indir" this program has gone astray.
2731 */
2732int
Denys Vlasenko12014262011-05-30 14:00:14 +02002733sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002734{
2735 int i, scno, nargs;
2736
2737 if (entering(tcp)) {
2738 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2739 fprintf(stderr, "Bogus syscall: %u\n", scno);
2740 return 0;
2741 }
2742 nargs = sysent[scno].nargs;
2743 tprintf("%s", sysent[scno].sys_name);
2744 for (i = 0; i < nargs; i++)
2745 tprintf(", %#lx", tcp->u_arg[i+1]);
2746 }
2747 return 0;
2748}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002749#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002750
2751int
2752is_restart_error(struct tcb *tcp)
2753{
2754#ifdef LINUX
2755 if (!syserror(tcp))
2756 return 0;
2757 switch (tcp->u_error) {
2758 case ERESTARTSYS:
2759 case ERESTARTNOINTR:
2760 case ERESTARTNOHAND:
2761 case ERESTART_RESTARTBLOCK:
2762 return 1;
2763 default:
2764 break;
2765 }
2766#endif /* LINUX */
2767 return 0;
2768}