blob: 7f7872c0c67a7a61248c1f7f8a52bdd7a9f6dd7f [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};
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000119
120#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000121static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#include "syscallent1.h"
123};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200124#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000125
126#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000127static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000128#include "syscallent2.h"
129};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200130#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000131
132/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000133#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134#undef TF
135#undef TI
136#undef TN
137#undef TP
138#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000139#undef NF
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140
Denys Vlasenko39fca622011-08-20 02:12:33 +0200141
142/*
143 * `ioctlent.h' may be generated from `ioctlent.raw' by the auxiliary
144 * program `ioctlsort', such that the list is sorted by the `code' field.
145 * This has the side-effect of resolving the _IO.. macros into
146 * plain integers, eliminating the need to include here everything
147 * in "/usr/include".
148 */
149
150
Roland McGrathee36ce12004-09-04 03:53:10 +0000151static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152#include "errnoent.h"
153};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200154static const char *const signalent0[] = {
155#include "signalent.h"
156};
157static const struct ioctlent ioctlent0[] = {
158#include "ioctlent.h"
159};
160enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
161enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
162enum { nsignals0 = ARRAY_SIZE(signalent0) };
163enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
164int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000165
166#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000167static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000168#include "errnoent1.h"
169};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200170static const char *const signalent1[] = {
171#include "signalent1.h"
172};
173static const struct ioctlent ioctlent1[] = {
174#include "ioctlent1.h"
175};
176enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
177enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
178enum { nsignals1 = ARRAY_SIZE(signalent1) };
179enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
180int qual_flags1[MAX_QUALS];
181#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182
183#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000184static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000185#include "errnoent2.h"
186};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200187static const char *const signalent2[] = {
188#include "signalent2.h"
189};
190static const struct ioctlent ioctlent2[] = {
191#include "ioctlent2.h"
192};
193enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
194enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
195enum { nsignals2 = ARRAY_SIZE(signalent2) };
196enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
197int qual_flags2[MAX_QUALS];
198#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199
Denys Vlasenko39fca622011-08-20 02:12:33 +0200200
201const struct sysent *sysent;
Roland McGrathee36ce12004-09-04 03:53:10 +0000202const char *const *errnoent;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200203const char *const *signalent;
204const struct ioctlent *ioctlent;
205int nsyscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000206int nerrnos;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200207int nsignals;
208int nioctlents;
209int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000210
211int current_personality;
212
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000213#ifndef PERSONALITY0_WORDSIZE
214# define PERSONALITY0_WORDSIZE sizeof(long)
215#endif
216const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
217 PERSONALITY0_WORDSIZE,
218#if SUPPORTED_PERSONALITIES > 1
219 PERSONALITY1_WORDSIZE,
220#endif
221#if SUPPORTED_PERSONALITIES > 2
222 PERSONALITY2_WORDSIZE,
223#endif
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200224};
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000225
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200226void
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000227set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000228{
229 switch (personality) {
230 case 0:
231 errnoent = errnoent0;
232 nerrnos = nerrnos0;
233 sysent = sysent0;
234 nsyscalls = nsyscalls0;
235 ioctlent = ioctlent0;
236 nioctlents = nioctlents0;
237 signalent = signalent0;
238 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000239 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 break;
241
242#if SUPPORTED_PERSONALITIES >= 2
243 case 1:
244 errnoent = errnoent1;
245 nerrnos = nerrnos1;
246 sysent = sysent1;
247 nsyscalls = nsyscalls1;
248 ioctlent = ioctlent1;
249 nioctlents = nioctlents1;
250 signalent = signalent1;
251 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000252 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200254#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255
256#if SUPPORTED_PERSONALITIES >= 3
257 case 2:
258 errnoent = errnoent2;
259 nerrnos = nerrnos2;
260 sysent = sysent2;
261 nsyscalls = nsyscalls2;
262 ioctlent = ioctlent2;
263 nioctlents = nioctlents2;
264 signalent = signalent2;
265 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000266 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000267 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200268#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000269 }
270
271 current_personality = personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000272}
273
Roland McGrathe10e62a2004-09-04 04:20:43 +0000274
Roland McGrath9797ceb2002-12-30 10:23:00 +0000275static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000276
Roland McGrathe10e62a2004-09-04 04:20:43 +0000277static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000278 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000279 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000280 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000281 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000282} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000283 { QUAL_TRACE, "trace", qual_syscall, "system call" },
284 { QUAL_TRACE, "t", qual_syscall, "system call" },
285 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
286 { QUAL_ABBREV, "a", qual_syscall, "system call" },
287 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
288 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
289 { QUAL_RAW, "raw", qual_syscall, "system call" },
290 { QUAL_RAW, "x", qual_syscall, "system call" },
291 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
292 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
293 { QUAL_SIGNAL, "s", qual_signal, "signal" },
294 { QUAL_FAULT, "fault", qual_fault, "fault" },
295 { QUAL_FAULT, "faults", qual_fault, "fault" },
296 { QUAL_FAULT, "m", qual_fault, "fault" },
297 { QUAL_READ, "read", qual_desc, "descriptor" },
298 { QUAL_READ, "reads", qual_desc, "descriptor" },
299 { QUAL_READ, "r", qual_desc, "descriptor" },
300 { QUAL_WRITE, "write", qual_desc, "descriptor" },
301 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
302 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000303 { 0, NULL, NULL, NULL },
304};
305
Roland McGrath9797ceb2002-12-30 10:23:00 +0000306static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000307qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000308{
Roland McGrath138c6a32006-01-12 09:50:49 +0000309 if (pers == 0 || pers < 0) {
310 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000311 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000312 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000313 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000314 }
315
316#if SUPPORTED_PERSONALITIES >= 2
317 if (pers == 1 || pers < 0) {
318 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000319 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000320 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000321 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000322 }
323#endif /* SUPPORTED_PERSONALITIES >= 2 */
324
325#if SUPPORTED_PERSONALITIES >= 3
326 if (pers == 2 || pers < 0) {
327 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000328 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000329 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000330 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000331 }
332#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000333}
334
335static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000336qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000337{
338 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000339 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000340
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000341 if (isdigit((unsigned char)*s)) {
342 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000343 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000344 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000345 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000346 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000347 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000348 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000349 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000350 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000351 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000352 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000353
354#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000355 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000356 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000357 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000358 rc = 0;
359 }
360#endif /* SUPPORTED_PERSONALITIES >= 2 */
361
362#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000363 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000364 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000365 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000366 rc = 0;
367 }
368#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000369
Roland McGrathfe6b3522005-02-02 04:40:11 +0000370 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000371}
372
373static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000374qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375{
376 int i;
377 char buf[32];
378
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000379 if (isdigit((unsigned char)*s)) {
380 int signo = atoi(s);
381 if (signo < 0 || signo >= MAX_QUALS)
382 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000383 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000384 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000385 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000386 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000387 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000388 strcpy(buf, s);
389 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000390 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000391 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000392 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000393 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000394 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000395 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000396 }
Roland McGrath76421df2005-02-02 03:51:18 +0000397 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000398}
399
400static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000401qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000402{
403 return -1;
404}
405
406static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000407qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000408{
Roland McGrath48a035f2006-01-12 09:45:56 +0000409 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000410 int desc = atoi(s);
411 if (desc < 0 || desc >= MAX_QUALS)
412 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000413 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000414 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415 }
416 return -1;
417}
418
419static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000420lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000421{
422 if (strcmp(s, "file") == 0)
423 return TRACE_FILE;
424 if (strcmp(s, "ipc") == 0)
425 return TRACE_IPC;
426 if (strcmp(s, "network") == 0)
427 return TRACE_NETWORK;
428 if (strcmp(s, "process") == 0)
429 return TRACE_PROCESS;
430 if (strcmp(s, "signal") == 0)
431 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000432 if (strcmp(s, "desc") == 0)
433 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000434 return -1;
435}
436
437void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000438qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000439{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000440 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000442 char *copy;
443 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000444 int i, n;
445
446 opt = &qual_options[0];
447 for (i = 0; (p = qual_options[i].option_name); i++) {
448 n = strlen(p);
449 if (strncmp(s, p, n) == 0 && s[n] == '=') {
450 opt = &qual_options[i];
451 s += n + 1;
452 break;
453 }
454 }
455 not = 0;
456 if (*s == '!') {
457 not = 1;
458 s++;
459 }
460 if (strcmp(s, "none") == 0) {
461 not = 1 - not;
462 s = "all";
463 }
464 if (strcmp(s, "all") == 0) {
465 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000466 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 }
468 return;
469 }
470 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000471 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000472 }
Denys Vlasenko5d645812011-08-20 12:48:18 +0200473 copy = strdup(s);
474 if (!copy) {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000475 fprintf(stderr, "out of memory\n");
476 exit(1);
477 }
478 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000479 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000480 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000481 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000482 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000483
484#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000485 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000486 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000487 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000488#endif /* SUPPORTED_PERSONALITIES >= 2 */
489
490#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000491 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000492 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000493 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000494#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000495
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000496 continue;
497 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000498 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000499 fprintf(stderr, "strace: invalid %s `%s'\n",
500 opt->argument_name, p);
501 exit(1);
502 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000504 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000505 return;
506}
507
508static void
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000509dumpio(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000510{
511 if (syserror(tcp))
512 return;
513 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
514 return;
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000515 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
516 return;
517 if (sysent[tcp->scno].sys_func == printargs)
518 return;
519 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
520 if (sysent[tcp->scno].sys_func == sys_read ||
521 sysent[tcp->scno].sys_func == sys_pread ||
522 sysent[tcp->scno].sys_func == sys_pread64 ||
523 sysent[tcp->scno].sys_func == sys_recv ||
524 sysent[tcp->scno].sys_func == sys_recvfrom)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000525 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000526 else if (sysent[tcp->scno].sys_func == sys_readv)
527 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
528 return;
529 }
530 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
531 if (sysent[tcp->scno].sys_func == sys_write ||
532 sysent[tcp->scno].sys_func == sys_pwrite ||
533 sysent[tcp->scno].sys_func == sys_pwrite64 ||
534 sysent[tcp->scno].sys_func == sys_send ||
535 sysent[tcp->scno].sys_func == sys_sendto)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000537 else if (sysent[tcp->scno].sys_func == sys_writev)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000538 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000539 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540 }
541}
542
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000543#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000544enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000545#else /* FREEBSD */
546enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
547
548struct subcall {
549 int call;
550 int nsubcalls;
551 int subcalls[5];
552};
553
Roland McGratha4d48532005-06-08 20:45:28 +0000554static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000555 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000556#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000557 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000558#else
559 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
560#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000561 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
562};
563#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000564
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000565#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566
Roland McGratha4d48532005-06-08 20:45:28 +0000567static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200568decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000570 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000571 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000572 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000573
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000574 switch (style) {
575 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000576 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
577 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000578 tcp->scno = subcall + tcp->u_arg[0];
579 if (sysent[tcp->scno].nargs != -1)
580 tcp->u_nargs = sysent[tcp->scno].nargs;
581 else
582 tcp->u_nargs--;
583 for (i = 0; i < tcp->u_nargs; i++)
584 tcp->u_arg[i] = tcp->u_arg[i + 1];
585 break;
586 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000587 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
588 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 tcp->scno = subcall + tcp->u_arg[0];
590 addr = tcp->u_arg[1];
591 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000592 if (size == sizeof(int)) {
593 unsigned int arg;
594 if (umove(tcp, addr, &arg) < 0)
595 arg = 0;
596 tcp->u_arg[i] = arg;
597 }
598 else if (size == sizeof(long)) {
599 unsigned long arg;
600 if (umove(tcp, addr, &arg) < 0)
601 arg = 0;
602 tcp->u_arg[i] = arg;
603 }
604 else
605 abort();
606 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 }
608 tcp->u_nargs = sysent[tcp->scno].nargs;
609 break;
610 case mask_style:
611 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 for (i = 0; mask; i++)
613 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000614 if (i >= nsubcalls)
615 return;
616 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617 tcp->scno = subcall + i;
618 if (sysent[tcp->scno].nargs != -1)
619 tcp->u_nargs = sysent[tcp->scno].nargs;
620 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000621 case door_style:
622 /*
623 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000624 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000625 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000626 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
627 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000628 tcp->scno = subcall + tcp->u_arg[5];
629 if (sysent[tcp->scno].nargs != -1)
630 tcp->u_nargs = sysent[tcp->scno].nargs;
631 else
632 tcp->u_nargs--;
633 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000634#ifdef FREEBSD
635 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000636 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000637 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000638 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000639 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
640 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
641 for (i = 0; i < tcp->u_nargs; i++)
642 tcp->u_arg[i] = tcp->u_arg[i + 1];
643 }
644 break;
645#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000646 }
647}
648#endif
649
650struct tcb *tcp_last = NULL;
651
652static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000653internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000654{
655 /*
656 * We must always trace a few critical system calls in order to
657 * correctly support following forks in the presence of tracing
658 * qualifiers.
659 */
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200660 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000662 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
663 return 0;
664
665 func = sysent[tcp->scno].sys_func;
666
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000667 if ( sys_fork == func
668#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
669 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000671#ifdef LINUX
672 || sys_clone == func
673#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000674#if UNIXWARE > 2
675 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000677 )
678 return internal_fork(tcp);
679
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200680#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000681 if ( sys_execve == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200682# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200684# endif
685# if UNIXWARE > 2
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000686 || sys_rexecve == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200687# endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000688 )
689 return internal_exec(tcp);
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200690#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000691
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000692 return 0;
693}
694
Wichert Akkermanc7926982000-04-10 22:22:31 +0000695
696#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200697# if defined (I386)
698static long eax;
699# elif defined (IA64)
700long r8, r10, psr; /* TODO: make static? */
701long ia32 = 0; /* not static */
702# elif defined (POWERPC)
703static long result, flags;
704# elif defined (M68K)
705static long d0;
706# elif defined(BFIN)
707static long r0;
708# elif defined (ARM)
709static struct pt_regs regs;
710# elif defined (ALPHA)
711static long r0;
712static long a3;
713# elif defined(AVR32)
714static struct pt_regs regs;
715# elif defined (SPARC) || defined (SPARC64)
716static struct pt_regs regs;
717static unsigned long trap;
718# elif defined(LINUX_MIPSN32)
719static long long a3;
720static long long r2;
721# elif defined(MIPS)
722static long a3;
723static long r2;
724# elif defined(S390) || defined(S390X)
725static long gpr2;
726static long pc;
727static long syscall_mode;
728# elif defined(HPPA)
729static long r28;
730# elif defined(SH)
731static long r0;
732# elif defined(SH64)
733static long r9;
734# elif defined(X86_64)
735static long rax;
736# elif defined(CRISV10) || defined(CRISV32)
737static long r10;
738# elif defined(MICROBLAZE)
739static long r3;
740# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000741#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000742#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200743struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000744#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000745
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200746/* Returns:
747 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
748 * 1: ok, continue in trace_syscall().
749 * other: error, trace_syscall() should print error indicator
750 * ("????" etc) and bail out.
751 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000752int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000753get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000754{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000755 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000756
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000758# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000759 if (tcp->flags & TCB_WAITEXECVE) {
760 /*
761 * When the execve system call completes successfully, the
762 * new process still has -ENOSYS (old style) or __NR_execve
763 * (new style) in gpr2. We cannot recover the scno again
764 * by disassembly, because the image that executed the
765 * syscall is gone now. Fortunately, we don't want it. We
766 * leave the flag set so that syscall_fixup can fake the
767 * result.
768 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200769 if (exiting(tcp))
Roland McGrath96dc5142003-01-20 10:23:04 +0000770 return 1;
771 /*
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200772 * This is the post-execve SIGTRAP. We cannot try to read
Roland McGrath96dc5142003-01-20 10:23:04 +0000773 * the system call here either.
774 */
775 tcp->flags &= ~TCB_WAITEXECVE;
776 return 0;
777 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000778
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000779 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200780 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000781
782 if (syscall_mode != -ENOSYS) {
783 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000784 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000785 */
786 scno = syscall_mode;
787 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000788 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000789 * Old style of "passing" the scno via the SVC instruction.
790 */
791
792 long opcode, offset_reg, tmp;
793 void * svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200794 static const int gpr_offset[16] = {
795 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
796 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
797 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
798 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
799 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000800
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000801 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000802 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000803 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000804 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000805 if (errno) {
806 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000807 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000808 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000809
810 /*
811 * We have to check if the SVC got executed directly or via an
812 * EXECUTE instruction. In case of EXECUTE it is necessary to do
813 * instruction decoding to derive the system call number.
814 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
815 * so that this doesn't work if a SVC opcode is part of an EXECUTE
816 * opcode. Since there is no way to find out the opcode size this
817 * is the best we can do...
818 */
819
820 if ((opcode & 0xff00) == 0x0a00) {
821 /* SVC opcode */
822 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000823 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000824 else {
825 /* SVC got executed by EXECUTE instruction */
826
827 /*
828 * Do instruction decoding of EXECUTE. If you really want to
829 * understand this, read the Principles of Operations.
830 */
831 svc_addr = (void *) (opcode & 0xfff);
832
833 tmp = 0;
834 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000835 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000836 return -1;
837 svc_addr += tmp;
838
839 tmp = 0;
840 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000841 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000842 return -1;
843 svc_addr += tmp;
844
Denys Vlasenkofb036672009-01-23 16:30:26 +0000845 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000846 if (errno)
847 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000848# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000849 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000850# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000851 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000852# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000853 tmp = 0;
854 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000855 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000856 return -1;
857
858 scno = (scno | tmp) & 0xff;
859 }
860 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000861# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000862 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000863 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200864 if (entering(tcp)) {
865 /* Check if this is the post-execve SIGTRAP. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
867 tcp->flags &= ~TCB_WAITEXECVE;
868 return 0;
869 }
870 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200871
872# ifdef POWERPC64
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200873 if (entering(tcp)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200874 /* TODO: speed up strace by not doing this at every syscall.
875 * We only need to do it after execve.
876 */
877 int currpers;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200878 long val;
879 int pid = tcp->pid;
880
881 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200882 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200883 return -1;
884 /* SF is bit 0 of MSR */
885 if (val < 0)
886 currpers = 0;
887 else
888 currpers = 1;
889 if (currpers != current_personality) {
890 static const char *const names[] = {"64 bit", "32 bit"};
891 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000892 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200893 pid, names[current_personality]);
894 }
895 }
896# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000897# elif defined(AVR32)
898 /*
899 * Read complete register set in one go.
900 */
901 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
902 return -1;
903
904 /*
905 * We only need to grab the syscall number on syscall entry.
906 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200907 if (entering(tcp)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000908 scno = regs.r8;
909
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200910 /* Check if this is the post-execve SIGTRAP. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000911 if (tcp->flags & TCB_WAITEXECVE) {
912 tcp->flags &= ~TCB_WAITEXECVE;
913 return 0;
914 }
915 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000916# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000917 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000918 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000919# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000920 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000922# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000923 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000924 return -1;
925
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200926 if (entering(tcp)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200927 /* TODO: speed up strace by not doing this at every syscall.
928 * We only need to do it after execve.
929 */
930 int currpers;
Michal Ludvig0e035502002-09-23 15:41:01 +0000931 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000932 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000933
934 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200935 * 0x33 for long mode (64 bit)
936 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000937 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000938 * to be cached.
939 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000940 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000941 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000942 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000943 case 0x23: currpers = 1; break;
944 case 0x33: currpers = 0; break;
945 default:
946 fprintf(stderr, "Unknown value CS=0x%02X while "
947 "detecting personality of process "
948 "PID=%d\n", (int)val, pid);
949 currpers = current_personality;
950 break;
951 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000952# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000953 /* This version analyzes the opcode of a syscall instruction.
954 * (int 0x80 on i386 vs. syscall on x86-64)
955 * It works, but is too complicated.
956 */
957 unsigned long val, rip, i;
958
Denys Vlasenko8236f252009-01-02 18:10:08 +0000959 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000960 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000961
Michal Ludvig0e035502002-09-23 15:41:01 +0000962 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000963 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000964 errno = 0;
965
Denys Vlasenko8236f252009-01-02 18:10:08 +0000966 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000967 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000968 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000969 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000970 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000971 /* x86-64: syscall = 0x0f 0x05 */
972 case 0x050f: currpers = 0; break;
973 /* i386: int 0x80 = 0xcd 0x80 */
974 case 0x80cd: currpers = 1; break;
975 default:
976 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000977 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000978 "Unknown syscall opcode (0x%04X) while "
979 "detecting personality of process "
980 "PID=%d\n", (int)call, pid);
981 break;
982 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000983# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000984 if (currpers != current_personality) {
985 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000986 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000987 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000988 pid, names[current_personality]);
989 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000990 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000991# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000992# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200993 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000994 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200995 if (entering(tcp)) {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000996 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000997 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000998 return -1;
999 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001000 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001001 return -1;
1002 }
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001003 /* Check if this is the post-execve SIGTRAP. */
Roland McGrathba954762003-03-05 06:29:06 +00001004 if (tcp->flags & TCB_WAITEXECVE) {
1005 tcp->flags &= ~TCB_WAITEXECVE;
1006 return 0;
1007 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001008 } else {
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001009 /* Syscall exit */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001010 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001011 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001012 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001013 return -1;
1014 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001015# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001016 /*
1017 * Read complete register set in one go.
1018 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001019 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001020 return -1;
1021
1022 /*
1023 * We only need to grab the syscall number on syscall entry.
1024 */
1025 if (regs.ARM_ip == 0) {
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001026 if (entering(tcp)) {
1027 /* Check if this is the post-execve SIGTRAP. */
Roland McGrath9bc63402007-11-01 21:42:18 +00001028 if (tcp->flags & TCB_WAITEXECVE) {
1029 tcp->flags &= ~TCB_WAITEXECVE;
1030 return 0;
1031 }
1032 }
1033
Roland McGrath0f87c492003-06-03 23:29:04 +00001034 /*
1035 * Note: we only deal with only 32-bit CPUs here.
1036 */
1037 if (regs.ARM_cpsr & 0x20) {
1038 /*
1039 * Get the Thumb-mode system call number
1040 */
1041 scno = regs.ARM_r7;
1042 } else {
1043 /*
1044 * Get the ARM-mode system call number
1045 */
1046 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001047 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001048 if (errno)
1049 return -1;
1050
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001051 /* FIXME: bogus check? it is already done on entering before,
1052 * so we never can see it here?
1053 */
Roland McGrath0f87c492003-06-03 23:29:04 +00001054 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1055 tcp->flags &= ~TCB_WAITEXECVE;
1056 return 0;
1057 }
1058
Roland McGrathf691bd22006-04-25 07:34:41 +00001059 /* Handle the EABI syscall convention. We do not
1060 bother converting structures between the two
1061 ABIs, but basic functionality should work even
1062 if strace and the traced program have different
1063 ABIs. */
1064 if (scno == 0xef000000) {
1065 scno = regs.ARM_r7;
1066 } else {
1067 if ((scno & 0x0ff00000) != 0x0f900000) {
1068 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1069 scno);
1070 return -1;
1071 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001072
Roland McGrathf691bd22006-04-25 07:34:41 +00001073 /*
1074 * Fixup the syscall number
1075 */
1076 scno &= 0x000fffff;
1077 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001078 }
Roland McGrath56703312008-05-20 01:35:55 +00001079 if (scno & 0x0f0000) {
1080 /*
1081 * Handle ARM specific syscall
1082 */
1083 set_personality(1);
1084 scno &= 0x0000ffff;
1085 } else
1086 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001087
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001088 if (exiting(tcp)) {
1089 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
Roland McGrath0f87c492003-06-03 23:29:04 +00001090 tcp->flags &= ~TCB_INSYSCALL;
1091 }
1092 } else {
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001093 if (entering(tcp)) {
1094 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
Roland McGrath0f87c492003-06-03 23:29:04 +00001095 tcp->flags |= TCB_INSYSCALL;
1096 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001097 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001098# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001099 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001101# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001102 unsigned long long regs[38];
1103
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001104 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001105 return -1;
1106 a3 = regs[REG_A3];
1107 r2 = regs[REG_V0];
1108
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001109 if (entering(tcp)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001110 scno = r2;
1111
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001112 /* Check if this is the post-execve SIGTRAP. */
Roland McGrath542c2c62008-05-20 01:11:56 +00001113 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1114 tcp->flags &= ~TCB_WAITEXECVE;
1115 return 0;
1116 }
1117
1118 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001119 if (a3 == 0 || a3 == -1) {
1120 if (debug)
1121 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001122 return 0;
1123 }
1124 }
1125 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001126# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001127 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001128 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001129 if (entering(tcp)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001130 if (upeek(tcp, REG_V0, &scno) < 0)
1131 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001132
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001133 /* Check if this is the post-execve SIGTRAP. */
Roland McGrath542c2c62008-05-20 01:11:56 +00001134 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1135 tcp->flags &= ~TCB_WAITEXECVE;
1136 return 0;
1137 }
1138
Wichert Akkermanf90da011999-10-31 21:15:38 +00001139 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001140 if (a3 == 0 || a3 == -1) {
1141 if (debug)
1142 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001143 return 0;
1144 }
1145 }
1146 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001147 if (upeek(tcp, REG_V0, &r2) < 0)
1148 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001149 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001150# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001151 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001152 return -1;
1153
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001154 if (entering(tcp)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001155 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001156 return -1;
1157
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001158 /* Check if this is the post-execve SIGTRAP. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1160 tcp->flags &= ~TCB_WAITEXECVE;
1161 return 0;
1162 }
1163
1164 /*
1165 * Do some sanity checks to figure out if it's
1166 * really a syscall entry
1167 */
1168 if (scno < 0 || scno > nsyscalls) {
1169 if (a3 == 0 || a3 == -1) {
1170 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001171 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 return 0;
1173 }
1174 }
1175 }
1176 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001177 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001178 return -1;
1179 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001180# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001182 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183 return -1;
1184
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001185 /* If we are entering, then disassemble the syscall trap. */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001186 if (entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001187 /* Retrieve the syscall trap instruction. */
1188 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001189# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001190 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001191 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001192# else
1193 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001194# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001195 if (errno)
1196 return -1;
1197
1198 /* Disassemble the trap to see what personality to use. */
1199 switch (trap) {
1200 case 0x91d02010:
1201 /* Linux/SPARC syscall trap. */
1202 set_personality(0);
1203 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001204 case 0x91d0206d:
1205 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001206 set_personality(2);
1207 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001208 case 0x91d02000:
1209 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001210 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001211 return -1;
1212 case 0x91d02008:
1213 /* Solaris 2.x syscall trap. (per 2) */
1214 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001215 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216 case 0x91d02009:
1217 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001218 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001219 return -1;
1220 case 0x91d02027:
1221 /* Solaris 2.x gettimeofday */
1222 set_personality(1);
1223 break;
1224 default:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001225 /* Check if this is the post-execve SIGTRAP. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001226 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227 tcp->flags &= ~TCB_WAITEXECVE;
1228 return 0;
1229 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001230# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001231 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001232# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001233 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001234# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 return -1;
1236 }
1237
1238 /* Extract the system call number from the registers. */
1239 if (trap == 0x91d02027)
1240 scno = 156;
1241 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001242 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001244 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001245 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 +00001246 }
1247 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001248# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001249 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001250 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001251 if (entering(tcp)) {
1252 /* Check if this is the post-execve SIGTRAP. */
1253 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001254 tcp->flags &= ~TCB_WAITEXECVE;
1255 return 0;
1256 }
1257 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001258# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001259 /*
1260 * In the new syscall ABI, the system call number is in R3.
1261 */
1262 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1263 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001264
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001265 if (scno < 0) {
1266 /* Odd as it may seem, a glibc bug has been known to cause
1267 glibc to issue bogus negative syscall numbers. So for
1268 our purposes, make strace print what it *should* have been */
1269 long correct_scno = (scno & 0xff);
1270 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001271 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001272 "Detected glibc bug: bogus system call"
1273 " number = %ld, correcting to %ld\n",
1274 scno,
1275 correct_scno);
1276 scno = correct_scno;
1277 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001278
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001279 if (entering(tcp)) {
1280 /* Check if this is the post-execve SIGTRAP. */
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001281 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1282 tcp->flags &= ~TCB_WAITEXECVE;
1283 return 0;
1284 }
1285 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001286# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001287 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001288 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001289 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001290
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001291 if (entering(tcp)) {
1292 /* Check if this is the post-execve SIGTRAP. */
Roland McGrathe1e584b2003-06-02 19:18:58 +00001293 if (tcp->flags & TCB_WAITEXECVE) {
1294 tcp->flags &= ~TCB_WAITEXECVE;
1295 return 0;
1296 }
1297 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001298# elif defined(CRISV10) || defined(CRISV32)
1299 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1300 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001301# elif defined(TILE)
1302 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1303 return -1;
1304
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001305 if (entering(tcp)) {
1306 /* Check if this is the post-execve SIGTRAP. */
Chris Metcalfc8c66982009-12-28 10:00:15 -05001307 if (tcp->flags & TCB_WAITEXECVE) {
1308 tcp->flags &= ~TCB_WAITEXECVE;
1309 return 0;
1310 }
1311 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001312# elif defined(MICROBLAZE)
1313 if (upeek(tcp, 0, &scno) < 0)
1314 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001315# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001317
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001319 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001320 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001321#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001322 /* new syscall ABI returns result in R0 */
1323 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1324 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001325#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001326 /* ABI defines result returned in r9 */
1327 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1328 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001330
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001331#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001332# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001333 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001334# else
1335# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001336 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001337# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001338 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001339 perror("pread");
1340 return -1;
1341 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001342 switch (regs.r_eax) {
1343 case SYS_syscall:
1344 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001345 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1346 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001347 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001348 scno = regs.r_eax;
1349 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001350 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001351# endif /* FREEBSD */
1352# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001353#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001354
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001355 if (entering(tcp))
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001356 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001357 return 1;
1358}
1359
Pavel Machek4dc3b142000-02-01 17:58:41 +00001360
Roland McGrath17352792005-06-07 23:21:26 +00001361long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001362known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001363{
1364 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001365#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001366 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1367 scno = sysent[scno].native_scno;
1368 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001369#endif
Roland McGrath17352792005-06-07 23:21:26 +00001370 scno += NR_SYSCALL_BASE;
1371 return scno;
1372}
1373
Roland McGratheb9e2e82009-06-02 16:49:22 -07001374/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001375 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001376 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001377 * 1: ok, continue in trace_syscall().
1378 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001379 * ("????" etc) and bail out.
1380 */
Roland McGratha4d48532005-06-08 20:45:28 +00001381static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001382syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001383{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001384#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001385 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001386
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001387 if (entering(tcp)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001388 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001389 if (
1390 scno == SYS_fork
1391#ifdef SYS_vfork
1392 || scno == SYS_vfork
1393#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001394#ifdef SYS_fork1
1395 || scno == SYS_fork1
1396#endif /* SYS_fork1 */
1397#ifdef SYS_forkall
1398 || scno == SYS_forkall
1399#endif /* SYS_forkall */
1400#ifdef SYS_rfork1
1401 || scno == SYS_rfork1
1402#endif /* SYS_fork1 */
1403#ifdef SYS_rforkall
1404 || scno == SYS_rforkall
1405#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001406 ) {
1407 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001408 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001409 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001410 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001411 }
1412 else {
1413 fprintf(stderr, "syscall: missing entry\n");
1414 tcp->flags |= TCB_INSYSCALL;
1415 }
1416 }
1417 }
1418 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001419 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001420 fprintf(stderr, "syscall: missing exit\n");
1421 tcp->flags &= ~TCB_INSYSCALL;
1422 }
1423 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001424#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001425
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001426#ifdef SUNOS4
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001427 if (entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001428 if (scno == 0) {
1429 fprintf(stderr, "syscall: missing entry\n");
1430 tcp->flags |= TCB_INSYSCALL;
1431 }
1432 }
1433 else {
1434 if (scno != 0) {
1435 if (debug) {
1436 /*
1437 * This happens when a signal handler
1438 * for a signal which interrupted a
1439 * a system call makes another system call.
1440 */
1441 fprintf(stderr, "syscall: missing exit\n");
1442 }
1443 tcp->flags &= ~TCB_INSYSCALL;
1444 }
1445 }
1446#endif /* SUNOS4 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001447
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001449 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001450#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001451 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001453 if (eax != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001455 fprintf(stderr, "not a syscall entry (eax = %ld)\n", eax);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001456 return 0;
1457 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001458#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001459 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001460 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001461 if (current_personality == 1)
1462 rax = (long int)(int)rax; /* sign extend from 32 bits */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001463 if (rax != -ENOSYS && entering(tcp)) {
Michal Ludvig0e035502002-09-23 15:41:01 +00001464 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001465 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
Michal Ludvig0e035502002-09-23 15:41:01 +00001466 return 0;
1467 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001468#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001469 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001470 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001471 if (syscall_mode != -ENOSYS)
1472 syscall_mode = tcp->scno;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001473 if (gpr2 != syscall_mode && entering(tcp)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001474 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001475 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001476 return 0;
1477 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001478 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1479 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1480 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1481 /*
1482 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1483 * flag set for the post-execve SIGTRAP to see and reset.
1484 */
1485 gpr2 = 0;
1486 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001487#elif defined (POWERPC)
1488# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001489 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001490 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001491 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001492 return -1;
1493 if (flags & SO_MASK)
1494 result = -result;
1495#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001496 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001497 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001498 if (d0 != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001499 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001500 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001501 return 0;
1502 }
1503#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001504 /*
1505 * Nothing required
1506 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001507#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001508 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001509 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001510#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001511 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001512 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001513#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001514 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001515 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001516 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001517 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001518 if (ia32 && r8 != -ENOSYS && entering(tcp)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001519 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001520 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001521 return 0;
1522 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001523#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001524 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001525 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001526 if (r10 != -ENOSYS && entering(tcp)) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001527 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001528 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001529 return 0;
1530 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001531#elif defined(MICROBLAZE)
1532 if (upeek(tcp, 3 * 4, &r3) < 0)
1533 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001534 if (r3 != -ENOSYS && entering(tcp)) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001535 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001536 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001537 return 0;
1538 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001539#endif
1540#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001541 return 1;
1542}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001543
Roland McGrathc1e45922008-05-27 23:18:29 +00001544#ifdef LINUX
1545/*
1546 * Check the syscall return value register value for whether it is
1547 * a negated errno code indicating an error, or a success return value.
1548 */
1549static inline int
1550is_negated_errno(unsigned long int val)
1551{
1552 unsigned long int max = -(long int) nerrnos;
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001553# if SUPPORTED_PERSONALITIES > 1
Roland McGrathc1e45922008-05-27 23:18:29 +00001554 if (personality_wordsize[current_personality] < sizeof(val)) {
1555 val = (unsigned int) val;
1556 max = (unsigned int) max;
1557 }
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001558# endif
Roland McGrathc1e45922008-05-27 23:18:29 +00001559 return val > max;
1560}
1561#endif
1562
Roland McGratha4d48532005-06-08 20:45:28 +00001563static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001564get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001565{
1566 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001567#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001568 int check_errno = 1;
1569 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1570 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1571 check_errno = 0;
1572 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001573# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001574 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001575 tcp->u_rval = -1;
1576 u_error = -gpr2;
1577 }
1578 else {
1579 tcp->u_rval = gpr2;
1580 u_error = 0;
1581 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001582# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001583 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001584 tcp->u_rval = -1;
1585 u_error = -eax;
1586 }
1587 else {
1588 tcp->u_rval = eax;
1589 u_error = 0;
1590 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001591# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001592 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001593 tcp->u_rval = -1;
1594 u_error = -rax;
1595 }
1596 else {
1597 tcp->u_rval = rax;
1598 u_error = 0;
1599 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001600# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001601 if (ia32) {
1602 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001603
Roland McGrathc1e45922008-05-27 23:18:29 +00001604 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001605 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001606 tcp->u_rval = -1;
1607 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001608 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001609 else {
1610 tcp->u_rval = err;
1611 u_error = 0;
1612 }
1613 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001614 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001615 tcp->u_rval = -1;
1616 u_error = r8;
1617 } else {
1618 tcp->u_rval = r8;
1619 u_error = 0;
1620 }
1621 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001622# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001623 if (check_errno && a3) {
1624 tcp->u_rval = -1;
1625 u_error = r2;
1626 } else {
1627 tcp->u_rval = r2;
1628 u_error = 0;
1629 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001630# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001631 if (check_errno && is_negated_errno(result)) {
1632 tcp->u_rval = -1;
1633 u_error = -result;
1634 }
1635 else {
1636 tcp->u_rval = result;
1637 u_error = 0;
1638 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001639# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001640 if (check_errno && is_negated_errno(d0)) {
1641 tcp->u_rval = -1;
1642 u_error = -d0;
1643 }
1644 else {
1645 tcp->u_rval = d0;
1646 u_error = 0;
1647 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001648# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001649 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1650 tcp->u_rval = -1;
1651 u_error = -regs.ARM_r0;
1652 }
1653 else {
1654 tcp->u_rval = regs.ARM_r0;
1655 u_error = 0;
1656 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001657# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001658 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1659 tcp->u_rval = -1;
1660 u_error = -regs.r12;
1661 }
1662 else {
1663 tcp->u_rval = regs.r12;
1664 u_error = 0;
1665 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001666# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001667 if (check_errno && is_negated_errno(r0)) {
1668 tcp->u_rval = -1;
1669 u_error = -r0;
1670 } else {
1671 tcp->u_rval = r0;
1672 u_error = 0;
1673 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001674# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001675 if (check_errno && a3) {
1676 tcp->u_rval = -1;
1677 u_error = r0;
1678 }
1679 else {
1680 tcp->u_rval = r0;
1681 u_error = 0;
1682 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001683# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001684 if (check_errno && regs.psr & PSR_C) {
1685 tcp->u_rval = -1;
1686 u_error = regs.u_regs[U_REG_O0];
1687 }
1688 else {
1689 tcp->u_rval = regs.u_regs[U_REG_O0];
1690 u_error = 0;
1691 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001692# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001693 if (check_errno && regs.tstate & 0x1100000000UL) {
1694 tcp->u_rval = -1;
1695 u_error = regs.u_regs[U_REG_O0];
1696 }
1697 else {
1698 tcp->u_rval = regs.u_regs[U_REG_O0];
1699 u_error = 0;
1700 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001701# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001702 if (check_errno && is_negated_errno(r28)) {
1703 tcp->u_rval = -1;
1704 u_error = -r28;
1705 }
1706 else {
1707 tcp->u_rval = r28;
1708 u_error = 0;
1709 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001710# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001711 /* interpret R0 as return value or error number */
1712 if (check_errno && is_negated_errno(r0)) {
1713 tcp->u_rval = -1;
1714 u_error = -r0;
1715 }
1716 else {
1717 tcp->u_rval = r0;
1718 u_error = 0;
1719 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001720# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001721 /* interpret result as return value or error number */
1722 if (check_errno && is_negated_errno(r9)) {
1723 tcp->u_rval = -1;
1724 u_error = -r9;
1725 }
1726 else {
1727 tcp->u_rval = r9;
1728 u_error = 0;
1729 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001730# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001731 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1732 tcp->u_rval = -1;
1733 u_error = -r10;
1734 }
1735 else {
1736 tcp->u_rval = r10;
1737 u_error = 0;
1738 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001739# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001740 long rval;
1741 /* interpret result as return value or error number */
1742 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1743 return -1;
1744 if (check_errno && rval < 0 && rval > -nerrnos) {
1745 tcp->u_rval = -1;
1746 u_error = -rval;
1747 }
1748 else {
1749 tcp->u_rval = rval;
1750 u_error = 0;
1751 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001752# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001753 /* interpret result as return value or error number */
1754 if (check_errno && is_negated_errno(r3)) {
1755 tcp->u_rval = -1;
1756 u_error = -r3;
1757 }
1758 else {
1759 tcp->u_rval = r3;
1760 u_error = 0;
1761 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001762# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763#endif /* LINUX */
1764#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001765 /* get error code from user struct */
1766 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1767 return -1;
1768 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001769
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001770 /* get system call return value */
1771 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1772 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001773#endif /* SUNOS4 */
1774#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001775# ifdef SPARC
1776 /* Judicious guessing goes a long way. */
1777 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1778 tcp->u_rval = -1;
1779 u_error = tcp->status.pr_reg[R_O0];
1780 }
1781 else {
1782 tcp->u_rval = tcp->status.pr_reg[R_O0];
1783 u_error = 0;
1784 }
1785# endif /* SPARC */
1786# ifdef I386
1787 /* Wanna know how to kill an hour single-stepping? */
1788 if (tcp->status.PR_REG[EFL] & 0x1) {
1789 tcp->u_rval = -1;
1790 u_error = tcp->status.PR_REG[EAX];
1791 }
1792 else {
1793 tcp->u_rval = tcp->status.PR_REG[EAX];
1794# ifdef HAVE_LONG_LONG
1795 tcp->u_lrval =
1796 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1797 tcp->status.PR_REG[EAX];
1798# endif
1799 u_error = 0;
1800 }
1801# endif /* I386 */
1802# ifdef X86_64
1803 /* Wanna know how to kill an hour single-stepping? */
1804 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1805 tcp->u_rval = -1;
1806 u_error = tcp->status.PR_REG[RAX];
1807 }
1808 else {
1809 tcp->u_rval = tcp->status.PR_REG[RAX];
1810 u_error = 0;
1811 }
1812# endif /* X86_64 */
1813# ifdef MIPS
1814 if (tcp->status.pr_reg[CTX_A3]) {
1815 tcp->u_rval = -1;
1816 u_error = tcp->status.pr_reg[CTX_V0];
1817 }
1818 else {
1819 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1820 u_error = 0;
1821 }
1822# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001823#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001824#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001825 if (regs.r_eflags & PSL_C) {
1826 tcp->u_rval = -1;
1827 u_error = regs.r_eax;
1828 } else {
1829 tcp->u_rval = regs.r_eax;
1830 tcp->u_lrval =
1831 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1832 u_error = 0;
1833 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001834#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001835 tcp->u_error = u_error;
1836 return 1;
1837}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001838
Roland McGrathb69f81b2002-12-21 23:25:18 +00001839int
Denys Vlasenko12014262011-05-30 14:00:14 +02001840force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001841{
1842#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001843# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001844 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001845 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1846 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001847# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001848 eax = error ? -error : rval;
1849 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1850 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001851# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001852 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001853 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001854 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001855# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001856 if (ia32) {
1857 r8 = error ? -error : rval;
1858 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1859 return -1;
1860 }
1861 else {
1862 if (error) {
1863 r8 = error;
1864 r10 = -1;
1865 }
1866 else {
1867 r8 = rval;
1868 r10 = 0;
1869 }
1870 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1871 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1872 return -1;
1873 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001874# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001875 r0 = error ? -error : rval;
1876 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1877 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001878# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001879 if (error) {
1880 r2 = error;
1881 a3 = -1;
1882 }
1883 else {
1884 r2 = rval;
1885 a3 = 0;
1886 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001887 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001888 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1889 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001890 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001891# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001892 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001893 return -1;
1894 if (error) {
1895 flags |= SO_MASK;
1896 result = error;
1897 }
1898 else {
1899 flags &= ~SO_MASK;
1900 result = rval;
1901 }
Roland McGratheb285352003-01-14 09:59:00 +00001902 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1903 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001904 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001905# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001906 d0 = error ? -error : rval;
1907 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1908 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001909# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001910 regs.ARM_r0 = error ? -error : rval;
1911 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001912 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001913# elif defined(AVR32)
1914 regs.r12 = error ? -error : rval;
1915 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1916 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001917# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001918 if (error) {
1919 a3 = -1;
1920 r0 = error;
1921 }
1922 else {
1923 a3 = 0;
1924 r0 = rval;
1925 }
1926 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1927 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1928 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001929# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001930 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1931 return -1;
1932 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001933 regs.psr |= PSR_C;
1934 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001935 }
1936 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001937 regs.psr &= ~PSR_C;
1938 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001939 }
1940 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1941 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001942# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001943 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1944 return -1;
1945 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001946 regs.tstate |= 0x1100000000UL;
1947 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001948 }
1949 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001950 regs.tstate &= ~0x1100000000UL;
1951 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001952 }
1953 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1954 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001955# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001956 r28 = error ? -error : rval;
1957 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1958 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001959# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001960 r0 = error ? -error : rval;
1961 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1962 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001963# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001964 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001965 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1966 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001967# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001968#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001969
Roland McGrathb69f81b2002-12-21 23:25:18 +00001970#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001971 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1972 error << 24) < 0 ||
1973 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001974 return -1;
1975#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001976
Roland McGrathb69f81b2002-12-21 23:25:18 +00001977#ifdef SVR4
1978 /* XXX no clue */
1979 return -1;
1980#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001981
Roland McGrathb69f81b2002-12-21 23:25:18 +00001982#ifdef FREEBSD
1983 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001984 perror("pread");
1985 return -1;
1986 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001987 if (error) {
1988 regs.r_eflags |= PSL_C;
1989 regs.r_eax = error;
1990 }
1991 else {
1992 regs.r_eflags &= ~PSL_C;
1993 regs.r_eax = rval;
1994 }
1995 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001996 perror("pwrite");
1997 return -1;
1998 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001999#endif /* FREEBSD */
2000
2001 /* All branches reach here on success (only). */
2002 tcp->u_error = error;
2003 tcp->u_rval = rval;
2004 return 0;
2005}
2006
Roland McGratha4d48532005-06-08 20:45:28 +00002007static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002008syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002009{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002010#ifdef LINUX
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002011# if defined(S390) || defined(S390X)
2012 int i;
2013 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2014 tcp->u_nargs = sysent[tcp->scno].nargs;
2015 else
2016 tcp->u_nargs = MAX_ARGS;
2017 for (i = 0; i < tcp->u_nargs; i++) {
2018 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
2019 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002020 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002021# elif defined(ALPHA)
2022 int i;
2023 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2024 tcp->u_nargs = sysent[tcp->scno].nargs;
2025 else
2026 tcp->u_nargs = MAX_ARGS;
2027 for (i = 0; i < tcp->u_nargs; i++) {
2028 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2029 * for scno somewhere above here!
2030 */
2031 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
2032 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002033 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002034# elif defined(IA64)
2035 if (!ia32) {
2036 unsigned long *out0, cfm, sof, sol, i;
2037 long rbs_end;
2038 /* be backwards compatible with kernel < 2.4.4... */
2039# ifndef PT_RBS_END
2040# define PT_RBS_END PT_AR_BSP
2041# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002042
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002043 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
2044 return -1;
2045 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002046 return -1;
2047
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002048 sof = (cfm >> 0) & 0x7f;
2049 sol = (cfm >> 7) & 0x7f;
2050 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
2051
2052 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2053 && sysent[tcp->scno].nargs != -1)
2054 tcp->u_nargs = sysent[tcp->scno].nargs;
2055 else
2056 tcp->u_nargs = MAX_ARGS;
2057 for (i = 0; i < tcp->u_nargs; ++i) {
2058 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2059 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2060 return -1;
2061 }
2062 } else {
2063 int i;
2064
2065 if (/* EBX = out0 */
2066 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
2067 /* ECX = out1 */
2068 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
2069 /* EDX = out2 */
2070 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
2071 /* ESI = out3 */
2072 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
2073 /* EDI = out4 */
2074 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
2075 /* EBP = out5 */
2076 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2077 return -1;
2078
2079 for (i = 0; i < 6; ++i)
2080 /* truncate away IVE sign-extension */
2081 tcp->u_arg[i] &= 0xffffffff;
2082
2083 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2084 && sysent[tcp->scno].nargs != -1)
2085 tcp->u_nargs = sysent[tcp->scno].nargs;
2086 else
2087 tcp->u_nargs = 5;
2088 }
2089# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2090 /* N32 and N64 both use up to six registers. */
2091 unsigned long long regs[38];
2092 int i, nargs;
2093 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2094 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2095 else
2096 nargs = tcp->u_nargs = MAX_ARGS;
2097
2098 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2099 return -1;
2100
2101 for (i = 0; i < nargs; i++) {
2102 tcp->u_arg[i] = regs[REG_A0 + i];
2103# if defined(LINUX_MIPSN32)
2104 tcp->ext_arg[i] = regs[REG_A0 + i];
2105# endif
2106 }
2107# elif defined(MIPS)
2108 long sp;
2109 int i, nargs;
2110
2111 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2112 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2113 else
2114 nargs = tcp->u_nargs = MAX_ARGS;
2115 if (nargs > 4) {
2116 if (upeek(tcp, REG_SP, &sp) < 0)
2117 return -1;
2118 for (i = 0; i < 4; i++) {
2119 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2120 return -1;
2121 }
2122 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2123 (char *)(tcp->u_arg + 4));
2124 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002125 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002126 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002127 return -1;
2128 }
2129 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002130# elif defined(POWERPC)
2131# ifndef PT_ORIG_R3
2132# define PT_ORIG_R3 34
2133# endif
2134 int i;
2135 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2136 tcp->u_nargs = sysent[tcp->scno].nargs;
2137 else
2138 tcp->u_nargs = MAX_ARGS;
2139 for (i = 0; i < tcp->u_nargs; i++) {
2140 if (upeek(tcp, (i==0) ?
2141 (sizeof(unsigned long) * PT_ORIG_R3) :
2142 ((i+PT_R3) * sizeof(unsigned long)),
2143 &tcp->u_arg[i]) < 0)
2144 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002145 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002146# elif defined(SPARC) || defined(SPARC64)
2147 int i;
2148 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2149 tcp->u_nargs = sysent[tcp->scno].nargs;
2150 else
2151 tcp->u_nargs = MAX_ARGS;
2152 for (i = 0; i < tcp->u_nargs; i++)
2153 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2154# elif defined(HPPA)
2155 int i;
2156 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2157 tcp->u_nargs = sysent[tcp->scno].nargs;
2158 else
2159 tcp->u_nargs = MAX_ARGS;
2160 for (i = 0; i < tcp->u_nargs; i++) {
2161 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2162 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002163 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002164# elif defined(ARM)
2165 int i;
2166 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2167 tcp->u_nargs = sysent[tcp->scno].nargs;
2168 else
2169 tcp->u_nargs = MAX_ARGS;
2170 for (i = 0; i < tcp->u_nargs; i++)
2171 tcp->u_arg[i] = regs.uregs[i];
2172# elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002173 tcp->u_nargs = sysent[tcp->scno].nargs;
2174 tcp->u_arg[0] = regs.r12;
2175 tcp->u_arg[1] = regs.r11;
2176 tcp->u_arg[2] = regs.r10;
2177 tcp->u_arg[3] = regs.r9;
2178 tcp->u_arg[4] = regs.r5;
2179 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002180# elif defined(BFIN)
2181 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002182 static const int argreg[] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002183
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002184 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002185 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002186 else
2187 tcp->u_nargs = ARRAY_SIZE(argreg);
2188
2189 for (i = 0; i < tcp->u_nargs; ++i)
2190 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2191 return -1;
2192# elif defined(SH)
2193 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002194 static const int syscall_regs[] = {
2195 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6), 4 * (REG_REG0+7),
2196 4 * (REG_REG0 ), 4 * (REG_REG0+1), 4 * (REG_REG0+2)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002197 };
2198
2199 tcp->u_nargs = sysent[tcp->scno].nargs;
2200 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002201 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002202 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002203 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002204# elif defined(SH64)
2205 int i;
2206 /* Registers used by SH5 Linux system calls for parameters */
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002207 static const int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002208
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002209 /*
2210 * TODO: should also check that the number of arguments encoded
2211 * in the trap number matches the number strace expects.
2212 */
2213 /*
2214 assert(sysent[tcp->scno].nargs < ARRAY_SIZE(syscall_regs));
2215 */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002216
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002217 tcp->u_nargs = sysent[tcp->scno].nargs;
2218 for (i = 0; i < tcp->u_nargs; i++) {
2219 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2220 return -1;
2221 }
2222# elif defined(X86_64)
2223 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002224 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2225 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2226 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002227 };
2228
2229 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002230 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002231 else
2232 tcp->u_nargs = MAX_ARGS;
2233 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002234 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002235 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00002236 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002237# elif defined(MICROBLAZE)
2238 int i;
2239 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2240 tcp->u_nargs = sysent[tcp->scno].nargs;
2241 else
2242 tcp->u_nargs = 0;
2243 for (i = 0; i < tcp->u_nargs; i++) {
2244 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2245 return -1;
2246 }
2247# elif defined(CRISV10) || defined(CRISV32)
2248 int i;
2249 static const int crisregs[] = {
2250 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002251 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002252 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002253
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002254 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2255 tcp->u_nargs = sysent[tcp->scno].nargs;
2256 else
2257 tcp->u_nargs = 0;
2258 for (i = 0; i < tcp->u_nargs; i++) {
2259 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2260 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00002261 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002262# elif defined(TILE)
2263 int i;
2264 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2265 tcp->u_nargs = sysent[tcp->scno].nargs;
2266 else
2267 tcp->u_nargs = MAX_ARGS;
2268 for (i = 0; i < tcp->u_nargs; ++i) {
2269 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2270 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002271 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002272# elif defined(M68K)
2273 int i;
2274 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2275 tcp->u_nargs = sysent[tcp->scno].nargs;
2276 else
2277 tcp->u_nargs = MAX_ARGS;
2278 for (i = 0; i < tcp->u_nargs; i++) {
2279 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2280 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002281 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002282# else /* Other architecture (like i386) (32bits specific) */
2283 int i;
2284 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2285 tcp->u_nargs = sysent[tcp->scno].nargs;
2286 else
2287 tcp->u_nargs = MAX_ARGS;
2288 for (i = 0; i < tcp->u_nargs; i++) {
2289 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2290 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05002291 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002292# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293#endif /* LINUX */
2294#ifdef SUNOS4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002295 int i;
2296 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2297 tcp->u_nargs = sysent[tcp->scno].nargs;
2298 else
2299 tcp->u_nargs = MAX_ARGS;
2300 for (i = 0; i < tcp->u_nargs; i++) {
2301 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002302
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002303 if (upeek(tcp, uoff(u_arg[0]) +
2304 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2305 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002306 }
2307#endif /* SUNOS4 */
2308#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002309# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002310 /*
2311 * SGI is broken: even though it has pr_sysarg, it doesn't
2312 * set them on system call entry. Get a clue.
2313 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002314 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002315 tcp->u_nargs = sysent[tcp->scno].nargs;
2316 else
2317 tcp->u_nargs = tcp->status.pr_nsysarg;
2318 if (tcp->u_nargs > 4) {
2319 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002320 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002321 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002322 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002323 }
2324 else {
2325 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002326 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002327 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002328# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002329 /*
2330 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2331 */
2332 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2333 tcp->u_nargs = sysent[tcp->scno].nargs;
2334 else
2335 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2336 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002337 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2338# elif defined(HAVE_PR_SYSCALL)
2339 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002340 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002341 tcp->u_nargs = sysent[tcp->scno].nargs;
2342 else
2343 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002344 for (i = 0; i < tcp->u_nargs; i++)
2345 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2346# elif defined(I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002347 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002348 tcp->u_nargs = sysent[tcp->scno].nargs;
2349 else
2350 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002351 if (tcp->u_nargs > 0)
2352 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002353 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2354# else
John Hughes25299712001-03-06 10:10:06 +00002355 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002356# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002357#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002358#ifdef FREEBSD
2359 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2360 sysent[tcp->scno].nargs > tcp->status.val)
2361 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002362 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002363 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002364 if (tcp->u_nargs < 0)
2365 tcp->u_nargs = 0;
2366 if (tcp->u_nargs > MAX_ARGS)
2367 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002368 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002369 case SYS___syscall:
2370 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2371 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002372 break;
2373 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002374 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2375 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002376 break;
2377 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002378 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2379 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002380 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002381 }
2382#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002383 return 1;
2384}
2385
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002386static int
2387trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002388{
2389 int sys_res;
2390 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002391 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002392 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002393
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002394 /* Measure the exit time as early as possible to avoid errors. */
2395 if (dtime || cflag)
2396 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002397
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002398 /* BTW, why we don't just memorize syscall no. on entry
2399 * in tcp->something?
2400 */
2401 scno_good = res = get_scno(tcp);
2402 if (res == 0)
2403 return res;
2404 if (res == 1)
2405 res = syscall_fixup(tcp);
2406 if (res == 0)
2407 return res;
2408 if (res == 1)
2409 res = get_error(tcp);
2410 if (res == 0)
2411 return res;
2412 if (res == 1)
2413 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002414
Grant Edwards8a082772011-04-07 20:25:40 +00002415 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002416 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002417 }
2418
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002419 if (tcp->flags & TCB_REPRINT) {
2420 printleader(tcp);
2421 tprintf("<... ");
2422 if (scno_good != 1)
2423 tprintf("????");
2424 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2425 tprintf("syscall_%lu", tcp->scno);
2426 else
2427 tprintf("%s", sysent[tcp->scno].sys_name);
2428 tprintf(" resumed> ");
2429 }
2430
2431 if (cflag) {
2432 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002433 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002434 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002435 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002436 }
2437 }
2438
2439 if (res != 1) {
2440 tprintf(") ");
2441 tabto(acolumn);
2442 tprintf("= ? <unavailable>");
2443 printtrailer();
2444 tcp->flags &= ~TCB_INSYSCALL;
2445 return res;
2446 }
2447
2448 if (tcp->scno >= nsyscalls || tcp->scno < 0
2449 || (qual_flags[tcp->scno] & QUAL_RAW))
2450 sys_res = printargs(tcp);
2451 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002452 /* FIXME: not_failing_only (IOW, option -z) is broken:
2453 * failure of syscall is known only after syscall return.
2454 * Thus we end up with something like this on, say, ENOENT:
2455 * open("doesnt_exist", O_RDONLY <unfinished ...>
2456 * {next syscall decode}
2457 * whereas the intended result is that open(...) line
2458 * is not shown at all.
2459 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002460 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002461 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002462 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2463 }
2464
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002465 tprintf(") ");
2466 tabto(acolumn);
Denys Vlasenko3b738812011-08-22 02:06:35 +02002467 u_error = tcp->u_error;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002468 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2469 qual_flags[tcp->scno] & QUAL_RAW) {
2470 if (u_error)
2471 tprintf("= -1 (errno %ld)", u_error);
2472 else
2473 tprintf("= %#lx", tcp->u_rval);
2474 }
2475 else if (!(sys_res & RVAL_NONE) && u_error) {
2476 switch (u_error) {
2477#ifdef LINUX
2478 case ERESTARTSYS:
2479 tprintf("= ? ERESTARTSYS (To be restarted)");
2480 break;
2481 case ERESTARTNOINTR:
2482 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2483 break;
2484 case ERESTARTNOHAND:
2485 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2486 break;
2487 case ERESTART_RESTARTBLOCK:
2488 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2489 break;
2490#endif /* LINUX */
2491 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002492 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002493 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002494 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002495 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002496 strerror(u_error));
2497 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002498 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002499 strerror(u_error));
2500 break;
2501 }
2502 if ((sys_res & RVAL_STR) && tcp->auxstr)
2503 tprintf(" (%s)", tcp->auxstr);
2504 }
2505 else {
2506 if (sys_res & RVAL_NONE)
2507 tprintf("= ?");
2508 else {
2509 switch (sys_res & RVAL_MASK) {
2510 case RVAL_HEX:
2511 tprintf("= %#lx", tcp->u_rval);
2512 break;
2513 case RVAL_OCTAL:
2514 tprintf("= %#lo", tcp->u_rval);
2515 break;
2516 case RVAL_UDECIMAL:
2517 tprintf("= %lu", tcp->u_rval);
2518 break;
2519 case RVAL_DECIMAL:
2520 tprintf("= %ld", tcp->u_rval);
2521 break;
2522#ifdef HAVE_LONG_LONG
2523 case RVAL_LHEX:
2524 tprintf("= %#llx", tcp->u_lrval);
2525 break;
2526 case RVAL_LOCTAL:
2527 tprintf("= %#llo", tcp->u_lrval);
2528 break;
2529 case RVAL_LUDECIMAL:
2530 tprintf("= %llu", tcp->u_lrval);
2531 break;
2532 case RVAL_LDECIMAL:
2533 tprintf("= %lld", tcp->u_lrval);
2534 break;
2535#endif
2536 default:
2537 fprintf(stderr,
2538 "invalid rval format\n");
2539 break;
2540 }
2541 }
2542 if ((sys_res & RVAL_STR) && tcp->auxstr)
2543 tprintf(" (%s)", tcp->auxstr);
2544 }
2545 if (dtime) {
2546 tv_sub(&tv, &tv, &tcp->etime);
2547 tprintf(" <%ld.%06ld>",
2548 (long) tv.tv_sec, (long) tv.tv_usec);
2549 }
2550 printtrailer();
2551
2552 dumpio(tcp);
2553 if (fflush(tcp->outf) == EOF)
2554 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002555 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002556 tcp->flags &= ~TCB_INSYSCALL;
2557 return 0;
2558}
2559
2560static int
2561trace_syscall_entering(struct tcb *tcp)
2562{
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002563 int res, scno_good;
2564
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002565 scno_good = res = get_scno(tcp);
2566 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002567 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002568 if (res == 1)
2569 res = syscall_fixup(tcp);
2570 if (res == 0)
2571 return res;
2572 if (res == 1)
2573 res = syscall_enter(tcp);
2574 if (res == 0)
2575 return res;
2576
2577 if (res != 1) {
2578 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002579 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002580 tcp_last = tcp;
2581 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002582 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002583 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2584 tprintf("syscall_%lu(", tcp->scno);
2585 else
2586 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002587 /*
2588 * " <unavailable>" will be added later by the code which
2589 * detects ptrace errors.
2590 */
Denys Vlasenko3b738812011-08-22 02:06:35 +02002591 goto ret;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002592 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002593
Roland McGrath17352792005-06-07 23:21:26 +00002594 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002595#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002596 case SYS_socketcall:
2597 decode_subcall(tcp, SYS_socket_subcall,
2598 SYS_socket_nsubcalls, deref_style);
2599 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002600#endif
2601#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002602 case SYS_ipc:
2603 decode_subcall(tcp, SYS_ipc_subcall,
2604 SYS_ipc_nsubcalls, shift_style);
2605 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002606#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002607#ifdef SVR4
2608#ifdef SYS_pgrpsys_subcall
2609 case SYS_pgrpsys:
2610 decode_subcall(tcp, SYS_pgrpsys_subcall,
2611 SYS_pgrpsys_nsubcalls, shift_style);
2612 break;
2613#endif /* SYS_pgrpsys_subcall */
2614#ifdef SYS_sigcall_subcall
2615 case SYS_sigcall:
2616 decode_subcall(tcp, SYS_sigcall_subcall,
2617 SYS_sigcall_nsubcalls, mask_style);
2618 break;
2619#endif /* SYS_sigcall_subcall */
2620 case SYS_msgsys:
2621 decode_subcall(tcp, SYS_msgsys_subcall,
2622 SYS_msgsys_nsubcalls, shift_style);
2623 break;
2624 case SYS_shmsys:
2625 decode_subcall(tcp, SYS_shmsys_subcall,
2626 SYS_shmsys_nsubcalls, shift_style);
2627 break;
2628 case SYS_semsys:
2629 decode_subcall(tcp, SYS_semsys_subcall,
2630 SYS_semsys_nsubcalls, shift_style);
2631 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002632 case SYS_sysfs:
2633 decode_subcall(tcp, SYS_sysfs_subcall,
2634 SYS_sysfs_nsubcalls, shift_style);
2635 break;
2636 case SYS_spcall:
2637 decode_subcall(tcp, SYS_spcall_subcall,
2638 SYS_spcall_nsubcalls, shift_style);
2639 break;
2640#ifdef SYS_context_subcall
2641 case SYS_context:
2642 decode_subcall(tcp, SYS_context_subcall,
2643 SYS_context_nsubcalls, shift_style);
2644 break;
2645#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002646#ifdef SYS_door_subcall
2647 case SYS_door:
2648 decode_subcall(tcp, SYS_door_subcall,
2649 SYS_door_nsubcalls, door_style);
2650 break;
2651#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002652#ifdef SYS_kaio_subcall
2653 case SYS_kaio:
2654 decode_subcall(tcp, SYS_kaio_subcall,
2655 SYS_kaio_nsubcalls, shift_style);
2656 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002657#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002658#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002659#ifdef FREEBSD
2660 case SYS_msgsys:
2661 case SYS_shmsys:
2662 case SYS_semsys:
2663 decode_subcall(tcp, 0, 0, table_style);
2664 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002665#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002666#ifdef SUNOS4
2667 case SYS_semsys:
2668 decode_subcall(tcp, SYS_semsys_subcall,
2669 SYS_semsys_nsubcalls, shift_style);
2670 break;
2671 case SYS_msgsys:
2672 decode_subcall(tcp, SYS_msgsys_subcall,
2673 SYS_msgsys_nsubcalls, shift_style);
2674 break;
2675 case SYS_shmsys:
2676 decode_subcall(tcp, SYS_shmsys_subcall,
2677 SYS_shmsys_nsubcalls, shift_style);
2678 break;
2679#endif
2680 }
2681
2682 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002683
2684 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2685 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2686 (tracing_paths && !pathtrace_match(tcp))) {
2687 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002688 return 0;
2689 }
2690
Grant Edwards8a082772011-04-07 20:25:40 +00002691 tcp->flags &= ~TCB_FILTERED;
2692
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002693 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002694 res = 0;
2695 goto ret;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002696 }
2697
2698 printleader(tcp);
2699 tcp->flags &= ~TCB_REPRINT;
2700 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002701 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002702 tprintf("syscall_%lu(", tcp->scno);
2703 else
2704 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002705 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002706 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2707 sysent[tcp->scno].sys_func != sys_exit))
Denys Vlasenko3b738812011-08-22 02:06:35 +02002708 res = printargs(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002709 else
Denys Vlasenko3b738812011-08-22 02:06:35 +02002710 res = (*sysent[tcp->scno].sys_func)(tcp);
2711
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002712 if (fflush(tcp->outf) == EOF)
2713 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002714 ret:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002715 tcp->flags |= TCB_INSYSCALL;
2716 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002717 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002718 gettimeofday(&tcp->etime, NULL);
Denys Vlasenko3b738812011-08-22 02:06:35 +02002719 return res;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002720}
2721
2722int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002723trace_syscall(struct tcb *tcp)
2724{
2725 return exiting(tcp) ?
2726 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2727}
2728
2729int
Denys Vlasenko12014262011-05-30 14:00:14 +02002730printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002731{
2732 if (entering(tcp)) {
2733 int i;
2734
2735 for (i = 0; i < tcp->u_nargs; i++)
2736 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2737 }
2738 return 0;
2739}
2740
2741long
Denys Vlasenko12014262011-05-30 14:00:14 +02002742getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002743{
2744 long val = -1;
2745
2746#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002747#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002748 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002749 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002750 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002751 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002752#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002753 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002754 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002755#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002756 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002757 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002758#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002759#endif /* LINUX */
2760
2761#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002762 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002763 return -1;
2764#endif /* SUNOS4 */
2765
2766#ifdef SVR4
2767#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002768 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002769#endif /* SPARC */
2770#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002771 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002772#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002773#ifdef X86_64
2774 val = tcp->status.PR_REG[RDX];
2775#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002776#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002777 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002778#endif /* MIPS */
2779#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002780
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002781#ifdef FREEBSD
2782 struct reg regs;
2783 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2784 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002785#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002786 return val;
2787}
2788
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002789#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002790/*
2791 * Apparently, indirect system calls have already be converted by ptrace(2),
2792 * so if you see "indir" this program has gone astray.
2793 */
2794int
Denys Vlasenko12014262011-05-30 14:00:14 +02002795sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002796{
2797 int i, scno, nargs;
2798
2799 if (entering(tcp)) {
Denys Vlasenko5d645812011-08-20 12:48:18 +02002800 scno = tcp->u_arg[0];
2801 if (scno > nsyscalls) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002802 fprintf(stderr, "Bogus syscall: %u\n", scno);
2803 return 0;
2804 }
2805 nargs = sysent[scno].nargs;
2806 tprintf("%s", sysent[scno].sys_name);
2807 for (i = 0; i < nargs; i++)
2808 tprintf(", %#lx", tcp->u_arg[i+1]);
2809 }
2810 return 0;
2811}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002812#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002813
2814int
2815is_restart_error(struct tcb *tcp)
2816{
2817#ifdef LINUX
2818 if (!syserror(tcp))
2819 return 0;
2820 switch (tcp->u_error) {
2821 case ERESTARTSYS:
2822 case ERESTARTNOINTR:
2823 case ERESTARTNOHAND:
2824 case ERESTART_RESTARTBLOCK:
2825 return 1;
2826 default:
2827 break;
2828 }
2829#endif /* LINUX */
2830 return 0;
2831}