blob: 3f69c18101927028fce33dc8658edfe546481dde [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
Denys Vlasenko523635f2012-02-25 02:44:25 +010046# 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)
Denys Vlasenko523635f2012-02-25 02:44:25 +010051# 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
Denys Vlasenko523635f2012-02-25 02:44:25 +010058# 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
Denys Vlasenko84703742012-02-25 02:38:52 +010063#if 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
Denys Vlasenko84703742012-02-25 02:38:52 +010068#endif
Roland McGrath6d1a65c2004-07-12 07:44:08 +000069
Denys Vlasenko84703742012-02-25 02:38:52 +010070#if defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000071# include <asm/ptrace_offsets.h>
72# include <asm/rse.h>
73#endif
74
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000075#ifndef ERESTARTSYS
Denys Vlasenko523635f2012-02-25 02:44:25 +010076# define ERESTARTSYS 512
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000077#endif
Denys Vlasenko523635f2012-02-25 02:44:25 +010078# ifndef ERESTARTNOINTR
79# define ERESTARTNOINTR 513
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000080#endif
Denys Vlasenko523635f2012-02-25 02:44:25 +010081# ifndef ERESTARTNOHAND
82# define ERESTARTNOHAND 514 /* restart if no handler.. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000083#endif
Denys Vlasenko523635f2012-02-25 02:44:25 +010084# ifndef ENOIOCTLCMD
85# define ENOIOCTLCMD 515 /* No ioctl command */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000086#endif
Denys Vlasenko523635f2012-02-25 02:44:25 +010087# ifndef ERESTART_RESTARTBLOCK
88# define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
Roland McGrath9c555e72003-07-09 09:47:59 +000089#endif
Denys Vlasenko523635f2012-02-25 02:44:25 +010090
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifndef NSIG
Denys Vlasenko523635f2012-02-25 02:44:25 +010092# warning: NSIG is not defined, using 32
93# define NSIG 32
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000094#endif
95#ifdef ARM
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020096/* Ugh. Is this really correct? ARM has no RT signals?! */
Denys Vlasenko523635f2012-02-25 02:44:25 +010097# undef NSIG
98# define NSIG 32
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000099#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000100
101#include "syscall.h"
102
103/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000104#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000105#define TF TRACE_FILE
106#define TI TRACE_IPC
107#define TN TRACE_NETWORK
108#define TP TRACE_PROCESS
109#define TS TRACE_SIGNAL
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000110#define NF SYSCALL_NEVER_FAILS
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200111#define MA MAX_ARGS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000112
Roland McGrathee36ce12004-09-04 03:53:10 +0000113static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000114#include "syscallent.h"
115};
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116
117#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000118static const struct sysent sysent1[] = {
Denys Vlasenko523635f2012-02-25 02:44:25 +0100119# include "syscallent1.h"
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200121#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122
123#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000124static const struct sysent sysent2[] = {
Denys Vlasenko523635f2012-02-25 02:44:25 +0100125# include "syscallent2.h"
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200127#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000128
129/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000130#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000131#undef TF
132#undef TI
133#undef TN
134#undef TP
135#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000136#undef NF
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200137#undef MA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000138
Denys Vlasenko39fca622011-08-20 02:12:33 +0200139
140/*
141 * `ioctlent.h' may be generated from `ioctlent.raw' by the auxiliary
142 * program `ioctlsort', such that the list is sorted by the `code' field.
143 * This has the side-effect of resolving the _IO.. macros into
144 * plain integers, eliminating the need to include here everything
145 * in "/usr/include".
146 */
147
148
Roland McGrathee36ce12004-09-04 03:53:10 +0000149static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000150#include "errnoent.h"
151};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200152static const char *const signalent0[] = {
153#include "signalent.h"
154};
155static const struct ioctlent ioctlent0[] = {
156#include "ioctlent.h"
157};
158enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
159enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
160enum { nsignals0 = ARRAY_SIZE(signalent0) };
161enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
162int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163
164#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const char *const errnoent1[] = {
Denys Vlasenko523635f2012-02-25 02:44:25 +0100166# include "errnoent1.h"
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200168static const char *const signalent1[] = {
Denys Vlasenko523635f2012-02-25 02:44:25 +0100169# include "signalent1.h"
Denys Vlasenko39fca622011-08-20 02:12:33 +0200170};
171static const struct ioctlent ioctlent1[] = {
Denys Vlasenko523635f2012-02-25 02:44:25 +0100172# include "ioctlent1.h"
Denys Vlasenko39fca622011-08-20 02:12:33 +0200173};
174enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
175enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
176enum { nsignals1 = ARRAY_SIZE(signalent1) };
177enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
178int qual_flags1[MAX_QUALS];
179#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000180
181#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000182static const char *const errnoent2[] = {
Denys Vlasenko523635f2012-02-25 02:44:25 +0100183# include "errnoent2.h"
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200185static const char *const signalent2[] = {
Denys Vlasenko523635f2012-02-25 02:44:25 +0100186# include "signalent2.h"
Denys Vlasenko39fca622011-08-20 02:12:33 +0200187};
188static const struct ioctlent ioctlent2[] = {
Denys Vlasenko523635f2012-02-25 02:44:25 +0100189# include "ioctlent2.h"
Denys Vlasenko39fca622011-08-20 02:12:33 +0200190};
191enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
192enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
193enum { nsignals2 = ARRAY_SIZE(signalent2) };
194enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
195int qual_flags2[MAX_QUALS];
196#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000197
Denys Vlasenko39fca622011-08-20 02:12:33 +0200198
199const struct sysent *sysent;
Roland McGrathee36ce12004-09-04 03:53:10 +0000200const char *const *errnoent;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200201const char *const *signalent;
202const struct ioctlent *ioctlent;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200203unsigned nsyscalls;
204unsigned nerrnos;
205unsigned nsignals;
206unsigned nioctlents;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200207int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000208
209int current_personality;
210
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000211#ifndef PERSONALITY0_WORDSIZE
212# define PERSONALITY0_WORDSIZE sizeof(long)
213#endif
214const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
215 PERSONALITY0_WORDSIZE,
216#if SUPPORTED_PERSONALITIES > 1
217 PERSONALITY1_WORDSIZE,
218#endif
219#if SUPPORTED_PERSONALITIES > 2
220 PERSONALITY2_WORDSIZE,
221#endif
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200222};
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000223
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200224void
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000225set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000226{
227 switch (personality) {
228 case 0:
229 errnoent = errnoent0;
230 nerrnos = nerrnos0;
231 sysent = sysent0;
232 nsyscalls = nsyscalls0;
233 ioctlent = ioctlent0;
234 nioctlents = nioctlents0;
235 signalent = signalent0;
236 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000237 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000238 break;
239
240#if SUPPORTED_PERSONALITIES >= 2
241 case 1:
242 errnoent = errnoent1;
243 nerrnos = nerrnos1;
244 sysent = sysent1;
245 nsyscalls = nsyscalls1;
246 ioctlent = ioctlent1;
247 nioctlents = nioctlents1;
248 signalent = signalent1;
249 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000250 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000251 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200252#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253
254#if SUPPORTED_PERSONALITIES >= 3
255 case 2:
256 errnoent = errnoent2;
257 nerrnos = nerrnos2;
258 sysent = sysent2;
259 nsyscalls = nsyscalls2;
260 ioctlent = ioctlent2;
261 nioctlents = nioctlents2;
262 signalent = signalent2;
263 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000264 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000265 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200266#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000267 }
268
269 current_personality = personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000270}
271
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000272#if SUPPORTED_PERSONALITIES > 1
273static void
274update_personality(struct tcb *tcp, int personality)
275{
276 if (personality == current_personality)
277 return;
278 set_personality(personality);
279
280 if (personality == tcp->currpers)
281 return;
282 tcp->currpers = personality;
283
Denys Vlasenko523635f2012-02-25 02:44:25 +0100284# if defined(POWERPC64) || defined(X86_64)
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000285 if (!qflag) {
286 static const char *const names[] = {"64 bit", "32 bit"};
287 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
288 tcp->pid, names[personality]);
289 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100290# endif
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000291}
292#endif
Roland McGrathe10e62a2004-09-04 04:20:43 +0000293
Roland McGrath9797ceb2002-12-30 10:23:00 +0000294static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000295
Roland McGrathe10e62a2004-09-04 04:20:43 +0000296static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000297 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000298 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000299 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000300 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000301} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000302 { QUAL_TRACE, "trace", qual_syscall, "system call" },
303 { QUAL_TRACE, "t", qual_syscall, "system call" },
304 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
305 { QUAL_ABBREV, "a", qual_syscall, "system call" },
306 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
307 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
308 { QUAL_RAW, "raw", qual_syscall, "system call" },
309 { QUAL_RAW, "x", qual_syscall, "system call" },
310 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
311 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
312 { QUAL_SIGNAL, "s", qual_signal, "signal" },
313 { QUAL_FAULT, "fault", qual_fault, "fault" },
314 { QUAL_FAULT, "faults", qual_fault, "fault" },
315 { QUAL_FAULT, "m", qual_fault, "fault" },
316 { QUAL_READ, "read", qual_desc, "descriptor" },
317 { QUAL_READ, "reads", qual_desc, "descriptor" },
318 { QUAL_READ, "r", qual_desc, "descriptor" },
319 { QUAL_WRITE, "write", qual_desc, "descriptor" },
320 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
321 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000322 { 0, NULL, NULL, NULL },
323};
324
Roland McGrath9797ceb2002-12-30 10:23:00 +0000325static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000326qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000327{
Roland McGrath138c6a32006-01-12 09:50:49 +0000328 if (pers == 0 || pers < 0) {
329 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000330 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000331 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000332 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 }
334
335#if SUPPORTED_PERSONALITIES >= 2
336 if (pers == 1 || pers < 0) {
337 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000338 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000339 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000340 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000341 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100342#endif
Roland McGrath138c6a32006-01-12 09:50:49 +0000343
344#if SUPPORTED_PERSONALITIES >= 3
345 if (pers == 2 || pers < 0) {
346 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000347 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000348 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000349 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000350 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100351#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000352}
353
354static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000355qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000356{
357 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000358 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000359
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000360 if (isdigit((unsigned char)*s)) {
361 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000362 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000363 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000364 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000365 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000366 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000367 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000368 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000369 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000370 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000371 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000372
373#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000374 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000375 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000376 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000377 rc = 0;
378 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100379#endif
Roland McGrath138c6a32006-01-12 09:50:49 +0000380
381#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000382 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000383 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000384 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000385 rc = 0;
386 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100387#endif
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000388
Roland McGrathfe6b3522005-02-02 04:40:11 +0000389 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000390}
391
392static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000393qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000394{
395 int i;
396 char buf[32];
397
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000398 if (isdigit((unsigned char)*s)) {
399 int signo = atoi(s);
400 if (signo < 0 || signo >= MAX_QUALS)
401 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000402 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000403 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000404 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000405 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000406 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000407 strcpy(buf, s);
408 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000409 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000411 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000412 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000413 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000414 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000415 }
Roland McGrath76421df2005-02-02 03:51:18 +0000416 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000417}
418
419static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000420qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000421{
422 return -1;
423}
424
425static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000426qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000427{
Roland McGrath48a035f2006-01-12 09:45:56 +0000428 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000429 int desc = atoi(s);
430 if (desc < 0 || desc >= MAX_QUALS)
431 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000432 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000433 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000434 }
435 return -1;
436}
437
438static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000439lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000440{
441 if (strcmp(s, "file") == 0)
442 return TRACE_FILE;
443 if (strcmp(s, "ipc") == 0)
444 return TRACE_IPC;
445 if (strcmp(s, "network") == 0)
446 return TRACE_NETWORK;
447 if (strcmp(s, "process") == 0)
448 return TRACE_PROCESS;
449 if (strcmp(s, "signal") == 0)
450 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000451 if (strcmp(s, "desc") == 0)
452 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000453 return -1;
454}
455
456void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000457qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000458{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000459 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000460 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000461 char *copy;
462 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 int i, n;
464
465 opt = &qual_options[0];
466 for (i = 0; (p = qual_options[i].option_name); i++) {
467 n = strlen(p);
468 if (strncmp(s, p, n) == 0 && s[n] == '=') {
469 opt = &qual_options[i];
470 s += n + 1;
471 break;
472 }
473 }
474 not = 0;
475 if (*s == '!') {
476 not = 1;
477 s++;
478 }
479 if (strcmp(s, "none") == 0) {
480 not = 1 - not;
481 s = "all";
482 }
483 if (strcmp(s, "all") == 0) {
484 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000485 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000486 }
487 return;
488 }
489 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000490 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000491 }
Denys Vlasenko5d645812011-08-20 12:48:18 +0200492 copy = strdup(s);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200493 if (!copy)
494 die_out_of_memory();
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000495 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000496 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000497 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000498 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000499 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000500
501#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000502 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000503 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000504 qualify_one(i, opt->bitflag, not, 1);
Denys Vlasenko523635f2012-02-25 02:44:25 +0100505#endif
Roland McGrath138c6a32006-01-12 09:50:49 +0000506
507#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000508 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000509 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000510 qualify_one(i, opt->bitflag, not, 2);
Denys Vlasenko523635f2012-02-25 02:44:25 +0100511#endif
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000512
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000513 continue;
514 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000515 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000516 fprintf(stderr, "strace: invalid %s `%s'\n",
517 opt->argument_name, p);
518 exit(1);
519 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000520 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000521 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000522 return;
523}
524
Wichert Akkerman8829a551999-06-11 13:18:40 +0000525enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000526
Denys Vlasenko84703742012-02-25 02:38:52 +0100527#if !(defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000528
Roland McGratha4d48532005-06-08 20:45:28 +0000529static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200530decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000531{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000532 unsigned long addr, mask;
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200533 int i, n;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000534 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000535
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536 switch (style) {
537 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000538 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
539 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540 tcp->scno = subcall + tcp->u_arg[0];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200541 tcp->u_nargs = n = sysent[tcp->scno].nargs;
542 for (i = 0; i < n; i++)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543 tcp->u_arg[i] = tcp->u_arg[i + 1];
544 break;
545 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000546 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
547 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000548 tcp->scno = subcall + tcp->u_arg[0];
549 addr = tcp->u_arg[1];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200550 tcp->u_nargs = n = sysent[tcp->scno].nargs;
551 for (i = 0; i < n; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000552 if (size == sizeof(int)) {
553 unsigned int arg;
554 if (umove(tcp, addr, &arg) < 0)
555 arg = 0;
556 tcp->u_arg[i] = arg;
557 }
558 else if (size == sizeof(long)) {
559 unsigned long arg;
560 if (umove(tcp, addr, &arg) < 0)
561 arg = 0;
562 tcp->u_arg[i] = arg;
563 }
564 else
565 abort();
566 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000567 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568 break;
569 case mask_style:
570 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000571 for (i = 0; mask; i++)
572 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000573 if (i >= nsubcalls)
574 return;
575 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 tcp->scno = subcall + i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200577 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000578 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000579 case door_style:
580 /*
581 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000582 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000583 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000584 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
585 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000586 tcp->scno = subcall + tcp->u_arg[5];
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200587 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000588 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 }
590}
591#endif
592
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200593int
594printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000595{
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200596 if (entering(tcp)) {
597 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000598
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200599 for (i = 0; i < tcp->u_nargs; i++)
600 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
601 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 return 0;
603}
604
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200605long
606getrval2(struct tcb *tcp)
607{
608 long val = -1;
609
Denys Vlasenko523635f2012-02-25 02:44:25 +0100610#if defined(SPARC) || defined(SPARC64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200611 struct pt_regs regs;
612 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
613 return -1;
614 val = regs.u_regs[U_REG_O1];
615#elif defined(SH)
616 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
617 return -1;
618#elif defined(IA64)
619 if (upeek(tcp, PT_R9, &val) < 0)
620 return -1;
621#endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200622
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200623 return val;
624}
625
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200626int
627is_restart_error(struct tcb *tcp)
628{
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200629 switch (tcp->u_error) {
630 case ERESTARTSYS:
631 case ERESTARTNOINTR:
632 case ERESTARTNOHAND:
633 case ERESTART_RESTARTBLOCK:
634 return 1;
635 default:
636 break;
637 }
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200638 return 0;
639}
640
Denys Vlasenko523635f2012-02-25 02:44:25 +0100641#if defined(I386)
Denys Vlasenkob11322f2012-01-10 16:40:35 +0100642struct pt_regs i386_regs;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100643#elif defined(X86_64)
Denys Vlasenkoe73a89d2012-01-18 11:07:24 +0100644/*
645 * On 32 bits, pt_regs and user_regs_struct are the same,
646 * but on 64 bits, user_regs_struct has six more fields:
647 * fs_base, gs_base, ds, es, fs, gs.
648 * PTRACE_GETREGS fills them too, so struct pt_regs would overflow.
649 */
650static struct user_regs_struct x86_64_regs;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100651#elif defined(IA64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200652long r8, r10, psr; /* TODO: make static? */
653long ia32 = 0; /* not static */
Denys Vlasenko523635f2012-02-25 02:44:25 +0100654#elif defined(POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +0200655static long result;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100656#elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200657static long d0;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100658#elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200659static long r0;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100660#elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200661static struct pt_regs regs;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100662#elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200663static long r0;
664static long a3;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100665#elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200666static struct pt_regs regs;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100667#elif defined(SPARC) || defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200668static struct pt_regs regs;
669static unsigned long trap;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100670#elif defined(LINUX_MIPSN32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200671static long long a3;
672static long long r2;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100673#elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200674static long a3;
675static long r2;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100676#elif defined(S390) || defined(S390X)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200677static long gpr2;
678static long pc;
679static long syscall_mode;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100680#elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200681static long r28;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100682#elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200683static long r0;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100684#elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200685static long r9;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100686#elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200687static long r10;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100688#elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200689static long r3;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100690#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000691
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200692/* Returns:
693 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
694 * 1: ok, continue in trace_syscall().
695 * other: error, trace_syscall() should print error indicator
696 * ("????" etc) and bail out.
697 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200698static
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000699int
Denys Vlasenko06602d92011-08-24 17:53:52 +0200700get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000701{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000702 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000703
Denys Vlasenko523635f2012-02-25 02:44:25 +0100704#if defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000705 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200706 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000707
708 if (syscall_mode != -ENOSYS) {
709 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000710 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000711 */
712 scno = syscall_mode;
713 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000714 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000715 * Old style of "passing" the scno via the SVC instruction.
716 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000717 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200718 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200719 static const int gpr_offset[16] = {
720 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
721 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
722 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
723 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
724 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000725
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000726 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000727 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000728 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000729 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000730 if (errno) {
731 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000732 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000733 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000734
735 /*
736 * We have to check if the SVC got executed directly or via an
737 * EXECUTE instruction. In case of EXECUTE it is necessary to do
738 * instruction decoding to derive the system call number.
739 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
740 * so that this doesn't work if a SVC opcode is part of an EXECUTE
741 * opcode. Since there is no way to find out the opcode size this
742 * is the best we can do...
743 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000744 if ((opcode & 0xff00) == 0x0a00) {
745 /* SVC opcode */
746 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000747 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000748 else {
749 /* SVC got executed by EXECUTE instruction */
750
751 /*
752 * Do instruction decoding of EXECUTE. If you really want to
753 * understand this, read the Principles of Operations.
754 */
755 svc_addr = (void *) (opcode & 0xfff);
756
757 tmp = 0;
758 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000759 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000760 return -1;
761 svc_addr += tmp;
762
763 tmp = 0;
764 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000765 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000766 return -1;
767 svc_addr += tmp;
768
Denys Vlasenkofb036672009-01-23 16:30:26 +0000769 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000770 if (errno)
771 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100772# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000773 scno >>= 48;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100774# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000775 scno >>= 16;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100776# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000777 tmp = 0;
778 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000779 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000780 return -1;
781
782 scno = (scno | tmp) & 0xff;
783 }
784 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100785#elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000786 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100788# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200789 /* TODO: speed up strace by not doing this at every syscall.
790 * We only need to do it after execve.
791 */
792 int currpers;
793 long val;
794 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200795
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200796 /* Check for 64/32 bit mode. */
797 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
798 return -1;
799 /* SF is bit 0 of MSR */
800 if (val < 0)
801 currpers = 0;
802 else
803 currpers = 1;
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000804 update_personality(tcp, currpers);
Denys Vlasenko523635f2012-02-25 02:44:25 +0100805# endif
806#elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200807 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000808 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
809 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200810 scno = regs.r8;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100811#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000812 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000813 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100814#elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200815 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200817 scno = i386_regs.orig_eax;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100818#elif defined(X86_64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200819 int currpers;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200820 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
821 return -1;
822 scno = x86_64_regs.orig_rax;
Michal Ludvig0e035502002-09-23 15:41:01 +0000823
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200824 /* Check CS register value. On x86-64 linux it is:
825 * 0x33 for long mode (64 bit)
826 * 0x23 for compatibility mode (32 bit)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200827 */
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200828 switch (x86_64_regs.cs) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200829 case 0x23: currpers = 1; break;
830 case 0x33: currpers = 0; break;
831 default:
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200832 fprintf(stderr, "Unknown value CS=0x%08X while "
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200833 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200834 "PID=%d\n", (int)x86_64_regs.cs, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200835 currpers = current_personality;
836 break;
837 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100838# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200839 /* This version analyzes the opcode of a syscall instruction.
840 * (int 0x80 on i386 vs. syscall on x86-64)
841 * It works, but is too complicated.
842 */
843 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000844
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200845 rip = x86_64_regs.rip;
Roland McGrath761b5d72002-12-15 23:58:31 +0000846
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200847 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
848 rip -= 2;
849 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000850
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200851 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200852 if (errno)
853 fprintf(stderr, "ptrace_peektext failed: %s\n",
854 strerror(errno));
855 switch (call & 0xffff) {
856 /* x86-64: syscall = 0x0f 0x05 */
857 case 0x050f: currpers = 0; break;
858 /* i386: int 0x80 = 0xcd 0x80 */
859 case 0x80cd: currpers = 1; break;
860 default:
861 currpers = current_personality;
862 fprintf(stderr,
863 "Unknown syscall opcode (0x%04X) while "
864 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200865 "PID=%d\n", (int)call, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200866 break;
867 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100868# endif
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000869 update_personality(tcp, currpers);
Denys Vlasenko523635f2012-02-25 02:44:25 +0100870#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000871# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200872 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000873 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200874 if (ia32) {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200875 if (upeek(tcp, PT_R1, &scno) < 0)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200876 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000877 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200878 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000879 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200880 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100881#elif defined(ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200882 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000883 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000884 return -1;
885
886 /*
887 * We only need to grab the syscall number on syscall entry.
888 */
889 if (regs.ARM_ip == 0) {
890 /*
891 * Note: we only deal with only 32-bit CPUs here.
892 */
893 if (regs.ARM_cpsr & 0x20) {
894 /*
895 * Get the Thumb-mode system call number
896 */
897 scno = regs.ARM_r7;
898 } else {
899 /*
900 * Get the ARM-mode system call number
901 */
902 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000903 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +0000904 if (errno)
905 return -1;
906
Roland McGrathf691bd22006-04-25 07:34:41 +0000907 /* Handle the EABI syscall convention. We do not
908 bother converting structures between the two
909 ABIs, but basic functionality should work even
910 if strace and the traced program have different
911 ABIs. */
912 if (scno == 0xef000000) {
913 scno = regs.ARM_r7;
914 } else {
915 if ((scno & 0x0ff00000) != 0x0f900000) {
916 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
917 scno);
918 return -1;
919 }
Roland McGrath0f87c492003-06-03 23:29:04 +0000920
Roland McGrathf691bd22006-04-25 07:34:41 +0000921 /*
922 * Fixup the syscall number
923 */
924 scno &= 0x000fffff;
925 }
Roland McGrath0f87c492003-06-03 23:29:04 +0000926 }
Roland McGrath56703312008-05-20 01:35:55 +0000927 if (scno & 0x0f0000) {
928 /*
929 * Handle ARM specific syscall
930 */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000931 update_personality(tcp, 1);
Roland McGrath56703312008-05-20 01:35:55 +0000932 scno &= 0x0000ffff;
933 } else
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000934 update_personality(tcp, 0);
Roland McGrath0f87c492003-06-03 23:29:04 +0000935
Roland McGrath0f87c492003-06-03 23:29:04 +0000936 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200937 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
938 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000939 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100940#elif defined(M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000941 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000942 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100943#elif defined(LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +0000944 unsigned long long regs[38];
945
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200946 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +0000947 return -1;
948 a3 = regs[REG_A3];
949 r2 = regs[REG_V0];
950
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200951 scno = r2;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200952 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200953 if (a3 == 0 || a3 == -1) {
954 if (debug)
955 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +0000956 return 0;
957 }
Roland McGrath542c2c62008-05-20 01:11:56 +0000958 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100959#elif defined(MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000960 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000961 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200962 if (upeek(tcp, REG_V0, &scno) < 0)
963 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000964
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200965 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200966 if (a3 == 0 || a3 == -1) {
967 if (debug)
968 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +0000969 return 0;
970 }
Wichert Akkermanf90da011999-10-31 21:15:38 +0000971 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100972#elif defined(ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000973 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200975 if (upeek(tcp, REG_R0, &scno) < 0)
976 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200978 /*
979 * Do some sanity checks to figure out if it's
980 * really a syscall entry
981 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200982 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200983 if (a3 == 0 || a3 == -1) {
984 if (debug)
985 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 return 0;
987 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000988 }
Denys Vlasenko523635f2012-02-25 02:44:25 +0100989#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000991 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992 return -1;
993
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200994 /* Disassemble the syscall trap. */
995 /* Retrieve the syscall trap instruction. */
996 errno = 0;
Denys Vlasenko523635f2012-02-25 02:44:25 +0100997# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200998 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
999 trap >>= 32;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001000# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001001 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenko523635f2012-02-25 02:44:25 +01001002# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001003 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001004 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001005
1006 /* Disassemble the trap to see what personality to use. */
1007 switch (trap) {
1008 case 0x91d02010:
1009 /* Linux/SPARC syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001010 update_personality(tcp, 0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001011 break;
1012 case 0x91d0206d:
1013 /* Linux/SPARC64 syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001014 update_personality(tcp, 2);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001015 break;
1016 case 0x91d02000:
1017 /* SunOS syscall trap. (pers 1) */
1018 fprintf(stderr, "syscall: SunOS no support\n");
1019 return -1;
1020 case 0x91d02008:
1021 /* Solaris 2.x syscall trap. (per 2) */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001022 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001023 break;
1024 case 0x91d02009:
1025 /* NetBSD/FreeBSD syscall trap. */
1026 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1027 return -1;
1028 case 0x91d02027:
1029 /* Solaris 2.x gettimeofday */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001030 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001031 break;
1032 default:
Denys Vlasenko523635f2012-02-25 02:44:25 +01001033# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001034 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenko523635f2012-02-25 02:44:25 +01001035# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001036 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenko523635f2012-02-25 02:44:25 +01001037# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001038 return -1;
1039 }
1040
1041 /* Extract the system call number from the registers. */
1042 if (trap == 0x91d02027)
1043 scno = 156;
1044 else
1045 scno = regs.u_regs[U_REG_G1];
1046 if (scno == 0) {
1047 scno = regs.u_regs[U_REG_O0];
1048 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1049 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001050#elif defined(HPPA)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001051 if (upeek(tcp, PT_GR20, &scno) < 0)
1052 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001053#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001054 /*
1055 * In the new syscall ABI, the system call number is in R3.
1056 */
1057 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1058 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001059
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001060 if (scno < 0) {
1061 /* Odd as it may seem, a glibc bug has been known to cause
1062 glibc to issue bogus negative syscall numbers. So for
1063 our purposes, make strace print what it *should* have been */
1064 long correct_scno = (scno & 0xff);
1065 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001066 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001067 "Detected glibc bug: bogus system call"
1068 " number = %ld, correcting to %ld\n",
1069 scno,
1070 correct_scno);
1071 scno = correct_scno;
1072 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001073#elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001074 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001075 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001076 scno &= 0xFFFF;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001077#elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001078 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1079 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001080#elif defined(TILE)
Chris Metcalfc8c66982009-12-28 10:00:15 -05001081 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1082 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001083#elif defined(MICROBLAZE)
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001084 if (upeek(tcp, 0, &scno) < 0)
1085 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001086#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001087
Denys Vlasenko523635f2012-02-25 02:44:25 +01001088#if defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001089 /* new syscall ABI returns result in R0 */
1090 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1091 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001092#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001093 /* ABI defines result returned in r9 */
1094 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1095 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001096#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001097
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001098 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001099 return 1;
1100}
1101
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001102/* Called at each syscall entry.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001103 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001104 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001105 * 1: ok, continue in trace_syscall().
1106 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001107 * ("????" etc) and bail out.
1108 */
Roland McGratha4d48532005-06-08 20:45:28 +00001109static int
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001110syscall_fixup_on_sysenter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001111{
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001112 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Denys Vlasenko523635f2012-02-25 02:44:25 +01001113#if defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001114 if (i386_regs.eax != -ENOSYS) {
1115 if (debug)
1116 fprintf(stderr, "not a syscall entry (eax = %ld)\n", i386_regs.eax);
1117 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001119#elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001120 {
1121 long rax = x86_64_regs.rax;
Denys Vlasenko18beb982011-08-24 16:59:23 +02001122 if (current_personality == 1)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001123 rax = (int)rax; /* sign extend from 32 bits */
1124 if (rax != -ENOSYS) {
Denys Vlasenko18beb982011-08-24 16:59:23 +02001125 if (debug)
1126 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1127 return 0;
1128 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001129 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001130#elif defined(S390) || defined(S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001131 /* TODO: we already fetched PT_GPR2 in get_scno
1132 * and stored it in syscall_mode, reuse it here
1133 * instead of re-fetching?
1134 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001135 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001136 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001137 if (syscall_mode != -ENOSYS)
1138 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001139 if (gpr2 != syscall_mode) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001140 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001141 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001142 return 0;
1143 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001144#elif defined(M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001145 /* TODO? Eliminate upeek's in arches below like we did in x86 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001146 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001148 if (d0 != -ENOSYS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001150 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151 return 0;
1152 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001153#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001154 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001155 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001156 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001157 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001158 if (ia32 && r8 != -ENOSYS) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001159 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001160 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001161 return 0;
1162 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001163#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001164 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001165 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001166 if (r10 != -ENOSYS) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001167 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001168 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001169 return 0;
1170 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001171#elif defined(MICROBLAZE)
1172 if (upeek(tcp, 3 * 4, &r3) < 0)
1173 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001174 if (r3 != -ENOSYS) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001175 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001176 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001177 return 0;
1178 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00001180 return 1;
1181}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001183static int
1184internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001185{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001186 /*
1187 * We must always trace a few critical system calls in order to
1188 * correctly support following forks in the presence of tracing
1189 * qualifiers.
1190 */
1191 int (*func)();
1192
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001193 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001194 return 0;
1195
1196 func = sysent[tcp->scno].sys_func;
1197
1198 if ( sys_fork == func
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001199 || sys_vfork == func
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001200 || sys_clone == func
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001201 )
1202 return internal_fork(tcp);
1203
Denys Vlasenko84703742012-02-25 02:38:52 +01001204#if defined(TCB_WAITEXECVE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001205 if ( sys_execve == func
Denys Vlasenko84703742012-02-25 02:38:52 +01001206# if defined(SPARC) || defined(SPARC64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001207 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001208# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001209 )
1210 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001211#endif
1212
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001213 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001214}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001215
Roland McGratha4d48532005-06-08 20:45:28 +00001216static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001217syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001218{
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001219 int i, nargs;
1220
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001221 if (SCNO_IN_RANGE(tcp->scno))
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001222 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001223 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001224 nargs = tcp->u_nargs = MAX_ARGS;
1225
Denys Vlasenko523635f2012-02-25 02:44:25 +01001226#if defined(S390) || defined(S390X)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001227 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001228 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1229 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001230#elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001231 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001232 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1233 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001234#elif defined(IA64)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001235 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001236 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001237 long rbs_end;
1238 /* be backwards compatible with kernel < 2.4.4... */
1239# ifndef PT_RBS_END
1240# define PT_RBS_END PT_AR_BSP
1241# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001242
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001243 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1244 return -1;
1245 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001246 return -1;
1247
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001248 sof = (cfm >> 0) & 0x7f;
1249 sol = (cfm >> 7) & 0x7f;
1250 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1251
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001252 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001253 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1254 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1255 return -1;
1256 }
1257 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001258 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1259 PT_R9 /* ECX = out1 */,
1260 PT_R10 /* EDX = out2 */,
1261 PT_R14 /* ESI = out3 */,
1262 PT_R15 /* EDI = out4 */,
1263 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001264
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001265 for (i = 0; i < nargs; ++i) {
1266 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1267 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001268 /* truncate away IVE sign-extension */
1269 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001270 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001271 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001272#elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001273 /* N32 and N64 both use up to six registers. */
1274 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001275
1276 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1277 return -1;
1278
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001279 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001280 tcp->u_arg[i] = regs[REG_A0 + i];
Denys Vlasenko523635f2012-02-25 02:44:25 +01001281# if defined(LINUX_MIPSN32)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001282 tcp->ext_arg[i] = regs[REG_A0 + i];
Denys Vlasenko523635f2012-02-25 02:44:25 +01001283# endif
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001284 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001285#elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001286 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001287 long sp;
1288
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001289 if (upeek(tcp, REG_SP, &sp) < 0)
1290 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001291 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001292 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1293 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001294 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001295 (char *)(tcp->u_arg + 4));
1296 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001297 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001298 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001299 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001301#elif defined(POWERPC)
1302# ifndef PT_ORIG_R3
1303# define PT_ORIG_R3 34
1304# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001305 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001306 if (upeek(tcp, (i==0) ?
1307 (sizeof(unsigned long) * PT_ORIG_R3) :
1308 ((i+PT_R3) * sizeof(unsigned long)),
1309 &tcp->u_arg[i]) < 0)
1310 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001311 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001312#elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001313 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001314 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
Denys Vlasenko523635f2012-02-25 02:44:25 +01001315#elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001316 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001317 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1318 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001319#elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001320 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001321 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko523635f2012-02-25 02:44:25 +01001322#elif defined(AVR32)
Denys Vlasenkob5b25892011-08-30 19:04:54 +02001323 (void)i;
1324 (void)nargs;
1325 tcp->u_arg[0] = regs.r12;
1326 tcp->u_arg[1] = regs.r11;
1327 tcp->u_arg[2] = regs.r10;
1328 tcp->u_arg[3] = regs.r9;
1329 tcp->u_arg[4] = regs.r5;
1330 tcp->u_arg[5] = regs.r3;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001331#elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001332 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 +02001333
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001334 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001335 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1336 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001337#elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001338 static const int syscall_regs[MAX_ARGS] = {
1339 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1340 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001341 };
1342
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001343 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001344 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001345 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001346#elif defined(SH64)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001347 int i;
1348 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001349 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001350
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001351 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001352 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1353 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001354#elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001355 (void)i;
1356 (void)nargs;
1357 if (current_personality == 0) { /* x86-64 ABI */
1358 tcp->u_arg[0] = x86_64_regs.rdi;
1359 tcp->u_arg[1] = x86_64_regs.rsi;
1360 tcp->u_arg[2] = x86_64_regs.rdx;
1361 tcp->u_arg[3] = x86_64_regs.r10;
1362 tcp->u_arg[4] = x86_64_regs.r8;
1363 tcp->u_arg[5] = x86_64_regs.r9;
1364 } else { /* i386 ABI */
1365 /* Sign-extend lower 32 bits */
1366 tcp->u_arg[0] = (long)(int)x86_64_regs.rbx;
1367 tcp->u_arg[1] = (long)(int)x86_64_regs.rcx;
1368 tcp->u_arg[2] = (long)(int)x86_64_regs.rdx;
1369 tcp->u_arg[3] = (long)(int)x86_64_regs.rsi;
1370 tcp->u_arg[4] = (long)(int)x86_64_regs.rdi;
1371 tcp->u_arg[5] = (long)(int)x86_64_regs.rbp;
1372 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001373#elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001374 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001375 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1376 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001377#elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001378 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001379 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001380 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001381 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001382
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001383 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001384 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1385 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001386#elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001387 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001388 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1389 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001390#elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001391 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001392 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1393 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001394#elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001395 (void)i;
1396 (void)nargs;
1397 tcp->u_arg[0] = i386_regs.ebx;
1398 tcp->u_arg[1] = i386_regs.ecx;
1399 tcp->u_arg[2] = i386_regs.edx;
1400 tcp->u_arg[3] = i386_regs.esi;
1401 tcp->u_arg[4] = i386_regs.edi;
1402 tcp->u_arg[5] = i386_regs.ebp;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001403#else /* Other architecture (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001404 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001405 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1406 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001407#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00001408 return 1;
1409}
1410
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001411static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001412trace_syscall_entering(struct tcb *tcp)
1413{
1414 int res, scno_good;
1415
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001416#if defined TCB_WAITEXECVE
1417 if (tcp->flags & TCB_WAITEXECVE) {
1418 /* This is the post-execve SIGTRAP. */
1419 tcp->flags &= ~TCB_WAITEXECVE;
1420 return 0;
1421 }
1422#endif
1423
Denys Vlasenko06602d92011-08-24 17:53:52 +02001424 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001425 if (res == 0)
1426 return res;
1427 if (res == 1)
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001428 res = syscall_fixup_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001429 if (res == 0)
1430 return res;
1431 if (res == 1)
1432 res = syscall_enter(tcp);
1433 if (res == 0)
1434 return res;
1435
1436 if (res != 1) {
1437 printleader(tcp);
1438 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001439 if (scno_good != 1)
1440 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001441 else if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001442 tprintf("syscall_%lu(", tcp->scno);
1443 else
1444 tprintf("%s(", sysent[tcp->scno].sys_name);
1445 /*
1446 * " <unavailable>" will be added later by the code which
1447 * detects ptrace errors.
1448 */
1449 goto ret;
1450 }
1451
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001452#if defined(SYS_socket_subcall) || defined(SYS_ipc_subcall)
1453 while (SCNO_IN_RANGE(tcp->scno)) {
Denys Vlasenko523635f2012-02-25 02:44:25 +01001454# ifdef SYS_socket_subcall
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001455 if (sysent[tcp->scno].sys_func == sys_socketcall) {
1456 decode_subcall(tcp, SYS_socket_subcall,
1457 SYS_socket_nsubcalls, deref_style);
1458 break;
1459 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001460# endif
1461# ifdef SYS_ipc_subcall
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001462 if (sysent[tcp->scno].sys_func == sys_ipc) {
1463 decode_subcall(tcp, SYS_ipc_subcall,
1464 SYS_ipc_nsubcalls, shift_style);
1465 break;
1466 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001467# endif
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001468 break;
1469 }
1470#endif /* SYS_socket_subcall || SYS_ipc_subcall */
1471
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001472 internal_syscall(tcp);
1473
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001474 if ((SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001475 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1476 (tracing_paths && !pathtrace_match(tcp))) {
1477 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1478 return 0;
1479 }
1480
1481 tcp->flags &= ~TCB_FILTERED;
1482
1483 if (cflag == CFLAG_ONLY_STATS) {
1484 res = 0;
1485 goto ret;
1486 }
1487
1488 printleader(tcp);
1489 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001490 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001491 tprintf("syscall_%lu(", tcp->scno);
1492 else
1493 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001494 if (!SCNO_IN_RANGE(tcp->scno) ||
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001495 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1496 sysent[tcp->scno].sys_func != sys_exit))
1497 res = printargs(tcp);
1498 else
1499 res = (*sysent[tcp->scno].sys_func)(tcp);
1500
1501 if (fflush(tcp->outf) == EOF)
1502 return -1;
1503 ret:
1504 tcp->flags |= TCB_INSYSCALL;
1505 /* Measure the entrance time as late as possible to avoid errors. */
1506 if (dtime || cflag)
1507 gettimeofday(&tcp->etime, NULL);
1508 return res;
1509}
1510
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001511/* Returns:
1512 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1513 * 1: ok, continue in trace_syscall().
1514 * other: error, trace_syscall() should print error indicator
1515 * ("????" etc) and bail out.
1516 */
1517static int
1518get_syscall_result(struct tcb *tcp)
1519{
Denys Vlasenko523635f2012-02-25 02:44:25 +01001520#if defined(S390) || defined(S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001521 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
1522 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001523#elif defined(POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001524# define SO_MASK 0x10000000
1525 {
1526 long flags;
1527 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1528 return -1;
1529 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
1530 return -1;
1531 if (flags & SO_MASK)
1532 result = -result;
1533 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001534#elif defined(AVR32)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001535 /* Read complete register set in one go. */
1536 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1537 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001538#elif defined(BFIN)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001539 if (upeek(tcp, PT_R0, &r0) < 0)
1540 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001541#elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001542 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001543 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001544#elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001545 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001546 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001547#elif defined(IA64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001548# define IA64_PSR_IS ((long)1 << 34)
1549 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1550 ia32 = (psr & IA64_PSR_IS) != 0;
1551 if (upeek(tcp, PT_R8, &r8) < 0)
1552 return -1;
1553 if (upeek(tcp, PT_R10, &r10) < 0)
1554 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001555#elif defined(ARM)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001556 /* Read complete register set in one go. */
1557 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1558 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001559#elif defined(M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001560 if (upeek(tcp, 4*PT_D0, &d0) < 0)
1561 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001562#elif defined(LINUX_MIPSN32)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001563 unsigned long long regs[38];
1564
1565 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1566 return -1;
1567 a3 = regs[REG_A3];
1568 r2 = regs[REG_V0];
Denys Vlasenko523635f2012-02-25 02:44:25 +01001569#elif defined(MIPS)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001570 if (upeek(tcp, REG_A3, &a3) < 0)
1571 return -1;
1572 if (upeek(tcp, REG_V0, &r2) < 0)
1573 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001574#elif defined(ALPHA)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001575 if (upeek(tcp, REG_A3, &a3) < 0)
1576 return -1;
1577 if (upeek(tcp, REG_R0, &r0) < 0)
1578 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001579#elif defined(SPARC) || defined(SPARC64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001580 /* Everything we need is in the current register set. */
1581 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1582 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001583#elif defined(HPPA)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001584 if (upeek(tcp, PT_GR28, &r28) < 0)
1585 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001586#elif defined(SH)
1587#elif defined(SH64)
1588#elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001589 if (upeek(tcp, 4*PT_R10, &r10) < 0)
1590 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001591#elif defined(TILE)
1592#elif defined(MICROBLAZE)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001593 if (upeek(tcp, 3 * 4, &r3) < 0)
1594 return -1;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001595#endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001596
Denys Vlasenko523635f2012-02-25 02:44:25 +01001597#if defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001598 /* new syscall ABI returns result in R0 */
1599 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1600 return -1;
1601#elif defined(SH64)
1602 /* ABI defines result returned in r9 */
1603 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1604 return -1;
1605#endif
1606
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001607 return 1;
1608}
1609
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001610/* Called at each syscall exit.
1611 * Returns:
1612 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1613 * 1: ok, continue in trace_syscall().
1614 * other: error, trace_syscall() should print error indicator
1615 * ("????" etc) and bail out.
1616 */
1617static int
1618syscall_fixup_on_sysexit(struct tcb *tcp)
1619{
Denys Vlasenko523635f2012-02-25 02:44:25 +01001620#if defined(S390) || defined(S390X)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001621 if (syscall_mode != -ENOSYS)
1622 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001623 if ((tcp->flags & TCB_WAITEXECVE)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001624 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1625 /*
1626 * Return from execve.
1627 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1628 * flag set for the post-execve SIGTRAP to see and reset.
1629 */
1630 gpr2 = 0;
1631 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001632#endif
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001633 return 1;
1634}
1635
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001636/*
1637 * Check the syscall return value register value for whether it is
1638 * a negated errno code indicating an error, or a success return value.
1639 */
1640static inline int
1641is_negated_errno(unsigned long int val)
1642{
1643 unsigned long int max = -(long int) nerrnos;
Denys Vlasenko523635f2012-02-25 02:44:25 +01001644#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001645 if (personality_wordsize[current_personality] < sizeof(val)) {
1646 val = (unsigned int) val;
1647 max = (unsigned int) max;
1648 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001649#endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001650 return val > max;
1651}
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001652
1653static int
1654get_error(struct tcb *tcp)
1655{
1656 int u_error = 0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001657 int check_errno = 1;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001658 if (SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001659 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1660 check_errno = 0;
1661 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001662#if defined(S390) || defined(S390X)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001663 if (check_errno && is_negated_errno(gpr2)) {
1664 tcp->u_rval = -1;
1665 u_error = -gpr2;
1666 }
1667 else {
1668 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001669 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001670#elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001671 if (check_errno && is_negated_errno(i386_regs.eax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001672 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001673 u_error = -i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001674 }
1675 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001676 tcp->u_rval = i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001677 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001678#elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001679 if (check_errno && is_negated_errno(x86_64_regs.rax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001680 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001681 u_error = -x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001682 }
1683 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001684 tcp->u_rval = x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001685 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001686#elif defined(IA64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001687 if (ia32) {
1688 int err;
1689
1690 err = (int)r8;
1691 if (check_errno && is_negated_errno(err)) {
1692 tcp->u_rval = -1;
1693 u_error = -err;
1694 }
1695 else {
1696 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001697 }
1698 } else {
1699 if (check_errno && r10) {
1700 tcp->u_rval = -1;
1701 u_error = r8;
1702 } else {
1703 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001704 }
1705 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001706#elif defined(MIPS)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001707 if (check_errno && a3) {
1708 tcp->u_rval = -1;
1709 u_error = r2;
1710 } else {
1711 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001712 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001713#elif defined(POWERPC)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001714 if (check_errno && is_negated_errno(result)) {
1715 tcp->u_rval = -1;
1716 u_error = -result;
1717 }
1718 else {
1719 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001720 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001721#elif defined(M68K)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001722 if (check_errno && is_negated_errno(d0)) {
1723 tcp->u_rval = -1;
1724 u_error = -d0;
1725 }
1726 else {
1727 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001728 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001729#elif defined(ARM)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001730 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1731 tcp->u_rval = -1;
1732 u_error = -regs.ARM_r0;
1733 }
1734 else {
1735 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001736 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001737#elif defined(AVR32)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001738 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1739 tcp->u_rval = -1;
1740 u_error = -regs.r12;
1741 }
1742 else {
1743 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001744 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001745#elif defined(BFIN)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001746 if (check_errno && is_negated_errno(r0)) {
1747 tcp->u_rval = -1;
1748 u_error = -r0;
1749 } else {
1750 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001751 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001752#elif defined(ALPHA)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001753 if (check_errno && a3) {
1754 tcp->u_rval = -1;
1755 u_error = r0;
1756 }
1757 else {
1758 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001759 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001760#elif defined(SPARC)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001761 if (check_errno && regs.psr & PSR_C) {
1762 tcp->u_rval = -1;
1763 u_error = regs.u_regs[U_REG_O0];
1764 }
1765 else {
1766 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001767 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001768#elif defined(SPARC64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001769 if (check_errno && regs.tstate & 0x1100000000UL) {
1770 tcp->u_rval = -1;
1771 u_error = regs.u_regs[U_REG_O0];
1772 }
1773 else {
1774 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001775 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001776#elif defined(HPPA)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001777 if (check_errno && is_negated_errno(r28)) {
1778 tcp->u_rval = -1;
1779 u_error = -r28;
1780 }
1781 else {
1782 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001783 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001784#elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001785 if (check_errno && is_negated_errno(r0)) {
1786 tcp->u_rval = -1;
1787 u_error = -r0;
1788 }
1789 else {
1790 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001791 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001792#elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001793 if (check_errno && is_negated_errno(r9)) {
1794 tcp->u_rval = -1;
1795 u_error = -r9;
1796 }
1797 else {
1798 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001799 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001800#elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001801 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1802 tcp->u_rval = -1;
1803 u_error = -r10;
1804 }
1805 else {
1806 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001807 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001808#elif defined(TILE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001809 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001810 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1811 return -1;
1812 if (check_errno && rval < 0 && rval > -nerrnos) {
1813 tcp->u_rval = -1;
1814 u_error = -rval;
1815 }
1816 else {
1817 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001818 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001819#elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001820 if (check_errno && is_negated_errno(r3)) {
1821 tcp->u_rval = -1;
1822 u_error = -r3;
1823 }
1824 else {
1825 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001826 }
Denys Vlasenko523635f2012-02-25 02:44:25 +01001827#endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001828 tcp->u_error = u_error;
1829 return 1;
1830}
1831
1832static void
1833dumpio(struct tcb *tcp)
1834{
1835 if (syserror(tcp))
1836 return;
1837 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
1838 return;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001839 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001840 return;
1841 if (sysent[tcp->scno].sys_func == printargs)
1842 return;
1843 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
1844 if (sysent[tcp->scno].sys_func == sys_read ||
1845 sysent[tcp->scno].sys_func == sys_pread ||
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001846 sysent[tcp->scno].sys_func == sys_recv ||
1847 sysent[tcp->scno].sys_func == sys_recvfrom)
1848 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
1849 else if (sysent[tcp->scno].sys_func == sys_readv)
1850 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
1851 return;
1852 }
1853 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
1854 if (sysent[tcp->scno].sys_func == sys_write ||
1855 sysent[tcp->scno].sys_func == sys_pwrite ||
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001856 sysent[tcp->scno].sys_func == sys_send ||
1857 sysent[tcp->scno].sys_func == sys_sendto)
1858 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
1859 else if (sysent[tcp->scno].sys_func == sys_writev)
1860 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
1861 return;
1862 }
1863}
1864
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001865static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001866trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001867{
1868 int sys_res;
1869 struct timeval tv;
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02001870 int res;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001871 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001872
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001873 /* Measure the exit time as early as possible to avoid errors. */
1874 if (dtime || cflag)
1875 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001876
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001877#if SUPPORTED_PERSONALITIES > 1
1878 update_personality(tcp, tcp->currpers);
1879#endif
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02001880 res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001881 if (res == 0)
1882 return res;
1883 if (res == 1)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001884 res = syscall_fixup_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001885 if (res == 0)
1886 return res;
1887 if (res == 1)
1888 res = get_error(tcp);
1889 if (res == 0)
1890 return res;
1891 if (res == 1)
1892 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001893
Grant Edwards8a082772011-04-07 20:25:40 +00001894 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02001895 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001896 }
1897
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001898 if (tcp->flags & TCB_REPRINT) {
1899 printleader(tcp);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001900 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02001901 tprintf("<... syscall_%lu resumed> ", tcp->scno);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001902 else
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02001903 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001904 }
1905
1906 if (cflag) {
1907 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02001908 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02001909 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02001910 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001911 }
1912 }
1913
1914 if (res != 1) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001915 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02001916 tabto();
Denys Vlasenko000b6012012-01-28 01:25:03 +01001917 tprints("= ? <unavailable>\n");
1918 printing_tcp = NULL;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001919 tcp->flags &= ~TCB_INSYSCALL;
1920 return res;
1921 }
1922
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001923 if (!SCNO_IN_RANGE(tcp->scno)
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001924 || (qual_flags[tcp->scno] & QUAL_RAW))
1925 sys_res = printargs(tcp);
1926 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02001927 /* FIXME: not_failing_only (IOW, option -z) is broken:
1928 * failure of syscall is known only after syscall return.
1929 * Thus we end up with something like this on, say, ENOENT:
1930 * open("doesnt_exist", O_RDONLY <unfinished ...>
1931 * {next syscall decode}
1932 * whereas the intended result is that open(...) line
1933 * is not shown at all.
1934 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001935 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02001936 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001937 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
1938 }
1939
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001940 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02001941 tabto();
Denys Vlasenko3b738812011-08-22 02:06:35 +02001942 u_error = tcp->u_error;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001943 if (!SCNO_IN_RANGE(tcp->scno) ||
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001944 qual_flags[tcp->scno] & QUAL_RAW) {
1945 if (u_error)
1946 tprintf("= -1 (errno %ld)", u_error);
1947 else
1948 tprintf("= %#lx", tcp->u_rval);
1949 }
1950 else if (!(sys_res & RVAL_NONE) && u_error) {
1951 switch (u_error) {
Denys Vlasenkofe585652012-01-12 11:26:34 +01001952 /* Blocked signals do not interrupt any syscalls.
1953 * In this case syscalls don't return ERESTARTfoo codes.
1954 *
1955 * Deadly signals set to SIG_DFL interrupt syscalls
1956 * and kill the process regardless of which of the codes below
1957 * is returned by the interrupted syscall.
1958 * In some cases, kernel forces a kernel-generated deadly
1959 * signal to be unblocked and set to SIG_DFL (and thus cause
1960 * death) if it is blocked or SIG_IGNed: for example, SIGSEGV
1961 * or SIGILL. (The alternative is to leave process spinning
1962 * forever on the faulty instruction - not useful).
1963 *
1964 * SIG_IGNed signals and non-deadly signals set to SIG_DFL
1965 * (for example, SIGCHLD, SIGWINCH) interrupt syscalls,
1966 * but kernel will always restart them.
1967 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001968 case ERESTARTSYS:
Denys Vlasenkofe585652012-01-12 11:26:34 +01001969 /* Most common type of signal-interrupted syscall exit code.
1970 * The system call will be restarted with the same arguments
1971 * if SA_RESTART is set; otherwise, it will fail with EINTR.
1972 */
1973 tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001974 break;
1975 case ERESTARTNOINTR:
Denys Vlasenkofe585652012-01-12 11:26:34 +01001976 /* Rare. For example, fork() returns this if interrupted.
1977 * SA_RESTART is ignored (assumed set): the restart is unconditional.
1978 */
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001979 tprints("= ? ERESTARTNOINTR (To be restarted)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001980 break;
1981 case ERESTARTNOHAND:
Denys Vlasenkofe585652012-01-12 11:26:34 +01001982 /* pause(), rt_sigsuspend() etc use this code.
1983 * SA_RESTART is ignored (assumed not set):
1984 * syscall won't restart (will return EINTR instead)
1985 * even after signal with SA_RESTART set.
1986 * However, after SIG_IGN or SIG_DFL signal it will.
1987 */
1988 tprints("= ? ERESTARTNOHAND (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001989 break;
1990 case ERESTART_RESTARTBLOCK:
Denys Vlasenkofe585652012-01-12 11:26:34 +01001991 /* Syscalls like nanosleep(), poll() which can't be
1992 * restarted with their original arguments use this
1993 * code. Kernel will execute restart_syscall() instead,
1994 * which changes arguments before restarting syscall.
1995 * SA_RESTART is ignored (assumed not set) similarly
1996 * to ERESTARTNOHAND. (Kernel can't honor SA_RESTART
1997 * since restart data is saved in "restart block"
1998 * in task struct, and if signal handler uses a syscall
1999 * which in turn saves another such restart block,
2000 * old data is lost and restart becomes impossible)
2001 */
2002 tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002003 break;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002004 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002005 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002006 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002007 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002008 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002009 strerror(u_error));
2010 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002011 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002012 strerror(u_error));
2013 break;
2014 }
2015 if ((sys_res & RVAL_STR) && tcp->auxstr)
2016 tprintf(" (%s)", tcp->auxstr);
2017 }
2018 else {
2019 if (sys_res & RVAL_NONE)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002020 tprints("= ?");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002021 else {
2022 switch (sys_res & RVAL_MASK) {
2023 case RVAL_HEX:
2024 tprintf("= %#lx", tcp->u_rval);
2025 break;
2026 case RVAL_OCTAL:
2027 tprintf("= %#lo", tcp->u_rval);
2028 break;
2029 case RVAL_UDECIMAL:
2030 tprintf("= %lu", tcp->u_rval);
2031 break;
2032 case RVAL_DECIMAL:
2033 tprintf("= %ld", tcp->u_rval);
2034 break;
2035#ifdef HAVE_LONG_LONG
2036 case RVAL_LHEX:
2037 tprintf("= %#llx", tcp->u_lrval);
2038 break;
2039 case RVAL_LOCTAL:
2040 tprintf("= %#llo", tcp->u_lrval);
2041 break;
2042 case RVAL_LUDECIMAL:
2043 tprintf("= %llu", tcp->u_lrval);
2044 break;
2045 case RVAL_LDECIMAL:
2046 tprintf("= %lld", tcp->u_lrval);
2047 break;
2048#endif
2049 default:
2050 fprintf(stderr,
2051 "invalid rval format\n");
2052 break;
2053 }
2054 }
2055 if ((sys_res & RVAL_STR) && tcp->auxstr)
2056 tprintf(" (%s)", tcp->auxstr);
2057 }
2058 if (dtime) {
2059 tv_sub(&tv, &tv, &tcp->etime);
2060 tprintf(" <%ld.%06ld>",
2061 (long) tv.tv_sec, (long) tv.tv_usec);
2062 }
Denys Vlasenko000b6012012-01-28 01:25:03 +01002063 tprints("\n");
2064 printing_tcp = NULL;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002065
2066 dumpio(tcp);
2067 if (fflush(tcp->outf) == EOF)
2068 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002069 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002070 tcp->flags &= ~TCB_INSYSCALL;
2071 return 0;
2072}
2073
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002074int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002075trace_syscall(struct tcb *tcp)
2076{
2077 return exiting(tcp) ?
2078 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2079}