blob: 76ef39c19e0d99b48693750179987513297fa66f [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 */
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200660 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
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200680#if defined SUNOS4 || (defined LINUX && defined TCB_WAITEXECVE)
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000681 if ( sys_execve == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200682# if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683 || sys_execv == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200684# endif
685# if UNIXWARE > 2
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000686 || sys_rexecve == func
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200687# endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000688 )
689 return internal_exec(tcp);
Denys Vlasenkoa7949742011-08-21 17:26:55 +0200690#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000691
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000692 return 0;
693}
694
Wichert Akkermanc7926982000-04-10 22:22:31 +0000695
696#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200697# if defined (I386)
698static long eax;
699# elif defined (IA64)
700long r8, r10, psr; /* TODO: make static? */
701long ia32 = 0; /* not static */
702# elif defined (POWERPC)
703static long result, flags;
704# elif defined (M68K)
705static long d0;
706# elif defined(BFIN)
707static long r0;
708# elif defined (ARM)
709static struct pt_regs regs;
710# elif defined (ALPHA)
711static long r0;
712static long a3;
713# elif defined(AVR32)
714static struct pt_regs regs;
715# elif defined (SPARC) || defined (SPARC64)
716static struct pt_regs regs;
717static unsigned long trap;
718# elif defined(LINUX_MIPSN32)
719static long long a3;
720static long long r2;
721# elif defined(MIPS)
722static long a3;
723static long r2;
724# elif defined(S390) || defined(S390X)
725static long gpr2;
726static long pc;
727static long syscall_mode;
728# elif defined(HPPA)
729static long r28;
730# elif defined(SH)
731static long r0;
732# elif defined(SH64)
733static long r9;
734# elif defined(X86_64)
735static long rax;
736# elif defined(CRISV10) || defined(CRISV32)
737static long r10;
738# elif defined(MICROBLAZE)
739static long r3;
740# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000741#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000742#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200743struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000744#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000745
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000747get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000748{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000749 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000750
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000751#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000752# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000753 if (tcp->flags & TCB_WAITEXECVE) {
754 /*
755 * When the execve system call completes successfully, the
756 * new process still has -ENOSYS (old style) or __NR_execve
757 * (new style) in gpr2. We cannot recover the scno again
758 * by disassembly, because the image that executed the
759 * syscall is gone now. Fortunately, we don't want it. We
760 * leave the flag set so that syscall_fixup can fake the
761 * result.
762 */
763 if (tcp->flags & TCB_INSYSCALL)
764 return 1;
765 /*
766 * This is the SIGTRAP after execve. We cannot try to read
767 * the system call here either.
768 */
769 tcp->flags &= ~TCB_WAITEXECVE;
770 return 0;
771 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000772
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000773 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200774 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000775
776 if (syscall_mode != -ENOSYS) {
777 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000778 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000779 */
780 scno = syscall_mode;
781 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000782 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000783 * Old style of "passing" the scno via the SVC instruction.
784 */
785
786 long opcode, offset_reg, tmp;
787 void * svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200788 static const int gpr_offset[16] = {
789 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
790 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
791 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
792 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
793 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000794
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000795 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000796 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000797 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000798 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000799 if (errno) {
800 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000801 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000802 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000803
804 /*
805 * We have to check if the SVC got executed directly or via an
806 * EXECUTE instruction. In case of EXECUTE it is necessary to do
807 * instruction decoding to derive the system call number.
808 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
809 * so that this doesn't work if a SVC opcode is part of an EXECUTE
810 * opcode. Since there is no way to find out the opcode size this
811 * is the best we can do...
812 */
813
814 if ((opcode & 0xff00) == 0x0a00) {
815 /* SVC opcode */
816 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000817 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000818 else {
819 /* SVC got executed by EXECUTE instruction */
820
821 /*
822 * Do instruction decoding of EXECUTE. If you really want to
823 * understand this, read the Principles of Operations.
824 */
825 svc_addr = (void *) (opcode & 0xfff);
826
827 tmp = 0;
828 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000829 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000830 return -1;
831 svc_addr += tmp;
832
833 tmp = 0;
834 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000835 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000836 return -1;
837 svc_addr += tmp;
838
Denys Vlasenkofb036672009-01-23 16:30:26 +0000839 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000840 if (errno)
841 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000842# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000843 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000844# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000845 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000846# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000847 tmp = 0;
848 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000849 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000850 return -1;
851
852 scno = (scno | tmp) & 0xff;
853 }
854 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000855# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000856 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000857 return -1;
858 if (!(tcp->flags & TCB_INSYSCALL)) {
859 /* Check if we return from execve. */
860 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
861 tcp->flags &= ~TCB_WAITEXECVE;
862 return 0;
863 }
864 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200865
866# ifdef POWERPC64
867 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200868 /* TODO: speed up strace by not doing this at every syscall.
869 * We only need to do it after execve.
870 */
871 int currpers;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200872 long val;
873 int pid = tcp->pid;
874
875 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200876 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200877 return -1;
878 /* SF is bit 0 of MSR */
879 if (val < 0)
880 currpers = 0;
881 else
882 currpers = 1;
883 if (currpers != current_personality) {
884 static const char *const names[] = {"64 bit", "32 bit"};
885 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000886 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200887 pid, names[current_personality]);
888 }
889 }
890# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000891# elif defined(AVR32)
892 /*
893 * Read complete register set in one go.
894 */
895 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
896 return -1;
897
898 /*
899 * We only need to grab the syscall number on syscall entry.
900 */
901 if (!(tcp->flags & TCB_INSYSCALL)) {
902 scno = regs.r8;
903
904 /* Check if we return from execve. */
905 if (tcp->flags & TCB_WAITEXECVE) {
906 tcp->flags &= ~TCB_WAITEXECVE;
907 return 0;
908 }
909 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000910# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000911 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000912 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000913# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000914 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000915 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000916# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000917 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000918 return -1;
919
Roland McGrath761b5d72002-12-15 23:58:31 +0000920 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200921 /* TODO: speed up strace by not doing this at every syscall.
922 * We only need to do it after execve.
923 */
924 int currpers;
Michal Ludvig0e035502002-09-23 15:41:01 +0000925 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000926 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000927
928 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200929 * 0x33 for long mode (64 bit)
930 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000931 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000932 * to be cached.
933 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000934 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000935 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000936 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000937 case 0x23: currpers = 1; break;
938 case 0x33: currpers = 0; break;
939 default:
940 fprintf(stderr, "Unknown value CS=0x%02X while "
941 "detecting personality of process "
942 "PID=%d\n", (int)val, pid);
943 currpers = current_personality;
944 break;
945 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000946# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000947 /* This version analyzes the opcode of a syscall instruction.
948 * (int 0x80 on i386 vs. syscall on x86-64)
949 * It works, but is too complicated.
950 */
951 unsigned long val, rip, i;
952
Denys Vlasenko8236f252009-01-02 18:10:08 +0000953 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000954 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000955
Michal Ludvig0e035502002-09-23 15:41:01 +0000956 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000957 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000958 errno = 0;
959
Denys Vlasenko8236f252009-01-02 18:10:08 +0000960 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000961 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000962 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000963 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000964 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000965 /* x86-64: syscall = 0x0f 0x05 */
966 case 0x050f: currpers = 0; break;
967 /* i386: int 0x80 = 0xcd 0x80 */
968 case 0x80cd: currpers = 1; break;
969 default:
970 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000971 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000972 "Unknown syscall opcode (0x%04X) while "
973 "detecting personality of process "
974 "PID=%d\n", (int)call, pid);
975 break;
976 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000977# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000978 if (currpers != current_personality) {
979 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000980 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000981 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000982 pid, names[current_personality]);
983 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000984 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000985# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000986# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200987 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000988 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000989 if (!(tcp->flags & TCB_INSYSCALL)) {
990 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000991 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000992 return -1;
993 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200994 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000995 return -1;
996 }
Roland McGrathba954762003-03-05 06:29:06 +0000997 /* Check if we return from execve. */
998 if (tcp->flags & TCB_WAITEXECVE) {
999 tcp->flags &= ~TCB_WAITEXECVE;
1000 return 0;
1001 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001002 } else {
1003 /* syscall in progress */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001004 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001005 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001006 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001007 return -1;
1008 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001009# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001010 /*
1011 * Read complete register set in one go.
1012 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001013 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001014 return -1;
1015
1016 /*
1017 * We only need to grab the syscall number on syscall entry.
1018 */
1019 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001020 if (!(tcp->flags & TCB_INSYSCALL)) {
1021 /* Check if we return from execve. */
1022 if (tcp->flags & TCB_WAITEXECVE) {
1023 tcp->flags &= ~TCB_WAITEXECVE;
1024 return 0;
1025 }
1026 }
1027
Roland McGrath0f87c492003-06-03 23:29:04 +00001028 /*
1029 * Note: we only deal with only 32-bit CPUs here.
1030 */
1031 if (regs.ARM_cpsr & 0x20) {
1032 /*
1033 * Get the Thumb-mode system call number
1034 */
1035 scno = regs.ARM_r7;
1036 } else {
1037 /*
1038 * Get the ARM-mode system call number
1039 */
1040 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001041 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001042 if (errno)
1043 return -1;
1044
1045 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1046 tcp->flags &= ~TCB_WAITEXECVE;
1047 return 0;
1048 }
1049
Roland McGrathf691bd22006-04-25 07:34:41 +00001050 /* Handle the EABI syscall convention. We do not
1051 bother converting structures between the two
1052 ABIs, but basic functionality should work even
1053 if strace and the traced program have different
1054 ABIs. */
1055 if (scno == 0xef000000) {
1056 scno = regs.ARM_r7;
1057 } else {
1058 if ((scno & 0x0ff00000) != 0x0f900000) {
1059 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1060 scno);
1061 return -1;
1062 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001063
Roland McGrathf691bd22006-04-25 07:34:41 +00001064 /*
1065 * Fixup the syscall number
1066 */
1067 scno &= 0x000fffff;
1068 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001069 }
Roland McGrath56703312008-05-20 01:35:55 +00001070 if (scno & 0x0f0000) {
1071 /*
1072 * Handle ARM specific syscall
1073 */
1074 set_personality(1);
1075 scno &= 0x0000ffff;
1076 } else
1077 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001078
1079 if (tcp->flags & TCB_INSYSCALL) {
1080 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1081 tcp->flags &= ~TCB_INSYSCALL;
1082 }
1083 } else {
1084 if (!(tcp->flags & TCB_INSYSCALL)) {
1085 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1086 tcp->flags |= TCB_INSYSCALL;
1087 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001088 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001089# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001090 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001092# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001093 unsigned long long regs[38];
1094
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001095 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001096 return -1;
1097 a3 = regs[REG_A3];
1098 r2 = regs[REG_V0];
1099
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001100 if (!(tcp->flags & TCB_INSYSCALL)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001101 scno = r2;
1102
1103 /* Check if we return from execve. */
1104 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1105 tcp->flags &= ~TCB_WAITEXECVE;
1106 return 0;
1107 }
1108
1109 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001110 if (a3 == 0 || a3 == -1) {
1111 if (debug)
1112 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001113 return 0;
1114 }
1115 }
1116 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001117# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001118 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001119 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001120 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001121 if (upeek(tcp, REG_V0, &scno) < 0)
1122 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001123
Roland McGrath542c2c62008-05-20 01:11:56 +00001124 /* Check if we return from execve. */
1125 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1126 tcp->flags &= ~TCB_WAITEXECVE;
1127 return 0;
1128 }
1129
Wichert Akkermanf90da011999-10-31 21:15:38 +00001130 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001131 if (a3 == 0 || a3 == -1) {
1132 if (debug)
1133 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001134 return 0;
1135 }
1136 }
1137 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001138 if (upeek(tcp, REG_V0, &r2) < 0)
1139 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001140 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001141# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001142 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143 return -1;
1144
1145 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001146 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147 return -1;
1148
1149 /* Check if we return from execve. */
1150 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1151 tcp->flags &= ~TCB_WAITEXECVE;
1152 return 0;
1153 }
1154
1155 /*
1156 * Do some sanity checks to figure out if it's
1157 * really a syscall entry
1158 */
1159 if (scno < 0 || scno > nsyscalls) {
1160 if (a3 == 0 || a3 == -1) {
1161 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001162 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001163 return 0;
1164 }
1165 }
1166 }
1167 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001168 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169 return -1;
1170 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001171# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001173 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174 return -1;
1175
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001176 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 if (!(tcp->flags & TCB_INSYSCALL)) {
1178 /* Retrieve the syscall trap instruction. */
1179 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001180# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001181 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001182 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001183# else
1184 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001185# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186 if (errno)
1187 return -1;
1188
1189 /* Disassemble the trap to see what personality to use. */
1190 switch (trap) {
1191 case 0x91d02010:
1192 /* Linux/SPARC syscall trap. */
1193 set_personality(0);
1194 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001195 case 0x91d0206d:
1196 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001197 set_personality(2);
1198 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001199 case 0x91d02000:
1200 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001201 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001202 return -1;
1203 case 0x91d02008:
1204 /* Solaris 2.x syscall trap. (per 2) */
1205 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001206 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001207 case 0x91d02009:
1208 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001209 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210 return -1;
1211 case 0x91d02027:
1212 /* Solaris 2.x gettimeofday */
1213 set_personality(1);
1214 break;
1215 default:
1216 /* Unknown syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001217 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001218 tcp->flags &= ~TCB_WAITEXECVE;
1219 return 0;
1220 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001221# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001222 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001223# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001224 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001225# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001226 return -1;
1227 }
1228
1229 /* Extract the system call number from the registers. */
1230 if (trap == 0x91d02027)
1231 scno = 156;
1232 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001233 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001234 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001235 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001236 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 +00001237 }
1238 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001239# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001240 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001241 return -1;
1242 if (!(tcp->flags & TCB_INSYSCALL)) {
1243 /* Check if we return from execve. */
1244 if ((tcp->flags & TCB_WAITEXECVE)) {
1245 tcp->flags &= ~TCB_WAITEXECVE;
1246 return 0;
1247 }
1248 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001249# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001250 /*
1251 * In the new syscall ABI, the system call number is in R3.
1252 */
1253 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1254 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001255
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001256 if (scno < 0) {
1257 /* Odd as it may seem, a glibc bug has been known to cause
1258 glibc to issue bogus negative syscall numbers. So for
1259 our purposes, make strace print what it *should* have been */
1260 long correct_scno = (scno & 0xff);
1261 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001262 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001263 "Detected glibc bug: bogus system call"
1264 " number = %ld, correcting to %ld\n",
1265 scno,
1266 correct_scno);
1267 scno = correct_scno;
1268 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001269
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001270 if (!(tcp->flags & TCB_INSYSCALL)) {
1271 /* Check if we return from execve. */
1272 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1273 tcp->flags &= ~TCB_WAITEXECVE;
1274 return 0;
1275 }
1276 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001277# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001278 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001279 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001280 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001281
1282 if (!(tcp->flags & TCB_INSYSCALL)) {
1283 /* Check if we return from execve. */
1284 if (tcp->flags & TCB_WAITEXECVE) {
1285 tcp->flags &= ~TCB_WAITEXECVE;
1286 return 0;
1287 }
1288 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001289# elif defined(CRISV10) || defined(CRISV32)
1290 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1291 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001292# elif defined(TILE)
1293 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1294 return -1;
1295
1296 if (!(tcp->flags & TCB_INSYSCALL)) {
1297 /* Check if we return from execve. */
1298 if (tcp->flags & TCB_WAITEXECVE) {
1299 tcp->flags &= ~TCB_WAITEXECVE;
1300 return 0;
1301 }
1302 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001303# elif defined(MICROBLAZE)
1304 if (upeek(tcp, 0, &scno) < 0)
1305 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001306# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001308
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001309#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001310 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001311 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001312#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001313 /* new syscall ABI returns result in R0 */
1314 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1315 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001316#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001317 /* ABI defines result returned in r9 */
1318 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1319 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001320#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001321
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001322#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001323# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001324 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001325# else
1326# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001327 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001328# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001329 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001330 perror("pread");
1331 return -1;
1332 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001333 switch (regs.r_eax) {
1334 case SYS_syscall:
1335 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001336 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1337 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001338 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001339 scno = regs.r_eax;
1340 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001341 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001342# endif /* FREEBSD */
1343# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001344#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001345
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001346 if (!(tcp->flags & TCB_INSYSCALL))
1347 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001348 return 1;
1349}
1350
Pavel Machek4dc3b142000-02-01 17:58:41 +00001351
Roland McGrath17352792005-06-07 23:21:26 +00001352long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001353known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001354{
1355 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001356#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001357 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1358 scno = sysent[scno].native_scno;
1359 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001360#endif
Roland McGrath17352792005-06-07 23:21:26 +00001361 scno += NR_SYSCALL_BASE;
1362 return scno;
1363}
1364
Roland McGratheb9e2e82009-06-02 16:49:22 -07001365/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001366 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001367 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1368 * 1: ok, continue in trace_syscall().
1369 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001370 * ("????" etc) and bail out.
1371 */
Roland McGratha4d48532005-06-08 20:45:28 +00001372static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001373syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001374{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001375#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001376 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001377
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001379 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001380 if (
1381 scno == SYS_fork
1382#ifdef SYS_vfork
1383 || scno == SYS_vfork
1384#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001385#ifdef SYS_fork1
1386 || scno == SYS_fork1
1387#endif /* SYS_fork1 */
1388#ifdef SYS_forkall
1389 || scno == SYS_forkall
1390#endif /* SYS_forkall */
1391#ifdef SYS_rfork1
1392 || scno == SYS_rfork1
1393#endif /* SYS_fork1 */
1394#ifdef SYS_rforkall
1395 || scno == SYS_rforkall
1396#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001397 ) {
1398 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001399 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001400 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001401 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001402 }
1403 else {
1404 fprintf(stderr, "syscall: missing entry\n");
1405 tcp->flags |= TCB_INSYSCALL;
1406 }
1407 }
1408 }
1409 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001410 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001411 fprintf(stderr, "syscall: missing exit\n");
1412 tcp->flags &= ~TCB_INSYSCALL;
1413 }
1414 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001415#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001416#ifdef SUNOS4
1417 if (!(tcp->flags & TCB_INSYSCALL)) {
1418 if (scno == 0) {
1419 fprintf(stderr, "syscall: missing entry\n");
1420 tcp->flags |= TCB_INSYSCALL;
1421 }
1422 }
1423 else {
1424 if (scno != 0) {
1425 if (debug) {
1426 /*
1427 * This happens when a signal handler
1428 * for a signal which interrupted a
1429 * a system call makes another system call.
1430 */
1431 fprintf(stderr, "syscall: missing exit\n");
1432 }
1433 tcp->flags &= ~TCB_INSYSCALL;
1434 }
1435 }
1436#endif /* SUNOS4 */
1437#ifdef LINUX
1438#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001439 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001440 return -1;
1441 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1442 if (debug)
1443 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1444 return 0;
1445 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001446#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001447 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001448 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001449 if (current_personality == 1)
1450 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001451 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1452 if (debug)
1453 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1454 return 0;
1455 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001456#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001457 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001458 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001459 if (syscall_mode != -ENOSYS)
1460 syscall_mode = tcp->scno;
1461 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001462 if (debug)
1463 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1464 return 0;
1465 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001466 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1467 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1468 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1469 /*
1470 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1471 * flag set for the post-execve SIGTRAP to see and reset.
1472 */
1473 gpr2 = 0;
1474 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001475#elif defined (POWERPC)
1476# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001477 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001478 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001479 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001480 return -1;
1481 if (flags & SO_MASK)
1482 result = -result;
1483#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001484 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001485 return -1;
1486 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1487 if (debug)
1488 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1489 return 0;
1490 }
1491#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001492 /*
1493 * Nothing required
1494 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001495#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001496 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001497 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001498#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001499 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001500 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001501#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001502 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001503 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001504 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001505 return -1;
1506 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1507 if (debug)
1508 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1509 return 0;
1510 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001511#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001512 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001513 return -1;
1514 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1515 if (debug)
1516 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1517 return 0;
1518 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001519#elif defined(MICROBLAZE)
1520 if (upeek(tcp, 3 * 4, &r3) < 0)
1521 return -1;
1522 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1523 if (debug)
1524 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1525 return 0;
1526 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001527#endif
1528#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001529 return 1;
1530}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001531
Roland McGrathc1e45922008-05-27 23:18:29 +00001532#ifdef LINUX
1533/*
1534 * Check the syscall return value register value for whether it is
1535 * a negated errno code indicating an error, or a success return value.
1536 */
1537static inline int
1538is_negated_errno(unsigned long int val)
1539{
1540 unsigned long int max = -(long int) nerrnos;
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001541# if SUPPORTED_PERSONALITIES > 1
Roland McGrathc1e45922008-05-27 23:18:29 +00001542 if (personality_wordsize[current_personality] < sizeof(val)) {
1543 val = (unsigned int) val;
1544 max = (unsigned int) max;
1545 }
Denys Vlasenkoa7949742011-08-21 17:26:55 +02001546# endif
Roland McGrathc1e45922008-05-27 23:18:29 +00001547 return val > max;
1548}
1549#endif
1550
Roland McGratha4d48532005-06-08 20:45:28 +00001551static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001552get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001553{
1554 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001555#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001556 int check_errno = 1;
1557 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1558 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1559 check_errno = 0;
1560 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001561# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001562 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001563 tcp->u_rval = -1;
1564 u_error = -gpr2;
1565 }
1566 else {
1567 tcp->u_rval = gpr2;
1568 u_error = 0;
1569 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001570# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001571 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001572 tcp->u_rval = -1;
1573 u_error = -eax;
1574 }
1575 else {
1576 tcp->u_rval = eax;
1577 u_error = 0;
1578 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001579# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001580 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001581 tcp->u_rval = -1;
1582 u_error = -rax;
1583 }
1584 else {
1585 tcp->u_rval = rax;
1586 u_error = 0;
1587 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001588# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001589 if (ia32) {
1590 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001591
Roland McGrathc1e45922008-05-27 23:18:29 +00001592 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001593 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001594 tcp->u_rval = -1;
1595 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001596 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001597 else {
1598 tcp->u_rval = err;
1599 u_error = 0;
1600 }
1601 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001602 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001603 tcp->u_rval = -1;
1604 u_error = r8;
1605 } else {
1606 tcp->u_rval = r8;
1607 u_error = 0;
1608 }
1609 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001610# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001611 if (check_errno && a3) {
1612 tcp->u_rval = -1;
1613 u_error = r2;
1614 } else {
1615 tcp->u_rval = r2;
1616 u_error = 0;
1617 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001618# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001619 if (check_errno && is_negated_errno(result)) {
1620 tcp->u_rval = -1;
1621 u_error = -result;
1622 }
1623 else {
1624 tcp->u_rval = result;
1625 u_error = 0;
1626 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001627# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001628 if (check_errno && is_negated_errno(d0)) {
1629 tcp->u_rval = -1;
1630 u_error = -d0;
1631 }
1632 else {
1633 tcp->u_rval = d0;
1634 u_error = 0;
1635 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001636# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001637 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1638 tcp->u_rval = -1;
1639 u_error = -regs.ARM_r0;
1640 }
1641 else {
1642 tcp->u_rval = regs.ARM_r0;
1643 u_error = 0;
1644 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001645# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001646 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1647 tcp->u_rval = -1;
1648 u_error = -regs.r12;
1649 }
1650 else {
1651 tcp->u_rval = regs.r12;
1652 u_error = 0;
1653 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001654# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001655 if (check_errno && is_negated_errno(r0)) {
1656 tcp->u_rval = -1;
1657 u_error = -r0;
1658 } else {
1659 tcp->u_rval = r0;
1660 u_error = 0;
1661 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001662# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001663 if (check_errno && a3) {
1664 tcp->u_rval = -1;
1665 u_error = r0;
1666 }
1667 else {
1668 tcp->u_rval = r0;
1669 u_error = 0;
1670 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001671# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001672 if (check_errno && regs.psr & PSR_C) {
1673 tcp->u_rval = -1;
1674 u_error = regs.u_regs[U_REG_O0];
1675 }
1676 else {
1677 tcp->u_rval = regs.u_regs[U_REG_O0];
1678 u_error = 0;
1679 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001680# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001681 if (check_errno && regs.tstate & 0x1100000000UL) {
1682 tcp->u_rval = -1;
1683 u_error = regs.u_regs[U_REG_O0];
1684 }
1685 else {
1686 tcp->u_rval = regs.u_regs[U_REG_O0];
1687 u_error = 0;
1688 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001689# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001690 if (check_errno && is_negated_errno(r28)) {
1691 tcp->u_rval = -1;
1692 u_error = -r28;
1693 }
1694 else {
1695 tcp->u_rval = r28;
1696 u_error = 0;
1697 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001698# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001699 /* interpret R0 as return value or error number */
1700 if (check_errno && is_negated_errno(r0)) {
1701 tcp->u_rval = -1;
1702 u_error = -r0;
1703 }
1704 else {
1705 tcp->u_rval = r0;
1706 u_error = 0;
1707 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001708# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001709 /* interpret result as return value or error number */
1710 if (check_errno && is_negated_errno(r9)) {
1711 tcp->u_rval = -1;
1712 u_error = -r9;
1713 }
1714 else {
1715 tcp->u_rval = r9;
1716 u_error = 0;
1717 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001718# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001719 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1720 tcp->u_rval = -1;
1721 u_error = -r10;
1722 }
1723 else {
1724 tcp->u_rval = r10;
1725 u_error = 0;
1726 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001727# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001728 long rval;
1729 /* interpret result as return value or error number */
1730 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1731 return -1;
1732 if (check_errno && rval < 0 && rval > -nerrnos) {
1733 tcp->u_rval = -1;
1734 u_error = -rval;
1735 }
1736 else {
1737 tcp->u_rval = rval;
1738 u_error = 0;
1739 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001740# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001741 /* interpret result as return value or error number */
1742 if (check_errno && is_negated_errno(r3)) {
1743 tcp->u_rval = -1;
1744 u_error = -r3;
1745 }
1746 else {
1747 tcp->u_rval = r3;
1748 u_error = 0;
1749 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001750# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001751#endif /* LINUX */
1752#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001753 /* get error code from user struct */
1754 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1755 return -1;
1756 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001757
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001758 /* get system call return value */
1759 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1760 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001761#endif /* SUNOS4 */
1762#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001763# ifdef SPARC
1764 /* Judicious guessing goes a long way. */
1765 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1766 tcp->u_rval = -1;
1767 u_error = tcp->status.pr_reg[R_O0];
1768 }
1769 else {
1770 tcp->u_rval = tcp->status.pr_reg[R_O0];
1771 u_error = 0;
1772 }
1773# endif /* SPARC */
1774# ifdef I386
1775 /* Wanna know how to kill an hour single-stepping? */
1776 if (tcp->status.PR_REG[EFL] & 0x1) {
1777 tcp->u_rval = -1;
1778 u_error = tcp->status.PR_REG[EAX];
1779 }
1780 else {
1781 tcp->u_rval = tcp->status.PR_REG[EAX];
1782# ifdef HAVE_LONG_LONG
1783 tcp->u_lrval =
1784 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1785 tcp->status.PR_REG[EAX];
1786# endif
1787 u_error = 0;
1788 }
1789# endif /* I386 */
1790# ifdef X86_64
1791 /* Wanna know how to kill an hour single-stepping? */
1792 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1793 tcp->u_rval = -1;
1794 u_error = tcp->status.PR_REG[RAX];
1795 }
1796 else {
1797 tcp->u_rval = tcp->status.PR_REG[RAX];
1798 u_error = 0;
1799 }
1800# endif /* X86_64 */
1801# ifdef MIPS
1802 if (tcp->status.pr_reg[CTX_A3]) {
1803 tcp->u_rval = -1;
1804 u_error = tcp->status.pr_reg[CTX_V0];
1805 }
1806 else {
1807 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1808 u_error = 0;
1809 }
1810# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001811#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001812#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001813 if (regs.r_eflags & PSL_C) {
1814 tcp->u_rval = -1;
1815 u_error = regs.r_eax;
1816 } else {
1817 tcp->u_rval = regs.r_eax;
1818 tcp->u_lrval =
1819 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1820 u_error = 0;
1821 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001822#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001823 tcp->u_error = u_error;
1824 return 1;
1825}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001826
Roland McGrathb69f81b2002-12-21 23:25:18 +00001827int
Denys Vlasenko12014262011-05-30 14:00:14 +02001828force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001829{
1830#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001831# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001832 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001833 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1834 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001835# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001836 eax = error ? -error : rval;
1837 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1838 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001839# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001840 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001841 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001842 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001843# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001844 if (ia32) {
1845 r8 = error ? -error : rval;
1846 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1847 return -1;
1848 }
1849 else {
1850 if (error) {
1851 r8 = error;
1852 r10 = -1;
1853 }
1854 else {
1855 r8 = rval;
1856 r10 = 0;
1857 }
1858 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1859 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1860 return -1;
1861 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001862# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001863 r0 = error ? -error : rval;
1864 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1865 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001866# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001867 if (error) {
1868 r2 = error;
1869 a3 = -1;
1870 }
1871 else {
1872 r2 = rval;
1873 a3 = 0;
1874 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001875 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001876 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1877 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001878 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001879# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001880 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001881 return -1;
1882 if (error) {
1883 flags |= SO_MASK;
1884 result = error;
1885 }
1886 else {
1887 flags &= ~SO_MASK;
1888 result = rval;
1889 }
Roland McGratheb285352003-01-14 09:59:00 +00001890 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1891 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001892 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001893# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001894 d0 = error ? -error : rval;
1895 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1896 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001897# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001898 regs.ARM_r0 = error ? -error : rval;
1899 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001900 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001901# elif defined(AVR32)
1902 regs.r12 = error ? -error : rval;
1903 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1904 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001905# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001906 if (error) {
1907 a3 = -1;
1908 r0 = error;
1909 }
1910 else {
1911 a3 = 0;
1912 r0 = rval;
1913 }
1914 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1915 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1916 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001917# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001918 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1919 return -1;
1920 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001921 regs.psr |= PSR_C;
1922 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001923 }
1924 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001925 regs.psr &= ~PSR_C;
1926 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001927 }
1928 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1929 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001930# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001931 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1932 return -1;
1933 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001934 regs.tstate |= 0x1100000000UL;
1935 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001936 }
1937 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001938 regs.tstate &= ~0x1100000000UL;
1939 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001940 }
1941 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1942 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001943# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001944 r28 = error ? -error : rval;
1945 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1946 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001947# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001948 r0 = error ? -error : rval;
1949 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1950 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001951# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001952 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001953 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1954 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001955# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001956#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001957
Roland McGrathb69f81b2002-12-21 23:25:18 +00001958#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001959 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1960 error << 24) < 0 ||
1961 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001962 return -1;
1963#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001964
Roland McGrathb69f81b2002-12-21 23:25:18 +00001965#ifdef SVR4
1966 /* XXX no clue */
1967 return -1;
1968#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001969
Roland McGrathb69f81b2002-12-21 23:25:18 +00001970#ifdef FREEBSD
1971 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001972 perror("pread");
1973 return -1;
1974 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001975 if (error) {
1976 regs.r_eflags |= PSL_C;
1977 regs.r_eax = error;
1978 }
1979 else {
1980 regs.r_eflags &= ~PSL_C;
1981 regs.r_eax = rval;
1982 }
1983 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001984 perror("pwrite");
1985 return -1;
1986 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001987#endif /* FREEBSD */
1988
1989 /* All branches reach here on success (only). */
1990 tcp->u_error = error;
1991 tcp->u_rval = rval;
1992 return 0;
1993}
1994
Roland McGratha4d48532005-06-08 20:45:28 +00001995static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001996syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001997{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001998#ifdef LINUX
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001999# if defined(S390) || defined(S390X)
2000 int i;
2001 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2002 tcp->u_nargs = sysent[tcp->scno].nargs;
2003 else
2004 tcp->u_nargs = MAX_ARGS;
2005 for (i = 0; i < tcp->u_nargs; i++) {
2006 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
2007 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002008 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002009# elif defined(ALPHA)
2010 int i;
2011 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2012 tcp->u_nargs = sysent[tcp->scno].nargs;
2013 else
2014 tcp->u_nargs = MAX_ARGS;
2015 for (i = 0; i < tcp->u_nargs; i++) {
2016 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2017 * for scno somewhere above here!
2018 */
2019 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
2020 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002021 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002022# elif defined(IA64)
2023 if (!ia32) {
2024 unsigned long *out0, cfm, sof, sol, i;
2025 long rbs_end;
2026 /* be backwards compatible with kernel < 2.4.4... */
2027# ifndef PT_RBS_END
2028# define PT_RBS_END PT_AR_BSP
2029# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002030
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002031 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
2032 return -1;
2033 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002034 return -1;
2035
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002036 sof = (cfm >> 0) & 0x7f;
2037 sol = (cfm >> 7) & 0x7f;
2038 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
2039
2040 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2041 && sysent[tcp->scno].nargs != -1)
2042 tcp->u_nargs = sysent[tcp->scno].nargs;
2043 else
2044 tcp->u_nargs = MAX_ARGS;
2045 for (i = 0; i < tcp->u_nargs; ++i) {
2046 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2047 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2048 return -1;
2049 }
2050 } else {
2051 int i;
2052
2053 if (/* EBX = out0 */
2054 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
2055 /* ECX = out1 */
2056 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
2057 /* EDX = out2 */
2058 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
2059 /* ESI = out3 */
2060 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
2061 /* EDI = out4 */
2062 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
2063 /* EBP = out5 */
2064 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2065 return -1;
2066
2067 for (i = 0; i < 6; ++i)
2068 /* truncate away IVE sign-extension */
2069 tcp->u_arg[i] &= 0xffffffff;
2070
2071 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2072 && sysent[tcp->scno].nargs != -1)
2073 tcp->u_nargs = sysent[tcp->scno].nargs;
2074 else
2075 tcp->u_nargs = 5;
2076 }
2077# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2078 /* N32 and N64 both use up to six registers. */
2079 unsigned long long regs[38];
2080 int i, nargs;
2081 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2082 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2083 else
2084 nargs = tcp->u_nargs = MAX_ARGS;
2085
2086 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2087 return -1;
2088
2089 for (i = 0; i < nargs; i++) {
2090 tcp->u_arg[i] = regs[REG_A0 + i];
2091# if defined(LINUX_MIPSN32)
2092 tcp->ext_arg[i] = regs[REG_A0 + i];
2093# endif
2094 }
2095# elif defined(MIPS)
2096 long sp;
2097 int i, nargs;
2098
2099 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2100 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2101 else
2102 nargs = tcp->u_nargs = MAX_ARGS;
2103 if (nargs > 4) {
2104 if (upeek(tcp, REG_SP, &sp) < 0)
2105 return -1;
2106 for (i = 0; i < 4; i++) {
2107 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2108 return -1;
2109 }
2110 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2111 (char *)(tcp->u_arg + 4));
2112 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002113 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002114 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002115 return -1;
2116 }
2117 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002118# elif defined(POWERPC)
2119# ifndef PT_ORIG_R3
2120# define PT_ORIG_R3 34
2121# endif
2122 int i;
2123 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2124 tcp->u_nargs = sysent[tcp->scno].nargs;
2125 else
2126 tcp->u_nargs = MAX_ARGS;
2127 for (i = 0; i < tcp->u_nargs; i++) {
2128 if (upeek(tcp, (i==0) ?
2129 (sizeof(unsigned long) * PT_ORIG_R3) :
2130 ((i+PT_R3) * sizeof(unsigned long)),
2131 &tcp->u_arg[i]) < 0)
2132 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002133 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002134# elif defined(SPARC) || defined(SPARC64)
2135 int i;
2136 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2137 tcp->u_nargs = sysent[tcp->scno].nargs;
2138 else
2139 tcp->u_nargs = MAX_ARGS;
2140 for (i = 0; i < tcp->u_nargs; i++)
2141 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2142# elif defined(HPPA)
2143 int i;
2144 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2145 tcp->u_nargs = sysent[tcp->scno].nargs;
2146 else
2147 tcp->u_nargs = MAX_ARGS;
2148 for (i = 0; i < tcp->u_nargs; i++) {
2149 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2150 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002151 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002152# elif defined(ARM)
2153 int i;
2154 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2155 tcp->u_nargs = sysent[tcp->scno].nargs;
2156 else
2157 tcp->u_nargs = MAX_ARGS;
2158 for (i = 0; i < tcp->u_nargs; i++)
2159 tcp->u_arg[i] = regs.uregs[i];
2160# elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002161 tcp->u_nargs = sysent[tcp->scno].nargs;
2162 tcp->u_arg[0] = regs.r12;
2163 tcp->u_arg[1] = regs.r11;
2164 tcp->u_arg[2] = regs.r10;
2165 tcp->u_arg[3] = regs.r9;
2166 tcp->u_arg[4] = regs.r5;
2167 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002168# elif defined(BFIN)
2169 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002170 static const int argreg[] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002171
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002172 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002173 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002174 else
2175 tcp->u_nargs = ARRAY_SIZE(argreg);
2176
2177 for (i = 0; i < tcp->u_nargs; ++i)
2178 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2179 return -1;
2180# elif defined(SH)
2181 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002182 static const int syscall_regs[] = {
2183 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6), 4 * (REG_REG0+7),
2184 4 * (REG_REG0 ), 4 * (REG_REG0+1), 4 * (REG_REG0+2)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002185 };
2186
2187 tcp->u_nargs = sysent[tcp->scno].nargs;
2188 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002189 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002190 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002191 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002192# elif defined(SH64)
2193 int i;
2194 /* Registers used by SH5 Linux system calls for parameters */
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002195 static const int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002196
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002197 /*
2198 * TODO: should also check that the number of arguments encoded
2199 * in the trap number matches the number strace expects.
2200 */
2201 /*
2202 assert(sysent[tcp->scno].nargs < ARRAY_SIZE(syscall_regs));
2203 */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002204
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002205 tcp->u_nargs = sysent[tcp->scno].nargs;
2206 for (i = 0; i < tcp->u_nargs; i++) {
2207 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2208 return -1;
2209 }
2210# elif defined(X86_64)
2211 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002212 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2213 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2214 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002215 };
2216
2217 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002218 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002219 else
2220 tcp->u_nargs = MAX_ARGS;
2221 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002222 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002223 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00002224 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002225# elif defined(MICROBLAZE)
2226 int i;
2227 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2228 tcp->u_nargs = sysent[tcp->scno].nargs;
2229 else
2230 tcp->u_nargs = 0;
2231 for (i = 0; i < tcp->u_nargs; i++) {
2232 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2233 return -1;
2234 }
2235# elif defined(CRISV10) || defined(CRISV32)
2236 int i;
2237 static const int crisregs[] = {
2238 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002239 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002240 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002241
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002242 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2243 tcp->u_nargs = sysent[tcp->scno].nargs;
2244 else
2245 tcp->u_nargs = 0;
2246 for (i = 0; i < tcp->u_nargs; i++) {
2247 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2248 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00002249 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002250# elif defined(TILE)
2251 int i;
2252 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2253 tcp->u_nargs = sysent[tcp->scno].nargs;
2254 else
2255 tcp->u_nargs = MAX_ARGS;
2256 for (i = 0; i < tcp->u_nargs; ++i) {
2257 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2258 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002259 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002260# elif defined(M68K)
2261 int i;
2262 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2263 tcp->u_nargs = sysent[tcp->scno].nargs;
2264 else
2265 tcp->u_nargs = MAX_ARGS;
2266 for (i = 0; i < tcp->u_nargs; i++) {
2267 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2268 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002269 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002270# else /* Other architecture (like i386) (32bits specific) */
2271 int i;
2272 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2273 tcp->u_nargs = sysent[tcp->scno].nargs;
2274 else
2275 tcp->u_nargs = MAX_ARGS;
2276 for (i = 0; i < tcp->u_nargs; i++) {
2277 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2278 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05002279 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002280# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002281#endif /* LINUX */
2282#ifdef SUNOS4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002283 int i;
2284 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2285 tcp->u_nargs = sysent[tcp->scno].nargs;
2286 else
2287 tcp->u_nargs = MAX_ARGS;
2288 for (i = 0; i < tcp->u_nargs; i++) {
2289 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002290
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002291 if (upeek(tcp, uoff(u_arg[0]) +
2292 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2293 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 }
2295#endif /* SUNOS4 */
2296#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002297# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002298 /*
2299 * SGI is broken: even though it has pr_sysarg, it doesn't
2300 * set them on system call entry. Get a clue.
2301 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002302 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002303 tcp->u_nargs = sysent[tcp->scno].nargs;
2304 else
2305 tcp->u_nargs = tcp->status.pr_nsysarg;
2306 if (tcp->u_nargs > 4) {
2307 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002308 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002309 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002310 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002311 }
2312 else {
2313 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002314 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002315 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002316# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002317 /*
2318 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2319 */
2320 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2321 tcp->u_nargs = sysent[tcp->scno].nargs;
2322 else
2323 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2324 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002325 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2326# elif defined(HAVE_PR_SYSCALL)
2327 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002328 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002329 tcp->u_nargs = sysent[tcp->scno].nargs;
2330 else
2331 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002332 for (i = 0; i < tcp->u_nargs; i++)
2333 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2334# elif defined(I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002335 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002336 tcp->u_nargs = sysent[tcp->scno].nargs;
2337 else
2338 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002339 if (tcp->u_nargs > 0)
2340 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002341 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2342# else
John Hughes25299712001-03-06 10:10:06 +00002343 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002344# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002345#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002346#ifdef FREEBSD
2347 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2348 sysent[tcp->scno].nargs > tcp->status.val)
2349 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002350 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002351 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002352 if (tcp->u_nargs < 0)
2353 tcp->u_nargs = 0;
2354 if (tcp->u_nargs > MAX_ARGS)
2355 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002356 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002357 case SYS___syscall:
2358 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2359 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002360 break;
2361 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002362 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2363 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002364 break;
2365 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002366 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2367 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002368 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002369 }
2370#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002371 return 1;
2372}
2373
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002374static int
2375trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002376{
2377 int sys_res;
2378 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002379 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002380 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002381
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002382 /* Measure the exit time as early as possible to avoid errors. */
2383 if (dtime || cflag)
2384 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002385
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002386 /* BTW, why we don't just memorize syscall no. on entry
2387 * in tcp->something?
2388 */
2389 scno_good = res = get_scno(tcp);
2390 if (res == 0)
2391 return res;
2392 if (res == 1)
2393 res = syscall_fixup(tcp);
2394 if (res == 0)
2395 return res;
2396 if (res == 1)
2397 res = get_error(tcp);
2398 if (res == 0)
2399 return res;
2400 if (res == 1)
2401 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002402
Grant Edwards8a082772011-04-07 20:25:40 +00002403 if (res == 1 && filtered(tcp)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002404 tcp->flags &= ~TCB_INSYSCALL;
2405 return 0;
2406 }
2407
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002408 if (tcp->flags & TCB_REPRINT) {
2409 printleader(tcp);
2410 tprintf("<... ");
2411 if (scno_good != 1)
2412 tprintf("????");
2413 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2414 tprintf("syscall_%lu", tcp->scno);
2415 else
2416 tprintf("%s", sysent[tcp->scno].sys_name);
2417 tprintf(" resumed> ");
2418 }
2419
2420 if (cflag) {
2421 struct timeval t = tv;
2422 int rc = count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002423 if (cflag == CFLAG_ONLY_STATS) {
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002424 tcp->flags &= ~TCB_INSYSCALL;
2425 return rc;
2426 }
2427 }
2428
2429 if (res != 1) {
2430 tprintf(") ");
2431 tabto(acolumn);
2432 tprintf("= ? <unavailable>");
2433 printtrailer();
2434 tcp->flags &= ~TCB_INSYSCALL;
2435 return res;
2436 }
2437
2438 if (tcp->scno >= nsyscalls || tcp->scno < 0
2439 || (qual_flags[tcp->scno] & QUAL_RAW))
2440 sys_res = printargs(tcp);
2441 else {
2442 if (not_failing_only && tcp->u_error)
2443 return 0; /* ignore failed syscalls */
2444 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2445 }
2446
2447 u_error = tcp->u_error;
2448 tprintf(") ");
2449 tabto(acolumn);
2450 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2451 qual_flags[tcp->scno] & QUAL_RAW) {
2452 if (u_error)
2453 tprintf("= -1 (errno %ld)", u_error);
2454 else
2455 tprintf("= %#lx", tcp->u_rval);
2456 }
2457 else if (!(sys_res & RVAL_NONE) && u_error) {
2458 switch (u_error) {
2459#ifdef LINUX
2460 case ERESTARTSYS:
2461 tprintf("= ? ERESTARTSYS (To be restarted)");
2462 break;
2463 case ERESTARTNOINTR:
2464 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2465 break;
2466 case ERESTARTNOHAND:
2467 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2468 break;
2469 case ERESTART_RESTARTBLOCK:
2470 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2471 break;
2472#endif /* LINUX */
2473 default:
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002474 if (u_error < 0)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002475 tprintf("= -1 E??? (errno %ld)", u_error);
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002476 else if (u_error < nerrnos)
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002477 tprintf("= -1 %s (%s)", errnoent[u_error],
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002478 strerror(u_error));
2479 else
Denys Vlasenkoa7949742011-08-21 17:26:55 +02002480 tprintf("= -1 ERRNO_%ld (%s)", u_error,
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002481 strerror(u_error));
2482 break;
2483 }
2484 if ((sys_res & RVAL_STR) && tcp->auxstr)
2485 tprintf(" (%s)", tcp->auxstr);
2486 }
2487 else {
2488 if (sys_res & RVAL_NONE)
2489 tprintf("= ?");
2490 else {
2491 switch (sys_res & RVAL_MASK) {
2492 case RVAL_HEX:
2493 tprintf("= %#lx", tcp->u_rval);
2494 break;
2495 case RVAL_OCTAL:
2496 tprintf("= %#lo", tcp->u_rval);
2497 break;
2498 case RVAL_UDECIMAL:
2499 tprintf("= %lu", tcp->u_rval);
2500 break;
2501 case RVAL_DECIMAL:
2502 tprintf("= %ld", tcp->u_rval);
2503 break;
2504#ifdef HAVE_LONG_LONG
2505 case RVAL_LHEX:
2506 tprintf("= %#llx", tcp->u_lrval);
2507 break;
2508 case RVAL_LOCTAL:
2509 tprintf("= %#llo", tcp->u_lrval);
2510 break;
2511 case RVAL_LUDECIMAL:
2512 tprintf("= %llu", tcp->u_lrval);
2513 break;
2514 case RVAL_LDECIMAL:
2515 tprintf("= %lld", tcp->u_lrval);
2516 break;
2517#endif
2518 default:
2519 fprintf(stderr,
2520 "invalid rval format\n");
2521 break;
2522 }
2523 }
2524 if ((sys_res & RVAL_STR) && tcp->auxstr)
2525 tprintf(" (%s)", tcp->auxstr);
2526 }
2527 if (dtime) {
2528 tv_sub(&tv, &tv, &tcp->etime);
2529 tprintf(" <%ld.%06ld>",
2530 (long) tv.tv_sec, (long) tv.tv_usec);
2531 }
2532 printtrailer();
2533
2534 dumpio(tcp);
2535 if (fflush(tcp->outf) == EOF)
2536 return -1;
2537 tcp->flags &= ~TCB_INSYSCALL;
2538 return 0;
2539}
2540
2541static int
2542trace_syscall_entering(struct tcb *tcp)
2543{
2544 int sys_res;
2545 int res, scno_good;
2546
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002547 scno_good = res = get_scno(tcp);
2548 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002549 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002550 if (res == 1)
2551 res = syscall_fixup(tcp);
2552 if (res == 0)
2553 return res;
2554 if (res == 1)
2555 res = syscall_enter(tcp);
2556 if (res == 0)
2557 return res;
2558
2559 if (res != 1) {
2560 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002561 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002562 tcp_last = tcp;
2563 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002564 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002565 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2566 tprintf("syscall_%lu(", tcp->scno);
2567 else
2568 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002569 /*
2570 * " <unavailable>" will be added later by the code which
2571 * detects ptrace errors.
2572 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002573 tcp->flags |= TCB_INSYSCALL;
2574 return res;
2575 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002576
Roland McGrath17352792005-06-07 23:21:26 +00002577 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002578#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002579 case SYS_socketcall:
2580 decode_subcall(tcp, SYS_socket_subcall,
2581 SYS_socket_nsubcalls, deref_style);
2582 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002583#endif
2584#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002585 case SYS_ipc:
2586 decode_subcall(tcp, SYS_ipc_subcall,
2587 SYS_ipc_nsubcalls, shift_style);
2588 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002589#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002590#ifdef SVR4
2591#ifdef SYS_pgrpsys_subcall
2592 case SYS_pgrpsys:
2593 decode_subcall(tcp, SYS_pgrpsys_subcall,
2594 SYS_pgrpsys_nsubcalls, shift_style);
2595 break;
2596#endif /* SYS_pgrpsys_subcall */
2597#ifdef SYS_sigcall_subcall
2598 case SYS_sigcall:
2599 decode_subcall(tcp, SYS_sigcall_subcall,
2600 SYS_sigcall_nsubcalls, mask_style);
2601 break;
2602#endif /* SYS_sigcall_subcall */
2603 case SYS_msgsys:
2604 decode_subcall(tcp, SYS_msgsys_subcall,
2605 SYS_msgsys_nsubcalls, shift_style);
2606 break;
2607 case SYS_shmsys:
2608 decode_subcall(tcp, SYS_shmsys_subcall,
2609 SYS_shmsys_nsubcalls, shift_style);
2610 break;
2611 case SYS_semsys:
2612 decode_subcall(tcp, SYS_semsys_subcall,
2613 SYS_semsys_nsubcalls, shift_style);
2614 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615 case SYS_sysfs:
2616 decode_subcall(tcp, SYS_sysfs_subcall,
2617 SYS_sysfs_nsubcalls, shift_style);
2618 break;
2619 case SYS_spcall:
2620 decode_subcall(tcp, SYS_spcall_subcall,
2621 SYS_spcall_nsubcalls, shift_style);
2622 break;
2623#ifdef SYS_context_subcall
2624 case SYS_context:
2625 decode_subcall(tcp, SYS_context_subcall,
2626 SYS_context_nsubcalls, shift_style);
2627 break;
2628#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002629#ifdef SYS_door_subcall
2630 case SYS_door:
2631 decode_subcall(tcp, SYS_door_subcall,
2632 SYS_door_nsubcalls, door_style);
2633 break;
2634#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002635#ifdef SYS_kaio_subcall
2636 case SYS_kaio:
2637 decode_subcall(tcp, SYS_kaio_subcall,
2638 SYS_kaio_nsubcalls, shift_style);
2639 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002640#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002641#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002642#ifdef FREEBSD
2643 case SYS_msgsys:
2644 case SYS_shmsys:
2645 case SYS_semsys:
2646 decode_subcall(tcp, 0, 0, table_style);
2647 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002648#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002649#ifdef SUNOS4
2650 case SYS_semsys:
2651 decode_subcall(tcp, SYS_semsys_subcall,
2652 SYS_semsys_nsubcalls, shift_style);
2653 break;
2654 case SYS_msgsys:
2655 decode_subcall(tcp, SYS_msgsys_subcall,
2656 SYS_msgsys_nsubcalls, shift_style);
2657 break;
2658 case SYS_shmsys:
2659 decode_subcall(tcp, SYS_shmsys_subcall,
2660 SYS_shmsys_nsubcalls, shift_style);
2661 break;
2662#endif
2663 }
2664
2665 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002666
2667 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2668 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2669 (tracing_paths && !pathtrace_match(tcp))) {
2670 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002671 return 0;
2672 }
2673
Grant Edwards8a082772011-04-07 20:25:40 +00002674 tcp->flags &= ~TCB_FILTERED;
2675
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002676 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002677 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002678 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002679 return 0;
2680 }
2681
2682 printleader(tcp);
2683 tcp->flags &= ~TCB_REPRINT;
2684 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002685 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002686 tprintf("syscall_%lu(", tcp->scno);
2687 else
2688 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002689 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002690 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2691 sysent[tcp->scno].sys_func != sys_exit))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002692 sys_res = printargs(tcp);
2693 else
2694 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2695 if (fflush(tcp->outf) == EOF)
2696 return -1;
2697 tcp->flags |= TCB_INSYSCALL;
2698 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002699 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002700 gettimeofday(&tcp->etime, NULL);
2701 return sys_res;
2702}
2703
2704int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002705trace_syscall(struct tcb *tcp)
2706{
2707 return exiting(tcp) ?
2708 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2709}
2710
2711int
Denys Vlasenko12014262011-05-30 14:00:14 +02002712printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713{
2714 if (entering(tcp)) {
2715 int i;
2716
2717 for (i = 0; i < tcp->u_nargs; i++)
2718 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2719 }
2720 return 0;
2721}
2722
2723long
Denys Vlasenko12014262011-05-30 14:00:14 +02002724getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002725{
2726 long val = -1;
2727
2728#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002729#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002730 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002731 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002732 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002733 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002734#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002735 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002736 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002737#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002738 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002739 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002740#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741#endif /* LINUX */
2742
2743#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002744 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002745 return -1;
2746#endif /* SUNOS4 */
2747
2748#ifdef SVR4
2749#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002750 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002751#endif /* SPARC */
2752#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002753 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002754#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002755#ifdef X86_64
2756 val = tcp->status.PR_REG[RDX];
2757#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002758#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002759 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002760#endif /* MIPS */
2761#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002762
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002763#ifdef FREEBSD
2764 struct reg regs;
2765 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2766 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002767#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002768 return val;
2769}
2770
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002771#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002772/*
2773 * Apparently, indirect system calls have already be converted by ptrace(2),
2774 * so if you see "indir" this program has gone astray.
2775 */
2776int
Denys Vlasenko12014262011-05-30 14:00:14 +02002777sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002778{
2779 int i, scno, nargs;
2780
2781 if (entering(tcp)) {
Denys Vlasenko5d645812011-08-20 12:48:18 +02002782 scno = tcp->u_arg[0];
2783 if (scno > nsyscalls) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002784 fprintf(stderr, "Bogus syscall: %u\n", scno);
2785 return 0;
2786 }
2787 nargs = sysent[scno].nargs;
2788 tprintf("%s", sysent[scno].sys_name);
2789 for (i = 0; i < nargs; i++)
2790 tprintf(", %#lx", tcp->u_arg[i+1]);
2791 }
2792 return 0;
2793}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002794#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002795
2796int
2797is_restart_error(struct tcb *tcp)
2798{
2799#ifdef LINUX
2800 if (!syserror(tcp))
2801 return 0;
2802 switch (tcp->u_error) {
2803 case ERESTARTSYS:
2804 case ERESTARTNOINTR:
2805 case ERESTARTNOHAND:
2806 case ERESTART_RESTARTBLOCK:
2807 return 1;
2808 default:
2809 break;
2810 }
2811#endif /* LINUX */
2812 return 0;
2813}