blob: cbe9f124b20e46a0bf84a9ec3cfb5c0595b0a7d0 [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
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115
Roland McGrathee36ce12004-09-04 03:53:10 +0000116static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117#include "syscallent.h"
118};
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000119
120#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000121static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#include "syscallent1.h"
123};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200124#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000125
126#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000127static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000128#include "syscallent2.h"
129};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200130#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000131
132/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000133#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134#undef TF
135#undef TI
136#undef TN
137#undef TP
138#undef TS
Dmitry V. Levin50a218d2011-01-18 17:36:20 +0000139#undef NF
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140
Denys Vlasenko39fca622011-08-20 02:12:33 +0200141
142/*
143 * `ioctlent.h' may be generated from `ioctlent.raw' by the auxiliary
144 * program `ioctlsort', such that the list is sorted by the `code' field.
145 * This has the side-effect of resolving the _IO.. macros into
146 * plain integers, eliminating the need to include here everything
147 * in "/usr/include".
148 */
149
150
Roland McGrathee36ce12004-09-04 03:53:10 +0000151static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152#include "errnoent.h"
153};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200154static const char *const signalent0[] = {
155#include "signalent.h"
156};
157static const struct ioctlent ioctlent0[] = {
158#include "ioctlent.h"
159};
160enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
161enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
162enum { nsignals0 = ARRAY_SIZE(signalent0) };
163enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
164int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000165
166#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000167static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000168#include "errnoent1.h"
169};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200170static const char *const signalent1[] = {
171#include "signalent1.h"
172};
173static const struct ioctlent ioctlent1[] = {
174#include "ioctlent1.h"
175};
176enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
177enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
178enum { nsignals1 = ARRAY_SIZE(signalent1) };
179enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
180int qual_flags1[MAX_QUALS];
181#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182
183#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000184static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000185#include "errnoent2.h"
186};
Denys Vlasenko39fca622011-08-20 02:12:33 +0200187static const char *const signalent2[] = {
188#include "signalent2.h"
189};
190static const struct ioctlent ioctlent2[] = {
191#include "ioctlent2.h"
192};
193enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
194enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
195enum { nsignals2 = ARRAY_SIZE(signalent2) };
196enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
197int qual_flags2[MAX_QUALS];
198#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199
Denys Vlasenko39fca622011-08-20 02:12:33 +0200200
201const struct sysent *sysent;
Roland McGrathee36ce12004-09-04 03:53:10 +0000202const char *const *errnoent;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200203const char *const *signalent;
204const struct ioctlent *ioctlent;
205int nsyscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000206int nerrnos;
Denys Vlasenko39fca622011-08-20 02:12:33 +0200207int nsignals;
208int nioctlents;
209int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000210
211int current_personality;
212
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000213#ifndef PERSONALITY0_WORDSIZE
214# define PERSONALITY0_WORDSIZE sizeof(long)
215#endif
216const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
217 PERSONALITY0_WORDSIZE,
218#if SUPPORTED_PERSONALITIES > 1
219 PERSONALITY1_WORDSIZE,
220#endif
221#if SUPPORTED_PERSONALITIES > 2
222 PERSONALITY2_WORDSIZE,
223#endif
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200224};
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000225
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200226void
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000227set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000228{
229 switch (personality) {
230 case 0:
231 errnoent = errnoent0;
232 nerrnos = nerrnos0;
233 sysent = sysent0;
234 nsyscalls = nsyscalls0;
235 ioctlent = ioctlent0;
236 nioctlents = nioctlents0;
237 signalent = signalent0;
238 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000239 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 break;
241
242#if SUPPORTED_PERSONALITIES >= 2
243 case 1:
244 errnoent = errnoent1;
245 nerrnos = nerrnos1;
246 sysent = sysent1;
247 nsyscalls = nsyscalls1;
248 ioctlent = ioctlent1;
249 nioctlents = nioctlents1;
250 signalent = signalent1;
251 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000252 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200254#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255
256#if SUPPORTED_PERSONALITIES >= 3
257 case 2:
258 errnoent = errnoent2;
259 nerrnos = nerrnos2;
260 sysent = sysent2;
261 nsyscalls = nsyscalls2;
262 ioctlent = ioctlent2;
263 nioctlents = nioctlents2;
264 signalent = signalent2;
265 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000266 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000267 break;
Denys Vlasenko5c774b22011-08-20 01:50:09 +0200268#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000269 }
270
271 current_personality = personality;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000272}
273
Roland McGrathe10e62a2004-09-04 04:20:43 +0000274
Roland McGrath9797ceb2002-12-30 10:23:00 +0000275static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000276
Roland McGrathe10e62a2004-09-04 04:20:43 +0000277static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000278 int bitflag;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000279 const char *option_name;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000280 int (*qualify)(const char *, int, int);
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000281 const char *argument_name;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000282} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000283 { QUAL_TRACE, "trace", qual_syscall, "system call" },
284 { QUAL_TRACE, "t", qual_syscall, "system call" },
285 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
286 { QUAL_ABBREV, "a", qual_syscall, "system call" },
287 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
288 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
289 { QUAL_RAW, "raw", qual_syscall, "system call" },
290 { QUAL_RAW, "x", qual_syscall, "system call" },
291 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
292 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
293 { QUAL_SIGNAL, "s", qual_signal, "signal" },
294 { QUAL_FAULT, "fault", qual_fault, "fault" },
295 { QUAL_FAULT, "faults", qual_fault, "fault" },
296 { QUAL_FAULT, "m", qual_fault, "fault" },
297 { QUAL_READ, "read", qual_desc, "descriptor" },
298 { QUAL_READ, "reads", qual_desc, "descriptor" },
299 { QUAL_READ, "r", qual_desc, "descriptor" },
300 { QUAL_WRITE, "write", qual_desc, "descriptor" },
301 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
302 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000303 { 0, NULL, NULL, NULL },
304};
305
Roland McGrath9797ceb2002-12-30 10:23:00 +0000306static void
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000307qualify_one(int n, int bitflag, int not, int pers)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000308{
Roland McGrath138c6a32006-01-12 09:50:49 +0000309 if (pers == 0 || pers < 0) {
310 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000311 qual_flags0[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000312 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000313 qual_flags0[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000314 }
315
316#if SUPPORTED_PERSONALITIES >= 2
317 if (pers == 1 || pers < 0) {
318 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000319 qual_flags1[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000320 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000321 qual_flags1[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000322 }
323#endif /* SUPPORTED_PERSONALITIES >= 2 */
324
325#if SUPPORTED_PERSONALITIES >= 3
326 if (pers == 2 || pers < 0) {
327 if (not)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000328 qual_flags2[n] &= ~bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000329 else
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000330 qual_flags2[n] |= bitflag;
Roland McGrath138c6a32006-01-12 09:50:49 +0000331 }
332#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000333}
334
335static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000336qual_syscall(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000337{
338 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000339 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000340
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000341 if (isdigit((unsigned char)*s)) {
342 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000343 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000344 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000345 qualify_one(i, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000346 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000347 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000348 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000349 if (strcmp(s, sysent0[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000350 qualify_one(i, bitflag, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000351 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000352 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000353
354#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000355 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000356 if (strcmp(s, sysent1[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000357 qualify_one(i, bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000358 rc = 0;
359 }
360#endif /* SUPPORTED_PERSONALITIES >= 2 */
361
362#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000363 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000364 if (strcmp(s, sysent2[i].sys_name) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000365 qualify_one(i, bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000366 rc = 0;
367 }
368#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000369
Roland McGrathfe6b3522005-02-02 04:40:11 +0000370 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000371}
372
373static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000374qual_signal(const char *s, int bitflag, int not)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375{
376 int i;
377 char buf[32];
378
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000379 if (isdigit((unsigned char)*s)) {
380 int signo = atoi(s);
381 if (signo < 0 || signo >= MAX_QUALS)
382 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000383 qualify_one(signo, bitflag, not, -1);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000384 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000385 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000386 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000387 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000388 strcpy(buf, s);
389 s = buf;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000390 if (strncasecmp(s, "SIG", 3) == 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000391 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000392 for (i = 0; i <= NSIG; i++)
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000393 if (strcasecmp(s, signame(i) + 3) == 0) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000394 qualify_one(i, bitflag, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000395 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000396 }
Roland McGrath76421df2005-02-02 03:51:18 +0000397 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000398}
399
400static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000401qual_fault(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000402{
403 return -1;
404}
405
406static int
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000407qual_desc(const char *s, int bitflag, int not)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000408{
Roland McGrath48a035f2006-01-12 09:45:56 +0000409 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000410 int desc = atoi(s);
411 if (desc < 0 || desc >= MAX_QUALS)
412 return -1;
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000413 qualify_one(desc, bitflag, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000414 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415 }
416 return -1;
417}
418
419static int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000420lookup_class(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000421{
422 if (strcmp(s, "file") == 0)
423 return TRACE_FILE;
424 if (strcmp(s, "ipc") == 0)
425 return TRACE_IPC;
426 if (strcmp(s, "network") == 0)
427 return TRACE_NETWORK;
428 if (strcmp(s, "process") == 0)
429 return TRACE_PROCESS;
430 if (strcmp(s, "signal") == 0)
431 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000432 if (strcmp(s, "desc") == 0)
433 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000434 return -1;
435}
436
437void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000438qualify(const char *s)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000439{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000440 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441 int not;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000442 char *copy;
443 const char *p;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000444 int i, n;
445
446 opt = &qual_options[0];
447 for (i = 0; (p = qual_options[i].option_name); i++) {
448 n = strlen(p);
449 if (strncmp(s, p, n) == 0 && s[n] == '=') {
450 opt = &qual_options[i];
451 s += n + 1;
452 break;
453 }
454 }
455 not = 0;
456 if (*s == '!') {
457 not = 1;
458 s++;
459 }
460 if (strcmp(s, "none") == 0) {
461 not = 1 - not;
462 s = "all";
463 }
464 if (strcmp(s, "all") == 0) {
465 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000466 qualify_one(i, opt->bitflag, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 }
468 return;
469 }
470 for (i = 0; i < MAX_QUALS; i++) {
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000471 qualify_one(i, opt->bitflag, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000472 }
Denys Vlasenko5d645812011-08-20 12:48:18 +0200473 copy = strdup(s);
474 if (!copy) {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000475 fprintf(stderr, "out of memory\n");
476 exit(1);
477 }
478 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000479 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000480 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000481 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000482 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000483
484#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000485 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000486 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000487 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000488#endif /* SUPPORTED_PERSONALITIES >= 2 */
489
490#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000491 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000492 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000493 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000494#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000495
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000496 continue;
497 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000498 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000499 fprintf(stderr, "strace: invalid %s `%s'\n",
500 opt->argument_name, p);
501 exit(1);
502 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000504 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000505 return;
506}
507
508static void
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000509dumpio(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000510{
511 if (syserror(tcp))
512 return;
513 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
514 return;
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000515 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
516 return;
517 if (sysent[tcp->scno].sys_func == printargs)
518 return;
519 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
520 if (sysent[tcp->scno].sys_func == sys_read ||
521 sysent[tcp->scno].sys_func == sys_pread ||
522 sysent[tcp->scno].sys_func == sys_pread64 ||
523 sysent[tcp->scno].sys_func == sys_recv ||
524 sysent[tcp->scno].sys_func == sys_recvfrom)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000525 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000526 else if (sysent[tcp->scno].sys_func == sys_readv)
527 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
528 return;
529 }
530 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
531 if (sysent[tcp->scno].sys_func == sys_write ||
532 sysent[tcp->scno].sys_func == sys_pwrite ||
533 sysent[tcp->scno].sys_func == sys_pwrite64 ||
534 sysent[tcp->scno].sys_func == sys_send ||
535 sysent[tcp->scno].sys_func == sys_sendto)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000537 else if (sysent[tcp->scno].sys_func == sys_writev)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000538 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000539 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540 }
541}
542
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000543#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000544enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000545#else /* FREEBSD */
546enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
547
548struct subcall {
549 int call;
550 int nsubcalls;
551 int subcalls[5];
552};
553
Roland McGratha4d48532005-06-08 20:45:28 +0000554static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000555 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000556#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000557 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000558#else
559 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
560#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000561 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
562};
563#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000564
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000565#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566
Roland McGratha4d48532005-06-08 20:45:28 +0000567static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200568decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000570 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000571 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000572 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000573
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000574 switch (style) {
575 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000576 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
577 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000578 tcp->scno = subcall + tcp->u_arg[0];
579 if (sysent[tcp->scno].nargs != -1)
580 tcp->u_nargs = sysent[tcp->scno].nargs;
581 else
582 tcp->u_nargs--;
583 for (i = 0; i < tcp->u_nargs; i++)
584 tcp->u_arg[i] = tcp->u_arg[i + 1];
585 break;
586 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000587 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
588 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 tcp->scno = subcall + tcp->u_arg[0];
590 addr = tcp->u_arg[1];
591 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000592 if (size == sizeof(int)) {
593 unsigned int arg;
594 if (umove(tcp, addr, &arg) < 0)
595 arg = 0;
596 tcp->u_arg[i] = arg;
597 }
598 else if (size == sizeof(long)) {
599 unsigned long arg;
600 if (umove(tcp, addr, &arg) < 0)
601 arg = 0;
602 tcp->u_arg[i] = arg;
603 }
604 else
605 abort();
606 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 }
608 tcp->u_nargs = sysent[tcp->scno].nargs;
609 break;
610 case mask_style:
611 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 for (i = 0; mask; i++)
613 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000614 if (i >= nsubcalls)
615 return;
616 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617 tcp->scno = subcall + i;
618 if (sysent[tcp->scno].nargs != -1)
619 tcp->u_nargs = sysent[tcp->scno].nargs;
620 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000621 case door_style:
622 /*
623 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000624 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000625 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000626 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
627 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000628 tcp->scno = subcall + tcp->u_arg[5];
629 if (sysent[tcp->scno].nargs != -1)
630 tcp->u_nargs = sysent[tcp->scno].nargs;
631 else
632 tcp->u_nargs--;
633 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000634#ifdef FREEBSD
635 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000636 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000637 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000638 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000639 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
640 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
641 for (i = 0; i < tcp->u_nargs; i++)
642 tcp->u_arg[i] = tcp->u_arg[i + 1];
643 }
644 break;
645#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000646 }
647}
648#endif
649
650struct tcb *tcp_last = NULL;
651
652static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000653internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000654{
655 /*
656 * We must always trace a few critical system calls in order to
657 * correctly support following forks in the presence of tracing
658 * qualifiers.
659 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000660 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000662 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
663 return 0;
664
665 func = sysent[tcp->scno].sys_func;
666
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000667 if ( sys_fork == func
668#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
669 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000671#ifdef LINUX
672 || sys_clone == func
673#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000674#if UNIXWARE > 2
675 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000677 )
678 return internal_fork(tcp);
679
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000680 if ( sys_execve == func
681#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
682 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000683#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000684#if UNIXWARE > 2
685 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000686#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000687 )
688 return internal_exec(tcp);
689
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000690 return 0;
691}
692
Wichert Akkermanc7926982000-04-10 22:22:31 +0000693
694#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200695# if defined (I386)
696static long eax;
697# elif defined (IA64)
698long r8, r10, psr; /* TODO: make static? */
699long ia32 = 0; /* not static */
700# elif defined (POWERPC)
701static long result, flags;
702# elif defined (M68K)
703static long d0;
704# elif defined(BFIN)
705static long r0;
706# elif defined (ARM)
707static struct pt_regs regs;
708# elif defined (ALPHA)
709static long r0;
710static long a3;
711# elif defined(AVR32)
712static struct pt_regs regs;
713# elif defined (SPARC) || defined (SPARC64)
714static struct pt_regs regs;
715static unsigned long trap;
716# elif defined(LINUX_MIPSN32)
717static long long a3;
718static long long r2;
719# elif defined(MIPS)
720static long a3;
721static long r2;
722# elif defined(S390) || defined(S390X)
723static long gpr2;
724static long pc;
725static long syscall_mode;
726# elif defined(HPPA)
727static long r28;
728# elif defined(SH)
729static long r0;
730# elif defined(SH64)
731static long r9;
732# elif defined(X86_64)
733static long rax;
734# elif defined(CRISV10) || defined(CRISV32)
735static long r10;
736# elif defined(MICROBLAZE)
737static long r3;
738# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000739#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000740#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200741struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000742#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000743
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000744int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000745get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000747 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000748
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000749#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000750# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000751 if (tcp->flags & TCB_WAITEXECVE) {
752 /*
753 * When the execve system call completes successfully, the
754 * new process still has -ENOSYS (old style) or __NR_execve
755 * (new style) in gpr2. We cannot recover the scno again
756 * by disassembly, because the image that executed the
757 * syscall is gone now. Fortunately, we don't want it. We
758 * leave the flag set so that syscall_fixup can fake the
759 * result.
760 */
761 if (tcp->flags & TCB_INSYSCALL)
762 return 1;
763 /*
764 * This is the SIGTRAP after execve. We cannot try to read
765 * the system call here either.
766 */
767 tcp->flags &= ~TCB_WAITEXECVE;
768 return 0;
769 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000770
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000771 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200772 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000773
774 if (syscall_mode != -ENOSYS) {
775 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000776 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000777 */
778 scno = syscall_mode;
779 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000780 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000781 * Old style of "passing" the scno via the SVC instruction.
782 */
783
784 long opcode, offset_reg, tmp;
785 void * svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200786 static const int gpr_offset[16] = {
787 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
788 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
789 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
790 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
791 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000792
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000793 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000794 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000795 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000796 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000797 if (errno) {
798 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000799 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000800 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000801
802 /*
803 * We have to check if the SVC got executed directly or via an
804 * EXECUTE instruction. In case of EXECUTE it is necessary to do
805 * instruction decoding to derive the system call number.
806 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
807 * so that this doesn't work if a SVC opcode is part of an EXECUTE
808 * opcode. Since there is no way to find out the opcode size this
809 * is the best we can do...
810 */
811
812 if ((opcode & 0xff00) == 0x0a00) {
813 /* SVC opcode */
814 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000815 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000816 else {
817 /* SVC got executed by EXECUTE instruction */
818
819 /*
820 * Do instruction decoding of EXECUTE. If you really want to
821 * understand this, read the Principles of Operations.
822 */
823 svc_addr = (void *) (opcode & 0xfff);
824
825 tmp = 0;
826 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000827 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000828 return -1;
829 svc_addr += tmp;
830
831 tmp = 0;
832 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000833 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000834 return -1;
835 svc_addr += tmp;
836
Denys Vlasenkofb036672009-01-23 16:30:26 +0000837 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000838 if (errno)
839 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000840# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000841 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000842# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000843 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000844# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000845 tmp = 0;
846 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000847 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000848 return -1;
849
850 scno = (scno | tmp) & 0xff;
851 }
852 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000853# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000854 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000855 return -1;
856 if (!(tcp->flags & TCB_INSYSCALL)) {
857 /* Check if we return from execve. */
858 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
859 tcp->flags &= ~TCB_WAITEXECVE;
860 return 0;
861 }
862 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200863
864# ifdef POWERPC64
865 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200866 /* TODO: speed up strace by not doing this at every syscall.
867 * We only need to do it after execve.
868 */
869 int currpers;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200870 long val;
871 int pid = tcp->pid;
872
873 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200874 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200875 return -1;
876 /* SF is bit 0 of MSR */
877 if (val < 0)
878 currpers = 0;
879 else
880 currpers = 1;
881 if (currpers != current_personality) {
882 static const char *const names[] = {"64 bit", "32 bit"};
883 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000884 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200885 pid, names[current_personality]);
886 }
887 }
888# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000889# elif defined(AVR32)
890 /*
891 * Read complete register set in one go.
892 */
893 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
894 return -1;
895
896 /*
897 * We only need to grab the syscall number on syscall entry.
898 */
899 if (!(tcp->flags & TCB_INSYSCALL)) {
900 scno = regs.r8;
901
902 /* Check if we return from execve. */
903 if (tcp->flags & TCB_WAITEXECVE) {
904 tcp->flags &= ~TCB_WAITEXECVE;
905 return 0;
906 }
907 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000908# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000909 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000910 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000911# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000912 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000913 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000914# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000915 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000916 return -1;
917
Roland McGrath761b5d72002-12-15 23:58:31 +0000918 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200919 /* TODO: speed up strace by not doing this at every syscall.
920 * We only need to do it after execve.
921 */
922 int currpers;
Michal Ludvig0e035502002-09-23 15:41:01 +0000923 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000924 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000925
926 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200927 * 0x33 for long mode (64 bit)
928 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000929 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000930 * to be cached.
931 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000932 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000933 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000934 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000935 case 0x23: currpers = 1; break;
936 case 0x33: currpers = 0; break;
937 default:
938 fprintf(stderr, "Unknown value CS=0x%02X while "
939 "detecting personality of process "
940 "PID=%d\n", (int)val, pid);
941 currpers = current_personality;
942 break;
943 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000944# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000945 /* This version analyzes the opcode of a syscall instruction.
946 * (int 0x80 on i386 vs. syscall on x86-64)
947 * It works, but is too complicated.
948 */
949 unsigned long val, rip, i;
950
Denys Vlasenko8236f252009-01-02 18:10:08 +0000951 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000952 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000953
Michal Ludvig0e035502002-09-23 15:41:01 +0000954 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000955 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000956 errno = 0;
957
Denys Vlasenko8236f252009-01-02 18:10:08 +0000958 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000959 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000960 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000961 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000962 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000963 /* x86-64: syscall = 0x0f 0x05 */
964 case 0x050f: currpers = 0; break;
965 /* i386: int 0x80 = 0xcd 0x80 */
966 case 0x80cd: currpers = 1; break;
967 default:
968 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000969 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000970 "Unknown syscall opcode (0x%04X) while "
971 "detecting personality of process "
972 "PID=%d\n", (int)call, pid);
973 break;
974 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000975# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000976 if (currpers != current_personality) {
977 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000978 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000979 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000980 pid, names[current_personality]);
981 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000982 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000983# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000984# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200985 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000986 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000987 if (!(tcp->flags & TCB_INSYSCALL)) {
988 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000989 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000990 return -1;
991 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200992 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000993 return -1;
994 }
Roland McGrathba954762003-03-05 06:29:06 +0000995 /* Check if we return from execve. */
996 if (tcp->flags & TCB_WAITEXECVE) {
997 tcp->flags &= ~TCB_WAITEXECVE;
998 return 0;
999 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001000 } else {
1001 /* syscall in progress */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001002 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001003 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001004 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001005 return -1;
1006 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001007# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001008 /*
1009 * Read complete register set in one go.
1010 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001011 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001012 return -1;
1013
1014 /*
1015 * We only need to grab the syscall number on syscall entry.
1016 */
1017 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001018 if (!(tcp->flags & TCB_INSYSCALL)) {
1019 /* Check if we return from execve. */
1020 if (tcp->flags & TCB_WAITEXECVE) {
1021 tcp->flags &= ~TCB_WAITEXECVE;
1022 return 0;
1023 }
1024 }
1025
Roland McGrath0f87c492003-06-03 23:29:04 +00001026 /*
1027 * Note: we only deal with only 32-bit CPUs here.
1028 */
1029 if (regs.ARM_cpsr & 0x20) {
1030 /*
1031 * Get the Thumb-mode system call number
1032 */
1033 scno = regs.ARM_r7;
1034 } else {
1035 /*
1036 * Get the ARM-mode system call number
1037 */
1038 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001039 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001040 if (errno)
1041 return -1;
1042
1043 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1044 tcp->flags &= ~TCB_WAITEXECVE;
1045 return 0;
1046 }
1047
Roland McGrathf691bd22006-04-25 07:34:41 +00001048 /* Handle the EABI syscall convention. We do not
1049 bother converting structures between the two
1050 ABIs, but basic functionality should work even
1051 if strace and the traced program have different
1052 ABIs. */
1053 if (scno == 0xef000000) {
1054 scno = regs.ARM_r7;
1055 } else {
1056 if ((scno & 0x0ff00000) != 0x0f900000) {
1057 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1058 scno);
1059 return -1;
1060 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001061
Roland McGrathf691bd22006-04-25 07:34:41 +00001062 /*
1063 * Fixup the syscall number
1064 */
1065 scno &= 0x000fffff;
1066 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001067 }
Roland McGrath56703312008-05-20 01:35:55 +00001068 if (scno & 0x0f0000) {
1069 /*
1070 * Handle ARM specific syscall
1071 */
1072 set_personality(1);
1073 scno &= 0x0000ffff;
1074 } else
1075 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001076
1077 if (tcp->flags & TCB_INSYSCALL) {
1078 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1079 tcp->flags &= ~TCB_INSYSCALL;
1080 }
1081 } else {
1082 if (!(tcp->flags & TCB_INSYSCALL)) {
1083 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1084 tcp->flags |= TCB_INSYSCALL;
1085 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001087# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001088 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001090# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001091 unsigned long long regs[38];
1092
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001093 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001094 return -1;
1095 a3 = regs[REG_A3];
1096 r2 = regs[REG_V0];
1097
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001098 if (!(tcp->flags & TCB_INSYSCALL)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001099 scno = r2;
1100
1101 /* Check if we return from execve. */
1102 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1103 tcp->flags &= ~TCB_WAITEXECVE;
1104 return 0;
1105 }
1106
1107 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001108 if (a3 == 0 || a3 == -1) {
1109 if (debug)
1110 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001111 return 0;
1112 }
1113 }
1114 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001115# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001116 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001117 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001118 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001119 if (upeek(tcp, REG_V0, &scno) < 0)
1120 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001121
Roland McGrath542c2c62008-05-20 01:11:56 +00001122 /* Check if we return from execve. */
1123 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1124 tcp->flags &= ~TCB_WAITEXECVE;
1125 return 0;
1126 }
1127
Wichert Akkermanf90da011999-10-31 21:15:38 +00001128 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001129 if (a3 == 0 || a3 == -1) {
1130 if (debug)
1131 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001132 return 0;
1133 }
1134 }
1135 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001136 if (upeek(tcp, REG_V0, &r2) < 0)
1137 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001138 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001139# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001140 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001141 return -1;
1142
1143 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001144 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145 return -1;
1146
1147 /* Check if we return from execve. */
1148 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1149 tcp->flags &= ~TCB_WAITEXECVE;
1150 return 0;
1151 }
1152
1153 /*
1154 * Do some sanity checks to figure out if it's
1155 * really a syscall entry
1156 */
1157 if (scno < 0 || scno > nsyscalls) {
1158 if (a3 == 0 || a3 == -1) {
1159 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001160 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161 return 0;
1162 }
1163 }
1164 }
1165 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001166 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167 return -1;
1168 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001169# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001170 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001171 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 return -1;
1173
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001174 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175 if (!(tcp->flags & TCB_INSYSCALL)) {
1176 /* Retrieve the syscall trap instruction. */
1177 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001178# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001179 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001180 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001181# else
1182 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001183# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184 if (errno)
1185 return -1;
1186
1187 /* Disassemble the trap to see what personality to use. */
1188 switch (trap) {
1189 case 0x91d02010:
1190 /* Linux/SPARC syscall trap. */
1191 set_personality(0);
1192 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001193 case 0x91d0206d:
1194 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001195 set_personality(2);
1196 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197 case 0x91d02000:
1198 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001199 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001200 return -1;
1201 case 0x91d02008:
1202 /* Solaris 2.x syscall trap. (per 2) */
1203 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001204 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001205 case 0x91d02009:
1206 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001207 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001208 return -1;
1209 case 0x91d02027:
1210 /* Solaris 2.x gettimeofday */
1211 set_personality(1);
1212 break;
1213 default:
1214 /* Unknown syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001215 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216 tcp->flags &= ~TCB_WAITEXECVE;
1217 return 0;
1218 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001219# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001220 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001221# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001222 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001223# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224 return -1;
1225 }
1226
1227 /* Extract the system call number from the registers. */
1228 if (trap == 0x91d02027)
1229 scno = 156;
1230 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001231 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001233 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001234 memmove(&regs.u_regs[U_REG_O0], &regs.u_regs[U_REG_O1], 7*sizeof(regs.u_regs[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 }
1236 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001237# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001238 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001239 return -1;
1240 if (!(tcp->flags & TCB_INSYSCALL)) {
1241 /* Check if we return from execve. */
1242 if ((tcp->flags & TCB_WAITEXECVE)) {
1243 tcp->flags &= ~TCB_WAITEXECVE;
1244 return 0;
1245 }
1246 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001247# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001248 /*
1249 * In the new syscall ABI, the system call number is in R3.
1250 */
1251 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1252 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001253
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001254 if (scno < 0) {
1255 /* Odd as it may seem, a glibc bug has been known to cause
1256 glibc to issue bogus negative syscall numbers. So for
1257 our purposes, make strace print what it *should* have been */
1258 long correct_scno = (scno & 0xff);
1259 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001260 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001261 "Detected glibc bug: bogus system call"
1262 " number = %ld, correcting to %ld\n",
1263 scno,
1264 correct_scno);
1265 scno = correct_scno;
1266 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001267
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001268 if (!(tcp->flags & TCB_INSYSCALL)) {
1269 /* Check if we return from execve. */
1270 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1271 tcp->flags &= ~TCB_WAITEXECVE;
1272 return 0;
1273 }
1274 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001275# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001276 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001277 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001278 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001279
1280 if (!(tcp->flags & TCB_INSYSCALL)) {
1281 /* Check if we return from execve. */
1282 if (tcp->flags & TCB_WAITEXECVE) {
1283 tcp->flags &= ~TCB_WAITEXECVE;
1284 return 0;
1285 }
1286 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001287# elif defined(CRISV10) || defined(CRISV32)
1288 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1289 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001290# elif defined(TILE)
1291 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1292 return -1;
1293
1294 if (!(tcp->flags & TCB_INSYSCALL)) {
1295 /* Check if we return from execve. */
1296 if (tcp->flags & TCB_WAITEXECVE) {
1297 tcp->flags &= ~TCB_WAITEXECVE;
1298 return 0;
1299 }
1300 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001301# elif defined(MICROBLAZE)
1302 if (upeek(tcp, 0, &scno) < 0)
1303 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001304# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001305#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001306
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001308 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001309 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001310#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001311 /* new syscall ABI returns result in R0 */
1312 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1313 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001314#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001315 /* ABI defines result returned in r9 */
1316 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1317 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001319
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001320#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001321# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001322 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001323# else
1324# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001325 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001326# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001327 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001328 perror("pread");
1329 return -1;
1330 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001331 switch (regs.r_eax) {
1332 case SYS_syscall:
1333 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001334 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1335 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001336 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001337 scno = regs.r_eax;
1338 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001339 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001340# endif /* FREEBSD */
1341# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001342#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001343
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001344 if (!(tcp->flags & TCB_INSYSCALL))
1345 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001346 return 1;
1347}
1348
Pavel Machek4dc3b142000-02-01 17:58:41 +00001349
Roland McGrath17352792005-06-07 23:21:26 +00001350long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001351known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001352{
1353 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001354#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001355 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1356 scno = sysent[scno].native_scno;
1357 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001358#endif
Roland McGrath17352792005-06-07 23:21:26 +00001359 scno += NR_SYSCALL_BASE;
1360 return scno;
1361}
1362
Roland McGratheb9e2e82009-06-02 16:49:22 -07001363/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001364 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001365 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1366 * 1: ok, continue in trace_syscall().
1367 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001368 * ("????" etc) and bail out.
1369 */
Roland McGratha4d48532005-06-08 20:45:28 +00001370static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001371syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001372{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001373#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001374 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001375
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001377 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 if (
1379 scno == SYS_fork
1380#ifdef SYS_vfork
1381 || scno == SYS_vfork
1382#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001383#ifdef SYS_fork1
1384 || scno == SYS_fork1
1385#endif /* SYS_fork1 */
1386#ifdef SYS_forkall
1387 || scno == SYS_forkall
1388#endif /* SYS_forkall */
1389#ifdef SYS_rfork1
1390 || scno == SYS_rfork1
1391#endif /* SYS_fork1 */
1392#ifdef SYS_rforkall
1393 || scno == SYS_rforkall
1394#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001395 ) {
1396 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001397 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001398 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001399 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001400 }
1401 else {
1402 fprintf(stderr, "syscall: missing entry\n");
1403 tcp->flags |= TCB_INSYSCALL;
1404 }
1405 }
1406 }
1407 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001408 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001409 fprintf(stderr, "syscall: missing exit\n");
1410 tcp->flags &= ~TCB_INSYSCALL;
1411 }
1412 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001413#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001414#ifdef SUNOS4
1415 if (!(tcp->flags & TCB_INSYSCALL)) {
1416 if (scno == 0) {
1417 fprintf(stderr, "syscall: missing entry\n");
1418 tcp->flags |= TCB_INSYSCALL;
1419 }
1420 }
1421 else {
1422 if (scno != 0) {
1423 if (debug) {
1424 /*
1425 * This happens when a signal handler
1426 * for a signal which interrupted a
1427 * a system call makes another system call.
1428 */
1429 fprintf(stderr, "syscall: missing exit\n");
1430 }
1431 tcp->flags &= ~TCB_INSYSCALL;
1432 }
1433 }
1434#endif /* SUNOS4 */
1435#ifdef LINUX
1436#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001437 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001438 return -1;
1439 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1440 if (debug)
1441 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1442 return 0;
1443 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001444#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001445 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001446 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001447 if (current_personality == 1)
1448 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001449 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1450 if (debug)
1451 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1452 return 0;
1453 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001454#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001455 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001456 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001457 if (syscall_mode != -ENOSYS)
1458 syscall_mode = tcp->scno;
1459 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001460 if (debug)
1461 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1462 return 0;
1463 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001464 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1465 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1466 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1467 /*
1468 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1469 * flag set for the post-execve SIGTRAP to see and reset.
1470 */
1471 gpr2 = 0;
1472 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001473#elif defined (POWERPC)
1474# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001475 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001476 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001477 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001478 return -1;
1479 if (flags & SO_MASK)
1480 result = -result;
1481#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001482 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483 return -1;
1484 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1485 if (debug)
1486 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1487 return 0;
1488 }
1489#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001490 /*
1491 * Nothing required
1492 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001493#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001494 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001495 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001496#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001497 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001498 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001499#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001500 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001501 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001502 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001503 return -1;
1504 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1505 if (debug)
1506 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1507 return 0;
1508 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001509#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001510 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001511 return -1;
1512 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1513 if (debug)
1514 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1515 return 0;
1516 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001517#elif defined(MICROBLAZE)
1518 if (upeek(tcp, 3 * 4, &r3) < 0)
1519 return -1;
1520 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1521 if (debug)
1522 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1523 return 0;
1524 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001525#endif
1526#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001527 return 1;
1528}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001529
Roland McGrathc1e45922008-05-27 23:18:29 +00001530#ifdef LINUX
1531/*
1532 * Check the syscall return value register value for whether it is
1533 * a negated errno code indicating an error, or a success return value.
1534 */
1535static inline int
1536is_negated_errno(unsigned long int val)
1537{
1538 unsigned long int max = -(long int) nerrnos;
1539 if (personality_wordsize[current_personality] < sizeof(val)) {
1540 val = (unsigned int) val;
1541 max = (unsigned int) max;
1542 }
1543 return val > max;
1544}
1545#endif
1546
Roland McGratha4d48532005-06-08 20:45:28 +00001547static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001548get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001549{
1550 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001551#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001552 int check_errno = 1;
1553 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1554 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1555 check_errno = 0;
1556 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001557# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001558 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001559 tcp->u_rval = -1;
1560 u_error = -gpr2;
1561 }
1562 else {
1563 tcp->u_rval = gpr2;
1564 u_error = 0;
1565 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001566# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001567 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001568 tcp->u_rval = -1;
1569 u_error = -eax;
1570 }
1571 else {
1572 tcp->u_rval = eax;
1573 u_error = 0;
1574 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001575# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001576 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001577 tcp->u_rval = -1;
1578 u_error = -rax;
1579 }
1580 else {
1581 tcp->u_rval = rax;
1582 u_error = 0;
1583 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001584# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001585 if (ia32) {
1586 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001587
Roland McGrathc1e45922008-05-27 23:18:29 +00001588 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001589 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001590 tcp->u_rval = -1;
1591 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001592 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001593 else {
1594 tcp->u_rval = err;
1595 u_error = 0;
1596 }
1597 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001598 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001599 tcp->u_rval = -1;
1600 u_error = r8;
1601 } else {
1602 tcp->u_rval = r8;
1603 u_error = 0;
1604 }
1605 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001606# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001607 if (check_errno && a3) {
1608 tcp->u_rval = -1;
1609 u_error = r2;
1610 } else {
1611 tcp->u_rval = r2;
1612 u_error = 0;
1613 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001614# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001615 if (check_errno && is_negated_errno(result)) {
1616 tcp->u_rval = -1;
1617 u_error = -result;
1618 }
1619 else {
1620 tcp->u_rval = result;
1621 u_error = 0;
1622 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001623# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001624 if (check_errno && is_negated_errno(d0)) {
1625 tcp->u_rval = -1;
1626 u_error = -d0;
1627 }
1628 else {
1629 tcp->u_rval = d0;
1630 u_error = 0;
1631 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001632# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001633 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1634 tcp->u_rval = -1;
1635 u_error = -regs.ARM_r0;
1636 }
1637 else {
1638 tcp->u_rval = regs.ARM_r0;
1639 u_error = 0;
1640 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001641# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001642 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1643 tcp->u_rval = -1;
1644 u_error = -regs.r12;
1645 }
1646 else {
1647 tcp->u_rval = regs.r12;
1648 u_error = 0;
1649 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001650# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001651 if (check_errno && is_negated_errno(r0)) {
1652 tcp->u_rval = -1;
1653 u_error = -r0;
1654 } else {
1655 tcp->u_rval = r0;
1656 u_error = 0;
1657 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001658# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001659 if (check_errno && a3) {
1660 tcp->u_rval = -1;
1661 u_error = r0;
1662 }
1663 else {
1664 tcp->u_rval = r0;
1665 u_error = 0;
1666 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001667# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001668 if (check_errno && regs.psr & PSR_C) {
1669 tcp->u_rval = -1;
1670 u_error = regs.u_regs[U_REG_O0];
1671 }
1672 else {
1673 tcp->u_rval = regs.u_regs[U_REG_O0];
1674 u_error = 0;
1675 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001676# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001677 if (check_errno && regs.tstate & 0x1100000000UL) {
1678 tcp->u_rval = -1;
1679 u_error = regs.u_regs[U_REG_O0];
1680 }
1681 else {
1682 tcp->u_rval = regs.u_regs[U_REG_O0];
1683 u_error = 0;
1684 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001685# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001686 if (check_errno && is_negated_errno(r28)) {
1687 tcp->u_rval = -1;
1688 u_error = -r28;
1689 }
1690 else {
1691 tcp->u_rval = r28;
1692 u_error = 0;
1693 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001694# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001695 /* interpret R0 as return value or error number */
1696 if (check_errno && is_negated_errno(r0)) {
1697 tcp->u_rval = -1;
1698 u_error = -r0;
1699 }
1700 else {
1701 tcp->u_rval = r0;
1702 u_error = 0;
1703 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001704# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001705 /* interpret result as return value or error number */
1706 if (check_errno && is_negated_errno(r9)) {
1707 tcp->u_rval = -1;
1708 u_error = -r9;
1709 }
1710 else {
1711 tcp->u_rval = r9;
1712 u_error = 0;
1713 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001714# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001715 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1716 tcp->u_rval = -1;
1717 u_error = -r10;
1718 }
1719 else {
1720 tcp->u_rval = r10;
1721 u_error = 0;
1722 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001723# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001724 long rval;
1725 /* interpret result as return value or error number */
1726 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1727 return -1;
1728 if (check_errno && rval < 0 && rval > -nerrnos) {
1729 tcp->u_rval = -1;
1730 u_error = -rval;
1731 }
1732 else {
1733 tcp->u_rval = rval;
1734 u_error = 0;
1735 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001736# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001737 /* interpret result as return value or error number */
1738 if (check_errno && is_negated_errno(r3)) {
1739 tcp->u_rval = -1;
1740 u_error = -r3;
1741 }
1742 else {
1743 tcp->u_rval = r3;
1744 u_error = 0;
1745 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001746# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001747#endif /* LINUX */
1748#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001749 /* get error code from user struct */
1750 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1751 return -1;
1752 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001753
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001754 /* get system call return value */
1755 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1756 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001757#endif /* SUNOS4 */
1758#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001759# ifdef SPARC
1760 /* Judicious guessing goes a long way. */
1761 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1762 tcp->u_rval = -1;
1763 u_error = tcp->status.pr_reg[R_O0];
1764 }
1765 else {
1766 tcp->u_rval = tcp->status.pr_reg[R_O0];
1767 u_error = 0;
1768 }
1769# endif /* SPARC */
1770# ifdef I386
1771 /* Wanna know how to kill an hour single-stepping? */
1772 if (tcp->status.PR_REG[EFL] & 0x1) {
1773 tcp->u_rval = -1;
1774 u_error = tcp->status.PR_REG[EAX];
1775 }
1776 else {
1777 tcp->u_rval = tcp->status.PR_REG[EAX];
1778# ifdef HAVE_LONG_LONG
1779 tcp->u_lrval =
1780 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1781 tcp->status.PR_REG[EAX];
1782# endif
1783 u_error = 0;
1784 }
1785# endif /* I386 */
1786# ifdef X86_64
1787 /* Wanna know how to kill an hour single-stepping? */
1788 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1789 tcp->u_rval = -1;
1790 u_error = tcp->status.PR_REG[RAX];
1791 }
1792 else {
1793 tcp->u_rval = tcp->status.PR_REG[RAX];
1794 u_error = 0;
1795 }
1796# endif /* X86_64 */
1797# ifdef MIPS
1798 if (tcp->status.pr_reg[CTX_A3]) {
1799 tcp->u_rval = -1;
1800 u_error = tcp->status.pr_reg[CTX_V0];
1801 }
1802 else {
1803 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1804 u_error = 0;
1805 }
1806# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001807#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001808#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001809 if (regs.r_eflags & PSL_C) {
1810 tcp->u_rval = -1;
1811 u_error = regs.r_eax;
1812 } else {
1813 tcp->u_rval = regs.r_eax;
1814 tcp->u_lrval =
1815 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1816 u_error = 0;
1817 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001818#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001819 tcp->u_error = u_error;
1820 return 1;
1821}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001822
Roland McGrathb69f81b2002-12-21 23:25:18 +00001823int
Denys Vlasenko12014262011-05-30 14:00:14 +02001824force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001825{
1826#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001827# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001828 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001829 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1830 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001831# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001832 eax = error ? -error : rval;
1833 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1834 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001835# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001836 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001837 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001838 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001839# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001840 if (ia32) {
1841 r8 = error ? -error : rval;
1842 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1843 return -1;
1844 }
1845 else {
1846 if (error) {
1847 r8 = error;
1848 r10 = -1;
1849 }
1850 else {
1851 r8 = rval;
1852 r10 = 0;
1853 }
1854 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1855 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1856 return -1;
1857 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001858# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001859 r0 = error ? -error : rval;
1860 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1861 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001862# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001863 if (error) {
1864 r2 = error;
1865 a3 = -1;
1866 }
1867 else {
1868 r2 = rval;
1869 a3 = 0;
1870 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001871 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001872 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1873 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001874 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001875# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001876 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001877 return -1;
1878 if (error) {
1879 flags |= SO_MASK;
1880 result = error;
1881 }
1882 else {
1883 flags &= ~SO_MASK;
1884 result = rval;
1885 }
Roland McGratheb285352003-01-14 09:59:00 +00001886 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1887 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001888 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001889# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001890 d0 = error ? -error : rval;
1891 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1892 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001893# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001894 regs.ARM_r0 = error ? -error : rval;
1895 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001896 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001897# elif defined(AVR32)
1898 regs.r12 = error ? -error : rval;
1899 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1900 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001901# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001902 if (error) {
1903 a3 = -1;
1904 r0 = error;
1905 }
1906 else {
1907 a3 = 0;
1908 r0 = rval;
1909 }
1910 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1911 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1912 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001913# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001914 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1915 return -1;
1916 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001917 regs.psr |= PSR_C;
1918 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001919 }
1920 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001921 regs.psr &= ~PSR_C;
1922 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001923 }
1924 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1925 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001926# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001927 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1928 return -1;
1929 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001930 regs.tstate |= 0x1100000000UL;
1931 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001932 }
1933 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001934 regs.tstate &= ~0x1100000000UL;
1935 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001936 }
1937 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1938 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001939# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001940 r28 = error ? -error : rval;
1941 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1942 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001943# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001944 r0 = error ? -error : rval;
1945 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1946 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001947# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001948 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001949 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1950 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001951# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001952#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001953
Roland McGrathb69f81b2002-12-21 23:25:18 +00001954#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001955 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1956 error << 24) < 0 ||
1957 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001958 return -1;
1959#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001960
Roland McGrathb69f81b2002-12-21 23:25:18 +00001961#ifdef SVR4
1962 /* XXX no clue */
1963 return -1;
1964#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001965
Roland McGrathb69f81b2002-12-21 23:25:18 +00001966#ifdef FREEBSD
1967 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001968 perror("pread");
1969 return -1;
1970 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001971 if (error) {
1972 regs.r_eflags |= PSL_C;
1973 regs.r_eax = error;
1974 }
1975 else {
1976 regs.r_eflags &= ~PSL_C;
1977 regs.r_eax = rval;
1978 }
1979 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001980 perror("pwrite");
1981 return -1;
1982 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001983#endif /* FREEBSD */
1984
1985 /* All branches reach here on success (only). */
1986 tcp->u_error = error;
1987 tcp->u_rval = rval;
1988 return 0;
1989}
1990
Roland McGratha4d48532005-06-08 20:45:28 +00001991static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001992syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001993{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001994#ifdef LINUX
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001995# if defined(S390) || defined(S390X)
1996 int i;
1997 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1998 tcp->u_nargs = sysent[tcp->scno].nargs;
1999 else
2000 tcp->u_nargs = MAX_ARGS;
2001 for (i = 0; i < tcp->u_nargs; i++) {
2002 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
2003 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002004 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002005# elif defined(ALPHA)
2006 int i;
2007 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2008 tcp->u_nargs = sysent[tcp->scno].nargs;
2009 else
2010 tcp->u_nargs = MAX_ARGS;
2011 for (i = 0; i < tcp->u_nargs; i++) {
2012 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2013 * for scno somewhere above here!
2014 */
2015 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
2016 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002017 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002018# elif defined(IA64)
2019 if (!ia32) {
2020 unsigned long *out0, cfm, sof, sol, i;
2021 long rbs_end;
2022 /* be backwards compatible with kernel < 2.4.4... */
2023# ifndef PT_RBS_END
2024# define PT_RBS_END PT_AR_BSP
2025# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002026
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002027 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
2028 return -1;
2029 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002030 return -1;
2031
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002032 sof = (cfm >> 0) & 0x7f;
2033 sol = (cfm >> 7) & 0x7f;
2034 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
2035
2036 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2037 && sysent[tcp->scno].nargs != -1)
2038 tcp->u_nargs = sysent[tcp->scno].nargs;
2039 else
2040 tcp->u_nargs = MAX_ARGS;
2041 for (i = 0; i < tcp->u_nargs; ++i) {
2042 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2043 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2044 return -1;
2045 }
2046 } else {
2047 int i;
2048
2049 if (/* EBX = out0 */
2050 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
2051 /* ECX = out1 */
2052 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
2053 /* EDX = out2 */
2054 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
2055 /* ESI = out3 */
2056 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
2057 /* EDI = out4 */
2058 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
2059 /* EBP = out5 */
2060 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2061 return -1;
2062
2063 for (i = 0; i < 6; ++i)
2064 /* truncate away IVE sign-extension */
2065 tcp->u_arg[i] &= 0xffffffff;
2066
2067 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2068 && sysent[tcp->scno].nargs != -1)
2069 tcp->u_nargs = sysent[tcp->scno].nargs;
2070 else
2071 tcp->u_nargs = 5;
2072 }
2073# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2074 /* N32 and N64 both use up to six registers. */
2075 unsigned long long regs[38];
2076 int i, nargs;
2077 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2078 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2079 else
2080 nargs = tcp->u_nargs = MAX_ARGS;
2081
2082 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2083 return -1;
2084
2085 for (i = 0; i < nargs; i++) {
2086 tcp->u_arg[i] = regs[REG_A0 + i];
2087# if defined(LINUX_MIPSN32)
2088 tcp->ext_arg[i] = regs[REG_A0 + i];
2089# endif
2090 }
2091# elif defined(MIPS)
2092 long sp;
2093 int i, nargs;
2094
2095 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2096 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2097 else
2098 nargs = tcp->u_nargs = MAX_ARGS;
2099 if (nargs > 4) {
2100 if (upeek(tcp, REG_SP, &sp) < 0)
2101 return -1;
2102 for (i = 0; i < 4; i++) {
2103 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2104 return -1;
2105 }
2106 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2107 (char *)(tcp->u_arg + 4));
2108 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002109 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002110 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002111 return -1;
2112 }
2113 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002114# elif defined(POWERPC)
2115# ifndef PT_ORIG_R3
2116# define PT_ORIG_R3 34
2117# endif
2118 int i;
2119 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2120 tcp->u_nargs = sysent[tcp->scno].nargs;
2121 else
2122 tcp->u_nargs = MAX_ARGS;
2123 for (i = 0; i < tcp->u_nargs; i++) {
2124 if (upeek(tcp, (i==0) ?
2125 (sizeof(unsigned long) * PT_ORIG_R3) :
2126 ((i+PT_R3) * sizeof(unsigned long)),
2127 &tcp->u_arg[i]) < 0)
2128 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002129 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002130# elif defined(SPARC) || defined(SPARC64)
2131 int i;
2132 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2133 tcp->u_nargs = sysent[tcp->scno].nargs;
2134 else
2135 tcp->u_nargs = MAX_ARGS;
2136 for (i = 0; i < tcp->u_nargs; i++)
2137 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2138# elif defined(HPPA)
2139 int i;
2140 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2141 tcp->u_nargs = sysent[tcp->scno].nargs;
2142 else
2143 tcp->u_nargs = MAX_ARGS;
2144 for (i = 0; i < tcp->u_nargs; i++) {
2145 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2146 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002147 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002148# elif defined(ARM)
2149 int i;
2150 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2151 tcp->u_nargs = sysent[tcp->scno].nargs;
2152 else
2153 tcp->u_nargs = MAX_ARGS;
2154 for (i = 0; i < tcp->u_nargs; i++)
2155 tcp->u_arg[i] = regs.uregs[i];
2156# elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002157 tcp->u_nargs = sysent[tcp->scno].nargs;
2158 tcp->u_arg[0] = regs.r12;
2159 tcp->u_arg[1] = regs.r11;
2160 tcp->u_arg[2] = regs.r10;
2161 tcp->u_arg[3] = regs.r9;
2162 tcp->u_arg[4] = regs.r5;
2163 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002164# elif defined(BFIN)
2165 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002166 static const int argreg[] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002167
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002168 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002169 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002170 else
2171 tcp->u_nargs = ARRAY_SIZE(argreg);
2172
2173 for (i = 0; i < tcp->u_nargs; ++i)
2174 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2175 return -1;
2176# elif defined(SH)
2177 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002178 static const int syscall_regs[] = {
2179 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6), 4 * (REG_REG0+7),
2180 4 * (REG_REG0 ), 4 * (REG_REG0+1), 4 * (REG_REG0+2)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002181 };
2182
2183 tcp->u_nargs = sysent[tcp->scno].nargs;
2184 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002185 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002186 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002187 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002188# elif defined(SH64)
2189 int i;
2190 /* Registers used by SH5 Linux system calls for parameters */
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002191 static const int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002192
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002193 /*
2194 * TODO: should also check that the number of arguments encoded
2195 * in the trap number matches the number strace expects.
2196 */
2197 /*
2198 assert(sysent[tcp->scno].nargs < ARRAY_SIZE(syscall_regs));
2199 */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002200
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002201 tcp->u_nargs = sysent[tcp->scno].nargs;
2202 for (i = 0; i < tcp->u_nargs; i++) {
2203 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2204 return -1;
2205 }
2206# elif defined(X86_64)
2207 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002208 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2209 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2210 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002211 };
2212
2213 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002214 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002215 else
2216 tcp->u_nargs = MAX_ARGS;
2217 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002218 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002219 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00002220 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002221# elif defined(MICROBLAZE)
2222 int i;
2223 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2224 tcp->u_nargs = sysent[tcp->scno].nargs;
2225 else
2226 tcp->u_nargs = 0;
2227 for (i = 0; i < tcp->u_nargs; i++) {
2228 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2229 return -1;
2230 }
2231# elif defined(CRISV10) || defined(CRISV32)
2232 int i;
2233 static const int crisregs[] = {
2234 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002235 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002236 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002237
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002238 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2239 tcp->u_nargs = sysent[tcp->scno].nargs;
2240 else
2241 tcp->u_nargs = 0;
2242 for (i = 0; i < tcp->u_nargs; i++) {
2243 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2244 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00002245 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002246# elif defined(TILE)
2247 int i;
2248 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2249 tcp->u_nargs = sysent[tcp->scno].nargs;
2250 else
2251 tcp->u_nargs = MAX_ARGS;
2252 for (i = 0; i < tcp->u_nargs; ++i) {
2253 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2254 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002255 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002256# elif defined(M68K)
2257 int i;
2258 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2259 tcp->u_nargs = sysent[tcp->scno].nargs;
2260 else
2261 tcp->u_nargs = MAX_ARGS;
2262 for (i = 0; i < tcp->u_nargs; i++) {
2263 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2264 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002265 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002266# else /* Other architecture (like i386) (32bits specific) */
2267 int i;
2268 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2269 tcp->u_nargs = sysent[tcp->scno].nargs;
2270 else
2271 tcp->u_nargs = MAX_ARGS;
2272 for (i = 0; i < tcp->u_nargs; i++) {
2273 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2274 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05002275 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002276# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002277#endif /* LINUX */
2278#ifdef SUNOS4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002279 int i;
2280 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2281 tcp->u_nargs = sysent[tcp->scno].nargs;
2282 else
2283 tcp->u_nargs = MAX_ARGS;
2284 for (i = 0; i < tcp->u_nargs; i++) {
2285 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002286
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002287 if (upeek(tcp, uoff(u_arg[0]) +
2288 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2289 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002290 }
2291#endif /* SUNOS4 */
2292#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002293# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 /*
2295 * SGI is broken: even though it has pr_sysarg, it doesn't
2296 * set them on system call entry. Get a clue.
2297 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002298 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002299 tcp->u_nargs = sysent[tcp->scno].nargs;
2300 else
2301 tcp->u_nargs = tcp->status.pr_nsysarg;
2302 if (tcp->u_nargs > 4) {
2303 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002304 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002305 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002306 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002307 }
2308 else {
2309 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002310 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002311 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002312# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002313 /*
2314 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2315 */
2316 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2317 tcp->u_nargs = sysent[tcp->scno].nargs;
2318 else
2319 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2320 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002321 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2322# elif defined(HAVE_PR_SYSCALL)
2323 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002324 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002325 tcp->u_nargs = sysent[tcp->scno].nargs;
2326 else
2327 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002328 for (i = 0; i < tcp->u_nargs; i++)
2329 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2330# elif defined(I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002331 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002332 tcp->u_nargs = sysent[tcp->scno].nargs;
2333 else
2334 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002335 if (tcp->u_nargs > 0)
2336 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002337 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2338# else
John Hughes25299712001-03-06 10:10:06 +00002339 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002340# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002341#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002342#ifdef FREEBSD
2343 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2344 sysent[tcp->scno].nargs > tcp->status.val)
2345 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002346 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002347 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002348 if (tcp->u_nargs < 0)
2349 tcp->u_nargs = 0;
2350 if (tcp->u_nargs > MAX_ARGS)
2351 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002352 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002353 case SYS___syscall:
2354 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2355 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002356 break;
2357 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002358 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2359 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002360 break;
2361 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002362 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2363 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002364 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002365 }
2366#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002367 return 1;
2368}
2369
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002370static int
2371trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002372{
2373 int sys_res;
2374 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002375 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002376 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002377
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002378 /* Measure the exit time as early as possible to avoid errors. */
2379 if (dtime || cflag)
2380 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002381
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002382 /* BTW, why we don't just memorize syscall no. on entry
2383 * in tcp->something?
2384 */
2385 scno_good = res = get_scno(tcp);
2386 if (res == 0)
2387 return res;
2388 if (res == 1)
2389 res = syscall_fixup(tcp);
2390 if (res == 0)
2391 return res;
2392 if (res == 1)
2393 res = get_error(tcp);
2394 if (res == 0)
2395 return res;
2396 if (res == 1)
2397 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002398
Grant Edwards8a082772011-04-07 20:25:40 +00002399 if (res == 1 && filtered(tcp)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002400 tcp->flags &= ~TCB_INSYSCALL;
2401 return 0;
2402 }
2403
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002404 if (tcp->flags & TCB_REPRINT) {
2405 printleader(tcp);
2406 tprintf("<... ");
2407 if (scno_good != 1)
2408 tprintf("????");
2409 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2410 tprintf("syscall_%lu", tcp->scno);
2411 else
2412 tprintf("%s", sysent[tcp->scno].sys_name);
2413 tprintf(" resumed> ");
2414 }
2415
2416 if (cflag) {
2417 struct timeval t = tv;
2418 int rc = count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002419 if (cflag == CFLAG_ONLY_STATS) {
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002420 tcp->flags &= ~TCB_INSYSCALL;
2421 return rc;
2422 }
2423 }
2424
2425 if (res != 1) {
2426 tprintf(") ");
2427 tabto(acolumn);
2428 tprintf("= ? <unavailable>");
2429 printtrailer();
2430 tcp->flags &= ~TCB_INSYSCALL;
2431 return res;
2432 }
2433
2434 if (tcp->scno >= nsyscalls || tcp->scno < 0
2435 || (qual_flags[tcp->scno] & QUAL_RAW))
2436 sys_res = printargs(tcp);
2437 else {
2438 if (not_failing_only && tcp->u_error)
2439 return 0; /* ignore failed syscalls */
2440 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2441 }
2442
2443 u_error = tcp->u_error;
2444 tprintf(") ");
2445 tabto(acolumn);
2446 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2447 qual_flags[tcp->scno] & QUAL_RAW) {
2448 if (u_error)
2449 tprintf("= -1 (errno %ld)", u_error);
2450 else
2451 tprintf("= %#lx", tcp->u_rval);
2452 }
2453 else if (!(sys_res & RVAL_NONE) && u_error) {
2454 switch (u_error) {
2455#ifdef LINUX
2456 case ERESTARTSYS:
2457 tprintf("= ? ERESTARTSYS (To be restarted)");
2458 break;
2459 case ERESTARTNOINTR:
2460 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2461 break;
2462 case ERESTARTNOHAND:
2463 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2464 break;
2465 case ERESTART_RESTARTBLOCK:
2466 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2467 break;
2468#endif /* LINUX */
2469 default:
2470 tprintf("= -1 ");
2471 if (u_error < 0)
2472 tprintf("E??? (errno %ld)", u_error);
2473 else if (u_error < nerrnos)
2474 tprintf("%s (%s)", errnoent[u_error],
2475 strerror(u_error));
2476 else
2477 tprintf("ERRNO_%ld (%s)", u_error,
2478 strerror(u_error));
2479 break;
2480 }
2481 if ((sys_res & RVAL_STR) && tcp->auxstr)
2482 tprintf(" (%s)", tcp->auxstr);
2483 }
2484 else {
2485 if (sys_res & RVAL_NONE)
2486 tprintf("= ?");
2487 else {
2488 switch (sys_res & RVAL_MASK) {
2489 case RVAL_HEX:
2490 tprintf("= %#lx", tcp->u_rval);
2491 break;
2492 case RVAL_OCTAL:
2493 tprintf("= %#lo", tcp->u_rval);
2494 break;
2495 case RVAL_UDECIMAL:
2496 tprintf("= %lu", tcp->u_rval);
2497 break;
2498 case RVAL_DECIMAL:
2499 tprintf("= %ld", tcp->u_rval);
2500 break;
2501#ifdef HAVE_LONG_LONG
2502 case RVAL_LHEX:
2503 tprintf("= %#llx", tcp->u_lrval);
2504 break;
2505 case RVAL_LOCTAL:
2506 tprintf("= %#llo", tcp->u_lrval);
2507 break;
2508 case RVAL_LUDECIMAL:
2509 tprintf("= %llu", tcp->u_lrval);
2510 break;
2511 case RVAL_LDECIMAL:
2512 tprintf("= %lld", tcp->u_lrval);
2513 break;
2514#endif
2515 default:
2516 fprintf(stderr,
2517 "invalid rval format\n");
2518 break;
2519 }
2520 }
2521 if ((sys_res & RVAL_STR) && tcp->auxstr)
2522 tprintf(" (%s)", tcp->auxstr);
2523 }
2524 if (dtime) {
2525 tv_sub(&tv, &tv, &tcp->etime);
2526 tprintf(" <%ld.%06ld>",
2527 (long) tv.tv_sec, (long) tv.tv_usec);
2528 }
2529 printtrailer();
2530
2531 dumpio(tcp);
2532 if (fflush(tcp->outf) == EOF)
2533 return -1;
2534 tcp->flags &= ~TCB_INSYSCALL;
2535 return 0;
2536}
2537
2538static int
2539trace_syscall_entering(struct tcb *tcp)
2540{
2541 int sys_res;
2542 int res, scno_good;
2543
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002544 scno_good = res = get_scno(tcp);
2545 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002546 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002547 if (res == 1)
2548 res = syscall_fixup(tcp);
2549 if (res == 0)
2550 return res;
2551 if (res == 1)
2552 res = syscall_enter(tcp);
2553 if (res == 0)
2554 return res;
2555
2556 if (res != 1) {
2557 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002558 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002559 tcp_last = tcp;
2560 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002561 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002562 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2563 tprintf("syscall_%lu(", tcp->scno);
2564 else
2565 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002566 /*
2567 * " <unavailable>" will be added later by the code which
2568 * detects ptrace errors.
2569 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002570 tcp->flags |= TCB_INSYSCALL;
2571 return res;
2572 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002573
Roland McGrath17352792005-06-07 23:21:26 +00002574 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002575#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002576 case SYS_socketcall:
2577 decode_subcall(tcp, SYS_socket_subcall,
2578 SYS_socket_nsubcalls, deref_style);
2579 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002580#endif
2581#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002582 case SYS_ipc:
2583 decode_subcall(tcp, SYS_ipc_subcall,
2584 SYS_ipc_nsubcalls, shift_style);
2585 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002586#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002587#ifdef SVR4
2588#ifdef SYS_pgrpsys_subcall
2589 case SYS_pgrpsys:
2590 decode_subcall(tcp, SYS_pgrpsys_subcall,
2591 SYS_pgrpsys_nsubcalls, shift_style);
2592 break;
2593#endif /* SYS_pgrpsys_subcall */
2594#ifdef SYS_sigcall_subcall
2595 case SYS_sigcall:
2596 decode_subcall(tcp, SYS_sigcall_subcall,
2597 SYS_sigcall_nsubcalls, mask_style);
2598 break;
2599#endif /* SYS_sigcall_subcall */
2600 case SYS_msgsys:
2601 decode_subcall(tcp, SYS_msgsys_subcall,
2602 SYS_msgsys_nsubcalls, shift_style);
2603 break;
2604 case SYS_shmsys:
2605 decode_subcall(tcp, SYS_shmsys_subcall,
2606 SYS_shmsys_nsubcalls, shift_style);
2607 break;
2608 case SYS_semsys:
2609 decode_subcall(tcp, SYS_semsys_subcall,
2610 SYS_semsys_nsubcalls, shift_style);
2611 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002612 case SYS_sysfs:
2613 decode_subcall(tcp, SYS_sysfs_subcall,
2614 SYS_sysfs_nsubcalls, shift_style);
2615 break;
2616 case SYS_spcall:
2617 decode_subcall(tcp, SYS_spcall_subcall,
2618 SYS_spcall_nsubcalls, shift_style);
2619 break;
2620#ifdef SYS_context_subcall
2621 case SYS_context:
2622 decode_subcall(tcp, SYS_context_subcall,
2623 SYS_context_nsubcalls, shift_style);
2624 break;
2625#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002626#ifdef SYS_door_subcall
2627 case SYS_door:
2628 decode_subcall(tcp, SYS_door_subcall,
2629 SYS_door_nsubcalls, door_style);
2630 break;
2631#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002632#ifdef SYS_kaio_subcall
2633 case SYS_kaio:
2634 decode_subcall(tcp, SYS_kaio_subcall,
2635 SYS_kaio_nsubcalls, shift_style);
2636 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002637#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002638#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002639#ifdef FREEBSD
2640 case SYS_msgsys:
2641 case SYS_shmsys:
2642 case SYS_semsys:
2643 decode_subcall(tcp, 0, 0, table_style);
2644 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002645#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002646#ifdef SUNOS4
2647 case SYS_semsys:
2648 decode_subcall(tcp, SYS_semsys_subcall,
2649 SYS_semsys_nsubcalls, shift_style);
2650 break;
2651 case SYS_msgsys:
2652 decode_subcall(tcp, SYS_msgsys_subcall,
2653 SYS_msgsys_nsubcalls, shift_style);
2654 break;
2655 case SYS_shmsys:
2656 decode_subcall(tcp, SYS_shmsys_subcall,
2657 SYS_shmsys_nsubcalls, shift_style);
2658 break;
2659#endif
2660 }
2661
2662 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002663
2664 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2665 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2666 (tracing_paths && !pathtrace_match(tcp))) {
2667 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002668 return 0;
2669 }
2670
Grant Edwards8a082772011-04-07 20:25:40 +00002671 tcp->flags &= ~TCB_FILTERED;
2672
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002673 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002674 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002675 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002676 return 0;
2677 }
2678
2679 printleader(tcp);
2680 tcp->flags &= ~TCB_REPRINT;
2681 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002682 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002683 tprintf("syscall_%lu(", tcp->scno);
2684 else
2685 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002686 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002687 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2688 sysent[tcp->scno].sys_func != sys_exit))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002689 sys_res = printargs(tcp);
2690 else
2691 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2692 if (fflush(tcp->outf) == EOF)
2693 return -1;
2694 tcp->flags |= TCB_INSYSCALL;
2695 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002696 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002697 gettimeofday(&tcp->etime, NULL);
2698 return sys_res;
2699}
2700
2701int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002702trace_syscall(struct tcb *tcp)
2703{
2704 return exiting(tcp) ?
2705 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2706}
2707
2708int
Denys Vlasenko12014262011-05-30 14:00:14 +02002709printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710{
2711 if (entering(tcp)) {
2712 int i;
2713
2714 for (i = 0; i < tcp->u_nargs; i++)
2715 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2716 }
2717 return 0;
2718}
2719
2720long
Denys Vlasenko12014262011-05-30 14:00:14 +02002721getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002722{
2723 long val = -1;
2724
2725#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002726#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002727 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002728 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002729 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002730 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002731#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002732 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002733 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002734#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002735 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002736 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002737#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002738#endif /* LINUX */
2739
2740#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002741 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002742 return -1;
2743#endif /* SUNOS4 */
2744
2745#ifdef SVR4
2746#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002747 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002748#endif /* SPARC */
2749#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002750 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002751#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002752#ifdef X86_64
2753 val = tcp->status.PR_REG[RDX];
2754#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002755#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002756 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002757#endif /* MIPS */
2758#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002759
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002760#ifdef FREEBSD
2761 struct reg regs;
2762 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2763 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002764#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002765 return val;
2766}
2767
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002768#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002769/*
2770 * Apparently, indirect system calls have already be converted by ptrace(2),
2771 * so if you see "indir" this program has gone astray.
2772 */
2773int
Denys Vlasenko12014262011-05-30 14:00:14 +02002774sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002775{
2776 int i, scno, nargs;
2777
2778 if (entering(tcp)) {
Denys Vlasenko5d645812011-08-20 12:48:18 +02002779 scno = tcp->u_arg[0];
2780 if (scno > nsyscalls) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002781 fprintf(stderr, "Bogus syscall: %u\n", scno);
2782 return 0;
2783 }
2784 nargs = sysent[scno].nargs;
2785 tprintf("%s", sysent[scno].sys_name);
2786 for (i = 0; i < nargs; i++)
2787 tprintf(", %#lx", tcp->u_arg[i+1]);
2788 }
2789 return 0;
2790}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002791#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002792
2793int
2794is_restart_error(struct tcb *tcp)
2795{
2796#ifdef LINUX
2797 if (!syserror(tcp))
2798 return 0;
2799 switch (tcp->u_error) {
2800 case ERESTARTSYS:
2801 case ERESTARTNOINTR:
2802 case ERESTARTNOHAND:
2803 case ERESTART_RESTARTBLOCK:
2804 return 1;
2805 default:
2806 break;
2807 }
2808#endif /* LINUX */
2809 return 0;
2810}