blob: 9c04cf90fe0080b907b5bcc2429ce03397148849 [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
734struct tcb *tcp_last = NULL;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000735
736#ifdef LINUX
Denys Vlasenkob11322f2012-01-10 16:40:35 +0100737# if defined(I386)
738struct pt_regs i386_regs;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200739# elif defined(X86_64)
Denys Vlasenkoe73a89d2012-01-18 11:07:24 +0100740/*
741 * On 32 bits, pt_regs and user_regs_struct are the same,
742 * but on 64 bits, user_regs_struct has six more fields:
743 * fs_base, gs_base, ds, es, fs, gs.
744 * PTRACE_GETREGS fills them too, so struct pt_regs would overflow.
745 */
746static struct user_regs_struct x86_64_regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200747# elif defined (IA64)
748long r8, r10, psr; /* TODO: make static? */
749long ia32 = 0; /* not static */
750# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +0200751static long result;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200752# elif defined (M68K)
753static long d0;
754# elif defined(BFIN)
755static long r0;
756# elif defined (ARM)
757static struct pt_regs regs;
758# elif defined (ALPHA)
759static long r0;
760static long a3;
761# elif defined(AVR32)
762static struct pt_regs regs;
763# elif defined (SPARC) || defined (SPARC64)
764static struct pt_regs regs;
765static unsigned long trap;
766# elif defined(LINUX_MIPSN32)
767static long long a3;
768static long long r2;
769# elif defined(MIPS)
770static long a3;
771static long r2;
772# elif defined(S390) || defined(S390X)
773static long gpr2;
774static long pc;
775static long syscall_mode;
776# elif defined(HPPA)
777static long r28;
778# elif defined(SH)
779static long r0;
780# elif defined(SH64)
781static long r9;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200782# elif defined(CRISV10) || defined(CRISV32)
783static long r10;
784# elif defined(MICROBLAZE)
785static long r3;
786# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000787#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000788#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200789struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000790#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000791
Denys Vlasenkob88f9612011-08-21 18:03:23 +0200792/* Returns:
793 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
794 * 1: ok, continue in trace_syscall().
795 * other: error, trace_syscall() should print error indicator
796 * ("????" etc) and bail out.
797 */
Denys Vlasenko9a36ae52011-08-24 16:47:32 +0200798#ifndef USE_PROCFS
799static
800#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000801int
Denys Vlasenko06602d92011-08-24 17:53:52 +0200802get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000803{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000804 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000806#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000807# if defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000808 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200809 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000810
811 if (syscall_mode != -ENOSYS) {
812 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000813 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000814 */
815 scno = syscall_mode;
816 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000817 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000818 * Old style of "passing" the scno via the SVC instruction.
819 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000820 long opcode, offset_reg, tmp;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200821 void *svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200822 static const int gpr_offset[16] = {
823 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
824 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
825 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
826 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
827 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000828
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000829 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000830 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000831 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000832 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000833 if (errno) {
834 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000835 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000836 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000837
838 /*
839 * We have to check if the SVC got executed directly or via an
840 * EXECUTE instruction. In case of EXECUTE it is necessary to do
841 * instruction decoding to derive the system call number.
842 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
843 * so that this doesn't work if a SVC opcode is part of an EXECUTE
844 * opcode. Since there is no way to find out the opcode size this
845 * is the best we can do...
846 */
Michal Ludvig882eda82002-11-11 12:50:47 +0000847 if ((opcode & 0xff00) == 0x0a00) {
848 /* SVC opcode */
849 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000850 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000851 else {
852 /* SVC got executed by EXECUTE instruction */
853
854 /*
855 * Do instruction decoding of EXECUTE. If you really want to
856 * understand this, read the Principles of Operations.
857 */
858 svc_addr = (void *) (opcode & 0xfff);
859
860 tmp = 0;
861 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000862 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000863 return -1;
864 svc_addr += tmp;
865
866 tmp = 0;
867 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000868 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000869 return -1;
870 svc_addr += tmp;
871
Denys Vlasenkofb036672009-01-23 16:30:26 +0000872 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000873 if (errno)
874 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000875# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000876 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000877# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000878 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000879# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000880 tmp = 0;
881 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000882 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000883 return -1;
884
885 scno = (scno | tmp) & 0xff;
886 }
887 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000888# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000889 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000890 return -1;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200891# ifdef POWERPC64
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200892 /* TODO: speed up strace by not doing this at every syscall.
893 * We only need to do it after execve.
894 */
895 int currpers;
896 long val;
897 int pid = tcp->pid;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200898
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200899 /* Check for 64/32 bit mode. */
900 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
901 return -1;
902 /* SF is bit 0 of MSR */
903 if (val < 0)
904 currpers = 0;
905 else
906 currpers = 1;
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000907 update_personality(tcp, currpers);
Andreas Schwabd69fa492010-07-12 21:39:57 +0200908# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000909# elif defined(AVR32)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200910 /* Read complete register set in one go. */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000911 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
912 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200913 scno = regs.r8;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000914# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000915 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000916 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000917# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200918 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000919 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200920 scno = i386_regs.orig_eax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000921# elif defined (X86_64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200922 int currpers;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200923 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
924 return -1;
925 scno = x86_64_regs.orig_rax;
Michal Ludvig0e035502002-09-23 15:41:01 +0000926
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200927 /* Check CS register value. On x86-64 linux it is:
928 * 0x33 for long mode (64 bit)
929 * 0x23 for compatibility mode (32 bit)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200930 */
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200931 switch (x86_64_regs.cs) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200932 case 0x23: currpers = 1; break;
933 case 0x33: currpers = 0; break;
934 default:
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200935 fprintf(stderr, "Unknown value CS=0x%08X while "
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200936 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200937 "PID=%d\n", (int)x86_64_regs.cs, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200938 currpers = current_personality;
939 break;
940 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000941# if 0
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200942 /* This version analyzes the opcode of a syscall instruction.
943 * (int 0x80 on i386 vs. syscall on x86-64)
944 * It works, but is too complicated.
945 */
946 unsigned long val, rip, i;
Michal Ludvig0e035502002-09-23 15:41:01 +0000947
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200948 rip = x86_64_regs.rip;
Roland McGrath761b5d72002-12-15 23:58:31 +0000949
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200950 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
951 rip -= 2;
952 errno = 0;
Michal Ludvig0e035502002-09-23 15:41:01 +0000953
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200954 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200955 if (errno)
956 fprintf(stderr, "ptrace_peektext failed: %s\n",
957 strerror(errno));
958 switch (call & 0xffff) {
959 /* x86-64: syscall = 0x0f 0x05 */
960 case 0x050f: currpers = 0; break;
961 /* i386: int 0x80 = 0xcd 0x80 */
962 case 0x80cd: currpers = 1; break;
963 default:
964 currpers = current_personality;
965 fprintf(stderr,
966 "Unknown syscall opcode (0x%04X) while "
967 "detecting personality of process "
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200968 "PID=%d\n", (int)call, tcp->pid);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200969 break;
970 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000971# endif
Dmitry V. Levina5a839a2011-12-23 00:50:49 +0000972 update_personality(tcp, currpers);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000973# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000974# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200975 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000976 ia32 = (psr & IA64_PSR_IS) != 0;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200977 if (ia32) {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +0200978 if (upeek(tcp, PT_R1, &scno) < 0)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200979 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000980 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200981 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000982 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +0200983 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000984# elif defined (ARM)
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +0200985 /* Read complete register set in one go. */
Denys Vlasenkofb036672009-01-23 16:30:26 +0000986 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +0000987 return -1;
988
989 /*
990 * We only need to grab the syscall number on syscall entry.
991 */
992 if (regs.ARM_ip == 0) {
993 /*
994 * Note: we only deal with only 32-bit CPUs here.
995 */
996 if (regs.ARM_cpsr & 0x20) {
997 /*
998 * Get the Thumb-mode system call number
999 */
1000 scno = regs.ARM_r7;
1001 } else {
1002 /*
1003 * Get the ARM-mode system call number
1004 */
1005 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001006 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001007 if (errno)
1008 return -1;
1009
Roland McGrathf691bd22006-04-25 07:34:41 +00001010 /* Handle the EABI syscall convention. We do not
1011 bother converting structures between the two
1012 ABIs, but basic functionality should work even
1013 if strace and the traced program have different
1014 ABIs. */
1015 if (scno == 0xef000000) {
1016 scno = regs.ARM_r7;
1017 } else {
1018 if ((scno & 0x0ff00000) != 0x0f900000) {
1019 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1020 scno);
1021 return -1;
1022 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001023
Roland McGrathf691bd22006-04-25 07:34:41 +00001024 /*
1025 * Fixup the syscall number
1026 */
1027 scno &= 0x000fffff;
1028 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001029 }
Roland McGrath56703312008-05-20 01:35:55 +00001030 if (scno & 0x0f0000) {
1031 /*
1032 * Handle ARM specific syscall
1033 */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001034 update_personality(tcp, 1);
Roland McGrath56703312008-05-20 01:35:55 +00001035 scno &= 0x0000ffff;
1036 } else
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001037 update_personality(tcp, 0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001038
Roland McGrath0f87c492003-06-03 23:29:04 +00001039 } else {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001040 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1041 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001042 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001043# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001044 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001045 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001046# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001047 unsigned long long regs[38];
1048
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001049 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001050 return -1;
1051 a3 = regs[REG_A3];
1052 r2 = regs[REG_V0];
1053
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001054 scno = r2;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001055 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001056 if (a3 == 0 || a3 == -1) {
1057 if (debug)
1058 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001059 return 0;
1060 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001061 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001062# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001063 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001064 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001065 if (upeek(tcp, REG_V0, &scno) < 0)
1066 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001067
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001068 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001069 if (a3 == 0 || a3 == -1) {
1070 if (debug)
1071 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001072 return 0;
1073 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001074 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001075# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001076 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001078 if (upeek(tcp, REG_R0, &scno) < 0)
1079 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001081 /*
1082 * Do some sanity checks to figure out if it's
1083 * really a syscall entry
1084 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001085 if (!SCNO_IN_RANGE(scno)) {
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001086 if (a3 == 0 || a3 == -1) {
1087 if (debug)
1088 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 return 0;
1090 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001092# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001093 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001094 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001095 return -1;
1096
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001097 /* Disassemble the syscall trap. */
1098 /* Retrieve the syscall trap instruction. */
1099 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001100# if defined(SPARC64)
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001101 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
1102 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001103# else
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001104 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001105# endif
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001106 if (errno)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001107 return -1;
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001108
1109 /* Disassemble the trap to see what personality to use. */
1110 switch (trap) {
1111 case 0x91d02010:
1112 /* Linux/SPARC syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001113 update_personality(tcp, 0);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001114 break;
1115 case 0x91d0206d:
1116 /* Linux/SPARC64 syscall trap. */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001117 update_personality(tcp, 2);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001118 break;
1119 case 0x91d02000:
1120 /* SunOS syscall trap. (pers 1) */
1121 fprintf(stderr, "syscall: SunOS no support\n");
1122 return -1;
1123 case 0x91d02008:
1124 /* Solaris 2.x syscall trap. (per 2) */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001125 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001126 break;
1127 case 0x91d02009:
1128 /* NetBSD/FreeBSD syscall trap. */
1129 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
1130 return -1;
1131 case 0x91d02027:
1132 /* Solaris 2.x gettimeofday */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001133 update_personality(tcp, 1);
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001134 break;
1135 default:
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001136# if defined (SPARC64)
1137 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
1138# else
1139 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
1140# endif
1141 return -1;
1142 }
1143
1144 /* Extract the system call number from the registers. */
1145 if (trap == 0x91d02027)
1146 scno = 156;
1147 else
1148 scno = regs.u_regs[U_REG_G1];
1149 if (scno == 0) {
1150 scno = regs.u_regs[U_REG_O0];
1151 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
1152 }
1153# elif defined(HPPA)
1154 if (upeek(tcp, PT_GR20, &scno) < 0)
1155 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001156# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001157 /*
1158 * In the new syscall ABI, the system call number is in R3.
1159 */
1160 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1161 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001162
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001163 if (scno < 0) {
1164 /* Odd as it may seem, a glibc bug has been known to cause
1165 glibc to issue bogus negative syscall numbers. So for
1166 our purposes, make strace print what it *should* have been */
1167 long correct_scno = (scno & 0xff);
1168 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001169 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001170 "Detected glibc bug: bogus system call"
1171 " number = %ld, correcting to %ld\n",
1172 scno,
1173 correct_scno);
1174 scno = correct_scno;
1175 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001176# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001177 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001178 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001179 scno &= 0xFFFF;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001180# elif defined(CRISV10) || defined(CRISV32)
1181 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1182 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001183# elif defined(TILE)
1184 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1185 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001186# elif defined(MICROBLAZE)
1187 if (upeek(tcp, 0, &scno) < 0)
1188 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001189# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001191
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001193 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001194 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001195#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001196 /* new syscall ABI returns result in R0 */
1197 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1198 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001199#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001200 /* ABI defines result returned in r9 */
1201 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1202 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001204
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001205#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001206# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001207 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001208# else
1209# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001210 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001211# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001212 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001213 perror("pread");
1214 return -1;
1215 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001216 switch (regs.r_eax) {
1217 case SYS_syscall:
1218 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001219 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1220 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001221 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001222 scno = regs.r_eax;
1223 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001224 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001225# endif /* FREEBSD */
1226# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001227#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001228
Denys Vlasenko8cd1acd2011-08-24 16:52:57 +02001229 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001230 return 1;
1231}
1232
Roland McGrath17352792005-06-07 23:21:26 +00001233long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001234known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001235{
1236 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001237#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001238 if (SCNO_IN_RANGE(scno) && sysent[scno].native_scno != 0)
Roland McGrath17352792005-06-07 23:21:26 +00001239 scno = sysent[scno].native_scno;
1240 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001241#endif
Roland McGrath17352792005-06-07 23:21:26 +00001242 scno += NR_SYSCALL_BASE;
1243 return scno;
1244}
1245
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001246/* Called at each syscall entry.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001247 * Returns:
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001248 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
Roland McGratheb9e2e82009-06-02 16:49:22 -07001249 * 1: ok, continue in trace_syscall().
1250 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001251 * ("????" etc) and bail out.
1252 */
Roland McGratha4d48532005-06-08 20:45:28 +00001253static int
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001254syscall_fixup_on_sysenter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001255{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001256#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001257 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001258
Denys Vlasenkoece98792011-08-25 10:25:35 +02001259 if (tcp->status.PR_WHY != PR_SYSENTRY) {
1260 if (
1261 scno == SYS_fork
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262#ifdef SYS_vfork
Denys Vlasenkoece98792011-08-25 10:25:35 +02001263 || scno == SYS_vfork
1264#endif
John Hughes4e36a812001-04-18 15:11:51 +00001265#ifdef SYS_fork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001266 || scno == SYS_fork1
1267#endif
John Hughes4e36a812001-04-18 15:11:51 +00001268#ifdef SYS_forkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001269 || scno == SYS_forkall
1270#endif
John Hughes4e36a812001-04-18 15:11:51 +00001271#ifdef SYS_rfork1
Denys Vlasenkoece98792011-08-25 10:25:35 +02001272 || scno == SYS_rfork1
1273#endif
John Hughes4e36a812001-04-18 15:11:51 +00001274#ifdef SYS_rforkall
Denys Vlasenkoece98792011-08-25 10:25:35 +02001275 || scno == SYS_rforkall
1276#endif
1277 ) {
1278 /* We are returning in the child, fake it. */
1279 tcp->status.PR_WHY = PR_SYSENTRY;
1280 trace_syscall(tcp);
1281 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001282 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001283 else {
1284 fprintf(stderr, "syscall: missing entry\n");
1285 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286 }
1287 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001288#endif /* USE_PROCFS */
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001289
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001290#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02001291 if (scno == 0) {
1292 fprintf(stderr, "syscall: missing entry\n");
1293 tcp->flags |= TCB_INSYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001294 }
Denys Vlasenkoece98792011-08-25 10:25:35 +02001295#endif
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001296
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001297#ifdef LINUX
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001298 /* A common case of "not a syscall entry" is post-execve SIGTRAP */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001299#if defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001300 if (i386_regs.eax != -ENOSYS) {
1301 if (debug)
1302 fprintf(stderr, "not a syscall entry (eax = %ld)\n", i386_regs.eax);
1303 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001305#elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001306 {
1307 long rax = x86_64_regs.rax;
Denys Vlasenko18beb982011-08-24 16:59:23 +02001308 if (current_personality == 1)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001309 rax = (int)rax; /* sign extend from 32 bits */
1310 if (rax != -ENOSYS) {
Denys Vlasenko18beb982011-08-24 16:59:23 +02001311 if (debug)
1312 fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
1313 return 0;
1314 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001315 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001316#elif defined (S390) || defined (S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001317 /* TODO: we already fetched PT_GPR2 in get_scno
1318 * and stored it in syscall_mode, reuse it here
1319 * instead of re-fetching?
1320 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001321 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001322 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001323 if (syscall_mode != -ENOSYS)
1324 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001325 if (gpr2 != syscall_mode) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001326 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001327 fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001328 return 0;
1329 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001330#elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001331 /* TODO? Eliminate upeek's in arches below like we did in x86 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001332 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001334 if (d0 != -ENOSYS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001336 fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001337 return 0;
1338 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001339#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001340 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001341 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001342 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001343 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001344 if (ia32 && r8 != -ENOSYS) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001345 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001346 fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001347 return 0;
1348 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001349#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001350 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001351 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001352 if (r10 != -ENOSYS) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001353 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001354 fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001355 return 0;
1356 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001357#elif defined(MICROBLAZE)
1358 if (upeek(tcp, 3 * 4, &r3) < 0)
1359 return -1;
Denys Vlasenkoece98792011-08-25 10:25:35 +02001360 if (r3 != -ENOSYS) {
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001361 if (debug)
Denys Vlasenkob88f9612011-08-21 18:03:23 +02001362 fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001363 return 0;
1364 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001365#endif
1366#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001367 return 1;
1368}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001370static int
1371internal_syscall(struct tcb *tcp)
Roland McGrathc1e45922008-05-27 23:18:29 +00001372{
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001373 /*
1374 * We must always trace a few critical system calls in order to
1375 * correctly support following forks in the presence of tracing
1376 * qualifiers.
1377 */
1378 int (*func)();
1379
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001380 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001381 return 0;
1382
1383 func = sysent[tcp->scno].sys_func;
1384
1385 if ( sys_fork == func
1386#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
1387 || sys_vfork == func
1388#endif
1389#ifdef LINUX
1390 || sys_clone == func
1391#endif
1392#if UNIXWARE > 2
1393 || sys_rfork == func
1394#endif
1395 )
1396 return internal_fork(tcp);
1397
1398#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
1399 if ( sys_execve == func
1400# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
1401 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001402# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001403# if UNIXWARE > 2
1404 || sys_rexecve == func
1405# endif
1406 )
1407 return internal_exec(tcp);
Roland McGrathc1e45922008-05-27 23:18:29 +00001408#endif
1409
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001410 return 0;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001411}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001412
Roland McGratha4d48532005-06-08 20:45:28 +00001413static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001414syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001415{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001416#ifdef LINUX
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001417 int i, nargs;
1418
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001419 if (SCNO_IN_RANGE(tcp->scno))
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001420 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001421 else
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001422 nargs = tcp->u_nargs = MAX_ARGS;
1423
1424# if defined(S390) || defined(S390X)
1425 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001426 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
1427 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001428# elif defined(ALPHA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001429 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001430 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
1431 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001432# elif defined(IA64)
1433 if (!ia32) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001434 unsigned long *out0, cfm, sof, sol;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001435 long rbs_end;
1436 /* be backwards compatible with kernel < 2.4.4... */
1437# ifndef PT_RBS_END
1438# define PT_RBS_END PT_AR_BSP
1439# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001440
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001441 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
1442 return -1;
1443 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001444 return -1;
1445
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001446 sof = (cfm >> 0) & 0x7f;
1447 sol = (cfm >> 7) & 0x7f;
1448 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
1449
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001450 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001451 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1452 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1453 return -1;
1454 }
1455 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001456 static const int argreg[MAX_ARGS] = { PT_R11 /* EBX = out0 */,
1457 PT_R9 /* ECX = out1 */,
1458 PT_R10 /* EDX = out2 */,
1459 PT_R14 /* ESI = out3 */,
1460 PT_R15 /* EDI = out4 */,
1461 PT_R13 /* EBP = out5 */};
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001462
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001463 for (i = 0; i < nargs; ++i) {
1464 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1465 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001466 /* truncate away IVE sign-extension */
1467 tcp->u_arg[i] &= 0xffffffff;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001468 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001469 }
1470# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
1471 /* N32 and N64 both use up to six registers. */
1472 unsigned long long regs[38];
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001473
1474 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1475 return -1;
1476
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001477 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001478 tcp->u_arg[i] = regs[REG_A0 + i];
1479# if defined(LINUX_MIPSN32)
1480 tcp->ext_arg[i] = regs[REG_A0 + i];
1481# endif
1482 }
1483# elif defined(MIPS)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001484 if (nargs > 4) {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001485 long sp;
1486
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001487 if (upeek(tcp, REG_SP, &sp) < 0)
1488 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001489 for (i = 0; i < 4; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001490 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
1491 return -1;
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001492 umoven(tcp, sp + 16, (nargs - 4) * sizeof(tcp->u_arg[0]),
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001493 (char *)(tcp->u_arg + 4));
1494 } else {
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001495 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001496 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001497 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001498 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001499# elif defined(POWERPC)
1500# ifndef PT_ORIG_R3
1501# define PT_ORIG_R3 34
1502# endif
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001503 for (i = 0; i < nargs; ++i) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001504 if (upeek(tcp, (i==0) ?
1505 (sizeof(unsigned long) * PT_ORIG_R3) :
1506 ((i+PT_R3) * sizeof(unsigned long)),
1507 &tcp->u_arg[i]) < 0)
1508 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001509 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001510# elif defined(SPARC) || defined(SPARC64)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001511 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001512 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
1513# elif defined(HPPA)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001514 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001515 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
1516 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001517# elif defined(ARM)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001518 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001519 tcp->u_arg[i] = regs.uregs[i];
1520# elif defined(AVR32)
Denys Vlasenkob5b25892011-08-30 19:04:54 +02001521 (void)i;
1522 (void)nargs;
1523 tcp->u_arg[0] = regs.r12;
1524 tcp->u_arg[1] = regs.r11;
1525 tcp->u_arg[2] = regs.r10;
1526 tcp->u_arg[3] = regs.r9;
1527 tcp->u_arg[4] = regs.r5;
1528 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001529# elif defined(BFIN)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001530 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 +02001531
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001532 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001533 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
1534 return -1;
1535# elif defined(SH)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001536 static const int syscall_regs[MAX_ARGS] = {
1537 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6),
1538 4 * (REG_REG0+7), 4 * (REG_REG0 ), 4 * (REG_REG0+1)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001539 };
1540
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001541 for (i = 0; i < nargs; ++i)
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001542 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001543 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001544# elif defined(SH64)
1545 int i;
1546 /* Registers used by SH5 Linux system calls for parameters */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001547 static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001548
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001549 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001550 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
1551 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001552# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001553 (void)i;
1554 (void)nargs;
1555 if (current_personality == 0) { /* x86-64 ABI */
1556 tcp->u_arg[0] = x86_64_regs.rdi;
1557 tcp->u_arg[1] = x86_64_regs.rsi;
1558 tcp->u_arg[2] = x86_64_regs.rdx;
1559 tcp->u_arg[3] = x86_64_regs.r10;
1560 tcp->u_arg[4] = x86_64_regs.r8;
1561 tcp->u_arg[5] = x86_64_regs.r9;
1562 } else { /* i386 ABI */
1563 /* Sign-extend lower 32 bits */
1564 tcp->u_arg[0] = (long)(int)x86_64_regs.rbx;
1565 tcp->u_arg[1] = (long)(int)x86_64_regs.rcx;
1566 tcp->u_arg[2] = (long)(int)x86_64_regs.rdx;
1567 tcp->u_arg[3] = (long)(int)x86_64_regs.rsi;
1568 tcp->u_arg[4] = (long)(int)x86_64_regs.rdi;
1569 tcp->u_arg[5] = (long)(int)x86_64_regs.rbp;
1570 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001571# elif defined(MICROBLAZE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001572 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001573 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
1574 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001575# elif defined(CRISV10) || defined(CRISV32)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001576 static const int crisregs[MAX_ARGS] = {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001577 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02001578 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001579 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00001580
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001581 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001582 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
1583 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001584# elif defined(TILE)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001585 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001586 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
1587 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001588# elif defined(M68K)
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001589 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001590 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
1591 return -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001592# elif defined(I386)
1593 (void)i;
1594 (void)nargs;
1595 tcp->u_arg[0] = i386_regs.ebx;
1596 tcp->u_arg[1] = i386_regs.ecx;
1597 tcp->u_arg[2] = i386_regs.edx;
1598 tcp->u_arg[3] = i386_regs.esi;
1599 tcp->u_arg[4] = i386_regs.edi;
1600 tcp->u_arg[5] = i386_regs.ebp;
1601# else /* Other architecture (32bits specific) */
Dmitry V. Levin5f731c42011-08-23 16:24:20 +00001602 for (i = 0; i < nargs; ++i)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001603 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
1604 return -1;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001605# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001606#endif /* LINUX */
1607#ifdef SUNOS4
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001608 int i, nargs;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001609 if (SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001610 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001611 else
Denys Vlasenko4b887a52011-08-23 13:32:38 +02001612 nargs = tcp->u_nargs = MAX_ARGS;
1613 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001614 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001616 if (upeek(tcp, uoff(u_arg[0]) +
1617 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
1618 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619 }
1620#endif /* SUNOS4 */
1621#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001622# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 /*
1624 * SGI is broken: even though it has pr_sysarg, it doesn't
1625 * set them on system call entry. Get a clue.
1626 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001627 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 tcp->u_nargs = sysent[tcp->scno].nargs;
1629 else
1630 tcp->u_nargs = tcp->status.pr_nsysarg;
1631 if (tcp->u_nargs > 4) {
1632 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001633 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001635 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 }
1637 else {
1638 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001639 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001641# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00001642 /*
1643 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
1644 */
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001645 if (SCNO_IN_RANGE(tcp->scno))
John Hughes25299712001-03-06 10:10:06 +00001646 tcp->u_nargs = sysent[tcp->scno].nargs;
1647 else
1648 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
1649 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001650 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1651# elif defined(HAVE_PR_SYSCALL)
1652 int i;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001653 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001654 tcp->u_nargs = sysent[tcp->scno].nargs;
1655 else
1656 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001657 for (i = 0; i < tcp->u_nargs; i++)
1658 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
1659# elif defined(I386)
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001660 if (SCNO_IN_RANGE(tcp->scno))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661 tcp->u_nargs = sysent[tcp->scno].nargs;
1662 else
1663 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02001664 if (tcp->u_nargs > 0)
1665 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001666 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
1667# else
John Hughes25299712001-03-06 10:10:06 +00001668 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001669# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001671#ifdef FREEBSD
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001672 if (SCNO_IN_RANGE(tcp->scno) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001673 sysent[tcp->scno].nargs > tcp->status.val)
1674 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001675 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001676 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001677 if (tcp->u_nargs < 0)
1678 tcp->u_nargs = 0;
1679 if (tcp->u_nargs > MAX_ARGS)
1680 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001681 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001682 case SYS___syscall:
1683 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1684 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001685 break;
1686 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001687 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1688 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001689 break;
1690 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001691 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
1692 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001693 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001694 }
1695#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001696 return 1;
1697}
1698
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00001699static int
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001700trace_syscall_entering(struct tcb *tcp)
1701{
1702 int res, scno_good;
1703
Denys Vlasenko2ce12ed2011-08-24 17:25:32 +02001704#if defined TCB_WAITEXECVE
1705 if (tcp->flags & TCB_WAITEXECVE) {
1706 /* This is the post-execve SIGTRAP. */
1707 tcp->flags &= ~TCB_WAITEXECVE;
1708 return 0;
1709 }
1710#endif
1711
Denys Vlasenko06602d92011-08-24 17:53:52 +02001712 scno_good = res = get_scno(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001713 if (res == 0)
1714 return res;
1715 if (res == 1)
Denys Vlasenko8b4454c2011-08-25 10:40:14 +02001716 res = syscall_fixup_on_sysenter(tcp);
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001717 if (res == 0)
1718 return res;
1719 if (res == 1)
1720 res = syscall_enter(tcp);
1721 if (res == 0)
1722 return res;
1723
1724 if (res != 1) {
1725 printleader(tcp);
1726 tcp->flags &= ~TCB_REPRINT;
1727 tcp_last = tcp;
1728 if (scno_good != 1)
1729 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001730 else if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001731 tprintf("syscall_%lu(", tcp->scno);
1732 else
1733 tprintf("%s(", sysent[tcp->scno].sys_name);
1734 /*
1735 * " <unavailable>" will be added later by the code which
1736 * detects ptrace errors.
1737 */
1738 goto ret;
1739 }
1740
1741 switch (known_scno(tcp)) {
1742#ifdef SYS_socket_subcall
1743 case SYS_socketcall:
1744 decode_subcall(tcp, SYS_socket_subcall,
1745 SYS_socket_nsubcalls, deref_style);
1746 break;
1747#endif
1748#ifdef SYS_ipc_subcall
1749 case SYS_ipc:
1750 decode_subcall(tcp, SYS_ipc_subcall,
1751 SYS_ipc_nsubcalls, shift_style);
1752 break;
1753#endif
1754#ifdef SVR4
1755#ifdef SYS_pgrpsys_subcall
1756 case SYS_pgrpsys:
1757 decode_subcall(tcp, SYS_pgrpsys_subcall,
1758 SYS_pgrpsys_nsubcalls, shift_style);
1759 break;
1760#endif /* SYS_pgrpsys_subcall */
1761#ifdef SYS_sigcall_subcall
1762 case SYS_sigcall:
1763 decode_subcall(tcp, SYS_sigcall_subcall,
1764 SYS_sigcall_nsubcalls, mask_style);
1765 break;
1766#endif /* SYS_sigcall_subcall */
1767 case SYS_msgsys:
1768 decode_subcall(tcp, SYS_msgsys_subcall,
1769 SYS_msgsys_nsubcalls, shift_style);
1770 break;
1771 case SYS_shmsys:
1772 decode_subcall(tcp, SYS_shmsys_subcall,
1773 SYS_shmsys_nsubcalls, shift_style);
1774 break;
1775 case SYS_semsys:
1776 decode_subcall(tcp, SYS_semsys_subcall,
1777 SYS_semsys_nsubcalls, shift_style);
1778 break;
1779 case SYS_sysfs:
1780 decode_subcall(tcp, SYS_sysfs_subcall,
1781 SYS_sysfs_nsubcalls, shift_style);
1782 break;
1783 case SYS_spcall:
1784 decode_subcall(tcp, SYS_spcall_subcall,
1785 SYS_spcall_nsubcalls, shift_style);
1786 break;
1787#ifdef SYS_context_subcall
1788 case SYS_context:
1789 decode_subcall(tcp, SYS_context_subcall,
1790 SYS_context_nsubcalls, shift_style);
1791 break;
1792#endif /* SYS_context_subcall */
1793#ifdef SYS_door_subcall
1794 case SYS_door:
1795 decode_subcall(tcp, SYS_door_subcall,
1796 SYS_door_nsubcalls, door_style);
1797 break;
1798#endif /* SYS_door_subcall */
1799#ifdef SYS_kaio_subcall
1800 case SYS_kaio:
1801 decode_subcall(tcp, SYS_kaio_subcall,
1802 SYS_kaio_nsubcalls, shift_style);
1803 break;
1804#endif
1805#endif /* SVR4 */
1806#ifdef FREEBSD
1807 case SYS_msgsys:
1808 case SYS_shmsys:
1809 case SYS_semsys:
1810 decode_subcall(tcp, 0, 0, table_style);
1811 break;
1812#endif
1813#ifdef SUNOS4
1814 case SYS_semsys:
1815 decode_subcall(tcp, SYS_semsys_subcall,
1816 SYS_semsys_nsubcalls, shift_style);
1817 break;
1818 case SYS_msgsys:
1819 decode_subcall(tcp, SYS_msgsys_subcall,
1820 SYS_msgsys_nsubcalls, shift_style);
1821 break;
1822 case SYS_shmsys:
1823 decode_subcall(tcp, SYS_shmsys_subcall,
1824 SYS_shmsys_nsubcalls, shift_style);
1825 break;
1826#endif
1827 }
1828
1829 internal_syscall(tcp);
1830
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001831 if ((SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001832 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
1833 (tracing_paths && !pathtrace_match(tcp))) {
1834 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
1835 return 0;
1836 }
1837
1838 tcp->flags &= ~TCB_FILTERED;
1839
1840 if (cflag == CFLAG_ONLY_STATS) {
1841 res = 0;
1842 goto ret;
1843 }
1844
1845 printleader(tcp);
1846 tcp->flags &= ~TCB_REPRINT;
1847 tcp_last = tcp;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001848 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001849 tprintf("syscall_%lu(", tcp->scno);
1850 else
1851 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02001852 if (!SCNO_IN_RANGE(tcp->scno) ||
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02001853 ((qual_flags[tcp->scno] & QUAL_RAW) &&
1854 sysent[tcp->scno].sys_func != sys_exit))
1855 res = printargs(tcp);
1856 else
1857 res = (*sysent[tcp->scno].sys_func)(tcp);
1858
1859 if (fflush(tcp->outf) == EOF)
1860 return -1;
1861 ret:
1862 tcp->flags |= TCB_INSYSCALL;
1863 /* Measure the entrance time as late as possible to avoid errors. */
1864 if (dtime || cflag)
1865 gettimeofday(&tcp->etime, NULL);
1866 return res;
1867}
1868
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001869/* Returns:
1870 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1871 * 1: ok, continue in trace_syscall().
1872 * other: error, trace_syscall() should print error indicator
1873 * ("????" etc) and bail out.
1874 */
1875static int
1876get_syscall_result(struct tcb *tcp)
1877{
1878#ifdef LINUX
1879# if defined(S390) || defined(S390X)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001880 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
1881 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001882# elif defined (POWERPC)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001883# define SO_MASK 0x10000000
1884 {
1885 long flags;
1886 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
1887 return -1;
1888 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
1889 return -1;
1890 if (flags & SO_MASK)
1891 result = -result;
1892 }
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001893# elif defined(AVR32)
1894 /* Read complete register set in one go. */
1895 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
1896 return -1;
1897# elif defined(BFIN)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001898 if (upeek(tcp, PT_R0, &r0) < 0)
1899 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001900# elif defined (I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001901 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001902 return -1;
1903# elif defined (X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02001904 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001905 return -1;
1906# elif defined(IA64)
1907# define IA64_PSR_IS ((long)1 << 34)
1908 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
1909 ia32 = (psr & IA64_PSR_IS) != 0;
1910 if (upeek(tcp, PT_R8, &r8) < 0)
1911 return -1;
1912 if (upeek(tcp, PT_R10, &r10) < 0)
1913 return -1;
1914# elif defined (ARM)
1915 /* Read complete register set in one go. */
1916 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
1917 return -1;
1918# elif defined (M68K)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001919 if (upeek(tcp, 4*PT_D0, &d0) < 0)
1920 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001921# elif defined (LINUX_MIPSN32)
1922 unsigned long long regs[38];
1923
1924 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
1925 return -1;
1926 a3 = regs[REG_A3];
1927 r2 = regs[REG_V0];
1928# elif defined (MIPS)
1929 if (upeek(tcp, REG_A3, &a3) < 0)
1930 return -1;
1931 if (upeek(tcp, REG_V0, &r2) < 0)
1932 return -1;
1933# elif defined (ALPHA)
1934 if (upeek(tcp, REG_A3, &a3) < 0)
1935 return -1;
1936 if (upeek(tcp, REG_R0, &r0) < 0)
1937 return -1;
1938# elif defined (SPARC) || defined (SPARC64)
1939 /* Everything we need is in the current register set. */
1940 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1941 return -1;
1942# elif defined(HPPA)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001943 if (upeek(tcp, PT_GR28, &r28) < 0)
1944 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001945# elif defined(SH)
1946# elif defined(SH64)
1947# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001948 if (upeek(tcp, 4*PT_R10, &r10) < 0)
1949 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001950# elif defined(TILE)
1951# elif defined(MICROBLAZE)
Denys Vlasenkof20bff62011-08-25 10:31:24 +02001952 if (upeek(tcp, 3 * 4, &r3) < 0)
1953 return -1;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02001954# endif
1955#endif /* LINUX */
1956
1957#ifdef SUNOS4
1958#elif defined(SH)
1959 /* new syscall ABI returns result in R0 */
1960 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1961 return -1;
1962#elif defined(SH64)
1963 /* ABI defines result returned in r9 */
1964 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1965 return -1;
1966#endif
1967
1968#ifdef USE_PROCFS
1969# ifndef HAVE_PR_SYSCALL
1970# ifdef FREEBSD
1971 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1972 perror("pread");
1973 return -1;
1974 }
1975# endif /* FREEBSD */
1976# endif /* !HAVE_PR_SYSCALL */
1977#endif /* USE_PROCFS */
1978
1979 return 1;
1980}
1981
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001982/* Called at each syscall exit.
1983 * Returns:
1984 * 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
1985 * 1: ok, continue in trace_syscall().
1986 * other: error, trace_syscall() should print error indicator
1987 * ("????" etc) and bail out.
1988 */
1989static int
1990syscall_fixup_on_sysexit(struct tcb *tcp)
1991{
1992#ifdef USE_PROCFS
Denys Vlasenkoece98792011-08-25 10:25:35 +02001993 if (tcp->status.PR_WHY != PR_SYSEXIT) {
1994 fprintf(stderr, "syscall: missing exit\n");
1995 tcp->flags &= ~TCB_INSYSCALL;
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02001996 }
1997#endif /* USE_PROCFS */
1998
1999#ifdef SUNOS4
Denys Vlasenkoece98792011-08-25 10:25:35 +02002000 {
2001 int scno = known_scno(tcp);
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002002 if (scno != 0) {
2003 if (debug) {
2004 /*
2005 * This happens when a signal handler
2006 * for a signal which interrupted a
2007 * a system call makes another system call.
2008 */
2009 fprintf(stderr, "syscall: missing exit\n");
2010 }
2011 tcp->flags &= ~TCB_INSYSCALL;
2012 }
2013 }
2014#endif /* SUNOS4 */
2015
2016#ifdef LINUX
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002017# if defined (S390) || defined (S390X)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002018 if (syscall_mode != -ENOSYS)
2019 syscall_mode = tcp->scno;
Denys Vlasenkoece98792011-08-25 10:25:35 +02002020 if ((tcp->flags & TCB_WAITEXECVE)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002021 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
2022 /*
2023 * Return from execve.
2024 * Fake a return value of zero. We leave the TCB_WAITEXECVE
2025 * flag set for the post-execve SIGTRAP to see and reset.
2026 */
2027 gpr2 = 0;
2028 }
Denys Vlasenkof20bff62011-08-25 10:31:24 +02002029# endif
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002030#endif /* LINUX */
2031 return 1;
2032}
2033
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002034#ifdef LINUX
2035/*
2036 * Check the syscall return value register value for whether it is
2037 * a negated errno code indicating an error, or a success return value.
2038 */
2039static inline int
2040is_negated_errno(unsigned long int val)
2041{
2042 unsigned long int max = -(long int) nerrnos;
2043# if SUPPORTED_PERSONALITIES > 1
2044 if (personality_wordsize[current_personality] < sizeof(val)) {
2045 val = (unsigned int) val;
2046 max = (unsigned int) max;
2047 }
2048# endif
2049 return val > max;
2050}
2051#endif
2052
2053static int
2054get_error(struct tcb *tcp)
2055{
2056 int u_error = 0;
2057#ifdef LINUX
2058 int check_errno = 1;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002059 if (SCNO_IN_RANGE(tcp->scno) &&
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002060 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
2061 check_errno = 0;
2062 }
2063# if defined(S390) || defined(S390X)
2064 if (check_errno && is_negated_errno(gpr2)) {
2065 tcp->u_rval = -1;
2066 u_error = -gpr2;
2067 }
2068 else {
2069 tcp->u_rval = gpr2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002070 }
2071# elif defined(I386)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002072 if (check_errno && is_negated_errno(i386_regs.eax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002073 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002074 u_error = -i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002075 }
2076 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002077 tcp->u_rval = i386_regs.eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002078 }
2079# elif defined(X86_64)
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002080 if (check_errno && is_negated_errno(x86_64_regs.rax)) {
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002081 tcp->u_rval = -1;
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002082 u_error = -x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002083 }
2084 else {
Denys Vlasenkoeb0e3e82011-08-30 18:53:49 +02002085 tcp->u_rval = x86_64_regs.rax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002086 }
2087# elif defined(IA64)
2088 if (ia32) {
2089 int err;
2090
2091 err = (int)r8;
2092 if (check_errno && is_negated_errno(err)) {
2093 tcp->u_rval = -1;
2094 u_error = -err;
2095 }
2096 else {
2097 tcp->u_rval = err;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002098 }
2099 } else {
2100 if (check_errno && r10) {
2101 tcp->u_rval = -1;
2102 u_error = r8;
2103 } else {
2104 tcp->u_rval = r8;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002105 }
2106 }
2107# elif defined(MIPS)
2108 if (check_errno && a3) {
2109 tcp->u_rval = -1;
2110 u_error = r2;
2111 } else {
2112 tcp->u_rval = r2;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002113 }
2114# elif defined(POWERPC)
2115 if (check_errno && is_negated_errno(result)) {
2116 tcp->u_rval = -1;
2117 u_error = -result;
2118 }
2119 else {
2120 tcp->u_rval = result;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002121 }
2122# elif defined(M68K)
2123 if (check_errno && is_negated_errno(d0)) {
2124 tcp->u_rval = -1;
2125 u_error = -d0;
2126 }
2127 else {
2128 tcp->u_rval = d0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002129 }
2130# elif defined(ARM)
2131 if (check_errno && is_negated_errno(regs.ARM_r0)) {
2132 tcp->u_rval = -1;
2133 u_error = -regs.ARM_r0;
2134 }
2135 else {
2136 tcp->u_rval = regs.ARM_r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002137 }
2138# elif defined(AVR32)
2139 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
2140 tcp->u_rval = -1;
2141 u_error = -regs.r12;
2142 }
2143 else {
2144 tcp->u_rval = regs.r12;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002145 }
2146# elif defined(BFIN)
2147 if (check_errno && is_negated_errno(r0)) {
2148 tcp->u_rval = -1;
2149 u_error = -r0;
2150 } else {
2151 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002152 }
2153# elif defined(ALPHA)
2154 if (check_errno && a3) {
2155 tcp->u_rval = -1;
2156 u_error = r0;
2157 }
2158 else {
2159 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002160 }
2161# elif defined(SPARC)
2162 if (check_errno && regs.psr & PSR_C) {
2163 tcp->u_rval = -1;
2164 u_error = regs.u_regs[U_REG_O0];
2165 }
2166 else {
2167 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002168 }
2169# elif defined(SPARC64)
2170 if (check_errno && regs.tstate & 0x1100000000UL) {
2171 tcp->u_rval = -1;
2172 u_error = regs.u_regs[U_REG_O0];
2173 }
2174 else {
2175 tcp->u_rval = regs.u_regs[U_REG_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002176 }
2177# elif defined(HPPA)
2178 if (check_errno && is_negated_errno(r28)) {
2179 tcp->u_rval = -1;
2180 u_error = -r28;
2181 }
2182 else {
2183 tcp->u_rval = r28;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002184 }
2185# elif defined(SH)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002186 if (check_errno && is_negated_errno(r0)) {
2187 tcp->u_rval = -1;
2188 u_error = -r0;
2189 }
2190 else {
2191 tcp->u_rval = r0;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002192 }
2193# elif defined(SH64)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002194 if (check_errno && is_negated_errno(r9)) {
2195 tcp->u_rval = -1;
2196 u_error = -r9;
2197 }
2198 else {
2199 tcp->u_rval = r9;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002200 }
2201# elif defined(CRISV10) || defined(CRISV32)
2202 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
2203 tcp->u_rval = -1;
2204 u_error = -r10;
2205 }
2206 else {
2207 tcp->u_rval = r10;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002208 }
2209# elif defined(TILE)
2210 long rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002211 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
2212 return -1;
2213 if (check_errno && rval < 0 && rval > -nerrnos) {
2214 tcp->u_rval = -1;
2215 u_error = -rval;
2216 }
2217 else {
2218 tcp->u_rval = rval;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002219 }
2220# elif defined(MICROBLAZE)
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002221 if (check_errno && is_negated_errno(r3)) {
2222 tcp->u_rval = -1;
2223 u_error = -r3;
2224 }
2225 else {
2226 tcp->u_rval = r3;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002227 }
2228# endif
2229#endif /* LINUX */
2230#ifdef SUNOS4
2231 /* get error code from user struct */
2232 if (upeek(tcp, uoff(u_error), &u_error) < 0)
2233 return -1;
2234 u_error >>= 24; /* u_error is a char */
2235
2236 /* get system call return value */
2237 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
2238 return -1;
2239#endif /* SUNOS4 */
2240#ifdef SVR4
2241# ifdef SPARC
2242 /* Judicious guessing goes a long way. */
2243 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
2244 tcp->u_rval = -1;
2245 u_error = tcp->status.pr_reg[R_O0];
2246 }
2247 else {
2248 tcp->u_rval = tcp->status.pr_reg[R_O0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002249 }
2250# endif /* SPARC */
2251# ifdef I386
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002252 if (tcp->status.PR_REG[EFL] & 0x1) {
2253 tcp->u_rval = -1;
2254 u_error = tcp->status.PR_REG[EAX];
2255 }
2256 else {
2257 tcp->u_rval = tcp->status.PR_REG[EAX];
2258# ifdef HAVE_LONG_LONG
2259 tcp->u_lrval =
2260 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
2261 tcp->status.PR_REG[EAX];
2262# endif
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002263 }
2264# endif /* I386 */
2265# ifdef X86_64
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002266 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
2267 tcp->u_rval = -1;
2268 u_error = tcp->status.PR_REG[RAX];
2269 }
2270 else {
2271 tcp->u_rval = tcp->status.PR_REG[RAX];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002272 }
2273# endif /* X86_64 */
2274# ifdef MIPS
2275 if (tcp->status.pr_reg[CTX_A3]) {
2276 tcp->u_rval = -1;
2277 u_error = tcp->status.pr_reg[CTX_V0];
2278 }
2279 else {
2280 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002281 }
2282# endif /* MIPS */
2283#endif /* SVR4 */
2284#ifdef FREEBSD
2285 if (regs.r_eflags & PSL_C) {
2286 tcp->u_rval = -1;
2287 u_error = regs.r_eax;
2288 } else {
2289 tcp->u_rval = regs.r_eax;
2290 tcp->u_lrval =
Denys Vlasenko684fb1a2011-08-25 00:26:38 +02002291 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002292 }
2293#endif /* FREEBSD */
2294 tcp->u_error = u_error;
2295 return 1;
2296}
2297
2298static void
2299dumpio(struct tcb *tcp)
2300{
2301 if (syserror(tcp))
2302 return;
2303 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
2304 return;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002305 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenkoa6146922011-08-24 18:07:22 +02002306 return;
2307 if (sysent[tcp->scno].sys_func == printargs)
2308 return;
2309 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
2310 if (sysent[tcp->scno].sys_func == sys_read ||
2311 sysent[tcp->scno].sys_func == sys_pread ||
2312 sysent[tcp->scno].sys_func == sys_pread64 ||
2313 sysent[tcp->scno].sys_func == sys_recv ||
2314 sysent[tcp->scno].sys_func == sys_recvfrom)
2315 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
2316 else if (sysent[tcp->scno].sys_func == sys_readv)
2317 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2318 return;
2319 }
2320 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
2321 if (sysent[tcp->scno].sys_func == sys_write ||
2322 sysent[tcp->scno].sys_func == sys_pwrite ||
2323 sysent[tcp->scno].sys_func == sys_pwrite64 ||
2324 sysent[tcp->scno].sys_func == sys_send ||
2325 sysent[tcp->scno].sys_func == sys_sendto)
2326 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
2327 else if (sysent[tcp->scno].sys_func == sys_writev)
2328 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
2329 return;
2330 }
2331}
2332
Denys Vlasenkoed4f4f02011-08-22 11:54:06 +02002333static int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002334trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002335{
2336 int sys_res;
2337 struct timeval tv;
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002338 int res;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002339 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002340
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002341 /* Measure the exit time as early as possible to avoid errors. */
2342 if (dtime || cflag)
2343 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002344
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00002345#if SUPPORTED_PERSONALITIES > 1
2346 update_personality(tcp, tcp->currpers);
2347#endif
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002348 res = get_syscall_result(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002349 if (res == 0)
2350 return res;
2351 if (res == 1)
Denys Vlasenko20c41fd2011-08-25 10:23:00 +02002352 res = syscall_fixup_on_sysexit(tcp);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002353 if (res == 0)
2354 return res;
2355 if (res == 1)
2356 res = get_error(tcp);
2357 if (res == 0)
2358 return res;
2359 if (res == 1)
2360 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002361
Grant Edwards8a082772011-04-07 20:25:40 +00002362 if (res == 1 && filtered(tcp)) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002363 goto ret;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002364 }
2365
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002366 if (tcp->flags & TCB_REPRINT) {
2367 printleader(tcp);
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002368 if (!SCNO_IN_RANGE(tcp->scno))
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002369 tprintf("<... syscall_%lu resumed> ", tcp->scno);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002370 else
Denys Vlasenko1a5b5a72011-08-25 00:29:56 +02002371 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002372 }
2373
2374 if (cflag) {
2375 struct timeval t = tv;
Denys Vlasenkoc95a88f2011-08-21 17:47:40 +02002376 count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002377 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002378 goto ret;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002379 }
2380 }
2381
2382 if (res != 1) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002383 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002384 tabto();
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002385 tprints("= ? <unavailable>");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002386 printtrailer();
2387 tcp->flags &= ~TCB_INSYSCALL;
2388 return res;
2389 }
2390
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002391 if (!SCNO_IN_RANGE(tcp->scno)
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002392 || (qual_flags[tcp->scno] & QUAL_RAW))
2393 sys_res = printargs(tcp);
2394 else {
Denys Vlasenko3b738812011-08-22 02:06:35 +02002395 /* FIXME: not_failing_only (IOW, option -z) is broken:
2396 * failure of syscall is known only after syscall return.
2397 * Thus we end up with something like this on, say, ENOENT:
2398 * open("doesnt_exist", O_RDONLY <unfinished ...>
2399 * {next syscall decode}
2400 * whereas the intended result is that open(...) line
2401 * is not shown at all.
2402 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002403 if (not_failing_only && tcp->u_error)
Denys Vlasenko3b738812011-08-22 02:06:35 +02002404 goto ret; /* ignore failed syscalls */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002405 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2406 }
2407
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002408 tprints(") ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002409 tabto();
Denys Vlasenko3b738812011-08-22 02:06:35 +02002410 u_error = tcp->u_error;
Denys Vlasenkocb6f0562011-08-25 01:13:43 +02002411 if (!SCNO_IN_RANGE(tcp->scno) ||
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002412 qual_flags[tcp->scno] & QUAL_RAW) {
2413 if (u_error)
2414 tprintf("= -1 (errno %ld)", u_error);
2415 else
2416 tprintf("= %#lx", tcp->u_rval);
2417 }
2418 else if (!(sys_res & RVAL_NONE) && u_error) {
2419 switch (u_error) {
2420#ifdef LINUX
Denys Vlasenkofe585652012-01-12 11:26:34 +01002421 /* Blocked signals do not interrupt any syscalls.
2422 * In this case syscalls don't return ERESTARTfoo codes.
2423 *
2424 * Deadly signals set to SIG_DFL interrupt syscalls
2425 * and kill the process regardless of which of the codes below
2426 * is returned by the interrupted syscall.
2427 * In some cases, kernel forces a kernel-generated deadly
2428 * signal to be unblocked and set to SIG_DFL (and thus cause
2429 * death) if it is blocked or SIG_IGNed: for example, SIGSEGV
2430 * or SIGILL. (The alternative is to leave process spinning
2431 * forever on the faulty instruction - not useful).
2432 *
2433 * SIG_IGNed signals and non-deadly signals set to SIG_DFL
2434 * (for example, SIGCHLD, SIGWINCH) interrupt syscalls,
2435 * but kernel will always restart them.
2436 */
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002437 case ERESTARTSYS:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002438 /* Most common type of signal-interrupted syscall exit code.
2439 * The system call will be restarted with the same arguments
2440 * if SA_RESTART is set; otherwise, it will fail with EINTR.
2441 */
2442 tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002443 break;
2444 case ERESTARTNOINTR:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002445 /* Rare. For example, fork() returns this if interrupted.
2446 * SA_RESTART is ignored (assumed set): the restart is unconditional.
2447 */
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002448 tprints("= ? ERESTARTNOINTR (To be restarted)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002449 break;
2450 case ERESTARTNOHAND:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002451 /* pause(), rt_sigsuspend() etc use this code.
2452 * SA_RESTART is ignored (assumed not set):
2453 * syscall won't restart (will return EINTR instead)
2454 * even after signal with SA_RESTART set.
2455 * However, after SIG_IGN or SIG_DFL signal it will.
2456 */
2457 tprints("= ? ERESTARTNOHAND (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002458 break;
2459 case ERESTART_RESTARTBLOCK:
Denys Vlasenkofe585652012-01-12 11:26:34 +01002460 /* Syscalls like nanosleep(), poll() which can't be
2461 * restarted with their original arguments use this
2462 * code. Kernel will execute restart_syscall() instead,
2463 * which changes arguments before restarting syscall.
2464 * SA_RESTART is ignored (assumed not set) similarly
2465 * to ERESTARTNOHAND. (Kernel can't honor SA_RESTART
2466 * since restart data is saved in "restart block"
2467 * in task struct, and if signal handler uses a syscall
2468 * which in turn saves another such restart block,
2469 * old data is lost and restart becomes impossible)
2470 */
2471 tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002472 break;
2473#endif /* LINUX */
2474 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002475 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002476 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002477 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002478 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002479 strerror(u_error));
2480 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002481 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002482 strerror(u_error));
2483 break;
2484 }
2485 if ((sys_res & RVAL_STR) && tcp->auxstr)
2486 tprintf(" (%s)", tcp->auxstr);
2487 }
2488 else {
2489 if (sys_res & RVAL_NONE)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002490 tprints("= ?");
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002491 else {
2492 switch (sys_res & RVAL_MASK) {
2493 case RVAL_HEX:
2494 tprintf("= %#lx", tcp->u_rval);
2495 break;
2496 case RVAL_OCTAL:
2497 tprintf("= %#lo", tcp->u_rval);
2498 break;
2499 case RVAL_UDECIMAL:
2500 tprintf("= %lu", tcp->u_rval);
2501 break;
2502 case RVAL_DECIMAL:
2503 tprintf("= %ld", tcp->u_rval);
2504 break;
2505#ifdef HAVE_LONG_LONG
2506 case RVAL_LHEX:
2507 tprintf("= %#llx", tcp->u_lrval);
2508 break;
2509 case RVAL_LOCTAL:
2510 tprintf("= %#llo", tcp->u_lrval);
2511 break;
2512 case RVAL_LUDECIMAL:
2513 tprintf("= %llu", tcp->u_lrval);
2514 break;
2515 case RVAL_LDECIMAL:
2516 tprintf("= %lld", tcp->u_lrval);
2517 break;
2518#endif
2519 default:
2520 fprintf(stderr,
2521 "invalid rval format\n");
2522 break;
2523 }
2524 }
2525 if ((sys_res & RVAL_STR) && tcp->auxstr)
2526 tprintf(" (%s)", tcp->auxstr);
2527 }
2528 if (dtime) {
2529 tv_sub(&tv, &tv, &tcp->etime);
2530 tprintf(" <%ld.%06ld>",
2531 (long) tv.tv_sec, (long) tv.tv_usec);
2532 }
2533 printtrailer();
2534
2535 dumpio(tcp);
2536 if (fflush(tcp->outf) == EOF)
2537 return -1;
Denys Vlasenko3b738812011-08-22 02:06:35 +02002538 ret:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002539 tcp->flags &= ~TCB_INSYSCALL;
2540 return 0;
2541}
2542
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002543int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002544trace_syscall(struct tcb *tcp)
2545{
2546 return exiting(tcp) ?
2547 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2548}