blob: 273b3c801d108a3e988ef97a20065d6d2e97eac6 [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
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001338/* Called in trace_syscall() at each syscall entry and exit.
1339 * Returns:
1340 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1341 * 1: ok, continue in trace_syscall().
1342 * other: error, trace_syscall() should print error indicator
1343 * ("????" etc) and bail out.
1344 */
Roland McGratha4d48532005-06-08 20:45:28 +00001345static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001346syscall_fixup(tcp)
1347struct tcb *tcp;
1348{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001349#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001350 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001351
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001352 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001353 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354 if (
1355 scno == SYS_fork
1356#ifdef SYS_vfork
1357 || scno == SYS_vfork
1358#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001359#ifdef SYS_fork1
1360 || scno == SYS_fork1
1361#endif /* SYS_fork1 */
1362#ifdef SYS_forkall
1363 || scno == SYS_forkall
1364#endif /* SYS_forkall */
1365#ifdef SYS_rfork1
1366 || scno == SYS_rfork1
1367#endif /* SYS_fork1 */
1368#ifdef SYS_rforkall
1369 || scno == SYS_rforkall
1370#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371 ) {
1372 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001373 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001375 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376 }
1377 else {
1378 fprintf(stderr, "syscall: missing entry\n");
1379 tcp->flags |= TCB_INSYSCALL;
1380 }
1381 }
1382 }
1383 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001384 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001385 fprintf(stderr, "syscall: missing exit\n");
1386 tcp->flags &= ~TCB_INSYSCALL;
1387 }
1388 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001389#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001390#ifdef SUNOS4
1391 if (!(tcp->flags & TCB_INSYSCALL)) {
1392 if (scno == 0) {
1393 fprintf(stderr, "syscall: missing entry\n");
1394 tcp->flags |= TCB_INSYSCALL;
1395 }
1396 }
1397 else {
1398 if (scno != 0) {
1399 if (debug) {
1400 /*
1401 * This happens when a signal handler
1402 * for a signal which interrupted a
1403 * a system call makes another system call.
1404 */
1405 fprintf(stderr, "syscall: missing exit\n");
1406 }
1407 tcp->flags &= ~TCB_INSYSCALL;
1408 }
1409 }
1410#endif /* SUNOS4 */
1411#ifdef LINUX
1412#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001413 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001414 return -1;
1415 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1416 if (debug)
1417 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1418 return 0;
1419 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001420#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001421 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001422 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001423 if (current_personality == 1)
1424 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001425 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1426 if (debug)
1427 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1428 return 0;
1429 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001430#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001431 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001432 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001433 if (syscall_mode != -ENOSYS)
1434 syscall_mode = tcp->scno;
1435 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001436 if (debug)
1437 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1438 return 0;
1439 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001440 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1441 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1442 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1443 /*
1444 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1445 * flag set for the post-execve SIGTRAP to see and reset.
1446 */
1447 gpr2 = 0;
1448 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001449#elif defined (POWERPC)
1450# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001451 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001453 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454 return -1;
1455 if (flags & SO_MASK)
1456 result = -result;
1457#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001458 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001459 return -1;
1460 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1461 if (debug)
1462 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1463 return 0;
1464 }
1465#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001466 /*
1467 * Nothing required
1468 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001469#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001470 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001471 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001472#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001473 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001474 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001475#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001476 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001477 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001478 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001479 return -1;
1480 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1481 if (debug)
1482 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1483 return 0;
1484 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001485#endif
1486#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001487 return 1;
1488}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001489
Roland McGrathc1e45922008-05-27 23:18:29 +00001490#ifdef LINUX
1491/*
1492 * Check the syscall return value register value for whether it is
1493 * a negated errno code indicating an error, or a success return value.
1494 */
1495static inline int
1496is_negated_errno(unsigned long int val)
1497{
1498 unsigned long int max = -(long int) nerrnos;
1499 if (personality_wordsize[current_personality] < sizeof(val)) {
1500 val = (unsigned int) val;
1501 max = (unsigned int) max;
1502 }
1503 return val > max;
1504}
1505#endif
1506
Roland McGratha4d48532005-06-08 20:45:28 +00001507static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001508get_error(tcp)
1509struct tcb *tcp;
1510{
1511 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001512#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001513#if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001514 if (is_negated_errno(gpr2)) {
1515 tcp->u_rval = -1;
1516 u_error = -gpr2;
1517 }
1518 else {
1519 tcp->u_rval = gpr2;
1520 u_error = 0;
1521 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001522#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001523#ifdef I386
Roland McGrathc1e45922008-05-27 23:18:29 +00001524 if (is_negated_errno(eax)) {
1525 tcp->u_rval = -1;
1526 u_error = -eax;
1527 }
1528 else {
1529 tcp->u_rval = eax;
1530 u_error = 0;
1531 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001532#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001533#ifdef X86_64
Roland McGrathc1e45922008-05-27 23:18:29 +00001534 if (is_negated_errno(rax)) {
1535 tcp->u_rval = -1;
1536 u_error = -rax;
1537 }
1538 else {
1539 tcp->u_rval = rax;
1540 u_error = 0;
1541 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001542#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001543#ifdef IA64
Roland McGrathc1e45922008-05-27 23:18:29 +00001544 if (ia32) {
1545 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001546
Roland McGrathc1e45922008-05-27 23:18:29 +00001547 err = (int)r8;
1548 if (is_negated_errno(err)) {
1549 tcp->u_rval = -1;
1550 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001551 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001552 else {
1553 tcp->u_rval = err;
1554 u_error = 0;
1555 }
1556 } else {
1557 if (r10) {
1558 tcp->u_rval = -1;
1559 u_error = r8;
1560 } else {
1561 tcp->u_rval = r8;
1562 u_error = 0;
1563 }
1564 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001565#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001566#ifdef MIPS
1567 if (a3) {
1568 tcp->u_rval = -1;
1569 u_error = r2;
1570 } else {
1571 tcp->u_rval = r2;
1572 u_error = 0;
1573 }
1574#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001575#ifdef POWERPC
Roland McGrathc1e45922008-05-27 23:18:29 +00001576 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001577 tcp->u_rval = -1;
1578 u_error = -result;
1579 }
1580 else {
1581 tcp->u_rval = result;
1582 u_error = 0;
1583 }
1584#else /* !POWERPC */
1585#ifdef M68K
Roland McGrathc1e45922008-05-27 23:18:29 +00001586 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587 tcp->u_rval = -1;
1588 u_error = -d0;
1589 }
1590 else {
1591 tcp->u_rval = d0;
1592 u_error = 0;
1593 }
1594#else /* !M68K */
1595#ifdef ARM
Roland McGrathc1e45922008-05-27 23:18:29 +00001596 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001597 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001598 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599 }
1600 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001601 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602 u_error = 0;
1603 }
1604#else /* !ARM */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001605#ifdef BFIN
1606 if (is_negated_errno(r0)) {
1607 tcp->u_rval = -1;
1608 u_error = -r0;
1609 } else {
1610 tcp->u_rval = r0;
1611 u_error = 0;
1612 }
1613#else /* !BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614#ifdef ALPHA
1615 if (a3) {
1616 tcp->u_rval = -1;
1617 u_error = r0;
1618 }
1619 else {
1620 tcp->u_rval = r0;
1621 u_error = 0;
1622 }
1623#else /* !ALPHA */
1624#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001625 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001626 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001627 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 }
1629 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001630 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631 u_error = 0;
1632 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001633#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001634#ifdef SPARC64
1635 if (regs.r_tstate & 0x1100000000UL) {
1636 tcp->u_rval = -1;
1637 u_error = regs.r_o0;
1638 }
1639 else {
1640 tcp->u_rval = regs.r_o0;
1641 u_error = 0;
1642 }
1643#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001644#ifdef HPPA
Roland McGrathc1e45922008-05-27 23:18:29 +00001645 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001646 tcp->u_rval = -1;
1647 u_error = -r28;
1648 }
1649 else {
1650 tcp->u_rval = r28;
1651 u_error = 0;
1652 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001653#else
1654#ifdef SH
Roland McGrathc1e45922008-05-27 23:18:29 +00001655 /* interpret R0 as return value or error number */
1656 if (is_negated_errno(r0)) {
1657 tcp->u_rval = -1;
1658 u_error = -r0;
1659 }
1660 else {
1661 tcp->u_rval = r0;
1662 u_error = 0;
1663 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001664#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001665#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001666 /* interpret result as return value or error number */
1667 if (is_negated_errno(r9)) {
1668 tcp->u_rval = -1;
1669 u_error = -r9;
1670 }
1671 else {
1672 tcp->u_rval = r9;
1673 u_error = 0;
1674 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001675#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001676#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001677#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001678#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001679#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001680#endif /* ALPHA */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001681#endif /* BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001682#endif /* ARM */
1683#endif /* M68K */
1684#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001685#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001686#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001687#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001688#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001689#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001690#endif /* LINUX */
1691#ifdef SUNOS4
1692 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001693 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001694 return -1;
1695 u_error >>= 24; /* u_error is a char */
1696
1697 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001698 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699 return -1;
1700#endif /* SUNOS4 */
1701#ifdef SVR4
1702#ifdef SPARC
1703 /* Judicious guessing goes a long way. */
1704 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1705 tcp->u_rval = -1;
1706 u_error = tcp->status.pr_reg[R_O0];
1707 }
1708 else {
1709 tcp->u_rval = tcp->status.pr_reg[R_O0];
1710 u_error = 0;
1711 }
1712#endif /* SPARC */
1713#ifdef I386
1714 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001715 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001717 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718 }
1719 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001720 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001721#ifdef HAVE_LONG_LONG
1722 tcp->u_lrval =
1723 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1724 tcp->status.PR_REG[EAX];
1725#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001726 u_error = 0;
1727 }
1728#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001729#ifdef X86_64
1730 /* Wanna know how to kill an hour single-stepping? */
1731 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1732 tcp->u_rval = -1;
1733 u_error = tcp->status.PR_REG[RAX];
1734 }
1735 else {
1736 tcp->u_rval = tcp->status.PR_REG[RAX];
1737 u_error = 0;
1738 }
1739#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001740#ifdef MIPS
1741 if (tcp->status.pr_reg[CTX_A3]) {
1742 tcp->u_rval = -1;
1743 u_error = tcp->status.pr_reg[CTX_V0];
1744 }
1745 else {
1746 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1747 u_error = 0;
1748 }
1749#endif /* MIPS */
1750#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001751#ifdef FREEBSD
1752 if (regs.r_eflags & PSL_C) {
1753 tcp->u_rval = -1;
1754 u_error = regs.r_eax;
1755 } else {
1756 tcp->u_rval = regs.r_eax;
1757 tcp->u_lrval =
1758 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1759 u_error = 0;
1760 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001761#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001762 tcp->u_error = u_error;
1763 return 1;
1764}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001765
Roland McGrathb69f81b2002-12-21 23:25:18 +00001766int
1767force_result(tcp, error, rval)
1768 struct tcb *tcp;
1769 int error;
1770 long rval;
1771{
1772#ifdef LINUX
1773#if defined(S390) || defined(S390X)
1774 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001775 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1776 return -1;
1777#else /* !S390 && !S390X */
1778#ifdef I386
1779 eax = error ? -error : rval;
1780 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1781 return -1;
1782#else /* !I386 */
1783#ifdef X86_64
1784 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001785 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001786 return -1;
1787#else
1788#ifdef IA64
1789 if (ia32) {
1790 r8 = error ? -error : rval;
1791 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1792 return -1;
1793 }
1794 else {
1795 if (error) {
1796 r8 = error;
1797 r10 = -1;
1798 }
1799 else {
1800 r8 = rval;
1801 r10 = 0;
1802 }
1803 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1804 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1805 return -1;
1806 }
1807#else /* !IA64 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001808#ifdef BFIN
1809 r0 = error ? -error : rval;
1810 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1811 return -1;
1812#else /* !BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001813#ifdef MIPS
1814 if (error) {
1815 r2 = error;
1816 a3 = -1;
1817 }
1818 else {
1819 r2 = rval;
1820 a3 = 0;
1821 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001822 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001823 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1824 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1825 return -1;
1826#else
1827#ifdef POWERPC
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001828 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001829 return -1;
1830 if (error) {
1831 flags |= SO_MASK;
1832 result = error;
1833 }
1834 else {
1835 flags &= ~SO_MASK;
1836 result = rval;
1837 }
Roland McGratheb285352003-01-14 09:59:00 +00001838 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1839 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001840 return -1;
1841#else /* !POWERPC */
1842#ifdef M68K
1843 d0 = error ? -error : rval;
1844 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1845 return -1;
1846#else /* !M68K */
1847#ifdef ARM
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001848 regs.ARM_r0 = error ? -error : rval;
1849 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001850 return -1;
1851#else /* !ARM */
1852#ifdef ALPHA
1853 if (error) {
1854 a3 = -1;
1855 r0 = error;
1856 }
1857 else {
1858 a3 = 0;
1859 r0 = rval;
1860 }
1861 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1862 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1863 return -1;
1864#else /* !ALPHA */
1865#ifdef SPARC
1866 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1867 return -1;
1868 if (error) {
1869 regs.r_psr |= PSR_C;
1870 regs.r_o0 = error;
1871 }
1872 else {
1873 regs.r_psr &= ~PSR_C;
1874 regs.r_o0 = rval;
1875 }
1876 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1877 return -1;
1878#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001879#ifdef SPARC64
1880 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1881 return -1;
1882 if (error) {
1883 regs.r_tstate |= 0x1100000000UL;
1884 regs.r_o0 = error;
1885 }
1886 else {
1887 regs.r_tstate &= ~0x1100000000UL;
1888 regs.r_o0 = rval;
1889 }
1890 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1891 return -1;
1892#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001893#ifdef HPPA
1894 r28 = error ? -error : rval;
1895 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1896 return -1;
1897#else
1898#ifdef SH
1899 r0 = error ? -error : rval;
1900 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1901 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001902#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001903#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001904 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001905 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1906 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001907#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001908#endif /* SH */
1909#endif /* HPPA */
1910#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001911#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001912#endif /* ALPHA */
1913#endif /* ARM */
1914#endif /* M68K */
1915#endif /* POWERPC */
1916#endif /* MIPS */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001917#endif /* BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001918#endif /* IA64 */
1919#endif /* X86_64 */
1920#endif /* I386 */
1921#endif /* S390 || S390X */
1922#endif /* LINUX */
1923#ifdef SUNOS4
1924 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1925 error << 24) < 0 ||
1926 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1927 return -1;
1928#endif /* SUNOS4 */
1929#ifdef SVR4
1930 /* XXX no clue */
1931 return -1;
1932#endif /* SVR4 */
1933#ifdef FREEBSD
1934 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001935 perror("pread");
1936 return -1;
1937 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001938 if (error) {
1939 regs.r_eflags |= PSL_C;
1940 regs.r_eax = error;
1941 }
1942 else {
1943 regs.r_eflags &= ~PSL_C;
1944 regs.r_eax = rval;
1945 }
1946 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001947 perror("pwrite");
1948 return -1;
1949 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001950#endif /* FREEBSD */
1951
1952 /* All branches reach here on success (only). */
1953 tcp->u_error = error;
1954 tcp->u_rval = rval;
1955 return 0;
1956}
1957
Roland McGratha4d48532005-06-08 20:45:28 +00001958static int
1959syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001960struct tcb *tcp;
1961{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001962#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001963#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001964 {
1965 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001966 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1967 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001968 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001969 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001970 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001971 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001972 return -1;
1973 }
1974 }
1975#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001976 {
1977 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001978 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1979 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001980 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001981 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001982 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001983 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1984 * for scno somewhere above here!
1985 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001986 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001987 return -1;
1988 }
1989 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001990#elif defined (IA64)
1991 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001992 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001993 unsigned long *out0, cfm, sof, sol, i;
1994 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001995 /* be backwards compatible with kernel < 2.4.4... */
1996# ifndef PT_RBS_END
1997# define PT_RBS_END PT_AR_BSP
1998# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001999
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002000 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002001 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002002 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002003 return -1;
2004
2005 sof = (cfm >> 0) & 0x7f;
2006 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002007 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002008
2009 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2010 && sysent[tcp->scno].nargs != -1)
2011 tcp->u_nargs = sysent[tcp->scno].nargs;
2012 else
2013 tcp->u_nargs = MAX_ARGS;
2014 for (i = 0; i < tcp->u_nargs; ++i) {
2015 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2016 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2017 return -1;
2018 }
2019 } else {
2020 int i;
2021
2022 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002023 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002024 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002025 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002026 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002027 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002028 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002029 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002030 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002031 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002032 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002033 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002034 return -1;
2035
2036 for (i = 0; i < 6; ++i)
2037 /* truncate away IVE sign-extension */
2038 tcp->u_arg[i] &= 0xffffffff;
2039
2040 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2041 && sysent[tcp->scno].nargs != -1)
2042 tcp->u_nargs = sysent[tcp->scno].nargs;
2043 else
2044 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002045 }
2046 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002047#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2048 /* N32 and N64 both use up to six registers. */
2049 {
2050 unsigned long long regs[38];
2051 int i, nargs;
2052
2053 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2054 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002055 else
Roland McGrath542c2c62008-05-20 01:11:56 +00002056 nargs = tcp->u_nargs = MAX_ARGS;
2057
2058 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
2059 return -1;
2060
2061 for(i = 0; i < nargs; i++) {
2062 tcp->u_arg[i] = regs[REG_A0 + i];
2063# if defined (LINUX_MIPSN32)
2064 tcp->ext_arg[i] = regs[REG_A0 + i];
2065# endif
2066 }
2067 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002068#elif defined (MIPS)
2069 {
2070 long sp;
2071 int i, nargs;
2072
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002073 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2074 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002075 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002076 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002077 if(nargs > 4) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002078 if(upeek(tcp, REG_SP, &sp) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002079 return -1;
2080 for(i = 0; i < 4; 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 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2085 (char *)(tcp->u_arg + 4));
2086 } else {
2087 for(i = 0; i < nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002088 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002089 return -1;
2090 }
2091 }
2092 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002093#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002094#ifndef PT_ORIG_R3
2095#define PT_ORIG_R3 34
2096#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002097 {
2098 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002099 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2100 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002101 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002102 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002103 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002104 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002105 (sizeof(unsigned long)*PT_ORIG_R3) :
2106 ((i+PT_R3)*sizeof(unsigned long)),
2107 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002108 return -1;
2109 }
2110 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002111#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002112 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002113 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002114
2115 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2116 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002117 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002118 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002119 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002120 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002121 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002122#elif defined (HPPA)
2123 {
2124 int i;
2125
2126 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2127 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002128 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002129 tcp->u_nargs = MAX_ARGS;
2130 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002131 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002132 return -1;
2133 }
2134 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002135#elif defined(ARM)
2136 {
2137 int i;
2138
2139 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2140 tcp->u_nargs = sysent[tcp->scno].nargs;
2141 else
2142 tcp->u_nargs = MAX_ARGS;
2143 for (i = 0; i < tcp->u_nargs; i++)
2144 tcp->u_arg[i] = regs.uregs[i];
2145 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002146#elif defined(BFIN)
2147 {
2148 int i;
2149 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2150
2151 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2152 tcp->u_nargs = sysent[tcp->scno].nargs;
2153 else
2154 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2155
2156 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002157 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002158 return -1;
2159 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002160#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002161 {
2162 int i;
2163 static int syscall_regs[] = {
2164 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2165 REG_REG0, REG_REG0+1, REG_REG0+2
2166 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002167
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002168 tcp->u_nargs = sysent[tcp->scno].nargs;
2169 for (i = 0; i < tcp->u_nargs; i++) {
2170 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2171 return -1;
2172 }
2173 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002174#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002175 {
2176 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002177 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002178 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2179
2180 /*
2181 * TODO: should also check that the number of arguments encoded
2182 * in the trap number matches the number strace expects.
2183 */
2184 /*
2185 assert(sysent[tcp->scno].nargs <
2186 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2187 */
2188
2189 tcp->u_nargs = sysent[tcp->scno].nargs;
2190 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002191 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002192 return -1;
2193 }
2194 }
2195
Michal Ludvig0e035502002-09-23 15:41:01 +00002196#elif defined(X86_64)
2197 {
2198 int i;
2199 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2200 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002201 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002202 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002203
Michal Ludvig0e035502002-09-23 15:41:01 +00002204 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2205 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002206 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002207 tcp->u_nargs = MAX_ARGS;
2208 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002209 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002210 return -1;
2211 }
2212 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002213#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002214 {
2215 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002216 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2217 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002218 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002219 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002220 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002221 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002222 return -1;
2223 }
2224 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002225#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002226#endif /* LINUX */
2227#ifdef SUNOS4
2228 {
2229 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002230 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2231 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002232 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002233 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002234 for (i = 0; i < tcp->u_nargs; i++) {
2235 struct user *u;
2236
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002237 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002238 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2239 return -1;
2240 }
2241 }
2242#endif /* SUNOS4 */
2243#ifdef SVR4
2244#ifdef MIPS
2245 /*
2246 * SGI is broken: even though it has pr_sysarg, it doesn't
2247 * set them on system call entry. Get a clue.
2248 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002249 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002250 tcp->u_nargs = sysent[tcp->scno].nargs;
2251 else
2252 tcp->u_nargs = tcp->status.pr_nsysarg;
2253 if (tcp->u_nargs > 4) {
2254 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2255 4*sizeof(tcp->u_arg[0]));
2256 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2257 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2258 }
2259 else {
2260 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2261 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2262 }
John Hughes25299712001-03-06 10:10:06 +00002263#elif UNIXWARE >= 2
2264 /*
2265 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2266 */
2267 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2268 tcp->u_nargs = sysent[tcp->scno].nargs;
2269 else
2270 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2271 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2272 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2273#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002274 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002275 tcp->u_nargs = sysent[tcp->scno].nargs;
2276 else
2277 tcp->u_nargs = tcp->status.pr_nsysarg;
2278 {
2279 int i;
2280 for (i = 0; i < tcp->u_nargs; i++)
2281 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2282 }
John Hughes25299712001-03-06 10:10:06 +00002283#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002284 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002285 tcp->u_nargs = sysent[tcp->scno].nargs;
2286 else
2287 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002288 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002289 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002290#else
2291 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002292#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002294#ifdef FREEBSD
2295 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2296 sysent[tcp->scno].nargs > tcp->status.val)
2297 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002298 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002299 tcp->u_nargs = tcp->status.val;
2300 if (tcp->u_nargs < 0)
2301 tcp->u_nargs = 0;
2302 if (tcp->u_nargs > MAX_ARGS)
2303 tcp->u_nargs = MAX_ARGS;
2304 switch(regs.r_eax) {
2305 case SYS___syscall:
2306 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2307 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002308 break;
2309 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002310 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2311 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002312 break;
2313 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002314 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2315 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002316 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002317 }
2318#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002319 return 1;
2320}
2321
2322int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002323trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002324{
2325 int sys_res;
2326 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002327 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002328
2329 if (tcp->flags & TCB_INSYSCALL) {
2330 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002331
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002332 /* Measure the exit time as early as possible to avoid errors. */
2333 if (dtime)
2334 gettimeofday(&tv, NULL);
2335
2336 scno_good = res = get_scno(tcp);
2337 if (res == 0)
2338 return res;
2339 if (res == 1)
2340 res = syscall_fixup(tcp);
2341 if (res == 0)
2342 return res;
2343 if (res == 1)
2344 res = get_error(tcp);
2345 if (res == 0)
2346 return res;
2347 if (res == 1)
2348 internal_syscall(tcp);
2349
2350 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002351 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002352 tcp->flags &= ~TCB_INSYSCALL;
2353 return 0;
2354 }
2355
2356 if (tcp->flags & TCB_REPRINT) {
2357 printleader(tcp);
2358 tprintf("<... ");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002359 if (scno_good != 1)
2360 tprintf("????");
2361 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002362 tprintf("syscall_%lu", tcp->scno);
2363 else
2364 tprintf("%s", sysent[tcp->scno].sys_name);
2365 tprintf(" resumed> ");
2366 }
2367
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002368 if (cflag)
2369 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002370
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002371 if (res != 1) {
2372 tprintf(") ");
2373 tabto(acolumn);
2374 tcp->flags &= ~TCB_INSYSCALL;
2375 return res;
2376 }
2377
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002378 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002379 || (qual_flags[tcp->scno] & QUAL_RAW))
2380 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002381 else {
2382 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002383 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002384 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002385 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002386 u_error = tcp->u_error;
2387 tprintf(") ");
2388 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002389 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2390 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002391 if (u_error)
2392 tprintf("= -1 (errno %ld)", u_error);
2393 else
2394 tprintf("= %#lx", tcp->u_rval);
2395 }
2396 else if (!(sys_res & RVAL_NONE) && u_error) {
2397 switch (u_error) {
2398#ifdef LINUX
2399 case ERESTARTSYS:
2400 tprintf("= ? ERESTARTSYS (To be restarted)");
2401 break;
2402 case ERESTARTNOINTR:
2403 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2404 break;
2405 case ERESTARTNOHAND:
2406 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2407 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002408 case ERESTART_RESTARTBLOCK:
2409 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2410 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002411#endif /* LINUX */
2412 default:
2413 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002414 if (u_error < 0)
2415 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002416 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002417 tprintf("%s (%s)", errnoent[u_error],
2418 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002419 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002420 tprintf("ERRNO_%ld (%s)", u_error,
2421 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002422 break;
2423 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002424 if ((sys_res & RVAL_STR) && tcp->auxstr)
2425 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002426 }
2427 else {
2428 if (sys_res & RVAL_NONE)
2429 tprintf("= ?");
2430 else {
2431 switch (sys_res & RVAL_MASK) {
2432 case RVAL_HEX:
2433 tprintf("= %#lx", tcp->u_rval);
2434 break;
2435 case RVAL_OCTAL:
2436 tprintf("= %#lo", tcp->u_rval);
2437 break;
2438 case RVAL_UDECIMAL:
2439 tprintf("= %lu", tcp->u_rval);
2440 break;
2441 case RVAL_DECIMAL:
2442 tprintf("= %ld", tcp->u_rval);
2443 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002444#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002445 case RVAL_LHEX:
2446 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002447 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002448 case RVAL_LOCTAL:
2449 tprintf("= %#llo", tcp->u_lrval);
2450 break;
2451 case RVAL_LUDECIMAL:
2452 tprintf("= %llu", tcp->u_lrval);
2453 break;
2454 case RVAL_LDECIMAL:
2455 tprintf("= %lld", tcp->u_lrval);
2456 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002457#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002458 default:
2459 fprintf(stderr,
2460 "invalid rval format\n");
2461 break;
2462 }
2463 }
2464 if ((sys_res & RVAL_STR) && tcp->auxstr)
2465 tprintf(" (%s)", tcp->auxstr);
2466 }
2467 if (dtime) {
2468 tv_sub(&tv, &tv, &tcp->etime);
2469 tprintf(" <%ld.%06ld>",
2470 (long) tv.tv_sec, (long) tv.tv_usec);
2471 }
2472 printtrailer(tcp);
2473
2474 dumpio(tcp);
2475 if (fflush(tcp->outf) == EOF)
2476 return -1;
2477 tcp->flags &= ~TCB_INSYSCALL;
2478 return 0;
2479 }
2480
2481 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002482 scno_good = res = get_scno(tcp);
2483 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002484 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002485 if (res == 1)
2486 res = syscall_fixup(tcp);
2487 if (res == 0)
2488 return res;
2489 if (res == 1)
2490 res = syscall_enter(tcp);
2491 if (res == 0)
2492 return res;
2493
2494 if (res != 1) {
2495 printleader(tcp);
2496 tcp->flags &= ~TCB_REPRINT;
2497 tcp_last = tcp;
2498 if (scno_good != 1)
2499 tprintf("????" /* anti-trigraph gap */ "(");
2500 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2501 tprintf("syscall_%lu(", tcp->scno);
2502 else
2503 tprintf("%s(", sysent[tcp->scno].sys_name);
2504 /*
2505 * " <unavailable>" will be added later by the code which
2506 * detects ptrace errors.
2507 */
2508 tcp->flags |= TCB_INSYSCALL;
2509 return res;
2510 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002511
Roland McGrath17352792005-06-07 23:21:26 +00002512 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002513#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002514 case SYS_socketcall:
2515 decode_subcall(tcp, SYS_socket_subcall,
2516 SYS_socket_nsubcalls, deref_style);
2517 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002518#endif
2519#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002520 case SYS_ipc:
2521 decode_subcall(tcp, SYS_ipc_subcall,
2522 SYS_ipc_nsubcalls, shift_style);
2523 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002524#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002525#ifdef SVR4
2526#ifdef SYS_pgrpsys_subcall
2527 case SYS_pgrpsys:
2528 decode_subcall(tcp, SYS_pgrpsys_subcall,
2529 SYS_pgrpsys_nsubcalls, shift_style);
2530 break;
2531#endif /* SYS_pgrpsys_subcall */
2532#ifdef SYS_sigcall_subcall
2533 case SYS_sigcall:
2534 decode_subcall(tcp, SYS_sigcall_subcall,
2535 SYS_sigcall_nsubcalls, mask_style);
2536 break;
2537#endif /* SYS_sigcall_subcall */
2538 case SYS_msgsys:
2539 decode_subcall(tcp, SYS_msgsys_subcall,
2540 SYS_msgsys_nsubcalls, shift_style);
2541 break;
2542 case SYS_shmsys:
2543 decode_subcall(tcp, SYS_shmsys_subcall,
2544 SYS_shmsys_nsubcalls, shift_style);
2545 break;
2546 case SYS_semsys:
2547 decode_subcall(tcp, SYS_semsys_subcall,
2548 SYS_semsys_nsubcalls, shift_style);
2549 break;
2550#if 0 /* broken */
2551 case SYS_utssys:
2552 decode_subcall(tcp, SYS_utssys_subcall,
2553 SYS_utssys_nsubcalls, shift_style);
2554 break;
2555#endif
2556 case SYS_sysfs:
2557 decode_subcall(tcp, SYS_sysfs_subcall,
2558 SYS_sysfs_nsubcalls, shift_style);
2559 break;
2560 case SYS_spcall:
2561 decode_subcall(tcp, SYS_spcall_subcall,
2562 SYS_spcall_nsubcalls, shift_style);
2563 break;
2564#ifdef SYS_context_subcall
2565 case SYS_context:
2566 decode_subcall(tcp, SYS_context_subcall,
2567 SYS_context_nsubcalls, shift_style);
2568 break;
2569#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002570#ifdef SYS_door_subcall
2571 case SYS_door:
2572 decode_subcall(tcp, SYS_door_subcall,
2573 SYS_door_nsubcalls, door_style);
2574 break;
2575#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002576#ifdef SYS_kaio_subcall
2577 case SYS_kaio:
2578 decode_subcall(tcp, SYS_kaio_subcall,
2579 SYS_kaio_nsubcalls, shift_style);
2580 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002581#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002582#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002583#ifdef FREEBSD
2584 case SYS_msgsys:
2585 case SYS_shmsys:
2586 case SYS_semsys:
2587 decode_subcall(tcp, 0, 0, table_style);
2588 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002589#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002590#ifdef SUNOS4
2591 case SYS_semsys:
2592 decode_subcall(tcp, SYS_semsys_subcall,
2593 SYS_semsys_nsubcalls, shift_style);
2594 break;
2595 case SYS_msgsys:
2596 decode_subcall(tcp, SYS_msgsys_subcall,
2597 SYS_msgsys_nsubcalls, shift_style);
2598 break;
2599 case SYS_shmsys:
2600 decode_subcall(tcp, SYS_shmsys_subcall,
2601 SYS_shmsys_nsubcalls, shift_style);
2602 break;
2603#endif
2604 }
2605
2606 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002607 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002608 tcp->flags |= TCB_INSYSCALL;
2609 return 0;
2610 }
2611
2612 if (cflag) {
2613 gettimeofday(&tcp->etime, NULL);
2614 tcp->flags |= TCB_INSYSCALL;
2615 return 0;
2616 }
2617
2618 printleader(tcp);
2619 tcp->flags &= ~TCB_REPRINT;
2620 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002621 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002622 tprintf("syscall_%lu(", tcp->scno);
2623 else
2624 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002625 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002626 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2627 sys_res = printargs(tcp);
2628 else
2629 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2630 if (fflush(tcp->outf) == EOF)
2631 return -1;
2632 tcp->flags |= TCB_INSYSCALL;
2633 /* Measure the entrance time as late as possible to avoid errors. */
2634 if (dtime)
2635 gettimeofday(&tcp->etime, NULL);
2636 return sys_res;
2637}
2638
2639int
2640printargs(tcp)
2641struct tcb *tcp;
2642{
2643 if (entering(tcp)) {
2644 int i;
2645
2646 for (i = 0; i < tcp->u_nargs; i++)
2647 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2648 }
2649 return 0;
2650}
2651
2652long
2653getrval2(tcp)
2654struct tcb *tcp;
2655{
2656 long val = -1;
2657
2658#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002659#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002660 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002661 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2662 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002663 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002664#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002665 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002666 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002667#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002668 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002669 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002670#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002671#endif /* LINUX */
2672
2673#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002674 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002675 return -1;
2676#endif /* SUNOS4 */
2677
2678#ifdef SVR4
2679#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002680 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002681#endif /* SPARC */
2682#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002683 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002684#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002685#ifdef X86_64
2686 val = tcp->status.PR_REG[RDX];
2687#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002688#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002689 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002690#endif /* MIPS */
2691#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002692#ifdef FREEBSD
2693 struct reg regs;
2694 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2695 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002696#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002697 return val;
2698}
2699
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002700#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002701/*
2702 * Apparently, indirect system calls have already be converted by ptrace(2),
2703 * so if you see "indir" this program has gone astray.
2704 */
2705int
2706sys_indir(tcp)
2707struct tcb *tcp;
2708{
2709 int i, scno, nargs;
2710
2711 if (entering(tcp)) {
2712 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2713 fprintf(stderr, "Bogus syscall: %u\n", scno);
2714 return 0;
2715 }
2716 nargs = sysent[scno].nargs;
2717 tprintf("%s", sysent[scno].sys_name);
2718 for (i = 0; i < nargs; i++)
2719 tprintf(", %#lx", tcp->u_arg[i+1]);
2720 }
2721 return 0;
2722}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002723#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002724
2725int
2726is_restart_error(struct tcb *tcp)
2727{
2728#ifdef LINUX
2729 if (!syserror(tcp))
2730 return 0;
2731 switch (tcp->u_error) {
2732 case ERESTARTSYS:
2733 case ERESTARTNOINTR:
2734 case ERESTARTNOHAND:
2735 case ERESTART_RESTARTBLOCK:
2736 return 1;
2737 default:
2738 break;
2739 }
2740#endif /* LINUX */
2741 return 0;
2742}