blob: a6f47af42d6fff881e4ac56a64258d165403d945 [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
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200115#define MA MAX_ARGS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116
Roland McGrathee36ce12004-09-04 03:53:10 +0000117static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118#include "syscallent.h"
119};
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120
121#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000122static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123#include "syscallent1.h"
124};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200125#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126
127#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent2.h"
130};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200131#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000132
133/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000134#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000135#undef TF
136#undef TI
137#undef TN
138#undef TP
139#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000140#undef NF
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200141#undef MA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142
Denys Vlasenko39fca622011-08-20 02:12:33 +0200143
144/*
145 * `ioctlent.h' may be generated from `ioctlent.raw' by the auxiliary
146 * program `ioctlsort', such that the list is sorted by the `code' field.
147 * This has the side-effect of resolving the _IO.. macros into
148 * plain integers, eliminating the need to include here everything
149 * in "/usr/include".
150 */
151
152
Roland McGrathee36ce12004-09-04 03:53:10 +0000153static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000154#include "errnoent.h"
155};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200156static const char *const signalent0[] = {
157#include "signalent.h"
158};
159static const struct ioctlent ioctlent0[] = {
160#include "ioctlent.h"
161};
162enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
163enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
164enum { nsignals0 = ARRAY_SIZE(signalent0) };
165enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
166int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167
168#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000169static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000170#include "errnoent1.h"
171};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200172static const char *const signalent1[] = {
173#include "signalent1.h"
174};
175static const struct ioctlent ioctlent1[] = {
176#include "ioctlent1.h"
177};
178enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
179enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
180enum { nsignals1 = ARRAY_SIZE(signalent1) };
181enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
182int qual_flags1[MAX_QUALS];
183#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184
185#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000186static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000187#include "errnoent2.h"
188};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200189static const char *const signalent2[] = {
190#include "signalent2.h"
191};
192static const struct ioctlent ioctlent2[] = {
193#include "ioctlent2.h"
194};
195enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
196enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
197enum { nsignals2 = ARRAY_SIZE(signalent2) };
198enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
199int qual_flags2[MAX_QUALS];
200#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201
Denys Vlasenko39fca622011-08-20 02:12:33 +0200202
203const struct sysent *sysent;
Roland McGrathee36ce12004-09-04 03:53:10 +0000204const char *const *errnoent;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200205const char *const *signalent;
206const struct ioctlent *ioctlent;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200207unsigned nsyscalls;
208unsigned nerrnos;
209unsigned nsignals;
210unsigned nioctlents;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200211int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000212
213int current_personality;
214
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000215#ifndef PERSONALITY0_WORDSIZE
216# define PERSONALITY0_WORDSIZE sizeof(long)
217#endif
218const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
219 PERSONALITY0_WORDSIZE,
220#if SUPPORTED_PERSONALITIES > 1
221 PERSONALITY1_WORDSIZE,
222#endif
223#if SUPPORTED_PERSONALITIES > 2
224 PERSONALITY2_WORDSIZE,
225#endif
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200226};
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000227
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200228void
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000229set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000230{
231 switch (personality) {
232 case 0:
233 errnoent = errnoent0;
234 nerrnos = nerrnos0;
235 sysent = sysent0;
236 nsyscalls = nsyscalls0;
237 ioctlent = ioctlent0;
238 nioctlents = nioctlents0;
239 signalent = signalent0;
240 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000241 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000242 break;
243
244#if SUPPORTED_PERSONALITIES >= 2
245 case 1:
246 errnoent = errnoent1;
247 nerrnos = nerrnos1;
248 sysent = sysent1;
249 nsyscalls = nsyscalls1;
250 ioctlent = ioctlent1;
251 nioctlents = nioctlents1;
252 signalent = signalent1;
253 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000254 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200256#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000257
258#if SUPPORTED_PERSONALITIES >= 3
259 case 2:
260 errnoent = errnoent2;
261 nerrnos = nerrnos2;
262 sysent = sysent2;
263 nsyscalls = nsyscalls2;
264 ioctlent = ioctlent2;
265 nioctlents = nioctlents2;
266 signalent = signalent2;
267 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000268 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000269 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200270#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000271 }
272
273 current_personality = personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000274}
275
Roland McGrathe10e62a2004-09-04 04:20:43 +0000276
Roland McGrath9797ceb2002-12-30 10:23:00 +0000277static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000278
Roland McGrathe10e62a2004-09-04 04:20:43 +0000279static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000281 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000282 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000283 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000284} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000285 { QUAL_TRACE, "trace", qual_syscall, "system call" },
286 { QUAL_TRACE, "t", qual_syscall, "system call" },
287 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
288 { QUAL_ABBREV, "a", qual_syscall, "system call" },
289 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
290 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
291 { QUAL_RAW, "raw", qual_syscall, "system call" },
292 { QUAL_RAW, "x", qual_syscall, "system call" },
293 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
294 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
295 { QUAL_SIGNAL, "s", qual_signal, "signal" },
296 { QUAL_FAULT, "fault", qual_fault, "fault" },
297 { QUAL_FAULT, "faults", qual_fault, "fault" },
298 { QUAL_FAULT, "m", qual_fault, "fault" },
299 { QUAL_READ, "read", qual_desc, "descriptor" },
300 { QUAL_READ, "reads", qual_desc, "descriptor" },
301 { QUAL_READ, "r", qual_desc, "descriptor" },
302 { QUAL_WRITE, "write", qual_desc, "descriptor" },
303 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
304 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000305 { 0, NULL, NULL, NULL },
306};
307
Roland McGrath9797ceb2002-12-30 10:23:00 +0000308static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000309qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000310{
Roland McGrath138c6a32006-01-12 09:50:49 +0000311 if (pers == 0 || pers < 0) {
312 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000313 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000314 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000315 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000316 }
317
318#if SUPPORTED_PERSONALITIES >= 2
319 if (pers == 1 || pers < 0) {
320 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000321 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000322 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000323 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000324 }
325#endif /* SUPPORTED_PERSONALITIES >= 2 */
326
327#if SUPPORTED_PERSONALITIES >= 3
328 if (pers == 2 || pers < 0) {
329 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000330 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000331 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000332 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 }
334#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000335}
336
337static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000338qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000339{
340 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000341 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000342
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000343 if (isdigit((unsigned char)*s)) {
344 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000345 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000346 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000347 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000348 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000349 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000350 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000351 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000352 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000353 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000354 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000355
356#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000357 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000358 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000359 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000360 rc = 0;
361 }
362#endif /* SUPPORTED_PERSONALITIES >= 2 */
363
364#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000365 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000366 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000367 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000368 rc = 0;
369 }
370#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000371
Roland McGrathfe6b3522005-02-02 04:40:11 +0000372 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000373}
374
375static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000376qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000377{
378 int i;
379 char buf[32];
380
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000381 if (isdigit((unsigned char)*s)) {
382 int signo = atoi(s);
383 if (signo < 0 || signo >= MAX_QUALS)
384 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000385 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000386 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000388 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000389 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000390 strcpy(buf, s);
391 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000392 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000394 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000395 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000396 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000397 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000398 }
Roland McGrath76421df2005-02-02 03:51:18 +0000399 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000400}
401
402static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000403qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000404{
405 return -1;
406}
407
408static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000409qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000410{
Roland McGrath48a035f2006-01-12 09:45:56 +0000411 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000412 int desc = atoi(s);
413 if (desc < 0 || desc >= MAX_QUALS)
414 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000415 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000416 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417 }
418 return -1;
419}
420
421static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000422lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000423{
424 if (strcmp(s, "file") == 0)
425 return TRACE_FILE;
426 if (strcmp(s, "ipc") == 0)
427 return TRACE_IPC;
428 if (strcmp(s, "network") == 0)
429 return TRACE_NETWORK;
430 if (strcmp(s, "process") == 0)
431 return TRACE_PROCESS;
432 if (strcmp(s, "signal") == 0)
433 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000434 if (strcmp(s, "desc") == 0)
435 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000436 return -1;
437}
438
439void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000440qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000442 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000443 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000444 char *copy;
445 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000446 int i, n;
447
448 opt = &qual_options[0];
449 for (i = 0; (p = qual_options[i].option_name); i++) {
450 n = strlen(p);
451 if (strncmp(s, p, n) == 0 && s[n] == '=') {
452 opt = &qual_options[i];
453 s += n + 1;
454 break;
455 }
456 }
457 not = 0;
458 if (*s == '!') {
459 not = 1;
460 s++;
461 }
462 if (strcmp(s, "none") == 0) {
463 not = 1 - not;
464 s = "all";
465 }
466 if (strcmp(s, "all") == 0) {
467 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000468 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000469 }
470 return;
471 }
472 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000473 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000474 }
Denys Vlasenko5d645812011-08-20 12:48:18 +0200475 copy = strdup(s);
476 if (!copy) {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000477 fprintf(stderr, "out of memory\n");
478 exit(1);
479 }
480 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000481 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000482 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000483 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000484 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000485
486#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000487 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000488 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000489 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000490#endif /* SUPPORTED_PERSONALITIES >= 2 */
491
492#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000493 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000494 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000495 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000496#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000497
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000498 continue;
499 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000500 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000501 fprintf(stderr, "strace: invalid %s `%s'\n",
502 opt->argument_name, p);
503 exit(1);
504 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000505 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000506 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507 return;
508}
509
510static void
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000511dumpio(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000512{
513 if (syserror(tcp))
514 return;
515 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
516 return;
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000517 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
518 return;
519 if (sysent[tcp->scno].sys_func == printargs)
520 return;
521 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
522 if (sysent[tcp->scno].sys_func == sys_read ||
523 sysent[tcp->scno].sys_func == sys_pread ||
524 sysent[tcp->scno].sys_func == sys_pread64 ||
525 sysent[tcp->scno].sys_func == sys_recv ||
526 sysent[tcp->scno].sys_func == sys_recvfrom)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000528 else if (sysent[tcp->scno].sys_func == sys_readv)
529 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
530 return;
531 }
532 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
533 if (sysent[tcp->scno].sys_func == sys_write ||
534 sysent[tcp->scno].sys_func == sys_pwrite ||
535 sysent[tcp->scno].sys_func == sys_pwrite64 ||
536 sysent[tcp->scno].sys_func == sys_send ||
537 sysent[tcp->scno].sys_func == sys_sendto)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000539 else if (sysent[tcp->scno].sys_func == sys_writev)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000540 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000541 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000542 }
543}
544
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000545#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000546enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000547#else /* FREEBSD */
548enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
549
550struct subcall {
551 int call;
552 int nsubcalls;
553 int subcalls[5];
554};
555
Roland McGratha4d48532005-06-08 20:45:28 +0000556static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000557 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000558#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000559 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000560#else
561 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
562#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000563 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
564};
565#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000567#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568
Roland McGratha4d48532005-06-08 20:45:28 +0000569static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200570decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000571{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000572 unsigned long addr, mask;
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200573 int i, n;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000574 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000575
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 switch (style) {
577 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000578 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
579 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000580 tcp->scno = subcall + tcp->u_arg[0];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200581 tcp->u_nargs = n = sysent[tcp->scno].nargs;
582 for (i = 0; i < n; i++)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583 tcp->u_arg[i] = tcp->u_arg[i + 1];
584 break;
585 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000586 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
587 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588 tcp->scno = subcall + tcp->u_arg[0];
589 addr = tcp->u_arg[1];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200590 tcp->u_nargs = n = sysent[tcp->scno].nargs;
591 for (i = 0; i < n; 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 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000608 break;
609 case mask_style:
610 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000611 for (i = 0; mask; i++)
612 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000613 if (i >= nsubcalls)
614 return;
615 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616 tcp->scno = subcall + i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200617 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000618 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000619 case door_style:
620 /*
621 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000622 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000623 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000624 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
625 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000626 tcp->scno = subcall + tcp->u_arg[5];
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200627 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000628 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000629#ifdef FREEBSD
630 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000631 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000632 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000633 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000634 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
635 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
636 for (i = 0; i < tcp->u_nargs; i++)
637 tcp->u_arg[i] = tcp->u_arg[i + 1];
638 }
639 break;
640#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 }
642}
643#endif
644
645struct tcb *tcp_last = NULL;
646
647static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000648internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649{
650 /*
651 * We must always trace a few critical system calls in order to
652 * correctly support following forks in the presence of tracing
653 * qualifiers.
654 */
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200655 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000656
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000657 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
658 return 0;
659
660 func = sysent[tcp->scno].sys_func;
661
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000662 if ( sys_fork == func
663#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
664 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000665#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000666#ifdef LINUX
667 || sys_clone == func
668#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000669#if UNIXWARE > 2
670 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000671#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000672 )
673 return internal_fork(tcp);
674
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200675#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000676 if ( sys_execve == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200677# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000678 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200679# endif
680# if UNIXWARE > 2
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000681 || sys_rexecve == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200682# endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683 )
684 return internal_exec(tcp);
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200685#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000686
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000687 return 0;
688}
689
Wichert Akkermanc7926982000-04-10 22:22:31 +0000690
691#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200692# if defined (I386)
693static long eax;
694# elif defined (IA64)
695long r8, r10, psr; /* TODO: make static? */
696long ia32 = 0; /* not static */
697# elif defined (POWERPC)
698static long result, flags;
699# elif defined (M68K)
700static long d0;
701# elif defined(BFIN)
702static long r0;
703# elif defined (ARM)
704static struct pt_regs regs;
705# elif defined (ALPHA)
706static long r0;
707static long a3;
708# elif defined(AVR32)
709static struct pt_regs regs;
710# elif defined (SPARC) || defined (SPARC64)
711static struct pt_regs regs;
712static unsigned long trap;
713# elif defined(LINUX_MIPSN32)
714static long long a3;
715static long long r2;
716# elif defined(MIPS)
717static long a3;
718static long r2;
719# elif defined(S390) || defined(S390X)
720static long gpr2;
721static long pc;
722static long syscall_mode;
723# elif defined(HPPA)
724static long r28;
725# elif defined(SH)
726static long r0;
727# elif defined(SH64)
728static long r9;
729# elif defined(X86_64)
730static long rax;
731# elif defined(CRISV10) || defined(CRISV32)
732static long r10;
733# elif defined(MICROBLAZE)
734static long r3;
735# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000736#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000737#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200738struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000739#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000740
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200741/* Returns:
742 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
743 * 1: ok, continue in trace_syscall().
744 * other: error, trace_syscall() should print error indicator
745 * ("????" etc) and bail out.
746 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200747#ifndef USE_PROCFS
748static
749#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000750int
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200751get_scno_on_sysenter(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000752{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000753 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000754
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000755#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000756# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000757 if (tcp->flags & TCB_WAITEXECVE) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200758 /* This is the post-execve SIGTRAP. */
Roland McGrath96dc5142003-01-20 10:23:04 +0000759 tcp->flags &= ~TCB_WAITEXECVE;
760 return 0;
761 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000762
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000763 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200764 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000765
766 if (syscall_mode != -ENOSYS) {
767 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000768 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000769 */
770 scno = syscall_mode;
771 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000772 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000773 * Old style of "passing" the scno via the SVC instruction.
774 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000775 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200776 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200777 static const int gpr_offset[16] = {
778 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
779 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
780 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
781 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
782 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000783
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000784 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000785 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000786 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000787 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000788 if (errno) {
789 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000790 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000791 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000792
793 /*
794 * We have to check if the SVC got executed directly or via an
795 * EXECUTE instruction. In case of EXECUTE it is necessary to do
796 * instruction decoding to derive the system call number.
797 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
798 * so that this doesn't work if a SVC opcode is part of an EXECUTE
799 * opcode. Since there is no way to find out the opcode size this
800 * is the best we can do...
801 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000802 if ((opcode & 0xff00) == 0x0a00) {
803 /* SVC opcode */
804 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000805 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000806 else {
807 /* SVC got executed by EXECUTE instruction */
808
809 /*
810 * Do instruction decoding of EXECUTE. If you really want to
811 * understand this, read the Principles of Operations.
812 */
813 svc_addr = (void *) (opcode & 0xfff);
814
815 tmp = 0;
816 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000817 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000818 return -1;
819 svc_addr += tmp;
820
821 tmp = 0;
822 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000823 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000824 return -1;
825 svc_addr += tmp;
826
Denys Vlasenkofb036672009-01-23 16:30:26 +0000827 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000828 if (errno)
829 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000830# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000831 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000832# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000833 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000834# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000835 tmp = 0;
836 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000837 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000838 return -1;
839
840 scno = (scno | tmp) & 0xff;
841 }
842 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000843# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000844 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000845 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200846 /* Check if this is the post-execve SIGTRAP. */
847 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
848 tcp->flags &= ~TCB_WAITEXECVE;
849 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000850 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200851# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200852 /* TODO: speed up strace by not doing this at every syscall.
853 * We only need to do it after execve.
854 */
855 int currpers;
856 long val;
857 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200858
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200859 /* Check for 64/32 bit mode. */
860 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
861 return -1;
862 /* SF is bit 0 of MSR */
863 if (val < 0)
864 currpers = 0;
865 else
866 currpers = 1;
867 if (currpers != current_personality) {
868 static const char *const names[] = {"64 bit", "32 bit"};
869 set_personality(currpers);
870 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
871 pid, names[current_personality]);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200872 }
873# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000874# elif defined(AVR32)
875 /*
876 * Read complete register set in one go.
877 */
878 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
879 return -1;
880
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200881 scno = regs.r8;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000882
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200883 /* Check if this is the post-execve SIGTRAP. */
884 if (tcp->flags & TCB_WAITEXECVE) {
885 tcp->flags &= ~TCB_WAITEXECVE;
886 return 0;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000887 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000888# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000889 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000890 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000891# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000892 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000893 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000894# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000895 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000896 return -1;
897
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200898 /* TODO: speed up strace by not doing this at every syscall.
899 * We only need to do it after execve.
900 */
901 int currpers;
902 long val;
903 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000904
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200905 /* Check CS register value. On x86-64 linux it is:
906 * 0x33 for long mode (64 bit)
907 * 0x23 for compatibility mode (32 bit)
908 * It takes only one ptrace and thus doesn't need
909 * to be cached.
910 */
911 if (upeek(tcp, 8*CS, &val) < 0)
912 return -1;
913 switch (val) {
914 case 0x23: currpers = 1; break;
915 case 0x33: currpers = 0; break;
916 default:
917 fprintf(stderr, "Unknown value CS=0x%02X while "
918 "detecting personality of process "
919 "PID=%d\n", (int)val, pid);
920 currpers = current_personality;
921 break;
922 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000923# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200924 /* This version analyzes the opcode of a syscall instruction.
925 * (int 0x80 on i386 vs. syscall on x86-64)
926 * It works, but is too complicated.
927 */
928 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000929
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200930 if (upeek(tcp, 8*RIP, &rip) < 0)
931 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000932
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200933 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
934 rip -= 2;
935 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000936
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200937 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
938 if (errno)
939 fprintf(stderr, "ptrace_peektext failed: %s\n",
940 strerror(errno));
941 switch (call & 0xffff) {
942 /* x86-64: syscall = 0x0f 0x05 */
943 case 0x050f: currpers = 0; break;
944 /* i386: int 0x80 = 0xcd 0x80 */
945 case 0x80cd: currpers = 1; break;
946 default:
947 currpers = current_personality;
948 fprintf(stderr,
949 "Unknown syscall opcode (0x%04X) while "
950 "detecting personality of process "
951 "PID=%d\n", (int)call, pid);
952 break;
953 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000954# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200955 if (currpers != current_personality) {
956 static const char *const names[] = {"64 bit", "32 bit"};
957 set_personality(currpers);
958 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
959 pid, names[current_personality]);
Roland McGrath761b5d72002-12-15 23:58:31 +0000960 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000961# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000962# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200963 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000964 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200965 if (ia32) {
966 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
967 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000968 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200969 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000970 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200971 }
972 /* Check if this is the post-execve SIGTRAP. */
973 if (tcp->flags & TCB_WAITEXECVE) {
974 tcp->flags &= ~TCB_WAITEXECVE;
975 return 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000976 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000977# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000978 /*
979 * Read complete register set in one go.
980 */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000981 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000982 return -1;
983
984 /*
985 * We only need to grab the syscall number on syscall entry.
986 */
987 if (regs.ARM_ip == 0) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200988 /* Check if this is the post-execve SIGTRAP. */
989 if (tcp->flags & TCB_WAITEXECVE) {
990 tcp->flags &= ~TCB_WAITEXECVE;
991 return 0;
Roland McGrath9bc63402007-11-01 21:42:18 +0000992 }
993
Roland McGrath0f87c492003-06-03 23:29:04 +0000994 /*
995 * Note: we only deal with only 32-bit CPUs here.
996 */
997 if (regs.ARM_cpsr & 0x20) {
998 /*
999 * Get the Thumb-mode system call number
1000 */
1001 scno = regs.ARM_r7;
1002 } else {
1003 /*
1004 * Get the ARM-mode system call number
1005 */
1006 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001007 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001008 if (errno)
1009 return -1;
1010
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001011 /* FIXME: bogus check? it is already done before,
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001012 * so we never can see it here?
1013 */
Roland McGrath0f87c492003-06-03 23:29:04 +00001014 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1015 tcp->flags &= ~TCB_WAITEXECVE;
1016 return 0;
1017 }
1018
Roland McGrathf691bd22006-04-25 07:34:41 +00001019 /* Handle the EABI syscall convention. We do not
1020 bother converting structures between the two
1021 ABIs, but basic functionality should work even
1022 if strace and the traced program have different
1023 ABIs. */
1024 if (scno == 0xef000000) {
1025 scno = regs.ARM_r7;
1026 } else {
1027 if ((scno & 0x0ff00000) != 0x0f900000) {
1028 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1029 scno);
1030 return -1;
1031 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001032
Roland McGrathf691bd22006-04-25 07:34:41 +00001033 /*
1034 * Fixup the syscall number
1035 */
1036 scno &= 0x000fffff;
1037 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001038 }
Roland McGrath56703312008-05-20 01:35:55 +00001039 if (scno & 0x0f0000) {
1040 /*
1041 * Handle ARM specific syscall
1042 */
1043 set_personality(1);
1044 scno &= 0x0000ffff;
1045 } else
1046 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001047
Roland McGrath0f87c492003-06-03 23:29:04 +00001048 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001049 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1050 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001052# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001053 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001054 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001055# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001056 unsigned long long regs[38];
1057
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001058 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001059 return -1;
1060 a3 = regs[REG_A3];
1061 r2 = regs[REG_V0];
1062
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001063 scno = r2;
Roland McGrath542c2c62008-05-20 01:11:56 +00001064
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001065 /* Check if this is the post-execve SIGTRAP. */
1066 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1067 tcp->flags &= ~TCB_WAITEXECVE;
1068 return 0;
1069 }
1070
1071 if (scno < 0 || scno > nsyscalls) {
1072 if (a3 == 0 || a3 == -1) {
1073 if (debug)
1074 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001075 return 0;
1076 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001077 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001078# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001079 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001080 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001081 if (upeek(tcp, REG_V0, &scno) < 0)
1082 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001083
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001084 /* Check if this is the post-execve SIGTRAP. */
1085 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1086 tcp->flags &= ~TCB_WAITEXECVE;
1087 return 0;
1088 }
1089
1090 if (scno < 0 || scno > nsyscalls) {
1091 if (a3 == 0 || a3 == -1) {
1092 if (debug)
1093 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001094 return 0;
1095 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001096 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001097# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001098 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001099 return -1;
1100
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001101 if (upeek(tcp, REG_R0, &scno) < 0)
1102 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001104 /* Check if this is the post-execve SIGTRAP. */
1105 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1106 tcp->flags &= ~TCB_WAITEXECVE;
1107 return 0;
1108 }
1109
1110 /*
1111 * Do some sanity checks to figure out if it's
1112 * really a syscall entry
1113 */
1114 if (scno < 0 || scno > nsyscalls) {
1115 if (a3 == 0 || a3 == -1) {
1116 if (debug)
1117 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 return 0;
1119 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001121# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001123 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001124 return -1;
1125
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001126 /* Disassemble the syscall trap. */
1127 /* Retrieve the syscall trap instruction. */
1128 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001129# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001130 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1131 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001132# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001133 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001134# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001135 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001136 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001137
1138 /* Disassemble the trap to see what personality to use. */
1139 switch (trap) {
1140 case 0x91d02010:
1141 /* Linux/SPARC syscall trap. */
1142 set_personality(0);
1143 break;
1144 case 0x91d0206d:
1145 /* Linux/SPARC64 syscall trap. */
1146 set_personality(2);
1147 break;
1148 case 0x91d02000:
1149 /* SunOS syscall trap. (pers 1) */
1150 fprintf(stderr, "syscall: SunOS no support\n");
1151 return -1;
1152 case 0x91d02008:
1153 /* Solaris 2.x syscall trap. (per 2) */
1154 set_personality(1);
1155 break;
1156 case 0x91d02009:
1157 /* NetBSD/FreeBSD syscall trap. */
1158 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1159 return -1;
1160 case 0x91d02027:
1161 /* Solaris 2.x gettimeofday */
1162 set_personality(1);
1163 break;
1164 default:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001165 /* Check if this is the post-execve SIGTRAP. */
1166 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001167 tcp->flags &= ~TCB_WAITEXECVE;
1168 return 0;
1169 }
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001170# if defined (SPARC64)
1171 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1172# else
1173 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1174# endif
1175 return -1;
1176 }
1177
1178 /* Extract the system call number from the registers. */
1179 if (trap == 0x91d02027)
1180 scno = 156;
1181 else
1182 scno = regs.u_regs[U_REG_G1];
1183 if (scno == 0) {
1184 scno = regs.u_regs[U_REG_O0];
1185 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1186 }
1187# elif defined(HPPA)
1188 if (upeek(tcp, PT_GR20, &scno) < 0)
1189 return -1;
1190 /* Check if this is the post-execve SIGTRAP. */
1191 if (tcp->flags & TCB_WAITEXECVE) {
1192 tcp->flags &= ~TCB_WAITEXECVE;
1193 return 0;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001194 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001195# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001196 /*
1197 * In the new syscall ABI, the system call number is in R3.
1198 */
1199 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1200 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001201
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001202 if (scno < 0) {
1203 /* Odd as it may seem, a glibc bug has been known to cause
1204 glibc to issue bogus negative syscall numbers. So for
1205 our purposes, make strace print what it *should* have been */
1206 long correct_scno = (scno & 0xff);
1207 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001208 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001209 "Detected glibc bug: bogus system call"
1210 " number = %ld, correcting to %ld\n",
1211 scno,
1212 correct_scno);
1213 scno = correct_scno;
1214 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001215
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001216 /* Check if this is the post-execve SIGTRAP. */
1217 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1218 tcp->flags &= ~TCB_WAITEXECVE;
1219 return 0;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001220 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001221# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001222 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001223 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001224 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001225
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001226 /* Check if this is the post-execve SIGTRAP. */
1227 if (tcp->flags & TCB_WAITEXECVE) {
1228 tcp->flags &= ~TCB_WAITEXECVE;
1229 return 0;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001230 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001231# elif defined(CRISV10) || defined(CRISV32)
1232 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1233 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001234# elif defined(TILE)
1235 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1236 return -1;
1237
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001238 /* Check if this is the post-execve SIGTRAP. */
1239 if (tcp->flags & TCB_WAITEXECVE) {
1240 tcp->flags &= ~TCB_WAITEXECVE;
1241 return 0;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001242 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001243# elif defined(MICROBLAZE)
1244 if (upeek(tcp, 0, &scno) < 0)
1245 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001246# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001248
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001250 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001252#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001253 /* new syscall ABI returns result in R0 */
1254 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1255 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001256#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001257 /* ABI defines result returned in r9 */
1258 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1259 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001260#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001261
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001262#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001263# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001264 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001265# else
1266# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001267 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001268# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001269 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001270 perror("pread");
1271 return -1;
1272 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001273 switch (regs.r_eax) {
1274 case SYS_syscall:
1275 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001276 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1277 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001278 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001279 scno = regs.r_eax;
1280 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001281 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001282# endif /* FREEBSD */
1283# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001284#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001285
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001286 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001287 return 1;
1288}
1289
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001290/* Returns:
1291 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1292 * 1: ok, continue in trace_syscall().
1293 * other: error, trace_syscall() should print error indicator
1294 * ("????" etc) and bail out.
1295 */
1296static int
1297get_scno_on_sysexit(struct tcb *tcp)
1298{
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001299#ifdef LINUX
1300# if defined(S390) || defined(S390X)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001301# elif defined (POWERPC)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001302# elif defined(AVR32)
1303 /*
1304 * Read complete register set in one go.
1305 */
1306 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1307 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001308# elif defined(BFIN)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001309# elif defined (I386)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001310# elif defined (X86_64)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001311# elif defined(IA64)
1312# define IA64_PSR_IS ((long)1 << 34)
1313 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1314 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001315 if (upeek(tcp, PT_R8, &r8) < 0)
1316 return -1;
1317 if (upeek(tcp, PT_R10, &r10) < 0)
1318 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001319# elif defined (ARM)
1320 /*
1321 * Read complete register set in one go.
1322 */
1323 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1324 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001325# elif defined (M68K)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001326# elif defined (LINUX_MIPSN32)
1327 unsigned long long regs[38];
1328
1329 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1330 return -1;
1331 a3 = regs[REG_A3];
1332 r2 = regs[REG_V0];
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001333# elif defined (MIPS)
1334 if (upeek(tcp, REG_A3, &a3) < 0)
1335 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001336 if (upeek(tcp, REG_V0, &r2) < 0)
1337 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001338# elif defined (ALPHA)
1339 if (upeek(tcp, REG_A3, &a3) < 0)
1340 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001341 if (upeek(tcp, REG_R0, &r0) < 0)
1342 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001343# elif defined (SPARC) || defined (SPARC64)
1344 /* Everything we need is in the current register set. */
1345 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1346 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001347# elif defined(HPPA)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001348# elif defined(SH)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001349# elif defined(SH64)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001350# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001351# elif defined(TILE)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001352# elif defined(MICROBLAZE)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001353# endif
1354#endif /* LINUX */
1355
1356#ifdef SUNOS4
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001357#elif defined(SH)
1358 /* new syscall ABI returns result in R0 */
1359 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1360 return -1;
1361#elif defined(SH64)
1362 /* ABI defines result returned in r9 */
1363 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1364 return -1;
1365#endif
1366
1367#ifdef USE_PROCFS
Denys Vlasenko77a74592011-08-24 16:56:03 +02001368# ifndef HAVE_PR_SYSCALL
1369# ifdef FREEBSD
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001370 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1371 perror("pread");
1372 return -1;
1373 }
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001374# endif /* FREEBSD */
1375# endif /* !HAVE_PR_SYSCALL */
1376#endif /* USE_PROCFS */
1377
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001378 return 1;
1379}
Pavel Machek4dc3b142000-02-01 17:58:41 +00001380
Roland McGrath17352792005-06-07 23:21:26 +00001381long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001382known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001383{
1384 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001385#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001386 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1387 scno = sysent[scno].native_scno;
1388 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001389#endif
Roland McGrath17352792005-06-07 23:21:26 +00001390 scno += NR_SYSCALL_BASE;
1391 return scno;
1392}
1393
Roland McGratheb9e2e82009-06-02 16:49:22 -07001394/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001395 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001396 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001397 * 1: ok, continue in trace_syscall().
1398 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001399 * ("????" etc) and bail out.
1400 */
Roland McGratha4d48532005-06-08 20:45:28 +00001401static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001402syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001403{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001404#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001405 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001406
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001407 if (entering(tcp)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001408 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001409 if (
1410 scno == SYS_fork
1411#ifdef SYS_vfork
1412 || scno == SYS_vfork
1413#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001414#ifdef SYS_fork1
1415 || scno == SYS_fork1
1416#endif /* SYS_fork1 */
1417#ifdef SYS_forkall
1418 || scno == SYS_forkall
1419#endif /* SYS_forkall */
1420#ifdef SYS_rfork1
1421 || scno == SYS_rfork1
1422#endif /* SYS_fork1 */
1423#ifdef SYS_rforkall
1424 || scno == SYS_rforkall
1425#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001426 ) {
1427 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001428 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001429 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001430 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001431 }
1432 else {
1433 fprintf(stderr, "syscall: missing entry\n");
1434 tcp->flags |= TCB_INSYSCALL;
1435 }
1436 }
1437 }
1438 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001439 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001440 fprintf(stderr, "syscall: missing exit\n");
1441 tcp->flags &= ~TCB_INSYSCALL;
1442 }
1443 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001444#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001445
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001446#ifdef SUNOS4
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001447 if (entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448 if (scno == 0) {
1449 fprintf(stderr, "syscall: missing entry\n");
1450 tcp->flags |= TCB_INSYSCALL;
1451 }
1452 }
1453 else {
1454 if (scno != 0) {
1455 if (debug) {
1456 /*
1457 * This happens when a signal handler
1458 * for a signal which interrupted a
1459 * a system call makes another system call.
1460 */
1461 fprintf(stderr, "syscall: missing exit\n");
1462 }
1463 tcp->flags &= ~TCB_INSYSCALL;
1464 }
1465 }
1466#endif /* SUNOS4 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001467
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001468#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001469 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001470#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001471 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001473 if (eax != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001474 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001475 fprintf(stderr, "not a syscall entry (eax = %ld)\n", eax);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001476 return 0;
1477 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001478#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001479 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001480 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001481 if (current_personality == 1)
1482 rax = (long int)(int)rax; /* sign extend from 32 bits */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001483 if (rax != -ENOSYS && entering(tcp)) {
Michal Ludvig0e035502002-09-23 15:41:01 +00001484 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001485 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
Michal Ludvig0e035502002-09-23 15:41:01 +00001486 return 0;
1487 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001488#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001489 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001490 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001491 if (syscall_mode != -ENOSYS)
1492 syscall_mode = tcp->scno;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001493 if (gpr2 != syscall_mode && entering(tcp)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001494 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001495 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001496 return 0;
1497 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001498 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1499 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1500 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1501 /*
1502 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1503 * flag set for the post-execve SIGTRAP to see and reset.
1504 */
1505 gpr2 = 0;
1506 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507#elif defined (POWERPC)
1508# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001509 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001510 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001511 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001512 return -1;
1513 if (flags & SO_MASK)
1514 result = -result;
1515#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001516 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001517 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001518 if (d0 != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001519 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001520 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001521 return 0;
1522 }
1523#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001524 /*
1525 * Nothing required
1526 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001527#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001528 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001529 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001530#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001531 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001532 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001533#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001534 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001535 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001536 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001537 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001538 if (ia32 && r8 != -ENOSYS && entering(tcp)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001539 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001540 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001541 return 0;
1542 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001543#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001544 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001545 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001546 if (r10 != -ENOSYS && entering(tcp)) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001547 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001548 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001549 return 0;
1550 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001551#elif defined(MICROBLAZE)
1552 if (upeek(tcp, 3 * 4, &r3) < 0)
1553 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001554 if (r3 != -ENOSYS && entering(tcp)) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001555 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001556 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001557 return 0;
1558 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001559#endif
1560#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001561 return 1;
1562}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001563
Roland McGrathc1e45922008-05-27 23:18:29 +00001564#ifdef LINUX
1565/*
1566 * Check the syscall return value register value for whether it is
1567 * a negated errno code indicating an error, or a success return value.
1568 */
1569static inline int
1570is_negated_errno(unsigned long int val)
1571{
1572 unsigned long int max = -(long int) nerrnos;
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001573# if SUPPORTED_PERSONALITIES > 1
Roland McGrathc1e45922008-05-27 23:18:29 +00001574 if (personality_wordsize[current_personality] < sizeof(val)) {
1575 val = (unsigned int) val;
1576 max = (unsigned int) max;
1577 }
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001578# endif
Roland McGrathc1e45922008-05-27 23:18:29 +00001579 return val > max;
1580}
1581#endif
1582
Roland McGratha4d48532005-06-08 20:45:28 +00001583static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001584get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001585{
1586 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001588 int check_errno = 1;
1589 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1590 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1591 check_errno = 0;
1592 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001593# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001594 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001595 tcp->u_rval = -1;
1596 u_error = -gpr2;
1597 }
1598 else {
1599 tcp->u_rval = gpr2;
1600 u_error = 0;
1601 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001602# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001603 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001604 tcp->u_rval = -1;
1605 u_error = -eax;
1606 }
1607 else {
1608 tcp->u_rval = eax;
1609 u_error = 0;
1610 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001611# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001612 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001613 tcp->u_rval = -1;
1614 u_error = -rax;
1615 }
1616 else {
1617 tcp->u_rval = rax;
1618 u_error = 0;
1619 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001620# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001621 if (ia32) {
1622 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001623
Roland McGrathc1e45922008-05-27 23:18:29 +00001624 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001625 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001626 tcp->u_rval = -1;
1627 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001628 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001629 else {
1630 tcp->u_rval = err;
1631 u_error = 0;
1632 }
1633 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001634 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001635 tcp->u_rval = -1;
1636 u_error = r8;
1637 } else {
1638 tcp->u_rval = r8;
1639 u_error = 0;
1640 }
1641 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001642# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001643 if (check_errno && a3) {
1644 tcp->u_rval = -1;
1645 u_error = r2;
1646 } else {
1647 tcp->u_rval = r2;
1648 u_error = 0;
1649 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001650# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001651 if (check_errno && is_negated_errno(result)) {
1652 tcp->u_rval = -1;
1653 u_error = -result;
1654 }
1655 else {
1656 tcp->u_rval = result;
1657 u_error = 0;
1658 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001659# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001660 if (check_errno && is_negated_errno(d0)) {
1661 tcp->u_rval = -1;
1662 u_error = -d0;
1663 }
1664 else {
1665 tcp->u_rval = d0;
1666 u_error = 0;
1667 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001668# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001669 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1670 tcp->u_rval = -1;
1671 u_error = -regs.ARM_r0;
1672 }
1673 else {
1674 tcp->u_rval = regs.ARM_r0;
1675 u_error = 0;
1676 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001677# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001678 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1679 tcp->u_rval = -1;
1680 u_error = -regs.r12;
1681 }
1682 else {
1683 tcp->u_rval = regs.r12;
1684 u_error = 0;
1685 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001686# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001687 if (check_errno && is_negated_errno(r0)) {
1688 tcp->u_rval = -1;
1689 u_error = -r0;
1690 } else {
1691 tcp->u_rval = r0;
1692 u_error = 0;
1693 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001694# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001695 if (check_errno && a3) {
1696 tcp->u_rval = -1;
1697 u_error = r0;
1698 }
1699 else {
1700 tcp->u_rval = r0;
1701 u_error = 0;
1702 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001703# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001704 if (check_errno && regs.psr & PSR_C) {
1705 tcp->u_rval = -1;
1706 u_error = regs.u_regs[U_REG_O0];
1707 }
1708 else {
1709 tcp->u_rval = regs.u_regs[U_REG_O0];
1710 u_error = 0;
1711 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001712# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001713 if (check_errno && regs.tstate & 0x1100000000UL) {
1714 tcp->u_rval = -1;
1715 u_error = regs.u_regs[U_REG_O0];
1716 }
1717 else {
1718 tcp->u_rval = regs.u_regs[U_REG_O0];
1719 u_error = 0;
1720 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001721# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001722 if (check_errno && is_negated_errno(r28)) {
1723 tcp->u_rval = -1;
1724 u_error = -r28;
1725 }
1726 else {
1727 tcp->u_rval = r28;
1728 u_error = 0;
1729 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001730# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001731 /* interpret R0 as return value or error number */
1732 if (check_errno && is_negated_errno(r0)) {
1733 tcp->u_rval = -1;
1734 u_error = -r0;
1735 }
1736 else {
1737 tcp->u_rval = r0;
1738 u_error = 0;
1739 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001740# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001741 /* interpret result as return value or error number */
1742 if (check_errno && is_negated_errno(r9)) {
1743 tcp->u_rval = -1;
1744 u_error = -r9;
1745 }
1746 else {
1747 tcp->u_rval = r9;
1748 u_error = 0;
1749 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001750# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001751 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1752 tcp->u_rval = -1;
1753 u_error = -r10;
1754 }
1755 else {
1756 tcp->u_rval = r10;
1757 u_error = 0;
1758 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001759# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001760 long rval;
1761 /* interpret result as return value or error number */
1762 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1763 return -1;
1764 if (check_errno && rval < 0 && rval > -nerrnos) {
1765 tcp->u_rval = -1;
1766 u_error = -rval;
1767 }
1768 else {
1769 tcp->u_rval = rval;
1770 u_error = 0;
1771 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001772# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001773 /* interpret result as return value or error number */
1774 if (check_errno && is_negated_errno(r3)) {
1775 tcp->u_rval = -1;
1776 u_error = -r3;
1777 }
1778 else {
1779 tcp->u_rval = r3;
1780 u_error = 0;
1781 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001782# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001783#endif /* LINUX */
1784#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001785 /* get error code from user struct */
1786 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1787 return -1;
1788 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001789
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001790 /* get system call return value */
1791 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1792 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001793#endif /* SUNOS4 */
1794#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001795# ifdef SPARC
1796 /* Judicious guessing goes a long way. */
1797 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1798 tcp->u_rval = -1;
1799 u_error = tcp->status.pr_reg[R_O0];
1800 }
1801 else {
1802 tcp->u_rval = tcp->status.pr_reg[R_O0];
1803 u_error = 0;
1804 }
1805# endif /* SPARC */
1806# ifdef I386
1807 /* Wanna know how to kill an hour single-stepping? */
1808 if (tcp->status.PR_REG[EFL] & 0x1) {
1809 tcp->u_rval = -1;
1810 u_error = tcp->status.PR_REG[EAX];
1811 }
1812 else {
1813 tcp->u_rval = tcp->status.PR_REG[EAX];
1814# ifdef HAVE_LONG_LONG
1815 tcp->u_lrval =
1816 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1817 tcp->status.PR_REG[EAX];
1818# endif
1819 u_error = 0;
1820 }
1821# endif /* I386 */
1822# ifdef X86_64
1823 /* Wanna know how to kill an hour single-stepping? */
1824 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1825 tcp->u_rval = -1;
1826 u_error = tcp->status.PR_REG[RAX];
1827 }
1828 else {
1829 tcp->u_rval = tcp->status.PR_REG[RAX];
1830 u_error = 0;
1831 }
1832# endif /* X86_64 */
1833# ifdef MIPS
1834 if (tcp->status.pr_reg[CTX_A3]) {
1835 tcp->u_rval = -1;
1836 u_error = tcp->status.pr_reg[CTX_V0];
1837 }
1838 else {
1839 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1840 u_error = 0;
1841 }
1842# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001843#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001844#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001845 if (regs.r_eflags & PSL_C) {
1846 tcp->u_rval = -1;
1847 u_error = regs.r_eax;
1848 } else {
1849 tcp->u_rval = regs.r_eax;
1850 tcp->u_lrval =
1851 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1852 u_error = 0;
1853 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001854#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001855 tcp->u_error = u_error;
1856 return 1;
1857}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001858
Roland McGrathb69f81b2002-12-21 23:25:18 +00001859int
Denys Vlasenko12014262011-05-30 14:00:14 +02001860force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001861{
1862#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001863# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001864 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001865 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1866 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001867# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001868 eax = error ? -error : rval;
1869 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1870 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001871# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001872 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001873 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001874 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001875# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001876 if (ia32) {
1877 r8 = error ? -error : rval;
1878 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1879 return -1;
1880 }
1881 else {
1882 if (error) {
1883 r8 = error;
1884 r10 = -1;
1885 }
1886 else {
1887 r8 = rval;
1888 r10 = 0;
1889 }
1890 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1891 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1892 return -1;
1893 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001894# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001895 r0 = error ? -error : rval;
1896 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1897 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001898# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001899 if (error) {
1900 r2 = error;
1901 a3 = -1;
1902 }
1903 else {
1904 r2 = rval;
1905 a3 = 0;
1906 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001907 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001908 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1909 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001910 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001911# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001912 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001913 return -1;
1914 if (error) {
1915 flags |= SO_MASK;
1916 result = error;
1917 }
1918 else {
1919 flags &= ~SO_MASK;
1920 result = rval;
1921 }
Roland McGratheb285352003-01-14 09:59:00 +00001922 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1923 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001924 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001925# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001926 d0 = error ? -error : rval;
1927 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1928 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001929# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001930 regs.ARM_r0 = error ? -error : rval;
1931 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001932 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001933# elif defined(AVR32)
1934 regs.r12 = error ? -error : rval;
1935 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1936 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001937# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001938 if (error) {
1939 a3 = -1;
1940 r0 = error;
1941 }
1942 else {
1943 a3 = 0;
1944 r0 = rval;
1945 }
1946 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1947 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1948 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001949# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001950 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1951 return -1;
1952 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001953 regs.psr |= PSR_C;
1954 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001955 }
1956 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001957 regs.psr &= ~PSR_C;
1958 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001959 }
1960 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1961 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001962# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001963 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1964 return -1;
1965 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001966 regs.tstate |= 0x1100000000UL;
1967 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001968 }
1969 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001970 regs.tstate &= ~0x1100000000UL;
1971 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001972 }
1973 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1974 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001975# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001976 r28 = error ? -error : rval;
1977 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1978 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001979# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001980 r0 = error ? -error : rval;
1981 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1982 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001983# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001984 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001985 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1986 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001987# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001988#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001989
Roland McGrathb69f81b2002-12-21 23:25:18 +00001990#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001991 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1992 error << 24) < 0 ||
1993 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001994 return -1;
1995#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001996
Roland McGrathb69f81b2002-12-21 23:25:18 +00001997#ifdef SVR4
1998 /* XXX no clue */
1999 return -1;
2000#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002001
Roland McGrathb69f81b2002-12-21 23:25:18 +00002002#ifdef FREEBSD
2003 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002004 perror("pread");
2005 return -1;
2006 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00002007 if (error) {
2008 regs.r_eflags |= PSL_C;
2009 regs.r_eax = error;
2010 }
2011 else {
2012 regs.r_eflags &= ~PSL_C;
2013 regs.r_eax = rval;
2014 }
2015 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002016 perror("pwrite");
2017 return -1;
2018 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00002019#endif /* FREEBSD */
2020
2021 /* All branches reach here on success (only). */
2022 tcp->u_error = error;
2023 tcp->u_rval = rval;
2024 return 0;
2025}
2026
Roland McGratha4d48532005-06-08 20:45:28 +00002027static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002028syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002029{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002030#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002031 int i, nargs;
2032
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002033 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002034 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002035 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002036 nargs = tcp->u_nargs = MAX_ARGS;
2037
2038# if defined(S390) || defined(S390X)
2039 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002040 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
2041 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002042# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002043 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002044 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
2045 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002046# elif defined(IA64)
2047 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002048 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002049 long rbs_end;
2050 /* be backwards compatible with kernel < 2.4.4... */
2051# ifndef PT_RBS_END
2052# define PT_RBS_END PT_AR_BSP
2053# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002054
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002055 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
2056 return -1;
2057 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002058 return -1;
2059
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002060 sof = (cfm >> 0) & 0x7f;
2061 sol = (cfm >> 7) & 0x7f;
2062 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
2063
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002064 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002065 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2066 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2067 return -1;
2068 }
2069 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002070 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
2071 PT_R9 /* ECX = out1 */,
2072 PT_R10 /* EDX = out2 */,
2073 PT_R14 /* ESI = out3 */,
2074 PT_R15 /* EDI = out4 */,
2075 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002076
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002077 for (i = 0; i < nargs; ++i) {
2078 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2079 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002080 /* truncate away IVE sign-extension */
2081 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002082 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002083 }
2084# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2085 /* N32 and N64 both use up to six registers. */
2086 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002087
2088 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2089 return -1;
2090
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002091 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002092 tcp->u_arg[i] = regs[REG_A0 + i];
2093# if defined(LINUX_MIPSN32)
2094 tcp->ext_arg[i] = regs[REG_A0 + i];
2095# endif
2096 }
2097# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002098 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002099 long sp;
2100
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002101 if (upeek(tcp, REG_SP, &sp) < 0)
2102 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002103 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002104 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2105 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002106 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002107 (char *)(tcp->u_arg + 4));
2108 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002109 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002110 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002111 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002112 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002113# elif defined(POWERPC)
2114# ifndef PT_ORIG_R3
2115# define PT_ORIG_R3 34
2116# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002117 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002118 if (upeek(tcp, (i==0) ?
2119 (sizeof(unsigned long) * PT_ORIG_R3) :
2120 ((i+PT_R3) * sizeof(unsigned long)),
2121 &tcp->u_arg[i]) < 0)
2122 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002123 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002124# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002125 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002126 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2127# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002128 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002129 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2130 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002131# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002132 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002133 tcp->u_arg[i] = regs.uregs[i];
2134# elif defined(AVR32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002135 static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
2136 &regs.r11,
2137 &regs.r10,
2138 &regs.r9,
2139 &regs.r5,
2140 &regs.r3 };
2141 for (i = 0; i < nargs; ++i)
2142 tcp->u_arg[i] = *argregp[i];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002143# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002144 static const int argreg[MAX_ARGS] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002145
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002146 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002147 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2148 return -1;
2149# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002150 static const int syscall_regs[MAX_ARGS] = {
2151 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
2152 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002153 };
2154
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002155 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002156 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002157 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002158# elif defined(SH64)
2159 int i;
2160 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002161 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002162
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002163 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002164 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2165 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002166# elif defined(X86_64)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002167 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2168 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2169 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002170 };
2171
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002172 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002173 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002174 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002175# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002176 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002177 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2178 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002179# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002180 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002181 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002182 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002183 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002184
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002185 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002186 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2187 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002188# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002189 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002190 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2191 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002192# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002193 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002194 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2195 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002196# else /* Other architecture (like i386) (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002197 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002198 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2199 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002200# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002201#endif /* LINUX */
2202#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002203 int i, nargs;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002204 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002205 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002206 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002207 nargs = tcp->u_nargs = MAX_ARGS;
2208 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002209 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002210
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002211 if (upeek(tcp, uoff(u_arg[0]) +
2212 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2213 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002214 }
2215#endif /* SUNOS4 */
2216#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002217# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002218 /*
2219 * SGI is broken: even though it has pr_sysarg, it doesn't
2220 * set them on system call entry. Get a clue.
2221 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002222 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002223 tcp->u_nargs = sysent[tcp->scno].nargs;
2224 else
2225 tcp->u_nargs = tcp->status.pr_nsysarg;
2226 if (tcp->u_nargs > 4) {
2227 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002228 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002229 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002230 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002231 }
2232 else {
2233 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002234 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002235 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002236# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002237 /*
2238 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2239 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002240 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
John Hughes25299712001-03-06 10:10:06 +00002241 tcp->u_nargs = sysent[tcp->scno].nargs;
2242 else
2243 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2244 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002245 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2246# elif defined(HAVE_PR_SYSCALL)
2247 int i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002248 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002249 tcp->u_nargs = sysent[tcp->scno].nargs;
2250 else
2251 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002252 for (i = 0; i < tcp->u_nargs; i++)
2253 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2254# elif defined(I386)
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002255 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002256 tcp->u_nargs = sysent[tcp->scno].nargs;
2257 else
2258 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002259 if (tcp->u_nargs > 0)
2260 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002261 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2262# else
John Hughes25299712001-03-06 10:10:06 +00002263 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002264# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002265#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002266#ifdef FREEBSD
2267 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2268 sysent[tcp->scno].nargs > tcp->status.val)
2269 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002270 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002271 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002272 if (tcp->u_nargs < 0)
2273 tcp->u_nargs = 0;
2274 if (tcp->u_nargs > MAX_ARGS)
2275 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002276 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002277 case SYS___syscall:
2278 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2279 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002280 break;
2281 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002282 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2283 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002284 break;
2285 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002286 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2287 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002288 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002289 }
2290#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002291 return 1;
2292}
2293
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002294static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002295trace_syscall_entering(struct tcb *tcp)
2296{
2297 int res, scno_good;
2298
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02002299 scno_good = res = get_scno_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002300 if (res == 0)
2301 return res;
2302 if (res == 1)
2303 res = syscall_fixup(tcp);
2304 if (res == 0)
2305 return res;
2306 if (res == 1)
2307 res = syscall_enter(tcp);
2308 if (res == 0)
2309 return res;
2310
2311 if (res != 1) {
2312 printleader(tcp);
2313 tcp->flags &= ~TCB_REPRINT;
2314 tcp_last = tcp;
2315 if (scno_good != 1)
2316 tprintf("????" /* anti-trigraph gap */ "(");
2317 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2318 tprintf("syscall_%lu(", tcp->scno);
2319 else
2320 tprintf("%s(", sysent[tcp->scno].sys_name);
2321 /*
2322 * " <unavailable>" will be added later by the code which
2323 * detects ptrace errors.
2324 */
2325 goto ret;
2326 }
2327
2328 switch (known_scno(tcp)) {
2329#ifdef SYS_socket_subcall
2330 case SYS_socketcall:
2331 decode_subcall(tcp, SYS_socket_subcall,
2332 SYS_socket_nsubcalls, deref_style);
2333 break;
2334#endif
2335#ifdef SYS_ipc_subcall
2336 case SYS_ipc:
2337 decode_subcall(tcp, SYS_ipc_subcall,
2338 SYS_ipc_nsubcalls, shift_style);
2339 break;
2340#endif
2341#ifdef SVR4
2342#ifdef SYS_pgrpsys_subcall
2343 case SYS_pgrpsys:
2344 decode_subcall(tcp, SYS_pgrpsys_subcall,
2345 SYS_pgrpsys_nsubcalls, shift_style);
2346 break;
2347#endif /* SYS_pgrpsys_subcall */
2348#ifdef SYS_sigcall_subcall
2349 case SYS_sigcall:
2350 decode_subcall(tcp, SYS_sigcall_subcall,
2351 SYS_sigcall_nsubcalls, mask_style);
2352 break;
2353#endif /* SYS_sigcall_subcall */
2354 case SYS_msgsys:
2355 decode_subcall(tcp, SYS_msgsys_subcall,
2356 SYS_msgsys_nsubcalls, shift_style);
2357 break;
2358 case SYS_shmsys:
2359 decode_subcall(tcp, SYS_shmsys_subcall,
2360 SYS_shmsys_nsubcalls, shift_style);
2361 break;
2362 case SYS_semsys:
2363 decode_subcall(tcp, SYS_semsys_subcall,
2364 SYS_semsys_nsubcalls, shift_style);
2365 break;
2366 case SYS_sysfs:
2367 decode_subcall(tcp, SYS_sysfs_subcall,
2368 SYS_sysfs_nsubcalls, shift_style);
2369 break;
2370 case SYS_spcall:
2371 decode_subcall(tcp, SYS_spcall_subcall,
2372 SYS_spcall_nsubcalls, shift_style);
2373 break;
2374#ifdef SYS_context_subcall
2375 case SYS_context:
2376 decode_subcall(tcp, SYS_context_subcall,
2377 SYS_context_nsubcalls, shift_style);
2378 break;
2379#endif /* SYS_context_subcall */
2380#ifdef SYS_door_subcall
2381 case SYS_door:
2382 decode_subcall(tcp, SYS_door_subcall,
2383 SYS_door_nsubcalls, door_style);
2384 break;
2385#endif /* SYS_door_subcall */
2386#ifdef SYS_kaio_subcall
2387 case SYS_kaio:
2388 decode_subcall(tcp, SYS_kaio_subcall,
2389 SYS_kaio_nsubcalls, shift_style);
2390 break;
2391#endif
2392#endif /* SVR4 */
2393#ifdef FREEBSD
2394 case SYS_msgsys:
2395 case SYS_shmsys:
2396 case SYS_semsys:
2397 decode_subcall(tcp, 0, 0, table_style);
2398 break;
2399#endif
2400#ifdef SUNOS4
2401 case SYS_semsys:
2402 decode_subcall(tcp, SYS_semsys_subcall,
2403 SYS_semsys_nsubcalls, shift_style);
2404 break;
2405 case SYS_msgsys:
2406 decode_subcall(tcp, SYS_msgsys_subcall,
2407 SYS_msgsys_nsubcalls, shift_style);
2408 break;
2409 case SYS_shmsys:
2410 decode_subcall(tcp, SYS_shmsys_subcall,
2411 SYS_shmsys_nsubcalls, shift_style);
2412 break;
2413#endif
2414 }
2415
2416 internal_syscall(tcp);
2417
2418 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2419 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2420 (tracing_paths && !pathtrace_match(tcp))) {
2421 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
2422 return 0;
2423 }
2424
2425 tcp->flags &= ~TCB_FILTERED;
2426
2427 if (cflag == CFLAG_ONLY_STATS) {
2428 res = 0;
2429 goto ret;
2430 }
2431
2432 printleader(tcp);
2433 tcp->flags &= ~TCB_REPRINT;
2434 tcp_last = tcp;
2435 if (tcp->scno >= nsyscalls || tcp->scno < 0)
2436 tprintf("syscall_%lu(", tcp->scno);
2437 else
2438 tprintf("%s(", sysent[tcp->scno].sys_name);
2439 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2440 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2441 sysent[tcp->scno].sys_func != sys_exit))
2442 res = printargs(tcp);
2443 else
2444 res = (*sysent[tcp->scno].sys_func)(tcp);
2445
2446 if (fflush(tcp->outf) == EOF)
2447 return -1;
2448 ret:
2449 tcp->flags |= TCB_INSYSCALL;
2450 /* Measure the entrance time as late as possible to avoid errors. */
2451 if (dtime || cflag)
2452 gettimeofday(&tcp->etime, NULL);
2453 return res;
2454}
2455
2456static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002457trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002458{
2459 int sys_res;
2460 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002461 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002462 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002463
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002464 /* Measure the exit time as early as possible to avoid errors. */
2465 if (dtime || cflag)
2466 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002467
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002468 /* BTW, why we don't just memorize syscall no. on entry
2469 * in tcp->something?
2470 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02002471 scno_good = res = get_scno_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002472 if (res == 0)
2473 return res;
2474 if (res == 1)
2475 res = syscall_fixup(tcp);
2476 if (res == 0)
2477 return res;
2478 if (res == 1)
2479 res = get_error(tcp);
2480 if (res == 0)
2481 return res;
2482 if (res == 1)
2483 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002484
Grant Edwards8a082772011-04-07 20:25:40 +00002485 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002486 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002487 }
2488
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002489 if (tcp->flags & TCB_REPRINT) {
2490 printleader(tcp);
2491 tprintf("<... ");
2492 if (scno_good != 1)
2493 tprintf("????");
2494 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2495 tprintf("syscall_%lu", tcp->scno);
2496 else
2497 tprintf("%s", sysent[tcp->scno].sys_name);
2498 tprintf(" resumed> ");
2499 }
2500
2501 if (cflag) {
2502 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002503 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002504 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002505 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002506 }
2507 }
2508
2509 if (res != 1) {
2510 tprintf(") ");
2511 tabto(acolumn);
2512 tprintf("= ? <unavailable>");
2513 printtrailer();
2514 tcp->flags &= ~TCB_INSYSCALL;
2515 return res;
2516 }
2517
2518 if (tcp->scno >= nsyscalls || tcp->scno < 0
2519 || (qual_flags[tcp->scno] & QUAL_RAW))
2520 sys_res = printargs(tcp);
2521 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002522 /* FIXME: not_failing_only (IOW, option -z) is broken:
2523 * failure of syscall is known only after syscall return.
2524 * Thus we end up with something like this on, say, ENOENT:
2525 * open("doesnt_exist", O_RDONLY <unfinished ...>
2526 * {next syscall decode}
2527 * whereas the intended result is that open(...) line
2528 * is not shown at all.
2529 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002530 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002531 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002532 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2533 }
2534
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002535 tprintf(") ");
2536 tabto(acolumn);
Denys Vlasenko3b738812011-08-22 02:06:35 +02002537 u_error = tcp->u_error;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002538 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2539 qual_flags[tcp->scno] & QUAL_RAW) {
2540 if (u_error)
2541 tprintf("= -1 (errno %ld)", u_error);
2542 else
2543 tprintf("= %#lx", tcp->u_rval);
2544 }
2545 else if (!(sys_res & RVAL_NONE) && u_error) {
2546 switch (u_error) {
2547#ifdef LINUX
2548 case ERESTARTSYS:
2549 tprintf("= ? ERESTARTSYS (To be restarted)");
2550 break;
2551 case ERESTARTNOINTR:
2552 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2553 break;
2554 case ERESTARTNOHAND:
2555 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2556 break;
2557 case ERESTART_RESTARTBLOCK:
2558 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2559 break;
2560#endif /* LINUX */
2561 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002562 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002563 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002564 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002565 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002566 strerror(u_error));
2567 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002568 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002569 strerror(u_error));
2570 break;
2571 }
2572 if ((sys_res & RVAL_STR) && tcp->auxstr)
2573 tprintf(" (%s)", tcp->auxstr);
2574 }
2575 else {
2576 if (sys_res & RVAL_NONE)
2577 tprintf("= ?");
2578 else {
2579 switch (sys_res & RVAL_MASK) {
2580 case RVAL_HEX:
2581 tprintf("= %#lx", tcp->u_rval);
2582 break;
2583 case RVAL_OCTAL:
2584 tprintf("= %#lo", tcp->u_rval);
2585 break;
2586 case RVAL_UDECIMAL:
2587 tprintf("= %lu", tcp->u_rval);
2588 break;
2589 case RVAL_DECIMAL:
2590 tprintf("= %ld", tcp->u_rval);
2591 break;
2592#ifdef HAVE_LONG_LONG
2593 case RVAL_LHEX:
2594 tprintf("= %#llx", tcp->u_lrval);
2595 break;
2596 case RVAL_LOCTAL:
2597 tprintf("= %#llo", tcp->u_lrval);
2598 break;
2599 case RVAL_LUDECIMAL:
2600 tprintf("= %llu", tcp->u_lrval);
2601 break;
2602 case RVAL_LDECIMAL:
2603 tprintf("= %lld", tcp->u_lrval);
2604 break;
2605#endif
2606 default:
2607 fprintf(stderr,
2608 "invalid rval format\n");
2609 break;
2610 }
2611 }
2612 if ((sys_res & RVAL_STR) && tcp->auxstr)
2613 tprintf(" (%s)", tcp->auxstr);
2614 }
2615 if (dtime) {
2616 tv_sub(&tv, &tv, &tcp->etime);
2617 tprintf(" <%ld.%06ld>",
2618 (long) tv.tv_sec, (long) tv.tv_usec);
2619 }
2620 printtrailer();
2621
2622 dumpio(tcp);
2623 if (fflush(tcp->outf) == EOF)
2624 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002625 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002626 tcp->flags &= ~TCB_INSYSCALL;
2627 return 0;
2628}
2629
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002630int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002631trace_syscall(struct tcb *tcp)
2632{
2633 return exiting(tcp) ?
2634 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2635}
2636
2637int
Denys Vlasenko12014262011-05-30 14:00:14 +02002638printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002639{
2640 if (entering(tcp)) {
2641 int i;
2642
2643 for (i = 0; i < tcp->u_nargs; i++)
2644 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2645 }
2646 return 0;
2647}
2648
2649long
Denys Vlasenko12014262011-05-30 14:00:14 +02002650getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651{
2652 long val = -1;
2653
2654#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002655#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002656 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002657 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002658 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002659 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002660#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002661 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002662 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002663#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002664 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002665 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002666#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002667#endif /* LINUX */
2668
2669#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002670 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002671 return -1;
2672#endif /* SUNOS4 */
2673
2674#ifdef SVR4
2675#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002676 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002677#endif /* SPARC */
2678#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002679 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002680#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002681#ifdef X86_64
2682 val = tcp->status.PR_REG[RDX];
2683#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002684#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002685 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002686#endif /* MIPS */
2687#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002688
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002689#ifdef FREEBSD
2690 struct reg regs;
2691 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2692 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002693#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694 return val;
2695}
2696
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002697#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002698/*
2699 * Apparently, indirect system calls have already be converted by ptrace(2),
2700 * so if you see "indir" this program has gone astray.
2701 */
2702int
Denys Vlasenko12014262011-05-30 14:00:14 +02002703sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002704{
2705 int i, scno, nargs;
2706
2707 if (entering(tcp)) {
Denys Vlasenko5d645812011-08-20 12:48:18 +02002708 scno = tcp->u_arg[0];
2709 if (scno > nsyscalls) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710 fprintf(stderr, "Bogus syscall: %u\n", scno);
2711 return 0;
2712 }
2713 nargs = sysent[scno].nargs;
2714 tprintf("%s", sysent[scno].sys_name);
2715 for (i = 0; i < nargs; i++)
2716 tprintf(", %#lx", tcp->u_arg[i+1]);
2717 }
2718 return 0;
2719}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002720#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002721
2722int
2723is_restart_error(struct tcb *tcp)
2724{
2725#ifdef LINUX
2726 if (!syserror(tcp))
2727 return 0;
2728 switch (tcp->u_error) {
2729 case ERESTARTSYS:
2730 case ERESTARTNOINTR:
2731 case ERESTARTNOHAND:
2732 case ERESTART_RESTARTBLOCK:
2733 return 1;
2734 default:
2735 break;
2736 }
2737#endif /* LINUX */
2738 return 0;
2739}