blob: 88c976629957d9052e5cca2f424dbd54f9931429 [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
719 if (!syserror(tcp))
720 return 0;
721 switch (tcp->u_error) {
722 case ERESTARTSYS:
723 case ERESTARTNOINTR:
724 case ERESTARTNOHAND:
725 case ERESTART_RESTARTBLOCK:
726 return 1;
727 default:
728 break;
729 }
730#endif /* LINUX */
731 return 0;
732}
733
Wichert Akkermanc7926982000-04-10 22:22:31 +0000734#ifdef LINUX
Denys Vlasenkob11322f2012-01-10 16:40:35 +0100735# if defined(I386)
736struct pt_regs i386_regs;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200737# elif defined(X86_64)
Denys Vlasenkoe73a89d2012-01-18 11:07:24 +0100738/*
739 * On 32 bits, pt_regs and user_regs_struct are the same,
740 * but on 64 bits, user_regs_struct has six more fields:
741 * fs_base, gs_base, ds, es, fs, gs.
742 * PTRACE_GETREGS fills them too, so struct pt_regs would overflow.
743 */
744static struct user_regs_struct x86_64_regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200745# elif defined (IA64)
746long r8, r10, psr; /* TODO: make static? */
747long ia32 = 0; /* not static */
748# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +0200749static long result;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200750# elif defined (M68K)
751static long d0;
752# elif defined(BFIN)
753static long r0;
754# elif defined (ARM)
755static struct pt_regs regs;
756# elif defined (ALPHA)
757static long r0;
758static long a3;
759# elif defined(AVR32)
760static struct pt_regs regs;
761# elif defined (SPARC) || defined (SPARC64)
762static struct pt_regs regs;
763static unsigned long trap;
764# elif defined(LINUX_MIPSN32)
765static long long a3;
766static long long r2;
767# elif defined(MIPS)
768static long a3;
769static long r2;
770# elif defined(S390) || defined(S390X)
771static long gpr2;
772static long pc;
773static long syscall_mode;
774# elif defined(HPPA)
775static long r28;
776# elif defined(SH)
777static long r0;
778# elif defined(SH64)
779static long r9;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200780# elif defined(CRISV10) || defined(CRISV32)
781static long r10;
782# elif defined(MICROBLAZE)
783static long r3;
784# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000785#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000786#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200787struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000788#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000789
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200790/* Returns:
791 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
792 * 1: ok, continue in trace_syscall().
793 * other: error, trace_syscall() should print error indicator
794 * ("????" etc) and bail out.
795 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200796#ifndef USE_PROCFS
797static
798#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799int
Denys Vlasenko06602d92011-08-24 17:53:52 +0200800get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000801{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000802 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000803
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000804#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000805# if defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000806 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200807 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000808
809 if (syscall_mode != -ENOSYS) {
810 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000811 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000812 */
813 scno = syscall_mode;
814 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000815 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000816 * Old style of "passing" the scno via the SVC instruction.
817 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000818 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200819 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200820 static const int gpr_offset[16] = {
821 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
822 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
823 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
824 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
825 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000826
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000827 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000828 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000829 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000830 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000831 if (errno) {
832 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000833 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000834 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000835
836 /*
837 * We have to check if the SVC got executed directly or via an
838 * EXECUTE instruction. In case of EXECUTE it is necessary to do
839 * instruction decoding to derive the system call number.
840 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
841 * so that this doesn't work if a SVC opcode is part of an EXECUTE
842 * opcode. Since there is no way to find out the opcode size this
843 * is the best we can do...
844 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000845 if ((opcode & 0xff00) == 0x0a00) {
846 /* SVC opcode */
847 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000848 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000849 else {
850 /* SVC got executed by EXECUTE instruction */
851
852 /*
853 * Do instruction decoding of EXECUTE. If you really want to
854 * understand this, read the Principles of Operations.
855 */
856 svc_addr = (void *) (opcode & 0xfff);
857
858 tmp = 0;
859 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000860 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000861 return -1;
862 svc_addr += tmp;
863
864 tmp = 0;
865 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000866 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000867 return -1;
868 svc_addr += tmp;
869
Denys Vlasenkofb036672009-01-23 16:30:26 +0000870 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000871 if (errno)
872 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000873# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000874 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000875# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000876 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000877# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000878 tmp = 0;
879 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000880 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000881 return -1;
882
883 scno = (scno | tmp) & 0xff;
884 }
885 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000886# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000887 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000888 return -1;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200889# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200890 /* TODO: speed up strace by not doing this at every syscall.
891 * We only need to do it after execve.
892 */
893 int currpers;
894 long val;
895 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200896
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200897 /* Check for 64/32 bit mode. */
898 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
899 return -1;
900 /* SF is bit 0 of MSR */
901 if (val < 0)
902 currpers = 0;
903 else
904 currpers = 1;
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000905 update_personality(tcp, currpers);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200906# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000907# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200908 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000909 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
910 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200911 scno = regs.r8;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000912# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000913 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000914 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000915# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200916 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000917 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200918 scno = i386_regs.orig_eax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000919# elif defined (X86_64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200920 int currpers;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200921 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
922 return -1;
923 scno = x86_64_regs.orig_rax;
Michal Ludvig0e035502002-09-23 15:41:01 +0000924
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200925 /* Check CS register value. On x86-64 linux it is:
926 * 0x33 for long mode (64 bit)
927 * 0x23 for compatibility mode (32 bit)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200928 */
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200929 switch (x86_64_regs.cs) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200930 case 0x23: currpers = 1; break;
931 case 0x33: currpers = 0; break;
932 default:
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200933 fprintf(stderr, "Unknown value CS=0x%08X while "
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200934 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200935 "PID=%d\n", (int)x86_64_regs.cs, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200936 currpers = current_personality;
937 break;
938 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000939# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200940 /* This version analyzes the opcode of a syscall instruction.
941 * (int 0x80 on i386 vs. syscall on x86-64)
942 * It works, but is too complicated.
943 */
944 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000945
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200946 rip = x86_64_regs.rip;
Roland McGrath761b5d72002-12-15 23:58:31 +0000947
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200948 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
949 rip -= 2;
950 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000951
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200952 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200953 if (errno)
954 fprintf(stderr, "ptrace_peektext failed: %s\n",
955 strerror(errno));
956 switch (call & 0xffff) {
957 /* x86-64: syscall = 0x0f 0x05 */
958 case 0x050f: currpers = 0; break;
959 /* i386: int 0x80 = 0xcd 0x80 */
960 case 0x80cd: currpers = 1; break;
961 default:
962 currpers = current_personality;
963 fprintf(stderr,
964 "Unknown syscall opcode (0x%04X) while "
965 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200966 "PID=%d\n", (int)call, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200967 break;
968 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000969# endif
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000970 update_personality(tcp, currpers);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000971# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000972# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200973 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000974 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200975 if (ia32) {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200976 if (upeek(tcp, PT_R1, &scno) < 0)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200977 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000978 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200979 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000980 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200981 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000982# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200983 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000984 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000985 return -1;
986
987 /*
988 * We only need to grab the syscall number on syscall entry.
989 */
990 if (regs.ARM_ip == 0) {
991 /*
992 * Note: we only deal with only 32-bit CPUs here.
993 */
994 if (regs.ARM_cpsr & 0x20) {
995 /*
996 * Get the Thumb-mode system call number
997 */
998 scno = regs.ARM_r7;
999 } else {
1000 /*
1001 * Get the ARM-mode system call number
1002 */
1003 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001004 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001005 if (errno)
1006 return -1;
1007
Roland McGrathf691bd22006-04-25 07:34:41 +00001008 /* Handle the EABI syscall convention. We do not
1009 bother converting structures between the two
1010 ABIs, but basic functionality should work even
1011 if strace and the traced program have different
1012 ABIs. */
1013 if (scno == 0xef000000) {
1014 scno = regs.ARM_r7;
1015 } else {
1016 if ((scno & 0x0ff00000) != 0x0f900000) {
1017 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1018 scno);
1019 return -1;
1020 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001021
Roland McGrathf691bd22006-04-25 07:34:41 +00001022 /*
1023 * Fixup the syscall number
1024 */
1025 scno &= 0x000fffff;
1026 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001027 }
Roland McGrath56703312008-05-20 01:35:55 +00001028 if (scno & 0x0f0000) {
1029 /*
1030 * Handle ARM specific syscall
1031 */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001032 update_personality(tcp, 1);
Roland McGrath56703312008-05-20 01:35:55 +00001033 scno &= 0x0000ffff;
1034 } else
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001035 update_personality(tcp, 0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001036
Roland McGrath0f87c492003-06-03 23:29:04 +00001037 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001038 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1039 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001040 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001041# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001042 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001043 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001044# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001045 unsigned long long regs[38];
1046
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001047 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001048 return -1;
1049 a3 = regs[REG_A3];
1050 r2 = regs[REG_V0];
1051
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001052 scno = r2;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001053 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001054 if (a3 == 0 || a3 == -1) {
1055 if (debug)
1056 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001057 return 0;
1058 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001059 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001060# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001061 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001062 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001063 if (upeek(tcp, REG_V0, &scno) < 0)
1064 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001065
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001066 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001067 if (a3 == 0 || a3 == -1) {
1068 if (debug)
1069 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001070 return 0;
1071 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001072 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001073# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001074 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001075 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001076 if (upeek(tcp, REG_R0, &scno) < 0)
1077 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001079 /*
1080 * Do some sanity checks to figure out if it's
1081 * really a syscall entry
1082 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001083 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001084 if (a3 == 0 || a3 == -1) {
1085 if (debug)
1086 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087 return 0;
1088 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001090# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001092 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001093 return -1;
1094
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001095 /* Disassemble the syscall trap. */
1096 /* Retrieve the syscall trap instruction. */
1097 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001098# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001099 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1100 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001101# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001102 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001103# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001104 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001105 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001106
1107 /* Disassemble the trap to see what personality to use. */
1108 switch (trap) {
1109 case 0x91d02010:
1110 /* Linux/SPARC syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001111 update_personality(tcp, 0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001112 break;
1113 case 0x91d0206d:
1114 /* Linux/SPARC64 syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001115 update_personality(tcp, 2);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001116 break;
1117 case 0x91d02000:
1118 /* SunOS syscall trap. (pers 1) */
1119 fprintf(stderr, "syscall: SunOS no support\n");
1120 return -1;
1121 case 0x91d02008:
1122 /* Solaris 2.x syscall trap. (per 2) */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001123 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001124 break;
1125 case 0x91d02009:
1126 /* NetBSD/FreeBSD syscall trap. */
1127 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1128 return -1;
1129 case 0x91d02027:
1130 /* Solaris 2.x gettimeofday */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001131 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001132 break;
1133 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001134# if defined (SPARC64)
1135 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1136# else
1137 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1138# endif
1139 return -1;
1140 }
1141
1142 /* Extract the system call number from the registers. */
1143 if (trap == 0x91d02027)
1144 scno = 156;
1145 else
1146 scno = regs.u_regs[U_REG_G1];
1147 if (scno == 0) {
1148 scno = regs.u_regs[U_REG_O0];
1149 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1150 }
1151# elif defined(HPPA)
1152 if (upeek(tcp, PT_GR20, &scno) < 0)
1153 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001154# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001155 /*
1156 * In the new syscall ABI, the system call number is in R3.
1157 */
1158 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1159 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001160
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001161 if (scno < 0) {
1162 /* Odd as it may seem, a glibc bug has been known to cause
1163 glibc to issue bogus negative syscall numbers. So for
1164 our purposes, make strace print what it *should* have been */
1165 long correct_scno = (scno & 0xff);
1166 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001167 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001168 "Detected glibc bug: bogus system call"
1169 " number = %ld, correcting to %ld\n",
1170 scno,
1171 correct_scno);
1172 scno = correct_scno;
1173 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001174# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001175 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001176 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001177 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001178# elif defined(CRISV10) || defined(CRISV32)
1179 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1180 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001181# elif defined(TILE)
1182 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1183 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001184# elif defined(MICROBLAZE)
1185 if (upeek(tcp, 0, &scno) < 0)
1186 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001187# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001189
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001191 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001193#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001194 /* new syscall ABI returns result in R0 */
1195 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1196 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001197#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001198 /* ABI defines result returned in r9 */
1199 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1200 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001201#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001202
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001203#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001204# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001205 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001206# else
1207# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001208 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001209# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001210 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001211 perror("pread");
1212 return -1;
1213 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001214 switch (regs.r_eax) {
1215 case SYS_syscall:
1216 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001217 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1218 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001219 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001220 scno = regs.r_eax;
1221 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001222 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001223# endif /* FREEBSD */
1224# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001225#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001226
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001227 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001228 return 1;
1229}
1230
Roland McGrath17352792005-06-07 23:21:26 +00001231long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001232known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001233{
1234 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001235#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001236 if (SCNO_IN_RANGE(scno) && sysent[scno].native_scno != 0)
Roland McGrath17352792005-06-07 23:21:26 +00001237 scno = sysent[scno].native_scno;
1238 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001239#endif
Roland McGrath17352792005-06-07 23:21:26 +00001240 scno += NR_SYSCALL_BASE;
1241 return scno;
1242}
1243
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001244/* Called at each syscall entry.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001245 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001246 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001247 * 1: ok, continue in trace_syscall().
1248 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001249 * ("????" etc) and bail out.
1250 */
Roland McGratha4d48532005-06-08 20:45:28 +00001251static int
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001252syscall_fixup_on_sysenter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001253{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001254#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001255 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001256
Denys Vlasenkoece98792011-08-25 10:25:35 +02001257 if (tcp->status.PR_WHY != PR_SYSENTRY) {
1258 if (
1259 scno == SYS_fork
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001260#ifdef SYS_vfork
Denys Vlasenkoece98792011-08-25 10:25:35 +02001261 || scno == SYS_vfork
1262#endif
John Hughes4e36a812001-04-18 15:11:51 +00001263#ifdef SYS_fork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001264 || scno == SYS_fork1
1265#endif
John Hughes4e36a812001-04-18 15:11:51 +00001266#ifdef SYS_forkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001267 || scno == SYS_forkall
1268#endif
John Hughes4e36a812001-04-18 15:11:51 +00001269#ifdef SYS_rfork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001270 || scno == SYS_rfork1
1271#endif
John Hughes4e36a812001-04-18 15:11:51 +00001272#ifdef SYS_rforkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001273 || scno == SYS_rforkall
1274#endif
1275 ) {
1276 /* We are returning in the child, fake it. */
1277 tcp->status.PR_WHY = PR_SYSENTRY;
1278 trace_syscall(tcp);
1279 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001280 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001281 else {
1282 fprintf(stderr, "syscall: missing entry\n");
1283 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284 }
1285 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001286#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001287
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001288#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001289 if (scno == 0) {
1290 fprintf(stderr, "syscall: missing entry\n");
1291 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001293#endif
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001294
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001296 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001297#if defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001298 if (i386_regs.eax != -ENOSYS) {
1299 if (debug)
1300 fprintf(stderr, "not a syscall entry (eax = %ld)\n", i386_regs.eax);
1301 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001302 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001303#elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001304 {
1305 long rax = x86_64_regs.rax;
Denys Vlasenko18beb982011-08-24 16:59:23 +02001306 if (current_personality == 1)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001307 rax = (int)rax; /* sign extend from 32 bits */
1308 if (rax != -ENOSYS) {
Denys Vlasenko18beb982011-08-24 16:59:23 +02001309 if (debug)
1310 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1311 return 0;
1312 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001313 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001314#elif defined (S390) || defined (S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001315 /* TODO: we already fetched PT_GPR2 in get_scno
1316 * and stored it in syscall_mode, reuse it here
1317 * instead of re-fetching?
1318 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001319 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001320 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001321 if (syscall_mode != -ENOSYS)
1322 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001323 if (gpr2 != syscall_mode) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001324 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001325 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001326 return 0;
1327 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001328#elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001329 /* TODO? Eliminate upeek's in arches below like we did in x86 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001330 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001331 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001332 if (d0 != -ENOSYS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001334 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 return 0;
1336 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001337#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001338 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001339 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001340 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001341 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001342 if (ia32 && r8 != -ENOSYS) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001343 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001344 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001345 return 0;
1346 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001347#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001348 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001349 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001350 if (r10 != -ENOSYS) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001351 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001352 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001353 return 0;
1354 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001355#elif defined(MICROBLAZE)
1356 if (upeek(tcp, 3 * 4, &r3) < 0)
1357 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001358 if (r3 != -ENOSYS) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001359 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001360 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001361 return 0;
1362 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001363#endif
1364#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001365 return 1;
1366}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001368static int
1369internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001370{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001371 /*
1372 * We must always trace a few critical system calls in order to
1373 * correctly support following forks in the presence of tracing
1374 * qualifiers.
1375 */
1376 int (*func)();
1377
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001378 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001379 return 0;
1380
1381 func = sysent[tcp->scno].sys_func;
1382
1383 if ( sys_fork == func
1384#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
1385 || sys_vfork == func
1386#endif
1387#ifdef LINUX
1388 || sys_clone == func
1389#endif
1390#if UNIXWARE > 2
1391 || sys_rfork == func
1392#endif
1393 )
1394 return internal_fork(tcp);
1395
1396#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
1397 if ( sys_execve == func
1398# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
1399 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001400# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001401# if UNIXWARE > 2
1402 || sys_rexecve == func
1403# endif
1404 )
1405 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001406#endif
1407
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001408 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001409}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001410
Roland McGratha4d48532005-06-08 20:45:28 +00001411static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001412syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001413{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001414#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001415 int i, nargs;
1416
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001417 if (SCNO_IN_RANGE(tcp->scno))
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001418 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001419 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001420 nargs = tcp->u_nargs = MAX_ARGS;
1421
1422# if defined(S390) || defined(S390X)
1423 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001424 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1425 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001426# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001427 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001428 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1429 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001430# elif defined(IA64)
1431 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001432 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001433 long rbs_end;
1434 /* be backwards compatible with kernel < 2.4.4... */
1435# ifndef PT_RBS_END
1436# define PT_RBS_END PT_AR_BSP
1437# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001438
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001439 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1440 return -1;
1441 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001442 return -1;
1443
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001444 sof = (cfm >> 0) & 0x7f;
1445 sol = (cfm >> 7) & 0x7f;
1446 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1447
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001448 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001449 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1450 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1451 return -1;
1452 }
1453 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001454 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1455 PT_R9 /* ECX = out1 */,
1456 PT_R10 /* EDX = out2 */,
1457 PT_R14 /* ESI = out3 */,
1458 PT_R15 /* EDI = out4 */,
1459 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001460
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001461 for (i = 0; i < nargs; ++i) {
1462 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1463 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001464 /* truncate away IVE sign-extension */
1465 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001466 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001467 }
1468# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
1469 /* N32 and N64 both use up to six registers. */
1470 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001471
1472 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1473 return -1;
1474
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001475 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001476 tcp->u_arg[i] = regs[REG_A0 + i];
1477# if defined(LINUX_MIPSN32)
1478 tcp->ext_arg[i] = regs[REG_A0 + i];
1479# endif
1480 }
1481# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001482 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001483 long sp;
1484
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001485 if (upeek(tcp, REG_SP, &sp) < 0)
1486 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001487 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001488 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1489 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001490 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001491 (char *)(tcp->u_arg + 4));
1492 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001493 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001494 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001495 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001496 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001497# elif defined(POWERPC)
1498# ifndef PT_ORIG_R3
1499# define PT_ORIG_R3 34
1500# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001501 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001502 if (upeek(tcp, (i==0) ?
1503 (sizeof(unsigned long) * PT_ORIG_R3) :
1504 ((i+PT_R3) * sizeof(unsigned long)),
1505 &tcp->u_arg[i]) < 0)
1506 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001508# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001509 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001510 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
1511# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001512 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001513 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1514 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001515# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001516 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001517 tcp->u_arg[i] = regs.uregs[i];
1518# elif defined(AVR32)
Denys Vlasenkob5b25892011-08-30 19:04:54 +02001519 (void)i;
1520 (void)nargs;
1521 tcp->u_arg[0] = regs.r12;
1522 tcp->u_arg[1] = regs.r11;
1523 tcp->u_arg[2] = regs.r10;
1524 tcp->u_arg[3] = regs.r9;
1525 tcp->u_arg[4] = regs.r5;
1526 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001527# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001528 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 +02001529
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001530 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001531 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1532 return -1;
1533# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001534 static const int syscall_regs[MAX_ARGS] = {
1535 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1536 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001537 };
1538
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001539 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001540 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001541 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001542# elif defined(SH64)
1543 int i;
1544 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001545 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001546
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001547 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001548 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1549 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001550# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001551 (void)i;
1552 (void)nargs;
1553 if (current_personality == 0) { /* x86-64 ABI */
1554 tcp->u_arg[0] = x86_64_regs.rdi;
1555 tcp->u_arg[1] = x86_64_regs.rsi;
1556 tcp->u_arg[2] = x86_64_regs.rdx;
1557 tcp->u_arg[3] = x86_64_regs.r10;
1558 tcp->u_arg[4] = x86_64_regs.r8;
1559 tcp->u_arg[5] = x86_64_regs.r9;
1560 } else { /* i386 ABI */
1561 /* Sign-extend lower 32 bits */
1562 tcp->u_arg[0] = (long)(int)x86_64_regs.rbx;
1563 tcp->u_arg[1] = (long)(int)x86_64_regs.rcx;
1564 tcp->u_arg[2] = (long)(int)x86_64_regs.rdx;
1565 tcp->u_arg[3] = (long)(int)x86_64_regs.rsi;
1566 tcp->u_arg[4] = (long)(int)x86_64_regs.rdi;
1567 tcp->u_arg[5] = (long)(int)x86_64_regs.rbp;
1568 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001569# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001570 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001571 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1572 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001573# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001574 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001575 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001576 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001577 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001578
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001579 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001580 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1581 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001582# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001583 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001584 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1585 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001586# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001587 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001588 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1589 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001590# elif defined(I386)
1591 (void)i;
1592 (void)nargs;
1593 tcp->u_arg[0] = i386_regs.ebx;
1594 tcp->u_arg[1] = i386_regs.ecx;
1595 tcp->u_arg[2] = i386_regs.edx;
1596 tcp->u_arg[3] = i386_regs.esi;
1597 tcp->u_arg[4] = i386_regs.edi;
1598 tcp->u_arg[5] = i386_regs.ebp;
1599# else /* Other architecture (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001600 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001601 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1602 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001603# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001604#endif /* LINUX */
1605#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001606 int i, nargs;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001607 if (SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001608 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001609 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001610 nargs = tcp->u_nargs = MAX_ARGS;
1611 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001612 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001614 if (upeek(tcp, uoff(u_arg[0]) +
1615 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1616 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617 }
1618#endif /* SUNOS4 */
1619#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001620# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 /*
1622 * SGI is broken: even though it has pr_sysarg, it doesn't
1623 * set them on system call entry. Get a clue.
1624 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001625 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001626 tcp->u_nargs = sysent[tcp->scno].nargs;
1627 else
1628 tcp->u_nargs = tcp->status.pr_nsysarg;
1629 if (tcp->u_nargs > 4) {
1630 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001631 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001633 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634 }
1635 else {
1636 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001637 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001638 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001639# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00001640 /*
1641 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1642 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001643 if (SCNO_IN_RANGE(tcp->scno))
John Hughes25299712001-03-06 10:10:06 +00001644 tcp->u_nargs = sysent[tcp->scno].nargs;
1645 else
1646 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1647 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001648 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1649# elif defined(HAVE_PR_SYSCALL)
1650 int i;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001651 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652 tcp->u_nargs = sysent[tcp->scno].nargs;
1653 else
1654 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001655 for (i = 0; i < tcp->u_nargs; i++)
1656 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1657# elif defined(I386)
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001658 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659 tcp->u_nargs = sysent[tcp->scno].nargs;
1660 else
1661 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02001662 if (tcp->u_nargs > 0)
1663 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001664 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1665# else
John Hughes25299712001-03-06 10:10:06 +00001666 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001667# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001668#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001669#ifdef FREEBSD
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001670 if (SCNO_IN_RANGE(tcp->scno) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001671 sysent[tcp->scno].nargs > tcp->status.val)
1672 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001673 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001674 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001675 if (tcp->u_nargs < 0)
1676 tcp->u_nargs = 0;
1677 if (tcp->u_nargs > MAX_ARGS)
1678 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001679 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001680 case SYS___syscall:
1681 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1682 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001683 break;
1684 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001685 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1686 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001687 break;
1688 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001689 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1690 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001691 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001692 }
1693#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001694 return 1;
1695}
1696
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001697static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001698trace_syscall_entering(struct tcb *tcp)
1699{
1700 int res, scno_good;
1701
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001702#if defined TCB_WAITEXECVE
1703 if (tcp->flags & TCB_WAITEXECVE) {
1704 /* This is the post-execve SIGTRAP. */
1705 tcp->flags &= ~TCB_WAITEXECVE;
1706 return 0;
1707 }
1708#endif
1709
Denys Vlasenko06602d92011-08-24 17:53:52 +02001710 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001711 if (res == 0)
1712 return res;
1713 if (res == 1)
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001714 res = syscall_fixup_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001715 if (res == 0)
1716 return res;
1717 if (res == 1)
1718 res = syscall_enter(tcp);
1719 if (res == 0)
1720 return res;
1721
1722 if (res != 1) {
1723 printleader(tcp);
1724 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001725 if (scno_good != 1)
1726 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001727 else if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001728 tprintf("syscall_%lu(", tcp->scno);
1729 else
1730 tprintf("%s(", sysent[tcp->scno].sys_name);
1731 /*
1732 * " <unavailable>" will be added later by the code which
1733 * detects ptrace errors.
1734 */
1735 goto ret;
1736 }
1737
1738 switch (known_scno(tcp)) {
1739#ifdef SYS_socket_subcall
1740 case SYS_socketcall:
1741 decode_subcall(tcp, SYS_socket_subcall,
1742 SYS_socket_nsubcalls, deref_style);
1743 break;
1744#endif
1745#ifdef SYS_ipc_subcall
1746 case SYS_ipc:
1747 decode_subcall(tcp, SYS_ipc_subcall,
1748 SYS_ipc_nsubcalls, shift_style);
1749 break;
1750#endif
1751#ifdef SVR4
1752#ifdef SYS_pgrpsys_subcall
1753 case SYS_pgrpsys:
1754 decode_subcall(tcp, SYS_pgrpsys_subcall,
1755 SYS_pgrpsys_nsubcalls, shift_style);
1756 break;
1757#endif /* SYS_pgrpsys_subcall */
1758#ifdef SYS_sigcall_subcall
1759 case SYS_sigcall:
1760 decode_subcall(tcp, SYS_sigcall_subcall,
1761 SYS_sigcall_nsubcalls, mask_style);
1762 break;
1763#endif /* SYS_sigcall_subcall */
1764 case SYS_msgsys:
1765 decode_subcall(tcp, SYS_msgsys_subcall,
1766 SYS_msgsys_nsubcalls, shift_style);
1767 break;
1768 case SYS_shmsys:
1769 decode_subcall(tcp, SYS_shmsys_subcall,
1770 SYS_shmsys_nsubcalls, shift_style);
1771 break;
1772 case SYS_semsys:
1773 decode_subcall(tcp, SYS_semsys_subcall,
1774 SYS_semsys_nsubcalls, shift_style);
1775 break;
1776 case SYS_sysfs:
1777 decode_subcall(tcp, SYS_sysfs_subcall,
1778 SYS_sysfs_nsubcalls, shift_style);
1779 break;
1780 case SYS_spcall:
1781 decode_subcall(tcp, SYS_spcall_subcall,
1782 SYS_spcall_nsubcalls, shift_style);
1783 break;
1784#ifdef SYS_context_subcall
1785 case SYS_context:
1786 decode_subcall(tcp, SYS_context_subcall,
1787 SYS_context_nsubcalls, shift_style);
1788 break;
1789#endif /* SYS_context_subcall */
1790#ifdef SYS_door_subcall
1791 case SYS_door:
1792 decode_subcall(tcp, SYS_door_subcall,
1793 SYS_door_nsubcalls, door_style);
1794 break;
1795#endif /* SYS_door_subcall */
1796#ifdef SYS_kaio_subcall
1797 case SYS_kaio:
1798 decode_subcall(tcp, SYS_kaio_subcall,
1799 SYS_kaio_nsubcalls, shift_style);
1800 break;
1801#endif
1802#endif /* SVR4 */
1803#ifdef FREEBSD
1804 case SYS_msgsys:
1805 case SYS_shmsys:
1806 case SYS_semsys:
1807 decode_subcall(tcp, 0, 0, table_style);
1808 break;
1809#endif
1810#ifdef SUNOS4
1811 case SYS_semsys:
1812 decode_subcall(tcp, SYS_semsys_subcall,
1813 SYS_semsys_nsubcalls, shift_style);
1814 break;
1815 case SYS_msgsys:
1816 decode_subcall(tcp, SYS_msgsys_subcall,
1817 SYS_msgsys_nsubcalls, shift_style);
1818 break;
1819 case SYS_shmsys:
1820 decode_subcall(tcp, SYS_shmsys_subcall,
1821 SYS_shmsys_nsubcalls, shift_style);
1822 break;
1823#endif
1824 }
1825
1826 internal_syscall(tcp);
1827
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001828 if ((SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001829 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1830 (tracing_paths && !pathtrace_match(tcp))) {
1831 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1832 return 0;
1833 }
1834
1835 tcp->flags &= ~TCB_FILTERED;
1836
1837 if (cflag == CFLAG_ONLY_STATS) {
1838 res = 0;
1839 goto ret;
1840 }
1841
1842 printleader(tcp);
1843 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001844 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001845 tprintf("syscall_%lu(", tcp->scno);
1846 else
1847 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001848 if (!SCNO_IN_RANGE(tcp->scno) ||
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001849 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1850 sysent[tcp->scno].sys_func != sys_exit))
1851 res = printargs(tcp);
1852 else
1853 res = (*sysent[tcp->scno].sys_func)(tcp);
1854
1855 if (fflush(tcp->outf) == EOF)
1856 return -1;
1857 ret:
1858 tcp->flags |= TCB_INSYSCALL;
1859 /* Measure the entrance time as late as possible to avoid errors. */
1860 if (dtime || cflag)
1861 gettimeofday(&tcp->etime, NULL);
1862 return res;
1863}
1864
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001865/* Returns:
1866 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1867 * 1: ok, continue in trace_syscall().
1868 * other: error, trace_syscall() should print error indicator
1869 * ("????" etc) and bail out.
1870 */
1871static int
1872get_syscall_result(struct tcb *tcp)
1873{
1874#ifdef LINUX
1875# if defined(S390) || defined(S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001876 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
1877 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001878# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001879# define SO_MASK 0x10000000
1880 {
1881 long flags;
1882 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1883 return -1;
1884 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
1885 return -1;
1886 if (flags & SO_MASK)
1887 result = -result;
1888 }
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001889# elif defined(AVR32)
1890 /* Read complete register set in one go. */
1891 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1892 return -1;
1893# elif defined(BFIN)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001894 if (upeek(tcp, PT_R0, &r0) < 0)
1895 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001896# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001897 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001898 return -1;
1899# elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001900 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001901 return -1;
1902# elif defined(IA64)
1903# define IA64_PSR_IS ((long)1 << 34)
1904 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1905 ia32 = (psr & IA64_PSR_IS) != 0;
1906 if (upeek(tcp, PT_R8, &r8) < 0)
1907 return -1;
1908 if (upeek(tcp, PT_R10, &r10) < 0)
1909 return -1;
1910# elif defined (ARM)
1911 /* Read complete register set in one go. */
1912 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1913 return -1;
1914# elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001915 if (upeek(tcp, 4*PT_D0, &d0) < 0)
1916 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001917# elif defined (LINUX_MIPSN32)
1918 unsigned long long regs[38];
1919
1920 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1921 return -1;
1922 a3 = regs[REG_A3];
1923 r2 = regs[REG_V0];
1924# elif defined (MIPS)
1925 if (upeek(tcp, REG_A3, &a3) < 0)
1926 return -1;
1927 if (upeek(tcp, REG_V0, &r2) < 0)
1928 return -1;
1929# elif defined (ALPHA)
1930 if (upeek(tcp, REG_A3, &a3) < 0)
1931 return -1;
1932 if (upeek(tcp, REG_R0, &r0) < 0)
1933 return -1;
1934# elif defined (SPARC) || defined (SPARC64)
1935 /* Everything we need is in the current register set. */
1936 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1937 return -1;
1938# elif defined(HPPA)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001939 if (upeek(tcp, PT_GR28, &r28) < 0)
1940 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001941# elif defined(SH)
1942# elif defined(SH64)
1943# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001944 if (upeek(tcp, 4*PT_R10, &r10) < 0)
1945 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001946# elif defined(TILE)
1947# elif defined(MICROBLAZE)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001948 if (upeek(tcp, 3 * 4, &r3) < 0)
1949 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001950# endif
1951#endif /* LINUX */
1952
1953#ifdef SUNOS4
1954#elif defined(SH)
1955 /* new syscall ABI returns result in R0 */
1956 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1957 return -1;
1958#elif defined(SH64)
1959 /* ABI defines result returned in r9 */
1960 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1961 return -1;
1962#endif
1963
1964#ifdef USE_PROCFS
1965# ifndef HAVE_PR_SYSCALL
1966# ifdef FREEBSD
1967 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1968 perror("pread");
1969 return -1;
1970 }
1971# endif /* FREEBSD */
1972# endif /* !HAVE_PR_SYSCALL */
1973#endif /* USE_PROCFS */
1974
1975 return 1;
1976}
1977
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001978/* Called at each syscall exit.
1979 * Returns:
1980 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1981 * 1: ok, continue in trace_syscall().
1982 * other: error, trace_syscall() should print error indicator
1983 * ("????" etc) and bail out.
1984 */
1985static int
1986syscall_fixup_on_sysexit(struct tcb *tcp)
1987{
1988#ifdef USE_PROCFS
Denys Vlasenkoece98792011-08-25 10:25:35 +02001989 if (tcp->status.PR_WHY != PR_SYSEXIT) {
1990 fprintf(stderr, "syscall: missing exit\n");
1991 tcp->flags &= ~TCB_INSYSCALL;
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001992 }
1993#endif /* USE_PROCFS */
1994
1995#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001996 {
1997 int scno = known_scno(tcp);
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001998 if (scno != 0) {
1999 if (debug) {
2000 /*
2001 * This happens when a signal handler
2002 * for a signal which interrupted a
2003 * a system call makes another system call.
2004 */
2005 fprintf(stderr, "syscall: missing exit\n");
2006 }
2007 tcp->flags &= ~TCB_INSYSCALL;
2008 }
2009 }
2010#endif /* SUNOS4 */
2011
2012#ifdef LINUX
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002013# if defined (S390) || defined (S390X)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002014 if (syscall_mode != -ENOSYS)
2015 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02002016 if ((tcp->flags & TCB_WAITEXECVE)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002017 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
2018 /*
2019 * Return from execve.
2020 * Fake a return value of zero. We leave the TCB_WAITEXECVE
2021 * flag set for the post-execve SIGTRAP to see and reset.
2022 */
2023 gpr2 = 0;
2024 }
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002025# endif
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002026#endif /* LINUX */
2027 return 1;
2028}
2029
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002030#ifdef LINUX
2031/*
2032 * Check the syscall return value register value for whether it is
2033 * a negated errno code indicating an error, or a success return value.
2034 */
2035static inline int
2036is_negated_errno(unsigned long int val)
2037{
2038 unsigned long int max = -(long int) nerrnos;
2039# if SUPPORTED_PERSONALITIES > 1
2040 if (personality_wordsize[current_personality] < sizeof(val)) {
2041 val = (unsigned int) val;
2042 max = (unsigned int) max;
2043 }
2044# endif
2045 return val > max;
2046}
2047#endif
2048
2049static int
2050get_error(struct tcb *tcp)
2051{
2052 int u_error = 0;
2053#ifdef LINUX
2054 int check_errno = 1;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002055 if (SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002056 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2057 check_errno = 0;
2058 }
2059# if defined(S390) || defined(S390X)
2060 if (check_errno && is_negated_errno(gpr2)) {
2061 tcp->u_rval = -1;
2062 u_error = -gpr2;
2063 }
2064 else {
2065 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002066 }
2067# elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002068 if (check_errno && is_negated_errno(i386_regs.eax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002069 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002070 u_error = -i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002071 }
2072 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002073 tcp->u_rval = i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002074 }
2075# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002076 if (check_errno && is_negated_errno(x86_64_regs.rax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002077 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002078 u_error = -x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002079 }
2080 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002081 tcp->u_rval = x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002082 }
2083# elif defined(IA64)
2084 if (ia32) {
2085 int err;
2086
2087 err = (int)r8;
2088 if (check_errno && is_negated_errno(err)) {
2089 tcp->u_rval = -1;
2090 u_error = -err;
2091 }
2092 else {
2093 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002094 }
2095 } else {
2096 if (check_errno && r10) {
2097 tcp->u_rval = -1;
2098 u_error = r8;
2099 } else {
2100 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002101 }
2102 }
2103# elif defined(MIPS)
2104 if (check_errno && a3) {
2105 tcp->u_rval = -1;
2106 u_error = r2;
2107 } else {
2108 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002109 }
2110# elif defined(POWERPC)
2111 if (check_errno && is_negated_errno(result)) {
2112 tcp->u_rval = -1;
2113 u_error = -result;
2114 }
2115 else {
2116 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002117 }
2118# elif defined(M68K)
2119 if (check_errno && is_negated_errno(d0)) {
2120 tcp->u_rval = -1;
2121 u_error = -d0;
2122 }
2123 else {
2124 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002125 }
2126# elif defined(ARM)
2127 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2128 tcp->u_rval = -1;
2129 u_error = -regs.ARM_r0;
2130 }
2131 else {
2132 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002133 }
2134# elif defined(AVR32)
2135 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2136 tcp->u_rval = -1;
2137 u_error = -regs.r12;
2138 }
2139 else {
2140 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002141 }
2142# elif defined(BFIN)
2143 if (check_errno && is_negated_errno(r0)) {
2144 tcp->u_rval = -1;
2145 u_error = -r0;
2146 } else {
2147 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002148 }
2149# elif defined(ALPHA)
2150 if (check_errno && a3) {
2151 tcp->u_rval = -1;
2152 u_error = r0;
2153 }
2154 else {
2155 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002156 }
2157# elif defined(SPARC)
2158 if (check_errno && regs.psr & PSR_C) {
2159 tcp->u_rval = -1;
2160 u_error = regs.u_regs[U_REG_O0];
2161 }
2162 else {
2163 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002164 }
2165# elif defined(SPARC64)
2166 if (check_errno && regs.tstate & 0x1100000000UL) {
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(HPPA)
2174 if (check_errno && is_negated_errno(r28)) {
2175 tcp->u_rval = -1;
2176 u_error = -r28;
2177 }
2178 else {
2179 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002180 }
2181# elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002182 if (check_errno && is_negated_errno(r0)) {
2183 tcp->u_rval = -1;
2184 u_error = -r0;
2185 }
2186 else {
2187 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002188 }
2189# elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002190 if (check_errno && is_negated_errno(r9)) {
2191 tcp->u_rval = -1;
2192 u_error = -r9;
2193 }
2194 else {
2195 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002196 }
2197# elif defined(CRISV10) || defined(CRISV32)
2198 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2199 tcp->u_rval = -1;
2200 u_error = -r10;
2201 }
2202 else {
2203 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002204 }
2205# elif defined(TILE)
2206 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002207 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2208 return -1;
2209 if (check_errno && rval < 0 && rval > -nerrnos) {
2210 tcp->u_rval = -1;
2211 u_error = -rval;
2212 }
2213 else {
2214 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002215 }
2216# elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002217 if (check_errno && is_negated_errno(r3)) {
2218 tcp->u_rval = -1;
2219 u_error = -r3;
2220 }
2221 else {
2222 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002223 }
2224# endif
2225#endif /* LINUX */
2226#ifdef SUNOS4
2227 /* get error code from user struct */
2228 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2229 return -1;
2230 u_error >>= 24; /* u_error is a char */
2231
2232 /* get system call return value */
2233 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2234 return -1;
2235#endif /* SUNOS4 */
2236#ifdef SVR4
2237# ifdef SPARC
2238 /* Judicious guessing goes a long way. */
2239 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2240 tcp->u_rval = -1;
2241 u_error = tcp->status.pr_reg[R_O0];
2242 }
2243 else {
2244 tcp->u_rval = tcp->status.pr_reg[R_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002245 }
2246# endif /* SPARC */
2247# ifdef I386
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002248 if (tcp->status.PR_REG[EFL] & 0x1) {
2249 tcp->u_rval = -1;
2250 u_error = tcp->status.PR_REG[EAX];
2251 }
2252 else {
2253 tcp->u_rval = tcp->status.PR_REG[EAX];
2254# ifdef HAVE_LONG_LONG
2255 tcp->u_lrval =
2256 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2257 tcp->status.PR_REG[EAX];
2258# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002259 }
2260# endif /* I386 */
2261# ifdef X86_64
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002262 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2263 tcp->u_rval = -1;
2264 u_error = tcp->status.PR_REG[RAX];
2265 }
2266 else {
2267 tcp->u_rval = tcp->status.PR_REG[RAX];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002268 }
2269# endif /* X86_64 */
2270# ifdef MIPS
2271 if (tcp->status.pr_reg[CTX_A3]) {
2272 tcp->u_rval = -1;
2273 u_error = tcp->status.pr_reg[CTX_V0];
2274 }
2275 else {
2276 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002277 }
2278# endif /* MIPS */
2279#endif /* SVR4 */
2280#ifdef FREEBSD
2281 if (regs.r_eflags & PSL_C) {
2282 tcp->u_rval = -1;
2283 u_error = regs.r_eax;
2284 } else {
2285 tcp->u_rval = regs.r_eax;
2286 tcp->u_lrval =
Denys Vlasenko684fb1a2011-08-25 00:26:38 +02002287 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002288 }
2289#endif /* FREEBSD */
2290 tcp->u_error = u_error;
2291 return 1;
2292}
2293
2294static void
2295dumpio(struct tcb *tcp)
2296{
2297 if (syserror(tcp))
2298 return;
2299 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
2300 return;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002301 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002302 return;
2303 if (sysent[tcp->scno].sys_func == printargs)
2304 return;
2305 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
2306 if (sysent[tcp->scno].sys_func == sys_read ||
2307 sysent[tcp->scno].sys_func == sys_pread ||
2308 sysent[tcp->scno].sys_func == sys_pread64 ||
2309 sysent[tcp->scno].sys_func == sys_recv ||
2310 sysent[tcp->scno].sys_func == sys_recvfrom)
2311 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
2312 else if (sysent[tcp->scno].sys_func == sys_readv)
2313 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2314 return;
2315 }
2316 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
2317 if (sysent[tcp->scno].sys_func == sys_write ||
2318 sysent[tcp->scno].sys_func == sys_pwrite ||
2319 sysent[tcp->scno].sys_func == sys_pwrite64 ||
2320 sysent[tcp->scno].sys_func == sys_send ||
2321 sysent[tcp->scno].sys_func == sys_sendto)
2322 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
2323 else if (sysent[tcp->scno].sys_func == sys_writev)
2324 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2325 return;
2326 }
2327}
2328
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002329static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002330trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002331{
2332 int sys_res;
2333 struct timeval tv;
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002334 int res;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002335 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002336
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002337 /* Measure the exit time as early as possible to avoid errors. */
2338 if (dtime || cflag)
2339 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002340
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00002341#if SUPPORTED_PERSONALITIES > 1
2342 update_personality(tcp, tcp->currpers);
2343#endif
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002344 res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002345 if (res == 0)
2346 return res;
2347 if (res == 1)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002348 res = syscall_fixup_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002349 if (res == 0)
2350 return res;
2351 if (res == 1)
2352 res = get_error(tcp);
2353 if (res == 0)
2354 return res;
2355 if (res == 1)
2356 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002357
Grant Edwards8a082772011-04-07 20:25:40 +00002358 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002359 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002360 }
2361
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002362 if (tcp->flags & TCB_REPRINT) {
2363 printleader(tcp);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002364 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002365 tprintf("<... syscall_%lu resumed> ", tcp->scno);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002366 else
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002367 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002368 }
2369
2370 if (cflag) {
2371 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002372 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002373 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002374 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002375 }
2376 }
2377
2378 if (res != 1) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002379 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002380 tabto();
Denys Vlasenko000b6012012-01-28 01:25:03 +01002381 tprints("= ? <unavailable>\n");
2382 printing_tcp = NULL;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002383 tcp->flags &= ~TCB_INSYSCALL;
2384 return res;
2385 }
2386
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002387 if (!SCNO_IN_RANGE(tcp->scno)
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002388 || (qual_flags[tcp->scno] & QUAL_RAW))
2389 sys_res = printargs(tcp);
2390 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002391 /* FIXME: not_failing_only (IOW, option -z) is broken:
2392 * failure of syscall is known only after syscall return.
2393 * Thus we end up with something like this on, say, ENOENT:
2394 * open("doesnt_exist", O_RDONLY <unfinished ...>
2395 * {next syscall decode}
2396 * whereas the intended result is that open(...) line
2397 * is not shown at all.
2398 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002399 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002400 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002401 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2402 }
2403
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002404 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002405 tabto();
Denys Vlasenko3b738812011-08-22 02:06:35 +02002406 u_error = tcp->u_error;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002407 if (!SCNO_IN_RANGE(tcp->scno) ||
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002408 qual_flags[tcp->scno] & QUAL_RAW) {
2409 if (u_error)
2410 tprintf("= -1 (errno %ld)", u_error);
2411 else
2412 tprintf("= %#lx", tcp->u_rval);
2413 }
2414 else if (!(sys_res & RVAL_NONE) && u_error) {
2415 switch (u_error) {
2416#ifdef LINUX
Denys Vlasenkofe585652012-01-12 11:26:34 +01002417 /* Blocked signals do not interrupt any syscalls.
2418 * In this case syscalls don't return ERESTARTfoo codes.
2419 *
2420 * Deadly signals set to SIG_DFL interrupt syscalls
2421 * and kill the process regardless of which of the codes below
2422 * is returned by the interrupted syscall.
2423 * In some cases, kernel forces a kernel-generated deadly
2424 * signal to be unblocked and set to SIG_DFL (and thus cause
2425 * death) if it is blocked or SIG_IGNed: for example, SIGSEGV
2426 * or SIGILL. (The alternative is to leave process spinning
2427 * forever on the faulty instruction - not useful).
2428 *
2429 * SIG_IGNed signals and non-deadly signals set to SIG_DFL
2430 * (for example, SIGCHLD, SIGWINCH) interrupt syscalls,
2431 * but kernel will always restart them.
2432 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002433 case ERESTARTSYS:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002434 /* Most common type of signal-interrupted syscall exit code.
2435 * The system call will be restarted with the same arguments
2436 * if SA_RESTART is set; otherwise, it will fail with EINTR.
2437 */
2438 tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002439 break;
2440 case ERESTARTNOINTR:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002441 /* Rare. For example, fork() returns this if interrupted.
2442 * SA_RESTART is ignored (assumed set): the restart is unconditional.
2443 */
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002444 tprints("= ? ERESTARTNOINTR (To be restarted)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002445 break;
2446 case ERESTARTNOHAND:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002447 /* pause(), rt_sigsuspend() etc use this code.
2448 * SA_RESTART is ignored (assumed not set):
2449 * syscall won't restart (will return EINTR instead)
2450 * even after signal with SA_RESTART set.
2451 * However, after SIG_IGN or SIG_DFL signal it will.
2452 */
2453 tprints("= ? ERESTARTNOHAND (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002454 break;
2455 case ERESTART_RESTARTBLOCK:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002456 /* Syscalls like nanosleep(), poll() which can't be
2457 * restarted with their original arguments use this
2458 * code. Kernel will execute restart_syscall() instead,
2459 * which changes arguments before restarting syscall.
2460 * SA_RESTART is ignored (assumed not set) similarly
2461 * to ERESTARTNOHAND. (Kernel can't honor SA_RESTART
2462 * since restart data is saved in "restart block"
2463 * in task struct, and if signal handler uses a syscall
2464 * which in turn saves another such restart block,
2465 * old data is lost and restart becomes impossible)
2466 */
2467 tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002468 break;
2469#endif /* LINUX */
2470 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002471 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002472 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002473 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002474 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002475 strerror(u_error));
2476 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002477 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002478 strerror(u_error));
2479 break;
2480 }
2481 if ((sys_res & RVAL_STR) && tcp->auxstr)
2482 tprintf(" (%s)", tcp->auxstr);
2483 }
2484 else {
2485 if (sys_res & RVAL_NONE)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002486 tprints("= ?");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002487 else {
2488 switch (sys_res & RVAL_MASK) {
2489 case RVAL_HEX:
2490 tprintf("= %#lx", tcp->u_rval);
2491 break;
2492 case RVAL_OCTAL:
2493 tprintf("= %#lo", tcp->u_rval);
2494 break;
2495 case RVAL_UDECIMAL:
2496 tprintf("= %lu", tcp->u_rval);
2497 break;
2498 case RVAL_DECIMAL:
2499 tprintf("= %ld", tcp->u_rval);
2500 break;
2501#ifdef HAVE_LONG_LONG
2502 case RVAL_LHEX:
2503 tprintf("= %#llx", tcp->u_lrval);
2504 break;
2505 case RVAL_LOCTAL:
2506 tprintf("= %#llo", tcp->u_lrval);
2507 break;
2508 case RVAL_LUDECIMAL:
2509 tprintf("= %llu", tcp->u_lrval);
2510 break;
2511 case RVAL_LDECIMAL:
2512 tprintf("= %lld", tcp->u_lrval);
2513 break;
2514#endif
2515 default:
2516 fprintf(stderr,
2517 "invalid rval format\n");
2518 break;
2519 }
2520 }
2521 if ((sys_res & RVAL_STR) && tcp->auxstr)
2522 tprintf(" (%s)", tcp->auxstr);
2523 }
2524 if (dtime) {
2525 tv_sub(&tv, &tv, &tcp->etime);
2526 tprintf(" <%ld.%06ld>",
2527 (long) tv.tv_sec, (long) tv.tv_usec);
2528 }
Denys Vlasenko000b6012012-01-28 01:25:03 +01002529 tprints("\n");
2530 printing_tcp = NULL;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002531
2532 dumpio(tcp);
2533 if (fflush(tcp->outf) == EOF)
2534 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002535 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002536 tcp->flags &= ~TCB_INSYSCALL;
2537 return 0;
2538}
2539
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002540int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002541trace_syscall(struct tcb *tcp)
2542{
2543 return exiting(tcp) ?
2544 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2545}