blob: e22e391eebdb66767b2f559194d5d1480248f6b8 [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 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000473 if (!(copy = strdup(s))) {
474 fprintf(stderr, "out of memory\n");
475 exit(1);
476 }
477 for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000478 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000479 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000480 if (sysent0[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000481 qualify_one(i, opt->bitflag, not, 0);
Roland McGrath138c6a32006-01-12 09:50:49 +0000482
483#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000484 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000485 if (sysent1[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000486 qualify_one(i, opt->bitflag, not, 1);
Roland McGrath138c6a32006-01-12 09:50:49 +0000487#endif /* SUPPORTED_PERSONALITIES >= 2 */
488
489#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000490 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000491 if (sysent2[i].sys_flags & n)
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000492 qualify_one(i, opt->bitflag, not, 2);
Roland McGrath138c6a32006-01-12 09:50:49 +0000493#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000494
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000495 continue;
496 }
Dmitry V. Levin35d05722010-09-15 16:18:20 +0000497 if (opt->qualify(p, opt->bitflag, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000498 fprintf(stderr, "strace: invalid %s `%s'\n",
499 opt->argument_name, p);
500 exit(1);
501 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000502 }
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000503 free(copy);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000504 return;
505}
506
507static void
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000508dumpio(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000509{
510 if (syserror(tcp))
511 return;
512 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
513 return;
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000514 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
515 return;
516 if (sysent[tcp->scno].sys_func == printargs)
517 return;
518 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) {
519 if (sysent[tcp->scno].sys_func == sys_read ||
520 sysent[tcp->scno].sys_func == sys_pread ||
521 sysent[tcp->scno].sys_func == sys_pread64 ||
522 sysent[tcp->scno].sys_func == sys_recv ||
523 sysent[tcp->scno].sys_func == sys_recvfrom)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000524 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000525 else if (sysent[tcp->scno].sys_func == sys_readv)
526 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
527 return;
528 }
529 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) {
530 if (sysent[tcp->scno].sys_func == sys_write ||
531 sysent[tcp->scno].sys_func == sys_pwrite ||
532 sysent[tcp->scno].sys_func == sys_pwrite64 ||
533 sysent[tcp->scno].sys_func == sys_send ||
534 sysent[tcp->scno].sys_func == sys_sendto)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000535 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000536 else if (sysent[tcp->scno].sys_func == sys_writev)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000537 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
Dmitry V. Levin65c1a812011-02-09 00:39:47 +0000538 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539 }
540}
541
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000542#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000543enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000544#else /* FREEBSD */
545enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
546
547struct subcall {
548 int call;
549 int nsubcalls;
550 int subcalls[5];
551};
552
Roland McGratha4d48532005-06-08 20:45:28 +0000553static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000554 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000555#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000556 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000557#else
558 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
559#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000560 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
561};
562#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000563
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000564#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000565
Roland McGratha4d48532005-06-08 20:45:28 +0000566static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200567decode_subcall(struct tcb *tcp, int subcall, int nsubcalls, enum subcall_style style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000569 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000570 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000571 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000572
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000573 switch (style) {
574 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000575 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
576 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000577 tcp->scno = subcall + tcp->u_arg[0];
578 if (sysent[tcp->scno].nargs != -1)
579 tcp->u_nargs = sysent[tcp->scno].nargs;
580 else
581 tcp->u_nargs--;
582 for (i = 0; i < tcp->u_nargs; i++)
583 tcp->u_arg[i] = tcp->u_arg[i + 1];
584 break;
585 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000586 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
587 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588 tcp->scno = subcall + tcp->u_arg[0];
589 addr = tcp->u_arg[1];
590 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000591 if (size == sizeof(int)) {
592 unsigned int arg;
593 if (umove(tcp, addr, &arg) < 0)
594 arg = 0;
595 tcp->u_arg[i] = arg;
596 }
597 else if (size == sizeof(long)) {
598 unsigned long arg;
599 if (umove(tcp, addr, &arg) < 0)
600 arg = 0;
601 tcp->u_arg[i] = arg;
602 }
603 else
604 abort();
605 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000606 }
607 tcp->u_nargs = sysent[tcp->scno].nargs;
608 break;
609 case mask_style:
610 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000611 for (i = 0; mask; i++)
612 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000613 if (i >= nsubcalls)
614 return;
615 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616 tcp->scno = subcall + i;
617 if (sysent[tcp->scno].nargs != -1)
618 tcp->u_nargs = sysent[tcp->scno].nargs;
619 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000620 case door_style:
621 /*
622 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000623 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000624 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000625 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
626 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000627 tcp->scno = subcall + tcp->u_arg[5];
628 if (sysent[tcp->scno].nargs != -1)
629 tcp->u_nargs = sysent[tcp->scno].nargs;
630 else
631 tcp->u_nargs--;
632 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000633#ifdef FREEBSD
634 case table_style:
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000635 for (i = 0; i < ARRAY_SIZE(subcalls_table); i++)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000636 if (subcalls_table[i].call == tcp->scno) break;
Dmitry V. Levinfcda7a52011-06-13 21:58:43 +0000637 if (i < ARRAY_SIZE(subcalls_table) &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000638 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
639 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
640 for (i = 0; i < tcp->u_nargs; i++)
641 tcp->u_arg[i] = tcp->u_arg[i + 1];
642 }
643 break;
644#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000645 }
646}
647#endif
648
649struct tcb *tcp_last = NULL;
650
651static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000652internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000653{
654 /*
655 * We must always trace a few critical system calls in order to
656 * correctly support following forks in the presence of tracing
657 * qualifiers.
658 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000659 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000660
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000661 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
662 return 0;
663
664 func = sysent[tcp->scno].sys_func;
665
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000666 if ( sys_fork == func
667#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
668 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000669#endif
Dmitry V. Levin257e1572009-12-26 17:55:24 +0000670#ifdef LINUX
671 || sys_clone == func
672#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000673#if UNIXWARE > 2
674 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000675#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000676 )
677 return internal_fork(tcp);
678
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000679 if ( sys_execve == func
680#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
681 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000682#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683#if UNIXWARE > 2
684 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000685#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000686 )
687 return internal_exec(tcp);
688
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000689 return 0;
690}
691
Wichert Akkermanc7926982000-04-10 22:22:31 +0000692
693#ifdef LINUX
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200694# if defined (I386)
695static long eax;
696# elif defined (IA64)
697long r8, r10, psr; /* TODO: make static? */
698long ia32 = 0; /* not static */
699# elif defined (POWERPC)
700static long result, flags;
701# elif defined (M68K)
702static long d0;
703# elif defined(BFIN)
704static long r0;
705# elif defined (ARM)
706static struct pt_regs regs;
707# elif defined (ALPHA)
708static long r0;
709static long a3;
710# elif defined(AVR32)
711static struct pt_regs regs;
712# elif defined (SPARC) || defined (SPARC64)
713static struct pt_regs regs;
714static unsigned long trap;
715# elif defined(LINUX_MIPSN32)
716static long long a3;
717static long long r2;
718# elif defined(MIPS)
719static long a3;
720static long r2;
721# elif defined(S390) || defined(S390X)
722static long gpr2;
723static long pc;
724static long syscall_mode;
725# elif defined(HPPA)
726static long r28;
727# elif defined(SH)
728static long r0;
729# elif defined(SH64)
730static long r9;
731# elif defined(X86_64)
732static long rax;
733# elif defined(CRISV10) || defined(CRISV32)
734static long r10;
735# elif defined(MICROBLAZE)
736static long r3;
737# endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000738#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000739#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200740struct reg regs; /* TODO: make static? */
Roland McGrath761b5d72002-12-15 23:58:31 +0000741#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000742
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000743int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000744get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000745{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000747
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000748#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000749# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000750 if (tcp->flags & TCB_WAITEXECVE) {
751 /*
752 * When the execve system call completes successfully, the
753 * new process still has -ENOSYS (old style) or __NR_execve
754 * (new style) in gpr2. We cannot recover the scno again
755 * by disassembly, because the image that executed the
756 * syscall is gone now. Fortunately, we don't want it. We
757 * leave the flag set so that syscall_fixup can fake the
758 * result.
759 */
760 if (tcp->flags & TCB_INSYSCALL)
761 return 1;
762 /*
763 * This is the SIGTRAP after execve. We cannot try to read
764 * the system call here either.
765 */
766 tcp->flags &= ~TCB_WAITEXECVE;
767 return 0;
768 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000769
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000770 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200771 return -1;
Roland McGrath2f924ca2003-06-26 22:23:28 +0000772
773 if (syscall_mode != -ENOSYS) {
774 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000775 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000776 */
777 scno = syscall_mode;
778 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000779 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000780 * Old style of "passing" the scno via the SVC instruction.
781 */
782
783 long opcode, offset_reg, tmp;
784 void * svc_addr;
Denys Vlasenko7c9ba8b2011-08-19 19:46:32 +0200785 static const int gpr_offset[16] = {
786 PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
787 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
788 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
789 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
790 };
Roland McGrath761b5d72002-12-15 23:58:31 +0000791
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000792 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000793 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000794 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000795 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000796 if (errno) {
797 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000798 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000799 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000800
801 /*
802 * We have to check if the SVC got executed directly or via an
803 * EXECUTE instruction. In case of EXECUTE it is necessary to do
804 * instruction decoding to derive the system call number.
805 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
806 * so that this doesn't work if a SVC opcode is part of an EXECUTE
807 * opcode. Since there is no way to find out the opcode size this
808 * is the best we can do...
809 */
810
811 if ((opcode & 0xff00) == 0x0a00) {
812 /* SVC opcode */
813 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000814 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000815 else {
816 /* SVC got executed by EXECUTE instruction */
817
818 /*
819 * Do instruction decoding of EXECUTE. If you really want to
820 * understand this, read the Principles of Operations.
821 */
822 svc_addr = (void *) (opcode & 0xfff);
823
824 tmp = 0;
825 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000826 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000827 return -1;
828 svc_addr += tmp;
829
830 tmp = 0;
831 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000832 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000833 return -1;
834 svc_addr += tmp;
835
Denys Vlasenkofb036672009-01-23 16:30:26 +0000836 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000837 if (errno)
838 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000839# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000840 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000841# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000842 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000843# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000844 tmp = 0;
845 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000846 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000847 return -1;
848
849 scno = (scno | tmp) & 0xff;
850 }
851 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000852# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000853 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000854 return -1;
855 if (!(tcp->flags & TCB_INSYSCALL)) {
856 /* Check if we return from execve. */
857 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
858 tcp->flags &= ~TCB_WAITEXECVE;
859 return 0;
860 }
861 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200862
863# ifdef POWERPC64
864 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200865 /* TODO: speed up strace by not doing this at every syscall.
866 * We only need to do it after execve.
867 */
868 int currpers;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200869 long val;
870 int pid = tcp->pid;
871
872 /* Check for 64/32 bit mode. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200873 if (upeek(tcp, sizeof(unsigned long)*PT_MSR, &val) < 0)
Andreas Schwabd69fa492010-07-12 21:39:57 +0200874 return -1;
875 /* SF is bit 0 of MSR */
876 if (val < 0)
877 currpers = 0;
878 else
879 currpers = 1;
880 if (currpers != current_personality) {
881 static const char *const names[] = {"64 bit", "32 bit"};
882 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000883 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Andreas Schwabd69fa492010-07-12 21:39:57 +0200884 pid, names[current_personality]);
885 }
886 }
887# endif
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000888# elif defined(AVR32)
889 /*
890 * Read complete register set in one go.
891 */
892 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
893 return -1;
894
895 /*
896 * We only need to grab the syscall number on syscall entry.
897 */
898 if (!(tcp->flags & TCB_INSYSCALL)) {
899 scno = regs.r8;
900
901 /* Check if we return from execve. */
902 if (tcp->flags & TCB_WAITEXECVE) {
903 tcp->flags &= ~TCB_WAITEXECVE;
904 return 0;
905 }
906 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000907# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000908 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000909 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000910# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000911 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000912 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000913# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000914 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000915 return -1;
916
Roland McGrath761b5d72002-12-15 23:58:31 +0000917 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenkodeec74e2011-08-20 00:03:10 +0200918 /* TODO: speed up strace by not doing this at every syscall.
919 * We only need to do it after execve.
920 */
921 int currpers;
Michal Ludvig0e035502002-09-23 15:41:01 +0000922 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000923 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000924
925 /* Check CS register value. On x86-64 linux it is:
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200926 * 0x33 for long mode (64 bit)
927 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000928 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000929 * to be cached.
930 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000931 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000932 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000933 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000934 case 0x23: currpers = 1; break;
935 case 0x33: currpers = 0; break;
936 default:
937 fprintf(stderr, "Unknown value CS=0x%02X while "
938 "detecting personality of process "
939 "PID=%d\n", (int)val, pid);
940 currpers = current_personality;
941 break;
942 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000943# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000944 /* This version analyzes the opcode of a syscall instruction.
945 * (int 0x80 on i386 vs. syscall on x86-64)
946 * It works, but is too complicated.
947 */
948 unsigned long val, rip, i;
949
Denys Vlasenko8236f252009-01-02 18:10:08 +0000950 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000951 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000952
Michal Ludvig0e035502002-09-23 15:41:01 +0000953 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000954 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000955 errno = 0;
956
Denys Vlasenko8236f252009-01-02 18:10:08 +0000957 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000958 if (errno)
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000959 fprintf(stderr, "ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000960 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000961 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000962 /* x86-64: syscall = 0x0f 0x05 */
963 case 0x050f: currpers = 0; break;
964 /* i386: int 0x80 = 0xcd 0x80 */
965 case 0x80cd: currpers = 1; break;
966 default:
967 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000968 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000969 "Unknown syscall opcode (0x%04X) while "
970 "detecting personality of process "
971 "PID=%d\n", (int)call, pid);
972 break;
973 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000974# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000975 if (currpers != current_personality) {
976 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000977 set_personality(currpers);
Dmitry V. Levinbdafa1a2010-12-02 23:38:13 +0000978 fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000979 pid, names[current_personality]);
980 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000981 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000982# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000983# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200984 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000985 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000986 if (!(tcp->flags & TCB_INSYSCALL)) {
987 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000988 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000989 return -1;
990 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200991 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000992 return -1;
993 }
Roland McGrathba954762003-03-05 06:29:06 +0000994 /* Check if we return from execve. */
995 if (tcp->flags & TCB_WAITEXECVE) {
996 tcp->flags &= ~TCB_WAITEXECVE;
997 return 0;
998 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000999 } else {
1000 /* syscall in progress */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001001 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001002 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001003 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001004 return -1;
1005 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001006# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001007 /*
1008 * Read complete register set in one go.
1009 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001010 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001011 return -1;
1012
1013 /*
1014 * We only need to grab the syscall number on syscall entry.
1015 */
1016 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001017 if (!(tcp->flags & TCB_INSYSCALL)) {
1018 /* Check if we return from execve. */
1019 if (tcp->flags & TCB_WAITEXECVE) {
1020 tcp->flags &= ~TCB_WAITEXECVE;
1021 return 0;
1022 }
1023 }
1024
Roland McGrath0f87c492003-06-03 23:29:04 +00001025 /*
1026 * Note: we only deal with only 32-bit CPUs here.
1027 */
1028 if (regs.ARM_cpsr & 0x20) {
1029 /*
1030 * Get the Thumb-mode system call number
1031 */
1032 scno = regs.ARM_r7;
1033 } else {
1034 /*
1035 * Get the ARM-mode system call number
1036 */
1037 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001038 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001039 if (errno)
1040 return -1;
1041
1042 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1043 tcp->flags &= ~TCB_WAITEXECVE;
1044 return 0;
1045 }
1046
Roland McGrathf691bd22006-04-25 07:34:41 +00001047 /* Handle the EABI syscall convention. We do not
1048 bother converting structures between the two
1049 ABIs, but basic functionality should work even
1050 if strace and the traced program have different
1051 ABIs. */
1052 if (scno == 0xef000000) {
1053 scno = regs.ARM_r7;
1054 } else {
1055 if ((scno & 0x0ff00000) != 0x0f900000) {
1056 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1057 scno);
1058 return -1;
1059 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001060
Roland McGrathf691bd22006-04-25 07:34:41 +00001061 /*
1062 * Fixup the syscall number
1063 */
1064 scno &= 0x000fffff;
1065 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001066 }
Roland McGrath56703312008-05-20 01:35:55 +00001067 if (scno & 0x0f0000) {
1068 /*
1069 * Handle ARM specific syscall
1070 */
1071 set_personality(1);
1072 scno &= 0x0000ffff;
1073 } else
1074 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001075
1076 if (tcp->flags & TCB_INSYSCALL) {
1077 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1078 tcp->flags &= ~TCB_INSYSCALL;
1079 }
1080 } else {
1081 if (!(tcp->flags & TCB_INSYSCALL)) {
1082 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1083 tcp->flags |= TCB_INSYSCALL;
1084 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001086# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001087 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001088 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001089# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001090 unsigned long long regs[38];
1091
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001092 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001093 return -1;
1094 a3 = regs[REG_A3];
1095 r2 = regs[REG_V0];
1096
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001097 if (!(tcp->flags & TCB_INSYSCALL)) {
Roland McGrath542c2c62008-05-20 01:11:56 +00001098 scno = r2;
1099
1100 /* Check if we return from execve. */
1101 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1102 tcp->flags &= ~TCB_WAITEXECVE;
1103 return 0;
1104 }
1105
1106 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001107 if (a3 == 0 || a3 == -1) {
1108 if (debug)
1109 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Roland McGrath542c2c62008-05-20 01:11:56 +00001110 return 0;
1111 }
1112 }
1113 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001114# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001115 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001116 return -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001117 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001118 if (upeek(tcp, REG_V0, &scno) < 0)
1119 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001120
Roland McGrath542c2c62008-05-20 01:11:56 +00001121 /* Check if we return from execve. */
1122 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1123 tcp->flags &= ~TCB_WAITEXECVE;
1124 return 0;
1125 }
1126
Wichert Akkermanf90da011999-10-31 21:15:38 +00001127 if (scno < 0 || scno > nsyscalls) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001128 if (a3 == 0 || a3 == -1) {
1129 if (debug)
1130 fprintf(stderr, "stray syscall exit: v0 = %ld\n", scno);
Wichert Akkermanf90da011999-10-31 21:15:38 +00001131 return 0;
1132 }
1133 }
1134 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001135 if (upeek(tcp, REG_V0, &r2) < 0)
1136 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001137 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001138# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001139 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140 return -1;
1141
1142 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001143 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001144 return -1;
1145
1146 /* Check if we return from execve. */
1147 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1148 tcp->flags &= ~TCB_WAITEXECVE;
1149 return 0;
1150 }
1151
1152 /*
1153 * Do some sanity checks to figure out if it's
1154 * really a syscall entry
1155 */
1156 if (scno < 0 || scno > nsyscalls) {
1157 if (a3 == 0 || a3 == -1) {
1158 if (debug)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001159 fprintf(stderr, "stray syscall exit: r0 = %ld\n", scno);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160 return 0;
1161 }
1162 }
1163 }
1164 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001165 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 return -1;
1167 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001168# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001170 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171 return -1;
1172
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001173 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174 if (!(tcp->flags & TCB_INSYSCALL)) {
1175 /* Retrieve the syscall trap instruction. */
1176 errno = 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001177# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001178 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.tpc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001179 trap >>= 32;
Mike Frysinger8566c502009-10-12 11:05:14 -04001180# else
1181 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001182# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183 if (errno)
1184 return -1;
1185
1186 /* Disassemble the trap to see what personality to use. */
1187 switch (trap) {
1188 case 0x91d02010:
1189 /* Linux/SPARC syscall trap. */
1190 set_personality(0);
1191 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001192 case 0x91d0206d:
1193 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001194 set_personality(2);
1195 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001196 case 0x91d02000:
1197 /* SunOS syscall trap. (pers 1) */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001198 fprintf(stderr, "syscall: SunOS no support\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001199 return -1;
1200 case 0x91d02008:
1201 /* Solaris 2.x syscall trap. (per 2) */
1202 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001203 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001204 case 0x91d02009:
1205 /* NetBSD/FreeBSD syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001206 fprintf(stderr, "syscall: NetBSD/FreeBSD not supported\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001207 return -1;
1208 case 0x91d02027:
1209 /* Solaris 2.x gettimeofday */
1210 set_personality(1);
1211 break;
1212 default:
1213 /* Unknown syscall trap. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001214 if (tcp->flags & TCB_WAITEXECVE) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001215 tcp->flags &= ~TCB_WAITEXECVE;
1216 return 0;
1217 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001218# if defined (SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001219 fprintf(stderr, "syscall: unknown syscall trap %08lx %016lx\n", trap, regs.tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001220# else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001221 fprintf(stderr, "syscall: unknown syscall trap %08lx %08lx\n", trap, regs.pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001222# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001223 return -1;
1224 }
1225
1226 /* Extract the system call number from the registers. */
1227 if (trap == 0x91d02027)
1228 scno = 156;
1229 else
Mike Frysinger8566c502009-10-12 11:05:14 -04001230 scno = regs.u_regs[U_REG_G1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231 if (scno == 0) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001232 scno = regs.u_regs[U_REG_O0];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001233 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 +00001234 }
1235 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001236# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001237 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001238 return -1;
1239 if (!(tcp->flags & TCB_INSYSCALL)) {
1240 /* Check if we return from execve. */
1241 if ((tcp->flags & TCB_WAITEXECVE)) {
1242 tcp->flags &= ~TCB_WAITEXECVE;
1243 return 0;
1244 }
1245 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001246# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001247 /*
1248 * In the new syscall ABI, the system call number is in R3.
1249 */
1250 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1251 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001252
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001253 if (scno < 0) {
1254 /* Odd as it may seem, a glibc bug has been known to cause
1255 glibc to issue bogus negative syscall numbers. So for
1256 our purposes, make strace print what it *should* have been */
1257 long correct_scno = (scno & 0xff);
1258 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001259 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001260 "Detected glibc bug: bogus system call"
1261 " number = %ld, correcting to %ld\n",
1262 scno,
1263 correct_scno);
1264 scno = correct_scno;
1265 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001266
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001267 if (!(tcp->flags & TCB_INSYSCALL)) {
1268 /* Check if we return from execve. */
1269 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1270 tcp->flags &= ~TCB_WAITEXECVE;
1271 return 0;
1272 }
1273 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001274# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001275 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001276 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001277 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001278
1279 if (!(tcp->flags & TCB_INSYSCALL)) {
1280 /* Check if we return from execve. */
1281 if (tcp->flags & TCB_WAITEXECVE) {
1282 tcp->flags &= ~TCB_WAITEXECVE;
1283 return 0;
1284 }
1285 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001286# elif defined(CRISV10) || defined(CRISV32)
1287 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1288 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05001289# elif defined(TILE)
1290 if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
1291 return -1;
1292
1293 if (!(tcp->flags & TCB_INSYSCALL)) {
1294 /* Check if we return from execve. */
1295 if (tcp->flags & TCB_WAITEXECVE) {
1296 tcp->flags &= ~TCB_WAITEXECVE;
1297 return 0;
1298 }
1299 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001300# elif defined(MICROBLAZE)
1301 if (upeek(tcp, 0, &scno) < 0)
1302 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001303# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001305
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001306#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001307 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001308 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001309#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001310 /* new syscall ABI returns result in R0 */
1311 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1312 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001313#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001314 /* ABI defines result returned in r9 */
1315 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1316 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001318
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001319#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001320# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001321 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001322# else
1323# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001324 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001325# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001326 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001327 perror("pread");
1328 return -1;
1329 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001330 switch (regs.r_eax) {
1331 case SYS_syscall:
1332 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001333 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1334 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001335 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001336 scno = regs.r_eax;
1337 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001338 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001339# endif /* FREEBSD */
1340# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001341#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001342
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001343 if (!(tcp->flags & TCB_INSYSCALL))
1344 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001345 return 1;
1346}
1347
Pavel Machek4dc3b142000-02-01 17:58:41 +00001348
Roland McGrath17352792005-06-07 23:21:26 +00001349long
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001350known_scno(struct tcb *tcp)
Roland McGrath17352792005-06-07 23:21:26 +00001351{
1352 long scno = tcp->scno;
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001353#if SUPPORTED_PERSONALITIES > 1
Roland McGrath17352792005-06-07 23:21:26 +00001354 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1355 scno = sysent[scno].native_scno;
1356 else
Dmitry V. Levinbd136452011-02-18 23:19:47 +00001357#endif
Roland McGrath17352792005-06-07 23:21:26 +00001358 scno += NR_SYSCALL_BASE;
1359 return scno;
1360}
1361
Roland McGratheb9e2e82009-06-02 16:49:22 -07001362/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001363 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001364 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1365 * 1: ok, continue in trace_syscall().
1366 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001367 * ("????" etc) and bail out.
1368 */
Roland McGratha4d48532005-06-08 20:45:28 +00001369static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001370syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001371{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001372#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001373 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001374
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001376 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001377 if (
1378 scno == SYS_fork
1379#ifdef SYS_vfork
1380 || scno == SYS_vfork
1381#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001382#ifdef SYS_fork1
1383 || scno == SYS_fork1
1384#endif /* SYS_fork1 */
1385#ifdef SYS_forkall
1386 || scno == SYS_forkall
1387#endif /* SYS_forkall */
1388#ifdef SYS_rfork1
1389 || scno == SYS_rfork1
1390#endif /* SYS_fork1 */
1391#ifdef SYS_rforkall
1392 || scno == SYS_rforkall
1393#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001394 ) {
1395 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001396 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001397 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001398 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001399 }
1400 else {
1401 fprintf(stderr, "syscall: missing entry\n");
1402 tcp->flags |= TCB_INSYSCALL;
1403 }
1404 }
1405 }
1406 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001407 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001408 fprintf(stderr, "syscall: missing exit\n");
1409 tcp->flags &= ~TCB_INSYSCALL;
1410 }
1411 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001412#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001413#ifdef SUNOS4
1414 if (!(tcp->flags & TCB_INSYSCALL)) {
1415 if (scno == 0) {
1416 fprintf(stderr, "syscall: missing entry\n");
1417 tcp->flags |= TCB_INSYSCALL;
1418 }
1419 }
1420 else {
1421 if (scno != 0) {
1422 if (debug) {
1423 /*
1424 * This happens when a signal handler
1425 * for a signal which interrupted a
1426 * a system call makes another system call.
1427 */
1428 fprintf(stderr, "syscall: missing exit\n");
1429 }
1430 tcp->flags &= ~TCB_INSYSCALL;
1431 }
1432 }
1433#endif /* SUNOS4 */
1434#ifdef LINUX
1435#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001436 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001437 return -1;
1438 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1439 if (debug)
1440 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1441 return 0;
1442 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001443#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001444 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001445 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001446 if (current_personality == 1)
1447 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001448 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1449 if (debug)
1450 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1451 return 0;
1452 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001453#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001454 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001455 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001456 if (syscall_mode != -ENOSYS)
1457 syscall_mode = tcp->scno;
1458 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001459 if (debug)
1460 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1461 return 0;
1462 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001463 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1464 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1465 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1466 /*
1467 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1468 * flag set for the post-execve SIGTRAP to see and reset.
1469 */
1470 gpr2 = 0;
1471 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472#elif defined (POWERPC)
1473# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001474 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001475 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001476 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001477 return -1;
1478 if (flags & SO_MASK)
1479 result = -result;
1480#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001481 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001482 return -1;
1483 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1484 if (debug)
1485 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1486 return 0;
1487 }
1488#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001489 /*
1490 * Nothing required
1491 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001492#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001493 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001494 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001495#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001496 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001497 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001498#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001499 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001500 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001501 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001502 return -1;
1503 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1504 if (debug)
1505 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1506 return 0;
1507 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001508#elif defined(CRISV10) || defined(CRISV32)
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001509 if (upeek(tcp, 4*PT_R10, &r10) < 0)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001510 return -1;
1511 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1512 if (debug)
1513 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1514 return 0;
1515 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001516#elif defined(MICROBLAZE)
1517 if (upeek(tcp, 3 * 4, &r3) < 0)
1518 return -1;
1519 if (r3 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1520 if (debug)
1521 fprintf(stderr, "stray syscall exit: r3 = %ld\n", r3);
1522 return 0;
1523 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001524#endif
1525#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001526 return 1;
1527}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001528
Roland McGrathc1e45922008-05-27 23:18:29 +00001529#ifdef LINUX
1530/*
1531 * Check the syscall return value register value for whether it is
1532 * a negated errno code indicating an error, or a success return value.
1533 */
1534static inline int
1535is_negated_errno(unsigned long int val)
1536{
1537 unsigned long int max = -(long int) nerrnos;
1538 if (personality_wordsize[current_personality] < sizeof(val)) {
1539 val = (unsigned int) val;
1540 max = (unsigned int) max;
1541 }
1542 return val > max;
1543}
1544#endif
1545
Roland McGratha4d48532005-06-08 20:45:28 +00001546static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001547get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001548{
1549 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001550#ifdef LINUX
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001551 int check_errno = 1;
1552 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
1553 sysent[tcp->scno].sys_flags & SYSCALL_NEVER_FAILS) {
1554 check_errno = 0;
1555 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001556# if defined(S390) || defined(S390X)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001557 if (check_errno && is_negated_errno(gpr2)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001558 tcp->u_rval = -1;
1559 u_error = -gpr2;
1560 }
1561 else {
1562 tcp->u_rval = gpr2;
1563 u_error = 0;
1564 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001565# elif defined(I386)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001566 if (check_errno && is_negated_errno(eax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001567 tcp->u_rval = -1;
1568 u_error = -eax;
1569 }
1570 else {
1571 tcp->u_rval = eax;
1572 u_error = 0;
1573 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001574# elif defined(X86_64)
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001575 if (check_errno && is_negated_errno(rax)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001576 tcp->u_rval = -1;
1577 u_error = -rax;
1578 }
1579 else {
1580 tcp->u_rval = rax;
1581 u_error = 0;
1582 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001583# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001584 if (ia32) {
1585 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001586
Roland McGrathc1e45922008-05-27 23:18:29 +00001587 err = (int)r8;
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001588 if (check_errno && is_negated_errno(err)) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001589 tcp->u_rval = -1;
1590 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001591 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001592 else {
1593 tcp->u_rval = err;
1594 u_error = 0;
1595 }
1596 } else {
Dmitry V. Levin50a218d2011-01-18 17:36:20 +00001597 if (check_errno && r10) {
Roland McGrathc1e45922008-05-27 23:18:29 +00001598 tcp->u_rval = -1;
1599 u_error = r8;
1600 } else {
1601 tcp->u_rval = r8;
1602 u_error = 0;
1603 }
1604 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001605# elif defined(MIPS)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001606 if (check_errno && a3) {
1607 tcp->u_rval = -1;
1608 u_error = r2;
1609 } else {
1610 tcp->u_rval = r2;
1611 u_error = 0;
1612 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001613# elif defined(POWERPC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001614 if (check_errno && is_negated_errno(result)) {
1615 tcp->u_rval = -1;
1616 u_error = -result;
1617 }
1618 else {
1619 tcp->u_rval = result;
1620 u_error = 0;
1621 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001622# elif defined(M68K)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001623 if (check_errno && is_negated_errno(d0)) {
1624 tcp->u_rval = -1;
1625 u_error = -d0;
1626 }
1627 else {
1628 tcp->u_rval = d0;
1629 u_error = 0;
1630 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001631# elif defined(ARM)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001632 if (check_errno && is_negated_errno(regs.ARM_r0)) {
1633 tcp->u_rval = -1;
1634 u_error = -regs.ARM_r0;
1635 }
1636 else {
1637 tcp->u_rval = regs.ARM_r0;
1638 u_error = 0;
1639 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001640# elif defined(AVR32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001641 if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1642 tcp->u_rval = -1;
1643 u_error = -regs.r12;
1644 }
1645 else {
1646 tcp->u_rval = regs.r12;
1647 u_error = 0;
1648 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001649# elif defined(BFIN)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001650 if (check_errno && is_negated_errno(r0)) {
1651 tcp->u_rval = -1;
1652 u_error = -r0;
1653 } else {
1654 tcp->u_rval = r0;
1655 u_error = 0;
1656 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001657# elif defined(ALPHA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001658 if (check_errno && a3) {
1659 tcp->u_rval = -1;
1660 u_error = r0;
1661 }
1662 else {
1663 tcp->u_rval = r0;
1664 u_error = 0;
1665 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001666# elif defined(SPARC)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001667 if (check_errno && regs.psr & PSR_C) {
1668 tcp->u_rval = -1;
1669 u_error = regs.u_regs[U_REG_O0];
1670 }
1671 else {
1672 tcp->u_rval = regs.u_regs[U_REG_O0];
1673 u_error = 0;
1674 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001675# elif defined(SPARC64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001676 if (check_errno && regs.tstate & 0x1100000000UL) {
1677 tcp->u_rval = -1;
1678 u_error = regs.u_regs[U_REG_O0];
1679 }
1680 else {
1681 tcp->u_rval = regs.u_regs[U_REG_O0];
1682 u_error = 0;
1683 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001684# elif defined(HPPA)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001685 if (check_errno && is_negated_errno(r28)) {
1686 tcp->u_rval = -1;
1687 u_error = -r28;
1688 }
1689 else {
1690 tcp->u_rval = r28;
1691 u_error = 0;
1692 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001693# elif defined(SH)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001694 /* interpret R0 as return value or error number */
1695 if (check_errno && is_negated_errno(r0)) {
1696 tcp->u_rval = -1;
1697 u_error = -r0;
1698 }
1699 else {
1700 tcp->u_rval = r0;
1701 u_error = 0;
1702 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001703# elif defined(SH64)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001704 /* interpret result as return value or error number */
1705 if (check_errno && is_negated_errno(r9)) {
1706 tcp->u_rval = -1;
1707 u_error = -r9;
1708 }
1709 else {
1710 tcp->u_rval = r9;
1711 u_error = 0;
1712 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001713# elif defined(CRISV10) || defined(CRISV32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001714 if (check_errno && r10 && (unsigned) -r10 < nerrnos) {
1715 tcp->u_rval = -1;
1716 u_error = -r10;
1717 }
1718 else {
1719 tcp->u_rval = r10;
1720 u_error = 0;
1721 }
Chris Metcalfc8c66982009-12-28 10:00:15 -05001722# elif defined(TILE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001723 long rval;
1724 /* interpret result as return value or error number */
1725 if (upeek(tcp, PTREGS_OFFSET_REG(0), &rval) < 0)
1726 return -1;
1727 if (check_errno && rval < 0 && rval > -nerrnos) {
1728 tcp->u_rval = -1;
1729 u_error = -rval;
1730 }
1731 else {
1732 tcp->u_rval = rval;
1733 u_error = 0;
1734 }
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02001735# elif defined(MICROBLAZE)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001736 /* interpret result as return value or error number */
1737 if (check_errno && is_negated_errno(r3)) {
1738 tcp->u_rval = -1;
1739 u_error = -r3;
1740 }
1741 else {
1742 tcp->u_rval = r3;
1743 u_error = 0;
1744 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001745# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001746#endif /* LINUX */
1747#ifdef SUNOS4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001748 /* get error code from user struct */
1749 if (upeek(tcp, uoff(u_error), &u_error) < 0)
1750 return -1;
1751 u_error >>= 24; /* u_error is a char */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001752
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001753 /* get system call return value */
1754 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
1755 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001756#endif /* SUNOS4 */
1757#ifdef SVR4
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001758# ifdef SPARC
1759 /* Judicious guessing goes a long way. */
1760 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1761 tcp->u_rval = -1;
1762 u_error = tcp->status.pr_reg[R_O0];
1763 }
1764 else {
1765 tcp->u_rval = tcp->status.pr_reg[R_O0];
1766 u_error = 0;
1767 }
1768# endif /* SPARC */
1769# ifdef I386
1770 /* Wanna know how to kill an hour single-stepping? */
1771 if (tcp->status.PR_REG[EFL] & 0x1) {
1772 tcp->u_rval = -1;
1773 u_error = tcp->status.PR_REG[EAX];
1774 }
1775 else {
1776 tcp->u_rval = tcp->status.PR_REG[EAX];
1777# ifdef HAVE_LONG_LONG
1778 tcp->u_lrval =
1779 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1780 tcp->status.PR_REG[EAX];
1781# endif
1782 u_error = 0;
1783 }
1784# endif /* I386 */
1785# ifdef X86_64
1786 /* Wanna know how to kill an hour single-stepping? */
1787 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1788 tcp->u_rval = -1;
1789 u_error = tcp->status.PR_REG[RAX];
1790 }
1791 else {
1792 tcp->u_rval = tcp->status.PR_REG[RAX];
1793 u_error = 0;
1794 }
1795# endif /* X86_64 */
1796# ifdef MIPS
1797 if (tcp->status.pr_reg[CTX_A3]) {
1798 tcp->u_rval = -1;
1799 u_error = tcp->status.pr_reg[CTX_V0];
1800 }
1801 else {
1802 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1803 u_error = 0;
1804 }
1805# endif /* MIPS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001806#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001807#ifdef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001808 if (regs.r_eflags & PSL_C) {
1809 tcp->u_rval = -1;
1810 u_error = regs.r_eax;
1811 } else {
1812 tcp->u_rval = regs.r_eax;
1813 tcp->u_lrval =
1814 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1815 u_error = 0;
1816 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001817#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001818 tcp->u_error = u_error;
1819 return 1;
1820}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001821
Roland McGrathb69f81b2002-12-21 23:25:18 +00001822int
Denys Vlasenko12014262011-05-30 14:00:14 +02001823force_result(struct tcb *tcp, int error, long rval)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001824{
1825#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001826# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001827 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001828 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1829 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001830# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001831 eax = error ? -error : rval;
1832 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1833 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001834# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001835 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001836 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001837 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001838# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001839 if (ia32) {
1840 r8 = error ? -error : rval;
1841 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1842 return -1;
1843 }
1844 else {
1845 if (error) {
1846 r8 = error;
1847 r10 = -1;
1848 }
1849 else {
1850 r8 = rval;
1851 r10 = 0;
1852 }
1853 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1854 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1855 return -1;
1856 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001857# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001858 r0 = error ? -error : rval;
1859 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1860 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001861# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001862 if (error) {
1863 r2 = error;
1864 a3 = -1;
1865 }
1866 else {
1867 r2 = rval;
1868 a3 = 0;
1869 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001870 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001871 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1872 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001873 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001874# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001875 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001876 return -1;
1877 if (error) {
1878 flags |= SO_MASK;
1879 result = error;
1880 }
1881 else {
1882 flags &= ~SO_MASK;
1883 result = rval;
1884 }
Roland McGratheb285352003-01-14 09:59:00 +00001885 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1886 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001887 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001888# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001889 d0 = error ? -error : rval;
1890 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1891 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001892# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001893 regs.ARM_r0 = error ? -error : rval;
1894 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001895 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001896# elif defined(AVR32)
1897 regs.r12 = error ? -error : rval;
1898 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1899 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001900# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001901 if (error) {
1902 a3 = -1;
1903 r0 = error;
1904 }
1905 else {
1906 a3 = 0;
1907 r0 = rval;
1908 }
1909 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1910 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1911 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001912# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001913 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1914 return -1;
1915 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001916 regs.psr |= PSR_C;
1917 regs.u_regs[U_REG_O0] = error;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001918 }
1919 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001920 regs.psr &= ~PSR_C;
1921 regs.u_regs[U_REG_O0] = rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001922 }
1923 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1924 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001925# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001926 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1927 return -1;
1928 if (error) {
Mike Frysinger8566c502009-10-12 11:05:14 -04001929 regs.tstate |= 0x1100000000UL;
1930 regs.u_regs[U_REG_O0] = error;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001931 }
1932 else {
Mike Frysinger8566c502009-10-12 11:05:14 -04001933 regs.tstate &= ~0x1100000000UL;
1934 regs.u_regs[U_REG_O0] = rval;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001935 }
1936 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1937 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001938# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001939 r28 = error ? -error : rval;
1940 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1941 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001942# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001943 r0 = error ? -error : rval;
1944 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1945 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001946# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001947 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001948 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1949 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001950# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001951#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001952
Roland McGrathb69f81b2002-12-21 23:25:18 +00001953#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001954 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1955 error << 24) < 0 ||
1956 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001957 return -1;
1958#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001959
Roland McGrathb69f81b2002-12-21 23:25:18 +00001960#ifdef SVR4
1961 /* XXX no clue */
1962 return -1;
1963#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001964
Roland McGrathb69f81b2002-12-21 23:25:18 +00001965#ifdef FREEBSD
1966 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001967 perror("pread");
1968 return -1;
1969 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001970 if (error) {
1971 regs.r_eflags |= PSL_C;
1972 regs.r_eax = error;
1973 }
1974 else {
1975 regs.r_eflags &= ~PSL_C;
1976 regs.r_eax = rval;
1977 }
1978 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001979 perror("pwrite");
1980 return -1;
1981 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001982#endif /* FREEBSD */
1983
1984 /* All branches reach here on success (only). */
1985 tcp->u_error = error;
1986 tcp->u_rval = rval;
1987 return 0;
1988}
1989
Roland McGratha4d48532005-06-08 20:45:28 +00001990static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001991syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001992{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001993#ifdef LINUX
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02001994# if defined(S390) || defined(S390X)
1995 int i;
1996 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1997 tcp->u_nargs = sysent[tcp->scno].nargs;
1998 else
1999 tcp->u_nargs = MAX_ARGS;
2000 for (i = 0; i < tcp->u_nargs; i++) {
2001 if (upeek(tcp, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
2002 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00002003 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002004# elif defined(ALPHA)
2005 int i;
2006 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2007 tcp->u_nargs = sysent[tcp->scno].nargs;
2008 else
2009 tcp->u_nargs = MAX_ARGS;
2010 for (i = 0; i < tcp->u_nargs; i++) {
2011 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2012 * for scno somewhere above here!
2013 */
2014 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
2015 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002016 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002017# elif defined(IA64)
2018 if (!ia32) {
2019 unsigned long *out0, cfm, sof, sol, i;
2020 long rbs_end;
2021 /* be backwards compatible with kernel < 2.4.4... */
2022# ifndef PT_RBS_END
2023# define PT_RBS_END PT_AR_BSP
2024# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002025
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002026 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
2027 return -1;
2028 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002029 return -1;
2030
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002031 sof = (cfm >> 0) & 0x7f;
2032 sol = (cfm >> 7) & 0x7f;
2033 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
2034
2035 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2036 && sysent[tcp->scno].nargs != -1)
2037 tcp->u_nargs = sysent[tcp->scno].nargs;
2038 else
2039 tcp->u_nargs = MAX_ARGS;
2040 for (i = 0; i < tcp->u_nargs; ++i) {
2041 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2042 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2043 return -1;
2044 }
2045 } else {
2046 int i;
2047
2048 if (/* EBX = out0 */
2049 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
2050 /* ECX = out1 */
2051 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
2052 /* EDX = out2 */
2053 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
2054 /* ESI = out3 */
2055 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
2056 /* EDI = out4 */
2057 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
2058 /* EBP = out5 */
2059 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2060 return -1;
2061
2062 for (i = 0; i < 6; ++i)
2063 /* truncate away IVE sign-extension */
2064 tcp->u_arg[i] &= 0xffffffff;
2065
2066 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2067 && sysent[tcp->scno].nargs != -1)
2068 tcp->u_nargs = sysent[tcp->scno].nargs;
2069 else
2070 tcp->u_nargs = 5;
2071 }
2072# elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
2073 /* N32 and N64 both use up to six registers. */
2074 unsigned long long regs[38];
2075 int i, nargs;
2076 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2077 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2078 else
2079 nargs = tcp->u_nargs = MAX_ARGS;
2080
2081 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
2082 return -1;
2083
2084 for (i = 0; i < nargs; i++) {
2085 tcp->u_arg[i] = regs[REG_A0 + i];
2086# if defined(LINUX_MIPSN32)
2087 tcp->ext_arg[i] = regs[REG_A0 + i];
2088# endif
2089 }
2090# elif defined(MIPS)
2091 long sp;
2092 int i, nargs;
2093
2094 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2095 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
2096 else
2097 nargs = tcp->u_nargs = MAX_ARGS;
2098 if (nargs > 4) {
2099 if (upeek(tcp, REG_SP, &sp) < 0)
2100 return -1;
2101 for (i = 0; i < 4; i++) {
2102 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2103 return -1;
2104 }
2105 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2106 (char *)(tcp->u_arg + 4));
2107 } else {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002108 for (i = 0; i < nargs; i++) {
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002109 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002110 return -1;
2111 }
2112 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002113# elif defined(POWERPC)
2114# ifndef PT_ORIG_R3
2115# define PT_ORIG_R3 34
2116# endif
2117 int i;
2118 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2119 tcp->u_nargs = sysent[tcp->scno].nargs;
2120 else
2121 tcp->u_nargs = MAX_ARGS;
2122 for (i = 0; i < tcp->u_nargs; i++) {
2123 if (upeek(tcp, (i==0) ?
2124 (sizeof(unsigned long) * PT_ORIG_R3) :
2125 ((i+PT_R3) * sizeof(unsigned long)),
2126 &tcp->u_arg[i]) < 0)
2127 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002128 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002129# elif defined(SPARC) || defined(SPARC64)
2130 int i;
2131 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2132 tcp->u_nargs = sysent[tcp->scno].nargs;
2133 else
2134 tcp->u_nargs = MAX_ARGS;
2135 for (i = 0; i < tcp->u_nargs; i++)
2136 tcp->u_arg[i] = regs.u_regs[U_REG_O0 + i];
2137# elif defined(HPPA)
2138 int i;
2139 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2140 tcp->u_nargs = sysent[tcp->scno].nargs;
2141 else
2142 tcp->u_nargs = MAX_ARGS;
2143 for (i = 0; i < tcp->u_nargs; i++) {
2144 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2145 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002146 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002147# elif defined(ARM)
2148 int i;
2149 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2150 tcp->u_nargs = sysent[tcp->scno].nargs;
2151 else
2152 tcp->u_nargs = MAX_ARGS;
2153 for (i = 0; i < tcp->u_nargs; i++)
2154 tcp->u_arg[i] = regs.uregs[i];
2155# elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002156 tcp->u_nargs = sysent[tcp->scno].nargs;
2157 tcp->u_arg[0] = regs.r12;
2158 tcp->u_arg[1] = regs.r11;
2159 tcp->u_arg[2] = regs.r10;
2160 tcp->u_arg[3] = regs.r9;
2161 tcp->u_arg[4] = regs.r5;
2162 tcp->u_arg[5] = regs.r3;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002163# elif defined(BFIN)
2164 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002165 static const int argreg[] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 };
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002166
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002167 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002168 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002169 else
2170 tcp->u_nargs = ARRAY_SIZE(argreg);
2171
2172 for (i = 0; i < tcp->u_nargs; ++i)
2173 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
2174 return -1;
2175# elif defined(SH)
2176 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002177 static const int syscall_regs[] = {
2178 4 * (REG_REG0+4), 4 * (REG_REG0+5), 4 * (REG_REG0+6), 4 * (REG_REG0+7),
2179 4 * (REG_REG0 ), 4 * (REG_REG0+1), 4 * (REG_REG0+2)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002180 };
2181
2182 tcp->u_nargs = sysent[tcp->scno].nargs;
2183 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002184 if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002185 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002186 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002187# elif defined(SH64)
2188 int i;
2189 /* Registers used by SH5 Linux system calls for parameters */
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002190 static const int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002191
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002192 /*
2193 * TODO: should also check that the number of arguments encoded
2194 * in the trap number matches the number strace expects.
2195 */
2196 /*
2197 assert(sysent[tcp->scno].nargs < ARRAY_SIZE(syscall_regs));
2198 */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002199
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002200 tcp->u_nargs = sysent[tcp->scno].nargs;
2201 for (i = 0; i < tcp->u_nargs; i++) {
2202 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2203 return -1;
2204 }
2205# elif defined(X86_64)
2206 int i;
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002207 static const int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2208 { 8 * RDI, 8 * RSI, 8 * RDX, 8 * R10, 8 * R8 , 8 * R9 }, /* x86-64 ABI */
2209 { 8 * RBX, 8 * RCX, 8 * RDX, 8 * RSI, 8 * RDI, 8 * RBP } /* i386 ABI */
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002210 };
2211
2212 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002213 tcp->u_nargs = sysent[tcp->scno].nargs;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002214 else
2215 tcp->u_nargs = MAX_ARGS;
2216 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002217 if (upeek(tcp, argreg[current_personality][i], &tcp->u_arg[i]) < 0)
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002218 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00002219 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002220# elif defined(MICROBLAZE)
2221 int i;
2222 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2223 tcp->u_nargs = sysent[tcp->scno].nargs;
2224 else
2225 tcp->u_nargs = 0;
2226 for (i = 0; i < tcp->u_nargs; i++) {
2227 if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0)
2228 return -1;
2229 }
2230# elif defined(CRISV10) || defined(CRISV32)
2231 int i;
2232 static const int crisregs[] = {
2233 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
Denys Vlasenko0b6c73c2011-06-23 22:22:34 +02002234 4*PT_R13 , 4*PT_MOF, 4*PT_SRP
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002235 };
Roland McGrathe1e584b2003-06-02 19:18:58 +00002236
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002237 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2238 tcp->u_nargs = sysent[tcp->scno].nargs;
2239 else
2240 tcp->u_nargs = 0;
2241 for (i = 0; i < tcp->u_nargs; i++) {
2242 if (upeek(tcp, crisregs[i], &tcp->u_arg[i]) < 0)
2243 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00002244 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002245# elif defined(TILE)
2246 int i;
2247 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2248 tcp->u_nargs = sysent[tcp->scno].nargs;
2249 else
2250 tcp->u_nargs = MAX_ARGS;
2251 for (i = 0; i < tcp->u_nargs; ++i) {
2252 if (upeek(tcp, PTREGS_OFFSET_REG(i), &tcp->u_arg[i]) < 0)
2253 return -1;
Edgar E. Iglesias939caba2010-07-06 14:21:07 +02002254 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002255# elif defined(M68K)
2256 int i;
2257 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2258 tcp->u_nargs = sysent[tcp->scno].nargs;
2259 else
2260 tcp->u_nargs = MAX_ARGS;
2261 for (i = 0; i < tcp->u_nargs; i++) {
2262 if (upeek(tcp, (i < 5 ? i : i + 2)*4, &tcp->u_arg[i]) < 0)
2263 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002264 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002265# else /* Other architecture (like i386) (32bits specific) */
2266 int i;
2267 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2268 tcp->u_nargs = sysent[tcp->scno].nargs;
2269 else
2270 tcp->u_nargs = MAX_ARGS;
2271 for (i = 0; i < tcp->u_nargs; i++) {
2272 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
2273 return -1;
Chris Metcalfc8c66982009-12-28 10:00:15 -05002274 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002275# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002276#endif /* LINUX */
2277#ifdef SUNOS4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002278 int i;
2279 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2280 tcp->u_nargs = sysent[tcp->scno].nargs;
2281 else
2282 tcp->u_nargs = MAX_ARGS;
2283 for (i = 0; i < tcp->u_nargs; i++) {
2284 struct user *u;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002285
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002286 if (upeek(tcp, uoff(u_arg[0]) +
2287 (i * sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2288 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002289 }
2290#endif /* SUNOS4 */
2291#ifdef SVR4
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002292# ifdef MIPS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293 /*
2294 * SGI is broken: even though it has pr_sysarg, it doesn't
2295 * set them on system call entry. Get a clue.
2296 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002297 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002298 tcp->u_nargs = sysent[tcp->scno].nargs;
2299 else
2300 tcp->u_nargs = tcp->status.pr_nsysarg;
2301 if (tcp->u_nargs > 4) {
2302 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002303 4 * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002304 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002305 (tcp->u_nargs - 4) * sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002306 }
2307 else {
2308 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002309 tcp->u_nargs * sizeof(tcp->u_arg[0]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002310 }
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002311# elif UNIXWARE >= 2
John Hughes25299712001-03-06 10:10:06 +00002312 /*
2313 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2314 */
2315 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2316 tcp->u_nargs = sysent[tcp->scno].nargs;
2317 else
2318 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2319 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002320 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2321# elif defined(HAVE_PR_SYSCALL)
2322 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002323 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002324 tcp->u_nargs = sysent[tcp->scno].nargs;
2325 else
2326 tcp->u_nargs = tcp->status.pr_nsysarg;
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002327 for (i = 0; i < tcp->u_nargs; i++)
2328 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2329# elif defined(I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002330 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002331 tcp->u_nargs = sysent[tcp->scno].nargs;
2332 else
2333 tcp->u_nargs = 5;
Denys Vlasenko4660fe62011-06-09 01:32:23 +02002334 if (tcp->u_nargs > 0)
2335 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002336 tcp->u_nargs * sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2337# else
John Hughes25299712001-03-06 10:10:06 +00002338 I DONT KNOW WHAT TO DO
Denys Vlasenkof5d099c2011-06-23 22:10:54 +02002339# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002340#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002341#ifdef FREEBSD
2342 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2343 sysent[tcp->scno].nargs > tcp->status.val)
2344 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002345 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002346 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002347 if (tcp->u_nargs < 0)
2348 tcp->u_nargs = 0;
2349 if (tcp->u_nargs > MAX_ARGS)
2350 tcp->u_nargs = MAX_ARGS;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002351 switch (regs.r_eax) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002352 case SYS___syscall:
2353 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2354 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002355 break;
2356 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002357 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2358 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002359 break;
2360 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002361 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2362 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002363 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002364 }
2365#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002366 return 1;
2367}
2368
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002369static int
2370trace_syscall_exiting(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002371{
2372 int sys_res;
2373 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002374 int res, scno_good;
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002375 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002376
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002377 /* Measure the exit time as early as possible to avoid errors. */
2378 if (dtime || cflag)
2379 gettimeofday(&tv, NULL);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002380
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002381 /* BTW, why we don't just memorize syscall no. on entry
2382 * in tcp->something?
2383 */
2384 scno_good = res = get_scno(tcp);
2385 if (res == 0)
2386 return res;
2387 if (res == 1)
2388 res = syscall_fixup(tcp);
2389 if (res == 0)
2390 return res;
2391 if (res == 1)
2392 res = get_error(tcp);
2393 if (res == 0)
2394 return res;
2395 if (res == 1)
2396 internal_syscall(tcp);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002397
Grant Edwards8a082772011-04-07 20:25:40 +00002398 if (res == 1 && filtered(tcp)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002399 tcp->flags &= ~TCB_INSYSCALL;
2400 return 0;
2401 }
2402
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002403 if (tcp->flags & TCB_REPRINT) {
2404 printleader(tcp);
2405 tprintf("<... ");
2406 if (scno_good != 1)
2407 tprintf("????");
2408 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2409 tprintf("syscall_%lu", tcp->scno);
2410 else
2411 tprintf("%s", sysent[tcp->scno].sys_name);
2412 tprintf(" resumed> ");
2413 }
2414
2415 if (cflag) {
2416 struct timeval t = tv;
2417 int rc = count_syscall(tcp, &t);
Denys Vlasenko7b609d52011-06-22 14:32:43 +02002418 if (cflag == CFLAG_ONLY_STATS) {
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002419 tcp->flags &= ~TCB_INSYSCALL;
2420 return rc;
2421 }
2422 }
2423
2424 if (res != 1) {
2425 tprintf(") ");
2426 tabto(acolumn);
2427 tprintf("= ? <unavailable>");
2428 printtrailer();
2429 tcp->flags &= ~TCB_INSYSCALL;
2430 return res;
2431 }
2432
2433 if (tcp->scno >= nsyscalls || tcp->scno < 0
2434 || (qual_flags[tcp->scno] & QUAL_RAW))
2435 sys_res = printargs(tcp);
2436 else {
2437 if (not_failing_only && tcp->u_error)
2438 return 0; /* ignore failed syscalls */
2439 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2440 }
2441
2442 u_error = tcp->u_error;
2443 tprintf(") ");
2444 tabto(acolumn);
2445 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2446 qual_flags[tcp->scno] & QUAL_RAW) {
2447 if (u_error)
2448 tprintf("= -1 (errno %ld)", u_error);
2449 else
2450 tprintf("= %#lx", tcp->u_rval);
2451 }
2452 else if (!(sys_res & RVAL_NONE) && u_error) {
2453 switch (u_error) {
2454#ifdef LINUX
2455 case ERESTARTSYS:
2456 tprintf("= ? ERESTARTSYS (To be restarted)");
2457 break;
2458 case ERESTARTNOINTR:
2459 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2460 break;
2461 case ERESTARTNOHAND:
2462 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2463 break;
2464 case ERESTART_RESTARTBLOCK:
2465 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2466 break;
2467#endif /* LINUX */
2468 default:
2469 tprintf("= -1 ");
2470 if (u_error < 0)
2471 tprintf("E??? (errno %ld)", u_error);
2472 else if (u_error < nerrnos)
2473 tprintf("%s (%s)", errnoent[u_error],
2474 strerror(u_error));
2475 else
2476 tprintf("ERRNO_%ld (%s)", u_error,
2477 strerror(u_error));
2478 break;
2479 }
2480 if ((sys_res & RVAL_STR) && tcp->auxstr)
2481 tprintf(" (%s)", tcp->auxstr);
2482 }
2483 else {
2484 if (sys_res & RVAL_NONE)
2485 tprintf("= ?");
2486 else {
2487 switch (sys_res & RVAL_MASK) {
2488 case RVAL_HEX:
2489 tprintf("= %#lx", tcp->u_rval);
2490 break;
2491 case RVAL_OCTAL:
2492 tprintf("= %#lo", tcp->u_rval);
2493 break;
2494 case RVAL_UDECIMAL:
2495 tprintf("= %lu", tcp->u_rval);
2496 break;
2497 case RVAL_DECIMAL:
2498 tprintf("= %ld", tcp->u_rval);
2499 break;
2500#ifdef HAVE_LONG_LONG
2501 case RVAL_LHEX:
2502 tprintf("= %#llx", tcp->u_lrval);
2503 break;
2504 case RVAL_LOCTAL:
2505 tprintf("= %#llo", tcp->u_lrval);
2506 break;
2507 case RVAL_LUDECIMAL:
2508 tprintf("= %llu", tcp->u_lrval);
2509 break;
2510 case RVAL_LDECIMAL:
2511 tprintf("= %lld", tcp->u_lrval);
2512 break;
2513#endif
2514 default:
2515 fprintf(stderr,
2516 "invalid rval format\n");
2517 break;
2518 }
2519 }
2520 if ((sys_res & RVAL_STR) && tcp->auxstr)
2521 tprintf(" (%s)", tcp->auxstr);
2522 }
2523 if (dtime) {
2524 tv_sub(&tv, &tv, &tcp->etime);
2525 tprintf(" <%ld.%06ld>",
2526 (long) tv.tv_sec, (long) tv.tv_usec);
2527 }
2528 printtrailer();
2529
2530 dumpio(tcp);
2531 if (fflush(tcp->outf) == EOF)
2532 return -1;
2533 tcp->flags &= ~TCB_INSYSCALL;
2534 return 0;
2535}
2536
2537static int
2538trace_syscall_entering(struct tcb *tcp)
2539{
2540 int sys_res;
2541 int res, scno_good;
2542
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002543 scno_good = res = get_scno(tcp);
2544 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002545 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002546 if (res == 1)
2547 res = syscall_fixup(tcp);
2548 if (res == 0)
2549 return res;
2550 if (res == 1)
2551 res = syscall_enter(tcp);
2552 if (res == 0)
2553 return res;
2554
2555 if (res != 1) {
2556 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002557 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002558 tcp_last = tcp;
2559 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002560 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002561 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2562 tprintf("syscall_%lu(", tcp->scno);
2563 else
2564 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002565 /*
2566 * " <unavailable>" will be added later by the code which
2567 * detects ptrace errors.
2568 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002569 tcp->flags |= TCB_INSYSCALL;
2570 return res;
2571 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002572
Roland McGrath17352792005-06-07 23:21:26 +00002573 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002574#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002575 case SYS_socketcall:
2576 decode_subcall(tcp, SYS_socket_subcall,
2577 SYS_socket_nsubcalls, deref_style);
2578 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002579#endif
2580#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002581 case SYS_ipc:
2582 decode_subcall(tcp, SYS_ipc_subcall,
2583 SYS_ipc_nsubcalls, shift_style);
2584 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002585#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002586#ifdef SVR4
2587#ifdef SYS_pgrpsys_subcall
2588 case SYS_pgrpsys:
2589 decode_subcall(tcp, SYS_pgrpsys_subcall,
2590 SYS_pgrpsys_nsubcalls, shift_style);
2591 break;
2592#endif /* SYS_pgrpsys_subcall */
2593#ifdef SYS_sigcall_subcall
2594 case SYS_sigcall:
2595 decode_subcall(tcp, SYS_sigcall_subcall,
2596 SYS_sigcall_nsubcalls, mask_style);
2597 break;
2598#endif /* SYS_sigcall_subcall */
2599 case SYS_msgsys:
2600 decode_subcall(tcp, SYS_msgsys_subcall,
2601 SYS_msgsys_nsubcalls, shift_style);
2602 break;
2603 case SYS_shmsys:
2604 decode_subcall(tcp, SYS_shmsys_subcall,
2605 SYS_shmsys_nsubcalls, shift_style);
2606 break;
2607 case SYS_semsys:
2608 decode_subcall(tcp, SYS_semsys_subcall,
2609 SYS_semsys_nsubcalls, shift_style);
2610 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002611 case SYS_sysfs:
2612 decode_subcall(tcp, SYS_sysfs_subcall,
2613 SYS_sysfs_nsubcalls, shift_style);
2614 break;
2615 case SYS_spcall:
2616 decode_subcall(tcp, SYS_spcall_subcall,
2617 SYS_spcall_nsubcalls, shift_style);
2618 break;
2619#ifdef SYS_context_subcall
2620 case SYS_context:
2621 decode_subcall(tcp, SYS_context_subcall,
2622 SYS_context_nsubcalls, shift_style);
2623 break;
2624#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002625#ifdef SYS_door_subcall
2626 case SYS_door:
2627 decode_subcall(tcp, SYS_door_subcall,
2628 SYS_door_nsubcalls, door_style);
2629 break;
2630#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002631#ifdef SYS_kaio_subcall
2632 case SYS_kaio:
2633 decode_subcall(tcp, SYS_kaio_subcall,
2634 SYS_kaio_nsubcalls, shift_style);
2635 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002636#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002637#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002638#ifdef FREEBSD
2639 case SYS_msgsys:
2640 case SYS_shmsys:
2641 case SYS_semsys:
2642 decode_subcall(tcp, 0, 0, table_style);
2643 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002644#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002645#ifdef SUNOS4
2646 case SYS_semsys:
2647 decode_subcall(tcp, SYS_semsys_subcall,
2648 SYS_semsys_nsubcalls, shift_style);
2649 break;
2650 case SYS_msgsys:
2651 decode_subcall(tcp, SYS_msgsys_subcall,
2652 SYS_msgsys_nsubcalls, shift_style);
2653 break;
2654 case SYS_shmsys:
2655 decode_subcall(tcp, SYS_shmsys_subcall,
2656 SYS_shmsys_nsubcalls, shift_style);
2657 break;
2658#endif
2659 }
2660
2661 internal_syscall(tcp);
Grant Edwards8a082772011-04-07 20:25:40 +00002662
2663 if ((tcp->scno >= 0 && tcp->scno < nsyscalls &&
2664 !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
2665 (tracing_paths && !pathtrace_match(tcp))) {
2666 tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002667 return 0;
2668 }
2669
Grant Edwards8a082772011-04-07 20:25:40 +00002670 tcp->flags &= ~TCB_FILTERED;
2671
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002672 if (cflag == CFLAG_ONLY_STATS) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002673 tcp->flags |= TCB_INSYSCALL;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002674 gettimeofday(&tcp->etime, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002675 return 0;
2676 }
2677
2678 printleader(tcp);
2679 tcp->flags &= ~TCB_REPRINT;
2680 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002681 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002682 tprintf("syscall_%lu(", tcp->scno);
2683 else
2684 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002685 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Dmitry V. Levin9fdbee62011-02-19 00:02:27 +00002686 ((qual_flags[tcp->scno] & QUAL_RAW) &&
2687 sysent[tcp->scno].sys_func != sys_exit))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002688 sys_res = printargs(tcp);
2689 else
2690 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2691 if (fflush(tcp->outf) == EOF)
2692 return -1;
2693 tcp->flags |= TCB_INSYSCALL;
2694 /* Measure the entrance time as late as possible to avoid errors. */
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002695 if (dtime || cflag)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002696 gettimeofday(&tcp->etime, NULL);
2697 return sys_res;
2698}
2699
2700int
Dmitry V. Levin7d7c9632010-03-29 17:51:02 +00002701trace_syscall(struct tcb *tcp)
2702{
2703 return exiting(tcp) ?
2704 trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
2705}
2706
2707int
Denys Vlasenko12014262011-05-30 14:00:14 +02002708printargs(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002709{
2710 if (entering(tcp)) {
2711 int i;
2712
2713 for (i = 0; i < tcp->u_nargs; i++)
2714 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2715 }
2716 return 0;
2717}
2718
2719long
Denys Vlasenko12014262011-05-30 14:00:14 +02002720getrval2(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002721{
2722 long val = -1;
2723
2724#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002725#if defined (SPARC) || defined (SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04002726 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002727 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002728 return -1;
Mike Frysinger8566c502009-10-12 11:05:14 -04002729 val = regs.u_regs[U_REG_O1];
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002730#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002731 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002732 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002733#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002734 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002735 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002736#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002737#endif /* LINUX */
2738
2739#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002740 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741 return -1;
2742#endif /* SUNOS4 */
2743
2744#ifdef SVR4
2745#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002746 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002747#endif /* SPARC */
2748#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002749 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002750#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002751#ifdef X86_64
2752 val = tcp->status.PR_REG[RDX];
2753#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002754#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002755 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002756#endif /* MIPS */
2757#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002758
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002759#ifdef FREEBSD
2760 struct reg regs;
2761 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2762 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002763#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002764 return val;
2765}
2766
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002767#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002768/*
2769 * Apparently, indirect system calls have already be converted by ptrace(2),
2770 * so if you see "indir" this program has gone astray.
2771 */
2772int
Denys Vlasenko12014262011-05-30 14:00:14 +02002773sys_indir(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002774{
2775 int i, scno, nargs;
2776
2777 if (entering(tcp)) {
2778 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2779 fprintf(stderr, "Bogus syscall: %u\n", scno);
2780 return 0;
2781 }
2782 nargs = sysent[scno].nargs;
2783 tprintf("%s", sysent[scno].sys_name);
2784 for (i = 0; i < nargs; i++)
2785 tprintf(", %#lx", tcp->u_arg[i+1]);
2786 }
2787 return 0;
2788}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002789#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002790
2791int
2792is_restart_error(struct tcb *tcp)
2793{
2794#ifdef LINUX
2795 if (!syserror(tcp))
2796 return 0;
2797 switch (tcp->u_error) {
2798 case ERESTARTSYS:
2799 case ERESTARTNOINTR:
2800 case ERESTARTNOHAND:
2801 case ERESTART_RESTARTBLOCK:
2802 return 1;
2803 default:
2804 break;
2805 }
2806#endif /* LINUX */
2807 return 0;
2808}