blob: 19f8fe9f74f14fdde6291efef73afb2c37c21552 [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)) {
917 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;
928 switch(val)
929 {
930 case 0x23: currpers = 1; break;
931 case 0x33: currpers = 0; break;
932 default:
933 fprintf(stderr, "Unknown value CS=0x%02X while "
934 "detecting personality of process "
935 "PID=%d\n", (int)val, pid);
936 currpers = current_personality;
937 break;
938 }
939#if 0
940 /* This version analyzes the opcode of a syscall instruction.
941 * (int 0x80 on i386 vs. syscall on x86-64)
942 * It works, but is too complicated.
943 */
944 unsigned long val, rip, i;
945
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000946 if(upeek(tcp, 8*RIP, &rip)<0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000947 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000948
Michal Ludvig0e035502002-09-23 15:41:01 +0000949 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
950 rip-=2;
951 errno = 0;
952
Roland McGrath761b5d72002-12-15 23:58:31 +0000953 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
954 if (errno)
955 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000956 strerror(errno));
957 switch (call & 0xffff)
958 {
959 /* x86-64: syscall = 0x0f 0x05 */
960 case 0x050f: currpers = 0; break;
961 /* i386: int 0x80 = 0xcd 0x80 */
962 case 0x80cd: currpers = 1; break;
963 default:
964 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000965 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000966 "Unknown syscall opcode (0x%04X) while "
967 "detecting personality of process "
968 "PID=%d\n", (int)call, pid);
969 break;
970 }
971#endif
972 if(currpers != current_personality)
973 {
974 char *names[]={"64 bit", "32 bit"};
975 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000976 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000977 pid, names[current_personality]);
978 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000979 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000980#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000981# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000982 if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000983 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000984 if (!(tcp->flags & TCB_INSYSCALL)) {
985 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000986 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000987 return -1;
988 } else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000989 if (upeek (tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000990 return -1;
991 }
Roland McGrathba954762003-03-05 06:29:06 +0000992 /* Check if we return from execve. */
993 if (tcp->flags & TCB_WAITEXECVE) {
994 tcp->flags &= ~TCB_WAITEXECVE;
995 return 0;
996 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000997 } else {
998 /* syscall in progress */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000999 if (upeek (tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001000 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001001 if (upeek (tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001002 return -1;
1003 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001004#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001005 /*
1006 * Read complete register set in one go.
1007 */
1008 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1009 return -1;
1010
1011 /*
1012 * We only need to grab the syscall number on syscall entry.
1013 */
1014 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001015 if (!(tcp->flags & TCB_INSYSCALL)) {
1016 /* Check if we return from execve. */
1017 if (tcp->flags & TCB_WAITEXECVE) {
1018 tcp->flags &= ~TCB_WAITEXECVE;
1019 return 0;
1020 }
1021 }
1022
Roland McGrath0f87c492003-06-03 23:29:04 +00001023 /*
1024 * Note: we only deal with only 32-bit CPUs here.
1025 */
1026 if (regs.ARM_cpsr & 0x20) {
1027 /*
1028 * Get the Thumb-mode system call number
1029 */
1030 scno = regs.ARM_r7;
1031 } else {
1032 /*
1033 * Get the ARM-mode system call number
1034 */
1035 errno = 0;
1036 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1037 if (errno)
1038 return -1;
1039
1040 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1041 tcp->flags &= ~TCB_WAITEXECVE;
1042 return 0;
1043 }
1044
Roland McGrathf691bd22006-04-25 07:34:41 +00001045 /* Handle the EABI syscall convention. We do not
1046 bother converting structures between the two
1047 ABIs, but basic functionality should work even
1048 if strace and the traced program have different
1049 ABIs. */
1050 if (scno == 0xef000000) {
1051 scno = regs.ARM_r7;
1052 } else {
1053 if ((scno & 0x0ff00000) != 0x0f900000) {
1054 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1055 scno);
1056 return -1;
1057 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001058
Roland McGrathf691bd22006-04-25 07:34:41 +00001059 /*
1060 * Fixup the syscall number
1061 */
1062 scno &= 0x000fffff;
1063 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001064 }
Roland McGrath56703312008-05-20 01:35:55 +00001065 if (scno & 0x0f0000) {
1066 /*
1067 * Handle ARM specific syscall
1068 */
1069 set_personality(1);
1070 scno &= 0x0000ffff;
1071 } else
1072 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001073
1074 if (tcp->flags & TCB_INSYSCALL) {
1075 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1076 tcp->flags &= ~TCB_INSYSCALL;
1077 }
1078 } else {
1079 if (!(tcp->flags & TCB_INSYSCALL)) {
1080 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1081 tcp->flags |= TCB_INSYSCALL;
1082 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 }
1084#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001085 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 return -1;
Roland McGrath542c2c62008-05-20 01:11:56 +00001087#elif defined (LINUX_MIPSN32)
1088 unsigned long long regs[38];
1089
1090 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
1091 return -1;
1092 a3 = regs[REG_A3];
1093 r2 = regs[REG_V0];
1094
1095 if(!(tcp->flags & TCB_INSYSCALL)) {
1096 scno = r2;
1097
1098 /* Check if we return from execve. */
1099 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1100 tcp->flags &= ~TCB_WAITEXECVE;
1101 return 0;
1102 }
1103
1104 if (scno < 0 || scno > nsyscalls) {
1105 if(a3 == 0 || a3 == -1) {
1106 if(debug)
1107 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1108 return 0;
1109 }
1110 }
1111 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001112#elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001113 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001114 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001115 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001116 if (upeek(tcp, REG_V0, &scno) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001117 return -1;
1118
Roland McGrath542c2c62008-05-20 01:11:56 +00001119 /* Check if we return from execve. */
1120 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1121 tcp->flags &= ~TCB_WAITEXECVE;
1122 return 0;
1123 }
1124
Wichert Akkermanf90da011999-10-31 21:15:38 +00001125 if (scno < 0 || scno > nsyscalls) {
1126 if(a3 == 0 || a3 == -1) {
1127 if(debug)
1128 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1129 return 0;
1130 }
1131 }
1132 } else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001133 if (upeek(tcp, REG_V0, &r2) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001134 return -1;
1135 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001136#elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001137 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138 return -1;
1139
1140 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001141 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001142 return -1;
1143
1144 /* Check if we return from execve. */
1145 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1146 tcp->flags &= ~TCB_WAITEXECVE;
1147 return 0;
1148 }
1149
1150 /*
1151 * Do some sanity checks to figure out if it's
1152 * really a syscall entry
1153 */
1154 if (scno < 0 || scno > nsyscalls) {
1155 if (a3 == 0 || a3 == -1) {
1156 if (debug)
1157 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1158 return 0;
1159 }
1160 }
1161 }
1162 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001163 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 return -1;
1165 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001166#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167 /* Everything we need is in the current register set. */
1168 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1169 return -1;
1170
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001171 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 if (!(tcp->flags & TCB_INSYSCALL)) {
1173 /* Retrieve the syscall trap instruction. */
1174 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001175 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001176#if defined(SPARC64)
1177 trap >>= 32;
1178#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 if (errno)
1180 return -1;
1181
1182 /* Disassemble the trap to see what personality to use. */
1183 switch (trap) {
1184 case 0x91d02010:
1185 /* Linux/SPARC syscall trap. */
1186 set_personality(0);
1187 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001188 case 0x91d0206d:
1189 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001190 set_personality(2);
1191 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192 case 0x91d02000:
1193 /* SunOS syscall trap. (pers 1) */
1194 fprintf(stderr,"syscall: SunOS no support\n");
1195 return -1;
1196 case 0x91d02008:
1197 /* Solaris 2.x syscall trap. (per 2) */
1198 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001199 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001200 case 0x91d02009:
1201 /* NetBSD/FreeBSD syscall trap. */
1202 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1203 return -1;
1204 case 0x91d02027:
1205 /* Solaris 2.x gettimeofday */
1206 set_personality(1);
1207 break;
1208 default:
1209 /* Unknown syscall trap. */
1210 if(tcp->flags & TCB_WAITEXECVE) {
1211 tcp->flags &= ~TCB_WAITEXECVE;
1212 return 0;
1213 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001214#if defined (SPARC64)
1215 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1216#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001217 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001218#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001219 return -1;
1220 }
1221
1222 /* Extract the system call number from the registers. */
1223 if (trap == 0x91d02027)
1224 scno = 156;
1225 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001226 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001228 scno = regs.r_o0;
1229 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230 }
1231 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001232#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001233 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001234 return -1;
1235 if (!(tcp->flags & TCB_INSYSCALL)) {
1236 /* Check if we return from execve. */
1237 if ((tcp->flags & TCB_WAITEXECVE)) {
1238 tcp->flags &= ~TCB_WAITEXECVE;
1239 return 0;
1240 }
1241 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001242#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001243 /*
1244 * In the new syscall ABI, the system call number is in R3.
1245 */
1246 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1247 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001248
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001249 if (scno < 0) {
1250 /* Odd as it may seem, a glibc bug has been known to cause
1251 glibc to issue bogus negative syscall numbers. So for
1252 our purposes, make strace print what it *should* have been */
1253 long correct_scno = (scno & 0xff);
1254 if (debug)
1255 fprintf(stderr,
1256 "Detected glibc bug: bogus system call"
1257 " number = %ld, correcting to %ld\n",
1258 scno,
1259 correct_scno);
1260 scno = correct_scno;
1261 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001262
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001263 if (!(tcp->flags & TCB_INSYSCALL)) {
1264 /* Check if we return from execve. */
1265 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1266 tcp->flags &= ~TCB_WAITEXECVE;
1267 return 0;
1268 }
1269 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001270#elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001271 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001272 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001273 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001274
1275 if (!(tcp->flags & TCB_INSYSCALL)) {
1276 /* Check if we return from execve. */
1277 if (tcp->flags & TCB_WAITEXECVE) {
1278 tcp->flags &= ~TCB_WAITEXECVE;
1279 return 0;
1280 }
1281 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001282#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001283#endif /* LINUX */
1284#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001285 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001287#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001288 /* new syscall ABI returns result in R0 */
1289 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1290 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001291#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001292 /* ABI defines result returned in r9 */
1293 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1294 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001295
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001296#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001297#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001298#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001299 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001301#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001302 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001303#else /* FREEBSD */
1304 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001305 perror("pread");
1306 return -1;
1307 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001308 switch (regs.r_eax) {
1309 case SYS_syscall:
1310 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001311 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1312 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001313 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001314 scno = regs.r_eax;
1315 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001316 }
1317#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001319#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001320 if (!(tcp->flags & TCB_INSYSCALL))
1321 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001322 return 1;
1323}
1324
Pavel Machek4dc3b142000-02-01 17:58:41 +00001325
Roland McGrath17352792005-06-07 23:21:26 +00001326long
1327known_scno(tcp)
1328struct tcb *tcp;
1329{
1330 long scno = tcp->scno;
1331 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1332 scno = sysent[scno].native_scno;
1333 else
1334 scno += NR_SYSCALL_BASE;
1335 return scno;
1336}
1337
Roland McGratha4d48532005-06-08 20:45:28 +00001338static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001339syscall_fixup(tcp)
1340struct tcb *tcp;
1341{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001342#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001343 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001344
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001345 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001346 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001347 if (
1348 scno == SYS_fork
1349#ifdef SYS_vfork
1350 || scno == SYS_vfork
1351#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001352#ifdef SYS_fork1
1353 || scno == SYS_fork1
1354#endif /* SYS_fork1 */
1355#ifdef SYS_forkall
1356 || scno == SYS_forkall
1357#endif /* SYS_forkall */
1358#ifdef SYS_rfork1
1359 || scno == SYS_rfork1
1360#endif /* SYS_fork1 */
1361#ifdef SYS_rforkall
1362 || scno == SYS_rforkall
1363#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001364 ) {
1365 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001366 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001368 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 }
1370 else {
1371 fprintf(stderr, "syscall: missing entry\n");
1372 tcp->flags |= TCB_INSYSCALL;
1373 }
1374 }
1375 }
1376 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001377 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 fprintf(stderr, "syscall: missing exit\n");
1379 tcp->flags &= ~TCB_INSYSCALL;
1380 }
1381 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001382#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001383#ifdef SUNOS4
1384 if (!(tcp->flags & TCB_INSYSCALL)) {
1385 if (scno == 0) {
1386 fprintf(stderr, "syscall: missing entry\n");
1387 tcp->flags |= TCB_INSYSCALL;
1388 }
1389 }
1390 else {
1391 if (scno != 0) {
1392 if (debug) {
1393 /*
1394 * This happens when a signal handler
1395 * for a signal which interrupted a
1396 * a system call makes another system call.
1397 */
1398 fprintf(stderr, "syscall: missing exit\n");
1399 }
1400 tcp->flags &= ~TCB_INSYSCALL;
1401 }
1402 }
1403#endif /* SUNOS4 */
1404#ifdef LINUX
1405#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001406 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001407 return -1;
1408 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1409 if (debug)
1410 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1411 return 0;
1412 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001413#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001414 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001415 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001416 if (current_personality == 1)
1417 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001418 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1419 if (debug)
1420 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1421 return 0;
1422 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001423#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001424 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001425 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001426 if (syscall_mode != -ENOSYS)
1427 syscall_mode = tcp->scno;
1428 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001429 if (debug)
1430 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1431 return 0;
1432 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001433 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1434 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1435 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1436 /*
1437 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1438 * flag set for the post-execve SIGTRAP to see and reset.
1439 */
1440 gpr2 = 0;
1441 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001442#elif defined (POWERPC)
1443# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001444 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001445 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001446 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001447 return -1;
1448 if (flags & SO_MASK)
1449 result = -result;
1450#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001451 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452 return -1;
1453 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1454 if (debug)
1455 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1456 return 0;
1457 }
1458#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001459 /*
1460 * Nothing required
1461 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001462#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001463 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001464 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001465#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001466 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001467 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001468#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001469 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001470 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001471 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001472 return -1;
1473 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1474 if (debug)
1475 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1476 return 0;
1477 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001478#endif
1479#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001480 return 1;
1481}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001482
Roland McGrathc1e45922008-05-27 23:18:29 +00001483#ifdef LINUX
1484/*
1485 * Check the syscall return value register value for whether it is
1486 * a negated errno code indicating an error, or a success return value.
1487 */
1488static inline int
1489is_negated_errno(unsigned long int val)
1490{
1491 unsigned long int max = -(long int) nerrnos;
1492 if (personality_wordsize[current_personality] < sizeof(val)) {
1493 val = (unsigned int) val;
1494 max = (unsigned int) max;
1495 }
1496 return val > max;
1497}
1498#endif
1499
Roland McGratha4d48532005-06-08 20:45:28 +00001500static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001501get_error(tcp)
1502struct tcb *tcp;
1503{
1504 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001505#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001506#if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001507 if (is_negated_errno(gpr2)) {
1508 tcp->u_rval = -1;
1509 u_error = -gpr2;
1510 }
1511 else {
1512 tcp->u_rval = gpr2;
1513 u_error = 0;
1514 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001515#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516#ifdef I386
Roland McGrathc1e45922008-05-27 23:18:29 +00001517 if (is_negated_errno(eax)) {
1518 tcp->u_rval = -1;
1519 u_error = -eax;
1520 }
1521 else {
1522 tcp->u_rval = eax;
1523 u_error = 0;
1524 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001525#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001526#ifdef X86_64
Roland McGrathc1e45922008-05-27 23:18:29 +00001527 if (is_negated_errno(rax)) {
1528 tcp->u_rval = -1;
1529 u_error = -rax;
1530 }
1531 else {
1532 tcp->u_rval = rax;
1533 u_error = 0;
1534 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001535#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001536#ifdef IA64
Roland McGrathc1e45922008-05-27 23:18:29 +00001537 if (ia32) {
1538 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001539
Roland McGrathc1e45922008-05-27 23:18:29 +00001540 err = (int)r8;
1541 if (is_negated_errno(err)) {
1542 tcp->u_rval = -1;
1543 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001544 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001545 else {
1546 tcp->u_rval = err;
1547 u_error = 0;
1548 }
1549 } else {
1550 if (r10) {
1551 tcp->u_rval = -1;
1552 u_error = r8;
1553 } else {
1554 tcp->u_rval = r8;
1555 u_error = 0;
1556 }
1557 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001558#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001559#ifdef MIPS
1560 if (a3) {
1561 tcp->u_rval = -1;
1562 u_error = r2;
1563 } else {
1564 tcp->u_rval = r2;
1565 u_error = 0;
1566 }
1567#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001568#ifdef POWERPC
Roland McGrathc1e45922008-05-27 23:18:29 +00001569 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001570 tcp->u_rval = -1;
1571 u_error = -result;
1572 }
1573 else {
1574 tcp->u_rval = result;
1575 u_error = 0;
1576 }
1577#else /* !POWERPC */
1578#ifdef M68K
Roland McGrathc1e45922008-05-27 23:18:29 +00001579 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001580 tcp->u_rval = -1;
1581 u_error = -d0;
1582 }
1583 else {
1584 tcp->u_rval = d0;
1585 u_error = 0;
1586 }
1587#else /* !M68K */
1588#ifdef ARM
Roland McGrathc1e45922008-05-27 23:18:29 +00001589 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001591 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592 }
1593 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001594 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001595 u_error = 0;
1596 }
1597#else /* !ARM */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001598#ifdef BFIN
1599 if (is_negated_errno(r0)) {
1600 tcp->u_rval = -1;
1601 u_error = -r0;
1602 } else {
1603 tcp->u_rval = r0;
1604 u_error = 0;
1605 }
1606#else /* !BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001607#ifdef ALPHA
1608 if (a3) {
1609 tcp->u_rval = -1;
1610 u_error = r0;
1611 }
1612 else {
1613 tcp->u_rval = r0;
1614 u_error = 0;
1615 }
1616#else /* !ALPHA */
1617#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001618 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001620 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 }
1622 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001623 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001624 u_error = 0;
1625 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001626#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001627#ifdef SPARC64
1628 if (regs.r_tstate & 0x1100000000UL) {
1629 tcp->u_rval = -1;
1630 u_error = regs.r_o0;
1631 }
1632 else {
1633 tcp->u_rval = regs.r_o0;
1634 u_error = 0;
1635 }
1636#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001637#ifdef HPPA
Roland McGrathc1e45922008-05-27 23:18:29 +00001638 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001639 tcp->u_rval = -1;
1640 u_error = -r28;
1641 }
1642 else {
1643 tcp->u_rval = r28;
1644 u_error = 0;
1645 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001646#else
1647#ifdef SH
Roland McGrathc1e45922008-05-27 23:18:29 +00001648 /* interpret R0 as return value or error number */
1649 if (is_negated_errno(r0)) {
1650 tcp->u_rval = -1;
1651 u_error = -r0;
1652 }
1653 else {
1654 tcp->u_rval = r0;
1655 u_error = 0;
1656 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001657#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001658#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001659 /* interpret result as return value or error number */
1660 if (is_negated_errno(r9)) {
1661 tcp->u_rval = -1;
1662 u_error = -r9;
1663 }
1664 else {
1665 tcp->u_rval = r9;
1666 u_error = 0;
1667 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001668#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001669#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001670#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001671#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001672#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001673#endif /* ALPHA */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001674#endif /* BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675#endif /* ARM */
1676#endif /* M68K */
1677#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001678#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001679#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001680#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001681#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001682#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683#endif /* LINUX */
1684#ifdef SUNOS4
1685 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001686 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687 return -1;
1688 u_error >>= 24; /* u_error is a char */
1689
1690 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001691 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692 return -1;
1693#endif /* SUNOS4 */
1694#ifdef SVR4
1695#ifdef SPARC
1696 /* Judicious guessing goes a long way. */
1697 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1698 tcp->u_rval = -1;
1699 u_error = tcp->status.pr_reg[R_O0];
1700 }
1701 else {
1702 tcp->u_rval = tcp->status.pr_reg[R_O0];
1703 u_error = 0;
1704 }
1705#endif /* SPARC */
1706#ifdef I386
1707 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001708 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001710 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711 }
1712 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001713 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001714#ifdef HAVE_LONG_LONG
1715 tcp->u_lrval =
1716 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1717 tcp->status.PR_REG[EAX];
1718#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001719 u_error = 0;
1720 }
1721#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001722#ifdef X86_64
1723 /* Wanna know how to kill an hour single-stepping? */
1724 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1725 tcp->u_rval = -1;
1726 u_error = tcp->status.PR_REG[RAX];
1727 }
1728 else {
1729 tcp->u_rval = tcp->status.PR_REG[RAX];
1730 u_error = 0;
1731 }
1732#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733#ifdef MIPS
1734 if (tcp->status.pr_reg[CTX_A3]) {
1735 tcp->u_rval = -1;
1736 u_error = tcp->status.pr_reg[CTX_V0];
1737 }
1738 else {
1739 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1740 u_error = 0;
1741 }
1742#endif /* MIPS */
1743#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001744#ifdef FREEBSD
1745 if (regs.r_eflags & PSL_C) {
1746 tcp->u_rval = -1;
1747 u_error = regs.r_eax;
1748 } else {
1749 tcp->u_rval = regs.r_eax;
1750 tcp->u_lrval =
1751 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1752 u_error = 0;
1753 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001754#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001755 tcp->u_error = u_error;
1756 return 1;
1757}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001758
Roland McGrathb69f81b2002-12-21 23:25:18 +00001759int
1760force_result(tcp, error, rval)
1761 struct tcb *tcp;
1762 int error;
1763 long rval;
1764{
1765#ifdef LINUX
1766#if defined(S390) || defined(S390X)
1767 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001768 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1769 return -1;
1770#else /* !S390 && !S390X */
1771#ifdef I386
1772 eax = error ? -error : rval;
1773 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1774 return -1;
1775#else /* !I386 */
1776#ifdef X86_64
1777 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001778 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001779 return -1;
1780#else
1781#ifdef IA64
1782 if (ia32) {
1783 r8 = error ? -error : rval;
1784 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1785 return -1;
1786 }
1787 else {
1788 if (error) {
1789 r8 = error;
1790 r10 = -1;
1791 }
1792 else {
1793 r8 = rval;
1794 r10 = 0;
1795 }
1796 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1797 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1798 return -1;
1799 }
1800#else /* !IA64 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001801#ifdef BFIN
1802 r0 = error ? -error : rval;
1803 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1804 return -1;
1805#else /* !BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001806#ifdef MIPS
1807 if (error) {
1808 r2 = error;
1809 a3 = -1;
1810 }
1811 else {
1812 r2 = rval;
1813 a3 = 0;
1814 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001815 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001816 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1817 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1818 return -1;
1819#else
1820#ifdef POWERPC
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001821 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001822 return -1;
1823 if (error) {
1824 flags |= SO_MASK;
1825 result = error;
1826 }
1827 else {
1828 flags &= ~SO_MASK;
1829 result = rval;
1830 }
Roland McGratheb285352003-01-14 09:59:00 +00001831 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1832 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001833 return -1;
1834#else /* !POWERPC */
1835#ifdef M68K
1836 d0 = error ? -error : rval;
1837 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1838 return -1;
1839#else /* !M68K */
1840#ifdef ARM
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001841 regs.ARM_r0 = error ? -error : rval;
1842 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001843 return -1;
1844#else /* !ARM */
1845#ifdef ALPHA
1846 if (error) {
1847 a3 = -1;
1848 r0 = error;
1849 }
1850 else {
1851 a3 = 0;
1852 r0 = rval;
1853 }
1854 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1855 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1856 return -1;
1857#else /* !ALPHA */
1858#ifdef SPARC
1859 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1860 return -1;
1861 if (error) {
1862 regs.r_psr |= PSR_C;
1863 regs.r_o0 = error;
1864 }
1865 else {
1866 regs.r_psr &= ~PSR_C;
1867 regs.r_o0 = rval;
1868 }
1869 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1870 return -1;
1871#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001872#ifdef SPARC64
1873 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1874 return -1;
1875 if (error) {
1876 regs.r_tstate |= 0x1100000000UL;
1877 regs.r_o0 = error;
1878 }
1879 else {
1880 regs.r_tstate &= ~0x1100000000UL;
1881 regs.r_o0 = rval;
1882 }
1883 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1884 return -1;
1885#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001886#ifdef HPPA
1887 r28 = error ? -error : rval;
1888 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1889 return -1;
1890#else
1891#ifdef SH
1892 r0 = error ? -error : rval;
1893 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1894 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001895#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001896#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001897 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001898 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1899 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001900#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001901#endif /* SH */
1902#endif /* HPPA */
1903#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001904#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001905#endif /* ALPHA */
1906#endif /* ARM */
1907#endif /* M68K */
1908#endif /* POWERPC */
1909#endif /* MIPS */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001910#endif /* BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001911#endif /* IA64 */
1912#endif /* X86_64 */
1913#endif /* I386 */
1914#endif /* S390 || S390X */
1915#endif /* LINUX */
1916#ifdef SUNOS4
1917 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1918 error << 24) < 0 ||
1919 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1920 return -1;
1921#endif /* SUNOS4 */
1922#ifdef SVR4
1923 /* XXX no clue */
1924 return -1;
1925#endif /* SVR4 */
1926#ifdef FREEBSD
1927 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001928 perror("pread");
1929 return -1;
1930 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001931 if (error) {
1932 regs.r_eflags |= PSL_C;
1933 regs.r_eax = error;
1934 }
1935 else {
1936 regs.r_eflags &= ~PSL_C;
1937 regs.r_eax = rval;
1938 }
1939 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001940 perror("pwrite");
1941 return -1;
1942 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001943#endif /* FREEBSD */
1944
1945 /* All branches reach here on success (only). */
1946 tcp->u_error = error;
1947 tcp->u_rval = rval;
1948 return 0;
1949}
1950
Roland McGratha4d48532005-06-08 20:45:28 +00001951static int
1952syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001953struct tcb *tcp;
1954{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001955#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001956#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001957 {
1958 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001959 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1960 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001961 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001962 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001963 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001964 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001965 return -1;
1966 }
1967 }
1968#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001969 {
1970 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001971 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1972 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001973 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001974 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001975 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001976 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1977 * for scno somewhere above here!
1978 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001979 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980 return -1;
1981 }
1982 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001983#elif defined (IA64)
1984 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001985 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001986 unsigned long *out0, cfm, sof, sol, i;
1987 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001988 /* be backwards compatible with kernel < 2.4.4... */
1989# ifndef PT_RBS_END
1990# define PT_RBS_END PT_AR_BSP
1991# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001992
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001993 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001994 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001995 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001996 return -1;
1997
1998 sof = (cfm >> 0) & 0x7f;
1999 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002000 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002001
2002 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2003 && sysent[tcp->scno].nargs != -1)
2004 tcp->u_nargs = sysent[tcp->scno].nargs;
2005 else
2006 tcp->u_nargs = MAX_ARGS;
2007 for (i = 0; i < tcp->u_nargs; ++i) {
2008 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2009 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2010 return -1;
2011 }
2012 } else {
2013 int i;
2014
2015 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002016 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002017 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002018 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002019 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002020 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002021 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002022 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002023 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002024 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002025 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002026 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002027 return -1;
2028
2029 for (i = 0; i < 6; ++i)
2030 /* truncate away IVE sign-extension */
2031 tcp->u_arg[i] &= 0xffffffff;
2032
2033 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2034 && sysent[tcp->scno].nargs != -1)
2035 tcp->u_nargs = sysent[tcp->scno].nargs;
2036 else
2037 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002038 }
2039 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002040#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2041 /* N32 and N64 both use up to six registers. */
2042 {
2043 unsigned long long regs[38];
2044 int i, nargs;
2045
2046 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2047 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002048 else
Roland McGrath542c2c62008-05-20 01:11:56 +00002049 nargs = tcp->u_nargs = MAX_ARGS;
2050
2051 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
2052 return -1;
2053
2054 for(i = 0; i < nargs; i++) {
2055 tcp->u_arg[i] = regs[REG_A0 + i];
2056# if defined (LINUX_MIPSN32)
2057 tcp->ext_arg[i] = regs[REG_A0 + i];
2058# endif
2059 }
2060 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002061#elif defined (MIPS)
2062 {
2063 long sp;
2064 int i, nargs;
2065
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002066 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2067 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002068 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002069 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002070 if(nargs > 4) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002071 if(upeek(tcp, REG_SP, &sp) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002072 return -1;
2073 for(i = 0; i < 4; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002074 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002075 return -1;
2076 }
2077 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2078 (char *)(tcp->u_arg + 4));
2079 } else {
2080 for(i = 0; i < nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002081 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002082 return -1;
2083 }
2084 }
2085 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002086#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002087#ifndef PT_ORIG_R3
2088#define PT_ORIG_R3 34
2089#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002090 {
2091 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002092 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2093 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002094 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002095 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002096 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002097 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002098 (sizeof(unsigned long)*PT_ORIG_R3) :
2099 ((i+PT_R3)*sizeof(unsigned long)),
2100 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002101 return -1;
2102 }
2103 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002104#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002105 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002106 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002107
2108 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2109 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002110 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002111 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002112 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002113 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002114 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002115#elif defined (HPPA)
2116 {
2117 int i;
2118
2119 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2120 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002121 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002122 tcp->u_nargs = MAX_ARGS;
2123 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002124 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002125 return -1;
2126 }
2127 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002128#elif defined(ARM)
2129 {
2130 int i;
2131
2132 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2133 tcp->u_nargs = sysent[tcp->scno].nargs;
2134 else
2135 tcp->u_nargs = MAX_ARGS;
2136 for (i = 0; i < tcp->u_nargs; i++)
2137 tcp->u_arg[i] = regs.uregs[i];
2138 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002139#elif defined(BFIN)
2140 {
2141 int i;
2142 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2143
2144 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2145 tcp->u_nargs = sysent[tcp->scno].nargs;
2146 else
2147 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2148
2149 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002150 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002151 return -1;
2152 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002153#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002154 {
2155 int i;
2156 static int syscall_regs[] = {
2157 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2158 REG_REG0, REG_REG0+1, REG_REG0+2
2159 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002160
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002161 tcp->u_nargs = sysent[tcp->scno].nargs;
2162 for (i = 0; i < tcp->u_nargs; i++) {
2163 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2164 return -1;
2165 }
2166 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002167#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002168 {
2169 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002170 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002171 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2172
2173 /*
2174 * TODO: should also check that the number of arguments encoded
2175 * in the trap number matches the number strace expects.
2176 */
2177 /*
2178 assert(sysent[tcp->scno].nargs <
2179 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2180 */
2181
2182 tcp->u_nargs = sysent[tcp->scno].nargs;
2183 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002184 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002185 return -1;
2186 }
2187 }
2188
Michal Ludvig0e035502002-09-23 15:41:01 +00002189#elif defined(X86_64)
2190 {
2191 int i;
2192 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2193 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002194 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002195 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002196
Michal Ludvig0e035502002-09-23 15:41:01 +00002197 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2198 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002199 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002200 tcp->u_nargs = MAX_ARGS;
2201 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002202 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002203 return -1;
2204 }
2205 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002206#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002207 {
2208 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002209 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2210 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002211 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002212 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002213 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002214 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002215 return -1;
2216 }
2217 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002218#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002219#endif /* LINUX */
2220#ifdef SUNOS4
2221 {
2222 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002223 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2224 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002225 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002226 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002227 for (i = 0; i < tcp->u_nargs; i++) {
2228 struct user *u;
2229
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002230 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002231 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2232 return -1;
2233 }
2234 }
2235#endif /* SUNOS4 */
2236#ifdef SVR4
2237#ifdef MIPS
2238 /*
2239 * SGI is broken: even though it has pr_sysarg, it doesn't
2240 * set them on system call entry. Get a clue.
2241 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002242 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002243 tcp->u_nargs = sysent[tcp->scno].nargs;
2244 else
2245 tcp->u_nargs = tcp->status.pr_nsysarg;
2246 if (tcp->u_nargs > 4) {
2247 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2248 4*sizeof(tcp->u_arg[0]));
2249 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2250 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2251 }
2252 else {
2253 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2254 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2255 }
John Hughes25299712001-03-06 10:10:06 +00002256#elif UNIXWARE >= 2
2257 /*
2258 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2259 */
2260 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2261 tcp->u_nargs = sysent[tcp->scno].nargs;
2262 else
2263 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2264 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2265 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2266#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002267 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002268 tcp->u_nargs = sysent[tcp->scno].nargs;
2269 else
2270 tcp->u_nargs = tcp->status.pr_nsysarg;
2271 {
2272 int i;
2273 for (i = 0; i < tcp->u_nargs; i++)
2274 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2275 }
John Hughes25299712001-03-06 10:10:06 +00002276#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002277 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002278 tcp->u_nargs = sysent[tcp->scno].nargs;
2279 else
2280 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002281 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002282 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002283#else
2284 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002285#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002286#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002287#ifdef FREEBSD
2288 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2289 sysent[tcp->scno].nargs > tcp->status.val)
2290 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002291 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002292 tcp->u_nargs = tcp->status.val;
2293 if (tcp->u_nargs < 0)
2294 tcp->u_nargs = 0;
2295 if (tcp->u_nargs > MAX_ARGS)
2296 tcp->u_nargs = MAX_ARGS;
2297 switch(regs.r_eax) {
2298 case SYS___syscall:
2299 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2300 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002301 break;
2302 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002303 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2304 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002305 break;
2306 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002307 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2308 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002309 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002310 }
2311#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002312 return 1;
2313}
2314
2315int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002316trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002317{
2318 int sys_res;
2319 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002320 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002321
2322 if (tcp->flags & TCB_INSYSCALL) {
2323 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002324
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002325 /* Measure the exit time as early as possible to avoid errors. */
2326 if (dtime)
2327 gettimeofday(&tv, NULL);
2328
2329 scno_good = res = get_scno(tcp);
2330 if (res == 0)
2331 return res;
2332 if (res == 1)
2333 res = syscall_fixup(tcp);
2334 if (res == 0)
2335 return res;
2336 if (res == 1)
2337 res = get_error(tcp);
2338 if (res == 0)
2339 return res;
2340 if (res == 1)
2341 internal_syscall(tcp);
2342
2343 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002344 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002345 tcp->flags &= ~TCB_INSYSCALL;
2346 return 0;
2347 }
2348
2349 if (tcp->flags & TCB_REPRINT) {
2350 printleader(tcp);
2351 tprintf("<... ");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002352 if (scno_good != 1)
2353 tprintf("????");
2354 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002355 tprintf("syscall_%lu", tcp->scno);
2356 else
2357 tprintf("%s", sysent[tcp->scno].sys_name);
2358 tprintf(" resumed> ");
2359 }
2360
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002361 if (cflag)
2362 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002363
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002364 if (res != 1) {
2365 tprintf(") ");
2366 tabto(acolumn);
2367 tcp->flags &= ~TCB_INSYSCALL;
2368 return res;
2369 }
2370
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002371 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002372 || (qual_flags[tcp->scno] & QUAL_RAW))
2373 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002374 else {
2375 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002376 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002377 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002378 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002379 u_error = tcp->u_error;
2380 tprintf(") ");
2381 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002382 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2383 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002384 if (u_error)
2385 tprintf("= -1 (errno %ld)", u_error);
2386 else
2387 tprintf("= %#lx", tcp->u_rval);
2388 }
2389 else if (!(sys_res & RVAL_NONE) && u_error) {
2390 switch (u_error) {
2391#ifdef LINUX
2392 case ERESTARTSYS:
2393 tprintf("= ? ERESTARTSYS (To be restarted)");
2394 break;
2395 case ERESTARTNOINTR:
2396 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2397 break;
2398 case ERESTARTNOHAND:
2399 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2400 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002401 case ERESTART_RESTARTBLOCK:
2402 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2403 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002404#endif /* LINUX */
2405 default:
2406 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002407 if (u_error < 0)
2408 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002409 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002410 tprintf("%s (%s)", errnoent[u_error],
2411 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002412 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002413 tprintf("ERRNO_%ld (%s)", u_error,
2414 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002415 break;
2416 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002417 if ((sys_res & RVAL_STR) && tcp->auxstr)
2418 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002419 }
2420 else {
2421 if (sys_res & RVAL_NONE)
2422 tprintf("= ?");
2423 else {
2424 switch (sys_res & RVAL_MASK) {
2425 case RVAL_HEX:
2426 tprintf("= %#lx", tcp->u_rval);
2427 break;
2428 case RVAL_OCTAL:
2429 tprintf("= %#lo", tcp->u_rval);
2430 break;
2431 case RVAL_UDECIMAL:
2432 tprintf("= %lu", tcp->u_rval);
2433 break;
2434 case RVAL_DECIMAL:
2435 tprintf("= %ld", tcp->u_rval);
2436 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002437#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002438 case RVAL_LHEX:
2439 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002440 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002441 case RVAL_LOCTAL:
2442 tprintf("= %#llo", tcp->u_lrval);
2443 break;
2444 case RVAL_LUDECIMAL:
2445 tprintf("= %llu", tcp->u_lrval);
2446 break;
2447 case RVAL_LDECIMAL:
2448 tprintf("= %lld", tcp->u_lrval);
2449 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002450#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002451 default:
2452 fprintf(stderr,
2453 "invalid rval format\n");
2454 break;
2455 }
2456 }
2457 if ((sys_res & RVAL_STR) && tcp->auxstr)
2458 tprintf(" (%s)", tcp->auxstr);
2459 }
2460 if (dtime) {
2461 tv_sub(&tv, &tv, &tcp->etime);
2462 tprintf(" <%ld.%06ld>",
2463 (long) tv.tv_sec, (long) tv.tv_usec);
2464 }
2465 printtrailer(tcp);
2466
2467 dumpio(tcp);
2468 if (fflush(tcp->outf) == EOF)
2469 return -1;
2470 tcp->flags &= ~TCB_INSYSCALL;
2471 return 0;
2472 }
2473
2474 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002475 scno_good = res = get_scno(tcp);
2476 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002477 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002478 if (res == 1)
2479 res = syscall_fixup(tcp);
2480 if (res == 0)
2481 return res;
2482 if (res == 1)
2483 res = syscall_enter(tcp);
2484 if (res == 0)
2485 return res;
2486
2487 if (res != 1) {
2488 printleader(tcp);
2489 tcp->flags &= ~TCB_REPRINT;
2490 tcp_last = tcp;
2491 if (scno_good != 1)
2492 tprintf("????" /* anti-trigraph gap */ "(");
2493 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2494 tprintf("syscall_%lu(", tcp->scno);
2495 else
2496 tprintf("%s(", sysent[tcp->scno].sys_name);
2497 /*
2498 * " <unavailable>" will be added later by the code which
2499 * detects ptrace errors.
2500 */
2501 tcp->flags |= TCB_INSYSCALL;
2502 return res;
2503 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002504
Roland McGrath17352792005-06-07 23:21:26 +00002505 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002506#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002507 case SYS_socketcall:
2508 decode_subcall(tcp, SYS_socket_subcall,
2509 SYS_socket_nsubcalls, deref_style);
2510 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002511#endif
2512#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002513 case SYS_ipc:
2514 decode_subcall(tcp, SYS_ipc_subcall,
2515 SYS_ipc_nsubcalls, shift_style);
2516 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002517#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002518#ifdef SVR4
2519#ifdef SYS_pgrpsys_subcall
2520 case SYS_pgrpsys:
2521 decode_subcall(tcp, SYS_pgrpsys_subcall,
2522 SYS_pgrpsys_nsubcalls, shift_style);
2523 break;
2524#endif /* SYS_pgrpsys_subcall */
2525#ifdef SYS_sigcall_subcall
2526 case SYS_sigcall:
2527 decode_subcall(tcp, SYS_sigcall_subcall,
2528 SYS_sigcall_nsubcalls, mask_style);
2529 break;
2530#endif /* SYS_sigcall_subcall */
2531 case SYS_msgsys:
2532 decode_subcall(tcp, SYS_msgsys_subcall,
2533 SYS_msgsys_nsubcalls, shift_style);
2534 break;
2535 case SYS_shmsys:
2536 decode_subcall(tcp, SYS_shmsys_subcall,
2537 SYS_shmsys_nsubcalls, shift_style);
2538 break;
2539 case SYS_semsys:
2540 decode_subcall(tcp, SYS_semsys_subcall,
2541 SYS_semsys_nsubcalls, shift_style);
2542 break;
2543#if 0 /* broken */
2544 case SYS_utssys:
2545 decode_subcall(tcp, SYS_utssys_subcall,
2546 SYS_utssys_nsubcalls, shift_style);
2547 break;
2548#endif
2549 case SYS_sysfs:
2550 decode_subcall(tcp, SYS_sysfs_subcall,
2551 SYS_sysfs_nsubcalls, shift_style);
2552 break;
2553 case SYS_spcall:
2554 decode_subcall(tcp, SYS_spcall_subcall,
2555 SYS_spcall_nsubcalls, shift_style);
2556 break;
2557#ifdef SYS_context_subcall
2558 case SYS_context:
2559 decode_subcall(tcp, SYS_context_subcall,
2560 SYS_context_nsubcalls, shift_style);
2561 break;
2562#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002563#ifdef SYS_door_subcall
2564 case SYS_door:
2565 decode_subcall(tcp, SYS_door_subcall,
2566 SYS_door_nsubcalls, door_style);
2567 break;
2568#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002569#ifdef SYS_kaio_subcall
2570 case SYS_kaio:
2571 decode_subcall(tcp, SYS_kaio_subcall,
2572 SYS_kaio_nsubcalls, shift_style);
2573 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002574#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002575#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002576#ifdef FREEBSD
2577 case SYS_msgsys:
2578 case SYS_shmsys:
2579 case SYS_semsys:
2580 decode_subcall(tcp, 0, 0, table_style);
2581 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002582#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002583#ifdef SUNOS4
2584 case SYS_semsys:
2585 decode_subcall(tcp, SYS_semsys_subcall,
2586 SYS_semsys_nsubcalls, shift_style);
2587 break;
2588 case SYS_msgsys:
2589 decode_subcall(tcp, SYS_msgsys_subcall,
2590 SYS_msgsys_nsubcalls, shift_style);
2591 break;
2592 case SYS_shmsys:
2593 decode_subcall(tcp, SYS_shmsys_subcall,
2594 SYS_shmsys_nsubcalls, shift_style);
2595 break;
2596#endif
2597 }
2598
2599 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002600 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002601 tcp->flags |= TCB_INSYSCALL;
2602 return 0;
2603 }
2604
2605 if (cflag) {
2606 gettimeofday(&tcp->etime, NULL);
2607 tcp->flags |= TCB_INSYSCALL;
2608 return 0;
2609 }
2610
2611 printleader(tcp);
2612 tcp->flags &= ~TCB_REPRINT;
2613 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002614 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615 tprintf("syscall_%lu(", tcp->scno);
2616 else
2617 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002618 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002619 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2620 sys_res = printargs(tcp);
2621 else
2622 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2623 if (fflush(tcp->outf) == EOF)
2624 return -1;
2625 tcp->flags |= TCB_INSYSCALL;
2626 /* Measure the entrance time as late as possible to avoid errors. */
2627 if (dtime)
2628 gettimeofday(&tcp->etime, NULL);
2629 return sys_res;
2630}
2631
2632int
2633printargs(tcp)
2634struct tcb *tcp;
2635{
2636 if (entering(tcp)) {
2637 int i;
2638
2639 for (i = 0; i < tcp->u_nargs; i++)
2640 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2641 }
2642 return 0;
2643}
2644
2645long
2646getrval2(tcp)
2647struct tcb *tcp;
2648{
2649 long val = -1;
2650
2651#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002652#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002653 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002654 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2655 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002656 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002657#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002658 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002659 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002660#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002661 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002662 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002663#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002664#endif /* LINUX */
2665
2666#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002667 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002668 return -1;
2669#endif /* SUNOS4 */
2670
2671#ifdef SVR4
2672#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002673 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002674#endif /* SPARC */
2675#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002676 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002677#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002678#ifdef X86_64
2679 val = tcp->status.PR_REG[RDX];
2680#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002681#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002682 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002683#endif /* MIPS */
2684#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002685#ifdef FREEBSD
2686 struct reg regs;
2687 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2688 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002689#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002690 return val;
2691}
2692
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002693#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694/*
2695 * Apparently, indirect system calls have already be converted by ptrace(2),
2696 * so if you see "indir" this program has gone astray.
2697 */
2698int
2699sys_indir(tcp)
2700struct tcb *tcp;
2701{
2702 int i, scno, nargs;
2703
2704 if (entering(tcp)) {
2705 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2706 fprintf(stderr, "Bogus syscall: %u\n", scno);
2707 return 0;
2708 }
2709 nargs = sysent[scno].nargs;
2710 tprintf("%s", sysent[scno].sys_name);
2711 for (i = 0; i < nargs; i++)
2712 tprintf(", %#lx", tcp->u_arg[i+1]);
2713 }
2714 return 0;
2715}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002716#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002717
2718int
2719is_restart_error(struct tcb *tcp)
2720{
2721#ifdef LINUX
2722 if (!syserror(tcp))
2723 return 0;
2724 switch (tcp->u_error) {
2725 case ERESTARTSYS:
2726 case ERESTARTNOINTR:
2727 case ERESTARTNOHAND:
2728 case ERESTART_RESTARTBLOCK:
2729 return 1;
2730 default:
2731 break;
2732 }
2733#endif /* LINUX */
2734 return 0;
2735}