blob: fc502bf27a8464d255a2a5560ee61380712534a5 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
38#include <signal.h>
39#include <time.h>
40#include <errno.h>
41#include <sys/user.h>
42#include <sys/syscall.h>
43#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044
Wichert Akkerman15dea971999-10-06 13:06:34 +000045#ifdef HAVE_SYS_REG_H
Roland McGratheb9e2e82009-06-02 16:49:22 -070046#include <sys/reg.h>
47#ifndef PTRACE_PEEKUSR
48# define PTRACE_PEEKUSR PTRACE_PEEKUSER
49#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000050#elif defined(HAVE_LINUX_PTRACE_H)
Roland McGratheb9e2e82009-06-02 16:49:22 -070051#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000052# ifdef HAVE_STRUCT_IA64_FPREG
53# define ia64_fpreg XXX_ia64_fpreg
54# endif
55# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
56# define pt_all_user_regs XXX_pt_all_user_regs
57# endif
Roland McGratheb9e2e82009-06-02 16:49:22 -070058#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000059# undef ia64_fpreg
60# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000061#endif
62
Roland McGrath6d1a65c2004-07-12 07:44:08 +000063#if defined (LINUX) && defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000064# undef PTRACE_GETREGS
65# define PTRACE_GETREGS PTRACE_GETREGS64
66# undef PTRACE_SETREGS
67# define PTRACE_SETREGS PTRACE_SETREGS64
68#endif /* LINUX && SPARC64 */
69
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000070#if defined(LINUX) && defined(IA64)
71# include <asm/ptrace_offsets.h>
72# include <asm/rse.h>
73#endif
74
Pavel Machekd8ae7e32000-02-01 17:17:25 +000075#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000076#ifdef LINUX
77#ifndef ERESTARTSYS
78#define ERESTARTSYS 512
79#endif
80#ifndef ERESTARTNOINTR
81#define ERESTARTNOINTR 513
82#endif
83#ifndef ERESTARTNOHAND
84#define ERESTARTNOHAND 514 /* restart if no handler.. */
85#endif
86#ifndef ENOIOCTLCMD
87#define ENOIOCTLCMD 515 /* No ioctl command */
88#endif
Roland McGrath9c555e72003-07-09 09:47:59 +000089#ifndef ERESTART_RESTARTBLOCK
90#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
91#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092#ifndef NSIG
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020093#warning: NSIG is not defined, using 32
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000094#define NSIG 32
95#endif
96#ifdef ARM
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020097/* Ugh. Is this really correct? ARM has no RT signals?! */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098#undef NSIG
99#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000100#undef NR_SYSCALL_BASE
101#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102#endif
103#endif /* LINUX */
104
105#include "syscall.h"
106
107/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000108#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000109#define TF TRACE_FILE
110#define TI TRACE_IPC
111#define TN TRACE_NETWORK
112#define TP TRACE_PROCESS
113#define TS TRACE_SIGNAL
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000114#define NF SYSCALL_NEVER_FAILS
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200115#define MA MAX_ARGS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116
Roland McGrathee36ce12004-09-04 03:53:10 +0000117static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118#include "syscallent.h"
119};
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120
121#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000122static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123#include "syscallent1.h"
124};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200125#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126
127#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent2.h"
130};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200131#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000132
133/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000134#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000135#undef TF
136#undef TI
137#undef TN
138#undef TP
139#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000140#undef NF
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200141#undef MA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142
Denys Vlasenko39fca622011-08-20 02:12:33 +0200143
144/*
145 * `ioctlent.h' may be generated from `ioctlent.raw' by the auxiliary
146 * program `ioctlsort', such that the list is sorted by the `code' field.
147 * This has the side-effect of resolving the _IO.. macros into
148 * plain integers, eliminating the need to include here everything
149 * in "/usr/include".
150 */
151
152
Roland McGrathee36ce12004-09-04 03:53:10 +0000153static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000154#include "errnoent.h"
155};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200156static const char *const signalent0[] = {
157#include "signalent.h"
158};
159static const struct ioctlent ioctlent0[] = {
160#include "ioctlent.h"
161};
162enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
163enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
164enum { nsignals0 = ARRAY_SIZE(signalent0) };
165enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
166int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167
168#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000169static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000170#include "errnoent1.h"
171};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200172static const char *const signalent1[] = {
173#include "signalent1.h"
174};
175static const struct ioctlent ioctlent1[] = {
176#include "ioctlent1.h"
177};
178enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
179enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
180enum { nsignals1 = ARRAY_SIZE(signalent1) };
181enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
182int qual_flags1[MAX_QUALS];
183#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184
185#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000186static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000187#include "errnoent2.h"
188};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200189static const char *const signalent2[] = {
190#include "signalent2.h"
191};
192static const struct ioctlent ioctlent2[] = {
193#include "ioctlent2.h"
194};
195enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
196enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
197enum { nsignals2 = ARRAY_SIZE(signalent2) };
198enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
199int qual_flags2[MAX_QUALS];
200#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201
Denys Vlasenko39fca622011-08-20 02:12:33 +0200202
203const struct sysent *sysent;
Roland McGrathee36ce12004-09-04 03:53:10 +0000204const char *const *errnoent;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200205const char *const *signalent;
206const struct ioctlent *ioctlent;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200207unsigned nsyscalls;
208unsigned nerrnos;
209unsigned nsignals;
210unsigned nioctlents;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200211int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000212
213int current_personality;
214
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000215#ifndef PERSONALITY0_WORDSIZE
216# define PERSONALITY0_WORDSIZE sizeof(long)
217#endif
218const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
219 PERSONALITY0_WORDSIZE,
220#if SUPPORTED_PERSONALITIES > 1
221 PERSONALITY1_WORDSIZE,
222#endif
223#if SUPPORTED_PERSONALITIES > 2
224 PERSONALITY2_WORDSIZE,
225#endif
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200226};
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000227
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200228void
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000229set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000230{
231 switch (personality) {
232 case 0:
233 errnoent = errnoent0;
234 nerrnos = nerrnos0;
235 sysent = sysent0;
236 nsyscalls = nsyscalls0;
237 ioctlent = ioctlent0;
238 nioctlents = nioctlents0;
239 signalent = signalent0;
240 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000241 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000242 break;
243
244#if SUPPORTED_PERSONALITIES >= 2
245 case 1:
246 errnoent = errnoent1;
247 nerrnos = nerrnos1;
248 sysent = sysent1;
249 nsyscalls = nsyscalls1;
250 ioctlent = ioctlent1;
251 nioctlents = nioctlents1;
252 signalent = signalent1;
253 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000254 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200256#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000257
258#if SUPPORTED_PERSONALITIES >= 3
259 case 2:
260 errnoent = errnoent2;
261 nerrnos = nerrnos2;
262 sysent = sysent2;
263 nsyscalls = nsyscalls2;
264 ioctlent = ioctlent2;
265 nioctlents = nioctlents2;
266 signalent = signalent2;
267 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000268 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000269 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200270#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000271 }
272
273 current_personality = personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000274}
275
Roland McGrathe10e62a2004-09-04 04:20:43 +0000276
Roland McGrath9797ceb2002-12-30 10:23:00 +0000277static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000278
Roland McGrathe10e62a2004-09-04 04:20:43 +0000279static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000281 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000282 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000283 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000284} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000285 { QUAL_TRACE, "trace", qual_syscall, "system call" },
286 { QUAL_TRACE, "t", qual_syscall, "system call" },
287 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
288 { QUAL_ABBREV, "a", qual_syscall, "system call" },
289 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
290 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
291 { QUAL_RAW, "raw", qual_syscall, "system call" },
292 { QUAL_RAW, "x", qual_syscall, "system call" },
293 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
294 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
295 { QUAL_SIGNAL, "s", qual_signal, "signal" },
296 { QUAL_FAULT, "fault", qual_fault, "fault" },
297 { QUAL_FAULT, "faults", qual_fault, "fault" },
298 { QUAL_FAULT, "m", qual_fault, "fault" },
299 { QUAL_READ, "read", qual_desc, "descriptor" },
300 { QUAL_READ, "reads", qual_desc, "descriptor" },
301 { QUAL_READ, "r", qual_desc, "descriptor" },
302 { QUAL_WRITE, "write", qual_desc, "descriptor" },
303 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
304 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000305 { 0, NULL, NULL, NULL },
306};
307
Roland McGrath9797ceb2002-12-30 10:23:00 +0000308static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000309qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000310{
Roland McGrath138c6a32006-01-12 09:50:49 +0000311 if (pers == 0 || pers < 0) {
312 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000313 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000314 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000315 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000316 }
317
318#if SUPPORTED_PERSONALITIES >= 2
319 if (pers == 1 || pers < 0) {
320 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000321 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000322 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000323 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000324 }
325#endif /* SUPPORTED_PERSONALITIES >= 2 */
326
327#if SUPPORTED_PERSONALITIES >= 3
328 if (pers == 2 || pers < 0) {
329 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000330 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000331 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000332 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 }
334#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000335}
336
337static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000338qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000339{
340 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000341 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000342
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000343 if (isdigit((unsigned char)*s)) {
344 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000345 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000346 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000347 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000348 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000349 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000350 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000351 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000352 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000353 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000354 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000355
356#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000357 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000358 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000359 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000360 rc = 0;
361 }
362#endif /* SUPPORTED_PERSONALITIES >= 2 */
363
364#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000365 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000366 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000367 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000368 rc = 0;
369 }
370#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000371
Roland McGrathfe6b3522005-02-02 04:40:11 +0000372 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000373}
374
375static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000376qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000377{
378 int i;
379 char buf[32];
380
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000381 if (isdigit((unsigned char)*s)) {
382 int signo = atoi(s);
383 if (signo < 0 || signo >= MAX_QUALS)
384 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000385 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000386 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000388 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000389 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000390 strcpy(buf, s);
391 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000392 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000394 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000395 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000396 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000397 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000398 }
Roland McGrath76421df2005-02-02 03:51:18 +0000399 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000400}
401
402static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000403qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000404{
405 return -1;
406}
407
408static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000409qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000410{
Roland McGrath48a035f2006-01-12 09:45:56 +0000411 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000412 int desc = atoi(s);
413 if (desc < 0 || desc >= MAX_QUALS)
414 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000415 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000416 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417 }
418 return -1;
419}
420
421static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000422lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000423{
424 if (strcmp(s, "file") == 0)
425 return TRACE_FILE;
426 if (strcmp(s, "ipc") == 0)
427 return TRACE_IPC;
428 if (strcmp(s, "network") == 0)
429 return TRACE_NETWORK;
430 if (strcmp(s, "process") == 0)
431 return TRACE_PROCESS;
432 if (strcmp(s, "signal") == 0)
433 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000434 if (strcmp(s, "desc") == 0)
435 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000436 return -1;
437}
438
439void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000440qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000442 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000443 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000444 char *copy;
445 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000446 int i, n;
447
448 opt = &qual_options[0];
449 for (i = 0; (p = qual_options[i].option_name); i++) {
450 n = strlen(p);
451 if (strncmp(s, p, n) == 0 && s[n] == '=') {
452 opt = &qual_options[i];
453 s += n + 1;
454 break;
455 }
456 }
457 not = 0;
458 if (*s == '!') {
459 not = 1;
460 s++;
461 }
462 if (strcmp(s, "none") == 0) {
463 not = 1 - not;
464 s = "all";
465 }
466 if (strcmp(s, "all") == 0) {
467 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000468 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000469 }
470 return;
471 }
472 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000473 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000474 }
Denys Vlasenko5d645812011-08-20 12:48:18 +0200475 copy = strdup(s);
476 if (!copy) {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000477 fprintf(stderr, "out of memory\n");
478 exit(1);
479 }
480 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000481 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000482 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000483 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000484 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000485
486#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000487 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000488 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000489 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000490#endif /* SUPPORTED_PERSONALITIES >= 2 */
491
492#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000493 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000494 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000495 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000496#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000497
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000498 continue;
499 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000500 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000501 fprintf(stderr, "strace: invalid %s `%s'\n",
502 opt->argument_name, p);
503 exit(1);
504 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000505 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000506 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507 return;
508}
509
510static void
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000511dumpio(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000512{
513 if (syserror(tcp))
514 return;
515 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
516 return;
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000517 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
518 return;
519 if (sysent[tcp->scno].sys_func == printargs)
520 return;
521 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
522 if (sysent[tcp->scno].sys_func == sys_read ||
523 sysent[tcp->scno].sys_func == sys_pread ||
524 sysent[tcp->scno].sys_func == sys_pread64 ||
525 sysent[tcp->scno].sys_func == sys_recv ||
526 sysent[tcp->scno].sys_func == sys_recvfrom)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000528 else if (sysent[tcp->scno].sys_func == sys_readv)
529 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
530 return;
531 }
532 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
533 if (sysent[tcp->scno].sys_func == sys_write ||
534 sysent[tcp->scno].sys_func == sys_pwrite ||
535 sysent[tcp->scno].sys_func == sys_pwrite64 ||
536 sysent[tcp->scno].sys_func == sys_send ||
537 sysent[tcp->scno].sys_func == sys_sendto)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000539 else if (sysent[tcp->scno].sys_func == sys_writev)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000540 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000541 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000542 }
543}
544
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000545#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000546enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000547#else /* FREEBSD */
548enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
549
550struct subcall {
551 int call;
552 int nsubcalls;
553 int subcalls[5];
554};
555
Roland McGratha4d48532005-06-08 20:45:28 +0000556static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000557 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000558#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000559 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000560#else
561 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
562#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000563 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
564};
565#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000567#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568
Roland McGratha4d48532005-06-08 20:45:28 +0000569static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200570decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000571{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000572 unsigned long addr, mask;
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200573 int i, n;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000574 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000575
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 switch (style) {
577 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000578 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
579 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000580 tcp->scno = subcall + tcp->u_arg[0];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200581 tcp->u_nargs = n = sysent[tcp->scno].nargs;
582 for (i = 0; i < n; i++)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583 tcp->u_arg[i] = tcp->u_arg[i + 1];
584 break;
585 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000586 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
587 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588 tcp->scno = subcall + tcp->u_arg[0];
589 addr = tcp->u_arg[1];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200590 tcp->u_nargs = n = sysent[tcp->scno].nargs;
591 for (i = 0; i < n; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000592 if (size == sizeof(int)) {
593 unsigned int arg;
594 if (umove(tcp, addr, &arg) < 0)
595 arg = 0;
596 tcp->u_arg[i] = arg;
597 }
598 else if (size == sizeof(long)) {
599 unsigned long arg;
600 if (umove(tcp, addr, &arg) < 0)
601 arg = 0;
602 tcp->u_arg[i] = arg;
603 }
604 else
605 abort();
606 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000608 break;
609 case mask_style:
610 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000611 for (i = 0; mask; i++)
612 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000613 if (i >= nsubcalls)
614 return;
615 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616 tcp->scno = subcall + i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200617 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000618 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000619 case door_style:
620 /*
621 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000622 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000623 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000624 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
625 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000626 tcp->scno = subcall + tcp->u_arg[5];
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200627 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000628 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000629#ifdef FREEBSD
630 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000631 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000632 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000633 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000634 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
635 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
636 for (i = 0; i < tcp->u_nargs; i++)
637 tcp->u_arg[i] = tcp->u_arg[i + 1];
638 }
639 break;
640#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 }
642}
643#endif
644
645struct tcb *tcp_last = NULL;
646
647static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000648internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649{
650 /*
651 * We must always trace a few critical system calls in order to
652 * correctly support following forks in the presence of tracing
653 * qualifiers.
654 */
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200655 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000656
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000657 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
658 return 0;
659
660 func = sysent[tcp->scno].sys_func;
661
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000662 if ( sys_fork == func
663#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
664 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000665#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000666#ifdef LINUX
667 || sys_clone == func
668#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000669#if UNIXWARE > 2
670 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000671#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000672 )
673 return internal_fork(tcp);
674
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200675#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000676 if ( sys_execve == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200677# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000678 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200679# endif
680# if UNIXWARE > 2
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000681 || sys_rexecve == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200682# endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683 )
684 return internal_exec(tcp);
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200685#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000686
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000687 return 0;
688}
689
Wichert Akkermanc7926982000-04-10 22:22:31 +0000690
691#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200692# if defined (I386)
693static long eax;
694# elif defined (IA64)
695long r8, r10, psr; /* TODO: make static? */
696long ia32 = 0; /* not static */
697# elif defined (POWERPC)
698static long result, flags;
699# elif defined (M68K)
700static long d0;
701# elif defined(BFIN)
702static long r0;
703# elif defined (ARM)
704static struct pt_regs regs;
705# elif defined (ALPHA)
706static long r0;
707static long a3;
708# elif defined(AVR32)
709static struct pt_regs regs;
710# elif defined (SPARC) || defined (SPARC64)
711static struct pt_regs regs;
712static unsigned long trap;
713# elif defined(LINUX_MIPSN32)
714static long long a3;
715static long long r2;
716# elif defined(MIPS)
717static long a3;
718static long r2;
719# elif defined(S390) || defined(S390X)
720static long gpr2;
721static long pc;
722static long syscall_mode;
723# elif defined(HPPA)
724static long r28;
725# elif defined(SH)
726static long r0;
727# elif defined(SH64)
728static long r9;
729# elif defined(X86_64)
730static long rax;
731# elif defined(CRISV10) || defined(CRISV32)
732static long r10;
733# elif defined(MICROBLAZE)
734static long r3;
735# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000736#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000737#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200738struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000739#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000740
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200741/* Returns:
742 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
743 * 1: ok, continue in trace_syscall().
744 * other: error, trace_syscall() should print error indicator
745 * ("????" etc) and bail out.
746 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200747#ifndef USE_PROCFS
748static
749#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000750int
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200751get_scno_on_sysenter(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000752{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000753 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000754
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000755#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000756# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000757 if (tcp->flags & TCB_WAITEXECVE) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200758 /* This is the post-execve SIGTRAP. */
Roland McGrath96dc5142003-01-20 10:23:04 +0000759 tcp->flags &= ~TCB_WAITEXECVE;
760 return 0;
761 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000762
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000763 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200764 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000765
766 if (syscall_mode != -ENOSYS) {
767 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000768 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000769 */
770 scno = syscall_mode;
771 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000772 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000773 * Old style of "passing" the scno via the SVC instruction.
774 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000775 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200776 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200777 static const int gpr_offset[16] = {
778 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
779 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
780 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
781 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
782 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000783
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000784 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000785 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000786 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000787 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000788 if (errno) {
789 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000790 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000791 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000792
793 /*
794 * We have to check if the SVC got executed directly or via an
795 * EXECUTE instruction. In case of EXECUTE it is necessary to do
796 * instruction decoding to derive the system call number.
797 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
798 * so that this doesn't work if a SVC opcode is part of an EXECUTE
799 * opcode. Since there is no way to find out the opcode size this
800 * is the best we can do...
801 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000802 if ((opcode & 0xff00) == 0x0a00) {
803 /* SVC opcode */
804 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000805 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000806 else {
807 /* SVC got executed by EXECUTE instruction */
808
809 /*
810 * Do instruction decoding of EXECUTE. If you really want to
811 * understand this, read the Principles of Operations.
812 */
813 svc_addr = (void *) (opcode & 0xfff);
814
815 tmp = 0;
816 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000817 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000818 return -1;
819 svc_addr += tmp;
820
821 tmp = 0;
822 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000823 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000824 return -1;
825 svc_addr += tmp;
826
Denys Vlasenkofb036672009-01-23 16:30:26 +0000827 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000828 if (errno)
829 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000830# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000831 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000832# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000833 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000834# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000835 tmp = 0;
836 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000837 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000838 return -1;
839
840 scno = (scno | tmp) & 0xff;
841 }
842 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000843# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000844 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000845 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200846 /* Check if this is the post-execve SIGTRAP. */
847 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
848 tcp->flags &= ~TCB_WAITEXECVE;
849 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000850 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200851# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200852 /* TODO: speed up strace by not doing this at every syscall.
853 * We only need to do it after execve.
854 */
855 int currpers;
856 long val;
857 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200858
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200859 /* Check for 64/32 bit mode. */
860 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
861 return -1;
862 /* SF is bit 0 of MSR */
863 if (val < 0)
864 currpers = 0;
865 else
866 currpers = 1;
867 if (currpers != current_personality) {
868 static const char *const names[] = {"64 bit", "32 bit"};
869 set_personality(currpers);
870 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
871 pid, names[current_personality]);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200872 }
873# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000874# elif defined(AVR32)
875 /*
876 * Read complete register set in one go.
877 */
878 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
879 return -1;
880
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200881 scno = regs.r8;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000882
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200883 /* Check if this is the post-execve SIGTRAP. */
884 if (tcp->flags & TCB_WAITEXECVE) {
885 tcp->flags &= ~TCB_WAITEXECVE;
886 return 0;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000887 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000888# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000889 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000890 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000891# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000892 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000893 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000894# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000895 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000896 return -1;
897
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200898 /* TODO: speed up strace by not doing this at every syscall.
899 * We only need to do it after execve.
900 */
901 int currpers;
902 long val;
903 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000904
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200905 /* Check CS register value. On x86-64 linux it is:
906 * 0x33 for long mode (64 bit)
907 * 0x23 for compatibility mode (32 bit)
908 * It takes only one ptrace and thus doesn't need
909 * to be cached.
910 */
911 if (upeek(tcp, 8*CS, &val) < 0)
912 return -1;
913 switch (val) {
914 case 0x23: currpers = 1; break;
915 case 0x33: currpers = 0; break;
916 default:
917 fprintf(stderr, "Unknown value CS=0x%02X while "
918 "detecting personality of process "
919 "PID=%d\n", (int)val, pid);
920 currpers = current_personality;
921 break;
922 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000923# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200924 /* This version analyzes the opcode of a syscall instruction.
925 * (int 0x80 on i386 vs. syscall on x86-64)
926 * It works, but is too complicated.
927 */
928 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000929
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200930 if (upeek(tcp, 8*RIP, &rip) < 0)
931 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000932
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200933 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
934 rip -= 2;
935 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000936
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200937 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
938 if (errno)
939 fprintf(stderr, "ptrace_peektext failed: %s\n",
940 strerror(errno));
941 switch (call & 0xffff) {
942 /* x86-64: syscall = 0x0f 0x05 */
943 case 0x050f: currpers = 0; break;
944 /* i386: int 0x80 = 0xcd 0x80 */
945 case 0x80cd: currpers = 1; break;
946 default:
947 currpers = current_personality;
948 fprintf(stderr,
949 "Unknown syscall opcode (0x%04X) while "
950 "detecting personality of process "
951 "PID=%d\n", (int)call, pid);
952 break;
953 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000954# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200955 if (currpers != current_personality) {
956 static const char *const names[] = {"64 bit", "32 bit"};
957 set_personality(currpers);
958 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
959 pid, names[current_personality]);
Roland McGrath761b5d72002-12-15 23:58:31 +0000960 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000961# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000962# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200963 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000964 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200965 if (ia32) {
966 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
967 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000968 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200969 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000970 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200971 }
972 /* Check if this is the post-execve SIGTRAP. */
973 if (tcp->flags & TCB_WAITEXECVE) {
974 tcp->flags &= ~TCB_WAITEXECVE;
975 return 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000976 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000977# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000978 /*
979 * Read complete register set in one go.
980 */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000981 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000982 return -1;
983
984 /*
985 * We only need to grab the syscall number on syscall entry.
986 */
987 if (regs.ARM_ip == 0) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200988 /* Check if this is the post-execve SIGTRAP. */
989 if (tcp->flags & TCB_WAITEXECVE) {
990 tcp->flags &= ~TCB_WAITEXECVE;
991 return 0;
Roland McGrath9bc63402007-11-01 21:42:18 +0000992 }
993
Roland McGrath0f87c492003-06-03 23:29:04 +0000994 /*
995 * Note: we only deal with only 32-bit CPUs here.
996 */
997 if (regs.ARM_cpsr & 0x20) {
998 /*
999 * Get the Thumb-mode system call number
1000 */
1001 scno = regs.ARM_r7;
1002 } else {
1003 /*
1004 * Get the ARM-mode system call number
1005 */
1006 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001007 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001008 if (errno)
1009 return -1;
1010
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001011 /* FIXME: bogus check? it is already done before,
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001012 * so we never can see it here?
1013 */
Roland McGrath0f87c492003-06-03 23:29:04 +00001014 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1015 tcp->flags &= ~TCB_WAITEXECVE;
1016 return 0;
1017 }
1018
Roland McGrathf691bd22006-04-25 07:34:41 +00001019 /* Handle the EABI syscall convention. We do not
1020 bother converting structures between the two
1021 ABIs, but basic functionality should work even
1022 if strace and the traced program have different
1023 ABIs. */
1024 if (scno == 0xef000000) {
1025 scno = regs.ARM_r7;
1026 } else {
1027 if ((scno & 0x0ff00000) != 0x0f900000) {
1028 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1029 scno);
1030 return -1;
1031 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001032
Roland McGrathf691bd22006-04-25 07:34:41 +00001033 /*
1034 * Fixup the syscall number
1035 */
1036 scno &= 0x000fffff;
1037 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001038 }
Roland McGrath56703312008-05-20 01:35:55 +00001039 if (scno & 0x0f0000) {
1040 /*
1041 * Handle ARM specific syscall
1042 */
1043 set_personality(1);
1044 scno &= 0x0000ffff;
1045 } else
1046 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001047
Roland McGrath0f87c492003-06-03 23:29:04 +00001048 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001049 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1050 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001052# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001053 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001054 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001055# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001056 unsigned long long regs[38];
1057
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001058 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001059 return -1;
1060 a3 = regs[REG_A3];
1061 r2 = regs[REG_V0];
1062
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001063 scno = r2;
Roland McGrath542c2c62008-05-20 01:11:56 +00001064
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001065 /* Check if this is the post-execve SIGTRAP. */
1066 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1067 tcp->flags &= ~TCB_WAITEXECVE;
1068 return 0;
1069 }
1070
1071 if (scno < 0 || scno > nsyscalls) {
1072 if (a3 == 0 || a3 == -1) {
1073 if (debug)
1074 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001075 return 0;
1076 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001077 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001078# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001079 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001080 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001081 if (upeek(tcp, REG_V0, &scno) < 0)
1082 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001083
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001084 /* Check if this is the post-execve SIGTRAP. */
1085 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1086 tcp->flags &= ~TCB_WAITEXECVE;
1087 return 0;
1088 }
1089
1090 if (scno < 0 || scno > nsyscalls) {
1091 if (a3 == 0 || a3 == -1) {
1092 if (debug)
1093 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001094 return 0;
1095 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001096 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001097# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001098 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001099 return -1;
1100
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001101 if (upeek(tcp, REG_R0, &scno) < 0)
1102 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001104 /* Check if this is the post-execve SIGTRAP. */
1105 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1106 tcp->flags &= ~TCB_WAITEXECVE;
1107 return 0;
1108 }
1109
1110 /*
1111 * Do some sanity checks to figure out if it's
1112 * really a syscall entry
1113 */
1114 if (scno < 0 || scno > nsyscalls) {
1115 if (a3 == 0 || a3 == -1) {
1116 if (debug)
1117 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 return 0;
1119 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001121# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001123 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001124 return -1;
1125
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001126 /* Disassemble the syscall trap. */
1127 /* Retrieve the syscall trap instruction. */
1128 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001129# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001130 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1131 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001132# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001133 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001134# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001135 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001136 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001137
1138 /* Disassemble the trap to see what personality to use. */
1139 switch (trap) {
1140 case 0x91d02010:
1141 /* Linux/SPARC syscall trap. */
1142 set_personality(0);
1143 break;
1144 case 0x91d0206d:
1145 /* Linux/SPARC64 syscall trap. */
1146 set_personality(2);
1147 break;
1148 case 0x91d02000:
1149 /* SunOS syscall trap. (pers 1) */
1150 fprintf(stderr, "syscall: SunOS no support\n");
1151 return -1;
1152 case 0x91d02008:
1153 /* Solaris 2.x syscall trap. (per 2) */
1154 set_personality(1);
1155 break;
1156 case 0x91d02009:
1157 /* NetBSD/FreeBSD syscall trap. */
1158 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1159 return -1;
1160 case 0x91d02027:
1161 /* Solaris 2.x gettimeofday */
1162 set_personality(1);
1163 break;
1164 default:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001165 /* Check if this is the post-execve SIGTRAP. */
1166 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001167 tcp->flags &= ~TCB_WAITEXECVE;
1168 return 0;
1169 }
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001170# if defined (SPARC64)
1171 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1172# else
1173 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1174# endif
1175 return -1;
1176 }
1177
1178 /* Extract the system call number from the registers. */
1179 if (trap == 0x91d02027)
1180 scno = 156;
1181 else
1182 scno = regs.u_regs[U_REG_G1];
1183 if (scno == 0) {
1184 scno = regs.u_regs[U_REG_O0];
1185 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1186 }
1187# elif defined(HPPA)
1188 if (upeek(tcp, PT_GR20, &scno) < 0)
1189 return -1;
1190 /* Check if this is the post-execve SIGTRAP. */
1191 if (tcp->flags & TCB_WAITEXECVE) {
1192 tcp->flags &= ~TCB_WAITEXECVE;
1193 return 0;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001194 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001195# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001196 /*
1197 * In the new syscall ABI, the system call number is in R3.
1198 */
1199 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1200 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001201
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001202 if (scno < 0) {
1203 /* Odd as it may seem, a glibc bug has been known to cause
1204 glibc to issue bogus negative syscall numbers. So for
1205 our purposes, make strace print what it *should* have been */
1206 long correct_scno = (scno & 0xff);
1207 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001208 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001209 "Detected glibc bug: bogus system call"
1210 " number = %ld, correcting to %ld\n",
1211 scno,
1212 correct_scno);
1213 scno = correct_scno;
1214 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001215
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001216 /* Check if this is the post-execve SIGTRAP. */
1217 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1218 tcp->flags &= ~TCB_WAITEXECVE;
1219 return 0;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001220 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001221# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001222 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001223 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001224 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001225
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001226 /* Check if this is the post-execve SIGTRAP. */
1227 if (tcp->flags & TCB_WAITEXECVE) {
1228 tcp->flags &= ~TCB_WAITEXECVE;
1229 return 0;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001230 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001231# elif defined(CRISV10) || defined(CRISV32)
1232 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1233 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001234# elif defined(TILE)
1235 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1236 return -1;
1237
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001238 /* Check if this is the post-execve SIGTRAP. */
1239 if (tcp->flags & TCB_WAITEXECVE) {
1240 tcp->flags &= ~TCB_WAITEXECVE;
1241 return 0;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001242 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001243# elif defined(MICROBLAZE)
1244 if (upeek(tcp, 0, &scno) < 0)
1245 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001246# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001248
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001250 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001252#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001253 /* new syscall ABI returns result in R0 */
1254 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1255 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001256#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001257 /* ABI defines result returned in r9 */
1258 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1259 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001260#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001261
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001262#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001263# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001264 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001265# else
1266# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001267 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001268# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001269 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001270 perror("pread");
1271 return -1;
1272 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001273 switch (regs.r_eax) {
1274 case SYS_syscall:
1275 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001276 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1277 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001278 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001279 scno = regs.r_eax;
1280 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001281 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001282# endif /* FREEBSD */
1283# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001284#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001285
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001286 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001287 return 1;
1288}
1289
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001290/* Returns:
1291 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1292 * 1: ok, continue in trace_syscall().
1293 * other: error, trace_syscall() should print error indicator
1294 * ("????" etc) and bail out.
1295 */
1296static int
1297get_scno_on_sysexit(struct tcb *tcp)
1298{
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001299#ifdef LINUX
1300# if defined(S390) || defined(S390X)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001301# elif defined (POWERPC)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001302# elif defined(AVR32)
1303 /*
1304 * Read complete register set in one go.
1305 */
1306 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1307 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001308# elif defined(BFIN)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001309# elif defined (I386)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001310 if (upeek(tcp, 4*EAX, &eax) < 0)
1311 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001312# elif defined (X86_64)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001313 if (upeek(tcp, 8*RAX, &rax) < 0)
1314 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001315# elif defined(IA64)
1316# define IA64_PSR_IS ((long)1 << 34)
1317 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1318 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001319 if (upeek(tcp, PT_R8, &r8) < 0)
1320 return -1;
1321 if (upeek(tcp, PT_R10, &r10) < 0)
1322 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001323# elif defined (ARM)
1324 /*
1325 * Read complete register set in one go.
1326 */
1327 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1328 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001329# elif defined (M68K)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001330# elif defined (LINUX_MIPSN32)
1331 unsigned long long regs[38];
1332
1333 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1334 return -1;
1335 a3 = regs[REG_A3];
1336 r2 = regs[REG_V0];
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001337# elif defined (MIPS)
1338 if (upeek(tcp, REG_A3, &a3) < 0)
1339 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001340 if (upeek(tcp, REG_V0, &r2) < 0)
1341 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001342# elif defined (ALPHA)
1343 if (upeek(tcp, REG_A3, &a3) < 0)
1344 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001345 if (upeek(tcp, REG_R0, &r0) < 0)
1346 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001347# elif defined (SPARC) || defined (SPARC64)
1348 /* Everything we need is in the current register set. */
1349 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1350 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001351# elif defined(HPPA)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001352# elif defined(SH)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001353# elif defined(SH64)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001354# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001355# elif defined(TILE)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001356# elif defined(MICROBLAZE)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001357# endif
1358#endif /* LINUX */
1359
1360#ifdef SUNOS4
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001361#elif defined(SH)
1362 /* new syscall ABI returns result in R0 */
1363 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1364 return -1;
1365#elif defined(SH64)
1366 /* ABI defines result returned in r9 */
1367 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1368 return -1;
1369#endif
1370
1371#ifdef USE_PROCFS
Denys Vlasenko77a74592011-08-24 16:56:03 +02001372# ifndef HAVE_PR_SYSCALL
1373# ifdef FREEBSD
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001374 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1375 perror("pread");
1376 return -1;
1377 }
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001378# endif /* FREEBSD */
1379# endif /* !HAVE_PR_SYSCALL */
1380#endif /* USE_PROCFS */
1381
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001382 return 1;
1383}
Pavel Machek4dc3b142000-02-01 17:58:41 +00001384
Roland McGrath17352792005-06-07 23:21:26 +00001385long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001386known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001387{
1388 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001389#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001390 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1391 scno = sysent[scno].native_scno;
1392 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001393#endif
Roland McGrath17352792005-06-07 23:21:26 +00001394 scno += NR_SYSCALL_BASE;
1395 return scno;
1396}
1397
Roland McGratheb9e2e82009-06-02 16:49:22 -07001398/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001399 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001400 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001401 * 1: ok, continue in trace_syscall().
1402 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001403 * ("????" etc) and bail out.
1404 */
Roland McGratha4d48532005-06-08 20:45:28 +00001405static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001406syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001407{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001408#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001409 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001410
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001411 if (entering(tcp)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001412 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001413 if (
1414 scno == SYS_fork
1415#ifdef SYS_vfork
1416 || scno == SYS_vfork
1417#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001418#ifdef SYS_fork1
1419 || scno == SYS_fork1
1420#endif /* SYS_fork1 */
1421#ifdef SYS_forkall
1422 || scno == SYS_forkall
1423#endif /* SYS_forkall */
1424#ifdef SYS_rfork1
1425 || scno == SYS_rfork1
1426#endif /* SYS_fork1 */
1427#ifdef SYS_rforkall
1428 || scno == SYS_rforkall
1429#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001430 ) {
1431 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001432 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001433 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001434 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435 }
1436 else {
1437 fprintf(stderr, "syscall: missing entry\n");
1438 tcp->flags |= TCB_INSYSCALL;
1439 }
1440 }
1441 }
1442 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001443 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001444 fprintf(stderr, "syscall: missing exit\n");
1445 tcp->flags &= ~TCB_INSYSCALL;
1446 }
1447 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001448#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001449
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001450#ifdef SUNOS4
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001451 if (entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452 if (scno == 0) {
1453 fprintf(stderr, "syscall: missing entry\n");
1454 tcp->flags |= TCB_INSYSCALL;
1455 }
1456 }
1457 else {
1458 if (scno != 0) {
1459 if (debug) {
1460 /*
1461 * This happens when a signal handler
1462 * for a signal which interrupted a
1463 * a system call makes another system call.
1464 */
1465 fprintf(stderr, "syscall: missing exit\n");
1466 }
1467 tcp->flags &= ~TCB_INSYSCALL;
1468 }
1469 }
1470#endif /* SUNOS4 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001471
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001473 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001474#if defined (I386)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001475 /* With PTRACE_O_TRACEEXEC, post-execve SIGTRAP is disabled.
1476 * Every extra ptrace call is expensive, so check EAX
1477 * on syscall entry only if PTRACE_O_TRACEEXEC is not enabled:
1478 */
1479 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
1480 if (upeek(tcp, 4*EAX, &eax) < 0)
1481 return -1;
1482 if (eax != -ENOSYS) {
1483 if (debug)
1484 fprintf(stderr, "not a syscall entry (eax = %ld)\n", eax);
1485 return 0;
1486 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001487 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001488#elif defined (X86_64)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001489 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
1490 if (upeek(tcp, 8*RAX, &rax) < 0)
1491 return -1;
1492 if (current_personality == 1)
1493 rax = (long int)(int)rax; /* sign extend from 32 bits */
1494 if (rax != -ENOSYS && entering(tcp)) {
1495 if (debug)
1496 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1497 return 0;
1498 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001499 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001500#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001501 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001502 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001503 if (syscall_mode != -ENOSYS)
1504 syscall_mode = tcp->scno;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001505 if (gpr2 != syscall_mode && entering(tcp)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001506 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001507 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001508 return 0;
1509 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001510 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1511 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1512 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1513 /*
1514 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1515 * flag set for the post-execve SIGTRAP to see and reset.
1516 */
1517 gpr2 = 0;
1518 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001519#elif defined (POWERPC)
1520# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001521 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001522 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001523 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001524 return -1;
1525 if (flags & SO_MASK)
1526 result = -result;
1527#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001528 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001529 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001530 if (d0 != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001531 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001532 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001533 return 0;
1534 }
1535#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001536 /*
1537 * Nothing required
1538 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001539#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001540 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001541 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001542#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001543 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001544 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001545#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001546 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001547 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001548 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001549 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001550 if (ia32 && r8 != -ENOSYS && entering(tcp)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001551 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001552 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001553 return 0;
1554 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001555#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001556 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001557 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001558 if (r10 != -ENOSYS && entering(tcp)) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001559 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001560 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001561 return 0;
1562 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001563#elif defined(MICROBLAZE)
1564 if (upeek(tcp, 3 * 4, &r3) < 0)
1565 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001566 if (r3 != -ENOSYS && entering(tcp)) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001567 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001568 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001569 return 0;
1570 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001571#endif
1572#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001573 return 1;
1574}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001575
Roland McGrathc1e45922008-05-27 23:18:29 +00001576#ifdef LINUX
1577/*
1578 * Check the syscall return value register value for whether it is
1579 * a negated errno code indicating an error, or a success return value.
1580 */
1581static inline int
1582is_negated_errno(unsigned long int val)
1583{
1584 unsigned long int max = -(long int) nerrnos;
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001585# if SUPPORTED_PERSONALITIES > 1
Roland McGrathc1e45922008-05-27 23:18:29 +00001586 if (personality_wordsize[current_personality] < sizeof(val)) {
1587 val = (unsigned int) val;
1588 max = (unsigned int) max;
1589 }
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001590# endif
Roland McGrathc1e45922008-05-27 23:18:29 +00001591 return val > max;
1592}
1593#endif
1594
Roland McGratha4d48532005-06-08 20:45:28 +00001595static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001596get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001597{
1598 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001600 int check_errno = 1;
1601 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1602 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1603 check_errno = 0;
1604 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001605# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001606 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001607 tcp->u_rval = -1;
1608 u_error = -gpr2;
1609 }
1610 else {
1611 tcp->u_rval = gpr2;
1612 u_error = 0;
1613 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001614# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001615 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001616 tcp->u_rval = -1;
1617 u_error = -eax;
1618 }
1619 else {
1620 tcp->u_rval = eax;
1621 u_error = 0;
1622 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001623# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001624 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001625 tcp->u_rval = -1;
1626 u_error = -rax;
1627 }
1628 else {
1629 tcp->u_rval = rax;
1630 u_error = 0;
1631 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001632# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001633 if (ia32) {
1634 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001635
Roland McGrathc1e45922008-05-27 23:18:29 +00001636 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001637 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001638 tcp->u_rval = -1;
1639 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001640 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001641 else {
1642 tcp->u_rval = err;
1643 u_error = 0;
1644 }
1645 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001646 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001647 tcp->u_rval = -1;
1648 u_error = r8;
1649 } else {
1650 tcp->u_rval = r8;
1651 u_error = 0;
1652 }
1653 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001654# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001655 if (check_errno && a3) {
1656 tcp->u_rval = -1;
1657 u_error = r2;
1658 } else {
1659 tcp->u_rval = r2;
1660 u_error = 0;
1661 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001662# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001663 if (check_errno && is_negated_errno(result)) {
1664 tcp->u_rval = -1;
1665 u_error = -result;
1666 }
1667 else {
1668 tcp->u_rval = result;
1669 u_error = 0;
1670 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001671# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001672 if (check_errno && is_negated_errno(d0)) {
1673 tcp->u_rval = -1;
1674 u_error = -d0;
1675 }
1676 else {
1677 tcp->u_rval = d0;
1678 u_error = 0;
1679 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001680# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001681 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1682 tcp->u_rval = -1;
1683 u_error = -regs.ARM_r0;
1684 }
1685 else {
1686 tcp->u_rval = regs.ARM_r0;
1687 u_error = 0;
1688 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001689# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001690 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1691 tcp->u_rval = -1;
1692 u_error = -regs.r12;
1693 }
1694 else {
1695 tcp->u_rval = regs.r12;
1696 u_error = 0;
1697 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001698# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001699 if (check_errno && is_negated_errno(r0)) {
1700 tcp->u_rval = -1;
1701 u_error = -r0;
1702 } else {
1703 tcp->u_rval = r0;
1704 u_error = 0;
1705 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001706# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001707 if (check_errno && a3) {
1708 tcp->u_rval = -1;
1709 u_error = r0;
1710 }
1711 else {
1712 tcp->u_rval = r0;
1713 u_error = 0;
1714 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001715# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001716 if (check_errno && regs.psr & PSR_C) {
1717 tcp->u_rval = -1;
1718 u_error = regs.u_regs[U_REG_O0];
1719 }
1720 else {
1721 tcp->u_rval = regs.u_regs[U_REG_O0];
1722 u_error = 0;
1723 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001724# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001725 if (check_errno && regs.tstate & 0x1100000000UL) {
1726 tcp->u_rval = -1;
1727 u_error = regs.u_regs[U_REG_O0];
1728 }
1729 else {
1730 tcp->u_rval = regs.u_regs[U_REG_O0];
1731 u_error = 0;
1732 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001733# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001734 if (check_errno && is_negated_errno(r28)) {
1735 tcp->u_rval = -1;
1736 u_error = -r28;
1737 }
1738 else {
1739 tcp->u_rval = r28;
1740 u_error = 0;
1741 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001742# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001743 /* interpret R0 as return value or error number */
1744 if (check_errno && is_negated_errno(r0)) {
1745 tcp->u_rval = -1;
1746 u_error = -r0;
1747 }
1748 else {
1749 tcp->u_rval = r0;
1750 u_error = 0;
1751 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001752# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001753 /* interpret result as return value or error number */
1754 if (check_errno && is_negated_errno(r9)) {
1755 tcp->u_rval = -1;
1756 u_error = -r9;
1757 }
1758 else {
1759 tcp->u_rval = r9;
1760 u_error = 0;
1761 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001762# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001763 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1764 tcp->u_rval = -1;
1765 u_error = -r10;
1766 }
1767 else {
1768 tcp->u_rval = r10;
1769 u_error = 0;
1770 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001771# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001772 long rval;
1773 /* interpret result as return value or error number */
1774 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1775 return -1;
1776 if (check_errno && rval < 0 && rval > -nerrnos) {
1777 tcp->u_rval = -1;
1778 u_error = -rval;
1779 }
1780 else {
1781 tcp->u_rval = rval;
1782 u_error = 0;
1783 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001784# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001785 /* interpret result as return value or error number */
1786 if (check_errno && is_negated_errno(r3)) {
1787 tcp->u_rval = -1;
1788 u_error = -r3;
1789 }
1790 else {
1791 tcp->u_rval = r3;
1792 u_error = 0;
1793 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001794# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795#endif /* LINUX */
1796#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001797 /* get error code from user struct */
1798 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1799 return -1;
1800 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001801
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001802 /* get system call return value */
1803 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1804 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001805#endif /* SUNOS4 */
1806#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001807# ifdef SPARC
1808 /* Judicious guessing goes a long way. */
1809 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1810 tcp->u_rval = -1;
1811 u_error = tcp->status.pr_reg[R_O0];
1812 }
1813 else {
1814 tcp->u_rval = tcp->status.pr_reg[R_O0];
1815 u_error = 0;
1816 }
1817# endif /* SPARC */
1818# ifdef I386
1819 /* Wanna know how to kill an hour single-stepping? */
1820 if (tcp->status.PR_REG[EFL] & 0x1) {
1821 tcp->u_rval = -1;
1822 u_error = tcp->status.PR_REG[EAX];
1823 }
1824 else {
1825 tcp->u_rval = tcp->status.PR_REG[EAX];
1826# ifdef HAVE_LONG_LONG
1827 tcp->u_lrval =
1828 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1829 tcp->status.PR_REG[EAX];
1830# endif
1831 u_error = 0;
1832 }
1833# endif /* I386 */
1834# ifdef X86_64
1835 /* Wanna know how to kill an hour single-stepping? */
1836 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1837 tcp->u_rval = -1;
1838 u_error = tcp->status.PR_REG[RAX];
1839 }
1840 else {
1841 tcp->u_rval = tcp->status.PR_REG[RAX];
1842 u_error = 0;
1843 }
1844# endif /* X86_64 */
1845# ifdef MIPS
1846 if (tcp->status.pr_reg[CTX_A3]) {
1847 tcp->u_rval = -1;
1848 u_error = tcp->status.pr_reg[CTX_V0];
1849 }
1850 else {
1851 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1852 u_error = 0;
1853 }
1854# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001855#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001856#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001857 if (regs.r_eflags & PSL_C) {
1858 tcp->u_rval = -1;
1859 u_error = regs.r_eax;
1860 } else {
1861 tcp->u_rval = regs.r_eax;
1862 tcp->u_lrval =
1863 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1864 u_error = 0;
1865 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001866#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001867 tcp->u_error = u_error;
1868 return 1;
1869}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001870
Roland McGrathb69f81b2002-12-21 23:25:18 +00001871int
Denys Vlasenko12014262011-05-30 14:00:14 +02001872force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001873{
1874#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001875# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001876 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001877 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1878 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001879# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001880 eax = error ? -error : rval;
1881 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1882 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001883# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001884 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001885 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001886 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001887# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001888 if (ia32) {
1889 r8 = error ? -error : rval;
1890 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1891 return -1;
1892 }
1893 else {
1894 if (error) {
1895 r8 = error;
1896 r10 = -1;
1897 }
1898 else {
1899 r8 = rval;
1900 r10 = 0;
1901 }
1902 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1903 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1904 return -1;
1905 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001906# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001907 r0 = error ? -error : rval;
1908 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1909 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001910# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001911 if (error) {
1912 r2 = error;
1913 a3 = -1;
1914 }
1915 else {
1916 r2 = rval;
1917 a3 = 0;
1918 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001919 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001920 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1921 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001922 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001923# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001924 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001925 return -1;
1926 if (error) {
1927 flags |= SO_MASK;
1928 result = error;
1929 }
1930 else {
1931 flags &= ~SO_MASK;
1932 result = rval;
1933 }
Roland McGratheb285352003-01-14 09:59:00 +00001934 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1935 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001936 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001937# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001938 d0 = error ? -error : rval;
1939 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1940 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001941# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001942 regs.ARM_r0 = error ? -error : rval;
1943 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001944 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001945# elif defined(AVR32)
1946 regs.r12 = error ? -error : rval;
1947 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1948 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001949# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001950 if (error) {
1951 a3 = -1;
1952 r0 = error;
1953 }
1954 else {
1955 a3 = 0;
1956 r0 = rval;
1957 }
1958 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1959 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1960 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001961# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001962 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1963 return -1;
1964 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001965 regs.psr |= PSR_C;
1966 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001967 }
1968 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001969 regs.psr &= ~PSR_C;
1970 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001971 }
1972 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1973 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001974# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001975 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1976 return -1;
1977 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001978 regs.tstate |= 0x1100000000UL;
1979 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001980 }
1981 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001982 regs.tstate &= ~0x1100000000UL;
1983 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001984 }
1985 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1986 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001987# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001988 r28 = error ? -error : rval;
1989 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1990 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001991# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001992 r0 = error ? -error : rval;
1993 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1994 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001995# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001996 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001997 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1998 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001999# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00002000#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002001
Roland McGrathb69f81b2002-12-21 23:25:18 +00002002#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07002003 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
2004 error << 24) < 0 ||
2005 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00002006 return -1;
2007#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002008
Roland McGrathb69f81b2002-12-21 23:25:18 +00002009#ifdef SVR4
2010 /* XXX no clue */
2011 return -1;
2012#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002013
Roland McGrathb69f81b2002-12-21 23:25:18 +00002014#ifdef FREEBSD
2015 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002016 perror("pread");
2017 return -1;
2018 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00002019 if (error) {
2020 regs.r_eflags |= PSL_C;
2021 regs.r_eax = error;
2022 }
2023 else {
2024 regs.r_eflags &= ~PSL_C;
2025 regs.r_eax = rval;
2026 }
2027 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002028 perror("pwrite");
2029 return -1;
2030 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00002031#endif /* FREEBSD */
2032
2033 /* All branches reach here on success (only). */
2034 tcp->u_error = error;
2035 tcp->u_rval = rval;
2036 return 0;
2037}
2038
Roland McGratha4d48532005-06-08 20:45:28 +00002039static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002040syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002041{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002042#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002043 int i, nargs;
2044
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002045 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002046 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002047 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002048 nargs = tcp->u_nargs = MAX_ARGS;
2049
2050# if defined(S390) || defined(S390X)
2051 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002052 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
2053 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002054# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002055 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002056 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
2057 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002058# elif defined(IA64)
2059 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002060 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002061 long rbs_end;
2062 /* be backwards compatible with kernel < 2.4.4... */
2063# ifndef PT_RBS_END
2064# define PT_RBS_END PT_AR_BSP
2065# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002066
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002067 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
2068 return -1;
2069 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002070 return -1;
2071
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002072 sof = (cfm >> 0) & 0x7f;
2073 sol = (cfm >> 7) & 0x7f;
2074 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
2075
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002076 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002077 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2078 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2079 return -1;
2080 }
2081 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002082 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
2083 PT_R9 /* ECX = out1 */,
2084 PT_R10 /* EDX = out2 */,
2085 PT_R14 /* ESI = out3 */,
2086 PT_R15 /* EDI = out4 */,
2087 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002088
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002089 for (i = 0; i < nargs; ++i) {
2090 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2091 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002092 /* truncate away IVE sign-extension */
2093 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002094 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002095 }
2096# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2097 /* N32 and N64 both use up to six registers. */
2098 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002099
2100 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2101 return -1;
2102
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002103 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002104 tcp->u_arg[i] = regs[REG_A0 + i];
2105# if defined(LINUX_MIPSN32)
2106 tcp->ext_arg[i] = regs[REG_A0 + i];
2107# endif
2108 }
2109# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002110 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002111 long sp;
2112
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002113 if (upeek(tcp, REG_SP, &sp) < 0)
2114 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002115 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002116 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2117 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002118 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002119 (char *)(tcp->u_arg + 4));
2120 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002121 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002122 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002123 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002124 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002125# elif defined(POWERPC)
2126# ifndef PT_ORIG_R3
2127# define PT_ORIG_R3 34
2128# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002129 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002130 if (upeek(tcp, (i==0) ?
2131 (sizeof(unsigned long) * PT_ORIG_R3) :
2132 ((i+PT_R3) * sizeof(unsigned long)),
2133 &tcp->u_arg[i]) < 0)
2134 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002135 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002136# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002137 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002138 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2139# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002140 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002141 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2142 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002143# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002144 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002145 tcp->u_arg[i] = regs.uregs[i];
2146# elif defined(AVR32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002147 static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
2148 &regs.r11,
2149 &regs.r10,
2150 &regs.r9,
2151 &regs.r5,
2152 &regs.r3 };
2153 for (i = 0; i < nargs; ++i)
2154 tcp->u_arg[i] = *argregp[i];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002155# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002156 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 +02002157
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002158 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002159 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2160 return -1;
2161# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002162 static const int syscall_regs[MAX_ARGS] = {
2163 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
2164 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002165 };
2166
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002167 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002168 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002169 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002170# elif defined(SH64)
2171 int i;
2172 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002173 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002174
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002175 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002176 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2177 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002178# elif defined(X86_64)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002179 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2180 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2181 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002182 };
2183
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002184 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002185 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002186 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002187# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002188 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002189 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2190 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002191# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002192 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002193 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002194 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002195 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002196
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002197 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002198 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2199 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002200# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002201 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002202 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2203 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002204# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002205 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002206 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2207 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002208# else /* Other architecture (like i386) (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002209 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002210 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2211 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002212# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002213#endif /* LINUX */
2214#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002215 int i, nargs;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002216 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002217 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002218 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002219 nargs = tcp->u_nargs = MAX_ARGS;
2220 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002221 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002222
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002223 if (upeek(tcp, uoff(u_arg[0]) +
2224 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2225 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002226 }
2227#endif /* SUNOS4 */
2228#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002229# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002230 /*
2231 * SGI is broken: even though it has pr_sysarg, it doesn't
2232 * set them on system call entry. Get a clue.
2233 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002234 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002235 tcp->u_nargs = sysent[tcp->scno].nargs;
2236 else
2237 tcp->u_nargs = tcp->status.pr_nsysarg;
2238 if (tcp->u_nargs > 4) {
2239 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002240 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002241 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002242 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002243 }
2244 else {
2245 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002246 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002248# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002249 /*
2250 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2251 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002252 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
John Hughes25299712001-03-06 10:10:06 +00002253 tcp->u_nargs = sysent[tcp->scno].nargs;
2254 else
2255 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2256 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002257 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2258# elif defined(HAVE_PR_SYSCALL)
2259 int i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002260 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002261 tcp->u_nargs = sysent[tcp->scno].nargs;
2262 else
2263 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002264 for (i = 0; i < tcp->u_nargs; i++)
2265 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2266# elif defined(I386)
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002267 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002268 tcp->u_nargs = sysent[tcp->scno].nargs;
2269 else
2270 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002271 if (tcp->u_nargs > 0)
2272 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002273 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2274# else
John Hughes25299712001-03-06 10:10:06 +00002275 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002276# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002277#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002278#ifdef FREEBSD
2279 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2280 sysent[tcp->scno].nargs > tcp->status.val)
2281 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002282 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002283 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002284 if (tcp->u_nargs < 0)
2285 tcp->u_nargs = 0;
2286 if (tcp->u_nargs > MAX_ARGS)
2287 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002288 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002289 case SYS___syscall:
2290 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2291 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002292 break;
2293 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002294 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2295 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002296 break;
2297 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002298 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2299 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002300 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002301 }
2302#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002303 return 1;
2304}
2305
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002306static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002307trace_syscall_entering(struct tcb *tcp)
2308{
2309 int res, scno_good;
2310
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02002311 scno_good = res = get_scno_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002312 if (res == 0)
2313 return res;
2314 if (res == 1)
2315 res = syscall_fixup(tcp);
2316 if (res == 0)
2317 return res;
2318 if (res == 1)
2319 res = syscall_enter(tcp);
2320 if (res == 0)
2321 return res;
2322
2323 if (res != 1) {
2324 printleader(tcp);
2325 tcp->flags &= ~TCB_REPRINT;
2326 tcp_last = tcp;
2327 if (scno_good != 1)
2328 tprintf("????" /* anti-trigraph gap */ "(");
2329 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2330 tprintf("syscall_%lu(", tcp->scno);
2331 else
2332 tprintf("%s(", sysent[tcp->scno].sys_name);
2333 /*
2334 * " <unavailable>" will be added later by the code which
2335 * detects ptrace errors.
2336 */
2337 goto ret;
2338 }
2339
2340 switch (known_scno(tcp)) {
2341#ifdef SYS_socket_subcall
2342 case SYS_socketcall:
2343 decode_subcall(tcp, SYS_socket_subcall,
2344 SYS_socket_nsubcalls, deref_style);
2345 break;
2346#endif
2347#ifdef SYS_ipc_subcall
2348 case SYS_ipc:
2349 decode_subcall(tcp, SYS_ipc_subcall,
2350 SYS_ipc_nsubcalls, shift_style);
2351 break;
2352#endif
2353#ifdef SVR4
2354#ifdef SYS_pgrpsys_subcall
2355 case SYS_pgrpsys:
2356 decode_subcall(tcp, SYS_pgrpsys_subcall,
2357 SYS_pgrpsys_nsubcalls, shift_style);
2358 break;
2359#endif /* SYS_pgrpsys_subcall */
2360#ifdef SYS_sigcall_subcall
2361 case SYS_sigcall:
2362 decode_subcall(tcp, SYS_sigcall_subcall,
2363 SYS_sigcall_nsubcalls, mask_style);
2364 break;
2365#endif /* SYS_sigcall_subcall */
2366 case SYS_msgsys:
2367 decode_subcall(tcp, SYS_msgsys_subcall,
2368 SYS_msgsys_nsubcalls, shift_style);
2369 break;
2370 case SYS_shmsys:
2371 decode_subcall(tcp, SYS_shmsys_subcall,
2372 SYS_shmsys_nsubcalls, shift_style);
2373 break;
2374 case SYS_semsys:
2375 decode_subcall(tcp, SYS_semsys_subcall,
2376 SYS_semsys_nsubcalls, shift_style);
2377 break;
2378 case SYS_sysfs:
2379 decode_subcall(tcp, SYS_sysfs_subcall,
2380 SYS_sysfs_nsubcalls, shift_style);
2381 break;
2382 case SYS_spcall:
2383 decode_subcall(tcp, SYS_spcall_subcall,
2384 SYS_spcall_nsubcalls, shift_style);
2385 break;
2386#ifdef SYS_context_subcall
2387 case SYS_context:
2388 decode_subcall(tcp, SYS_context_subcall,
2389 SYS_context_nsubcalls, shift_style);
2390 break;
2391#endif /* SYS_context_subcall */
2392#ifdef SYS_door_subcall
2393 case SYS_door:
2394 decode_subcall(tcp, SYS_door_subcall,
2395 SYS_door_nsubcalls, door_style);
2396 break;
2397#endif /* SYS_door_subcall */
2398#ifdef SYS_kaio_subcall
2399 case SYS_kaio:
2400 decode_subcall(tcp, SYS_kaio_subcall,
2401 SYS_kaio_nsubcalls, shift_style);
2402 break;
2403#endif
2404#endif /* SVR4 */
2405#ifdef FREEBSD
2406 case SYS_msgsys:
2407 case SYS_shmsys:
2408 case SYS_semsys:
2409 decode_subcall(tcp, 0, 0, table_style);
2410 break;
2411#endif
2412#ifdef SUNOS4
2413 case SYS_semsys:
2414 decode_subcall(tcp, SYS_semsys_subcall,
2415 SYS_semsys_nsubcalls, shift_style);
2416 break;
2417 case SYS_msgsys:
2418 decode_subcall(tcp, SYS_msgsys_subcall,
2419 SYS_msgsys_nsubcalls, shift_style);
2420 break;
2421 case SYS_shmsys:
2422 decode_subcall(tcp, SYS_shmsys_subcall,
2423 SYS_shmsys_nsubcalls, shift_style);
2424 break;
2425#endif
2426 }
2427
2428 internal_syscall(tcp);
2429
2430 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2431 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2432 (tracing_paths && !pathtrace_match(tcp))) {
2433 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
2434 return 0;
2435 }
2436
2437 tcp->flags &= ~TCB_FILTERED;
2438
2439 if (cflag == CFLAG_ONLY_STATS) {
2440 res = 0;
2441 goto ret;
2442 }
2443
2444 printleader(tcp);
2445 tcp->flags &= ~TCB_REPRINT;
2446 tcp_last = tcp;
2447 if (tcp->scno >= nsyscalls || tcp->scno < 0)
2448 tprintf("syscall_%lu(", tcp->scno);
2449 else
2450 tprintf("%s(", sysent[tcp->scno].sys_name);
2451 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2452 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2453 sysent[tcp->scno].sys_func != sys_exit))
2454 res = printargs(tcp);
2455 else
2456 res = (*sysent[tcp->scno].sys_func)(tcp);
2457
2458 if (fflush(tcp->outf) == EOF)
2459 return -1;
2460 ret:
2461 tcp->flags |= TCB_INSYSCALL;
2462 /* Measure the entrance time as late as possible to avoid errors. */
2463 if (dtime || cflag)
2464 gettimeofday(&tcp->etime, NULL);
2465 return res;
2466}
2467
2468static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002469trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002470{
2471 int sys_res;
2472 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002473 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002474 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002475
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002476 /* Measure the exit time as early as possible to avoid errors. */
2477 if (dtime || cflag)
2478 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002479
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002480 /* BTW, why we don't just memorize syscall no. on entry
2481 * in tcp->something?
2482 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02002483 scno_good = res = get_scno_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002484 if (res == 0)
2485 return res;
2486 if (res == 1)
2487 res = syscall_fixup(tcp);
2488 if (res == 0)
2489 return res;
2490 if (res == 1)
2491 res = get_error(tcp);
2492 if (res == 0)
2493 return res;
2494 if (res == 1)
2495 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002496
Grant Edwards8a082772011-04-07 20:25:40 +00002497 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002498 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002499 }
2500
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002501 if (tcp->flags & TCB_REPRINT) {
2502 printleader(tcp);
2503 tprintf("<... ");
2504 if (scno_good != 1)
2505 tprintf("????");
2506 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2507 tprintf("syscall_%lu", tcp->scno);
2508 else
2509 tprintf("%s", sysent[tcp->scno].sys_name);
2510 tprintf(" resumed> ");
2511 }
2512
2513 if (cflag) {
2514 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002515 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002516 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002517 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002518 }
2519 }
2520
2521 if (res != 1) {
2522 tprintf(") ");
2523 tabto(acolumn);
2524 tprintf("= ? <unavailable>");
2525 printtrailer();
2526 tcp->flags &= ~TCB_INSYSCALL;
2527 return res;
2528 }
2529
2530 if (tcp->scno >= nsyscalls || tcp->scno < 0
2531 || (qual_flags[tcp->scno] & QUAL_RAW))
2532 sys_res = printargs(tcp);
2533 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002534 /* FIXME: not_failing_only (IOW, option -z) is broken:
2535 * failure of syscall is known only after syscall return.
2536 * Thus we end up with something like this on, say, ENOENT:
2537 * open("doesnt_exist", O_RDONLY <unfinished ...>
2538 * {next syscall decode}
2539 * whereas the intended result is that open(...) line
2540 * is not shown at all.
2541 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002542 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002543 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002544 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2545 }
2546
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002547 tprintf(") ");
2548 tabto(acolumn);
Denys Vlasenko3b738812011-08-22 02:06:35 +02002549 u_error = tcp->u_error;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002550 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2551 qual_flags[tcp->scno] & QUAL_RAW) {
2552 if (u_error)
2553 tprintf("= -1 (errno %ld)", u_error);
2554 else
2555 tprintf("= %#lx", tcp->u_rval);
2556 }
2557 else if (!(sys_res & RVAL_NONE) && u_error) {
2558 switch (u_error) {
2559#ifdef LINUX
2560 case ERESTARTSYS:
2561 tprintf("= ? ERESTARTSYS (To be restarted)");
2562 break;
2563 case ERESTARTNOINTR:
2564 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2565 break;
2566 case ERESTARTNOHAND:
2567 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2568 break;
2569 case ERESTART_RESTARTBLOCK:
2570 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2571 break;
2572#endif /* LINUX */
2573 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002574 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002575 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002576 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002577 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002578 strerror(u_error));
2579 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002580 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002581 strerror(u_error));
2582 break;
2583 }
2584 if ((sys_res & RVAL_STR) && tcp->auxstr)
2585 tprintf(" (%s)", tcp->auxstr);
2586 }
2587 else {
2588 if (sys_res & RVAL_NONE)
2589 tprintf("= ?");
2590 else {
2591 switch (sys_res & RVAL_MASK) {
2592 case RVAL_HEX:
2593 tprintf("= %#lx", tcp->u_rval);
2594 break;
2595 case RVAL_OCTAL:
2596 tprintf("= %#lo", tcp->u_rval);
2597 break;
2598 case RVAL_UDECIMAL:
2599 tprintf("= %lu", tcp->u_rval);
2600 break;
2601 case RVAL_DECIMAL:
2602 tprintf("= %ld", tcp->u_rval);
2603 break;
2604#ifdef HAVE_LONG_LONG
2605 case RVAL_LHEX:
2606 tprintf("= %#llx", tcp->u_lrval);
2607 break;
2608 case RVAL_LOCTAL:
2609 tprintf("= %#llo", tcp->u_lrval);
2610 break;
2611 case RVAL_LUDECIMAL:
2612 tprintf("= %llu", tcp->u_lrval);
2613 break;
2614 case RVAL_LDECIMAL:
2615 tprintf("= %lld", tcp->u_lrval);
2616 break;
2617#endif
2618 default:
2619 fprintf(stderr,
2620 "invalid rval format\n");
2621 break;
2622 }
2623 }
2624 if ((sys_res & RVAL_STR) && tcp->auxstr)
2625 tprintf(" (%s)", tcp->auxstr);
2626 }
2627 if (dtime) {
2628 tv_sub(&tv, &tv, &tcp->etime);
2629 tprintf(" <%ld.%06ld>",
2630 (long) tv.tv_sec, (long) tv.tv_usec);
2631 }
2632 printtrailer();
2633
2634 dumpio(tcp);
2635 if (fflush(tcp->outf) == EOF)
2636 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002637 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002638 tcp->flags &= ~TCB_INSYSCALL;
2639 return 0;
2640}
2641
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002642int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002643trace_syscall(struct tcb *tcp)
2644{
2645 return exiting(tcp) ?
2646 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2647}
2648
2649int
Denys Vlasenko12014262011-05-30 14:00:14 +02002650printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651{
2652 if (entering(tcp)) {
2653 int i;
2654
2655 for (i = 0; i < tcp->u_nargs; i++)
2656 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2657 }
2658 return 0;
2659}
2660
2661long
Denys Vlasenko12014262011-05-30 14:00:14 +02002662getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002663{
2664 long val = -1;
2665
2666#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002667#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002668 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002669 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002670 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002671 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002672#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002673 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002674 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002675#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002676 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002677 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002678#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002679#endif /* LINUX */
2680
2681#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002682 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002683 return -1;
2684#endif /* SUNOS4 */
2685
2686#ifdef SVR4
2687#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002688 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002689#endif /* SPARC */
2690#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002691 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002692#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002693#ifdef X86_64
2694 val = tcp->status.PR_REG[RDX];
2695#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002696#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002697 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002698#endif /* MIPS */
2699#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002700
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002701#ifdef FREEBSD
2702 struct reg regs;
2703 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2704 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002705#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002706 return val;
2707}
2708
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002709#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710/*
2711 * Apparently, indirect system calls have already be converted by ptrace(2),
2712 * so if you see "indir" this program has gone astray.
2713 */
2714int
Denys Vlasenko12014262011-05-30 14:00:14 +02002715sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002716{
2717 int i, scno, nargs;
2718
2719 if (entering(tcp)) {
Denys Vlasenko5d645812011-08-20 12:48:18 +02002720 scno = tcp->u_arg[0];
2721 if (scno > nsyscalls) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002722 fprintf(stderr, "Bogus syscall: %u\n", scno);
2723 return 0;
2724 }
2725 nargs = sysent[scno].nargs;
2726 tprintf("%s", sysent[scno].sys_name);
2727 for (i = 0; i < nargs; i++)
2728 tprintf(", %#lx", tcp->u_arg[i+1]);
2729 }
2730 return 0;
2731}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002732#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002733
2734int
2735is_restart_error(struct tcb *tcp)
2736{
2737#ifdef LINUX
2738 if (!syserror(tcp))
2739 return 0;
2740 switch (tcp->u_error) {
2741 case ERESTARTSYS:
2742 case ERESTARTNOINTR:
2743 case ERESTARTNOHAND:
2744 case ERESTART_RESTARTBLOCK:
2745 return 1;
2746 default:
2747 break;
2748 }
2749#endif /* LINUX */
2750 return 0;
2751}