blob: b9b5d4aaab93af0da779047611dbe73a715ed0a2 [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
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000510#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000511enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000512#else /* FREEBSD */
513enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
514
515struct subcall {
516 int call;
517 int nsubcalls;
518 int subcalls[5];
519};
520
Roland McGratha4d48532005-06-08 20:45:28 +0000521static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000522 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000523#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000524 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000525#else
526 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
527#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000528 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
529};
530#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000531
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000532#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000533
Roland McGratha4d48532005-06-08 20:45:28 +0000534static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200535decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000537 unsigned long addr, mask;
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200538 int i, n;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000539 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000540
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000541 switch (style) {
542 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000543 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
544 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000545 tcp->scno = subcall + tcp->u_arg[0];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200546 tcp->u_nargs = n = sysent[tcp->scno].nargs;
547 for (i = 0; i < n; i++)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000548 tcp->u_arg[i] = tcp->u_arg[i + 1];
549 break;
550 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000551 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
552 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000553 tcp->scno = subcall + tcp->u_arg[0];
554 addr = tcp->u_arg[1];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200555 tcp->u_nargs = n = sysent[tcp->scno].nargs;
556 for (i = 0; i < n; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000557 if (size == sizeof(int)) {
558 unsigned int arg;
559 if (umove(tcp, addr, &arg) < 0)
560 arg = 0;
561 tcp->u_arg[i] = arg;
562 }
563 else if (size == sizeof(long)) {
564 unsigned long arg;
565 if (umove(tcp, addr, &arg) < 0)
566 arg = 0;
567 tcp->u_arg[i] = arg;
568 }
569 else
570 abort();
571 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000573 break;
574 case mask_style:
575 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 for (i = 0; mask; i++)
577 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000578 if (i >= nsubcalls)
579 return;
580 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581 tcp->scno = subcall + i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200582 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000584 case door_style:
585 /*
586 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000587 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000588 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000589 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
590 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000591 tcp->scno = subcall + tcp->u_arg[5];
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200592 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000593 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000594#ifdef FREEBSD
595 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000596 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000597 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000598 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000599 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
600 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
601 for (i = 0; i < tcp->u_nargs; i++)
602 tcp->u_arg[i] = tcp->u_arg[i + 1];
603 }
604 break;
605#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000606 }
607}
608#endif
609
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200610int
611printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612{
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200613 if (entering(tcp)) {
614 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200616 for (i = 0; i < tcp->u_nargs; i++)
617 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
618 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000619 return 0;
620}
621
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200622long
623getrval2(struct tcb *tcp)
624{
625 long val = -1;
626
627#ifdef LINUX
628#if defined (SPARC) || defined (SPARC64)
629 struct pt_regs regs;
630 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
631 return -1;
632 val = regs.u_regs[U_REG_O1];
633#elif defined(SH)
634 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
635 return -1;
636#elif defined(IA64)
637 if (upeek(tcp, PT_R9, &val) < 0)
638 return -1;
639#endif
640#endif /* LINUX */
641
642#ifdef SUNOS4
643 if (upeek(tcp, uoff(u_rval2), &val) < 0)
644 return -1;
645#endif /* SUNOS4 */
646
647#ifdef SVR4
648#ifdef SPARC
649 val = tcp->status.PR_REG[R_O1];
650#endif /* SPARC */
651#ifdef I386
652 val = tcp->status.PR_REG[EDX];
653#endif /* I386 */
654#ifdef X86_64
655 val = tcp->status.PR_REG[RDX];
656#endif /* X86_64 */
657#ifdef MIPS
658 val = tcp->status.PR_REG[CTX_V1];
659#endif /* MIPS */
660#endif /* SVR4 */
661
662#ifdef FREEBSD
663 struct reg regs;
664 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
665 val = regs.r_edx;
666#endif
667 return val;
668}
669
670#ifdef SUNOS4
671/*
672 * Apparently, indirect system calls have already be converted by ptrace(2),
673 * so if you see "indir" this program has gone astray.
674 */
675int
676sys_indir(struct tcb *tcp)
677{
678 int i, scno, nargs;
679
680 if (entering(tcp)) {
681 scno = tcp->u_arg[0];
682 if (scno > nsyscalls) {
683 fprintf(stderr, "Bogus syscall: %u\n", scno);
684 return 0;
685 }
686 nargs = sysent[scno].nargs;
687 tprintf("%s", sysent[scno].sys_name);
688 for (i = 0; i < nargs; i++)
689 tprintf(", %#lx", tcp->u_arg[i+1]);
690 }
691 return 0;
692}
693#endif /* SUNOS4 */
694
695int
696is_restart_error(struct tcb *tcp)
697{
698#ifdef LINUX
699 if (!syserror(tcp))
700 return 0;
701 switch (tcp->u_error) {
702 case ERESTARTSYS:
703 case ERESTARTNOINTR:
704 case ERESTARTNOHAND:
705 case ERESTART_RESTARTBLOCK:
706 return 1;
707 default:
708 break;
709 }
710#endif /* LINUX */
711 return 0;
712}
713
714struct tcb *tcp_last = NULL;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000715
716#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200717# if defined (I386)
718static long eax;
719# elif defined (IA64)
720long r8, r10, psr; /* TODO: make static? */
721long ia32 = 0; /* not static */
722# elif defined (POWERPC)
723static long result, flags;
724# elif defined (M68K)
725static long d0;
726# elif defined(BFIN)
727static long r0;
728# elif defined (ARM)
729static struct pt_regs regs;
730# elif defined (ALPHA)
731static long r0;
732static long a3;
733# elif defined(AVR32)
734static struct pt_regs regs;
735# elif defined (SPARC) || defined (SPARC64)
736static struct pt_regs regs;
737static unsigned long trap;
738# elif defined(LINUX_MIPSN32)
739static long long a3;
740static long long r2;
741# elif defined(MIPS)
742static long a3;
743static long r2;
744# elif defined(S390) || defined(S390X)
745static long gpr2;
746static long pc;
747static long syscall_mode;
748# elif defined(HPPA)
749static long r28;
750# elif defined(SH)
751static long r0;
752# elif defined(SH64)
753static long r9;
754# elif defined(X86_64)
755static long rax;
756# elif defined(CRISV10) || defined(CRISV32)
757static long r10;
758# elif defined(MICROBLAZE)
759static long r3;
760# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000761#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000762#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200763struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000764#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000765
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200766/* Returns:
767 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
768 * 1: ok, continue in trace_syscall().
769 * other: error, trace_syscall() should print error indicator
770 * ("????" etc) and bail out.
771 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200772#ifndef USE_PROCFS
773static
774#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775int
Denys Vlasenko06602d92011-08-24 17:53:52 +0200776get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000777{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000781# if defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000782 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200783 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000784
785 if (syscall_mode != -ENOSYS) {
786 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000787 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000788 */
789 scno = syscall_mode;
790 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000791 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000792 * Old style of "passing" the scno via the SVC instruction.
793 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000794 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200795 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200796 static const int gpr_offset[16] = {
797 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
798 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
799 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
800 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
801 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000802
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000803 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000804 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000805 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000806 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000807 if (errno) {
808 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000809 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000810 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000811
812 /*
813 * We have to check if the SVC got executed directly or via an
814 * EXECUTE instruction. In case of EXECUTE it is necessary to do
815 * instruction decoding to derive the system call number.
816 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
817 * so that this doesn't work if a SVC opcode is part of an EXECUTE
818 * opcode. Since there is no way to find out the opcode size this
819 * is the best we can do...
820 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000821 if ((opcode & 0xff00) == 0x0a00) {
822 /* SVC opcode */
823 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000824 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000825 else {
826 /* SVC got executed by EXECUTE instruction */
827
828 /*
829 * Do instruction decoding of EXECUTE. If you really want to
830 * understand this, read the Principles of Operations.
831 */
832 svc_addr = (void *) (opcode & 0xfff);
833
834 tmp = 0;
835 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000836 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000837 return -1;
838 svc_addr += tmp;
839
840 tmp = 0;
841 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000842 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000843 return -1;
844 svc_addr += tmp;
845
Denys Vlasenkofb036672009-01-23 16:30:26 +0000846 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000847 if (errno)
848 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000849# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000850 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000851# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000852 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000853# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000854 tmp = 0;
855 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000856 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000857 return -1;
858
859 scno = (scno | tmp) & 0xff;
860 }
861 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000862# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000863 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000864 return -1;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200865# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200866 /* TODO: speed up strace by not doing this at every syscall.
867 * We only need to do it after execve.
868 */
869 int currpers;
870 long val;
871 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200872
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200873 /* Check for 64/32 bit mode. */
874 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
875 return -1;
876 /* SF is bit 0 of MSR */
877 if (val < 0)
878 currpers = 0;
879 else
880 currpers = 1;
881 if (currpers != current_personality) {
882 static const char *const names[] = {"64 bit", "32 bit"};
883 set_personality(currpers);
884 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
885 pid, names[current_personality]);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200886 }
887# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000888# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200889 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000890 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
891 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200892 scno = regs.r8;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000893# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000894 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000895 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000896# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000897 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000898 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000899# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000900 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000901 return -1;
902
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200903 /* TODO: speed up strace by not doing this at every syscall.
904 * We only need to do it after execve.
905 */
906 int currpers;
907 long val;
908 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000909
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200910 /* Check CS register value. On x86-64 linux it is:
911 * 0x33 for long mode (64 bit)
912 * 0x23 for compatibility mode (32 bit)
913 * It takes only one ptrace and thus doesn't need
914 * to be cached.
915 */
916 if (upeek(tcp, 8*CS, &val) < 0)
917 return -1;
918 switch (val) {
919 case 0x23: currpers = 1; break;
920 case 0x33: currpers = 0; break;
921 default:
922 fprintf(stderr, "Unknown value CS=0x%02X while "
923 "detecting personality of process "
924 "PID=%d\n", (int)val, pid);
925 currpers = current_personality;
926 break;
927 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000928# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200929 /* This version analyzes the opcode of a syscall instruction.
930 * (int 0x80 on i386 vs. syscall on x86-64)
931 * It works, but is too complicated.
932 */
933 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000934
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200935 if (upeek(tcp, 8*RIP, &rip) < 0)
936 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000937
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200938 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
939 rip -= 2;
940 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000941
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200942 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
943 if (errno)
944 fprintf(stderr, "ptrace_peektext failed: %s\n",
945 strerror(errno));
946 switch (call & 0xffff) {
947 /* x86-64: syscall = 0x0f 0x05 */
948 case 0x050f: currpers = 0; break;
949 /* i386: int 0x80 = 0xcd 0x80 */
950 case 0x80cd: currpers = 1; break;
951 default:
952 currpers = current_personality;
953 fprintf(stderr,
954 "Unknown syscall opcode (0x%04X) while "
955 "detecting personality of process "
956 "PID=%d\n", (int)call, pid);
957 break;
958 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000959# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200960 if (currpers != current_personality) {
961 static const char *const names[] = {"64 bit", "32 bit"};
962 set_personality(currpers);
963 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
964 pid, names[current_personality]);
Roland McGrath761b5d72002-12-15 23:58:31 +0000965 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000966# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000967# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200968 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000969 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200970 if (ia32) {
971 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
972 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000973 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200974 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000975 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200976 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000977# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200978 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000979 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000980 return -1;
981
982 /*
983 * We only need to grab the syscall number on syscall entry.
984 */
985 if (regs.ARM_ip == 0) {
986 /*
987 * Note: we only deal with only 32-bit CPUs here.
988 */
989 if (regs.ARM_cpsr & 0x20) {
990 /*
991 * Get the Thumb-mode system call number
992 */
993 scno = regs.ARM_r7;
994 } else {
995 /*
996 * Get the ARM-mode system call number
997 */
998 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000999 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001000 if (errno)
1001 return -1;
1002
Roland McGrathf691bd22006-04-25 07:34:41 +00001003 /* Handle the EABI syscall convention. We do not
1004 bother converting structures between the two
1005 ABIs, but basic functionality should work even
1006 if strace and the traced program have different
1007 ABIs. */
1008 if (scno == 0xef000000) {
1009 scno = regs.ARM_r7;
1010 } else {
1011 if ((scno & 0x0ff00000) != 0x0f900000) {
1012 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1013 scno);
1014 return -1;
1015 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001016
Roland McGrathf691bd22006-04-25 07:34:41 +00001017 /*
1018 * Fixup the syscall number
1019 */
1020 scno &= 0x000fffff;
1021 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001022 }
Roland McGrath56703312008-05-20 01:35:55 +00001023 if (scno & 0x0f0000) {
1024 /*
1025 * Handle ARM specific syscall
1026 */
1027 set_personality(1);
1028 scno &= 0x0000ffff;
1029 } else
1030 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001031
Roland McGrath0f87c492003-06-03 23:29:04 +00001032 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001033 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1034 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001035 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001036# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001037 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001039# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001040 unsigned long long regs[38];
1041
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001042 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001043 return -1;
1044 a3 = regs[REG_A3];
1045 r2 = regs[REG_V0];
1046
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001047 scno = r2;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001048 if (scno < 0 || scno > nsyscalls) {
1049 if (a3 == 0 || a3 == -1) {
1050 if (debug)
1051 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001052 return 0;
1053 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001054 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001055# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001056 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001057 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001058 if (upeek(tcp, REG_V0, &scno) < 0)
1059 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001060
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001061 if (scno < 0 || scno > nsyscalls) {
1062 if (a3 == 0 || a3 == -1) {
1063 if (debug)
1064 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001065 return 0;
1066 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001067 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001068# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001069 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001071 if (upeek(tcp, REG_R0, &scno) < 0)
1072 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001074 /*
1075 * Do some sanity checks to figure out if it's
1076 * really a syscall entry
1077 */
1078 if (scno < 0 || scno > nsyscalls) {
1079 if (a3 == 0 || a3 == -1) {
1080 if (debug)
1081 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 return 0;
1083 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001084 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001085# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001087 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001088 return -1;
1089
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001090 /* Disassemble the syscall trap. */
1091 /* Retrieve the syscall trap instruction. */
1092 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001093# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001094 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1095 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001096# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001097 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001098# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001099 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001100 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001101
1102 /* Disassemble the trap to see what personality to use. */
1103 switch (trap) {
1104 case 0x91d02010:
1105 /* Linux/SPARC syscall trap. */
1106 set_personality(0);
1107 break;
1108 case 0x91d0206d:
1109 /* Linux/SPARC64 syscall trap. */
1110 set_personality(2);
1111 break;
1112 case 0x91d02000:
1113 /* SunOS syscall trap. (pers 1) */
1114 fprintf(stderr, "syscall: SunOS no support\n");
1115 return -1;
1116 case 0x91d02008:
1117 /* Solaris 2.x syscall trap. (per 2) */
1118 set_personality(1);
1119 break;
1120 case 0x91d02009:
1121 /* NetBSD/FreeBSD syscall trap. */
1122 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1123 return -1;
1124 case 0x91d02027:
1125 /* Solaris 2.x gettimeofday */
1126 set_personality(1);
1127 break;
1128 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001129# if defined (SPARC64)
1130 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1131# else
1132 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1133# endif
1134 return -1;
1135 }
1136
1137 /* Extract the system call number from the registers. */
1138 if (trap == 0x91d02027)
1139 scno = 156;
1140 else
1141 scno = regs.u_regs[U_REG_G1];
1142 if (scno == 0) {
1143 scno = regs.u_regs[U_REG_O0];
1144 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1145 }
1146# elif defined(HPPA)
1147 if (upeek(tcp, PT_GR20, &scno) < 0)
1148 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001149# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001150 /*
1151 * In the new syscall ABI, the system call number is in R3.
1152 */
1153 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1154 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001155
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001156 if (scno < 0) {
1157 /* Odd as it may seem, a glibc bug has been known to cause
1158 glibc to issue bogus negative syscall numbers. So for
1159 our purposes, make strace print what it *should* have been */
1160 long correct_scno = (scno & 0xff);
1161 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001162 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001163 "Detected glibc bug: bogus system call"
1164 " number = %ld, correcting to %ld\n",
1165 scno,
1166 correct_scno);
1167 scno = correct_scno;
1168 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001169# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001170 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001171 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001172 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001173# elif defined(CRISV10) || defined(CRISV32)
1174 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1175 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001176# elif defined(TILE)
1177 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1178 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001179# elif defined(MICROBLAZE)
1180 if (upeek(tcp, 0, &scno) < 0)
1181 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001182# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001184
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001186 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001187 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001188#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001189 /* new syscall ABI returns result in R0 */
1190 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1191 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001192#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001193 /* ABI defines result returned in r9 */
1194 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1195 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001196#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001197
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001198#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001199# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001200 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001201# else
1202# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001203 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001204# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001205 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001206 perror("pread");
1207 return -1;
1208 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001209 switch (regs.r_eax) {
1210 case SYS_syscall:
1211 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001212 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1213 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001214 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001215 scno = regs.r_eax;
1216 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001217 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001218# endif /* FREEBSD */
1219# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001220#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001221
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001222 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001223 return 1;
1224}
1225
Roland McGrath17352792005-06-07 23:21:26 +00001226long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001227known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001228{
1229 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001230#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001231 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1232 scno = sysent[scno].native_scno;
1233 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001234#endif
Roland McGrath17352792005-06-07 23:21:26 +00001235 scno += NR_SYSCALL_BASE;
1236 return scno;
1237}
1238
Roland McGratheb9e2e82009-06-02 16:49:22 -07001239/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001240 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001241 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001242 * 1: ok, continue in trace_syscall().
1243 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001244 * ("????" etc) and bail out.
1245 */
Roland McGratha4d48532005-06-08 20:45:28 +00001246static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001247syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001248{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001249#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001250 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001251
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001252 if (entering(tcp)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001253 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001254 if (
1255 scno == SYS_fork
1256#ifdef SYS_vfork
1257 || scno == SYS_vfork
1258#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001259#ifdef SYS_fork1
1260 || scno == SYS_fork1
1261#endif /* SYS_fork1 */
1262#ifdef SYS_forkall
1263 || scno == SYS_forkall
1264#endif /* SYS_forkall */
1265#ifdef SYS_rfork1
1266 || scno == SYS_rfork1
1267#endif /* SYS_fork1 */
1268#ifdef SYS_rforkall
1269 || scno == SYS_rforkall
1270#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001271 ) {
1272 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001273 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001274 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001275 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001276 }
1277 else {
1278 fprintf(stderr, "syscall: missing entry\n");
1279 tcp->flags |= TCB_INSYSCALL;
1280 }
1281 }
1282 }
1283 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001284 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001285 fprintf(stderr, "syscall: missing exit\n");
1286 tcp->flags &= ~TCB_INSYSCALL;
1287 }
1288 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001289#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001290
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291#ifdef SUNOS4
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001292 if (entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293 if (scno == 0) {
1294 fprintf(stderr, "syscall: missing entry\n");
1295 tcp->flags |= TCB_INSYSCALL;
1296 }
1297 }
1298 else {
1299 if (scno != 0) {
1300 if (debug) {
1301 /*
1302 * This happens when a signal handler
1303 * for a signal which interrupted a
1304 * a system call makes another system call.
1305 */
1306 fprintf(stderr, "syscall: missing exit\n");
1307 }
1308 tcp->flags &= ~TCB_INSYSCALL;
1309 }
1310 }
1311#endif /* SUNOS4 */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001312
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001314 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001315#if defined (I386)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001316 /* With PTRACE_O_TRACEEXEC, post-execve SIGTRAP is disabled.
1317 * Every extra ptrace call is expensive, so check EAX
1318 * on syscall entry only if PTRACE_O_TRACEEXEC is not enabled:
1319 */
1320 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
1321 if (upeek(tcp, 4*EAX, &eax) < 0)
1322 return -1;
1323 if (eax != -ENOSYS) {
1324 if (debug)
1325 fprintf(stderr, "not a syscall entry (eax = %ld)\n", eax);
1326 return 0;
1327 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001328 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001329#elif defined (X86_64)
Denys Vlasenko18beb982011-08-24 16:59:23 +02001330 if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
1331 if (upeek(tcp, 8*RAX, &rax) < 0)
1332 return -1;
1333 if (current_personality == 1)
1334 rax = (long int)(int)rax; /* sign extend from 32 bits */
1335 if (rax != -ENOSYS && entering(tcp)) {
1336 if (debug)
1337 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1338 return 0;
1339 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001340 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001341#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001342 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001343 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001344 if (syscall_mode != -ENOSYS)
1345 syscall_mode = tcp->scno;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001346 if (gpr2 != syscall_mode && entering(tcp)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001347 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001348 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001349 return 0;
1350 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001351 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1352 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1353 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1354 /*
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001355 * Return from execve.
Roland McGrath96dc5142003-01-20 10:23:04 +00001356 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1357 * flag set for the post-execve SIGTRAP to see and reset.
1358 */
1359 gpr2 = 0;
1360 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001361#elif defined (POWERPC)
1362# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001363 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001364 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001365 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001366 return -1;
1367 if (flags & SO_MASK)
1368 result = -result;
1369#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001370 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001372 if (d0 != -ENOSYS && entering(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001374 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375 return 0;
1376 }
1377#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001378 /*
1379 * Nothing required
1380 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001381#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001382 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001383 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001384#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001385 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001386 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001387#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001388 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001389 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001390 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001391 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001392 if (ia32 && r8 != -ENOSYS && entering(tcp)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001393 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001394 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001395 return 0;
1396 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001397#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001398 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001399 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001400 if (r10 != -ENOSYS && entering(tcp)) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001401 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001402 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001403 return 0;
1404 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001405#elif defined(MICROBLAZE)
1406 if (upeek(tcp, 3 * 4, &r3) < 0)
1407 return -1;
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001408 if (r3 != -ENOSYS && entering(tcp)) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001409 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001410 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001411 return 0;
1412 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001413#endif
1414#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001415 return 1;
1416}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001417
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001418static int
1419internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001420{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001421 /*
1422 * We must always trace a few critical system calls in order to
1423 * correctly support following forks in the presence of tracing
1424 * qualifiers.
1425 */
1426 int (*func)();
1427
1428 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
1429 return 0;
1430
1431 func = sysent[tcp->scno].sys_func;
1432
1433 if ( sys_fork == func
1434#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
1435 || sys_vfork == func
1436#endif
1437#ifdef LINUX
1438 || sys_clone == func
1439#endif
1440#if UNIXWARE > 2
1441 || sys_rfork == func
1442#endif
1443 )
1444 return internal_fork(tcp);
1445
1446#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
1447 if ( sys_execve == func
1448# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
1449 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001450# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001451# if UNIXWARE > 2
1452 || sys_rexecve == func
1453# endif
1454 )
1455 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001456#endif
1457
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001458 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001459}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001460
Roland McGratha4d48532005-06-08 20:45:28 +00001461static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001462syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001463{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001464#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001465 int i, nargs;
1466
Denys Vlasenkoafc64032011-08-23 13:29:01 +02001467 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001468 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001469 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001470 nargs = tcp->u_nargs = MAX_ARGS;
1471
1472# if defined(S390) || defined(S390X)
1473 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001474 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1475 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001476# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001477 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001478 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1479 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001480# elif defined(IA64)
1481 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001482 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001483 long rbs_end;
1484 /* be backwards compatible with kernel < 2.4.4... */
1485# ifndef PT_RBS_END
1486# define PT_RBS_END PT_AR_BSP
1487# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001488
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001489 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1490 return -1;
1491 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001492 return -1;
1493
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001494 sof = (cfm >> 0) & 0x7f;
1495 sol = (cfm >> 7) & 0x7f;
1496 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1497
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001498 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001499 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1500 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1501 return -1;
1502 }
1503 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001504 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1505 PT_R9 /* ECX = out1 */,
1506 PT_R10 /* EDX = out2 */,
1507 PT_R14 /* ESI = out3 */,
1508 PT_R15 /* EDI = out4 */,
1509 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001510
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001511 for (i = 0; i < nargs; ++i) {
1512 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1513 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001514 /* truncate away IVE sign-extension */
1515 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001516 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001517 }
1518# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
1519 /* N32 and N64 both use up to six registers. */
1520 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001521
1522 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1523 return -1;
1524
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001525 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001526 tcp->u_arg[i] = regs[REG_A0 + i];
1527# if defined(LINUX_MIPSN32)
1528 tcp->ext_arg[i] = regs[REG_A0 + i];
1529# endif
1530 }
1531# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001532 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001533 long sp;
1534
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001535 if (upeek(tcp, REG_SP, &sp) < 0)
1536 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001537 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001538 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1539 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001540 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001541 (char *)(tcp->u_arg + 4));
1542 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001543 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001544 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001545 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001546 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001547# elif defined(POWERPC)
1548# ifndef PT_ORIG_R3
1549# define PT_ORIG_R3 34
1550# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001551 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001552 if (upeek(tcp, (i==0) ?
1553 (sizeof(unsigned long) * PT_ORIG_R3) :
1554 ((i+PT_R3) * sizeof(unsigned long)),
1555 &tcp->u_arg[i]) < 0)
1556 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001557 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001558# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001559 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001560 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
1561# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001562 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001563 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1564 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001565# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001566 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001567 tcp->u_arg[i] = regs.uregs[i];
1568# elif defined(AVR32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001569 static const unsigned long *argregp[MAX_ARGS] = { &regs.r12,
1570 &regs.r11,
1571 &regs.r10,
1572 &regs.r9,
1573 &regs.r5,
1574 &regs.r3 };
1575 for (i = 0; i < nargs; ++i)
1576 tcp->u_arg[i] = *argregp[i];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001577# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001578 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 +02001579
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001580 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001581 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1582 return -1;
1583# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001584 static const int syscall_regs[MAX_ARGS] = {
1585 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1586 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001587 };
1588
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001589 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001590 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001591 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001592# elif defined(SH64)
1593 int i;
1594 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001595 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001596
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001597 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001598 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1599 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001600# elif defined(X86_64)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001601 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
1602 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
1603 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001604 };
1605
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001606 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001607 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001608 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001609# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001610 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001611 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1612 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001613# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001614 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001615 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001616 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001617 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001618
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001619 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001620 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1621 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001622# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001623 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001624 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1625 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001626# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001627 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001628 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1629 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001630# else /* Other architecture (like i386) (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001631 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001632 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1633 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001634# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001635#endif /* LINUX */
1636#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001637 int i, nargs;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02001638 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001639 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001640 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001641 nargs = tcp->u_nargs = MAX_ARGS;
1642 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001643 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001645 if (upeek(tcp, uoff(u_arg[0]) +
1646 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1647 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648 }
1649#endif /* SUNOS4 */
1650#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001651# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652 /*
1653 * SGI is broken: even though it has pr_sysarg, it doesn't
1654 * set them on system call entry. Get a clue.
1655 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02001656 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657 tcp->u_nargs = sysent[tcp->scno].nargs;
1658 else
1659 tcp->u_nargs = tcp->status.pr_nsysarg;
1660 if (tcp->u_nargs > 4) {
1661 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001662 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001663 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001664 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001665 }
1666 else {
1667 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001668 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001669 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001670# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00001671 /*
1672 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1673 */
Denys Vlasenkoafc64032011-08-23 13:29:01 +02001674 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
John Hughes25299712001-03-06 10:10:06 +00001675 tcp->u_nargs = sysent[tcp->scno].nargs;
1676 else
1677 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1678 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001679 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1680# elif defined(HAVE_PR_SYSCALL)
1681 int i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +02001682 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683 tcp->u_nargs = sysent[tcp->scno].nargs;
1684 else
1685 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001686 for (i = 0; i < tcp->u_nargs; i++)
1687 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1688# elif defined(I386)
Denys Vlasenkoafc64032011-08-23 13:29:01 +02001689 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001690 tcp->u_nargs = sysent[tcp->scno].nargs;
1691 else
1692 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02001693 if (tcp->u_nargs > 0)
1694 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001695 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1696# else
John Hughes25299712001-03-06 10:10:06 +00001697 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001698# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001700#ifdef FREEBSD
1701 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1702 sysent[tcp->scno].nargs > tcp->status.val)
1703 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001704 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001705 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001706 if (tcp->u_nargs < 0)
1707 tcp->u_nargs = 0;
1708 if (tcp->u_nargs > MAX_ARGS)
1709 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001710 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001711 case SYS___syscall:
1712 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1713 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001714 break;
1715 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001716 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1717 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001718 break;
1719 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001720 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1721 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001722 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001723 }
1724#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001725 return 1;
1726}
1727
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001728static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001729trace_syscall_entering(struct tcb *tcp)
1730{
1731 int res, scno_good;
1732
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001733#if defined TCB_WAITEXECVE
1734 if (tcp->flags & TCB_WAITEXECVE) {
1735 /* This is the post-execve SIGTRAP. */
1736 tcp->flags &= ~TCB_WAITEXECVE;
1737 return 0;
1738 }
1739#endif
1740
Denys Vlasenko06602d92011-08-24 17:53:52 +02001741 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001742 if (res == 0)
1743 return res;
1744 if (res == 1)
1745 res = syscall_fixup(tcp);
1746 if (res == 0)
1747 return res;
1748 if (res == 1)
1749 res = syscall_enter(tcp);
1750 if (res == 0)
1751 return res;
1752
1753 if (res != 1) {
1754 printleader(tcp);
1755 tcp->flags &= ~TCB_REPRINT;
1756 tcp_last = tcp;
1757 if (scno_good != 1)
1758 tprintf("????" /* anti-trigraph gap */ "(");
1759 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
1760 tprintf("syscall_%lu(", tcp->scno);
1761 else
1762 tprintf("%s(", sysent[tcp->scno].sys_name);
1763 /*
1764 * " <unavailable>" will be added later by the code which
1765 * detects ptrace errors.
1766 */
1767 goto ret;
1768 }
1769
1770 switch (known_scno(tcp)) {
1771#ifdef SYS_socket_subcall
1772 case SYS_socketcall:
1773 decode_subcall(tcp, SYS_socket_subcall,
1774 SYS_socket_nsubcalls, deref_style);
1775 break;
1776#endif
1777#ifdef SYS_ipc_subcall
1778 case SYS_ipc:
1779 decode_subcall(tcp, SYS_ipc_subcall,
1780 SYS_ipc_nsubcalls, shift_style);
1781 break;
1782#endif
1783#ifdef SVR4
1784#ifdef SYS_pgrpsys_subcall
1785 case SYS_pgrpsys:
1786 decode_subcall(tcp, SYS_pgrpsys_subcall,
1787 SYS_pgrpsys_nsubcalls, shift_style);
1788 break;
1789#endif /* SYS_pgrpsys_subcall */
1790#ifdef SYS_sigcall_subcall
1791 case SYS_sigcall:
1792 decode_subcall(tcp, SYS_sigcall_subcall,
1793 SYS_sigcall_nsubcalls, mask_style);
1794 break;
1795#endif /* SYS_sigcall_subcall */
1796 case SYS_msgsys:
1797 decode_subcall(tcp, SYS_msgsys_subcall,
1798 SYS_msgsys_nsubcalls, shift_style);
1799 break;
1800 case SYS_shmsys:
1801 decode_subcall(tcp, SYS_shmsys_subcall,
1802 SYS_shmsys_nsubcalls, shift_style);
1803 break;
1804 case SYS_semsys:
1805 decode_subcall(tcp, SYS_semsys_subcall,
1806 SYS_semsys_nsubcalls, shift_style);
1807 break;
1808 case SYS_sysfs:
1809 decode_subcall(tcp, SYS_sysfs_subcall,
1810 SYS_sysfs_nsubcalls, shift_style);
1811 break;
1812 case SYS_spcall:
1813 decode_subcall(tcp, SYS_spcall_subcall,
1814 SYS_spcall_nsubcalls, shift_style);
1815 break;
1816#ifdef SYS_context_subcall
1817 case SYS_context:
1818 decode_subcall(tcp, SYS_context_subcall,
1819 SYS_context_nsubcalls, shift_style);
1820 break;
1821#endif /* SYS_context_subcall */
1822#ifdef SYS_door_subcall
1823 case SYS_door:
1824 decode_subcall(tcp, SYS_door_subcall,
1825 SYS_door_nsubcalls, door_style);
1826 break;
1827#endif /* SYS_door_subcall */
1828#ifdef SYS_kaio_subcall
1829 case SYS_kaio:
1830 decode_subcall(tcp, SYS_kaio_subcall,
1831 SYS_kaio_nsubcalls, shift_style);
1832 break;
1833#endif
1834#endif /* SVR4 */
1835#ifdef FREEBSD
1836 case SYS_msgsys:
1837 case SYS_shmsys:
1838 case SYS_semsys:
1839 decode_subcall(tcp, 0, 0, table_style);
1840 break;
1841#endif
1842#ifdef SUNOS4
1843 case SYS_semsys:
1844 decode_subcall(tcp, SYS_semsys_subcall,
1845 SYS_semsys_nsubcalls, shift_style);
1846 break;
1847 case SYS_msgsys:
1848 decode_subcall(tcp, SYS_msgsys_subcall,
1849 SYS_msgsys_nsubcalls, shift_style);
1850 break;
1851 case SYS_shmsys:
1852 decode_subcall(tcp, SYS_shmsys_subcall,
1853 SYS_shmsys_nsubcalls, shift_style);
1854 break;
1855#endif
1856 }
1857
1858 internal_syscall(tcp);
1859
1860 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
1861 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1862 (tracing_paths && !pathtrace_match(tcp))) {
1863 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1864 return 0;
1865 }
1866
1867 tcp->flags &= ~TCB_FILTERED;
1868
1869 if (cflag == CFLAG_ONLY_STATS) {
1870 res = 0;
1871 goto ret;
1872 }
1873
1874 printleader(tcp);
1875 tcp->flags &= ~TCB_REPRINT;
1876 tcp_last = tcp;
1877 if (tcp->scno >= nsyscalls || tcp->scno < 0)
1878 tprintf("syscall_%lu(", tcp->scno);
1879 else
1880 tprintf("%s(", sysent[tcp->scno].sys_name);
1881 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
1882 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1883 sysent[tcp->scno].sys_func != sys_exit))
1884 res = printargs(tcp);
1885 else
1886 res = (*sysent[tcp->scno].sys_func)(tcp);
1887
1888 if (fflush(tcp->outf) == EOF)
1889 return -1;
1890 ret:
1891 tcp->flags |= TCB_INSYSCALL;
1892 /* Measure the entrance time as late as possible to avoid errors. */
1893 if (dtime || cflag)
1894 gettimeofday(&tcp->etime, NULL);
1895 return res;
1896}
1897
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001898/* Returns:
1899 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1900 * 1: ok, continue in trace_syscall().
1901 * other: error, trace_syscall() should print error indicator
1902 * ("????" etc) and bail out.
1903 */
1904static int
1905get_syscall_result(struct tcb *tcp)
1906{
1907#ifdef LINUX
1908# if defined(S390) || defined(S390X)
1909# elif defined (POWERPC)
1910# elif defined(AVR32)
1911 /* Read complete register set in one go. */
1912 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1913 return -1;
1914# elif defined(BFIN)
1915# elif defined (I386)
1916 if (upeek(tcp, 4*EAX, &eax) < 0)
1917 return -1;
1918# elif defined (X86_64)
1919 if (upeek(tcp, 8*RAX, &rax) < 0)
1920 return -1;
1921# elif defined(IA64)
1922# define IA64_PSR_IS ((long)1 << 34)
1923 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1924 ia32 = (psr & IA64_PSR_IS) != 0;
1925 if (upeek(tcp, PT_R8, &r8) < 0)
1926 return -1;
1927 if (upeek(tcp, PT_R10, &r10) < 0)
1928 return -1;
1929# elif defined (ARM)
1930 /* Read complete register set in one go. */
1931 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1932 return -1;
1933# elif defined (M68K)
1934# elif defined (LINUX_MIPSN32)
1935 unsigned long long regs[38];
1936
1937 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1938 return -1;
1939 a3 = regs[REG_A3];
1940 r2 = regs[REG_V0];
1941# elif defined (MIPS)
1942 if (upeek(tcp, REG_A3, &a3) < 0)
1943 return -1;
1944 if (upeek(tcp, REG_V0, &r2) < 0)
1945 return -1;
1946# elif defined (ALPHA)
1947 if (upeek(tcp, REG_A3, &a3) < 0)
1948 return -1;
1949 if (upeek(tcp, REG_R0, &r0) < 0)
1950 return -1;
1951# elif defined (SPARC) || defined (SPARC64)
1952 /* Everything we need is in the current register set. */
1953 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1954 return -1;
1955# elif defined(HPPA)
1956# elif defined(SH)
1957# elif defined(SH64)
1958# elif defined(CRISV10) || defined(CRISV32)
1959# elif defined(TILE)
1960# elif defined(MICROBLAZE)
1961# endif
1962#endif /* LINUX */
1963
1964#ifdef SUNOS4
1965#elif defined(SH)
1966 /* new syscall ABI returns result in R0 */
1967 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1968 return -1;
1969#elif defined(SH64)
1970 /* ABI defines result returned in r9 */
1971 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1972 return -1;
1973#endif
1974
1975#ifdef USE_PROCFS
1976# ifndef HAVE_PR_SYSCALL
1977# ifdef FREEBSD
1978 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1979 perror("pread");
1980 return -1;
1981 }
1982# endif /* FREEBSD */
1983# endif /* !HAVE_PR_SYSCALL */
1984#endif /* USE_PROCFS */
1985
1986 return 1;
1987}
1988
1989#ifdef LINUX
1990/*
1991 * Check the syscall return value register value for whether it is
1992 * a negated errno code indicating an error, or a success return value.
1993 */
1994static inline int
1995is_negated_errno(unsigned long int val)
1996{
1997 unsigned long int max = -(long int) nerrnos;
1998# if SUPPORTED_PERSONALITIES > 1
1999 if (personality_wordsize[current_personality] < sizeof(val)) {
2000 val = (unsigned int) val;
2001 max = (unsigned int) max;
2002 }
2003# endif
2004 return val > max;
2005}
2006#endif
2007
2008static int
2009get_error(struct tcb *tcp)
2010{
2011 int u_error = 0;
2012#ifdef LINUX
2013 int check_errno = 1;
2014 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2015 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2016 check_errno = 0;
2017 }
2018# if defined(S390) || defined(S390X)
2019 if (check_errno && is_negated_errno(gpr2)) {
2020 tcp->u_rval = -1;
2021 u_error = -gpr2;
2022 }
2023 else {
2024 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002025 }
2026# elif defined(I386)
2027 if (check_errno && is_negated_errno(eax)) {
2028 tcp->u_rval = -1;
2029 u_error = -eax;
2030 }
2031 else {
2032 tcp->u_rval = eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002033 }
2034# elif defined(X86_64)
2035 if (check_errno && is_negated_errno(rax)) {
2036 tcp->u_rval = -1;
2037 u_error = -rax;
2038 }
2039 else {
2040 tcp->u_rval = rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002041 }
2042# elif defined(IA64)
2043 if (ia32) {
2044 int err;
2045
2046 err = (int)r8;
2047 if (check_errno && is_negated_errno(err)) {
2048 tcp->u_rval = -1;
2049 u_error = -err;
2050 }
2051 else {
2052 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002053 }
2054 } else {
2055 if (check_errno && r10) {
2056 tcp->u_rval = -1;
2057 u_error = r8;
2058 } else {
2059 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002060 }
2061 }
2062# elif defined(MIPS)
2063 if (check_errno && a3) {
2064 tcp->u_rval = -1;
2065 u_error = r2;
2066 } else {
2067 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002068 }
2069# elif defined(POWERPC)
2070 if (check_errno && is_negated_errno(result)) {
2071 tcp->u_rval = -1;
2072 u_error = -result;
2073 }
2074 else {
2075 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002076 }
2077# elif defined(M68K)
2078 if (check_errno && is_negated_errno(d0)) {
2079 tcp->u_rval = -1;
2080 u_error = -d0;
2081 }
2082 else {
2083 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002084 }
2085# elif defined(ARM)
2086 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2087 tcp->u_rval = -1;
2088 u_error = -regs.ARM_r0;
2089 }
2090 else {
2091 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002092 }
2093# elif defined(AVR32)
2094 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2095 tcp->u_rval = -1;
2096 u_error = -regs.r12;
2097 }
2098 else {
2099 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002100 }
2101# elif defined(BFIN)
2102 if (check_errno && is_negated_errno(r0)) {
2103 tcp->u_rval = -1;
2104 u_error = -r0;
2105 } else {
2106 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002107 }
2108# elif defined(ALPHA)
2109 if (check_errno && a3) {
2110 tcp->u_rval = -1;
2111 u_error = r0;
2112 }
2113 else {
2114 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002115 }
2116# elif defined(SPARC)
2117 if (check_errno && regs.psr & PSR_C) {
2118 tcp->u_rval = -1;
2119 u_error = regs.u_regs[U_REG_O0];
2120 }
2121 else {
2122 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002123 }
2124# elif defined(SPARC64)
2125 if (check_errno && regs.tstate & 0x1100000000UL) {
2126 tcp->u_rval = -1;
2127 u_error = regs.u_regs[U_REG_O0];
2128 }
2129 else {
2130 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002131 }
2132# elif defined(HPPA)
2133 if (check_errno && is_negated_errno(r28)) {
2134 tcp->u_rval = -1;
2135 u_error = -r28;
2136 }
2137 else {
2138 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002139 }
2140# elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002141 if (check_errno && is_negated_errno(r0)) {
2142 tcp->u_rval = -1;
2143 u_error = -r0;
2144 }
2145 else {
2146 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002147 }
2148# elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002149 if (check_errno && is_negated_errno(r9)) {
2150 tcp->u_rval = -1;
2151 u_error = -r9;
2152 }
2153 else {
2154 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002155 }
2156# elif defined(CRISV10) || defined(CRISV32)
2157 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2158 tcp->u_rval = -1;
2159 u_error = -r10;
2160 }
2161 else {
2162 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002163 }
2164# elif defined(TILE)
2165 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002166 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2167 return -1;
2168 if (check_errno && rval < 0 && rval > -nerrnos) {
2169 tcp->u_rval = -1;
2170 u_error = -rval;
2171 }
2172 else {
2173 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002174 }
2175# elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002176 if (check_errno && is_negated_errno(r3)) {
2177 tcp->u_rval = -1;
2178 u_error = -r3;
2179 }
2180 else {
2181 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002182 }
2183# endif
2184#endif /* LINUX */
2185#ifdef SUNOS4
2186 /* get error code from user struct */
2187 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2188 return -1;
2189 u_error >>= 24; /* u_error is a char */
2190
2191 /* get system call return value */
2192 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2193 return -1;
2194#endif /* SUNOS4 */
2195#ifdef SVR4
2196# ifdef SPARC
2197 /* Judicious guessing goes a long way. */
2198 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2199 tcp->u_rval = -1;
2200 u_error = tcp->status.pr_reg[R_O0];
2201 }
2202 else {
2203 tcp->u_rval = tcp->status.pr_reg[R_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002204 }
2205# endif /* SPARC */
2206# ifdef I386
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002207 if (tcp->status.PR_REG[EFL] & 0x1) {
2208 tcp->u_rval = -1;
2209 u_error = tcp->status.PR_REG[EAX];
2210 }
2211 else {
2212 tcp->u_rval = tcp->status.PR_REG[EAX];
2213# ifdef HAVE_LONG_LONG
2214 tcp->u_lrval =
2215 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2216 tcp->status.PR_REG[EAX];
2217# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002218 }
2219# endif /* I386 */
2220# ifdef X86_64
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002221 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2222 tcp->u_rval = -1;
2223 u_error = tcp->status.PR_REG[RAX];
2224 }
2225 else {
2226 tcp->u_rval = tcp->status.PR_REG[RAX];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002227 }
2228# endif /* X86_64 */
2229# ifdef MIPS
2230 if (tcp->status.pr_reg[CTX_A3]) {
2231 tcp->u_rval = -1;
2232 u_error = tcp->status.pr_reg[CTX_V0];
2233 }
2234 else {
2235 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002236 }
2237# endif /* MIPS */
2238#endif /* SVR4 */
2239#ifdef FREEBSD
2240 if (regs.r_eflags & PSL_C) {
2241 tcp->u_rval = -1;
2242 u_error = regs.r_eax;
2243 } else {
2244 tcp->u_rval = regs.r_eax;
2245 tcp->u_lrval =
Denys Vlasenko684fb1a2011-08-25 00:26:38 +02002246 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002247 }
2248#endif /* FREEBSD */
2249 tcp->u_error = u_error;
2250 return 1;
2251}
2252
2253static void
2254dumpio(struct tcb *tcp)
2255{
2256 if (syserror(tcp))
2257 return;
2258 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
2259 return;
2260 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
2261 return;
2262 if (sysent[tcp->scno].sys_func == printargs)
2263 return;
2264 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
2265 if (sysent[tcp->scno].sys_func == sys_read ||
2266 sysent[tcp->scno].sys_func == sys_pread ||
2267 sysent[tcp->scno].sys_func == sys_pread64 ||
2268 sysent[tcp->scno].sys_func == sys_recv ||
2269 sysent[tcp->scno].sys_func == sys_recvfrom)
2270 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
2271 else if (sysent[tcp->scno].sys_func == sys_readv)
2272 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2273 return;
2274 }
2275 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
2276 if (sysent[tcp->scno].sys_func == sys_write ||
2277 sysent[tcp->scno].sys_func == sys_pwrite ||
2278 sysent[tcp->scno].sys_func == sys_pwrite64 ||
2279 sysent[tcp->scno].sys_func == sys_send ||
2280 sysent[tcp->scno].sys_func == sys_sendto)
2281 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
2282 else if (sysent[tcp->scno].sys_func == sys_writev)
2283 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2284 return;
2285 }
2286}
2287
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002288static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002289trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002290{
2291 int sys_res;
2292 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002293 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002294 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002295
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002296 /* Measure the exit time as early as possible to avoid errors. */
2297 if (dtime || cflag)
2298 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002299
Denys Vlasenko06602d92011-08-24 17:53:52 +02002300 scno_good = res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002301 if (res == 0)
2302 return res;
2303 if (res == 1)
2304 res = syscall_fixup(tcp);
2305 if (res == 0)
2306 return res;
2307 if (res == 1)
2308 res = get_error(tcp);
2309 if (res == 0)
2310 return res;
2311 if (res == 1)
2312 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002313
Grant Edwards8a082772011-04-07 20:25:40 +00002314 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002315 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002316 }
2317
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002318 if (tcp->flags & TCB_REPRINT) {
2319 printleader(tcp);
2320 tprintf("<... ");
2321 if (scno_good != 1)
2322 tprintf("????");
2323 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2324 tprintf("syscall_%lu", tcp->scno);
2325 else
2326 tprintf("%s", sysent[tcp->scno].sys_name);
2327 tprintf(" resumed> ");
2328 }
2329
2330 if (cflag) {
2331 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002332 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002333 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002334 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002335 }
2336 }
2337
2338 if (res != 1) {
2339 tprintf(") ");
2340 tabto(acolumn);
2341 tprintf("= ? <unavailable>");
2342 printtrailer();
2343 tcp->flags &= ~TCB_INSYSCALL;
2344 return res;
2345 }
2346
2347 if (tcp->scno >= nsyscalls || tcp->scno < 0
2348 || (qual_flags[tcp->scno] & QUAL_RAW))
2349 sys_res = printargs(tcp);
2350 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002351 /* FIXME: not_failing_only (IOW, option -z) is broken:
2352 * failure of syscall is known only after syscall return.
2353 * Thus we end up with something like this on, say, ENOENT:
2354 * open("doesnt_exist", O_RDONLY <unfinished ...>
2355 * {next syscall decode}
2356 * whereas the intended result is that open(...) line
2357 * is not shown at all.
2358 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002359 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002360 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002361 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2362 }
2363
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002364 tprintf(") ");
2365 tabto(acolumn);
Denys Vlasenko3b738812011-08-22 02:06:35 +02002366 u_error = tcp->u_error;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002367 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2368 qual_flags[tcp->scno] & QUAL_RAW) {
2369 if (u_error)
2370 tprintf("= -1 (errno %ld)", u_error);
2371 else
2372 tprintf("= %#lx", tcp->u_rval);
2373 }
2374 else if (!(sys_res & RVAL_NONE) && u_error) {
2375 switch (u_error) {
2376#ifdef LINUX
2377 case ERESTARTSYS:
2378 tprintf("= ? ERESTARTSYS (To be restarted)");
2379 break;
2380 case ERESTARTNOINTR:
2381 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2382 break;
2383 case ERESTARTNOHAND:
2384 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2385 break;
2386 case ERESTART_RESTARTBLOCK:
2387 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2388 break;
2389#endif /* LINUX */
2390 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002391 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002392 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002393 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002394 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002395 strerror(u_error));
2396 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002397 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002398 strerror(u_error));
2399 break;
2400 }
2401 if ((sys_res & RVAL_STR) && tcp->auxstr)
2402 tprintf(" (%s)", tcp->auxstr);
2403 }
2404 else {
2405 if (sys_res & RVAL_NONE)
2406 tprintf("= ?");
2407 else {
2408 switch (sys_res & RVAL_MASK) {
2409 case RVAL_HEX:
2410 tprintf("= %#lx", tcp->u_rval);
2411 break;
2412 case RVAL_OCTAL:
2413 tprintf("= %#lo", tcp->u_rval);
2414 break;
2415 case RVAL_UDECIMAL:
2416 tprintf("= %lu", tcp->u_rval);
2417 break;
2418 case RVAL_DECIMAL:
2419 tprintf("= %ld", tcp->u_rval);
2420 break;
2421#ifdef HAVE_LONG_LONG
2422 case RVAL_LHEX:
2423 tprintf("= %#llx", tcp->u_lrval);
2424 break;
2425 case RVAL_LOCTAL:
2426 tprintf("= %#llo", tcp->u_lrval);
2427 break;
2428 case RVAL_LUDECIMAL:
2429 tprintf("= %llu", tcp->u_lrval);
2430 break;
2431 case RVAL_LDECIMAL:
2432 tprintf("= %lld", tcp->u_lrval);
2433 break;
2434#endif
2435 default:
2436 fprintf(stderr,
2437 "invalid rval format\n");
2438 break;
2439 }
2440 }
2441 if ((sys_res & RVAL_STR) && tcp->auxstr)
2442 tprintf(" (%s)", tcp->auxstr);
2443 }
2444 if (dtime) {
2445 tv_sub(&tv, &tv, &tcp->etime);
2446 tprintf(" <%ld.%06ld>",
2447 (long) tv.tv_sec, (long) tv.tv_usec);
2448 }
2449 printtrailer();
2450
2451 dumpio(tcp);
2452 if (fflush(tcp->outf) == EOF)
2453 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002454 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002455 tcp->flags &= ~TCB_INSYSCALL;
2456 return 0;
2457}
2458
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002459int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002460trace_syscall(struct tcb *tcp)
2461{
2462 return exiting(tcp) ?
2463 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2464}