blob: 40fd985922dbe5f227bab66b46eccbe6e1a22787 [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#if HAVE_ASM_REG_H
Roland McGrath6d1a65c2004-07-12 07:44:08 +000046#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000047# define fpq kernel_fpq
48# define fq kernel_fq
49# define fpu kernel_fpu
50#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000051#include <asm/reg.h>
Roland McGrath6d1a65c2004-07-12 07:44:08 +000052#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000053# undef fpq
54# undef fq
Roland McGrath761b5d72002-12-15 23:58:31 +000055# undef fpu
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000056#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000057#endif
58
Wichert Akkerman15dea971999-10-06 13:06:34 +000059#ifdef HAVE_SYS_REG_H
60#include <sys/reg.h>
61#ifndef PTRACE_PEEKUSR
62# define PTRACE_PEEKUSR PTRACE_PEEKUSER
63#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000075#endif
76
Roland McGrath6d1a65c2004-07-12 07:44:08 +000077#if defined (LINUX) && defined (SPARC64)
78# define r_pc r_tpc
79# undef PTRACE_GETREGS
80# define PTRACE_GETREGS PTRACE_GETREGS64
81# undef PTRACE_SETREGS
82# define PTRACE_SETREGS PTRACE_SETREGS64
83#endif /* LINUX && SPARC64 */
84
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000085#if defined(LINUX) && defined(IA64)
86# include <asm/ptrace_offsets.h>
87# include <asm/rse.h>
88#endif
89
Pavel Machekd8ae7e32000-02-01 17:17:25 +000090#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifdef LINUX
92#ifndef ERESTARTSYS
93#define ERESTARTSYS 512
94#endif
95#ifndef ERESTARTNOINTR
96#define ERESTARTNOINTR 513
97#endif
98#ifndef ERESTARTNOHAND
99#define ERESTARTNOHAND 514 /* restart if no handler.. */
100#endif
101#ifndef ENOIOCTLCMD
102#define ENOIOCTLCMD 515 /* No ioctl command */
103#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000104#ifndef ERESTART_RESTARTBLOCK
105#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
106#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#ifndef NSIG
108#define NSIG 32
109#endif
110#ifdef ARM
111#undef NSIG
112#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000113#undef NR_SYSCALL_BASE
114#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#endif
116#endif /* LINUX */
117
118#include "syscall.h"
119
120/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000121#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#define TF TRACE_FILE
123#define TI TRACE_IPC
124#define TN TRACE_NETWORK
125#define TP TRACE_PROCESS
126#define TS TRACE_SIGNAL
127
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000132int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133
134#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000135static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000136#include "syscallent1.h"
137};
Roland McGrathee36ce12004-09-04 03:53:10 +0000138static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000139int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140#endif /* SUPPORTED_PERSONALITIES >= 2 */
141
142#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000143static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#include "syscallent2.h"
145};
Roland McGrathee36ce12004-09-04 03:53:10 +0000146static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000147int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148#endif /* SUPPORTED_PERSONALITIES >= 3 */
149
Roland McGrathee36ce12004-09-04 03:53:10 +0000150const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000151int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152int nsyscalls;
153
154/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000155#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156#undef TF
157#undef TI
158#undef TN
159#undef TP
160#undef TS
161
Roland McGrathee36ce12004-09-04 03:53:10 +0000162static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163#include "errnoent.h"
164};
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166
167#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000168static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169#include "errnoent1.h"
170};
Roland McGrathee36ce12004-09-04 03:53:10 +0000171static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000172#endif /* SUPPORTED_PERSONALITIES >= 2 */
173
174#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000175static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176#include "errnoent2.h"
177};
Roland McGrathee36ce12004-09-04 03:53:10 +0000178static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000179#endif /* SUPPORTED_PERSONALITIES >= 3 */
180
Roland McGrathee36ce12004-09-04 03:53:10 +0000181const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182int nerrnos;
183
184int current_personality;
185
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000186#ifndef PERSONALITY0_WORDSIZE
187# define PERSONALITY0_WORDSIZE sizeof(long)
188#endif
189const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
190 PERSONALITY0_WORDSIZE,
191#if SUPPORTED_PERSONALITIES > 1
192 PERSONALITY1_WORDSIZE,
193#endif
194#if SUPPORTED_PERSONALITIES > 2
195 PERSONALITY2_WORDSIZE,
196#endif
197};;
198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000200set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201{
202 switch (personality) {
203 case 0:
204 errnoent = errnoent0;
205 nerrnos = nerrnos0;
206 sysent = sysent0;
207 nsyscalls = nsyscalls0;
208 ioctlent = ioctlent0;
209 nioctlents = nioctlents0;
210 signalent = signalent0;
211 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000212 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000213 break;
214
215#if SUPPORTED_PERSONALITIES >= 2
216 case 1:
217 errnoent = errnoent1;
218 nerrnos = nerrnos1;
219 sysent = sysent1;
220 nsyscalls = nsyscalls1;
221 ioctlent = ioctlent1;
222 nioctlents = nioctlents1;
223 signalent = signalent1;
224 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000225 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000226 break;
227#endif /* SUPPORTED_PERSONALITIES >= 2 */
228
229#if SUPPORTED_PERSONALITIES >= 3
230 case 2:
231 errnoent = errnoent2;
232 nerrnos = nerrnos2;
233 sysent = sysent2;
234 nsyscalls = nsyscalls2;
235 ioctlent = ioctlent2;
236 nioctlents = nioctlents2;
237 signalent = signalent2;
238 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000239 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 break;
241#endif /* SUPPORTED_PERSONALITIES >= 3 */
242
243 default:
244 return -1;
245 }
246
247 current_personality = personality;
248 return 0;
249}
250
Roland McGrathe10e62a2004-09-04 04:20:43 +0000251
Roland McGrath9797ceb2002-12-30 10:23:00 +0000252static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253
Roland McGrathe10e62a2004-09-04 04:20:43 +0000254static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 int bitflag;
256 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000257 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000258 char *argument_name;
259} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000260 { QUAL_TRACE, "trace", qual_syscall, "system call" },
261 { QUAL_TRACE, "t", qual_syscall, "system call" },
262 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
263 { QUAL_ABBREV, "a", qual_syscall, "system call" },
264 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
265 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
266 { QUAL_RAW, "raw", qual_syscall, "system call" },
267 { QUAL_RAW, "x", qual_syscall, "system call" },
268 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
269 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
270 { QUAL_SIGNAL, "s", qual_signal, "signal" },
271 { QUAL_FAULT, "fault", qual_fault, "fault" },
272 { QUAL_FAULT, "faults", qual_fault, "fault" },
273 { QUAL_FAULT, "m", qual_fault, "fault" },
274 { QUAL_READ, "read", qual_desc, "descriptor" },
275 { QUAL_READ, "reads", qual_desc, "descriptor" },
276 { QUAL_READ, "r", qual_desc, "descriptor" },
277 { QUAL_WRITE, "write", qual_desc, "descriptor" },
278 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
279 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 { 0, NULL, NULL, NULL },
281};
282
Roland McGrath9797ceb2002-12-30 10:23:00 +0000283static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000284qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000285 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000286 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000287 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000288 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000289{
Roland McGrath138c6a32006-01-12 09:50:49 +0000290 if (pers == 0 || pers < 0) {
291 if (not)
292 qual_flags0[n] &= ~opt->bitflag;
293 else
294 qual_flags0[n] |= opt->bitflag;
295 }
296
297#if SUPPORTED_PERSONALITIES >= 2
298 if (pers == 1 || pers < 0) {
299 if (not)
300 qual_flags1[n] &= ~opt->bitflag;
301 else
302 qual_flags1[n] |= opt->bitflag;
303 }
304#endif /* SUPPORTED_PERSONALITIES >= 2 */
305
306#if SUPPORTED_PERSONALITIES >= 3
307 if (pers == 2 || pers < 0) {
308 if (not)
309 qual_flags2[n] &= ~opt->bitflag;
310 else
311 qual_flags2[n] |= opt->bitflag;
312 }
313#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000314}
315
316static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000317qual_syscall(s, opt, not)
318 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000319 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000320 int not;
321{
322 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000323 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000324
Roland McGrath48a035f2006-01-12 09:45:56 +0000325 if (isdigit((unsigned char)*s)) {
326 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000327 if (i < 0 || i >= MAX_QUALS)
Roland McGrath48a035f2006-01-12 09:45:56 +0000328 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000329 qualify_one(i, opt, not, -1);
Roland McGrath48a035f2006-01-12 09:45:56 +0000330 return 0;
331 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000332 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 if (strcmp(s, sysent0[i].sys_name) == 0) {
334 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000335 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000336 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000337
338#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000339 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000340 if (strcmp(s, sysent1[i].sys_name) == 0) {
341 qualify_one(i, opt, not, 1);
342 rc = 0;
343 }
344#endif /* SUPPORTED_PERSONALITIES >= 2 */
345
346#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000347 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000348 if (strcmp(s, sysent2[i].sys_name) == 0) {
349 qualify_one(i, opt, not, 2);
350 rc = 0;
351 }
352#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000353
Roland McGrathfe6b3522005-02-02 04:40:11 +0000354 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000355}
356
357static int
358qual_signal(s, opt, not)
359 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000360 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000361 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000362{
363 int i;
364 char buf[32];
365
Roland McGrath48a035f2006-01-12 09:45:56 +0000366 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000367 int signo = atoi(s);
368 if (signo < 0 || signo >= MAX_QUALS)
369 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000370 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000371 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000373 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000374 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375 strcpy(buf, s);
376 s = buf;
377 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000378 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379 if (strncmp(s, "SIG", 3) == 0)
380 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000381 for (i = 0; i <= NSIG; i++)
382 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000383 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000384 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000385 }
Roland McGrath76421df2005-02-02 03:51:18 +0000386 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387}
388
389static int
390qual_fault(s, opt, not)
391 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000392 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000393 int not;
394{
395 return -1;
396}
397
398static int
399qual_desc(s, opt, not)
400 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000401 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000402 int not;
403{
Roland McGrath48a035f2006-01-12 09:45:56 +0000404 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000405 int desc = atoi(s);
406 if (desc < 0 || desc >= MAX_QUALS)
407 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000408 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000409 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 }
411 return -1;
412}
413
414static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000416 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417{
418 if (strcmp(s, "file") == 0)
419 return TRACE_FILE;
420 if (strcmp(s, "ipc") == 0)
421 return TRACE_IPC;
422 if (strcmp(s, "network") == 0)
423 return TRACE_NETWORK;
424 if (strcmp(s, "process") == 0)
425 return TRACE_PROCESS;
426 if (strcmp(s, "signal") == 0)
427 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000428 if (strcmp(s, "desc") == 0)
429 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430 return -1;
431}
432
433void
434qualify(s)
435char *s;
436{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000437 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 int not;
439 char *p;
440 int i, n;
441
442 opt = &qual_options[0];
443 for (i = 0; (p = qual_options[i].option_name); i++) {
444 n = strlen(p);
445 if (strncmp(s, p, n) == 0 && s[n] == '=') {
446 opt = &qual_options[i];
447 s += n + 1;
448 break;
449 }
450 }
451 not = 0;
452 if (*s == '!') {
453 not = 1;
454 s++;
455 }
456 if (strcmp(s, "none") == 0) {
457 not = 1 - not;
458 s = "all";
459 }
460 if (strcmp(s, "all") == 0) {
461 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000462 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 }
464 return;
465 }
466 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000467 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000468 }
469 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
470 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000471 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000472 if (sysent0[i].sys_flags & n)
473 qualify_one(i, opt, not, 0);
474
475#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000476 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000477 if (sysent1[i].sys_flags & n)
478 qualify_one(i, opt, not, 1);
479#endif /* SUPPORTED_PERSONALITIES >= 2 */
480
481#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000482 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000483 if (sysent2[i].sys_flags & n)
484 qualify_one(i, opt, not, 2);
485#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000486
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487 continue;
488 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000489 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 fprintf(stderr, "strace: invalid %s `%s'\n",
491 opt->argument_name, p);
492 exit(1);
493 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000494 }
495 return;
496}
497
498static void
499dumpio(tcp)
500struct tcb *tcp;
501{
502 if (syserror(tcp))
503 return;
504 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
505 return;
Roland McGrath17352792005-06-07 23:21:26 +0000506 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000508#ifdef SYS_pread64
509 case SYS_pread64:
510#endif
511#if defined SYS_pread && SYS_pread64 != SYS_pread
512 case SYS_pread:
513#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514#ifdef SYS_recv
515 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000516#elif defined SYS_sub_recv
517 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000518#endif
519#ifdef SYS_recvfrom
520 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000521#elif defined SYS_sub_recvfrom
522 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523#endif
524 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
525 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
526 break;
527 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000528#ifdef SYS_pwrite64
529 case SYS_pwrite64:
530#endif
531#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
532 case SYS_pwrite:
533#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534#ifdef SYS_send
535 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000536#elif defined SYS_sub_send
537 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538#endif
539#ifdef SYS_sendto
540 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000541#elif defined SYS_sub_sendto
542 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543#endif
544 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
545 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
546 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000547#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000548 case SYS_readv:
549 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
550 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
551 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000552#endif
553#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000554 case SYS_writev:
555 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
556 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
557 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000558#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000559 }
560}
561
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000562#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000563enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000564#else /* FREEBSD */
565enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
566
567struct subcall {
568 int call;
569 int nsubcalls;
570 int subcalls[5];
571};
572
Roland McGratha4d48532005-06-08 20:45:28 +0000573static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000574 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000575#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000576 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000577#else
578 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
579#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000580 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
581};
582#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000584#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585
Roland McGratha4d48532005-06-08 20:45:28 +0000586static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000587decode_subcall(tcp, subcall, nsubcalls, style)
588struct tcb *tcp;
589int subcall;
590int nsubcalls;
591enum subcall_style style;
592{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000593 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000594 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000595 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000596
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597 switch (style) {
598 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000599 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
600 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000601 tcp->scno = subcall + tcp->u_arg[0];
602 if (sysent[tcp->scno].nargs != -1)
603 tcp->u_nargs = sysent[tcp->scno].nargs;
604 else
605 tcp->u_nargs--;
606 for (i = 0; i < tcp->u_nargs; i++)
607 tcp->u_arg[i] = tcp->u_arg[i + 1];
608 break;
609 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000610 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
611 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 tcp->scno = subcall + tcp->u_arg[0];
613 addr = tcp->u_arg[1];
614 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000615 if (size == sizeof(int)) {
616 unsigned int arg;
617 if (umove(tcp, addr, &arg) < 0)
618 arg = 0;
619 tcp->u_arg[i] = arg;
620 }
621 else if (size == sizeof(long)) {
622 unsigned long arg;
623 if (umove(tcp, addr, &arg) < 0)
624 arg = 0;
625 tcp->u_arg[i] = arg;
626 }
627 else
628 abort();
629 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 }
631 tcp->u_nargs = sysent[tcp->scno].nargs;
632 break;
633 case mask_style:
634 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000635 for (i = 0; mask; i++)
636 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000637 if (i >= nsubcalls)
638 return;
639 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640 tcp->scno = subcall + i;
641 if (sysent[tcp->scno].nargs != -1)
642 tcp->u_nargs = sysent[tcp->scno].nargs;
643 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000644 case door_style:
645 /*
646 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000647 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000648 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000649 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
650 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000651 tcp->scno = subcall + tcp->u_arg[5];
652 if (sysent[tcp->scno].nargs != -1)
653 tcp->u_nargs = sysent[tcp->scno].nargs;
654 else
655 tcp->u_nargs--;
656 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000657#ifdef FREEBSD
658 case table_style:
659 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
660 if (subcalls_table[i].call == tcp->scno) break;
661 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
662 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
663 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
664 for (i = 0; i < tcp->u_nargs; i++)
665 tcp->u_arg[i] = tcp->u_arg[i + 1];
666 }
667 break;
668#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000669 }
670}
671#endif
672
673struct tcb *tcp_last = NULL;
674
675static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000676internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000677{
678 /*
679 * We must always trace a few critical system calls in order to
680 * correctly support following forks in the presence of tracing
681 * qualifiers.
682 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000685 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
686 return 0;
687
688 func = sysent[tcp->scno].sys_func;
689
690 if (sys_exit == func)
691 return internal_exit(tcp);
692
693 if ( sys_fork == func
694#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
695 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000696#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000697#if UNIXWARE > 2
698 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000699#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000700 )
701 return internal_fork(tcp);
702
703#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
704 if (sys_clone == func)
705 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000706#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000707
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000708 if ( sys_execve == func
709#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
710 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000712#if UNIXWARE > 2
713 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000714#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000715 )
716 return internal_exec(tcp);
717
718 if ( sys_waitpid == func
719 || sys_wait4 == func
720#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
721 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000722#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000723#ifdef ALPHA
724 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000725#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000726 )
727 return internal_wait(tcp, 2);
728
729#if defined(LINUX) || defined(SVR4)
730 if (sys_waitid == func)
731 return internal_wait(tcp, 3);
732#endif
733
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000734 return 0;
735}
736
Wichert Akkermanc7926982000-04-10 22:22:31 +0000737
738#ifdef LINUX
739#if defined (I386)
740 static long eax;
741#elif defined (IA64)
742 long r8, r10, psr;
743 long ia32 = 0;
744#elif defined (POWERPC)
745 static long result,flags;
746#elif defined (M68K)
747 static int d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000748#elif defined(BFIN)
749 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000750#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000751 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000752#elif defined (ALPHA)
753 static long r0;
754 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000755#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000756 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000757 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000758#elif defined(LINUX_MIPSN32)
759 static long long a3;
760 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000761#elif defined(MIPS)
762 static long a3;
763 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000764#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000765 static long gpr2;
766 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000767 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000768#elif defined(HPPA)
769 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000770#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000771 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000772#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000773 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000774#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000775 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000776#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000777#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000778#ifdef FREEBSD
779 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000780#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000781
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000783get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000784struct tcb *tcp;
785{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000787#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000788 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000789#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000792#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000793 if (tcp->flags & TCB_WAITEXECVE) {
794 /*
795 * When the execve system call completes successfully, the
796 * new process still has -ENOSYS (old style) or __NR_execve
797 * (new style) in gpr2. We cannot recover the scno again
798 * by disassembly, because the image that executed the
799 * syscall is gone now. Fortunately, we don't want it. We
800 * leave the flag set so that syscall_fixup can fake the
801 * result.
802 */
803 if (tcp->flags & TCB_INSYSCALL)
804 return 1;
805 /*
806 * This is the SIGTRAP after execve. We cannot try to read
807 * the system call here either.
808 */
809 tcp->flags &= ~TCB_WAITEXECVE;
810 return 0;
811 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000812
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000813 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000814 return -1;
815
816 if (syscall_mode != -ENOSYS) {
817 /*
818 * Since kernel version 2.5.44 the scno gets passed in gpr2.
819 */
820 scno = syscall_mode;
821 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000822 /*
823 * Old style of "passing" the scno via the SVC instruction.
824 */
825
826 long opcode, offset_reg, tmp;
827 void * svc_addr;
828 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
829 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
830 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
831 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000832
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000833 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000834 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000835 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000836 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000837 if (errno) {
838 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000839 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000840 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000841
842 /*
843 * We have to check if the SVC got executed directly or via an
844 * EXECUTE instruction. In case of EXECUTE it is necessary to do
845 * instruction decoding to derive the system call number.
846 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
847 * so that this doesn't work if a SVC opcode is part of an EXECUTE
848 * opcode. Since there is no way to find out the opcode size this
849 * is the best we can do...
850 */
851
852 if ((opcode & 0xff00) == 0x0a00) {
853 /* SVC opcode */
854 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000855 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000856 else {
857 /* SVC got executed by EXECUTE instruction */
858
859 /*
860 * Do instruction decoding of EXECUTE. If you really want to
861 * understand this, read the Principles of Operations.
862 */
863 svc_addr = (void *) (opcode & 0xfff);
864
865 tmp = 0;
866 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000867 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000868 return -1;
869 svc_addr += tmp;
870
871 tmp = 0;
872 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000873 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000874 return -1;
875 svc_addr += tmp;
876
877 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
878 if (errno)
879 return -1;
880#if defined(S390X)
881 scno >>= 48;
882#else
883 scno >>= 16;
884#endif
885 tmp = 0;
886 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000887 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000888 return -1;
889
890 scno = (scno | tmp) & 0xff;
891 }
892 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000893#elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000894 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000895 return -1;
896 if (!(tcp->flags & TCB_INSYSCALL)) {
897 /* Check if we return from execve. */
898 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
899 tcp->flags &= ~TCB_WAITEXECVE;
900 return 0;
901 }
902 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000903#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000904 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000905 return -1;
906 /* Check if we return from execve. */
907 if (tcp->flags & TCB_WAITEXECVE && tcp->flags & TCB_INSYSCALL)
908 tcp->flags &= ~(TCB_INSYSCALL | TCB_WAITEXECVE);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000909#elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000910 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000911 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000912#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000913 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000914 return -1;
915
Roland McGrath761b5d72002-12-15 23:58:31 +0000916 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko8236f252009-01-02 18:10:08 +0000917 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000918 long val;
919
920 /* Check CS register value. On x86-64 linux it is:
921 * 0x33 for long mode (64 bit)
922 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000923 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000924 * to be cached.
925 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000926 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000927 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000928 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000929 case 0x23: currpers = 1; break;
930 case 0x33: currpers = 0; break;
931 default:
932 fprintf(stderr, "Unknown value CS=0x%02X while "
933 "detecting personality of process "
934 "PID=%d\n", (int)val, pid);
935 currpers = current_personality;
936 break;
937 }
938#if 0
939 /* This version analyzes the opcode of a syscall instruction.
940 * (int 0x80 on i386 vs. syscall on x86-64)
941 * It works, but is too complicated.
942 */
943 unsigned long val, rip, i;
944
Denys Vlasenko8236f252009-01-02 18:10:08 +0000945 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000946 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000947
Michal Ludvig0e035502002-09-23 15:41:01 +0000948 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000949 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000950 errno = 0;
951
Denys Vlasenko8236f252009-01-02 18:10:08 +0000952 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000953 if (errno)
954 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000955 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000956 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000957 /* x86-64: syscall = 0x0f 0x05 */
958 case 0x050f: currpers = 0; break;
959 /* i386: int 0x80 = 0xcd 0x80 */
960 case 0x80cd: currpers = 1; break;
961 default:
962 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000963 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000964 "Unknown syscall opcode (0x%04X) while "
965 "detecting personality of process "
966 "PID=%d\n", (int)call, pid);
967 break;
968 }
969#endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000970 if (currpers != current_personality) {
971 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000972 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000973 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000974 pid, names[current_personality]);
975 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000976 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000977#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000978# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000979 if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000980 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000981 if (!(tcp->flags & TCB_INSYSCALL)) {
982 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000983 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000984 return -1;
985 } else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000986 if (upeek (tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000987 return -1;
988 }
Roland McGrathba954762003-03-05 06:29:06 +0000989 /* Check if we return from execve. */
990 if (tcp->flags & TCB_WAITEXECVE) {
991 tcp->flags &= ~TCB_WAITEXECVE;
992 return 0;
993 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000994 } else {
995 /* syscall in progress */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000996 if (upeek (tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000997 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000998 if (upeek (tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000999 return -1;
1000 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001001#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001002 /*
1003 * Read complete register set in one go.
1004 */
1005 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1006 return -1;
1007
1008 /*
1009 * We only need to grab the syscall number on syscall entry.
1010 */
1011 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001012 if (!(tcp->flags & TCB_INSYSCALL)) {
1013 /* Check if we return from execve. */
1014 if (tcp->flags & TCB_WAITEXECVE) {
1015 tcp->flags &= ~TCB_WAITEXECVE;
1016 return 0;
1017 }
1018 }
1019
Roland McGrath0f87c492003-06-03 23:29:04 +00001020 /*
1021 * Note: we only deal with only 32-bit CPUs here.
1022 */
1023 if (regs.ARM_cpsr & 0x20) {
1024 /*
1025 * Get the Thumb-mode system call number
1026 */
1027 scno = regs.ARM_r7;
1028 } else {
1029 /*
1030 * Get the ARM-mode system call number
1031 */
1032 errno = 0;
1033 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1034 if (errno)
1035 return -1;
1036
1037 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1038 tcp->flags &= ~TCB_WAITEXECVE;
1039 return 0;
1040 }
1041
Roland McGrathf691bd22006-04-25 07:34:41 +00001042 /* Handle the EABI syscall convention. We do not
1043 bother converting structures between the two
1044 ABIs, but basic functionality should work even
1045 if strace and the traced program have different
1046 ABIs. */
1047 if (scno == 0xef000000) {
1048 scno = regs.ARM_r7;
1049 } else {
1050 if ((scno & 0x0ff00000) != 0x0f900000) {
1051 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1052 scno);
1053 return -1;
1054 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001055
Roland McGrathf691bd22006-04-25 07:34:41 +00001056 /*
1057 * Fixup the syscall number
1058 */
1059 scno &= 0x000fffff;
1060 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001061 }
Roland McGrath56703312008-05-20 01:35:55 +00001062 if (scno & 0x0f0000) {
1063 /*
1064 * Handle ARM specific syscall
1065 */
1066 set_personality(1);
1067 scno &= 0x0000ffff;
1068 } else
1069 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001070
1071 if (tcp->flags & TCB_INSYSCALL) {
1072 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1073 tcp->flags &= ~TCB_INSYSCALL;
1074 }
1075 } else {
1076 if (!(tcp->flags & TCB_INSYSCALL)) {
1077 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1078 tcp->flags |= TCB_INSYSCALL;
1079 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080 }
1081#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001082 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 return -1;
Roland McGrath542c2c62008-05-20 01:11:56 +00001084#elif defined (LINUX_MIPSN32)
1085 unsigned long long regs[38];
1086
1087 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
1088 return -1;
1089 a3 = regs[REG_A3];
1090 r2 = regs[REG_V0];
1091
1092 if(!(tcp->flags & TCB_INSYSCALL)) {
1093 scno = r2;
1094
1095 /* Check if we return from execve. */
1096 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1097 tcp->flags &= ~TCB_WAITEXECVE;
1098 return 0;
1099 }
1100
1101 if (scno < 0 || scno > nsyscalls) {
1102 if(a3 == 0 || a3 == -1) {
1103 if(debug)
1104 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1105 return 0;
1106 }
1107 }
1108 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001109#elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001110 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001111 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001112 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001113 if (upeek(tcp, REG_V0, &scno) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001114 return -1;
1115
Roland McGrath542c2c62008-05-20 01:11:56 +00001116 /* Check if we return from execve. */
1117 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1118 tcp->flags &= ~TCB_WAITEXECVE;
1119 return 0;
1120 }
1121
Wichert Akkermanf90da011999-10-31 21:15:38 +00001122 if (scno < 0 || scno > nsyscalls) {
1123 if(a3 == 0 || a3 == -1) {
1124 if(debug)
1125 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1126 return 0;
1127 }
1128 }
1129 } else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001130 if (upeek(tcp, REG_V0, &r2) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001131 return -1;
1132 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001133#elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001134 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 return -1;
1136
1137 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001138 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001139 return -1;
1140
1141 /* Check if we return from execve. */
1142 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1143 tcp->flags &= ~TCB_WAITEXECVE;
1144 return 0;
1145 }
1146
1147 /*
1148 * Do some sanity checks to figure out if it's
1149 * really a syscall entry
1150 */
1151 if (scno < 0 || scno > nsyscalls) {
1152 if (a3 == 0 || a3 == -1) {
1153 if (debug)
1154 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1155 return 0;
1156 }
1157 }
1158 }
1159 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001160 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161 return -1;
1162 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001163#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 /* Everything we need is in the current register set. */
1165 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1166 return -1;
1167
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001168 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169 if (!(tcp->flags & TCB_INSYSCALL)) {
1170 /* Retrieve the syscall trap instruction. */
1171 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001172 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001173#if defined(SPARC64)
1174 trap >>= 32;
1175#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 if (errno)
1177 return -1;
1178
1179 /* Disassemble the trap to see what personality to use. */
1180 switch (trap) {
1181 case 0x91d02010:
1182 /* Linux/SPARC syscall trap. */
1183 set_personality(0);
1184 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001185 case 0x91d0206d:
1186 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001187 set_personality(2);
1188 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189 case 0x91d02000:
1190 /* SunOS syscall trap. (pers 1) */
1191 fprintf(stderr,"syscall: SunOS no support\n");
1192 return -1;
1193 case 0x91d02008:
1194 /* Solaris 2.x syscall trap. (per 2) */
1195 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001196 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197 case 0x91d02009:
1198 /* NetBSD/FreeBSD syscall trap. */
1199 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1200 return -1;
1201 case 0x91d02027:
1202 /* Solaris 2.x gettimeofday */
1203 set_personality(1);
1204 break;
1205 default:
1206 /* Unknown syscall trap. */
1207 if(tcp->flags & TCB_WAITEXECVE) {
1208 tcp->flags &= ~TCB_WAITEXECVE;
1209 return 0;
1210 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001211#if defined (SPARC64)
1212 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1213#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001214 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001215#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216 return -1;
1217 }
1218
1219 /* Extract the system call number from the registers. */
1220 if (trap == 0x91d02027)
1221 scno = 156;
1222 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001223 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001225 scno = regs.r_o0;
1226 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227 }
1228 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001229#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001230 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001231 return -1;
1232 if (!(tcp->flags & TCB_INSYSCALL)) {
1233 /* Check if we return from execve. */
1234 if ((tcp->flags & TCB_WAITEXECVE)) {
1235 tcp->flags &= ~TCB_WAITEXECVE;
1236 return 0;
1237 }
1238 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001239#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001240 /*
1241 * In the new syscall ABI, the system call number is in R3.
1242 */
1243 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1244 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001245
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001246 if (scno < 0) {
1247 /* Odd as it may seem, a glibc bug has been known to cause
1248 glibc to issue bogus negative syscall numbers. So for
1249 our purposes, make strace print what it *should* have been */
1250 long correct_scno = (scno & 0xff);
1251 if (debug)
1252 fprintf(stderr,
1253 "Detected glibc bug: bogus system call"
1254 " number = %ld, correcting to %ld\n",
1255 scno,
1256 correct_scno);
1257 scno = correct_scno;
1258 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001259
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001260 if (!(tcp->flags & TCB_INSYSCALL)) {
1261 /* Check if we return from execve. */
1262 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1263 tcp->flags &= ~TCB_WAITEXECVE;
1264 return 0;
1265 }
1266 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001267#elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001268 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001269 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001270 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001271
1272 if (!(tcp->flags & TCB_INSYSCALL)) {
1273 /* Check if we return from execve. */
1274 if (tcp->flags & TCB_WAITEXECVE) {
1275 tcp->flags &= ~TCB_WAITEXECVE;
1276 return 0;
1277 }
1278 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001279#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001280#endif /* LINUX */
1281#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001282 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001283 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001284#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001285 /* new syscall ABI returns result in R0 */
1286 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1287 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001288#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001289 /* ABI defines result returned in r9 */
1290 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1291 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001292
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001294#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001296 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001297#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001298#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001299 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001300#else /* FREEBSD */
1301 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001302 perror("pread");
1303 return -1;
1304 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001305 switch (regs.r_eax) {
1306 case SYS_syscall:
1307 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001308 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1309 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001310 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001311 scno = regs.r_eax;
1312 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001313 }
1314#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001315#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001316#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001317 if (!(tcp->flags & TCB_INSYSCALL))
1318 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001319 return 1;
1320}
1321
Pavel Machek4dc3b142000-02-01 17:58:41 +00001322
Roland McGrath17352792005-06-07 23:21:26 +00001323long
1324known_scno(tcp)
1325struct tcb *tcp;
1326{
1327 long scno = tcp->scno;
1328 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1329 scno = sysent[scno].native_scno;
1330 else
1331 scno += NR_SYSCALL_BASE;
1332 return scno;
1333}
1334
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001335/* Called in trace_syscall() at each syscall entry and exit.
1336 * Returns:
1337 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1338 * 1: ok, continue in trace_syscall().
1339 * other: error, trace_syscall() should print error indicator
1340 * ("????" etc) and bail out.
1341 */
Roland McGratha4d48532005-06-08 20:45:28 +00001342static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001343syscall_fixup(tcp)
1344struct tcb *tcp;
1345{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001346#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001347 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001348
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001349 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001350 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001351 if (
1352 scno == SYS_fork
1353#ifdef SYS_vfork
1354 || scno == SYS_vfork
1355#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001356#ifdef SYS_fork1
1357 || scno == SYS_fork1
1358#endif /* SYS_fork1 */
1359#ifdef SYS_forkall
1360 || scno == SYS_forkall
1361#endif /* SYS_forkall */
1362#ifdef SYS_rfork1
1363 || scno == SYS_rfork1
1364#endif /* SYS_fork1 */
1365#ifdef SYS_rforkall
1366 || scno == SYS_rforkall
1367#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 ) {
1369 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001370 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001372 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373 }
1374 else {
1375 fprintf(stderr, "syscall: missing entry\n");
1376 tcp->flags |= TCB_INSYSCALL;
1377 }
1378 }
1379 }
1380 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001381 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001382 fprintf(stderr, "syscall: missing exit\n");
1383 tcp->flags &= ~TCB_INSYSCALL;
1384 }
1385 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001386#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001387#ifdef SUNOS4
1388 if (!(tcp->flags & TCB_INSYSCALL)) {
1389 if (scno == 0) {
1390 fprintf(stderr, "syscall: missing entry\n");
1391 tcp->flags |= TCB_INSYSCALL;
1392 }
1393 }
1394 else {
1395 if (scno != 0) {
1396 if (debug) {
1397 /*
1398 * This happens when a signal handler
1399 * for a signal which interrupted a
1400 * a system call makes another system call.
1401 */
1402 fprintf(stderr, "syscall: missing exit\n");
1403 }
1404 tcp->flags &= ~TCB_INSYSCALL;
1405 }
1406 }
1407#endif /* SUNOS4 */
1408#ifdef LINUX
1409#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001410 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001411 return -1;
1412 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1413 if (debug)
1414 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1415 return 0;
1416 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001417#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001418 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001419 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001420 if (current_personality == 1)
1421 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001422 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1423 if (debug)
1424 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1425 return 0;
1426 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001427#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001428 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001429 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001430 if (syscall_mode != -ENOSYS)
1431 syscall_mode = tcp->scno;
1432 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001433 if (debug)
1434 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1435 return 0;
1436 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001437 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1438 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1439 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1440 /*
1441 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1442 * flag set for the post-execve SIGTRAP to see and reset.
1443 */
1444 gpr2 = 0;
1445 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001446#elif defined (POWERPC)
1447# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001448 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001449 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001450 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451 return -1;
1452 if (flags & SO_MASK)
1453 result = -result;
1454#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001455 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001456 return -1;
1457 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1458 if (debug)
1459 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1460 return 0;
1461 }
1462#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001463 /*
1464 * Nothing required
1465 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001466#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001467 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001468 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001469#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001470 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001471 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001472#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001473 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001474 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001475 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001476 return -1;
1477 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1478 if (debug)
1479 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1480 return 0;
1481 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001482#endif
1483#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001484 return 1;
1485}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486
Roland McGrathc1e45922008-05-27 23:18:29 +00001487#ifdef LINUX
1488/*
1489 * Check the syscall return value register value for whether it is
1490 * a negated errno code indicating an error, or a success return value.
1491 */
1492static inline int
1493is_negated_errno(unsigned long int val)
1494{
1495 unsigned long int max = -(long int) nerrnos;
1496 if (personality_wordsize[current_personality] < sizeof(val)) {
1497 val = (unsigned int) val;
1498 max = (unsigned int) max;
1499 }
1500 return val > max;
1501}
1502#endif
1503
Roland McGratha4d48532005-06-08 20:45:28 +00001504static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001505get_error(tcp)
1506struct tcb *tcp;
1507{
1508 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001509#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001510#if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001511 if (is_negated_errno(gpr2)) {
1512 tcp->u_rval = -1;
1513 u_error = -gpr2;
1514 }
1515 else {
1516 tcp->u_rval = gpr2;
1517 u_error = 0;
1518 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001519#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001520#ifdef I386
Roland McGrathc1e45922008-05-27 23:18:29 +00001521 if (is_negated_errno(eax)) {
1522 tcp->u_rval = -1;
1523 u_error = -eax;
1524 }
1525 else {
1526 tcp->u_rval = eax;
1527 u_error = 0;
1528 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001529#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001530#ifdef X86_64
Roland McGrathc1e45922008-05-27 23:18:29 +00001531 if (is_negated_errno(rax)) {
1532 tcp->u_rval = -1;
1533 u_error = -rax;
1534 }
1535 else {
1536 tcp->u_rval = rax;
1537 u_error = 0;
1538 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001539#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001540#ifdef IA64
Roland McGrathc1e45922008-05-27 23:18:29 +00001541 if (ia32) {
1542 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001543
Roland McGrathc1e45922008-05-27 23:18:29 +00001544 err = (int)r8;
1545 if (is_negated_errno(err)) {
1546 tcp->u_rval = -1;
1547 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001548 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001549 else {
1550 tcp->u_rval = err;
1551 u_error = 0;
1552 }
1553 } else {
1554 if (r10) {
1555 tcp->u_rval = -1;
1556 u_error = r8;
1557 } else {
1558 tcp->u_rval = r8;
1559 u_error = 0;
1560 }
1561 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001562#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001563#ifdef MIPS
1564 if (a3) {
1565 tcp->u_rval = -1;
1566 u_error = r2;
1567 } else {
1568 tcp->u_rval = r2;
1569 u_error = 0;
1570 }
1571#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001572#ifdef POWERPC
Roland McGrathc1e45922008-05-27 23:18:29 +00001573 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001574 tcp->u_rval = -1;
1575 u_error = -result;
1576 }
1577 else {
1578 tcp->u_rval = result;
1579 u_error = 0;
1580 }
1581#else /* !POWERPC */
1582#ifdef M68K
Roland McGrathc1e45922008-05-27 23:18:29 +00001583 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001584 tcp->u_rval = -1;
1585 u_error = -d0;
1586 }
1587 else {
1588 tcp->u_rval = d0;
1589 u_error = 0;
1590 }
1591#else /* !M68K */
1592#ifdef ARM
Roland McGrathc1e45922008-05-27 23:18:29 +00001593 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001595 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596 }
1597 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001598 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599 u_error = 0;
1600 }
1601#else /* !ARM */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001602#ifdef BFIN
1603 if (is_negated_errno(r0)) {
1604 tcp->u_rval = -1;
1605 u_error = -r0;
1606 } else {
1607 tcp->u_rval = r0;
1608 u_error = 0;
1609 }
1610#else /* !BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001611#ifdef ALPHA
1612 if (a3) {
1613 tcp->u_rval = -1;
1614 u_error = r0;
1615 }
1616 else {
1617 tcp->u_rval = r0;
1618 u_error = 0;
1619 }
1620#else /* !ALPHA */
1621#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001622 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001624 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625 }
1626 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001627 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 u_error = 0;
1629 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001630#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001631#ifdef SPARC64
1632 if (regs.r_tstate & 0x1100000000UL) {
1633 tcp->u_rval = -1;
1634 u_error = regs.r_o0;
1635 }
1636 else {
1637 tcp->u_rval = regs.r_o0;
1638 u_error = 0;
1639 }
1640#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001641#ifdef HPPA
Roland McGrathc1e45922008-05-27 23:18:29 +00001642 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001643 tcp->u_rval = -1;
1644 u_error = -r28;
1645 }
1646 else {
1647 tcp->u_rval = r28;
1648 u_error = 0;
1649 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001650#else
1651#ifdef SH
Roland McGrathc1e45922008-05-27 23:18:29 +00001652 /* interpret R0 as return value or error number */
1653 if (is_negated_errno(r0)) {
1654 tcp->u_rval = -1;
1655 u_error = -r0;
1656 }
1657 else {
1658 tcp->u_rval = r0;
1659 u_error = 0;
1660 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001661#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001662#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001663 /* interpret result as return value or error number */
1664 if (is_negated_errno(r9)) {
1665 tcp->u_rval = -1;
1666 u_error = -r9;
1667 }
1668 else {
1669 tcp->u_rval = r9;
1670 u_error = 0;
1671 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001672#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001673#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001674#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001676#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677#endif /* ALPHA */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001678#endif /* BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001679#endif /* ARM */
1680#endif /* M68K */
1681#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001682#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001683#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001684#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001686#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687#endif /* LINUX */
1688#ifdef SUNOS4
1689 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001690 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691 return -1;
1692 u_error >>= 24; /* u_error is a char */
1693
1694 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001695 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696 return -1;
1697#endif /* SUNOS4 */
1698#ifdef SVR4
1699#ifdef SPARC
1700 /* Judicious guessing goes a long way. */
1701 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1702 tcp->u_rval = -1;
1703 u_error = tcp->status.pr_reg[R_O0];
1704 }
1705 else {
1706 tcp->u_rval = tcp->status.pr_reg[R_O0];
1707 u_error = 0;
1708 }
1709#endif /* SPARC */
1710#ifdef I386
1711 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001712 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001713 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001714 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715 }
1716 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001717 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001718#ifdef HAVE_LONG_LONG
1719 tcp->u_lrval =
1720 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1721 tcp->status.PR_REG[EAX];
1722#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001723 u_error = 0;
1724 }
1725#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001726#ifdef X86_64
1727 /* Wanna know how to kill an hour single-stepping? */
1728 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1729 tcp->u_rval = -1;
1730 u_error = tcp->status.PR_REG[RAX];
1731 }
1732 else {
1733 tcp->u_rval = tcp->status.PR_REG[RAX];
1734 u_error = 0;
1735 }
1736#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001737#ifdef MIPS
1738 if (tcp->status.pr_reg[CTX_A3]) {
1739 tcp->u_rval = -1;
1740 u_error = tcp->status.pr_reg[CTX_V0];
1741 }
1742 else {
1743 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1744 u_error = 0;
1745 }
1746#endif /* MIPS */
1747#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001748#ifdef FREEBSD
1749 if (regs.r_eflags & PSL_C) {
1750 tcp->u_rval = -1;
1751 u_error = regs.r_eax;
1752 } else {
1753 tcp->u_rval = regs.r_eax;
1754 tcp->u_lrval =
1755 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1756 u_error = 0;
1757 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001758#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001759 tcp->u_error = u_error;
1760 return 1;
1761}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001762
Roland McGrathb69f81b2002-12-21 23:25:18 +00001763int
1764force_result(tcp, error, rval)
1765 struct tcb *tcp;
1766 int error;
1767 long rval;
1768{
1769#ifdef LINUX
1770#if defined(S390) || defined(S390X)
1771 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001772 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1773 return -1;
1774#else /* !S390 && !S390X */
1775#ifdef I386
1776 eax = error ? -error : rval;
1777 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1778 return -1;
1779#else /* !I386 */
1780#ifdef X86_64
1781 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001782 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001783 return -1;
1784#else
1785#ifdef IA64
1786 if (ia32) {
1787 r8 = error ? -error : rval;
1788 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1789 return -1;
1790 }
1791 else {
1792 if (error) {
1793 r8 = error;
1794 r10 = -1;
1795 }
1796 else {
1797 r8 = rval;
1798 r10 = 0;
1799 }
1800 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1801 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1802 return -1;
1803 }
1804#else /* !IA64 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001805#ifdef BFIN
1806 r0 = error ? -error : rval;
1807 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1808 return -1;
1809#else /* !BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001810#ifdef MIPS
1811 if (error) {
1812 r2 = error;
1813 a3 = -1;
1814 }
1815 else {
1816 r2 = rval;
1817 a3 = 0;
1818 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001819 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001820 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1821 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1822 return -1;
1823#else
1824#ifdef POWERPC
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001825 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001826 return -1;
1827 if (error) {
1828 flags |= SO_MASK;
1829 result = error;
1830 }
1831 else {
1832 flags &= ~SO_MASK;
1833 result = rval;
1834 }
Roland McGratheb285352003-01-14 09:59:00 +00001835 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1836 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001837 return -1;
1838#else /* !POWERPC */
1839#ifdef M68K
1840 d0 = error ? -error : rval;
1841 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1842 return -1;
1843#else /* !M68K */
1844#ifdef ARM
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001845 regs.ARM_r0 = error ? -error : rval;
1846 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001847 return -1;
1848#else /* !ARM */
1849#ifdef ALPHA
1850 if (error) {
1851 a3 = -1;
1852 r0 = error;
1853 }
1854 else {
1855 a3 = 0;
1856 r0 = rval;
1857 }
1858 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1859 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1860 return -1;
1861#else /* !ALPHA */
1862#ifdef SPARC
1863 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1864 return -1;
1865 if (error) {
1866 regs.r_psr |= PSR_C;
1867 regs.r_o0 = error;
1868 }
1869 else {
1870 regs.r_psr &= ~PSR_C;
1871 regs.r_o0 = rval;
1872 }
1873 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1874 return -1;
1875#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001876#ifdef SPARC64
1877 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1878 return -1;
1879 if (error) {
1880 regs.r_tstate |= 0x1100000000UL;
1881 regs.r_o0 = error;
1882 }
1883 else {
1884 regs.r_tstate &= ~0x1100000000UL;
1885 regs.r_o0 = rval;
1886 }
1887 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1888 return -1;
1889#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001890#ifdef HPPA
1891 r28 = error ? -error : rval;
1892 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1893 return -1;
1894#else
1895#ifdef SH
1896 r0 = error ? -error : rval;
1897 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1898 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001899#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001900#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001901 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001902 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1903 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001904#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001905#endif /* SH */
1906#endif /* HPPA */
1907#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001908#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001909#endif /* ALPHA */
1910#endif /* ARM */
1911#endif /* M68K */
1912#endif /* POWERPC */
1913#endif /* MIPS */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001914#endif /* BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001915#endif /* IA64 */
1916#endif /* X86_64 */
1917#endif /* I386 */
1918#endif /* S390 || S390X */
1919#endif /* LINUX */
1920#ifdef SUNOS4
1921 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1922 error << 24) < 0 ||
1923 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1924 return -1;
1925#endif /* SUNOS4 */
1926#ifdef SVR4
1927 /* XXX no clue */
1928 return -1;
1929#endif /* SVR4 */
1930#ifdef FREEBSD
1931 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001932 perror("pread");
1933 return -1;
1934 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001935 if (error) {
1936 regs.r_eflags |= PSL_C;
1937 regs.r_eax = error;
1938 }
1939 else {
1940 regs.r_eflags &= ~PSL_C;
1941 regs.r_eax = rval;
1942 }
1943 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001944 perror("pwrite");
1945 return -1;
1946 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001947#endif /* FREEBSD */
1948
1949 /* All branches reach here on success (only). */
1950 tcp->u_error = error;
1951 tcp->u_rval = rval;
1952 return 0;
1953}
1954
Roland McGratha4d48532005-06-08 20:45:28 +00001955static int
1956syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001957struct tcb *tcp;
1958{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001959#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001960#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001961 {
1962 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001963 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1964 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001965 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001966 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001967 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001968 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001969 return -1;
1970 }
1971 }
1972#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001973 {
1974 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001975 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1976 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001977 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001978 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001979 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001980 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1981 * for scno somewhere above here!
1982 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001983 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001984 return -1;
1985 }
1986 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001987#elif defined (IA64)
1988 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001989 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001990 unsigned long *out0, cfm, sof, sol, i;
1991 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001992 /* be backwards compatible with kernel < 2.4.4... */
1993# ifndef PT_RBS_END
1994# define PT_RBS_END PT_AR_BSP
1995# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001996
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001997 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001998 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001999 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002000 return -1;
2001
2002 sof = (cfm >> 0) & 0x7f;
2003 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002004 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002005
2006 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2007 && sysent[tcp->scno].nargs != -1)
2008 tcp->u_nargs = sysent[tcp->scno].nargs;
2009 else
2010 tcp->u_nargs = MAX_ARGS;
2011 for (i = 0; i < tcp->u_nargs; ++i) {
2012 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2013 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2014 return -1;
2015 }
2016 } else {
2017 int i;
2018
2019 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002020 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002021 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002022 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002023 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002024 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002025 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002026 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002027 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002028 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002029 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002030 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002031 return -1;
2032
2033 for (i = 0; i < 6; ++i)
2034 /* truncate away IVE sign-extension */
2035 tcp->u_arg[i] &= 0xffffffff;
2036
2037 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2038 && sysent[tcp->scno].nargs != -1)
2039 tcp->u_nargs = sysent[tcp->scno].nargs;
2040 else
2041 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002042 }
2043 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002044#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2045 /* N32 and N64 both use up to six registers. */
2046 {
2047 unsigned long long regs[38];
2048 int i, nargs;
2049
2050 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2051 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002052 else
Roland McGrath542c2c62008-05-20 01:11:56 +00002053 nargs = tcp->u_nargs = MAX_ARGS;
2054
2055 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
2056 return -1;
2057
2058 for(i = 0; i < nargs; i++) {
2059 tcp->u_arg[i] = regs[REG_A0 + i];
2060# if defined (LINUX_MIPSN32)
2061 tcp->ext_arg[i] = regs[REG_A0 + i];
2062# endif
2063 }
2064 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002065#elif defined (MIPS)
2066 {
2067 long sp;
2068 int i, nargs;
2069
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002070 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2071 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002072 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002073 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002074 if(nargs > 4) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002075 if(upeek(tcp, REG_SP, &sp) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002076 return -1;
2077 for(i = 0; i < 4; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002078 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002079 return -1;
2080 }
2081 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2082 (char *)(tcp->u_arg + 4));
2083 } else {
2084 for(i = 0; i < nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002085 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002086 return -1;
2087 }
2088 }
2089 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002090#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002091#ifndef PT_ORIG_R3
2092#define PT_ORIG_R3 34
2093#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002094 {
2095 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002096 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2097 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002098 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002099 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002100 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002101 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002102 (sizeof(unsigned long)*PT_ORIG_R3) :
2103 ((i+PT_R3)*sizeof(unsigned long)),
2104 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002105 return -1;
2106 }
2107 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002108#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002109 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002110 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002111
2112 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2113 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002114 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002115 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002116 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002117 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002118 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002119#elif defined (HPPA)
2120 {
2121 int i;
2122
2123 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2124 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002125 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002126 tcp->u_nargs = MAX_ARGS;
2127 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002128 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002129 return -1;
2130 }
2131 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002132#elif defined(ARM)
2133 {
2134 int i;
2135
2136 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2137 tcp->u_nargs = sysent[tcp->scno].nargs;
2138 else
2139 tcp->u_nargs = MAX_ARGS;
2140 for (i = 0; i < tcp->u_nargs; i++)
2141 tcp->u_arg[i] = regs.uregs[i];
2142 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002143#elif defined(BFIN)
2144 {
2145 int i;
2146 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2147
2148 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2149 tcp->u_nargs = sysent[tcp->scno].nargs;
2150 else
2151 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2152
2153 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002154 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002155 return -1;
2156 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002157#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002158 {
2159 int i;
2160 static int syscall_regs[] = {
2161 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2162 REG_REG0, REG_REG0+1, REG_REG0+2
2163 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002164
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002165 tcp->u_nargs = sysent[tcp->scno].nargs;
2166 for (i = 0; i < tcp->u_nargs; i++) {
2167 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2168 return -1;
2169 }
2170 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002171#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002172 {
2173 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002174 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002175 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2176
2177 /*
2178 * TODO: should also check that the number of arguments encoded
2179 * in the trap number matches the number strace expects.
2180 */
2181 /*
2182 assert(sysent[tcp->scno].nargs <
2183 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2184 */
2185
2186 tcp->u_nargs = sysent[tcp->scno].nargs;
2187 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002188 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002189 return -1;
2190 }
2191 }
2192
Michal Ludvig0e035502002-09-23 15:41:01 +00002193#elif defined(X86_64)
2194 {
2195 int i;
2196 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2197 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002198 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002199 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002200
Michal Ludvig0e035502002-09-23 15:41:01 +00002201 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2202 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002203 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002204 tcp->u_nargs = MAX_ARGS;
2205 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002206 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002207 return -1;
2208 }
2209 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002210#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002211 {
2212 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002213 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2214 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002215 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002216 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002217 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002218 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002219 return -1;
2220 }
2221 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002222#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002223#endif /* LINUX */
2224#ifdef SUNOS4
2225 {
2226 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002227 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2228 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002229 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002230 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002231 for (i = 0; i < tcp->u_nargs; i++) {
2232 struct user *u;
2233
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002234 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002235 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2236 return -1;
2237 }
2238 }
2239#endif /* SUNOS4 */
2240#ifdef SVR4
2241#ifdef MIPS
2242 /*
2243 * SGI is broken: even though it has pr_sysarg, it doesn't
2244 * set them on system call entry. Get a clue.
2245 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002246 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247 tcp->u_nargs = sysent[tcp->scno].nargs;
2248 else
2249 tcp->u_nargs = tcp->status.pr_nsysarg;
2250 if (tcp->u_nargs > 4) {
2251 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2252 4*sizeof(tcp->u_arg[0]));
2253 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2254 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2255 }
2256 else {
2257 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2258 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2259 }
John Hughes25299712001-03-06 10:10:06 +00002260#elif UNIXWARE >= 2
2261 /*
2262 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2263 */
2264 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2265 tcp->u_nargs = sysent[tcp->scno].nargs;
2266 else
2267 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2268 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2269 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2270#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002271 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002272 tcp->u_nargs = sysent[tcp->scno].nargs;
2273 else
2274 tcp->u_nargs = tcp->status.pr_nsysarg;
2275 {
2276 int i;
2277 for (i = 0; i < tcp->u_nargs; i++)
2278 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2279 }
John Hughes25299712001-03-06 10:10:06 +00002280#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002281 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002282 tcp->u_nargs = sysent[tcp->scno].nargs;
2283 else
2284 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002285 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002286 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002287#else
2288 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002289#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002290#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002291#ifdef FREEBSD
2292 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2293 sysent[tcp->scno].nargs > tcp->status.val)
2294 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002295 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002296 tcp->u_nargs = tcp->status.val;
2297 if (tcp->u_nargs < 0)
2298 tcp->u_nargs = 0;
2299 if (tcp->u_nargs > MAX_ARGS)
2300 tcp->u_nargs = MAX_ARGS;
2301 switch(regs.r_eax) {
2302 case SYS___syscall:
2303 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2304 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002305 break;
2306 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002307 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2308 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002309 break;
2310 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002311 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2312 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002313 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002314 }
2315#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002316 return 1;
2317}
2318
2319int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002320trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002321{
2322 int sys_res;
2323 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002324 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002325
2326 if (tcp->flags & TCB_INSYSCALL) {
2327 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002328
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002329 /* Measure the exit time as early as possible to avoid errors. */
2330 if (dtime)
2331 gettimeofday(&tv, NULL);
2332
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002333 /* BTW, why we don't just memorize syscall no. on entry
2334 * in tcp->something?
2335 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002336 scno_good = res = get_scno(tcp);
2337 if (res == 0)
2338 return res;
2339 if (res == 1)
2340 res = syscall_fixup(tcp);
2341 if (res == 0)
2342 return res;
2343 if (res == 1)
2344 res = get_error(tcp);
2345 if (res == 0)
2346 return res;
2347 if (res == 1)
2348 internal_syscall(tcp);
2349
2350 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002351 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002352 tcp->flags &= ~TCB_INSYSCALL;
2353 return 0;
2354 }
2355
2356 if (tcp->flags & TCB_REPRINT) {
2357 printleader(tcp);
2358 tprintf("<... ");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002359 if (scno_good != 1)
2360 tprintf("????");
2361 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002362 tprintf("syscall_%lu", tcp->scno);
2363 else
2364 tprintf("%s", sysent[tcp->scno].sys_name);
2365 tprintf(" resumed> ");
2366 }
2367
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002368 if (cflag)
2369 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002370
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002371 if (res != 1) {
2372 tprintf(") ");
2373 tabto(acolumn);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002374 tprintf("= ? <unavailable>");
2375 printtrailer();
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002376 tcp->flags &= ~TCB_INSYSCALL;
2377 return res;
2378 }
2379
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002380 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002381 || (qual_flags[tcp->scno] & QUAL_RAW))
2382 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002383 else {
2384 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002385 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002386 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002387 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002388 u_error = tcp->u_error;
2389 tprintf(") ");
2390 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002391 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2392 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002393 if (u_error)
2394 tprintf("= -1 (errno %ld)", u_error);
2395 else
2396 tprintf("= %#lx", tcp->u_rval);
2397 }
2398 else if (!(sys_res & RVAL_NONE) && u_error) {
2399 switch (u_error) {
2400#ifdef LINUX
2401 case ERESTARTSYS:
2402 tprintf("= ? ERESTARTSYS (To be restarted)");
2403 break;
2404 case ERESTARTNOINTR:
2405 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2406 break;
2407 case ERESTARTNOHAND:
2408 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2409 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002410 case ERESTART_RESTARTBLOCK:
2411 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2412 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002413#endif /* LINUX */
2414 default:
2415 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002416 if (u_error < 0)
2417 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002418 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002419 tprintf("%s (%s)", errnoent[u_error],
2420 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002421 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002422 tprintf("ERRNO_%ld (%s)", u_error,
2423 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002424 break;
2425 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002426 if ((sys_res & RVAL_STR) && tcp->auxstr)
2427 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002428 }
2429 else {
2430 if (sys_res & RVAL_NONE)
2431 tprintf("= ?");
2432 else {
2433 switch (sys_res & RVAL_MASK) {
2434 case RVAL_HEX:
2435 tprintf("= %#lx", tcp->u_rval);
2436 break;
2437 case RVAL_OCTAL:
2438 tprintf("= %#lo", tcp->u_rval);
2439 break;
2440 case RVAL_UDECIMAL:
2441 tprintf("= %lu", tcp->u_rval);
2442 break;
2443 case RVAL_DECIMAL:
2444 tprintf("= %ld", tcp->u_rval);
2445 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002446#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002447 case RVAL_LHEX:
2448 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002449 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002450 case RVAL_LOCTAL:
2451 tprintf("= %#llo", tcp->u_lrval);
2452 break;
2453 case RVAL_LUDECIMAL:
2454 tprintf("= %llu", tcp->u_lrval);
2455 break;
2456 case RVAL_LDECIMAL:
2457 tprintf("= %lld", tcp->u_lrval);
2458 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002459#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002460 default:
2461 fprintf(stderr,
2462 "invalid rval format\n");
2463 break;
2464 }
2465 }
2466 if ((sys_res & RVAL_STR) && tcp->auxstr)
2467 tprintf(" (%s)", tcp->auxstr);
2468 }
2469 if (dtime) {
2470 tv_sub(&tv, &tv, &tcp->etime);
2471 tprintf(" <%ld.%06ld>",
2472 (long) tv.tv_sec, (long) tv.tv_usec);
2473 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002474 printtrailer();
Pavel Machek4dc3b142000-02-01 17:58:41 +00002475
2476 dumpio(tcp);
2477 if (fflush(tcp->outf) == EOF)
2478 return -1;
2479 tcp->flags &= ~TCB_INSYSCALL;
2480 return 0;
2481 }
2482
2483 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002484 scno_good = res = get_scno(tcp);
2485 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002486 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002487 if (res == 1)
2488 res = syscall_fixup(tcp);
2489 if (res == 0)
2490 return res;
2491 if (res == 1)
2492 res = syscall_enter(tcp);
2493 if (res == 0)
2494 return res;
2495
2496 if (res != 1) {
2497 printleader(tcp);
2498 tcp->flags &= ~TCB_REPRINT;
2499 tcp_last = tcp;
2500 if (scno_good != 1)
2501 tprintf("????" /* anti-trigraph gap */ "(");
2502 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2503 tprintf("syscall_%lu(", tcp->scno);
2504 else
2505 tprintf("%s(", sysent[tcp->scno].sys_name);
2506 /*
2507 * " <unavailable>" will be added later by the code which
2508 * detects ptrace errors.
2509 */
2510 tcp->flags |= TCB_INSYSCALL;
2511 return res;
2512 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002513
Roland McGrath17352792005-06-07 23:21:26 +00002514 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002515#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002516 case SYS_socketcall:
2517 decode_subcall(tcp, SYS_socket_subcall,
2518 SYS_socket_nsubcalls, deref_style);
2519 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002520#endif
2521#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002522 case SYS_ipc:
2523 decode_subcall(tcp, SYS_ipc_subcall,
2524 SYS_ipc_nsubcalls, shift_style);
2525 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002526#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002527#ifdef SVR4
2528#ifdef SYS_pgrpsys_subcall
2529 case SYS_pgrpsys:
2530 decode_subcall(tcp, SYS_pgrpsys_subcall,
2531 SYS_pgrpsys_nsubcalls, shift_style);
2532 break;
2533#endif /* SYS_pgrpsys_subcall */
2534#ifdef SYS_sigcall_subcall
2535 case SYS_sigcall:
2536 decode_subcall(tcp, SYS_sigcall_subcall,
2537 SYS_sigcall_nsubcalls, mask_style);
2538 break;
2539#endif /* SYS_sigcall_subcall */
2540 case SYS_msgsys:
2541 decode_subcall(tcp, SYS_msgsys_subcall,
2542 SYS_msgsys_nsubcalls, shift_style);
2543 break;
2544 case SYS_shmsys:
2545 decode_subcall(tcp, SYS_shmsys_subcall,
2546 SYS_shmsys_nsubcalls, shift_style);
2547 break;
2548 case SYS_semsys:
2549 decode_subcall(tcp, SYS_semsys_subcall,
2550 SYS_semsys_nsubcalls, shift_style);
2551 break;
2552#if 0 /* broken */
2553 case SYS_utssys:
2554 decode_subcall(tcp, SYS_utssys_subcall,
2555 SYS_utssys_nsubcalls, shift_style);
2556 break;
2557#endif
2558 case SYS_sysfs:
2559 decode_subcall(tcp, SYS_sysfs_subcall,
2560 SYS_sysfs_nsubcalls, shift_style);
2561 break;
2562 case SYS_spcall:
2563 decode_subcall(tcp, SYS_spcall_subcall,
2564 SYS_spcall_nsubcalls, shift_style);
2565 break;
2566#ifdef SYS_context_subcall
2567 case SYS_context:
2568 decode_subcall(tcp, SYS_context_subcall,
2569 SYS_context_nsubcalls, shift_style);
2570 break;
2571#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002572#ifdef SYS_door_subcall
2573 case SYS_door:
2574 decode_subcall(tcp, SYS_door_subcall,
2575 SYS_door_nsubcalls, door_style);
2576 break;
2577#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002578#ifdef SYS_kaio_subcall
2579 case SYS_kaio:
2580 decode_subcall(tcp, SYS_kaio_subcall,
2581 SYS_kaio_nsubcalls, shift_style);
2582 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002583#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002584#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002585#ifdef FREEBSD
2586 case SYS_msgsys:
2587 case SYS_shmsys:
2588 case SYS_semsys:
2589 decode_subcall(tcp, 0, 0, table_style);
2590 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002591#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002592#ifdef SUNOS4
2593 case SYS_semsys:
2594 decode_subcall(tcp, SYS_semsys_subcall,
2595 SYS_semsys_nsubcalls, shift_style);
2596 break;
2597 case SYS_msgsys:
2598 decode_subcall(tcp, SYS_msgsys_subcall,
2599 SYS_msgsys_nsubcalls, shift_style);
2600 break;
2601 case SYS_shmsys:
2602 decode_subcall(tcp, SYS_shmsys_subcall,
2603 SYS_shmsys_nsubcalls, shift_style);
2604 break;
2605#endif
2606 }
2607
2608 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002609 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002610 tcp->flags |= TCB_INSYSCALL;
2611 return 0;
2612 }
2613
2614 if (cflag) {
2615 gettimeofday(&tcp->etime, NULL);
2616 tcp->flags |= TCB_INSYSCALL;
2617 return 0;
2618 }
2619
2620 printleader(tcp);
2621 tcp->flags &= ~TCB_REPRINT;
2622 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002623 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002624 tprintf("syscall_%lu(", tcp->scno);
2625 else
2626 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002627 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002628 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2629 sys_res = printargs(tcp);
2630 else
2631 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2632 if (fflush(tcp->outf) == EOF)
2633 return -1;
2634 tcp->flags |= TCB_INSYSCALL;
2635 /* Measure the entrance time as late as possible to avoid errors. */
2636 if (dtime)
2637 gettimeofday(&tcp->etime, NULL);
2638 return sys_res;
2639}
2640
2641int
2642printargs(tcp)
2643struct tcb *tcp;
2644{
2645 if (entering(tcp)) {
2646 int i;
2647
2648 for (i = 0; i < tcp->u_nargs; i++)
2649 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2650 }
2651 return 0;
2652}
2653
2654long
2655getrval2(tcp)
2656struct tcb *tcp;
2657{
2658 long val = -1;
2659
2660#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002661#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002662 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002663 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2664 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002665 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002666#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002667 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002668 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002669#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002670 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002671 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002672#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002673#endif /* LINUX */
2674
2675#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002676 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002677 return -1;
2678#endif /* SUNOS4 */
2679
2680#ifdef SVR4
2681#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002682 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002683#endif /* SPARC */
2684#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002685 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002686#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002687#ifdef X86_64
2688 val = tcp->status.PR_REG[RDX];
2689#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002690#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002691 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002692#endif /* MIPS */
2693#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002694#ifdef FREEBSD
2695 struct reg regs;
2696 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2697 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002698#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002699 return val;
2700}
2701
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002702#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002703/*
2704 * Apparently, indirect system calls have already be converted by ptrace(2),
2705 * so if you see "indir" this program has gone astray.
2706 */
2707int
2708sys_indir(tcp)
2709struct tcb *tcp;
2710{
2711 int i, scno, nargs;
2712
2713 if (entering(tcp)) {
2714 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2715 fprintf(stderr, "Bogus syscall: %u\n", scno);
2716 return 0;
2717 }
2718 nargs = sysent[scno].nargs;
2719 tprintf("%s", sysent[scno].sys_name);
2720 for (i = 0; i < nargs; i++)
2721 tprintf(", %#lx", tcp->u_arg[i+1]);
2722 }
2723 return 0;
2724}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002725#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002726
2727int
2728is_restart_error(struct tcb *tcp)
2729{
2730#ifdef LINUX
2731 if (!syserror(tcp))
2732 return 0;
2733 switch (tcp->u_error) {
2734 case ERESTARTSYS:
2735 case ERESTARTNOINTR:
2736 case ERESTARTNOHAND:
2737 case ERESTART_RESTARTBLOCK:
2738 return 1;
2739 default:
2740 break;
2741 }
2742#endif /* LINUX */
2743 return 0;
2744}