blob: bbd2e583afc11ba705f35c7c4b41db237c8a02a7 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
38#include <signal.h>
39#include <time.h>
40#include <errno.h>
41#include <sys/user.h>
42#include <sys/syscall.h>
43#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044
Wichert Akkerman15dea971999-10-06 13:06:34 +000045#ifdef HAVE_SYS_REG_H
Roland McGratheb9e2e82009-06-02 16:49:22 -070046#include <sys/reg.h>
47#ifndef PTRACE_PEEKUSR
48# define PTRACE_PEEKUSR PTRACE_PEEKUSER
49#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000050#elif defined(HAVE_LINUX_PTRACE_H)
Roland McGratheb9e2e82009-06-02 16:49:22 -070051#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000052# ifdef HAVE_STRUCT_IA64_FPREG
53# define ia64_fpreg XXX_ia64_fpreg
54# endif
55# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
56# define pt_all_user_regs XXX_pt_all_user_regs
57# endif
Roland McGratheb9e2e82009-06-02 16:49:22 -070058#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000059# undef ia64_fpreg
60# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000061#endif
62
Roland McGrath6d1a65c2004-07-12 07:44:08 +000063#if defined (LINUX) && defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000064# undef PTRACE_GETREGS
65# define PTRACE_GETREGS PTRACE_GETREGS64
66# undef PTRACE_SETREGS
67# define PTRACE_SETREGS PTRACE_SETREGS64
68#endif /* LINUX && SPARC64 */
69
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000070#if defined(LINUX) && defined(IA64)
71# include <asm/ptrace_offsets.h>
72# include <asm/rse.h>
73#endif
74
Pavel Machekd8ae7e32000-02-01 17:17:25 +000075#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000076#ifdef LINUX
77#ifndef ERESTARTSYS
78#define ERESTARTSYS 512
79#endif
80#ifndef ERESTARTNOINTR
81#define ERESTARTNOINTR 513
82#endif
83#ifndef ERESTARTNOHAND
84#define ERESTARTNOHAND 514 /* restart if no handler.. */
85#endif
86#ifndef ENOIOCTLCMD
87#define ENOIOCTLCMD 515 /* No ioctl command */
88#endif
Roland McGrath9c555e72003-07-09 09:47:59 +000089#ifndef ERESTART_RESTARTBLOCK
90#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
91#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092#ifndef NSIG
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020093#warning: NSIG is not defined, using 32
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000094#define NSIG 32
95#endif
96#ifdef ARM
Denys Vlasenko041b3ee2011-08-18 12:48:56 +020097/* Ugh. Is this really correct? ARM has no RT signals?! */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098#undef NSIG
99#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000100#undef NR_SYSCALL_BASE
101#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102#endif
103#endif /* LINUX */
104
105#include "syscall.h"
106
107/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000108#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000109#define TF TRACE_FILE
110#define TI TRACE_IPC
111#define TN TRACE_NETWORK
112#define TP TRACE_PROCESS
113#define TS TRACE_SIGNAL
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000114#define NF SYSCALL_NEVER_FAILS
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200115#define MA MAX_ARGS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116
Roland McGrathee36ce12004-09-04 03:53:10 +0000117static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118#include "syscallent.h"
119};
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120
121#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000122static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123#include "syscallent1.h"
124};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200125#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126
127#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent2.h"
130};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200131#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000132
133/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000134#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000135#undef TF
136#undef TI
137#undef TN
138#undef TP
139#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000140#undef NF
Denys Vlasenkoac1ce772011-08-23 13:24:17 +0200141#undef MA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142
Denys Vlasenko39fca622011-08-20 02:12:33 +0200143
144/*
145 * `ioctlent.h' may be generated from `ioctlent.raw' by the auxiliary
146 * program `ioctlsort', such that the list is sorted by the `code' field.
147 * This has the side-effect of resolving the _IO.. macros into
148 * plain integers, eliminating the need to include here everything
149 * in "/usr/include".
150 */
151
152
Roland McGrathee36ce12004-09-04 03:53:10 +0000153static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000154#include "errnoent.h"
155};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200156static const char *const signalent0[] = {
157#include "signalent.h"
158};
159static const struct ioctlent ioctlent0[] = {
160#include "ioctlent.h"
161};
162enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
163enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
164enum { nsignals0 = ARRAY_SIZE(signalent0) };
165enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
166int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167
168#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000169static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000170#include "errnoent1.h"
171};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200172static const char *const signalent1[] = {
173#include "signalent1.h"
174};
175static const struct ioctlent ioctlent1[] = {
176#include "ioctlent1.h"
177};
178enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
179enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
180enum { nsignals1 = ARRAY_SIZE(signalent1) };
181enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
182int qual_flags1[MAX_QUALS];
183#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184
185#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000186static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000187#include "errnoent2.h"
188};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200189static const char *const signalent2[] = {
190#include "signalent2.h"
191};
192static const struct ioctlent ioctlent2[] = {
193#include "ioctlent2.h"
194};
195enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
196enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
197enum { nsignals2 = ARRAY_SIZE(signalent2) };
198enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
199int qual_flags2[MAX_QUALS];
200#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201
Denys Vlasenko39fca622011-08-20 02:12:33 +0200202
203const struct sysent *sysent;
Roland McGrathee36ce12004-09-04 03:53:10 +0000204const char *const *errnoent;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200205const char *const *signalent;
206const struct ioctlent *ioctlent;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200207unsigned nsyscalls;
208unsigned nerrnos;
209unsigned nsignals;
210unsigned nioctlents;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200211int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000212
213int current_personality;
214
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000215#ifndef PERSONALITY0_WORDSIZE
216# define PERSONALITY0_WORDSIZE sizeof(long)
217#endif
218const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
219 PERSONALITY0_WORDSIZE,
220#if SUPPORTED_PERSONALITIES > 1
221 PERSONALITY1_WORDSIZE,
222#endif
223#if SUPPORTED_PERSONALITIES > 2
224 PERSONALITY2_WORDSIZE,
225#endif
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200226};
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000227
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200228void
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000229set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000230{
231 switch (personality) {
232 case 0:
233 errnoent = errnoent0;
234 nerrnos = nerrnos0;
235 sysent = sysent0;
236 nsyscalls = nsyscalls0;
237 ioctlent = ioctlent0;
238 nioctlents = nioctlents0;
239 signalent = signalent0;
240 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000241 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000242 break;
243
244#if SUPPORTED_PERSONALITIES >= 2
245 case 1:
246 errnoent = errnoent1;
247 nerrnos = nerrnos1;
248 sysent = sysent1;
249 nsyscalls = nsyscalls1;
250 ioctlent = ioctlent1;
251 nioctlents = nioctlents1;
252 signalent = signalent1;
253 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000254 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200256#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000257
258#if SUPPORTED_PERSONALITIES >= 3
259 case 2:
260 errnoent = errnoent2;
261 nerrnos = nerrnos2;
262 sysent = sysent2;
263 nsyscalls = nsyscalls2;
264 ioctlent = ioctlent2;
265 nioctlents = nioctlents2;
266 signalent = signalent2;
267 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000268 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000269 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200270#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000271 }
272
273 current_personality = personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000274}
275
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000276#if SUPPORTED_PERSONALITIES > 1
277static void
278update_personality(struct tcb *tcp, int personality)
279{
280 if (personality == current_personality)
281 return;
282 set_personality(personality);
283
284 if (personality == tcp->currpers)
285 return;
286 tcp->currpers = personality;
287
288#if defined(POWERPC64) || defined(X86_64)
289 if (!qflag) {
290 static const char *const names[] = {"64 bit", "32 bit"};
291 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
292 tcp->pid, names[personality]);
293 }
294#endif
295}
296#endif
Roland McGrathe10e62a2004-09-04 04:20:43 +0000297
Roland McGrath9797ceb2002-12-30 10:23:00 +0000298static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299
Roland McGrathe10e62a2004-09-04 04:20:43 +0000300static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000301 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000302 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000303 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000304 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000305} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000306 { QUAL_TRACE, "trace", qual_syscall, "system call" },
307 { QUAL_TRACE, "t", qual_syscall, "system call" },
308 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
309 { QUAL_ABBREV, "a", qual_syscall, "system call" },
310 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
311 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
312 { QUAL_RAW, "raw", qual_syscall, "system call" },
313 { QUAL_RAW, "x", qual_syscall, "system call" },
314 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
315 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
316 { QUAL_SIGNAL, "s", qual_signal, "signal" },
317 { QUAL_FAULT, "fault", qual_fault, "fault" },
318 { QUAL_FAULT, "faults", qual_fault, "fault" },
319 { QUAL_FAULT, "m", qual_fault, "fault" },
320 { QUAL_READ, "read", qual_desc, "descriptor" },
321 { QUAL_READ, "reads", qual_desc, "descriptor" },
322 { QUAL_READ, "r", qual_desc, "descriptor" },
323 { QUAL_WRITE, "write", qual_desc, "descriptor" },
324 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
325 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000326 { 0, NULL, NULL, NULL },
327};
328
Roland McGrath9797ceb2002-12-30 10:23:00 +0000329static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000330qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000331{
Roland McGrath138c6a32006-01-12 09:50:49 +0000332 if (pers == 0 || pers < 0) {
333 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000334 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000335 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000336 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000337 }
338
339#if SUPPORTED_PERSONALITIES >= 2
340 if (pers == 1 || pers < 0) {
341 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000342 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000343 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000344 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000345 }
346#endif /* SUPPORTED_PERSONALITIES >= 2 */
347
348#if SUPPORTED_PERSONALITIES >= 3
349 if (pers == 2 || pers < 0) {
350 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000351 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000352 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000353 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000354 }
355#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000356}
357
358static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000359qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000360{
361 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000362 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000363
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000364 if (isdigit((unsigned char)*s)) {
365 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000366 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000367 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000368 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000369 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000370 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000371 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000372 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000373 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000374 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000375 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000376
377#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000378 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000379 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000380 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000381 rc = 0;
382 }
383#endif /* SUPPORTED_PERSONALITIES >= 2 */
384
385#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000386 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000387 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000388 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000389 rc = 0;
390 }
391#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000392
Roland McGrathfe6b3522005-02-02 04:40:11 +0000393 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000394}
395
396static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000397qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000398{
399 int i;
400 char buf[32];
401
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000402 if (isdigit((unsigned char)*s)) {
403 int signo = atoi(s);
404 if (signo < 0 || signo >= MAX_QUALS)
405 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000406 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000407 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000408 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000409 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000410 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000411 strcpy(buf, s);
412 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000413 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000414 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000415 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000416 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000417 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000418 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000419 }
Roland McGrath76421df2005-02-02 03:51:18 +0000420 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000421}
422
423static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000424qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000425{
426 return -1;
427}
428
429static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000430qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000431{
Roland McGrath48a035f2006-01-12 09:45:56 +0000432 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000433 int desc = atoi(s);
434 if (desc < 0 || desc >= MAX_QUALS)
435 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000436 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000437 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 }
439 return -1;
440}
441
442static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000443lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000444{
445 if (strcmp(s, "file") == 0)
446 return TRACE_FILE;
447 if (strcmp(s, "ipc") == 0)
448 return TRACE_IPC;
449 if (strcmp(s, "network") == 0)
450 return TRACE_NETWORK;
451 if (strcmp(s, "process") == 0)
452 return TRACE_PROCESS;
453 if (strcmp(s, "signal") == 0)
454 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000455 if (strcmp(s, "desc") == 0)
456 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000457 return -1;
458}
459
460void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000461qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000462{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000463 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000465 char *copy;
466 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 int i, n;
468
469 opt = &qual_options[0];
470 for (i = 0; (p = qual_options[i].option_name); i++) {
471 n = strlen(p);
472 if (strncmp(s, p, n) == 0 && s[n] == '=') {
473 opt = &qual_options[i];
474 s += n + 1;
475 break;
476 }
477 }
478 not = 0;
479 if (*s == '!') {
480 not = 1;
481 s++;
482 }
483 if (strcmp(s, "none") == 0) {
484 not = 1 - not;
485 s = "all";
486 }
487 if (strcmp(s, "all") == 0) {
488 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000489 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 }
491 return;
492 }
493 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000494 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000495 }
Denys Vlasenko5d645812011-08-20 12:48:18 +0200496 copy = strdup(s);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200497 if (!copy)
498 die_out_of_memory();
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000499 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000500 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000501 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000502 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000503 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000504
505#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000506 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000507 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000508 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000509#endif /* SUPPORTED_PERSONALITIES >= 2 */
510
511#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000512 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000513 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000514 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000515#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000516
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000517 continue;
518 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000519 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000520 fprintf(stderr, "strace: invalid %s `%s'\n",
521 opt->argument_name, p);
522 exit(1);
523 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000524 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000525 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000526 return;
527}
528
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000529#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000530enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000531#else /* FREEBSD */
532enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
533
534struct subcall {
535 int call;
536 int nsubcalls;
537 int subcalls[5];
538};
539
Roland McGratha4d48532005-06-08 20:45:28 +0000540static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000541 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000542#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000543 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000544#else
545 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
546#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000547 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
548};
549#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000550
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000551#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000552
Roland McGratha4d48532005-06-08 20:45:28 +0000553static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200554decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000555{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000556 unsigned long addr, mask;
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200557 int i, n;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000558 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000559
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560 switch (style) {
561 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000562 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
563 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000564 tcp->scno = subcall + tcp->u_arg[0];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200565 tcp->u_nargs = n = sysent[tcp->scno].nargs;
566 for (i = 0; i < n; i++)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000567 tcp->u_arg[i] = tcp->u_arg[i + 1];
568 break;
569 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000570 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
571 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572 tcp->scno = subcall + tcp->u_arg[0];
573 addr = tcp->u_arg[1];
Denys Vlasenko4b887a52011-08-23 13:32:38 +0200574 tcp->u_nargs = n = sysent[tcp->scno].nargs;
575 for (i = 0; i < n; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000576 if (size == sizeof(int)) {
577 unsigned int arg;
578 if (umove(tcp, addr, &arg) < 0)
579 arg = 0;
580 tcp->u_arg[i] = arg;
581 }
582 else if (size == sizeof(long)) {
583 unsigned long arg;
584 if (umove(tcp, addr, &arg) < 0)
585 arg = 0;
586 tcp->u_arg[i] = arg;
587 }
588 else
589 abort();
590 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000591 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000592 break;
593 case mask_style:
594 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000595 for (i = 0; mask; i++)
596 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000597 if (i >= nsubcalls)
598 return;
599 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600 tcp->scno = subcall + i;
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200601 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000603 case door_style:
604 /*
605 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000606 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000607 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000608 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
609 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000610 tcp->scno = subcall + tcp->u_arg[5];
Denys Vlasenkoafc64032011-08-23 13:29:01 +0200611 tcp->u_nargs = sysent[tcp->scno].nargs;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000612 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000613#ifdef FREEBSD
614 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000615 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000616 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000617 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000618 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
619 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
620 for (i = 0; i < tcp->u_nargs; i++)
621 tcp->u_arg[i] = tcp->u_arg[i + 1];
622 }
623 break;
624#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000625 }
626}
627#endif
628
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200629int
630printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631{
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200632 if (entering(tcp)) {
633 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000634
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200635 for (i = 0; i < tcp->u_nargs; i++)
636 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
637 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000638 return 0;
639}
640
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200641long
642getrval2(struct tcb *tcp)
643{
644 long val = -1;
645
646#ifdef LINUX
647#if defined (SPARC) || defined (SPARC64)
648 struct pt_regs regs;
649 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
650 return -1;
651 val = regs.u_regs[U_REG_O1];
652#elif defined(SH)
653 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
654 return -1;
655#elif defined(IA64)
656 if (upeek(tcp, PT_R9, &val) < 0)
657 return -1;
658#endif
659#endif /* LINUX */
660
661#ifdef SUNOS4
662 if (upeek(tcp, uoff(u_rval2), &val) < 0)
663 return -1;
664#endif /* SUNOS4 */
665
666#ifdef SVR4
667#ifdef SPARC
668 val = tcp->status.PR_REG[R_O1];
669#endif /* SPARC */
670#ifdef I386
671 val = tcp->status.PR_REG[EDX];
672#endif /* I386 */
673#ifdef X86_64
674 val = tcp->status.PR_REG[RDX];
675#endif /* X86_64 */
676#ifdef MIPS
677 val = tcp->status.PR_REG[CTX_V1];
678#endif /* MIPS */
679#endif /* SVR4 */
680
681#ifdef FREEBSD
682 struct reg regs;
683 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
684 val = regs.r_edx;
685#endif
686 return val;
687}
688
689#ifdef SUNOS4
690/*
691 * Apparently, indirect system calls have already be converted by ptrace(2),
692 * so if you see "indir" this program has gone astray.
693 */
694int
695sys_indir(struct tcb *tcp)
696{
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200697 int i, nargs;
698 long scno;
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200699
700 if (entering(tcp)) {
701 scno = tcp->u_arg[0];
Denys Vlasenkocb6f0562011-08-25 01:13:43 +0200702 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenkofabaa912011-08-25 01:23:10 +0200703 fprintf(stderr, "Bogus syscall: %ld\n", scno);
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200704 return 0;
705 }
706 nargs = sysent[scno].nargs;
Denys Vlasenko5940e652011-09-01 09:55:05 +0200707 tprints(sysent[scno].sys_name);
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200708 for (i = 0; i < nargs; i++)
709 tprintf(", %#lx", tcp->u_arg[i+1]);
710 }
711 return 0;
712}
713#endif /* SUNOS4 */
714
715int
716is_restart_error(struct tcb *tcp)
717{
718#ifdef LINUX
Denys Vlasenkoa6146922011-08-24 18:07:22 +0200719 switch (tcp->u_error) {
720 case ERESTARTSYS:
721 case ERESTARTNOINTR:
722 case ERESTARTNOHAND:
723 case ERESTART_RESTARTBLOCK:
724 return 1;
725 default:
726 break;
727 }
728#endif /* LINUX */
729 return 0;
730}
731
Wichert Akkermanc7926982000-04-10 22:22:31 +0000732#ifdef LINUX
Denys Vlasenkob11322f2012-01-10 16:40:35 +0100733# if defined(I386)
734struct pt_regs i386_regs;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200735# elif defined(X86_64)
Denys Vlasenkoe73a89d2012-01-18 11:07:24 +0100736/*
737 * On 32 bits, pt_regs and user_regs_struct are the same,
738 * but on 64 bits, user_regs_struct has six more fields:
739 * fs_base, gs_base, ds, es, fs, gs.
740 * PTRACE_GETREGS fills them too, so struct pt_regs would overflow.
741 */
742static struct user_regs_struct x86_64_regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200743# elif defined (IA64)
744long r8, r10, psr; /* TODO: make static? */
745long ia32 = 0; /* not static */
746# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +0200747static long result;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200748# elif defined (M68K)
749static long d0;
750# elif defined(BFIN)
751static long r0;
752# elif defined (ARM)
753static struct pt_regs regs;
754# elif defined (ALPHA)
755static long r0;
756static long a3;
757# elif defined(AVR32)
758static struct pt_regs regs;
759# elif defined (SPARC) || defined (SPARC64)
760static struct pt_regs regs;
761static unsigned long trap;
762# elif defined(LINUX_MIPSN32)
763static long long a3;
764static long long r2;
765# elif defined(MIPS)
766static long a3;
767static long r2;
768# elif defined(S390) || defined(S390X)
769static long gpr2;
770static long pc;
771static long syscall_mode;
772# elif defined(HPPA)
773static long r28;
774# elif defined(SH)
775static long r0;
776# elif defined(SH64)
777static long r9;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200778# elif defined(CRISV10) || defined(CRISV32)
779static long r10;
780# elif defined(MICROBLAZE)
781static long r3;
782# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000783#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000784#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200785struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000786#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000787
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200788/* Returns:
789 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
790 * 1: ok, continue in trace_syscall().
791 * other: error, trace_syscall() should print error indicator
792 * ("????" etc) and bail out.
793 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200794#ifndef USE_PROCFS
795static
796#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000797int
Denys Vlasenko06602d92011-08-24 17:53:52 +0200798get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000800 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000801
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000802#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000803# if defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000804 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200805 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000806
807 if (syscall_mode != -ENOSYS) {
808 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000809 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000810 */
811 scno = syscall_mode;
812 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000813 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000814 * Old style of "passing" the scno via the SVC instruction.
815 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000816 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200817 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200818 static const int gpr_offset[16] = {
819 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
820 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
821 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
822 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
823 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000824
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000825 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000826 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000827 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000828 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000829 if (errno) {
830 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000831 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000832 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000833
834 /*
835 * We have to check if the SVC got executed directly or via an
836 * EXECUTE instruction. In case of EXECUTE it is necessary to do
837 * instruction decoding to derive the system call number.
838 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
839 * so that this doesn't work if a SVC opcode is part of an EXECUTE
840 * opcode. Since there is no way to find out the opcode size this
841 * is the best we can do...
842 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000843 if ((opcode & 0xff00) == 0x0a00) {
844 /* SVC opcode */
845 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000846 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000847 else {
848 /* SVC got executed by EXECUTE instruction */
849
850 /*
851 * Do instruction decoding of EXECUTE. If you really want to
852 * understand this, read the Principles of Operations.
853 */
854 svc_addr = (void *) (opcode & 0xfff);
855
856 tmp = 0;
857 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000858 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000859 return -1;
860 svc_addr += tmp;
861
862 tmp = 0;
863 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000864 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000865 return -1;
866 svc_addr += tmp;
867
Denys Vlasenkofb036672009-01-23 16:30:26 +0000868 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000869 if (errno)
870 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000871# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000872 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000873# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000874 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000875# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000876 tmp = 0;
877 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000878 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000879 return -1;
880
881 scno = (scno | tmp) & 0xff;
882 }
883 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000884# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000885 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000886 return -1;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200887# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200888 /* TODO: speed up strace by not doing this at every syscall.
889 * We only need to do it after execve.
890 */
891 int currpers;
892 long val;
893 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200894
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200895 /* Check for 64/32 bit mode. */
896 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
897 return -1;
898 /* SF is bit 0 of MSR */
899 if (val < 0)
900 currpers = 0;
901 else
902 currpers = 1;
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000903 update_personality(tcp, currpers);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200904# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000905# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200906 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000907 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
908 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200909 scno = regs.r8;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000910# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000911 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000912 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000913# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200914 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000915 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200916 scno = i386_regs.orig_eax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000917# elif defined (X86_64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200918 int currpers;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200919 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
920 return -1;
921 scno = x86_64_regs.orig_rax;
Michal Ludvig0e035502002-09-23 15:41:01 +0000922
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200923 /* Check CS register value. On x86-64 linux it is:
924 * 0x33 for long mode (64 bit)
925 * 0x23 for compatibility mode (32 bit)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200926 */
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200927 switch (x86_64_regs.cs) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200928 case 0x23: currpers = 1; break;
929 case 0x33: currpers = 0; break;
930 default:
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200931 fprintf(stderr, "Unknown value CS=0x%08X while "
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200932 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200933 "PID=%d\n", (int)x86_64_regs.cs, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200934 currpers = current_personality;
935 break;
936 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000937# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200938 /* This version analyzes the opcode of a syscall instruction.
939 * (int 0x80 on i386 vs. syscall on x86-64)
940 * It works, but is too complicated.
941 */
942 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000943
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200944 rip = x86_64_regs.rip;
Roland McGrath761b5d72002-12-15 23:58:31 +0000945
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200946 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
947 rip -= 2;
948 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000949
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200950 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200951 if (errno)
952 fprintf(stderr, "ptrace_peektext failed: %s\n",
953 strerror(errno));
954 switch (call & 0xffff) {
955 /* x86-64: syscall = 0x0f 0x05 */
956 case 0x050f: currpers = 0; break;
957 /* i386: int 0x80 = 0xcd 0x80 */
958 case 0x80cd: currpers = 1; break;
959 default:
960 currpers = current_personality;
961 fprintf(stderr,
962 "Unknown syscall opcode (0x%04X) while "
963 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200964 "PID=%d\n", (int)call, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200965 break;
966 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000967# endif
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000968 update_personality(tcp, currpers);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000969# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000970# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200971 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000972 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200973 if (ia32) {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200974 if (upeek(tcp, PT_R1, &scno) < 0)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200975 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000976 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200977 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000978 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200979 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000980# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200981 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000982 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000983 return -1;
984
985 /*
986 * We only need to grab the syscall number on syscall entry.
987 */
988 if (regs.ARM_ip == 0) {
989 /*
990 * Note: we only deal with only 32-bit CPUs here.
991 */
992 if (regs.ARM_cpsr & 0x20) {
993 /*
994 * Get the Thumb-mode system call number
995 */
996 scno = regs.ARM_r7;
997 } else {
998 /*
999 * Get the ARM-mode system call number
1000 */
1001 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001002 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001003 if (errno)
1004 return -1;
1005
Roland McGrathf691bd22006-04-25 07:34:41 +00001006 /* Handle the EABI syscall convention. We do not
1007 bother converting structures between the two
1008 ABIs, but basic functionality should work even
1009 if strace and the traced program have different
1010 ABIs. */
1011 if (scno == 0xef000000) {
1012 scno = regs.ARM_r7;
1013 } else {
1014 if ((scno & 0x0ff00000) != 0x0f900000) {
1015 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1016 scno);
1017 return -1;
1018 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001019
Roland McGrathf691bd22006-04-25 07:34:41 +00001020 /*
1021 * Fixup the syscall number
1022 */
1023 scno &= 0x000fffff;
1024 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001025 }
Roland McGrath56703312008-05-20 01:35:55 +00001026 if (scno & 0x0f0000) {
1027 /*
1028 * Handle ARM specific syscall
1029 */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001030 update_personality(tcp, 1);
Roland McGrath56703312008-05-20 01:35:55 +00001031 scno &= 0x0000ffff;
1032 } else
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001033 update_personality(tcp, 0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001034
Roland McGrath0f87c492003-06-03 23:29:04 +00001035 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001036 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1037 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001039# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001040 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001042# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001043 unsigned long long regs[38];
1044
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001045 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001046 return -1;
1047 a3 = regs[REG_A3];
1048 r2 = regs[REG_V0];
1049
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001050 scno = r2;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001051 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001052 if (a3 == 0 || a3 == -1) {
1053 if (debug)
1054 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001055 return 0;
1056 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001057 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001058# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001059 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001060 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001061 if (upeek(tcp, REG_V0, &scno) < 0)
1062 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001063
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001064 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001065 if (a3 == 0 || a3 == -1) {
1066 if (debug)
1067 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001068 return 0;
1069 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001070 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001071# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001072 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001074 if (upeek(tcp, REG_R0, &scno) < 0)
1075 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001077 /*
1078 * Do some sanity checks to figure out if it's
1079 * really a syscall entry
1080 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001081 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001082 if (a3 == 0 || a3 == -1) {
1083 if (debug)
1084 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 return 0;
1086 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001088# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001090 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091 return -1;
1092
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001093 /* Disassemble the syscall trap. */
1094 /* Retrieve the syscall trap instruction. */
1095 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001096# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001097 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1098 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001099# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001100 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001101# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001102 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001103 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001104
1105 /* Disassemble the trap to see what personality to use. */
1106 switch (trap) {
1107 case 0x91d02010:
1108 /* Linux/SPARC syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001109 update_personality(tcp, 0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001110 break;
1111 case 0x91d0206d:
1112 /* Linux/SPARC64 syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001113 update_personality(tcp, 2);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001114 break;
1115 case 0x91d02000:
1116 /* SunOS syscall trap. (pers 1) */
1117 fprintf(stderr, "syscall: SunOS no support\n");
1118 return -1;
1119 case 0x91d02008:
1120 /* Solaris 2.x syscall trap. (per 2) */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001121 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001122 break;
1123 case 0x91d02009:
1124 /* NetBSD/FreeBSD syscall trap. */
1125 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1126 return -1;
1127 case 0x91d02027:
1128 /* Solaris 2.x gettimeofday */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001129 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001130 break;
1131 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001132# if defined (SPARC64)
1133 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1134# else
1135 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1136# endif
1137 return -1;
1138 }
1139
1140 /* Extract the system call number from the registers. */
1141 if (trap == 0x91d02027)
1142 scno = 156;
1143 else
1144 scno = regs.u_regs[U_REG_G1];
1145 if (scno == 0) {
1146 scno = regs.u_regs[U_REG_O0];
1147 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1148 }
1149# elif defined(HPPA)
1150 if (upeek(tcp, PT_GR20, &scno) < 0)
1151 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001152# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001153 /*
1154 * In the new syscall ABI, the system call number is in R3.
1155 */
1156 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1157 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001158
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001159 if (scno < 0) {
1160 /* Odd as it may seem, a glibc bug has been known to cause
1161 glibc to issue bogus negative syscall numbers. So for
1162 our purposes, make strace print what it *should* have been */
1163 long correct_scno = (scno & 0xff);
1164 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001165 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001166 "Detected glibc bug: bogus system call"
1167 " number = %ld, correcting to %ld\n",
1168 scno,
1169 correct_scno);
1170 scno = correct_scno;
1171 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001172# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001173 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001174 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001175 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001176# elif defined(CRISV10) || defined(CRISV32)
1177 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1178 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001179# elif defined(TILE)
1180 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1181 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001182# elif defined(MICROBLAZE)
1183 if (upeek(tcp, 0, &scno) < 0)
1184 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001185# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001187
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001189 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001191#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001192 /* new syscall ABI returns result in R0 */
1193 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1194 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001195#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001196 /* ABI defines result returned in r9 */
1197 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1198 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001199#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001200
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001201#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001202# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001203 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001204# else
1205# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001206 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001207# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001208 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001209 perror("pread");
1210 return -1;
1211 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001212 switch (regs.r_eax) {
1213 case SYS_syscall:
1214 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001215 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1216 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001217 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001218 scno = regs.r_eax;
1219 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001220 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001221# endif /* FREEBSD */
1222# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001223#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001224
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001225 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001226 return 1;
1227}
1228
Roland McGrath17352792005-06-07 23:21:26 +00001229long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001230known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001231{
1232 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001233#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001234 if (SCNO_IN_RANGE(scno) && sysent[scno].native_scno != 0)
Roland McGrath17352792005-06-07 23:21:26 +00001235 scno = sysent[scno].native_scno;
1236 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001237#endif
Roland McGrath17352792005-06-07 23:21:26 +00001238 scno += NR_SYSCALL_BASE;
1239 return scno;
1240}
1241
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001242/* Called at each syscall entry.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001243 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001244 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001245 * 1: ok, continue in trace_syscall().
1246 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001247 * ("????" etc) and bail out.
1248 */
Roland McGratha4d48532005-06-08 20:45:28 +00001249static int
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001250syscall_fixup_on_sysenter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001251{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001252#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001253 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001254
Denys Vlasenkoece98792011-08-25 10:25:35 +02001255 if (tcp->status.PR_WHY != PR_SYSENTRY) {
1256 if (
1257 scno == SYS_fork
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001258#ifdef SYS_vfork
Denys Vlasenkoece98792011-08-25 10:25:35 +02001259 || scno == SYS_vfork
1260#endif
John Hughes4e36a812001-04-18 15:11:51 +00001261#ifdef SYS_fork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001262 || scno == SYS_fork1
1263#endif
John Hughes4e36a812001-04-18 15:11:51 +00001264#ifdef SYS_forkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001265 || scno == SYS_forkall
1266#endif
John Hughes4e36a812001-04-18 15:11:51 +00001267#ifdef SYS_rfork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001268 || scno == SYS_rfork1
1269#endif
John Hughes4e36a812001-04-18 15:11:51 +00001270#ifdef SYS_rforkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001271 || scno == SYS_rforkall
1272#endif
1273 ) {
1274 /* We are returning in the child, fake it. */
1275 tcp->status.PR_WHY = PR_SYSENTRY;
1276 trace_syscall(tcp);
1277 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001278 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001279 else {
1280 fprintf(stderr, "syscall: missing entry\n");
1281 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001282 }
1283 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001284#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001285
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001287 if (scno == 0) {
1288 fprintf(stderr, "syscall: missing entry\n");
1289 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001290 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001291#endif
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001292
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001294 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295#if defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001296 if (i386_regs.eax != -ENOSYS) {
1297 if (debug)
1298 fprintf(stderr, "not a syscall entry (eax = %ld)\n", i386_regs.eax);
1299 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001301#elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001302 {
1303 long rax = x86_64_regs.rax;
Denys Vlasenko18beb982011-08-24 16:59:23 +02001304 if (current_personality == 1)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001305 rax = (int)rax; /* sign extend from 32 bits */
1306 if (rax != -ENOSYS) {
Denys Vlasenko18beb982011-08-24 16:59:23 +02001307 if (debug)
1308 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1309 return 0;
1310 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001311 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001312#elif defined (S390) || defined (S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001313 /* TODO: we already fetched PT_GPR2 in get_scno
1314 * and stored it in syscall_mode, reuse it here
1315 * instead of re-fetching?
1316 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001317 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001318 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001319 if (syscall_mode != -ENOSYS)
1320 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001321 if (gpr2 != syscall_mode) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001322 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001323 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001324 return 0;
1325 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001326#elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001327 /* TODO? Eliminate upeek's in arches below like we did in x86 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001328 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001330 if (d0 != -ENOSYS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001331 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001332 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333 return 0;
1334 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001335#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001336 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001337 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001338 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001339 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001340 if (ia32 && r8 != -ENOSYS) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001341 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001342 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001343 return 0;
1344 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001345#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001346 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001347 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001348 if (r10 != -ENOSYS) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001349 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001350 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001351 return 0;
1352 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001353#elif defined(MICROBLAZE)
1354 if (upeek(tcp, 3 * 4, &r3) < 0)
1355 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001356 if (r3 != -ENOSYS) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001357 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001358 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001359 return 0;
1360 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001361#endif
1362#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001363 return 1;
1364}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001365
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001366static int
1367internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001368{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001369 /*
1370 * We must always trace a few critical system calls in order to
1371 * correctly support following forks in the presence of tracing
1372 * qualifiers.
1373 */
1374 int (*func)();
1375
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001376 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001377 return 0;
1378
1379 func = sysent[tcp->scno].sys_func;
1380
1381 if ( sys_fork == func
1382#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
1383 || sys_vfork == func
1384#endif
1385#ifdef LINUX
1386 || sys_clone == func
1387#endif
1388#if UNIXWARE > 2
1389 || sys_rfork == func
1390#endif
1391 )
1392 return internal_fork(tcp);
1393
1394#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
1395 if ( sys_execve == func
1396# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
1397 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001398# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001399# if UNIXWARE > 2
1400 || sys_rexecve == func
1401# endif
1402 )
1403 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001404#endif
1405
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001406 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001407}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001408
Roland McGratha4d48532005-06-08 20:45:28 +00001409static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001410syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001411{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001412#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001413 int i, nargs;
1414
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001415 if (SCNO_IN_RANGE(tcp->scno))
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001416 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001417 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001418 nargs = tcp->u_nargs = MAX_ARGS;
1419
1420# if defined(S390) || defined(S390X)
1421 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001422 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1423 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001424# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001425 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001426 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1427 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001428# elif defined(IA64)
1429 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001430 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001431 long rbs_end;
1432 /* be backwards compatible with kernel < 2.4.4... */
1433# ifndef PT_RBS_END
1434# define PT_RBS_END PT_AR_BSP
1435# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001436
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001437 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1438 return -1;
1439 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001440 return -1;
1441
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001442 sof = (cfm >> 0) & 0x7f;
1443 sol = (cfm >> 7) & 0x7f;
1444 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1445
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001446 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001447 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1448 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1449 return -1;
1450 }
1451 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001452 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1453 PT_R9 /* ECX = out1 */,
1454 PT_R10 /* EDX = out2 */,
1455 PT_R14 /* ESI = out3 */,
1456 PT_R15 /* EDI = out4 */,
1457 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001458
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001459 for (i = 0; i < nargs; ++i) {
1460 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1461 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001462 /* truncate away IVE sign-extension */
1463 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001464 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001465 }
1466# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
1467 /* N32 and N64 both use up to six registers. */
1468 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001469
1470 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1471 return -1;
1472
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001473 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001474 tcp->u_arg[i] = regs[REG_A0 + i];
1475# if defined(LINUX_MIPSN32)
1476 tcp->ext_arg[i] = regs[REG_A0 + i];
1477# endif
1478 }
1479# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001480 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001481 long sp;
1482
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001483 if (upeek(tcp, REG_SP, &sp) < 0)
1484 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001485 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001486 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1487 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001488 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001489 (char *)(tcp->u_arg + 4));
1490 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001491 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001492 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001493 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001494 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001495# elif defined(POWERPC)
1496# ifndef PT_ORIG_R3
1497# define PT_ORIG_R3 34
1498# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001499 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001500 if (upeek(tcp, (i==0) ?
1501 (sizeof(unsigned long) * PT_ORIG_R3) :
1502 ((i+PT_R3) * sizeof(unsigned long)),
1503 &tcp->u_arg[i]) < 0)
1504 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001505 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001506# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001507 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001508 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
1509# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001510 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001511 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1512 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001513# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001514 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001515 tcp->u_arg[i] = regs.uregs[i];
1516# elif defined(AVR32)
Denys Vlasenkob5b25892011-08-30 19:04:54 +02001517 (void)i;
1518 (void)nargs;
1519 tcp->u_arg[0] = regs.r12;
1520 tcp->u_arg[1] = regs.r11;
1521 tcp->u_arg[2] = regs.r10;
1522 tcp->u_arg[3] = regs.r9;
1523 tcp->u_arg[4] = regs.r5;
1524 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001525# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001526 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 +02001527
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001528 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001529 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1530 return -1;
1531# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001532 static const int syscall_regs[MAX_ARGS] = {
1533 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1534 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001535 };
1536
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001537 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001538 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001539 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001540# elif defined(SH64)
1541 int i;
1542 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001543 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001544
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001545 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001546 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1547 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001548# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001549 (void)i;
1550 (void)nargs;
1551 if (current_personality == 0) { /* x86-64 ABI */
1552 tcp->u_arg[0] = x86_64_regs.rdi;
1553 tcp->u_arg[1] = x86_64_regs.rsi;
1554 tcp->u_arg[2] = x86_64_regs.rdx;
1555 tcp->u_arg[3] = x86_64_regs.r10;
1556 tcp->u_arg[4] = x86_64_regs.r8;
1557 tcp->u_arg[5] = x86_64_regs.r9;
1558 } else { /* i386 ABI */
1559 /* Sign-extend lower 32 bits */
1560 tcp->u_arg[0] = (long)(int)x86_64_regs.rbx;
1561 tcp->u_arg[1] = (long)(int)x86_64_regs.rcx;
1562 tcp->u_arg[2] = (long)(int)x86_64_regs.rdx;
1563 tcp->u_arg[3] = (long)(int)x86_64_regs.rsi;
1564 tcp->u_arg[4] = (long)(int)x86_64_regs.rdi;
1565 tcp->u_arg[5] = (long)(int)x86_64_regs.rbp;
1566 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001567# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001568 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001569 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1570 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001571# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001572 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001573 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001574 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001575 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001576
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001577 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001578 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1579 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001580# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001581 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001582 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1583 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001584# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001585 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001586 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1587 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001588# elif defined(I386)
1589 (void)i;
1590 (void)nargs;
1591 tcp->u_arg[0] = i386_regs.ebx;
1592 tcp->u_arg[1] = i386_regs.ecx;
1593 tcp->u_arg[2] = i386_regs.edx;
1594 tcp->u_arg[3] = i386_regs.esi;
1595 tcp->u_arg[4] = i386_regs.edi;
1596 tcp->u_arg[5] = i386_regs.ebp;
1597# else /* Other architecture (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001598 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001599 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1600 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001601# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602#endif /* LINUX */
1603#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001604 int i, nargs;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001605 if (SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001606 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001607 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001608 nargs = tcp->u_nargs = MAX_ARGS;
1609 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001610 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001611
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001612 if (upeek(tcp, uoff(u_arg[0]) +
1613 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1614 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615 }
1616#endif /* SUNOS4 */
1617#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001618# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619 /*
1620 * SGI is broken: even though it has pr_sysarg, it doesn't
1621 * set them on system call entry. Get a clue.
1622 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001623 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001624 tcp->u_nargs = sysent[tcp->scno].nargs;
1625 else
1626 tcp->u_nargs = tcp->status.pr_nsysarg;
1627 if (tcp->u_nargs > 4) {
1628 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001629 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001631 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632 }
1633 else {
1634 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001635 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001637# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00001638 /*
1639 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1640 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001641 if (SCNO_IN_RANGE(tcp->scno))
John Hughes25299712001-03-06 10:10:06 +00001642 tcp->u_nargs = sysent[tcp->scno].nargs;
1643 else
1644 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1645 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001646 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1647# elif defined(HAVE_PR_SYSCALL)
1648 int i;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001649 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650 tcp->u_nargs = sysent[tcp->scno].nargs;
1651 else
1652 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001653 for (i = 0; i < tcp->u_nargs; i++)
1654 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1655# elif defined(I386)
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001656 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657 tcp->u_nargs = sysent[tcp->scno].nargs;
1658 else
1659 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02001660 if (tcp->u_nargs > 0)
1661 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001662 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1663# else
John Hughes25299712001-03-06 10:10:06 +00001664 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001665# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001667#ifdef FREEBSD
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001668 if (SCNO_IN_RANGE(tcp->scno) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001669 sysent[tcp->scno].nargs > tcp->status.val)
1670 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001671 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001672 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001673 if (tcp->u_nargs < 0)
1674 tcp->u_nargs = 0;
1675 if (tcp->u_nargs > MAX_ARGS)
1676 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001677 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001678 case SYS___syscall:
1679 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1680 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001681 break;
1682 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001683 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1684 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001685 break;
1686 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001687 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1688 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001689 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001690 }
1691#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001692 return 1;
1693}
1694
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001695static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001696trace_syscall_entering(struct tcb *tcp)
1697{
1698 int res, scno_good;
1699
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001700#if defined TCB_WAITEXECVE
1701 if (tcp->flags & TCB_WAITEXECVE) {
1702 /* This is the post-execve SIGTRAP. */
1703 tcp->flags &= ~TCB_WAITEXECVE;
1704 return 0;
1705 }
1706#endif
1707
Denys Vlasenko06602d92011-08-24 17:53:52 +02001708 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001709 if (res == 0)
1710 return res;
1711 if (res == 1)
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001712 res = syscall_fixup_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001713 if (res == 0)
1714 return res;
1715 if (res == 1)
1716 res = syscall_enter(tcp);
1717 if (res == 0)
1718 return res;
1719
1720 if (res != 1) {
1721 printleader(tcp);
1722 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001723 if (scno_good != 1)
1724 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001725 else if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001726 tprintf("syscall_%lu(", tcp->scno);
1727 else
1728 tprintf("%s(", sysent[tcp->scno].sys_name);
1729 /*
1730 * " <unavailable>" will be added later by the code which
1731 * detects ptrace errors.
1732 */
1733 goto ret;
1734 }
1735
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001736#if defined(SYS_socket_subcall) || defined(SYS_ipc_subcall)
1737 while (SCNO_IN_RANGE(tcp->scno)) {
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001738#ifdef SYS_socket_subcall
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001739 if (sysent[tcp->scno].sys_func == sys_socketcall) {
1740 decode_subcall(tcp, SYS_socket_subcall,
1741 SYS_socket_nsubcalls, deref_style);
1742 break;
1743 }
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001744#endif
1745#ifdef SYS_ipc_subcall
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001746 if (sysent[tcp->scno].sys_func == sys_ipc) {
1747 decode_subcall(tcp, SYS_ipc_subcall,
1748 SYS_ipc_nsubcalls, shift_style);
1749 break;
1750 }
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001751#endif
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001752 break;
1753 }
1754#endif /* SYS_socket_subcall || SYS_ipc_subcall */
1755
1756#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
1757 switch (known_scno(tcp)) {
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001758#ifdef SVR4
1759#ifdef SYS_pgrpsys_subcall
1760 case SYS_pgrpsys:
1761 decode_subcall(tcp, SYS_pgrpsys_subcall,
1762 SYS_pgrpsys_nsubcalls, shift_style);
1763 break;
1764#endif /* SYS_pgrpsys_subcall */
1765#ifdef SYS_sigcall_subcall
1766 case SYS_sigcall:
1767 decode_subcall(tcp, SYS_sigcall_subcall,
1768 SYS_sigcall_nsubcalls, mask_style);
1769 break;
1770#endif /* SYS_sigcall_subcall */
1771 case SYS_msgsys:
1772 decode_subcall(tcp, SYS_msgsys_subcall,
1773 SYS_msgsys_nsubcalls, shift_style);
1774 break;
1775 case SYS_shmsys:
1776 decode_subcall(tcp, SYS_shmsys_subcall,
1777 SYS_shmsys_nsubcalls, shift_style);
1778 break;
1779 case SYS_semsys:
1780 decode_subcall(tcp, SYS_semsys_subcall,
1781 SYS_semsys_nsubcalls, shift_style);
1782 break;
1783 case SYS_sysfs:
1784 decode_subcall(tcp, SYS_sysfs_subcall,
1785 SYS_sysfs_nsubcalls, shift_style);
1786 break;
1787 case SYS_spcall:
1788 decode_subcall(tcp, SYS_spcall_subcall,
1789 SYS_spcall_nsubcalls, shift_style);
1790 break;
1791#ifdef SYS_context_subcall
1792 case SYS_context:
1793 decode_subcall(tcp, SYS_context_subcall,
1794 SYS_context_nsubcalls, shift_style);
1795 break;
1796#endif /* SYS_context_subcall */
1797#ifdef SYS_door_subcall
1798 case SYS_door:
1799 decode_subcall(tcp, SYS_door_subcall,
1800 SYS_door_nsubcalls, door_style);
1801 break;
1802#endif /* SYS_door_subcall */
1803#ifdef SYS_kaio_subcall
1804 case SYS_kaio:
1805 decode_subcall(tcp, SYS_kaio_subcall,
1806 SYS_kaio_nsubcalls, shift_style);
1807 break;
1808#endif
1809#endif /* SVR4 */
1810#ifdef FREEBSD
1811 case SYS_msgsys:
1812 case SYS_shmsys:
1813 case SYS_semsys:
1814 decode_subcall(tcp, 0, 0, table_style);
1815 break;
1816#endif
1817#ifdef SUNOS4
1818 case SYS_semsys:
1819 decode_subcall(tcp, SYS_semsys_subcall,
1820 SYS_semsys_nsubcalls, shift_style);
1821 break;
1822 case SYS_msgsys:
1823 decode_subcall(tcp, SYS_msgsys_subcall,
1824 SYS_msgsys_nsubcalls, shift_style);
1825 break;
1826 case SYS_shmsys:
1827 decode_subcall(tcp, SYS_shmsys_subcall,
1828 SYS_shmsys_nsubcalls, shift_style);
1829 break;
1830#endif
1831 }
Dmitry V. Levinb5e88d42012-02-20 17:02:38 +00001832#endif /* SVR4 || FREEBSD || SUNOS4 */
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001833
1834 internal_syscall(tcp);
1835
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001836 if ((SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001837 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1838 (tracing_paths && !pathtrace_match(tcp))) {
1839 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1840 return 0;
1841 }
1842
1843 tcp->flags &= ~TCB_FILTERED;
1844
1845 if (cflag == CFLAG_ONLY_STATS) {
1846 res = 0;
1847 goto ret;
1848 }
1849
1850 printleader(tcp);
1851 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001852 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001853 tprintf("syscall_%lu(", tcp->scno);
1854 else
1855 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001856 if (!SCNO_IN_RANGE(tcp->scno) ||
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001857 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1858 sysent[tcp->scno].sys_func != sys_exit))
1859 res = printargs(tcp);
1860 else
1861 res = (*sysent[tcp->scno].sys_func)(tcp);
1862
1863 if (fflush(tcp->outf) == EOF)
1864 return -1;
1865 ret:
1866 tcp->flags |= TCB_INSYSCALL;
1867 /* Measure the entrance time as late as possible to avoid errors. */
1868 if (dtime || cflag)
1869 gettimeofday(&tcp->etime, NULL);
1870 return res;
1871}
1872
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001873/* Returns:
1874 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1875 * 1: ok, continue in trace_syscall().
1876 * other: error, trace_syscall() should print error indicator
1877 * ("????" etc) and bail out.
1878 */
1879static int
1880get_syscall_result(struct tcb *tcp)
1881{
1882#ifdef LINUX
1883# if defined(S390) || defined(S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001884 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
1885 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001886# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001887# define SO_MASK 0x10000000
1888 {
1889 long flags;
1890 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1891 return -1;
1892 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
1893 return -1;
1894 if (flags & SO_MASK)
1895 result = -result;
1896 }
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001897# elif defined(AVR32)
1898 /* Read complete register set in one go. */
1899 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1900 return -1;
1901# elif defined(BFIN)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001902 if (upeek(tcp, PT_R0, &r0) < 0)
1903 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001904# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001905 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001906 return -1;
1907# elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001908 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001909 return -1;
1910# elif defined(IA64)
1911# define IA64_PSR_IS ((long)1 << 34)
1912 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1913 ia32 = (psr & IA64_PSR_IS) != 0;
1914 if (upeek(tcp, PT_R8, &r8) < 0)
1915 return -1;
1916 if (upeek(tcp, PT_R10, &r10) < 0)
1917 return -1;
1918# elif defined (ARM)
1919 /* Read complete register set in one go. */
1920 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1921 return -1;
1922# elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001923 if (upeek(tcp, 4*PT_D0, &d0) < 0)
1924 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001925# elif defined (LINUX_MIPSN32)
1926 unsigned long long regs[38];
1927
1928 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1929 return -1;
1930 a3 = regs[REG_A3];
1931 r2 = regs[REG_V0];
1932# elif defined (MIPS)
1933 if (upeek(tcp, REG_A3, &a3) < 0)
1934 return -1;
1935 if (upeek(tcp, REG_V0, &r2) < 0)
1936 return -1;
1937# elif defined (ALPHA)
1938 if (upeek(tcp, REG_A3, &a3) < 0)
1939 return -1;
1940 if (upeek(tcp, REG_R0, &r0) < 0)
1941 return -1;
1942# elif defined (SPARC) || defined (SPARC64)
1943 /* Everything we need is in the current register set. */
1944 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1945 return -1;
1946# elif defined(HPPA)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001947 if (upeek(tcp, PT_GR28, &r28) < 0)
1948 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001949# elif defined(SH)
1950# elif defined(SH64)
1951# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001952 if (upeek(tcp, 4*PT_R10, &r10) < 0)
1953 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001954# elif defined(TILE)
1955# elif defined(MICROBLAZE)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001956 if (upeek(tcp, 3 * 4, &r3) < 0)
1957 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001958# endif
1959#endif /* LINUX */
1960
1961#ifdef SUNOS4
1962#elif defined(SH)
1963 /* new syscall ABI returns result in R0 */
1964 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1965 return -1;
1966#elif defined(SH64)
1967 /* ABI defines result returned in r9 */
1968 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1969 return -1;
1970#endif
1971
1972#ifdef USE_PROCFS
1973# ifndef HAVE_PR_SYSCALL
1974# ifdef FREEBSD
1975 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1976 perror("pread");
1977 return -1;
1978 }
1979# endif /* FREEBSD */
1980# endif /* !HAVE_PR_SYSCALL */
1981#endif /* USE_PROCFS */
1982
1983 return 1;
1984}
1985
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001986/* Called at each syscall exit.
1987 * Returns:
1988 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1989 * 1: ok, continue in trace_syscall().
1990 * other: error, trace_syscall() should print error indicator
1991 * ("????" etc) and bail out.
1992 */
1993static int
1994syscall_fixup_on_sysexit(struct tcb *tcp)
1995{
1996#ifdef USE_PROCFS
Denys Vlasenkoece98792011-08-25 10:25:35 +02001997 if (tcp->status.PR_WHY != PR_SYSEXIT) {
1998 fprintf(stderr, "syscall: missing exit\n");
1999 tcp->flags &= ~TCB_INSYSCALL;
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002000 }
2001#endif /* USE_PROCFS */
2002
2003#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02002004 {
2005 int scno = known_scno(tcp);
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002006 if (scno != 0) {
2007 if (debug) {
2008 /*
2009 * This happens when a signal handler
2010 * for a signal which interrupted a
2011 * a system call makes another system call.
2012 */
2013 fprintf(stderr, "syscall: missing exit\n");
2014 }
2015 tcp->flags &= ~TCB_INSYSCALL;
2016 }
2017 }
2018#endif /* SUNOS4 */
2019
2020#ifdef LINUX
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002021# if defined (S390) || defined (S390X)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002022 if (syscall_mode != -ENOSYS)
2023 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02002024 if ((tcp->flags & TCB_WAITEXECVE)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002025 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
2026 /*
2027 * Return from execve.
2028 * Fake a return value of zero. We leave the TCB_WAITEXECVE
2029 * flag set for the post-execve SIGTRAP to see and reset.
2030 */
2031 gpr2 = 0;
2032 }
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002033# endif
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002034#endif /* LINUX */
2035 return 1;
2036}
2037
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002038#ifdef LINUX
2039/*
2040 * Check the syscall return value register value for whether it is
2041 * a negated errno code indicating an error, or a success return value.
2042 */
2043static inline int
2044is_negated_errno(unsigned long int val)
2045{
2046 unsigned long int max = -(long int) nerrnos;
2047# if SUPPORTED_PERSONALITIES > 1
2048 if (personality_wordsize[current_personality] < sizeof(val)) {
2049 val = (unsigned int) val;
2050 max = (unsigned int) max;
2051 }
2052# endif
2053 return val > max;
2054}
2055#endif
2056
2057static int
2058get_error(struct tcb *tcp)
2059{
2060 int u_error = 0;
2061#ifdef LINUX
2062 int check_errno = 1;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002063 if (SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002064 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2065 check_errno = 0;
2066 }
2067# if defined(S390) || defined(S390X)
2068 if (check_errno && is_negated_errno(gpr2)) {
2069 tcp->u_rval = -1;
2070 u_error = -gpr2;
2071 }
2072 else {
2073 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002074 }
2075# elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002076 if (check_errno && is_negated_errno(i386_regs.eax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002077 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002078 u_error = -i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002079 }
2080 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002081 tcp->u_rval = i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002082 }
2083# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002084 if (check_errno && is_negated_errno(x86_64_regs.rax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002085 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002086 u_error = -x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002087 }
2088 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002089 tcp->u_rval = x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002090 }
2091# elif defined(IA64)
2092 if (ia32) {
2093 int err;
2094
2095 err = (int)r8;
2096 if (check_errno && is_negated_errno(err)) {
2097 tcp->u_rval = -1;
2098 u_error = -err;
2099 }
2100 else {
2101 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002102 }
2103 } else {
2104 if (check_errno && r10) {
2105 tcp->u_rval = -1;
2106 u_error = r8;
2107 } else {
2108 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002109 }
2110 }
2111# elif defined(MIPS)
2112 if (check_errno && a3) {
2113 tcp->u_rval = -1;
2114 u_error = r2;
2115 } else {
2116 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002117 }
2118# elif defined(POWERPC)
2119 if (check_errno && is_negated_errno(result)) {
2120 tcp->u_rval = -1;
2121 u_error = -result;
2122 }
2123 else {
2124 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002125 }
2126# elif defined(M68K)
2127 if (check_errno && is_negated_errno(d0)) {
2128 tcp->u_rval = -1;
2129 u_error = -d0;
2130 }
2131 else {
2132 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002133 }
2134# elif defined(ARM)
2135 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2136 tcp->u_rval = -1;
2137 u_error = -regs.ARM_r0;
2138 }
2139 else {
2140 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002141 }
2142# elif defined(AVR32)
2143 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2144 tcp->u_rval = -1;
2145 u_error = -regs.r12;
2146 }
2147 else {
2148 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002149 }
2150# elif defined(BFIN)
2151 if (check_errno && is_negated_errno(r0)) {
2152 tcp->u_rval = -1;
2153 u_error = -r0;
2154 } else {
2155 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002156 }
2157# elif defined(ALPHA)
2158 if (check_errno && a3) {
2159 tcp->u_rval = -1;
2160 u_error = r0;
2161 }
2162 else {
2163 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002164 }
2165# elif defined(SPARC)
2166 if (check_errno && regs.psr & PSR_C) {
2167 tcp->u_rval = -1;
2168 u_error = regs.u_regs[U_REG_O0];
2169 }
2170 else {
2171 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002172 }
2173# elif defined(SPARC64)
2174 if (check_errno && regs.tstate & 0x1100000000UL) {
2175 tcp->u_rval = -1;
2176 u_error = regs.u_regs[U_REG_O0];
2177 }
2178 else {
2179 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002180 }
2181# elif defined(HPPA)
2182 if (check_errno && is_negated_errno(r28)) {
2183 tcp->u_rval = -1;
2184 u_error = -r28;
2185 }
2186 else {
2187 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002188 }
2189# elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002190 if (check_errno && is_negated_errno(r0)) {
2191 tcp->u_rval = -1;
2192 u_error = -r0;
2193 }
2194 else {
2195 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002196 }
2197# elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002198 if (check_errno && is_negated_errno(r9)) {
2199 tcp->u_rval = -1;
2200 u_error = -r9;
2201 }
2202 else {
2203 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002204 }
2205# elif defined(CRISV10) || defined(CRISV32)
2206 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2207 tcp->u_rval = -1;
2208 u_error = -r10;
2209 }
2210 else {
2211 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002212 }
2213# elif defined(TILE)
2214 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002215 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2216 return -1;
2217 if (check_errno && rval < 0 && rval > -nerrnos) {
2218 tcp->u_rval = -1;
2219 u_error = -rval;
2220 }
2221 else {
2222 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002223 }
2224# elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002225 if (check_errno && is_negated_errno(r3)) {
2226 tcp->u_rval = -1;
2227 u_error = -r3;
2228 }
2229 else {
2230 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002231 }
2232# endif
2233#endif /* LINUX */
2234#ifdef SUNOS4
2235 /* get error code from user struct */
2236 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2237 return -1;
2238 u_error >>= 24; /* u_error is a char */
2239
2240 /* get system call return value */
2241 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2242 return -1;
2243#endif /* SUNOS4 */
2244#ifdef SVR4
2245# ifdef SPARC
2246 /* Judicious guessing goes a long way. */
2247 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2248 tcp->u_rval = -1;
2249 u_error = tcp->status.pr_reg[R_O0];
2250 }
2251 else {
2252 tcp->u_rval = tcp->status.pr_reg[R_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002253 }
2254# endif /* SPARC */
2255# ifdef I386
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002256 if (tcp->status.PR_REG[EFL] & 0x1) {
2257 tcp->u_rval = -1;
2258 u_error = tcp->status.PR_REG[EAX];
2259 }
2260 else {
2261 tcp->u_rval = tcp->status.PR_REG[EAX];
2262# ifdef HAVE_LONG_LONG
2263 tcp->u_lrval =
2264 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2265 tcp->status.PR_REG[EAX];
2266# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002267 }
2268# endif /* I386 */
2269# ifdef X86_64
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002270 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2271 tcp->u_rval = -1;
2272 u_error = tcp->status.PR_REG[RAX];
2273 }
2274 else {
2275 tcp->u_rval = tcp->status.PR_REG[RAX];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002276 }
2277# endif /* X86_64 */
2278# ifdef MIPS
2279 if (tcp->status.pr_reg[CTX_A3]) {
2280 tcp->u_rval = -1;
2281 u_error = tcp->status.pr_reg[CTX_V0];
2282 }
2283 else {
2284 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002285 }
2286# endif /* MIPS */
2287#endif /* SVR4 */
2288#ifdef FREEBSD
2289 if (regs.r_eflags & PSL_C) {
2290 tcp->u_rval = -1;
2291 u_error = regs.r_eax;
2292 } else {
2293 tcp->u_rval = regs.r_eax;
2294 tcp->u_lrval =
Denys Vlasenko684fb1a2011-08-25 00:26:38 +02002295 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002296 }
2297#endif /* FREEBSD */
2298 tcp->u_error = u_error;
2299 return 1;
2300}
2301
2302static void
2303dumpio(struct tcb *tcp)
2304{
2305 if (syserror(tcp))
2306 return;
2307 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
2308 return;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002309 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002310 return;
2311 if (sysent[tcp->scno].sys_func == printargs)
2312 return;
2313 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
2314 if (sysent[tcp->scno].sys_func == sys_read ||
2315 sysent[tcp->scno].sys_func == sys_pread ||
Dmitry V. Levin309edeb2012-02-04 15:17:43 +00002316#ifdef SVR4
2317#if _LFS64_LARGEFILE
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002318 sysent[tcp->scno].sys_func == sys_pread64 ||
Dmitry V. Levin309edeb2012-02-04 15:17:43 +00002319#endif
2320#endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002321 sysent[tcp->scno].sys_func == sys_recv ||
2322 sysent[tcp->scno].sys_func == sys_recvfrom)
2323 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
2324 else if (sysent[tcp->scno].sys_func == sys_readv)
2325 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2326 return;
2327 }
2328 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
2329 if (sysent[tcp->scno].sys_func == sys_write ||
2330 sysent[tcp->scno].sys_func == sys_pwrite ||
Dmitry V. Levin309edeb2012-02-04 15:17:43 +00002331#ifdef SVR4
2332#if _LFS64_LARGEFILE
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002333 sysent[tcp->scno].sys_func == sys_pwrite64 ||
Dmitry V. Levin309edeb2012-02-04 15:17:43 +00002334#endif
2335#endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002336 sysent[tcp->scno].sys_func == sys_send ||
2337 sysent[tcp->scno].sys_func == sys_sendto)
2338 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
2339 else if (sysent[tcp->scno].sys_func == sys_writev)
2340 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2341 return;
2342 }
2343}
2344
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002345static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002346trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002347{
2348 int sys_res;
2349 struct timeval tv;
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002350 int res;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002351 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002352
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002353 /* Measure the exit time as early as possible to avoid errors. */
2354 if (dtime || cflag)
2355 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002356
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00002357#if SUPPORTED_PERSONALITIES > 1
2358 update_personality(tcp, tcp->currpers);
2359#endif
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002360 res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002361 if (res == 0)
2362 return res;
2363 if (res == 1)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002364 res = syscall_fixup_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002365 if (res == 0)
2366 return res;
2367 if (res == 1)
2368 res = get_error(tcp);
2369 if (res == 0)
2370 return res;
2371 if (res == 1)
2372 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002373
Grant Edwards8a082772011-04-07 20:25:40 +00002374 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002375 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002376 }
2377
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002378 if (tcp->flags & TCB_REPRINT) {
2379 printleader(tcp);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002380 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002381 tprintf("<... syscall_%lu resumed> ", tcp->scno);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002382 else
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002383 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002384 }
2385
2386 if (cflag) {
2387 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002388 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002389 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002390 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002391 }
2392 }
2393
2394 if (res != 1) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002395 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002396 tabto();
Denys Vlasenko000b6012012-01-28 01:25:03 +01002397 tprints("= ? <unavailable>\n");
2398 printing_tcp = NULL;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002399 tcp->flags &= ~TCB_INSYSCALL;
2400 return res;
2401 }
2402
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002403 if (!SCNO_IN_RANGE(tcp->scno)
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002404 || (qual_flags[tcp->scno] & QUAL_RAW))
2405 sys_res = printargs(tcp);
2406 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002407 /* FIXME: not_failing_only (IOW, option -z) is broken:
2408 * failure of syscall is known only after syscall return.
2409 * Thus we end up with something like this on, say, ENOENT:
2410 * open("doesnt_exist", O_RDONLY <unfinished ...>
2411 * {next syscall decode}
2412 * whereas the intended result is that open(...) line
2413 * is not shown at all.
2414 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002415 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002416 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002417 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2418 }
2419
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002420 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002421 tabto();
Denys Vlasenko3b738812011-08-22 02:06:35 +02002422 u_error = tcp->u_error;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002423 if (!SCNO_IN_RANGE(tcp->scno) ||
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002424 qual_flags[tcp->scno] & QUAL_RAW) {
2425 if (u_error)
2426 tprintf("= -1 (errno %ld)", u_error);
2427 else
2428 tprintf("= %#lx", tcp->u_rval);
2429 }
2430 else if (!(sys_res & RVAL_NONE) && u_error) {
2431 switch (u_error) {
2432#ifdef LINUX
Denys Vlasenkofe585652012-01-12 11:26:34 +01002433 /* Blocked signals do not interrupt any syscalls.
2434 * In this case syscalls don't return ERESTARTfoo codes.
2435 *
2436 * Deadly signals set to SIG_DFL interrupt syscalls
2437 * and kill the process regardless of which of the codes below
2438 * is returned by the interrupted syscall.
2439 * In some cases, kernel forces a kernel-generated deadly
2440 * signal to be unblocked and set to SIG_DFL (and thus cause
2441 * death) if it is blocked or SIG_IGNed: for example, SIGSEGV
2442 * or SIGILL. (The alternative is to leave process spinning
2443 * forever on the faulty instruction - not useful).
2444 *
2445 * SIG_IGNed signals and non-deadly signals set to SIG_DFL
2446 * (for example, SIGCHLD, SIGWINCH) interrupt syscalls,
2447 * but kernel will always restart them.
2448 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002449 case ERESTARTSYS:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002450 /* Most common type of signal-interrupted syscall exit code.
2451 * The system call will be restarted with the same arguments
2452 * if SA_RESTART is set; otherwise, it will fail with EINTR.
2453 */
2454 tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002455 break;
2456 case ERESTARTNOINTR:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002457 /* Rare. For example, fork() returns this if interrupted.
2458 * SA_RESTART is ignored (assumed set): the restart is unconditional.
2459 */
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002460 tprints("= ? ERESTARTNOINTR (To be restarted)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002461 break;
2462 case ERESTARTNOHAND:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002463 /* pause(), rt_sigsuspend() etc use this code.
2464 * SA_RESTART is ignored (assumed not set):
2465 * syscall won't restart (will return EINTR instead)
2466 * even after signal with SA_RESTART set.
2467 * However, after SIG_IGN or SIG_DFL signal it will.
2468 */
2469 tprints("= ? ERESTARTNOHAND (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002470 break;
2471 case ERESTART_RESTARTBLOCK:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002472 /* Syscalls like nanosleep(), poll() which can't be
2473 * restarted with their original arguments use this
2474 * code. Kernel will execute restart_syscall() instead,
2475 * which changes arguments before restarting syscall.
2476 * SA_RESTART is ignored (assumed not set) similarly
2477 * to ERESTARTNOHAND. (Kernel can't honor SA_RESTART
2478 * since restart data is saved in "restart block"
2479 * in task struct, and if signal handler uses a syscall
2480 * which in turn saves another such restart block,
2481 * old data is lost and restart becomes impossible)
2482 */
2483 tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002484 break;
2485#endif /* LINUX */
2486 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002487 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002488 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002489 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002490 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002491 strerror(u_error));
2492 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002493 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002494 strerror(u_error));
2495 break;
2496 }
2497 if ((sys_res & RVAL_STR) && tcp->auxstr)
2498 tprintf(" (%s)", tcp->auxstr);
2499 }
2500 else {
2501 if (sys_res & RVAL_NONE)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002502 tprints("= ?");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002503 else {
2504 switch (sys_res & RVAL_MASK) {
2505 case RVAL_HEX:
2506 tprintf("= %#lx", tcp->u_rval);
2507 break;
2508 case RVAL_OCTAL:
2509 tprintf("= %#lo", tcp->u_rval);
2510 break;
2511 case RVAL_UDECIMAL:
2512 tprintf("= %lu", tcp->u_rval);
2513 break;
2514 case RVAL_DECIMAL:
2515 tprintf("= %ld", tcp->u_rval);
2516 break;
2517#ifdef HAVE_LONG_LONG
2518 case RVAL_LHEX:
2519 tprintf("= %#llx", tcp->u_lrval);
2520 break;
2521 case RVAL_LOCTAL:
2522 tprintf("= %#llo", tcp->u_lrval);
2523 break;
2524 case RVAL_LUDECIMAL:
2525 tprintf("= %llu", tcp->u_lrval);
2526 break;
2527 case RVAL_LDECIMAL:
2528 tprintf("= %lld", tcp->u_lrval);
2529 break;
2530#endif
2531 default:
2532 fprintf(stderr,
2533 "invalid rval format\n");
2534 break;
2535 }
2536 }
2537 if ((sys_res & RVAL_STR) && tcp->auxstr)
2538 tprintf(" (%s)", tcp->auxstr);
2539 }
2540 if (dtime) {
2541 tv_sub(&tv, &tv, &tcp->etime);
2542 tprintf(" <%ld.%06ld>",
2543 (long) tv.tv_sec, (long) tv.tv_usec);
2544 }
Denys Vlasenko000b6012012-01-28 01:25:03 +01002545 tprints("\n");
2546 printing_tcp = NULL;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002547
2548 dumpio(tcp);
2549 if (fflush(tcp->outf) == EOF)
2550 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002551 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002552 tcp->flags &= ~TCB_INSYSCALL;
2553 return 0;
2554}
2555
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002556int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002557trace_syscall(struct tcb *tcp)
2558{
2559 return exiting(tcp) ?
2560 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2561}