blob: cb4bef9f9875eac0ae75131fee42ae3e5e850d6f [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) {
758 /*
759 * When the execve system call completes successfully, the
760 * new process still has -ENOSYS (old style) or __NR_execve
761 * (new style) in gpr2. We cannot recover the scno again
762 * by disassembly, because the image that executed the
763 * syscall is gone now. Fortunately, we don't want it. We
764 * leave the flag set so that syscall_fixup can fake the
765 * result.
766 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200767 if (exiting(tcp))
Roland McGrath96dc5142003-01-20 10:23:04 +0000768 return 1;
769 /*
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200770 * This is the post-execve SIGTRAP. We cannot try to read
Roland McGrath96dc5142003-01-20 10:23:04 +0000771 * the system call here either.
772 */
773 tcp->flags &= ~TCB_WAITEXECVE;
774 return 0;
775 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000776
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000777 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200778 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000779
780 if (syscall_mode != -ENOSYS) {
781 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000782 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000783 */
784 scno = syscall_mode;
785 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000786 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000787 * Old style of "passing" the scno via the SVC instruction.
788 */
789
790 long opcode, offset_reg, tmp;
791 void * svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200792 static const int gpr_offset[16] = {
793 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
794 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
795 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
796 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
797 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000798
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000799 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000800 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000801 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000802 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000803 if (errno) {
804 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000805 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000806 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000807
808 /*
809 * We have to check if the SVC got executed directly or via an
810 * EXECUTE instruction. In case of EXECUTE it is necessary to do
811 * instruction decoding to derive the system call number.
812 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
813 * so that this doesn't work if a SVC opcode is part of an EXECUTE
814 * opcode. Since there is no way to find out the opcode size this
815 * is the best we can do...
816 */
817
818 if ((opcode & 0xff00) == 0x0a00) {
819 /* SVC opcode */
820 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000821 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000822 else {
823 /* SVC got executed by EXECUTE instruction */
824
825 /*
826 * Do instruction decoding of EXECUTE. If you really want to
827 * understand this, read the Principles of Operations.
828 */
829 svc_addr = (void *) (opcode & 0xfff);
830
831 tmp = 0;
832 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000833 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000834 return -1;
835 svc_addr += tmp;
836
837 tmp = 0;
838 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000839 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000840 return -1;
841 svc_addr += tmp;
842
Denys Vlasenkofb036672009-01-23 16:30:26 +0000843 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000844 if (errno)
845 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000846# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000847 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000848# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000849 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000850# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000851 tmp = 0;
852 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000853 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000854 return -1;
855
856 scno = (scno | tmp) & 0xff;
857 }
858 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000859# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000860 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000861 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200862 if (entering(tcp)) {
863 /* Check if this is the post-execve SIGTRAP. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000864 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
865 tcp->flags &= ~TCB_WAITEXECVE;
866 return 0;
867 }
868 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200869
870# ifdef POWERPC64
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200871 if (entering(tcp)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200872 /* TODO: speed up strace by not doing this at every syscall.
873 * We only need to do it after execve.
874 */
875 int currpers;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200876 long val;
877 int pid = tcp->pid;
878
879 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200880 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200881 return -1;
882 /* SF is bit 0 of MSR */
883 if (val < 0)
884 currpers = 0;
885 else
886 currpers = 1;
887 if (currpers != current_personality) {
888 static const char *const names[] = {"64 bit", "32 bit"};
889 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000890 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200891 pid, names[current_personality]);
892 }
893 }
894# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000895# elif defined(AVR32)
896 /*
897 * Read complete register set in one go.
898 */
899 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
900 return -1;
901
902 /*
903 * We only need to grab the syscall number on syscall entry.
904 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200905 if (entering(tcp)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000906 scno = regs.r8;
907
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200908 /* Check if this is the post-execve SIGTRAP. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000909 if (tcp->flags & TCB_WAITEXECVE) {
910 tcp->flags &= ~TCB_WAITEXECVE;
911 return 0;
912 }
913 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000914# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000915 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000916 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000917# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000918 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000919 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000920# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000921 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000922 return -1;
923
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200924 if (entering(tcp)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200925 /* TODO: speed up strace by not doing this at every syscall.
926 * We only need to do it after execve.
927 */
928 int currpers;
Michal Ludvig0e035502002-09-23 15:41:01 +0000929 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000930 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000931
932 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200933 * 0x33 for long mode (64 bit)
934 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000935 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000936 * to be cached.
937 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000938 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000939 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000940 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000941 case 0x23: currpers = 1; break;
942 case 0x33: currpers = 0; break;
943 default:
944 fprintf(stderr, "Unknown value CS=0x%02X while "
945 "detecting personality of process "
946 "PID=%d\n", (int)val, pid);
947 currpers = current_personality;
948 break;
949 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000950# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000951 /* This version analyzes the opcode of a syscall instruction.
952 * (int 0x80 on i386 vs. syscall on x86-64)
953 * It works, but is too complicated.
954 */
955 unsigned long val, rip, i;
956
Denys Vlasenko8236f252009-01-02 18:10:08 +0000957 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000958 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000959
Michal Ludvig0e035502002-09-23 15:41:01 +0000960 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000961 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000962 errno = 0;
963
Denys Vlasenko8236f252009-01-02 18:10:08 +0000964 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000965 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000966 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000967 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000968 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000969 /* x86-64: syscall = 0x0f 0x05 */
970 case 0x050f: currpers = 0; break;
971 /* i386: int 0x80 = 0xcd 0x80 */
972 case 0x80cd: currpers = 1; break;
973 default:
974 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000975 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000976 "Unknown syscall opcode (0x%04X) while "
977 "detecting personality of process "
978 "PID=%d\n", (int)call, pid);
979 break;
980 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000981# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000982 if (currpers != current_personality) {
983 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000984 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000985 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000986 pid, names[current_personality]);
987 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000988 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000989# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000990# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200991 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000992 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200993 if (entering(tcp)) {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000994 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000995 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000996 return -1;
997 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200998 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000999 return -1;
1000 }
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001001 /* Check if this is the post-execve SIGTRAP. */
Roland McGrathba954762003-03-05 06:29:06 +00001002 if (tcp->flags & TCB_WAITEXECVE) {
1003 tcp->flags &= ~TCB_WAITEXECVE;
1004 return 0;
1005 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001006 } else {
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001007 /* Syscall exit */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001008 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001009 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001010 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001011 return -1;
1012 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001013# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001014 /*
1015 * Read complete register set in one go.
1016 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001017 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001018 return -1;
1019
1020 /*
1021 * We only need to grab the syscall number on syscall entry.
1022 */
1023 if (regs.ARM_ip == 0) {
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001024 if (entering(tcp)) {
1025 /* Check if this is the post-execve SIGTRAP. */
Roland McGrath9bc63402007-11-01 21:42:18 +00001026 if (tcp->flags & TCB_WAITEXECVE) {
1027 tcp->flags &= ~TCB_WAITEXECVE;
1028 return 0;
1029 }
1030 }
1031
Roland McGrath0f87c492003-06-03 23:29:04 +00001032 /*
1033 * Note: we only deal with only 32-bit CPUs here.
1034 */
1035 if (regs.ARM_cpsr & 0x20) {
1036 /*
1037 * Get the Thumb-mode system call number
1038 */
1039 scno = regs.ARM_r7;
1040 } else {
1041 /*
1042 * Get the ARM-mode system call number
1043 */
1044 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001045 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001046 if (errno)
1047 return -1;
1048
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001049 /* FIXME: bogus check? it is already done on entering before,
1050 * so we never can see it here?
1051 */
Roland McGrath0f87c492003-06-03 23:29:04 +00001052 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1053 tcp->flags &= ~TCB_WAITEXECVE;
1054 return 0;
1055 }
1056
Roland McGrathf691bd22006-04-25 07:34:41 +00001057 /* Handle the EABI syscall convention. We do not
1058 bother converting structures between the two
1059 ABIs, but basic functionality should work even
1060 if strace and the traced program have different
1061 ABIs. */
1062 if (scno == 0xef000000) {
1063 scno = regs.ARM_r7;
1064 } else {
1065 if ((scno & 0x0ff00000) != 0x0f900000) {
1066 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1067 scno);
1068 return -1;
1069 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001070
Roland McGrathf691bd22006-04-25 07:34:41 +00001071 /*
1072 * Fixup the syscall number
1073 */
1074 scno &= 0x000fffff;
1075 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001076 }
Roland McGrath56703312008-05-20 01:35:55 +00001077 if (scno & 0x0f0000) {
1078 /*
1079 * Handle ARM specific syscall
1080 */
1081 set_personality(1);
1082 scno &= 0x0000ffff;
1083 } else
1084 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001085
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001086 if (exiting(tcp)) {
1087 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
Roland McGrath0f87c492003-06-03 23:29:04 +00001088 tcp->flags &= ~TCB_INSYSCALL;
1089 }
1090 } else {
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001091 if (entering(tcp)) {
1092 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
Roland McGrath0f87c492003-06-03 23:29:04 +00001093 tcp->flags |= TCB_INSYSCALL;
1094 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001095 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001096# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001097 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001099# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001100 unsigned long long regs[38];
1101
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001102 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001103 return -1;
1104 a3 = regs[REG_A3];
1105 r2 = regs[REG_V0];
1106
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001107 if (entering(tcp)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001108 scno = r2;
1109
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001110 /* Check if this is the post-execve SIGTRAP. */
Roland McGrath542c2c62008-05-20 01:11:56 +00001111 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1112 tcp->flags &= ~TCB_WAITEXECVE;
1113 return 0;
1114 }
1115
1116 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001117 if (a3 == 0 || a3 == -1) {
1118 if (debug)
1119 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001120 return 0;
1121 }
1122 }
1123 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001124# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001125 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001126 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001127 if (entering(tcp)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001128 if (upeek(tcp, REG_V0, &scno) < 0)
1129 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001130
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001131 /* Check if this is the post-execve SIGTRAP. */
Roland McGrath542c2c62008-05-20 01:11:56 +00001132 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1133 tcp->flags &= ~TCB_WAITEXECVE;
1134 return 0;
1135 }
1136
Wichert Akkermanf90da011999-10-31 21:15:38 +00001137 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001138 if (a3 == 0 || a3 == -1) {
1139 if (debug)
1140 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001141 return 0;
1142 }
1143 }
1144 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001145 if (upeek(tcp, REG_V0, &r2) < 0)
1146 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001147 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001148# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001149 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150 return -1;
1151
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001152 if (entering(tcp)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001153 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001154 return -1;
1155
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001156 /* Check if this is the post-execve SIGTRAP. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1158 tcp->flags &= ~TCB_WAITEXECVE;
1159 return 0;
1160 }
1161
1162 /*
1163 * Do some sanity checks to figure out if it's
1164 * really a syscall entry
1165 */
1166 if (scno < 0 || scno > nsyscalls) {
1167 if (a3 == 0 || a3 == -1) {
1168 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001169 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001170 return 0;
1171 }
1172 }
1173 }
1174 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001175 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 return -1;
1177 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001178# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001180 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 return -1;
1182
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001183 /* If we are entering, then disassemble the syscall trap. */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001184 if (entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185 /* Retrieve the syscall trap instruction. */
1186 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001187# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001188 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001189 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001190# else
1191 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001192# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 if (errno)
1194 return -1;
1195
1196 /* Disassemble the trap to see what personality to use. */
1197 switch (trap) {
1198 case 0x91d02010:
1199 /* Linux/SPARC syscall trap. */
1200 set_personality(0);
1201 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001202 case 0x91d0206d:
1203 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001204 set_personality(2);
1205 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001206 case 0x91d02000:
1207 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001208 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001209 return -1;
1210 case 0x91d02008:
1211 /* Solaris 2.x syscall trap. (per 2) */
1212 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001213 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001214 case 0x91d02009:
1215 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001216 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001217 return -1;
1218 case 0x91d02027:
1219 /* Solaris 2.x gettimeofday */
1220 set_personality(1);
1221 break;
1222 default:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001223 /* Check if this is the post-execve SIGTRAP. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001224 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001225 tcp->flags &= ~TCB_WAITEXECVE;
1226 return 0;
1227 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001228# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001229 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001230# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001231 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001232# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233 return -1;
1234 }
1235
1236 /* Extract the system call number from the registers. */
1237 if (trap == 0x91d02027)
1238 scno = 156;
1239 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001240 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001241 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001242 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001243 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001244 }
1245 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001246# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001247 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001248 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001249 if (entering(tcp)) {
1250 /* Check if this is the post-execve SIGTRAP. */
1251 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001252 tcp->flags &= ~TCB_WAITEXECVE;
1253 return 0;
1254 }
1255 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001256# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001257 /*
1258 * In the new syscall ABI, the system call number is in R3.
1259 */
1260 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1261 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001262
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001263 if (scno < 0) {
1264 /* Odd as it may seem, a glibc bug has been known to cause
1265 glibc to issue bogus negative syscall numbers. So for
1266 our purposes, make strace print what it *should* have been */
1267 long correct_scno = (scno & 0xff);
1268 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001269 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001270 "Detected glibc bug: bogus system call"
1271 " number = %ld, correcting to %ld\n",
1272 scno,
1273 correct_scno);
1274 scno = correct_scno;
1275 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001276
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001277 if (entering(tcp)) {
1278 /* Check if this is the post-execve SIGTRAP. */
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001279 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1280 tcp->flags &= ~TCB_WAITEXECVE;
1281 return 0;
1282 }
1283 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001284# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001285 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001286 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001287 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001288
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001289 if (entering(tcp)) {
1290 /* Check if this is the post-execve SIGTRAP. */
Roland McGrathe1e584b2003-06-02 19:18:58 +00001291 if (tcp->flags & TCB_WAITEXECVE) {
1292 tcp->flags &= ~TCB_WAITEXECVE;
1293 return 0;
1294 }
1295 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001296# elif defined(CRISV10) || defined(CRISV32)
1297 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1298 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001299# elif defined(TILE)
1300 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1301 return -1;
1302
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001303 if (entering(tcp)) {
1304 /* Check if this is the post-execve SIGTRAP. */
Chris Metcalfc8c66982009-12-28 10:00:15 -05001305 if (tcp->flags & TCB_WAITEXECVE) {
1306 tcp->flags &= ~TCB_WAITEXECVE;
1307 return 0;
1308 }
1309 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001310# elif defined(MICROBLAZE)
1311 if (upeek(tcp, 0, &scno) < 0)
1312 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001313# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001315
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001317 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001319#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001320 /* new syscall ABI returns result in R0 */
1321 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1322 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001323#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001324 /* ABI defines result returned in r9 */
1325 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1326 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001328
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001329#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001330# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001331 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001332# else
1333# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001334 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001335# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001336 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001337 perror("pread");
1338 return -1;
1339 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001340 switch (regs.r_eax) {
1341 case SYS_syscall:
1342 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001343 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1344 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001345 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001346 scno = regs.r_eax;
1347 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001348 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001349# endif /* FREEBSD */
1350# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001351#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001352
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001353 if (entering(tcp))
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001354 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001355 return 1;
1356}
1357
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001358/* Returns:
1359 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1360 * 1: ok, continue in trace_syscall().
1361 * other: error, trace_syscall() should print error indicator
1362 * ("????" etc) and bail out.
1363 */
1364static int
1365get_scno_on_sysexit(struct tcb *tcp)
1366{
1367 long scno = 0;
1368
1369#ifdef LINUX
1370# if defined(S390) || defined(S390X)
1371 if (tcp->flags & TCB_WAITEXECVE) {
1372 /*
1373 * When the execve system call completes successfully, the
1374 * new process still has -ENOSYS (old style) or __NR_execve
1375 * (new style) in gpr2. We cannot recover the scno again
1376 * by disassembly, because the image that executed the
1377 * syscall is gone now. Fortunately, we don't want it. We
1378 * leave the flag set so that syscall_fixup can fake the
1379 * result.
1380 */
1381 if (exiting(tcp))
1382 return 1;
1383 /*
1384 * This is the post-execve SIGTRAP. We cannot try to read
1385 * the system call here either.
1386 */
1387 tcp->flags &= ~TCB_WAITEXECVE;
1388 return 0;
1389 }
1390
1391 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
1392 return -1;
1393
1394 if (syscall_mode != -ENOSYS) {
1395 /*
1396 * Since kernel version 2.5.44 the scno gets passed in gpr2.
1397 */
1398 scno = syscall_mode;
1399 } else {
1400 /*
1401 * Old style of "passing" the scno via the SVC instruction.
1402 */
1403
1404 long opcode, offset_reg, tmp;
1405 void * svc_addr;
1406 static const int gpr_offset[16] = {
1407 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
1408 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
1409 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
1410 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
1411 };
1412
1413 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
1414 return -1;
1415 errno = 0;
1416 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
1417 if (errno) {
1418 perror("peektext(pc-oneword)");
1419 return -1;
1420 }
1421
1422 /*
1423 * We have to check if the SVC got executed directly or via an
1424 * EXECUTE instruction. In case of EXECUTE it is necessary to do
1425 * instruction decoding to derive the system call number.
1426 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
1427 * so that this doesn't work if a SVC opcode is part of an EXECUTE
1428 * opcode. Since there is no way to find out the opcode size this
1429 * is the best we can do...
1430 */
1431
1432 if ((opcode & 0xff00) == 0x0a00) {
1433 /* SVC opcode */
1434 scno = opcode & 0xff;
1435 }
1436 else {
1437 /* SVC got executed by EXECUTE instruction */
1438
1439 /*
1440 * Do instruction decoding of EXECUTE. If you really want to
1441 * understand this, read the Principles of Operations.
1442 */
1443 svc_addr = (void *) (opcode & 0xfff);
1444
1445 tmp = 0;
1446 offset_reg = (opcode & 0x000f0000) >> 16;
1447 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
1448 return -1;
1449 svc_addr += tmp;
1450
1451 tmp = 0;
1452 offset_reg = (opcode & 0x0000f000) >> 12;
1453 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
1454 return -1;
1455 svc_addr += tmp;
1456
1457 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
1458 if (errno)
1459 return -1;
1460# if defined(S390X)
1461 scno >>= 48;
1462# else
1463 scno >>= 16;
1464# endif
1465 tmp = 0;
1466 offset_reg = (opcode & 0x00f00000) >> 20;
1467 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
1468 return -1;
1469
1470 scno = (scno | tmp) & 0xff;
1471 }
1472 }
1473# elif defined (POWERPC)
1474 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
1475 return -1;
1476 if (entering(tcp)) {
1477 /* Check if this is the post-execve SIGTRAP. */
1478 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1479 tcp->flags &= ~TCB_WAITEXECVE;
1480 return 0;
1481 }
1482 }
1483
1484# ifdef POWERPC64
1485 if (entering(tcp)) {
1486 /* TODO: speed up strace by not doing this at every syscall.
1487 * We only need to do it after execve.
1488 */
1489 int currpers;
1490 long val;
1491 int pid = tcp->pid;
1492
1493 /* Check for 64/32 bit mode. */
1494 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
1495 return -1;
1496 /* SF is bit 0 of MSR */
1497 if (val < 0)
1498 currpers = 0;
1499 else
1500 currpers = 1;
1501 if (currpers != current_personality) {
1502 static const char *const names[] = {"64 bit", "32 bit"};
1503 set_personality(currpers);
1504 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
1505 pid, names[current_personality]);
1506 }
1507 }
1508# endif
1509# elif defined(AVR32)
1510 /*
1511 * Read complete register set in one go.
1512 */
1513 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1514 return -1;
1515
1516 /*
1517 * We only need to grab the syscall number on syscall entry.
1518 */
1519 if (entering(tcp)) {
1520 scno = regs.r8;
1521
1522 /* Check if this is the post-execve SIGTRAP. */
1523 if (tcp->flags & TCB_WAITEXECVE) {
1524 tcp->flags &= ~TCB_WAITEXECVE;
1525 return 0;
1526 }
1527 }
1528# elif defined(BFIN)
1529 if (upeek(tcp, PT_ORIG_P0, &scno))
1530 return -1;
1531# elif defined (I386)
1532 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
1533 return -1;
1534# elif defined (X86_64)
1535 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
1536 return -1;
1537
1538 if (entering(tcp)) {
1539 /* TODO: speed up strace by not doing this at every syscall.
1540 * We only need to do it after execve.
1541 */
1542 int currpers;
1543 long val;
1544 int pid = tcp->pid;
1545
1546 /* Check CS register value. On x86-64 linux it is:
1547 * 0x33 for long mode (64 bit)
1548 * 0x23 for compatibility mode (32 bit)
1549 * It takes only one ptrace and thus doesn't need
1550 * to be cached.
1551 */
1552 if (upeek(tcp, 8*CS, &val) < 0)
1553 return -1;
1554 switch (val) {
1555 case 0x23: currpers = 1; break;
1556 case 0x33: currpers = 0; break;
1557 default:
1558 fprintf(stderr, "Unknown value CS=0x%02X while "
1559 "detecting personality of process "
1560 "PID=%d\n", (int)val, pid);
1561 currpers = current_personality;
1562 break;
1563 }
1564# if 0
1565 /* This version analyzes the opcode of a syscall instruction.
1566 * (int 0x80 on i386 vs. syscall on x86-64)
1567 * It works, but is too complicated.
1568 */
1569 unsigned long val, rip, i;
1570
1571 if (upeek(tcp, 8*RIP, &rip) < 0)
1572 perror("upeek(RIP)");
1573
1574 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
1575 rip -= 2;
1576 errno = 0;
1577
1578 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
1579 if (errno)
1580 fprintf(stderr, "ptrace_peektext failed: %s\n",
1581 strerror(errno));
1582 switch (call & 0xffff) {
1583 /* x86-64: syscall = 0x0f 0x05 */
1584 case 0x050f: currpers = 0; break;
1585 /* i386: int 0x80 = 0xcd 0x80 */
1586 case 0x80cd: currpers = 1; break;
1587 default:
1588 currpers = current_personality;
1589 fprintf(stderr,
1590 "Unknown syscall opcode (0x%04X) while "
1591 "detecting personality of process "
1592 "PID=%d\n", (int)call, pid);
1593 break;
1594 }
1595# endif
1596 if (currpers != current_personality) {
1597 static const char *const names[] = {"64 bit", "32 bit"};
1598 set_personality(currpers);
1599 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
1600 pid, names[current_personality]);
1601 }
1602 }
1603# elif defined(IA64)
1604# define IA64_PSR_IS ((long)1 << 34)
1605 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1606 ia32 = (psr & IA64_PSR_IS) != 0;
1607 if (entering(tcp)) {
1608 if (ia32) {
1609 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
1610 return -1;
1611 } else {
1612 if (upeek(tcp, PT_R15, &scno) < 0)
1613 return -1;
1614 }
1615 /* Check if this is the post-execve SIGTRAP. */
1616 if (tcp->flags & TCB_WAITEXECVE) {
1617 tcp->flags &= ~TCB_WAITEXECVE;
1618 return 0;
1619 }
1620 } else {
1621 /* Syscall exit */
1622 if (upeek(tcp, PT_R8, &r8) < 0)
1623 return -1;
1624 if (upeek(tcp, PT_R10, &r10) < 0)
1625 return -1;
1626 }
1627# elif defined (ARM)
1628 /*
1629 * Read complete register set in one go.
1630 */
1631 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1632 return -1;
1633
1634 /*
1635 * We only need to grab the syscall number on syscall entry.
1636 */
1637 if (regs.ARM_ip == 0) {
1638 if (entering(tcp)) {
1639 /* Check if this is the post-execve SIGTRAP. */
1640 if (tcp->flags & TCB_WAITEXECVE) {
1641 tcp->flags &= ~TCB_WAITEXECVE;
1642 return 0;
1643 }
1644 }
1645
1646 /*
1647 * Note: we only deal with only 32-bit CPUs here.
1648 */
1649 if (regs.ARM_cpsr & 0x20) {
1650 /*
1651 * Get the Thumb-mode system call number
1652 */
1653 scno = regs.ARM_r7;
1654 } else {
1655 /*
1656 * Get the ARM-mode system call number
1657 */
1658 errno = 0;
1659 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
1660 if (errno)
1661 return -1;
1662
1663 /* FIXME: bogus check? it is already done on entering before,
1664 * so we never can see it here?
1665 */
1666 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1667 tcp->flags &= ~TCB_WAITEXECVE;
1668 return 0;
1669 }
1670
1671 /* Handle the EABI syscall convention. We do not
1672 bother converting structures between the two
1673 ABIs, but basic functionality should work even
1674 if strace and the traced program have different
1675 ABIs. */
1676 if (scno == 0xef000000) {
1677 scno = regs.ARM_r7;
1678 } else {
1679 if ((scno & 0x0ff00000) != 0x0f900000) {
1680 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1681 scno);
1682 return -1;
1683 }
1684
1685 /*
1686 * Fixup the syscall number
1687 */
1688 scno &= 0x000fffff;
1689 }
1690 }
1691 if (scno & 0x0f0000) {
1692 /*
1693 * Handle ARM specific syscall
1694 */
1695 set_personality(1);
1696 scno &= 0x0000ffff;
1697 } else
1698 set_personality(0);
1699
1700 if (exiting(tcp)) {
1701 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1702 tcp->flags &= ~TCB_INSYSCALL;
1703 }
1704 } else {
1705 if (entering(tcp)) {
1706 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1707 tcp->flags |= TCB_INSYSCALL;
1708 }
1709 }
1710# elif defined (M68K)
1711 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
1712 return -1;
1713# elif defined (LINUX_MIPSN32)
1714 unsigned long long regs[38];
1715
1716 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1717 return -1;
1718 a3 = regs[REG_A3];
1719 r2 = regs[REG_V0];
1720
1721 if (entering(tcp)) {
1722 scno = r2;
1723
1724 /* Check if this is the post-execve SIGTRAP. */
1725 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1726 tcp->flags &= ~TCB_WAITEXECVE;
1727 return 0;
1728 }
1729
1730 if (scno < 0 || scno > nsyscalls) {
1731 if (a3 == 0 || a3 == -1) {
1732 if (debug)
1733 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
1734 return 0;
1735 }
1736 }
1737 }
1738# elif defined (MIPS)
1739 if (upeek(tcp, REG_A3, &a3) < 0)
1740 return -1;
1741 if (entering(tcp)) {
1742 if (upeek(tcp, REG_V0, &scno) < 0)
1743 return -1;
1744
1745 /* Check if this is the post-execve SIGTRAP. */
1746 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1747 tcp->flags &= ~TCB_WAITEXECVE;
1748 return 0;
1749 }
1750
1751 if (scno < 0 || scno > nsyscalls) {
1752 if (a3 == 0 || a3 == -1) {
1753 if (debug)
1754 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
1755 return 0;
1756 }
1757 }
1758 } else {
1759 if (upeek(tcp, REG_V0, &r2) < 0)
1760 return -1;
1761 }
1762# elif defined (ALPHA)
1763 if (upeek(tcp, REG_A3, &a3) < 0)
1764 return -1;
1765
1766 if (entering(tcp)) {
1767 if (upeek(tcp, REG_R0, &scno) < 0)
1768 return -1;
1769
1770 /* Check if this is the post-execve SIGTRAP. */
1771 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1772 tcp->flags &= ~TCB_WAITEXECVE;
1773 return 0;
1774 }
1775
1776 /*
1777 * Do some sanity checks to figure out if it's
1778 * really a syscall entry
1779 */
1780 if (scno < 0 || scno > nsyscalls) {
1781 if (a3 == 0 || a3 == -1) {
1782 if (debug)
1783 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
1784 return 0;
1785 }
1786 }
1787 }
1788 else {
1789 if (upeek(tcp, REG_R0, &r0) < 0)
1790 return -1;
1791 }
1792# elif defined (SPARC) || defined (SPARC64)
1793 /* Everything we need is in the current register set. */
1794 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1795 return -1;
1796
1797 /* If we are entering, then disassemble the syscall trap. */
1798 if (entering(tcp)) {
1799 /* Retrieve the syscall trap instruction. */
1800 errno = 0;
1801# if defined(SPARC64)
1802 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1803 trap >>= 32;
1804# else
1805 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
1806# endif
1807 if (errno)
1808 return -1;
1809
1810 /* Disassemble the trap to see what personality to use. */
1811 switch (trap) {
1812 case 0x91d02010:
1813 /* Linux/SPARC syscall trap. */
1814 set_personality(0);
1815 break;
1816 case 0x91d0206d:
1817 /* Linux/SPARC64 syscall trap. */
1818 set_personality(2);
1819 break;
1820 case 0x91d02000:
1821 /* SunOS syscall trap. (pers 1) */
1822 fprintf(stderr, "syscall: SunOS no support\n");
1823 return -1;
1824 case 0x91d02008:
1825 /* Solaris 2.x syscall trap. (per 2) */
1826 set_personality(1);
1827 break;
1828 case 0x91d02009:
1829 /* NetBSD/FreeBSD syscall trap. */
1830 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1831 return -1;
1832 case 0x91d02027:
1833 /* Solaris 2.x gettimeofday */
1834 set_personality(1);
1835 break;
1836 default:
1837 /* Check if this is the post-execve SIGTRAP. */
1838 if (tcp->flags & TCB_WAITEXECVE) {
1839 tcp->flags &= ~TCB_WAITEXECVE;
1840 return 0;
1841 }
1842# if defined (SPARC64)
1843 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1844# else
1845 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1846# endif
1847 return -1;
1848 }
1849
1850 /* Extract the system call number from the registers. */
1851 if (trap == 0x91d02027)
1852 scno = 156;
1853 else
1854 scno = regs.u_regs[U_REG_G1];
1855 if (scno == 0) {
1856 scno = regs.u_regs[U_REG_O0];
1857 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1858 }
1859 }
1860# elif defined(HPPA)
1861 if (upeek(tcp, PT_GR20, &scno) < 0)
1862 return -1;
1863 if (entering(tcp)) {
1864 /* Check if this is the post-execve SIGTRAP. */
1865 if (tcp->flags & TCB_WAITEXECVE) {
1866 tcp->flags &= ~TCB_WAITEXECVE;
1867 return 0;
1868 }
1869 }
1870# elif defined(SH)
1871 /*
1872 * In the new syscall ABI, the system call number is in R3.
1873 */
1874 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1875 return -1;
1876
1877 if (scno < 0) {
1878 /* Odd as it may seem, a glibc bug has been known to cause
1879 glibc to issue bogus negative syscall numbers. So for
1880 our purposes, make strace print what it *should* have been */
1881 long correct_scno = (scno & 0xff);
1882 if (debug)
1883 fprintf(stderr,
1884 "Detected glibc bug: bogus system call"
1885 " number = %ld, correcting to %ld\n",
1886 scno,
1887 correct_scno);
1888 scno = correct_scno;
1889 }
1890
1891 if (entering(tcp)) {
1892 /* Check if this is the post-execve SIGTRAP. */
1893 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1894 tcp->flags &= ~TCB_WAITEXECVE;
1895 return 0;
1896 }
1897 }
1898# elif defined(SH64)
1899 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
1900 return -1;
1901 scno &= 0xFFFF;
1902
1903 if (entering(tcp)) {
1904 /* Check if this is the post-execve SIGTRAP. */
1905 if (tcp->flags & TCB_WAITEXECVE) {
1906 tcp->flags &= ~TCB_WAITEXECVE;
1907 return 0;
1908 }
1909 }
1910# elif defined(CRISV10) || defined(CRISV32)
1911 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1912 return -1;
1913# elif defined(TILE)
1914 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1915 return -1;
1916
1917 if (entering(tcp)) {
1918 /* Check if this is the post-execve SIGTRAP. */
1919 if (tcp->flags & TCB_WAITEXECVE) {
1920 tcp->flags &= ~TCB_WAITEXECVE;
1921 return 0;
1922 }
1923 }
1924# elif defined(MICROBLAZE)
1925 if (upeek(tcp, 0, &scno) < 0)
1926 return -1;
1927# endif
1928#endif /* LINUX */
1929
1930#ifdef SUNOS4
1931 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
1932 return -1;
1933#elif defined(SH)
1934 /* new syscall ABI returns result in R0 */
1935 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1936 return -1;
1937#elif defined(SH64)
1938 /* ABI defines result returned in r9 */
1939 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1940 return -1;
1941#endif
1942
1943#ifdef USE_PROCFS
1944# ifdef HAVE_PR_SYSCALL
1945 scno = tcp->status.PR_SYSCALL;
1946# else
1947# ifndef FREEBSD
1948 scno = tcp->status.PR_WHAT;
1949# else
1950 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1951 perror("pread");
1952 return -1;
1953 }
1954 switch (regs.r_eax) {
1955 case SYS_syscall:
1956 case SYS___syscall:
1957 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1958 break;
1959 default:
1960 scno = regs.r_eax;
1961 break;
1962 }
1963# endif /* FREEBSD */
1964# endif /* !HAVE_PR_SYSCALL */
1965#endif /* USE_PROCFS */
1966
1967 if (entering(tcp))
1968 tcp->scno = scno;
1969 return 1;
1970}
Pavel Machek4dc3b142000-02-01 17:58:41 +00001971
Roland McGrath17352792005-06-07 23:21:26 +00001972long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001973known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001974{
1975 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001976#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001977 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1978 scno = sysent[scno].native_scno;
1979 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001980#endif
Roland McGrath17352792005-06-07 23:21:26 +00001981 scno += NR_SYSCALL_BASE;
1982 return scno;
1983}
1984
Roland McGratheb9e2e82009-06-02 16:49:22 -07001985/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001986 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001987 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001988 * 1: ok, continue in trace_syscall().
1989 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001990 * ("????" etc) and bail out.
1991 */
Roland McGratha4d48532005-06-08 20:45:28 +00001992static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001993syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001994{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001995#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001996 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001997
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001998 if (entering(tcp)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001999 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002000 if (
2001 scno == SYS_fork
2002#ifdef SYS_vfork
2003 || scno == SYS_vfork
2004#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00002005#ifdef SYS_fork1
2006 || scno == SYS_fork1
2007#endif /* SYS_fork1 */
2008#ifdef SYS_forkall
2009 || scno == SYS_forkall
2010#endif /* SYS_forkall */
2011#ifdef SYS_rfork1
2012 || scno == SYS_rfork1
2013#endif /* SYS_fork1 */
2014#ifdef SYS_rforkall
2015 || scno == SYS_rforkall
2016#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002017 ) {
2018 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002019 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002020 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002021 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002022 }
2023 else {
2024 fprintf(stderr, "syscall: missing entry\n");
2025 tcp->flags |= TCB_INSYSCALL;
2026 }
2027 }
2028 }
2029 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002030 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002031 fprintf(stderr, "syscall: missing exit\n");
2032 tcp->flags &= ~TCB_INSYSCALL;
2033 }
2034 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002035#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002036
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002037#ifdef SUNOS4
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002038 if (entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002039 if (scno == 0) {
2040 fprintf(stderr, "syscall: missing entry\n");
2041 tcp->flags |= TCB_INSYSCALL;
2042 }
2043 }
2044 else {
2045 if (scno != 0) {
2046 if (debug) {
2047 /*
2048 * This happens when a signal handler
2049 * for a signal which interrupted a
2050 * a system call makes another system call.
2051 */
2052 fprintf(stderr, "syscall: missing exit\n");
2053 }
2054 tcp->flags &= ~TCB_INSYSCALL;
2055 }
2056 }
2057#endif /* SUNOS4 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002058
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002059#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002060 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002061#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002062 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002063 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002064 if (eax != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002065 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002066 fprintf(stderr, "not a syscall entry (eax = %ld)\n", eax);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067 return 0;
2068 }
Michal Ludvig0e035502002-09-23 15:41:01 +00002069#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002070 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002071 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00002072 if (current_personality == 1)
2073 rax = (long int)(int)rax; /* sign extend from 32 bits */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002074 if (rax != -ENOSYS && entering(tcp)) {
Michal Ludvig0e035502002-09-23 15:41:01 +00002075 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002076 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
Michal Ludvig0e035502002-09-23 15:41:01 +00002077 return 0;
2078 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00002079#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002080 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00002081 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00002082 if (syscall_mode != -ENOSYS)
2083 syscall_mode = tcp->scno;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002084 if (gpr2 != syscall_mode && entering(tcp)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00002085 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002086 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00002087 return 0;
2088 }
Roland McGrath96dc5142003-01-20 10:23:04 +00002089 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
2090 == (TCB_INSYSCALL|TCB_WAITEXECVE))
2091 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
2092 /*
2093 * Fake a return value of zero. We leave the TCB_WAITEXECVE
2094 * flag set for the post-execve SIGTRAP to see and reset.
2095 */
2096 gpr2 = 0;
2097 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002098#elif defined (POWERPC)
2099# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002100 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002101 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002102 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002103 return -1;
2104 if (flags & SO_MASK)
2105 result = -result;
2106#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002107 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002108 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002109 if (d0 != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002110 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002111 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002112 return 0;
2113 }
2114#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00002115 /*
2116 * Nothing required
2117 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002118#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002119 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002120 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002121#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002122 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002123 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002124#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002125 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002126 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002127 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002128 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002129 if (ia32 && r8 != -ENOSYS && entering(tcp)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002130 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002131 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002132 return 0;
2133 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002134#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00002135 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002136 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002137 if (r10 != -ENOSYS && entering(tcp)) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002138 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002139 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002140 return 0;
2141 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002142#elif defined(MICROBLAZE)
2143 if (upeek(tcp, 3 * 4, &r3) < 0)
2144 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002145 if (r3 != -ENOSYS && entering(tcp)) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002146 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002147 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002148 return 0;
2149 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002150#endif
2151#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002152 return 1;
2153}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002154
Roland McGrathc1e45922008-05-27 23:18:29 +00002155#ifdef LINUX
2156/*
2157 * Check the syscall return value register value for whether it is
2158 * a negated errno code indicating an error, or a success return value.
2159 */
2160static inline int
2161is_negated_errno(unsigned long int val)
2162{
2163 unsigned long int max = -(long int) nerrnos;
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002164# if SUPPORTED_PERSONALITIES > 1
Roland McGrathc1e45922008-05-27 23:18:29 +00002165 if (personality_wordsize[current_personality] < sizeof(val)) {
2166 val = (unsigned int) val;
2167 max = (unsigned int) max;
2168 }
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002169# endif
Roland McGrathc1e45922008-05-27 23:18:29 +00002170 return val > max;
2171}
2172#endif
2173
Roland McGratha4d48532005-06-08 20:45:28 +00002174static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002175get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002176{
2177 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002178#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00002179 int check_errno = 1;
2180 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2181 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2182 check_errno = 0;
2183 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002184# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00002185 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00002186 tcp->u_rval = -1;
2187 u_error = -gpr2;
2188 }
2189 else {
2190 tcp->u_rval = gpr2;
2191 u_error = 0;
2192 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002193# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00002194 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00002195 tcp->u_rval = -1;
2196 u_error = -eax;
2197 }
2198 else {
2199 tcp->u_rval = eax;
2200 u_error = 0;
2201 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002202# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00002203 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00002204 tcp->u_rval = -1;
2205 u_error = -rax;
2206 }
2207 else {
2208 tcp->u_rval = rax;
2209 u_error = 0;
2210 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002211# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00002212 if (ia32) {
2213 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002214
Roland McGrathc1e45922008-05-27 23:18:29 +00002215 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00002216 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00002217 tcp->u_rval = -1;
2218 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002219 }
Roland McGrathc1e45922008-05-27 23:18:29 +00002220 else {
2221 tcp->u_rval = err;
2222 u_error = 0;
2223 }
2224 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00002225 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00002226 tcp->u_rval = -1;
2227 u_error = r8;
2228 } else {
2229 tcp->u_rval = r8;
2230 u_error = 0;
2231 }
2232 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002233# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002234 if (check_errno && a3) {
2235 tcp->u_rval = -1;
2236 u_error = r2;
2237 } else {
2238 tcp->u_rval = r2;
2239 u_error = 0;
2240 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002241# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002242 if (check_errno && is_negated_errno(result)) {
2243 tcp->u_rval = -1;
2244 u_error = -result;
2245 }
2246 else {
2247 tcp->u_rval = result;
2248 u_error = 0;
2249 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002250# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002251 if (check_errno && is_negated_errno(d0)) {
2252 tcp->u_rval = -1;
2253 u_error = -d0;
2254 }
2255 else {
2256 tcp->u_rval = d0;
2257 u_error = 0;
2258 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002259# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002260 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2261 tcp->u_rval = -1;
2262 u_error = -regs.ARM_r0;
2263 }
2264 else {
2265 tcp->u_rval = regs.ARM_r0;
2266 u_error = 0;
2267 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002268# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002269 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2270 tcp->u_rval = -1;
2271 u_error = -regs.r12;
2272 }
2273 else {
2274 tcp->u_rval = regs.r12;
2275 u_error = 0;
2276 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002277# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002278 if (check_errno && is_negated_errno(r0)) {
2279 tcp->u_rval = -1;
2280 u_error = -r0;
2281 } else {
2282 tcp->u_rval = r0;
2283 u_error = 0;
2284 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002285# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002286 if (check_errno && a3) {
2287 tcp->u_rval = -1;
2288 u_error = r0;
2289 }
2290 else {
2291 tcp->u_rval = r0;
2292 u_error = 0;
2293 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002294# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002295 if (check_errno && regs.psr & PSR_C) {
2296 tcp->u_rval = -1;
2297 u_error = regs.u_regs[U_REG_O0];
2298 }
2299 else {
2300 tcp->u_rval = regs.u_regs[U_REG_O0];
2301 u_error = 0;
2302 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002303# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002304 if (check_errno && regs.tstate & 0x1100000000UL) {
2305 tcp->u_rval = -1;
2306 u_error = regs.u_regs[U_REG_O0];
2307 }
2308 else {
2309 tcp->u_rval = regs.u_regs[U_REG_O0];
2310 u_error = 0;
2311 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002312# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002313 if (check_errno && is_negated_errno(r28)) {
2314 tcp->u_rval = -1;
2315 u_error = -r28;
2316 }
2317 else {
2318 tcp->u_rval = r28;
2319 u_error = 0;
2320 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002321# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002322 /* interpret R0 as return value or error number */
2323 if (check_errno && is_negated_errno(r0)) {
2324 tcp->u_rval = -1;
2325 u_error = -r0;
2326 }
2327 else {
2328 tcp->u_rval = r0;
2329 u_error = 0;
2330 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002331# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002332 /* interpret result as return value or error number */
2333 if (check_errno && is_negated_errno(r9)) {
2334 tcp->u_rval = -1;
2335 u_error = -r9;
2336 }
2337 else {
2338 tcp->u_rval = r9;
2339 u_error = 0;
2340 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002341# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002342 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2343 tcp->u_rval = -1;
2344 u_error = -r10;
2345 }
2346 else {
2347 tcp->u_rval = r10;
2348 u_error = 0;
2349 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05002350# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002351 long rval;
2352 /* interpret result as return value or error number */
2353 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2354 return -1;
2355 if (check_errno && rval < 0 && rval > -nerrnos) {
2356 tcp->u_rval = -1;
2357 u_error = -rval;
2358 }
2359 else {
2360 tcp->u_rval = rval;
2361 u_error = 0;
2362 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002363# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002364 /* interpret result as return value or error number */
2365 if (check_errno && is_negated_errno(r3)) {
2366 tcp->u_rval = -1;
2367 u_error = -r3;
2368 }
2369 else {
2370 tcp->u_rval = r3;
2371 u_error = 0;
2372 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002373# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002374#endif /* LINUX */
2375#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002376 /* get error code from user struct */
2377 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2378 return -1;
2379 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002380
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002381 /* get system call return value */
2382 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2383 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002384#endif /* SUNOS4 */
2385#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002386# ifdef SPARC
2387 /* Judicious guessing goes a long way. */
2388 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2389 tcp->u_rval = -1;
2390 u_error = tcp->status.pr_reg[R_O0];
2391 }
2392 else {
2393 tcp->u_rval = tcp->status.pr_reg[R_O0];
2394 u_error = 0;
2395 }
2396# endif /* SPARC */
2397# ifdef I386
2398 /* Wanna know how to kill an hour single-stepping? */
2399 if (tcp->status.PR_REG[EFL] & 0x1) {
2400 tcp->u_rval = -1;
2401 u_error = tcp->status.PR_REG[EAX];
2402 }
2403 else {
2404 tcp->u_rval = tcp->status.PR_REG[EAX];
2405# ifdef HAVE_LONG_LONG
2406 tcp->u_lrval =
2407 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2408 tcp->status.PR_REG[EAX];
2409# endif
2410 u_error = 0;
2411 }
2412# endif /* I386 */
2413# ifdef X86_64
2414 /* Wanna know how to kill an hour single-stepping? */
2415 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2416 tcp->u_rval = -1;
2417 u_error = tcp->status.PR_REG[RAX];
2418 }
2419 else {
2420 tcp->u_rval = tcp->status.PR_REG[RAX];
2421 u_error = 0;
2422 }
2423# endif /* X86_64 */
2424# ifdef MIPS
2425 if (tcp->status.pr_reg[CTX_A3]) {
2426 tcp->u_rval = -1;
2427 u_error = tcp->status.pr_reg[CTX_V0];
2428 }
2429 else {
2430 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
2431 u_error = 0;
2432 }
2433# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002434#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002435#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002436 if (regs.r_eflags & PSL_C) {
2437 tcp->u_rval = -1;
2438 u_error = regs.r_eax;
2439 } else {
2440 tcp->u_rval = regs.r_eax;
2441 tcp->u_lrval =
2442 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
2443 u_error = 0;
2444 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002445#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002446 tcp->u_error = u_error;
2447 return 1;
2448}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002449
Roland McGrathb69f81b2002-12-21 23:25:18 +00002450int
Denys Vlasenko12014262011-05-30 14:00:14 +02002451force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002452{
2453#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002454# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002455 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00002456 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
2457 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002458# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002459 eax = error ? -error : rval;
2460 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
2461 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002462# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002463 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00002464 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002465 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002466# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002467 if (ia32) {
2468 r8 = error ? -error : rval;
2469 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
2470 return -1;
2471 }
2472 else {
2473 if (error) {
2474 r8 = error;
2475 r10 = -1;
2476 }
2477 else {
2478 r8 = rval;
2479 r10 = 0;
2480 }
2481 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
2482 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
2483 return -1;
2484 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002485# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002486 r0 = error ? -error : rval;
2487 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
2488 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002489# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002490 if (error) {
2491 r2 = error;
2492 a3 = -1;
2493 }
2494 else {
2495 r2 = rval;
2496 a3 = 0;
2497 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002498 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00002499 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
2500 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002501 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002502# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002503 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002504 return -1;
2505 if (error) {
2506 flags |= SO_MASK;
2507 result = error;
2508 }
2509 else {
2510 flags &= ~SO_MASK;
2511 result = rval;
2512 }
Roland McGratheb285352003-01-14 09:59:00 +00002513 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
2514 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002515 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002516# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002517 d0 = error ? -error : rval;
2518 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
2519 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002520# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002521 regs.ARM_r0 = error ? -error : rval;
2522 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002523 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002524# elif defined(AVR32)
2525 regs.r12 = error ? -error : rval;
2526 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
2527 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002528# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002529 if (error) {
2530 a3 = -1;
2531 r0 = error;
2532 }
2533 else {
2534 a3 = 0;
2535 r0 = rval;
2536 }
2537 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
2538 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
2539 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002540# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002541 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
2542 return -1;
2543 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04002544 regs.psr |= PSR_C;
2545 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00002546 }
2547 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04002548 regs.psr &= ~PSR_C;
2549 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00002550 }
2551 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
2552 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002553# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002554 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
2555 return -1;
2556 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04002557 regs.tstate |= 0x1100000000UL;
2558 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002559 }
2560 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04002561 regs.tstate &= ~0x1100000000UL;
2562 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002563 }
2564 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
2565 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002566# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002567 r28 = error ? -error : rval;
2568 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
2569 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002570# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002571 r0 = error ? -error : rval;
2572 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
2573 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002574# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002575 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00002576 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
2577 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002578# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00002579#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002580
Roland McGrathb69f81b2002-12-21 23:25:18 +00002581#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07002582 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
2583 error << 24) < 0 ||
2584 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002585 return -1;
2586#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002587
Roland McGrathb69f81b2002-12-21 23:25:18 +00002588#ifdef SVR4
2589 /* XXX no clue */
2590 return -1;
2591#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002592
Roland McGrathb69f81b2002-12-21 23:25:18 +00002593#ifdef FREEBSD
2594 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002595 perror("pread");
2596 return -1;
2597 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00002598 if (error) {
2599 regs.r_eflags |= PSL_C;
2600 regs.r_eax = error;
2601 }
2602 else {
2603 regs.r_eflags &= ~PSL_C;
2604 regs.r_eax = rval;
2605 }
2606 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002607 perror("pwrite");
2608 return -1;
2609 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00002610#endif /* FREEBSD */
2611
2612 /* All branches reach here on success (only). */
2613 tcp->u_error = error;
2614 tcp->u_rval = rval;
2615 return 0;
2616}
2617
Roland McGratha4d48532005-06-08 20:45:28 +00002618static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002619syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002620{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002621#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002622 int i, nargs;
2623
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002624 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002625 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002626 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002627 nargs = tcp->u_nargs = MAX_ARGS;
2628
2629# if defined(S390) || defined(S390X)
2630 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002631 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
2632 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002633# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002634 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002635 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
2636 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002637# elif defined(IA64)
2638 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002639 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002640 long rbs_end;
2641 /* be backwards compatible with kernel < 2.4.4... */
2642# ifndef PT_RBS_END
2643# define PT_RBS_END PT_AR_BSP
2644# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002645
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002646 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
2647 return -1;
2648 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002649 return -1;
2650
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002651 sof = (cfm >> 0) & 0x7f;
2652 sol = (cfm >> 7) & 0x7f;
2653 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
2654
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002655 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002656 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2657 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2658 return -1;
2659 }
2660 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002661 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
2662 PT_R9 /* ECX = out1 */,
2663 PT_R10 /* EDX = out2 */,
2664 PT_R14 /* ESI = out3 */,
2665 PT_R15 /* EDI = out4 */,
2666 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002667
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002668 for (i = 0; i < nargs; ++i) {
2669 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2670 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002671 /* truncate away IVE sign-extension */
2672 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002673 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002674 }
2675# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2676 /* N32 and N64 both use up to six registers. */
2677 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002678
2679 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2680 return -1;
2681
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002682 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002683 tcp->u_arg[i] = regs[REG_A0 + i];
2684# if defined(LINUX_MIPSN32)
2685 tcp->ext_arg[i] = regs[REG_A0 + i];
2686# endif
2687 }
2688# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002689 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002690 long sp;
2691
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002692 if (upeek(tcp, REG_SP, &sp) < 0)
2693 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002694 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002695 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2696 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002697 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002698 (char *)(tcp->u_arg + 4));
2699 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002700 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002701 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002702 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002703 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002704# elif defined(POWERPC)
2705# ifndef PT_ORIG_R3
2706# define PT_ORIG_R3 34
2707# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002708 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002709 if (upeek(tcp, (i==0) ?
2710 (sizeof(unsigned long) * PT_ORIG_R3) :
2711 ((i+PT_R3) * sizeof(unsigned long)),
2712 &tcp->u_arg[i]) < 0)
2713 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002714 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002715# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002716 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002717 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2718# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002719 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002720 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2721 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002722# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002723 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002724 tcp->u_arg[i] = regs.uregs[i];
2725# elif defined(AVR32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002726 static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
2727 &regs.r11,
2728 &regs.r10,
2729 &regs.r9,
2730 &regs.r5,
2731 &regs.r3 };
2732 for (i = 0; i < nargs; ++i)
2733 tcp->u_arg[i] = *argregp[i];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002734# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002735 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 +02002736
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002737 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002738 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2739 return -1;
2740# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002741 static const int syscall_regs[MAX_ARGS] = {
2742 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
2743 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002744 };
2745
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002746 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002747 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002748 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002749# elif defined(SH64)
2750 int i;
2751 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002752 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002753
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002754 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002755 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2756 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002757# elif defined(X86_64)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002758 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2759 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2760 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002761 };
2762
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002763 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002764 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002765 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002766# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002767 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002768 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2769 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002770# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002771 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002772 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002773 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002774 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002775
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002776 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002777 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2778 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002779# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002780 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002781 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2782 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002783# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002784 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002785 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2786 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002787# else /* Other architecture (like i386) (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002788 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002789 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2790 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002791# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002792#endif /* LINUX */
2793#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002794 int i, nargs;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002795 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002796 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002797 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002798 nargs = tcp->u_nargs = MAX_ARGS;
2799 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002800 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002801
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002802 if (upeek(tcp, uoff(u_arg[0]) +
2803 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2804 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002805 }
2806#endif /* SUNOS4 */
2807#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002808# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002809 /*
2810 * SGI is broken: even though it has pr_sysarg, it doesn't
2811 * set them on system call entry. Get a clue.
2812 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002813 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002814 tcp->u_nargs = sysent[tcp->scno].nargs;
2815 else
2816 tcp->u_nargs = tcp->status.pr_nsysarg;
2817 if (tcp->u_nargs > 4) {
2818 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002819 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002820 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002821 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002822 }
2823 else {
2824 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002825 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002826 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002827# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002828 /*
2829 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2830 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002831 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
John Hughes25299712001-03-06 10:10:06 +00002832 tcp->u_nargs = sysent[tcp->scno].nargs;
2833 else
2834 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2835 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002836 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2837# elif defined(HAVE_PR_SYSCALL)
2838 int i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002839 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002840 tcp->u_nargs = sysent[tcp->scno].nargs;
2841 else
2842 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002843 for (i = 0; i < tcp->u_nargs; i++)
2844 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2845# elif defined(I386)
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002846 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002847 tcp->u_nargs = sysent[tcp->scno].nargs;
2848 else
2849 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002850 if (tcp->u_nargs > 0)
2851 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002852 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2853# else
John Hughes25299712001-03-06 10:10:06 +00002854 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002855# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002856#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002857#ifdef FREEBSD
2858 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2859 sysent[tcp->scno].nargs > tcp->status.val)
2860 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002861 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002862 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002863 if (tcp->u_nargs < 0)
2864 tcp->u_nargs = 0;
2865 if (tcp->u_nargs > MAX_ARGS)
2866 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002867 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002868 case SYS___syscall:
2869 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2870 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002871 break;
2872 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002873 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2874 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002875 break;
2876 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002877 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2878 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002879 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002880 }
2881#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002882 return 1;
2883}
2884
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002885static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002886trace_syscall_entering(struct tcb *tcp)
2887{
2888 int res, scno_good;
2889
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02002890 scno_good = res = get_scno_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002891 if (res == 0)
2892 return res;
2893 if (res == 1)
2894 res = syscall_fixup(tcp);
2895 if (res == 0)
2896 return res;
2897 if (res == 1)
2898 res = syscall_enter(tcp);
2899 if (res == 0)
2900 return res;
2901
2902 if (res != 1) {
2903 printleader(tcp);
2904 tcp->flags &= ~TCB_REPRINT;
2905 tcp_last = tcp;
2906 if (scno_good != 1)
2907 tprintf("????" /* anti-trigraph gap */ "(");
2908 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2909 tprintf("syscall_%lu(", tcp->scno);
2910 else
2911 tprintf("%s(", sysent[tcp->scno].sys_name);
2912 /*
2913 * " <unavailable>" will be added later by the code which
2914 * detects ptrace errors.
2915 */
2916 goto ret;
2917 }
2918
2919 switch (known_scno(tcp)) {
2920#ifdef SYS_socket_subcall
2921 case SYS_socketcall:
2922 decode_subcall(tcp, SYS_socket_subcall,
2923 SYS_socket_nsubcalls, deref_style);
2924 break;
2925#endif
2926#ifdef SYS_ipc_subcall
2927 case SYS_ipc:
2928 decode_subcall(tcp, SYS_ipc_subcall,
2929 SYS_ipc_nsubcalls, shift_style);
2930 break;
2931#endif
2932#ifdef SVR4
2933#ifdef SYS_pgrpsys_subcall
2934 case SYS_pgrpsys:
2935 decode_subcall(tcp, SYS_pgrpsys_subcall,
2936 SYS_pgrpsys_nsubcalls, shift_style);
2937 break;
2938#endif /* SYS_pgrpsys_subcall */
2939#ifdef SYS_sigcall_subcall
2940 case SYS_sigcall:
2941 decode_subcall(tcp, SYS_sigcall_subcall,
2942 SYS_sigcall_nsubcalls, mask_style);
2943 break;
2944#endif /* SYS_sigcall_subcall */
2945 case SYS_msgsys:
2946 decode_subcall(tcp, SYS_msgsys_subcall,
2947 SYS_msgsys_nsubcalls, shift_style);
2948 break;
2949 case SYS_shmsys:
2950 decode_subcall(tcp, SYS_shmsys_subcall,
2951 SYS_shmsys_nsubcalls, shift_style);
2952 break;
2953 case SYS_semsys:
2954 decode_subcall(tcp, SYS_semsys_subcall,
2955 SYS_semsys_nsubcalls, shift_style);
2956 break;
2957 case SYS_sysfs:
2958 decode_subcall(tcp, SYS_sysfs_subcall,
2959 SYS_sysfs_nsubcalls, shift_style);
2960 break;
2961 case SYS_spcall:
2962 decode_subcall(tcp, SYS_spcall_subcall,
2963 SYS_spcall_nsubcalls, shift_style);
2964 break;
2965#ifdef SYS_context_subcall
2966 case SYS_context:
2967 decode_subcall(tcp, SYS_context_subcall,
2968 SYS_context_nsubcalls, shift_style);
2969 break;
2970#endif /* SYS_context_subcall */
2971#ifdef SYS_door_subcall
2972 case SYS_door:
2973 decode_subcall(tcp, SYS_door_subcall,
2974 SYS_door_nsubcalls, door_style);
2975 break;
2976#endif /* SYS_door_subcall */
2977#ifdef SYS_kaio_subcall
2978 case SYS_kaio:
2979 decode_subcall(tcp, SYS_kaio_subcall,
2980 SYS_kaio_nsubcalls, shift_style);
2981 break;
2982#endif
2983#endif /* SVR4 */
2984#ifdef FREEBSD
2985 case SYS_msgsys:
2986 case SYS_shmsys:
2987 case SYS_semsys:
2988 decode_subcall(tcp, 0, 0, table_style);
2989 break;
2990#endif
2991#ifdef SUNOS4
2992 case SYS_semsys:
2993 decode_subcall(tcp, SYS_semsys_subcall,
2994 SYS_semsys_nsubcalls, shift_style);
2995 break;
2996 case SYS_msgsys:
2997 decode_subcall(tcp, SYS_msgsys_subcall,
2998 SYS_msgsys_nsubcalls, shift_style);
2999 break;
3000 case SYS_shmsys:
3001 decode_subcall(tcp, SYS_shmsys_subcall,
3002 SYS_shmsys_nsubcalls, shift_style);
3003 break;
3004#endif
3005 }
3006
3007 internal_syscall(tcp);
3008
3009 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
3010 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
3011 (tracing_paths && !pathtrace_match(tcp))) {
3012 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
3013 return 0;
3014 }
3015
3016 tcp->flags &= ~TCB_FILTERED;
3017
3018 if (cflag == CFLAG_ONLY_STATS) {
3019 res = 0;
3020 goto ret;
3021 }
3022
3023 printleader(tcp);
3024 tcp->flags &= ~TCB_REPRINT;
3025 tcp_last = tcp;
3026 if (tcp->scno >= nsyscalls || tcp->scno < 0)
3027 tprintf("syscall_%lu(", tcp->scno);
3028 else
3029 tprintf("%s(", sysent[tcp->scno].sys_name);
3030 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
3031 ((qual_flags[tcp->scno] & QUAL_RAW) &&
3032 sysent[tcp->scno].sys_func != sys_exit))
3033 res = printargs(tcp);
3034 else
3035 res = (*sysent[tcp->scno].sys_func)(tcp);
3036
3037 if (fflush(tcp->outf) == EOF)
3038 return -1;
3039 ret:
3040 tcp->flags |= TCB_INSYSCALL;
3041 /* Measure the entrance time as late as possible to avoid errors. */
3042 if (dtime || cflag)
3043 gettimeofday(&tcp->etime, NULL);
3044 return res;
3045}
3046
3047static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003048trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00003049{
3050 int sys_res;
3051 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00003052 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003053 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00003054
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003055 /* Measure the exit time as early as possible to avoid errors. */
3056 if (dtime || cflag)
3057 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00003058
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003059 /* BTW, why we don't just memorize syscall no. on entry
3060 * in tcp->something?
3061 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02003062 scno_good = res = get_scno_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003063 if (res == 0)
3064 return res;
3065 if (res == 1)
3066 res = syscall_fixup(tcp);
3067 if (res == 0)
3068 return res;
3069 if (res == 1)
3070 res = get_error(tcp);
3071 if (res == 0)
3072 return res;
3073 if (res == 1)
3074 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00003075
Grant Edwards8a082772011-04-07 20:25:40 +00003076 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02003077 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00003078 }
3079
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003080 if (tcp->flags & TCB_REPRINT) {
3081 printleader(tcp);
3082 tprintf("<... ");
3083 if (scno_good != 1)
3084 tprintf("????");
3085 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
3086 tprintf("syscall_%lu", tcp->scno);
3087 else
3088 tprintf("%s", sysent[tcp->scno].sys_name);
3089 tprintf(" resumed> ");
3090 }
3091
3092 if (cflag) {
3093 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02003094 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02003095 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02003096 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003097 }
3098 }
3099
3100 if (res != 1) {
3101 tprintf(") ");
3102 tabto(acolumn);
3103 tprintf("= ? <unavailable>");
3104 printtrailer();
3105 tcp->flags &= ~TCB_INSYSCALL;
3106 return res;
3107 }
3108
3109 if (tcp->scno >= nsyscalls || tcp->scno < 0
3110 || (qual_flags[tcp->scno] & QUAL_RAW))
3111 sys_res = printargs(tcp);
3112 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02003113 /* FIXME: not_failing_only (IOW, option -z) is broken:
3114 * failure of syscall is known only after syscall return.
3115 * Thus we end up with something like this on, say, ENOENT:
3116 * open("doesnt_exist", O_RDONLY <unfinished ...>
3117 * {next syscall decode}
3118 * whereas the intended result is that open(...) line
3119 * is not shown at all.
3120 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003121 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02003122 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003123 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
3124 }
3125
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003126 tprintf(") ");
3127 tabto(acolumn);
Denys Vlasenko3b738812011-08-22 02:06:35 +02003128 u_error = tcp->u_error;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003129 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
3130 qual_flags[tcp->scno] & QUAL_RAW) {
3131 if (u_error)
3132 tprintf("= -1 (errno %ld)", u_error);
3133 else
3134 tprintf("= %#lx", tcp->u_rval);
3135 }
3136 else if (!(sys_res & RVAL_NONE) && u_error) {
3137 switch (u_error) {
3138#ifdef LINUX
3139 case ERESTARTSYS:
3140 tprintf("= ? ERESTARTSYS (To be restarted)");
3141 break;
3142 case ERESTARTNOINTR:
3143 tprintf("= ? ERESTARTNOINTR (To be restarted)");
3144 break;
3145 case ERESTARTNOHAND:
3146 tprintf("= ? ERESTARTNOHAND (To be restarted)");
3147 break;
3148 case ERESTART_RESTARTBLOCK:
3149 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
3150 break;
3151#endif /* LINUX */
3152 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003153 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02003154 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003155 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02003156 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003157 strerror(u_error));
3158 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02003159 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003160 strerror(u_error));
3161 break;
3162 }
3163 if ((sys_res & RVAL_STR) && tcp->auxstr)
3164 tprintf(" (%s)", tcp->auxstr);
3165 }
3166 else {
3167 if (sys_res & RVAL_NONE)
3168 tprintf("= ?");
3169 else {
3170 switch (sys_res & RVAL_MASK) {
3171 case RVAL_HEX:
3172 tprintf("= %#lx", tcp->u_rval);
3173 break;
3174 case RVAL_OCTAL:
3175 tprintf("= %#lo", tcp->u_rval);
3176 break;
3177 case RVAL_UDECIMAL:
3178 tprintf("= %lu", tcp->u_rval);
3179 break;
3180 case RVAL_DECIMAL:
3181 tprintf("= %ld", tcp->u_rval);
3182 break;
3183#ifdef HAVE_LONG_LONG
3184 case RVAL_LHEX:
3185 tprintf("= %#llx", tcp->u_lrval);
3186 break;
3187 case RVAL_LOCTAL:
3188 tprintf("= %#llo", tcp->u_lrval);
3189 break;
3190 case RVAL_LUDECIMAL:
3191 tprintf("= %llu", tcp->u_lrval);
3192 break;
3193 case RVAL_LDECIMAL:
3194 tprintf("= %lld", tcp->u_lrval);
3195 break;
3196#endif
3197 default:
3198 fprintf(stderr,
3199 "invalid rval format\n");
3200 break;
3201 }
3202 }
3203 if ((sys_res & RVAL_STR) && tcp->auxstr)
3204 tprintf(" (%s)", tcp->auxstr);
3205 }
3206 if (dtime) {
3207 tv_sub(&tv, &tv, &tcp->etime);
3208 tprintf(" <%ld.%06ld>",
3209 (long) tv.tv_sec, (long) tv.tv_usec);
3210 }
3211 printtrailer();
3212
3213 dumpio(tcp);
3214 if (fflush(tcp->outf) == EOF)
3215 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02003216 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003217 tcp->flags &= ~TCB_INSYSCALL;
3218 return 0;
3219}
3220
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003221int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00003222trace_syscall(struct tcb *tcp)
3223{
3224 return exiting(tcp) ?
3225 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
3226}
3227
3228int
Denys Vlasenko12014262011-05-30 14:00:14 +02003229printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003230{
3231 if (entering(tcp)) {
3232 int i;
3233
3234 for (i = 0; i < tcp->u_nargs; i++)
3235 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
3236 }
3237 return 0;
3238}
3239
3240long
Denys Vlasenko12014262011-05-30 14:00:14 +02003241getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003242{
3243 long val = -1;
3244
3245#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00003246#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04003247 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02003248 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003249 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04003250 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00003251#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00003252 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00003253 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00003254#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00003255 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00003256 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00003257#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003258#endif /* LINUX */
3259
3260#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00003261 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003262 return -1;
3263#endif /* SUNOS4 */
3264
3265#ifdef SVR4
3266#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00003267 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003268#endif /* SPARC */
3269#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00003270 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003271#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00003272#ifdef X86_64
3273 val = tcp->status.PR_REG[RDX];
3274#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003275#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00003276 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003277#endif /* MIPS */
3278#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00003279
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00003280#ifdef FREEBSD
3281 struct reg regs;
3282 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
3283 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00003284#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003285 return val;
3286}
3287
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00003288#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003289/*
3290 * Apparently, indirect system calls have already be converted by ptrace(2),
3291 * so if you see "indir" this program has gone astray.
3292 */
3293int
Denys Vlasenko12014262011-05-30 14:00:14 +02003294sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003295{
3296 int i, scno, nargs;
3297
3298 if (entering(tcp)) {
Denys Vlasenko5d645812011-08-20 12:48:18 +02003299 scno = tcp->u_arg[0];
3300 if (scno > nsyscalls) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003301 fprintf(stderr, "Bogus syscall: %u\n", scno);
3302 return 0;
3303 }
3304 nargs = sysent[scno].nargs;
3305 tprintf("%s", sysent[scno].sys_name);
3306 for (i = 0; i < nargs; i++)
3307 tprintf(", %#lx", tcp->u_arg[i+1]);
3308 }
3309 return 0;
3310}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00003311#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00003312
3313int
3314is_restart_error(struct tcb *tcp)
3315{
3316#ifdef LINUX
3317 if (!syserror(tcp))
3318 return 0;
3319 switch (tcp->u_error) {
3320 case ERESTARTSYS:
3321 case ERESTARTNOINTR:
3322 case ERESTARTNOHAND:
3323 case ERESTART_RESTARTBLOCK:
3324 return 1;
3325 default:
3326 break;
3327 }
3328#endif /* LINUX */
3329 return 0;
3330}