blob: 8ffa4a6a24bb9800633191cac8a496813a3d89f4 [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)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000757 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200758 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000759
760 if (syscall_mode != -ENOSYS) {
761 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000762 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000763 */
764 scno = syscall_mode;
765 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000766 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000767 * Old style of "passing" the scno via the SVC instruction.
768 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000769 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200770 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200771 static const int gpr_offset[16] = {
772 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
773 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
774 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
775 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
776 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000777
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000778 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000779 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000780 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000781 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000782 if (errno) {
783 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000784 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000785 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000786
787 /*
788 * We have to check if the SVC got executed directly or via an
789 * EXECUTE instruction. In case of EXECUTE it is necessary to do
790 * instruction decoding to derive the system call number.
791 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
792 * so that this doesn't work if a SVC opcode is part of an EXECUTE
793 * opcode. Since there is no way to find out the opcode size this
794 * is the best we can do...
795 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000796 if ((opcode & 0xff00) == 0x0a00) {
797 /* SVC opcode */
798 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000799 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000800 else {
801 /* SVC got executed by EXECUTE instruction */
802
803 /*
804 * Do instruction decoding of EXECUTE. If you really want to
805 * understand this, read the Principles of Operations.
806 */
807 svc_addr = (void *) (opcode & 0xfff);
808
809 tmp = 0;
810 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000811 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000812 return -1;
813 svc_addr += tmp;
814
815 tmp = 0;
816 offset_reg = (opcode & 0x0000f000) >> 12;
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
Denys Vlasenkofb036672009-01-23 16:30:26 +0000821 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000822 if (errno)
823 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000824# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000825 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000826# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000827 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000828# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000829 tmp = 0;
830 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000831 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000832 return -1;
833
834 scno = (scno | tmp) & 0xff;
835 }
836 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000837# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000838 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000839 return -1;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200840# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200841 /* TODO: speed up strace by not doing this at every syscall.
842 * We only need to do it after execve.
843 */
844 int currpers;
845 long val;
846 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200847
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200848 /* Check for 64/32 bit mode. */
849 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
850 return -1;
851 /* SF is bit 0 of MSR */
852 if (val < 0)
853 currpers = 0;
854 else
855 currpers = 1;
856 if (currpers != current_personality) {
857 static const char *const names[] = {"64 bit", "32 bit"};
858 set_personality(currpers);
859 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
860 pid, names[current_personality]);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200861 }
862# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000863# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200864 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000865 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
866 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200867 scno = regs.r8;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000868# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000869 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000870 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000871# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000872 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000873 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000874# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000875 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000876 return -1;
877
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200878 /* TODO: speed up strace by not doing this at every syscall.
879 * We only need to do it after execve.
880 */
881 int currpers;
882 long val;
883 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000884
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200885 /* Check CS register value. On x86-64 linux it is:
886 * 0x33 for long mode (64 bit)
887 * 0x23 for compatibility mode (32 bit)
888 * It takes only one ptrace and thus doesn't need
889 * to be cached.
890 */
891 if (upeek(tcp, 8*CS, &val) < 0)
892 return -1;
893 switch (val) {
894 case 0x23: currpers = 1; break;
895 case 0x33: currpers = 0; break;
896 default:
897 fprintf(stderr, "Unknown value CS=0x%02X while "
898 "detecting personality of process "
899 "PID=%d\n", (int)val, pid);
900 currpers = current_personality;
901 break;
902 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000903# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200904 /* This version analyzes the opcode of a syscall instruction.
905 * (int 0x80 on i386 vs. syscall on x86-64)
906 * It works, but is too complicated.
907 */
908 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000909
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200910 if (upeek(tcp, 8*RIP, &rip) < 0)
911 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000912
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200913 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
914 rip -= 2;
915 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000916
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200917 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
918 if (errno)
919 fprintf(stderr, "ptrace_peektext failed: %s\n",
920 strerror(errno));
921 switch (call & 0xffff) {
922 /* x86-64: syscall = 0x0f 0x05 */
923 case 0x050f: currpers = 0; break;
924 /* i386: int 0x80 = 0xcd 0x80 */
925 case 0x80cd: currpers = 1; break;
926 default:
927 currpers = current_personality;
928 fprintf(stderr,
929 "Unknown syscall opcode (0x%04X) while "
930 "detecting personality of process "
931 "PID=%d\n", (int)call, pid);
932 break;
933 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000934# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200935 if (currpers != current_personality) {
936 static const char *const names[] = {"64 bit", "32 bit"};
937 set_personality(currpers);
938 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
939 pid, names[current_personality]);
Roland McGrath761b5d72002-12-15 23:58:31 +0000940 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000941# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000942# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200943 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000944 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200945 if (ia32) {
946 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
947 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000948 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200949 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000950 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200951 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000952# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200953 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000954 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000955 return -1;
956
957 /*
958 * We only need to grab the syscall number on syscall entry.
959 */
960 if (regs.ARM_ip == 0) {
961 /*
962 * Note: we only deal with only 32-bit CPUs here.
963 */
964 if (regs.ARM_cpsr & 0x20) {
965 /*
966 * Get the Thumb-mode system call number
967 */
968 scno = regs.ARM_r7;
969 } else {
970 /*
971 * Get the ARM-mode system call number
972 */
973 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000974 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +0000975 if (errno)
976 return -1;
977
Roland McGrathf691bd22006-04-25 07:34:41 +0000978 /* Handle the EABI syscall convention. We do not
979 bother converting structures between the two
980 ABIs, but basic functionality should work even
981 if strace and the traced program have different
982 ABIs. */
983 if (scno == 0xef000000) {
984 scno = regs.ARM_r7;
985 } else {
986 if ((scno & 0x0ff00000) != 0x0f900000) {
987 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
988 scno);
989 return -1;
990 }
Roland McGrath0f87c492003-06-03 23:29:04 +0000991
Roland McGrathf691bd22006-04-25 07:34:41 +0000992 /*
993 * Fixup the syscall number
994 */
995 scno &= 0x000fffff;
996 }
Roland McGrath0f87c492003-06-03 23:29:04 +0000997 }
Roland McGrath56703312008-05-20 01:35:55 +0000998 if (scno & 0x0f0000) {
999 /*
1000 * Handle ARM specific syscall
1001 */
1002 set_personality(1);
1003 scno &= 0x0000ffff;
1004 } else
1005 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001006
Roland McGrath0f87c492003-06-03 23:29:04 +00001007 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001008 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1009 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001010 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001011# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001012 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001013 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001014# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001015 unsigned long long regs[38];
1016
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001017 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001018 return -1;
1019 a3 = regs[REG_A3];
1020 r2 = regs[REG_V0];
1021
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001022 scno = r2;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001023 if (scno < 0 || scno > nsyscalls) {
1024 if (a3 == 0 || a3 == -1) {
1025 if (debug)
1026 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001027 return 0;
1028 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001029 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001030# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001031 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001032 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001033 if (upeek(tcp, REG_V0, &scno) < 0)
1034 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001035
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001036 if (scno < 0 || scno > nsyscalls) {
1037 if (a3 == 0 || a3 == -1) {
1038 if (debug)
1039 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001040 return 0;
1041 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001042 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001043# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001044 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001045 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001046 if (upeek(tcp, REG_R0, &scno) < 0)
1047 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001049 /*
1050 * Do some sanity checks to figure out if it's
1051 * really a syscall entry
1052 */
1053 if (scno < 0 || scno > nsyscalls) {
1054 if (a3 == 0 || a3 == -1) {
1055 if (debug)
1056 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001057 return 0;
1058 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001060# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001062 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063 return -1;
1064
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001065 /* Disassemble the syscall trap. */
1066 /* Retrieve the syscall trap instruction. */
1067 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001068# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001069 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1070 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001071# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001072 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001073# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001074 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001075 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001076
1077 /* Disassemble the trap to see what personality to use. */
1078 switch (trap) {
1079 case 0x91d02010:
1080 /* Linux/SPARC syscall trap. */
1081 set_personality(0);
1082 break;
1083 case 0x91d0206d:
1084 /* Linux/SPARC64 syscall trap. */
1085 set_personality(2);
1086 break;
1087 case 0x91d02000:
1088 /* SunOS syscall trap. (pers 1) */
1089 fprintf(stderr, "syscall: SunOS no support\n");
1090 return -1;
1091 case 0x91d02008:
1092 /* Solaris 2.x syscall trap. (per 2) */
1093 set_personality(1);
1094 break;
1095 case 0x91d02009:
1096 /* NetBSD/FreeBSD syscall trap. */
1097 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1098 return -1;
1099 case 0x91d02027:
1100 /* Solaris 2.x gettimeofday */
1101 set_personality(1);
1102 break;
1103 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001104# if defined (SPARC64)
1105 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1106# else
1107 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1108# endif
1109 return -1;
1110 }
1111
1112 /* Extract the system call number from the registers. */
1113 if (trap == 0x91d02027)
1114 scno = 156;
1115 else
1116 scno = regs.u_regs[U_REG_G1];
1117 if (scno == 0) {
1118 scno = regs.u_regs[U_REG_O0];
1119 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1120 }
1121# elif defined(HPPA)
1122 if (upeek(tcp, PT_GR20, &scno) < 0)
1123 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001124# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001125 /*
1126 * In the new syscall ABI, the system call number is in R3.
1127 */
1128 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1129 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001130
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001131 if (scno < 0) {
1132 /* Odd as it may seem, a glibc bug has been known to cause
1133 glibc to issue bogus negative syscall numbers. So for
1134 our purposes, make strace print what it *should* have been */
1135 long correct_scno = (scno & 0xff);
1136 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001137 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001138 "Detected glibc bug: bogus system call"
1139 " number = %ld, correcting to %ld\n",
1140 scno,
1141 correct_scno);
1142 scno = correct_scno;
1143 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001144# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001145 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001146 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001147 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001148# elif defined(CRISV10) || defined(CRISV32)
1149 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1150 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001151# elif defined(TILE)
1152 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1153 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001154# elif defined(MICROBLAZE)
1155 if (upeek(tcp, 0, &scno) < 0)
1156 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001157# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001158#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001159
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001161 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001162 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001163#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001164 /* new syscall ABI returns result in R0 */
1165 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1166 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001167#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001168 /* ABI defines result returned in r9 */
1169 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1170 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001172
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001173#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001174# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001175 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001176# else
1177# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001178 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001179# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001180 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001181 perror("pread");
1182 return -1;
1183 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001184 switch (regs.r_eax) {
1185 case SYS_syscall:
1186 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001187 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1188 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001189 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001190 scno = regs.r_eax;
1191 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001192 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001193# endif /* FREEBSD */
1194# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001195#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001196
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001197 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001198 return 1;
1199}
1200
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001201/* Returns:
1202 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1203 * 1: ok, continue in trace_syscall().
1204 * other: error, trace_syscall() should print error indicator
1205 * ("????" etc) and bail out.
1206 */
1207static int
1208get_scno_on_sysexit(struct tcb *tcp)
1209{
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001210#ifdef LINUX
1211# if defined(S390) || defined(S390X)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001212# elif defined (POWERPC)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001213# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001214 /* Read complete register set in one go. */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001215 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1216 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001217# elif defined(BFIN)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001218# elif defined (I386)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001219 if (upeek(tcp, 4*EAX, &eax) < 0)
1220 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001221# elif defined (X86_64)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001222 if (upeek(tcp, 8*RAX, &rax) < 0)
1223 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001224# elif defined(IA64)
1225# define IA64_PSR_IS ((long)1 << 34)
1226 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1227 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001228 if (upeek(tcp, PT_R8, &r8) < 0)
1229 return -1;
1230 if (upeek(tcp, PT_R10, &r10) < 0)
1231 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001232# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001233 /* Read complete register set in one go. */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001234 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1235 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001236# elif defined (M68K)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001237# elif defined (LINUX_MIPSN32)
1238 unsigned long long regs[38];
1239
1240 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1241 return -1;
1242 a3 = regs[REG_A3];
1243 r2 = regs[REG_V0];
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001244# elif defined (MIPS)
1245 if (upeek(tcp, REG_A3, &a3) < 0)
1246 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001247 if (upeek(tcp, REG_V0, &r2) < 0)
1248 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001249# elif defined (ALPHA)
1250 if (upeek(tcp, REG_A3, &a3) < 0)
1251 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001252 if (upeek(tcp, REG_R0, &r0) < 0)
1253 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001254# elif defined (SPARC) || defined (SPARC64)
1255 /* Everything we need is in the current register set. */
1256 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1257 return -1;
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001258# elif defined(HPPA)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001259# elif defined(SH)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001260# elif defined(SH64)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001261# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001262# elif defined(TILE)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001263# elif defined(MICROBLAZE)
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001264# endif
1265#endif /* LINUX */
1266
1267#ifdef SUNOS4
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001268#elif defined(SH)
1269 /* new syscall ABI returns result in R0 */
1270 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1271 return -1;
1272#elif defined(SH64)
1273 /* ABI defines result returned in r9 */
1274 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1275 return -1;
1276#endif
1277
1278#ifdef USE_PROCFS
Denys Vlasenko77a74592011-08-24 16:56:03 +02001279# ifndef HAVE_PR_SYSCALL
1280# ifdef FREEBSD
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001281 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1282 perror("pread");
1283 return -1;
1284 }
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001285# endif /* FREEBSD */
1286# endif /* !HAVE_PR_SYSCALL */
1287#endif /* USE_PROCFS */
1288
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02001289 return 1;
1290}
Pavel Machek4dc3b142000-02-01 17:58:41 +00001291
Roland McGrath17352792005-06-07 23:21:26 +00001292long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001293known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001294{
1295 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001296#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001297 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1298 scno = sysent[scno].native_scno;
1299 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001300#endif
Roland McGrath17352792005-06-07 23:21:26 +00001301 scno += NR_SYSCALL_BASE;
1302 return scno;
1303}
1304
Roland McGratheb9e2e82009-06-02 16:49:22 -07001305/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001306 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001307 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001308 * 1: ok, continue in trace_syscall().
1309 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001310 * ("????" etc) and bail out.
1311 */
Roland McGratha4d48532005-06-08 20:45:28 +00001312static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001313syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001314{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001315#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001316 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001317
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001318 if (entering(tcp)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001319 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001320 if (
1321 scno == SYS_fork
1322#ifdef SYS_vfork
1323 || scno == SYS_vfork
1324#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001325#ifdef SYS_fork1
1326 || scno == SYS_fork1
1327#endif /* SYS_fork1 */
1328#ifdef SYS_forkall
1329 || scno == SYS_forkall
1330#endif /* SYS_forkall */
1331#ifdef SYS_rfork1
1332 || scno == SYS_rfork1
1333#endif /* SYS_fork1 */
1334#ifdef SYS_rforkall
1335 || scno == SYS_rforkall
1336#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001337 ) {
1338 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001339 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001340 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001341 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001342 }
1343 else {
1344 fprintf(stderr, "syscall: missing entry\n");
1345 tcp->flags |= TCB_INSYSCALL;
1346 }
1347 }
1348 }
1349 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001350 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001351 fprintf(stderr, "syscall: missing exit\n");
1352 tcp->flags &= ~TCB_INSYSCALL;
1353 }
1354 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001355#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001356
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357#ifdef SUNOS4
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001358 if (entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359 if (scno == 0) {
1360 fprintf(stderr, "syscall: missing entry\n");
1361 tcp->flags |= TCB_INSYSCALL;
1362 }
1363 }
1364 else {
1365 if (scno != 0) {
1366 if (debug) {
1367 /*
1368 * This happens when a signal handler
1369 * for a signal which interrupted a
1370 * a system call makes another system call.
1371 */
1372 fprintf(stderr, "syscall: missing exit\n");
1373 }
1374 tcp->flags &= ~TCB_INSYSCALL;
1375 }
1376 }
1377#endif /* SUNOS4 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001378
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001379#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001380 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001381#if defined (I386)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001382 /* With PTRACE_O_TRACEEXEC, post-execve SIGTRAP is disabled.
1383 * Every extra ptrace call is expensive, so check EAX
1384 * on syscall entry only if PTRACE_O_TRACEEXEC is not enabled:
1385 */
1386 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
1387 if (upeek(tcp, 4*EAX, &eax) < 0)
1388 return -1;
1389 if (eax != -ENOSYS) {
1390 if (debug)
1391 fprintf(stderr, "not a syscall entry (eax = %ld)\n", eax);
1392 return 0;
1393 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001394 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001395#elif defined (X86_64)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001396 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
1397 if (upeek(tcp, 8*RAX, &rax) < 0)
1398 return -1;
1399 if (current_personality == 1)
1400 rax = (long int)(int)rax; /* sign extend from 32 bits */
1401 if (rax != -ENOSYS && entering(tcp)) {
1402 if (debug)
1403 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1404 return 0;
1405 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001406 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001407#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001408 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001409 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001410 if (syscall_mode != -ENOSYS)
1411 syscall_mode = tcp->scno;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001412 if (gpr2 != syscall_mode && entering(tcp)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001413 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001414 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001415 return 0;
1416 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001417 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1418 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1419 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1420 /*
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001421 * Return from execve.
Roland McGrath96dc5142003-01-20 10:23:04 +00001422 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1423 * flag set for the post-execve SIGTRAP to see and reset.
1424 */
1425 gpr2 = 0;
1426 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001427#elif defined (POWERPC)
1428# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001429 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001430 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001431 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001432 return -1;
1433 if (flags & SO_MASK)
1434 result = -result;
1435#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001436 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001437 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001438 if (d0 != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001439 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001440 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001441 return 0;
1442 }
1443#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001444 /*
1445 * Nothing required
1446 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001447#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001448 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001449 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001450#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001451 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001452 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001453#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001454 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001455 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001456 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001457 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001458 if (ia32 && r8 != -ENOSYS && entering(tcp)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001459 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001460 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001461 return 0;
1462 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001463#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001464 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001465 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001466 if (r10 != -ENOSYS && entering(tcp)) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001467 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001468 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001469 return 0;
1470 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001471#elif defined(MICROBLAZE)
1472 if (upeek(tcp, 3 * 4, &r3) < 0)
1473 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001474 if (r3 != -ENOSYS && entering(tcp)) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001475 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001476 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001477 return 0;
1478 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001479#endif
1480#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001481 return 1;
1482}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483
Roland McGrathc1e45922008-05-27 23:18:29 +00001484#ifdef LINUX
1485/*
1486 * Check the syscall return value register value for whether it is
1487 * a negated errno code indicating an error, or a success return value.
1488 */
1489static inline int
1490is_negated_errno(unsigned long int val)
1491{
1492 unsigned long int max = -(long int) nerrnos;
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001493# if SUPPORTED_PERSONALITIES > 1
Roland McGrathc1e45922008-05-27 23:18:29 +00001494 if (personality_wordsize[current_personality] < sizeof(val)) {
1495 val = (unsigned int) val;
1496 max = (unsigned int) max;
1497 }
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001498# endif
Roland McGrathc1e45922008-05-27 23:18:29 +00001499 return val > max;
1500}
1501#endif
1502
Roland McGratha4d48532005-06-08 20:45:28 +00001503static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001504get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001505{
1506 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001508 int check_errno = 1;
1509 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1510 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1511 check_errno = 0;
1512 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001513# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001514 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001515 tcp->u_rval = -1;
1516 u_error = -gpr2;
1517 }
1518 else {
1519 tcp->u_rval = gpr2;
1520 u_error = 0;
1521 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001522# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001523 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001524 tcp->u_rval = -1;
1525 u_error = -eax;
1526 }
1527 else {
1528 tcp->u_rval = eax;
1529 u_error = 0;
1530 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001531# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001532 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001533 tcp->u_rval = -1;
1534 u_error = -rax;
1535 }
1536 else {
1537 tcp->u_rval = rax;
1538 u_error = 0;
1539 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001540# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001541 if (ia32) {
1542 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001543
Roland McGrathc1e45922008-05-27 23:18:29 +00001544 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001545 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001546 tcp->u_rval = -1;
1547 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001548 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001549 else {
1550 tcp->u_rval = err;
1551 u_error = 0;
1552 }
1553 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001554 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001555 tcp->u_rval = -1;
1556 u_error = r8;
1557 } else {
1558 tcp->u_rval = r8;
1559 u_error = 0;
1560 }
1561 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001562# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001563 if (check_errno && a3) {
1564 tcp->u_rval = -1;
1565 u_error = r2;
1566 } else {
1567 tcp->u_rval = r2;
1568 u_error = 0;
1569 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001570# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001571 if (check_errno && is_negated_errno(result)) {
1572 tcp->u_rval = -1;
1573 u_error = -result;
1574 }
1575 else {
1576 tcp->u_rval = result;
1577 u_error = 0;
1578 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001579# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001580 if (check_errno && is_negated_errno(d0)) {
1581 tcp->u_rval = -1;
1582 u_error = -d0;
1583 }
1584 else {
1585 tcp->u_rval = d0;
1586 u_error = 0;
1587 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001588# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001589 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1590 tcp->u_rval = -1;
1591 u_error = -regs.ARM_r0;
1592 }
1593 else {
1594 tcp->u_rval = regs.ARM_r0;
1595 u_error = 0;
1596 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001597# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001598 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1599 tcp->u_rval = -1;
1600 u_error = -regs.r12;
1601 }
1602 else {
1603 tcp->u_rval = regs.r12;
1604 u_error = 0;
1605 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001606# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001607 if (check_errno && is_negated_errno(r0)) {
1608 tcp->u_rval = -1;
1609 u_error = -r0;
1610 } else {
1611 tcp->u_rval = r0;
1612 u_error = 0;
1613 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001614# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001615 if (check_errno && a3) {
1616 tcp->u_rval = -1;
1617 u_error = r0;
1618 }
1619 else {
1620 tcp->u_rval = r0;
1621 u_error = 0;
1622 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001623# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001624 if (check_errno && regs.psr & PSR_C) {
1625 tcp->u_rval = -1;
1626 u_error = regs.u_regs[U_REG_O0];
1627 }
1628 else {
1629 tcp->u_rval = regs.u_regs[U_REG_O0];
1630 u_error = 0;
1631 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001632# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001633 if (check_errno && regs.tstate & 0x1100000000UL) {
1634 tcp->u_rval = -1;
1635 u_error = regs.u_regs[U_REG_O0];
1636 }
1637 else {
1638 tcp->u_rval = regs.u_regs[U_REG_O0];
1639 u_error = 0;
1640 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001641# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001642 if (check_errno && is_negated_errno(r28)) {
1643 tcp->u_rval = -1;
1644 u_error = -r28;
1645 }
1646 else {
1647 tcp->u_rval = r28;
1648 u_error = 0;
1649 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001650# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001651 /* interpret R0 as return value or error number */
1652 if (check_errno && is_negated_errno(r0)) {
1653 tcp->u_rval = -1;
1654 u_error = -r0;
1655 }
1656 else {
1657 tcp->u_rval = r0;
1658 u_error = 0;
1659 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001660# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001661 /* interpret result as return value or error number */
1662 if (check_errno && is_negated_errno(r9)) {
1663 tcp->u_rval = -1;
1664 u_error = -r9;
1665 }
1666 else {
1667 tcp->u_rval = r9;
1668 u_error = 0;
1669 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001670# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001671 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1672 tcp->u_rval = -1;
1673 u_error = -r10;
1674 }
1675 else {
1676 tcp->u_rval = r10;
1677 u_error = 0;
1678 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001679# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001680 long rval;
1681 /* interpret result as return value or error number */
1682 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1683 return -1;
1684 if (check_errno && rval < 0 && rval > -nerrnos) {
1685 tcp->u_rval = -1;
1686 u_error = -rval;
1687 }
1688 else {
1689 tcp->u_rval = rval;
1690 u_error = 0;
1691 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001692# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001693 /* interpret result as return value or error number */
1694 if (check_errno && is_negated_errno(r3)) {
1695 tcp->u_rval = -1;
1696 u_error = -r3;
1697 }
1698 else {
1699 tcp->u_rval = r3;
1700 u_error = 0;
1701 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001702# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001703#endif /* LINUX */
1704#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001705 /* get error code from user struct */
1706 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1707 return -1;
1708 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001710 /* get system call return value */
1711 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1712 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001713#endif /* SUNOS4 */
1714#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001715# ifdef SPARC
1716 /* Judicious guessing goes a long way. */
1717 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1718 tcp->u_rval = -1;
1719 u_error = tcp->status.pr_reg[R_O0];
1720 }
1721 else {
1722 tcp->u_rval = tcp->status.pr_reg[R_O0];
1723 u_error = 0;
1724 }
1725# endif /* SPARC */
1726# ifdef I386
1727 /* Wanna know how to kill an hour single-stepping? */
1728 if (tcp->status.PR_REG[EFL] & 0x1) {
1729 tcp->u_rval = -1;
1730 u_error = tcp->status.PR_REG[EAX];
1731 }
1732 else {
1733 tcp->u_rval = tcp->status.PR_REG[EAX];
1734# ifdef HAVE_LONG_LONG
1735 tcp->u_lrval =
1736 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1737 tcp->status.PR_REG[EAX];
1738# endif
1739 u_error = 0;
1740 }
1741# endif /* I386 */
1742# ifdef X86_64
1743 /* Wanna know how to kill an hour single-stepping? */
1744 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1745 tcp->u_rval = -1;
1746 u_error = tcp->status.PR_REG[RAX];
1747 }
1748 else {
1749 tcp->u_rval = tcp->status.PR_REG[RAX];
1750 u_error = 0;
1751 }
1752# endif /* X86_64 */
1753# ifdef MIPS
1754 if (tcp->status.pr_reg[CTX_A3]) {
1755 tcp->u_rval = -1;
1756 u_error = tcp->status.pr_reg[CTX_V0];
1757 }
1758 else {
1759 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1760 u_error = 0;
1761 }
1762# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001764#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001765 if (regs.r_eflags & PSL_C) {
1766 tcp->u_rval = -1;
1767 u_error = regs.r_eax;
1768 } else {
1769 tcp->u_rval = regs.r_eax;
1770 tcp->u_lrval =
1771 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1772 u_error = 0;
1773 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001774#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001775 tcp->u_error = u_error;
1776 return 1;
1777}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001778
Roland McGrathb69f81b2002-12-21 23:25:18 +00001779int
Denys Vlasenko12014262011-05-30 14:00:14 +02001780force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001781{
1782#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001783# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001784 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001785 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1786 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001787# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001788 eax = error ? -error : rval;
1789 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1790 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001791# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001792 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001793 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001794 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001795# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001796 if (ia32) {
1797 r8 = error ? -error : rval;
1798 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1799 return -1;
1800 }
1801 else {
1802 if (error) {
1803 r8 = error;
1804 r10 = -1;
1805 }
1806 else {
1807 r8 = rval;
1808 r10 = 0;
1809 }
1810 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1811 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1812 return -1;
1813 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001814# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001815 r0 = error ? -error : rval;
1816 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1817 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001818# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001819 if (error) {
1820 r2 = error;
1821 a3 = -1;
1822 }
1823 else {
1824 r2 = rval;
1825 a3 = 0;
1826 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001827 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001828 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1829 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001830 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001831# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001832 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001833 return -1;
1834 if (error) {
1835 flags |= SO_MASK;
1836 result = error;
1837 }
1838 else {
1839 flags &= ~SO_MASK;
1840 result = rval;
1841 }
Roland McGratheb285352003-01-14 09:59:00 +00001842 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1843 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001844 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001845# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001846 d0 = error ? -error : rval;
1847 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1848 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001849# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001850 regs.ARM_r0 = error ? -error : rval;
1851 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001852 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001853# elif defined(AVR32)
1854 regs.r12 = error ? -error : rval;
1855 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1856 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001857# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001858 if (error) {
1859 a3 = -1;
1860 r0 = error;
1861 }
1862 else {
1863 a3 = 0;
1864 r0 = rval;
1865 }
1866 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1867 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1868 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001869# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001870 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1871 return -1;
1872 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001873 regs.psr |= PSR_C;
1874 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001875 }
1876 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001877 regs.psr &= ~PSR_C;
1878 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001879 }
1880 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1881 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001882# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001883 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1884 return -1;
1885 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001886 regs.tstate |= 0x1100000000UL;
1887 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001888 }
1889 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001890 regs.tstate &= ~0x1100000000UL;
1891 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001892 }
1893 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1894 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001895# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001896 r28 = error ? -error : rval;
1897 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1898 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001899# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001900 r0 = error ? -error : rval;
1901 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1902 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001903# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001904 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001905 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1906 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001907# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001908#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001909
Roland McGrathb69f81b2002-12-21 23:25:18 +00001910#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001911 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1912 error << 24) < 0 ||
1913 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001914 return -1;
1915#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001916
Roland McGrathb69f81b2002-12-21 23:25:18 +00001917#ifdef SVR4
1918 /* XXX no clue */
1919 return -1;
1920#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001921
Roland McGrathb69f81b2002-12-21 23:25:18 +00001922#ifdef FREEBSD
1923 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001924 perror("pread");
1925 return -1;
1926 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001927 if (error) {
1928 regs.r_eflags |= PSL_C;
1929 regs.r_eax = error;
1930 }
1931 else {
1932 regs.r_eflags &= ~PSL_C;
1933 regs.r_eax = rval;
1934 }
1935 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001936 perror("pwrite");
1937 return -1;
1938 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001939#endif /* FREEBSD */
1940
1941 /* All branches reach here on success (only). */
1942 tcp->u_error = error;
1943 tcp->u_rval = rval;
1944 return 0;
1945}
1946
Roland McGratha4d48532005-06-08 20:45:28 +00001947static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001948syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001949{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001950#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001951 int i, nargs;
1952
Denys Vlasenkoafc64032011-08-23 13:29:01 +02001953 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001954 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001955 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001956 nargs = tcp->u_nargs = MAX_ARGS;
1957
1958# if defined(S390) || defined(S390X)
1959 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001960 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1961 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001962# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001963 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001964 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1965 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001966# elif defined(IA64)
1967 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001968 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001969 long rbs_end;
1970 /* be backwards compatible with kernel < 2.4.4... */
1971# ifndef PT_RBS_END
1972# define PT_RBS_END PT_AR_BSP
1973# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001974
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001975 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1976 return -1;
1977 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001978 return -1;
1979
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001980 sof = (cfm >> 0) & 0x7f;
1981 sol = (cfm >> 7) & 0x7f;
1982 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1983
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001984 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001985 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1986 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1987 return -1;
1988 }
1989 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001990 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1991 PT_R9 /* ECX = out1 */,
1992 PT_R10 /* EDX = out2 */,
1993 PT_R14 /* ESI = out3 */,
1994 PT_R15 /* EDI = out4 */,
1995 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001996
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001997 for (i = 0; i < nargs; ++i) {
1998 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1999 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002000 /* truncate away IVE sign-extension */
2001 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002002 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002003 }
2004# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2005 /* N32 and N64 both use up to six registers. */
2006 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002007
2008 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2009 return -1;
2010
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002011 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002012 tcp->u_arg[i] = regs[REG_A0 + i];
2013# if defined(LINUX_MIPSN32)
2014 tcp->ext_arg[i] = regs[REG_A0 + i];
2015# endif
2016 }
2017# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002018 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002019 long sp;
2020
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002021 if (upeek(tcp, REG_SP, &sp) < 0)
2022 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002023 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002024 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2025 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002026 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002027 (char *)(tcp->u_arg + 4));
2028 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002029 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002030 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002031 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002032 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002033# elif defined(POWERPC)
2034# ifndef PT_ORIG_R3
2035# define PT_ORIG_R3 34
2036# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002037 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002038 if (upeek(tcp, (i==0) ?
2039 (sizeof(unsigned long) * PT_ORIG_R3) :
2040 ((i+PT_R3) * sizeof(unsigned long)),
2041 &tcp->u_arg[i]) < 0)
2042 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002043 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002044# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002045 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002046 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2047# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002048 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002049 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2050 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002051# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002052 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002053 tcp->u_arg[i] = regs.uregs[i];
2054# elif defined(AVR32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002055 static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
2056 &regs.r11,
2057 &regs.r10,
2058 &regs.r9,
2059 &regs.r5,
2060 &regs.r3 };
2061 for (i = 0; i < nargs; ++i)
2062 tcp->u_arg[i] = *argregp[i];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002063# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002064 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 +02002065
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002066 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002067 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2068 return -1;
2069# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002070 static const int syscall_regs[MAX_ARGS] = {
2071 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
2072 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002073 };
2074
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002075 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002076 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002077 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002078# elif defined(SH64)
2079 int i;
2080 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002081 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002082
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002083 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002084 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2085 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002086# elif defined(X86_64)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002087 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2088 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2089 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002090 };
2091
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002092 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002093 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002094 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002095# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002096 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002097 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2098 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002099# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002100 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002101 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002102 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002103 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002104
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002105 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002106 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2107 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002108# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002109 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002110 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2111 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002112# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002113 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002114 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2115 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002116# else /* Other architecture (like i386) (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00002117 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002118 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2119 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002120# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002121#endif /* LINUX */
2122#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002123 int i, nargs;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002124 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002125 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002126 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02002127 nargs = tcp->u_nargs = MAX_ARGS;
2128 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002129 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002130
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002131 if (upeek(tcp, uoff(u_arg[0]) +
2132 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2133 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002134 }
2135#endif /* SUNOS4 */
2136#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002137# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138 /*
2139 * SGI is broken: even though it has pr_sysarg, it doesn't
2140 * set them on system call entry. Get a clue.
2141 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002142 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002143 tcp->u_nargs = sysent[tcp->scno].nargs;
2144 else
2145 tcp->u_nargs = tcp->status.pr_nsysarg;
2146 if (tcp->u_nargs > 4) {
2147 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002148 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002149 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002150 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002151 }
2152 else {
2153 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002154 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002155 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002156# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002157 /*
2158 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2159 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002160 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
John Hughes25299712001-03-06 10:10:06 +00002161 tcp->u_nargs = sysent[tcp->scno].nargs;
2162 else
2163 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2164 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002165 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2166# elif defined(HAVE_PR_SYSCALL)
2167 int i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002168 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002169 tcp->u_nargs = sysent[tcp->scno].nargs;
2170 else
2171 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002172 for (i = 0; i < tcp->u_nargs; i++)
2173 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2174# elif defined(I386)
Denys Vlasenkoafc64032011-08-23 13:29:01 +02002175 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002176 tcp->u_nargs = sysent[tcp->scno].nargs;
2177 else
2178 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002179 if (tcp->u_nargs > 0)
2180 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002181 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2182# else
John Hughes25299712001-03-06 10:10:06 +00002183 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002184# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002185#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002186#ifdef FREEBSD
2187 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2188 sysent[tcp->scno].nargs > tcp->status.val)
2189 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002190 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002191 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002192 if (tcp->u_nargs < 0)
2193 tcp->u_nargs = 0;
2194 if (tcp->u_nargs > MAX_ARGS)
2195 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002196 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002197 case SYS___syscall:
2198 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2199 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002200 break;
2201 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002202 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2203 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002204 break;
2205 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002206 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2207 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002208 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002209 }
2210#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002211 return 1;
2212}
2213
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002214static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002215trace_syscall_entering(struct tcb *tcp)
2216{
2217 int res, scno_good;
2218
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02002219#if defined TCB_WAITEXECVE
2220 if (tcp->flags & TCB_WAITEXECVE) {
2221 /* This is the post-execve SIGTRAP. */
2222 tcp->flags &= ~TCB_WAITEXECVE;
2223 return 0;
2224 }
2225#endif
2226
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02002227 scno_good = res = get_scno_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002228 if (res == 0)
2229 return res;
2230 if (res == 1)
2231 res = syscall_fixup(tcp);
2232 if (res == 0)
2233 return res;
2234 if (res == 1)
2235 res = syscall_enter(tcp);
2236 if (res == 0)
2237 return res;
2238
2239 if (res != 1) {
2240 printleader(tcp);
2241 tcp->flags &= ~TCB_REPRINT;
2242 tcp_last = tcp;
2243 if (scno_good != 1)
2244 tprintf("????" /* anti-trigraph gap */ "(");
2245 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2246 tprintf("syscall_%lu(", tcp->scno);
2247 else
2248 tprintf("%s(", sysent[tcp->scno].sys_name);
2249 /*
2250 * " <unavailable>" will be added later by the code which
2251 * detects ptrace errors.
2252 */
2253 goto ret;
2254 }
2255
2256 switch (known_scno(tcp)) {
2257#ifdef SYS_socket_subcall
2258 case SYS_socketcall:
2259 decode_subcall(tcp, SYS_socket_subcall,
2260 SYS_socket_nsubcalls, deref_style);
2261 break;
2262#endif
2263#ifdef SYS_ipc_subcall
2264 case SYS_ipc:
2265 decode_subcall(tcp, SYS_ipc_subcall,
2266 SYS_ipc_nsubcalls, shift_style);
2267 break;
2268#endif
2269#ifdef SVR4
2270#ifdef SYS_pgrpsys_subcall
2271 case SYS_pgrpsys:
2272 decode_subcall(tcp, SYS_pgrpsys_subcall,
2273 SYS_pgrpsys_nsubcalls, shift_style);
2274 break;
2275#endif /* SYS_pgrpsys_subcall */
2276#ifdef SYS_sigcall_subcall
2277 case SYS_sigcall:
2278 decode_subcall(tcp, SYS_sigcall_subcall,
2279 SYS_sigcall_nsubcalls, mask_style);
2280 break;
2281#endif /* SYS_sigcall_subcall */
2282 case SYS_msgsys:
2283 decode_subcall(tcp, SYS_msgsys_subcall,
2284 SYS_msgsys_nsubcalls, shift_style);
2285 break;
2286 case SYS_shmsys:
2287 decode_subcall(tcp, SYS_shmsys_subcall,
2288 SYS_shmsys_nsubcalls, shift_style);
2289 break;
2290 case SYS_semsys:
2291 decode_subcall(tcp, SYS_semsys_subcall,
2292 SYS_semsys_nsubcalls, shift_style);
2293 break;
2294 case SYS_sysfs:
2295 decode_subcall(tcp, SYS_sysfs_subcall,
2296 SYS_sysfs_nsubcalls, shift_style);
2297 break;
2298 case SYS_spcall:
2299 decode_subcall(tcp, SYS_spcall_subcall,
2300 SYS_spcall_nsubcalls, shift_style);
2301 break;
2302#ifdef SYS_context_subcall
2303 case SYS_context:
2304 decode_subcall(tcp, SYS_context_subcall,
2305 SYS_context_nsubcalls, shift_style);
2306 break;
2307#endif /* SYS_context_subcall */
2308#ifdef SYS_door_subcall
2309 case SYS_door:
2310 decode_subcall(tcp, SYS_door_subcall,
2311 SYS_door_nsubcalls, door_style);
2312 break;
2313#endif /* SYS_door_subcall */
2314#ifdef SYS_kaio_subcall
2315 case SYS_kaio:
2316 decode_subcall(tcp, SYS_kaio_subcall,
2317 SYS_kaio_nsubcalls, shift_style);
2318 break;
2319#endif
2320#endif /* SVR4 */
2321#ifdef FREEBSD
2322 case SYS_msgsys:
2323 case SYS_shmsys:
2324 case SYS_semsys:
2325 decode_subcall(tcp, 0, 0, table_style);
2326 break;
2327#endif
2328#ifdef SUNOS4
2329 case SYS_semsys:
2330 decode_subcall(tcp, SYS_semsys_subcall,
2331 SYS_semsys_nsubcalls, shift_style);
2332 break;
2333 case SYS_msgsys:
2334 decode_subcall(tcp, SYS_msgsys_subcall,
2335 SYS_msgsys_nsubcalls, shift_style);
2336 break;
2337 case SYS_shmsys:
2338 decode_subcall(tcp, SYS_shmsys_subcall,
2339 SYS_shmsys_nsubcalls, shift_style);
2340 break;
2341#endif
2342 }
2343
2344 internal_syscall(tcp);
2345
2346 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2347 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2348 (tracing_paths && !pathtrace_match(tcp))) {
2349 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
2350 return 0;
2351 }
2352
2353 tcp->flags &= ~TCB_FILTERED;
2354
2355 if (cflag == CFLAG_ONLY_STATS) {
2356 res = 0;
2357 goto ret;
2358 }
2359
2360 printleader(tcp);
2361 tcp->flags &= ~TCB_REPRINT;
2362 tcp_last = tcp;
2363 if (tcp->scno >= nsyscalls || tcp->scno < 0)
2364 tprintf("syscall_%lu(", tcp->scno);
2365 else
2366 tprintf("%s(", sysent[tcp->scno].sys_name);
2367 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2368 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2369 sysent[tcp->scno].sys_func != sys_exit))
2370 res = printargs(tcp);
2371 else
2372 res = (*sysent[tcp->scno].sys_func)(tcp);
2373
2374 if (fflush(tcp->outf) == EOF)
2375 return -1;
2376 ret:
2377 tcp->flags |= TCB_INSYSCALL;
2378 /* Measure the entrance time as late as possible to avoid errors. */
2379 if (dtime || cflag)
2380 gettimeofday(&tcp->etime, NULL);
2381 return res;
2382}
2383
2384static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002385trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002386{
2387 int sys_res;
2388 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002389 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002390 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002391
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002392 /* Measure the exit time as early as possible to avoid errors. */
2393 if (dtime || cflag)
2394 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002395
Denys Vlasenko9a36ae52011-08-24 16:47:32 +02002396 scno_good = res = get_scno_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002397 if (res == 0)
2398 return res;
2399 if (res == 1)
2400 res = syscall_fixup(tcp);
2401 if (res == 0)
2402 return res;
2403 if (res == 1)
2404 res = get_error(tcp);
2405 if (res == 0)
2406 return res;
2407 if (res == 1)
2408 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002409
Grant Edwards8a082772011-04-07 20:25:40 +00002410 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002411 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002412 }
2413
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002414 if (tcp->flags & TCB_REPRINT) {
2415 printleader(tcp);
2416 tprintf("<... ");
2417 if (scno_good != 1)
2418 tprintf("????");
2419 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2420 tprintf("syscall_%lu", tcp->scno);
2421 else
2422 tprintf("%s", sysent[tcp->scno].sys_name);
2423 tprintf(" resumed> ");
2424 }
2425
2426 if (cflag) {
2427 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002428 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002429 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002430 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002431 }
2432 }
2433
2434 if (res != 1) {
2435 tprintf(") ");
2436 tabto(acolumn);
2437 tprintf("= ? <unavailable>");
2438 printtrailer();
2439 tcp->flags &= ~TCB_INSYSCALL;
2440 return res;
2441 }
2442
2443 if (tcp->scno >= nsyscalls || tcp->scno < 0
2444 || (qual_flags[tcp->scno] & QUAL_RAW))
2445 sys_res = printargs(tcp);
2446 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002447 /* FIXME: not_failing_only (IOW, option -z) is broken:
2448 * failure of syscall is known only after syscall return.
2449 * Thus we end up with something like this on, say, ENOENT:
2450 * open("doesnt_exist", O_RDONLY <unfinished ...>
2451 * {next syscall decode}
2452 * whereas the intended result is that open(...) line
2453 * is not shown at all.
2454 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002455 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002456 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002457 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2458 }
2459
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002460 tprintf(") ");
2461 tabto(acolumn);
Denys Vlasenko3b738812011-08-22 02:06:35 +02002462 u_error = tcp->u_error;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002463 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2464 qual_flags[tcp->scno] & QUAL_RAW) {
2465 if (u_error)
2466 tprintf("= -1 (errno %ld)", u_error);
2467 else
2468 tprintf("= %#lx", tcp->u_rval);
2469 }
2470 else if (!(sys_res & RVAL_NONE) && u_error) {
2471 switch (u_error) {
2472#ifdef LINUX
2473 case ERESTARTSYS:
2474 tprintf("= ? ERESTARTSYS (To be restarted)");
2475 break;
2476 case ERESTARTNOINTR:
2477 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2478 break;
2479 case ERESTARTNOHAND:
2480 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2481 break;
2482 case ERESTART_RESTARTBLOCK:
2483 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2484 break;
2485#endif /* LINUX */
2486 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002487 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002488 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002489 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002490 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002491 strerror(u_error));
2492 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002493 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002494 strerror(u_error));
2495 break;
2496 }
2497 if ((sys_res & RVAL_STR) && tcp->auxstr)
2498 tprintf(" (%s)", tcp->auxstr);
2499 }
2500 else {
2501 if (sys_res & RVAL_NONE)
2502 tprintf("= ?");
2503 else {
2504 switch (sys_res & RVAL_MASK) {
2505 case RVAL_HEX:
2506 tprintf("= %#lx", tcp->u_rval);
2507 break;
2508 case RVAL_OCTAL:
2509 tprintf("= %#lo", tcp->u_rval);
2510 break;
2511 case RVAL_UDECIMAL:
2512 tprintf("= %lu", tcp->u_rval);
2513 break;
2514 case RVAL_DECIMAL:
2515 tprintf("= %ld", tcp->u_rval);
2516 break;
2517#ifdef HAVE_LONG_LONG
2518 case RVAL_LHEX:
2519 tprintf("= %#llx", tcp->u_lrval);
2520 break;
2521 case RVAL_LOCTAL:
2522 tprintf("= %#llo", tcp->u_lrval);
2523 break;
2524 case RVAL_LUDECIMAL:
2525 tprintf("= %llu", tcp->u_lrval);
2526 break;
2527 case RVAL_LDECIMAL:
2528 tprintf("= %lld", tcp->u_lrval);
2529 break;
2530#endif
2531 default:
2532 fprintf(stderr,
2533 "invalid rval format\n");
2534 break;
2535 }
2536 }
2537 if ((sys_res & RVAL_STR) && tcp->auxstr)
2538 tprintf(" (%s)", tcp->auxstr);
2539 }
2540 if (dtime) {
2541 tv_sub(&tv, &tv, &tcp->etime);
2542 tprintf(" <%ld.%06ld>",
2543 (long) tv.tv_sec, (long) tv.tv_usec);
2544 }
2545 printtrailer();
2546
2547 dumpio(tcp);
2548 if (fflush(tcp->outf) == EOF)
2549 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002550 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002551 tcp->flags &= ~TCB_INSYSCALL;
2552 return 0;
2553}
2554
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002555int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002556trace_syscall(struct tcb *tcp)
2557{
2558 return exiting(tcp) ?
2559 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2560}
2561
2562int
Denys Vlasenko12014262011-05-30 14:00:14 +02002563printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002564{
2565 if (entering(tcp)) {
2566 int i;
2567
2568 for (i = 0; i < tcp->u_nargs; i++)
2569 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2570 }
2571 return 0;
2572}
2573
2574long
Denys Vlasenko12014262011-05-30 14:00:14 +02002575getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002576{
2577 long val = -1;
2578
2579#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002580#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002581 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002582 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002583 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002584 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002585#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002586 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002587 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002588#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002589 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002590 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002591#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002592#endif /* LINUX */
2593
2594#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002595 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002596 return -1;
2597#endif /* SUNOS4 */
2598
2599#ifdef SVR4
2600#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002601 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002602#endif /* SPARC */
2603#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002604 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002605#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002606#ifdef X86_64
2607 val = tcp->status.PR_REG[RDX];
2608#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002609#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002610 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002611#endif /* MIPS */
2612#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002613
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002614#ifdef FREEBSD
2615 struct reg regs;
2616 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2617 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002618#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002619 return val;
2620}
2621
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002622#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002623/*
2624 * Apparently, indirect system calls have already be converted by ptrace(2),
2625 * so if you see "indir" this program has gone astray.
2626 */
2627int
Denys Vlasenko12014262011-05-30 14:00:14 +02002628sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002629{
2630 int i, scno, nargs;
2631
2632 if (entering(tcp)) {
Denys Vlasenko5d645812011-08-20 12:48:18 +02002633 scno = tcp->u_arg[0];
2634 if (scno > nsyscalls) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002635 fprintf(stderr, "Bogus syscall: %u\n", scno);
2636 return 0;
2637 }
2638 nargs = sysent[scno].nargs;
2639 tprintf("%s", sysent[scno].sys_name);
2640 for (i = 0; i < nargs; i++)
2641 tprintf(", %#lx", tcp->u_arg[i+1]);
2642 }
2643 return 0;
2644}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002645#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002646
2647int
2648is_restart_error(struct tcb *tcp)
2649{
2650#ifdef LINUX
2651 if (!syserror(tcp))
2652 return 0;
2653 switch (tcp->u_error) {
2654 case ERESTARTSYS:
2655 case ERESTARTNOINTR:
2656 case ERESTARTNOHAND:
2657 case ERESTART_RESTARTBLOCK:
2658 return 1;
2659 default:
2660 break;
2661 }
2662#endif /* LINUX */
2663 return 0;
2664}