blob: 9722519fcaae00a170011405fc00c2a4156ad101 [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>
Denys Vlasenko84e20af2009-02-10 16:03:20 +000041#include <sched.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000042#include <sys/user.h>
43#include <sys/syscall.h>
44#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000045
Wichert Akkerman15dea971999-10-06 13:06:34 +000046#if HAVE_ASM_REG_H
Denys Vlasenko84e20af2009-02-10 16:03:20 +000047# if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000048# define fpq kernel_fpq
49# define fq kernel_fq
50# define fpu kernel_fpu
Denys Vlasenko84e20af2009-02-10 16:03:20 +000051# endif
52# include <asm/reg.h>
53# if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000054# undef fpq
55# undef fq
Roland McGrath761b5d72002-12-15 23:58:31 +000056# undef fpu
Denys Vlasenko84e20af2009-02-10 16:03:20 +000057# endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000058#endif
59
Wichert Akkerman15dea971999-10-06 13:06:34 +000060#ifdef HAVE_SYS_REG_H
Denys Vlasenko84e20af2009-02-10 16:03:20 +000061# include <sys/reg.h>
62# ifndef PTRACE_PEEKUSR
63# define PTRACE_PEEKUSR PTRACE_PEEKUSER
64# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000065#elif defined(HAVE_LINUX_PTRACE_H)
Denys Vlasenko84e20af2009-02-10 16:03:20 +000066# undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000067# ifdef HAVE_STRUCT_IA64_FPREG
68# define ia64_fpreg XXX_ia64_fpreg
69# endif
70# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
71# define pt_all_user_regs XXX_pt_all_user_regs
72# endif
Denys Vlasenko84e20af2009-02-10 16:03:20 +000073# include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000074# undef ia64_fpreg
75# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000076#endif
77
Roland McGrath6d1a65c2004-07-12 07:44:08 +000078#if defined (LINUX) && defined (SPARC64)
79# define r_pc r_tpc
80# undef PTRACE_GETREGS
81# define PTRACE_GETREGS PTRACE_GETREGS64
82# undef PTRACE_SETREGS
83# define PTRACE_SETREGS PTRACE_SETREGS64
84#endif /* LINUX && SPARC64 */
85
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000086#if defined(LINUX) && defined(IA64)
87# include <asm/ptrace_offsets.h>
88# include <asm/rse.h>
89#endif
90
Pavel Machekd8ae7e32000-02-01 17:17:25 +000091#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092#ifdef LINUX
93#ifndef ERESTARTSYS
94#define ERESTARTSYS 512
95#endif
96#ifndef ERESTARTNOINTR
97#define ERESTARTNOINTR 513
98#endif
99#ifndef ERESTARTNOHAND
100#define ERESTARTNOHAND 514 /* restart if no handler.. */
101#endif
102#ifndef ENOIOCTLCMD
103#define ENOIOCTLCMD 515 /* No ioctl command */
104#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000105#ifndef ERESTART_RESTARTBLOCK
106#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
107#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000108#ifndef NSIG
109#define NSIG 32
110#endif
111#ifdef ARM
112#undef NSIG
113#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000114#undef NR_SYSCALL_BASE
115#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116#endif
117#endif /* LINUX */
118
119#include "syscall.h"
120
121/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000122#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123#define TF TRACE_FILE
124#define TI TRACE_IPC
125#define TN TRACE_NETWORK
126#define TP TRACE_PROCESS
127#define TS TRACE_SIGNAL
128
Roland McGrathee36ce12004-09-04 03:53:10 +0000129static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000130#include "syscallent.h"
131};
Roland McGrathee36ce12004-09-04 03:53:10 +0000132static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000133int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134
135#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000136static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000137#include "syscallent1.h"
138};
Roland McGrathee36ce12004-09-04 03:53:10 +0000139static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000140int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000141#endif /* SUPPORTED_PERSONALITIES >= 2 */
142
143#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000144static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000145#include "syscallent2.h"
146};
Roland McGrathee36ce12004-09-04 03:53:10 +0000147static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000148int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000149#endif /* SUPPORTED_PERSONALITIES >= 3 */
150
Roland McGrathee36ce12004-09-04 03:53:10 +0000151const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000152int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000153int nsyscalls;
154
155/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000156#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000157#undef TF
158#undef TI
159#undef TN
160#undef TP
161#undef TS
162
Roland McGrathee36ce12004-09-04 03:53:10 +0000163static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000164#include "errnoent.h"
165};
Roland McGrathee36ce12004-09-04 03:53:10 +0000166static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167
168#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000169static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000170#include "errnoent1.h"
171};
Roland McGrathee36ce12004-09-04 03:53:10 +0000172static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000173#endif /* SUPPORTED_PERSONALITIES >= 2 */
174
175#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000176static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000177#include "errnoent2.h"
178};
Roland McGrathee36ce12004-09-04 03:53:10 +0000179static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000180#endif /* SUPPORTED_PERSONALITIES >= 3 */
181
Roland McGrathee36ce12004-09-04 03:53:10 +0000182const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000183int nerrnos;
184
185int current_personality;
186
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000187#ifndef PERSONALITY0_WORDSIZE
188# define PERSONALITY0_WORDSIZE sizeof(long)
189#endif
190const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
191 PERSONALITY0_WORDSIZE,
192#if SUPPORTED_PERSONALITIES > 1
193 PERSONALITY1_WORDSIZE,
194#endif
195#if SUPPORTED_PERSONALITIES > 2
196 PERSONALITY2_WORDSIZE,
197#endif
198};;
199
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000200int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000201set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000202{
203 switch (personality) {
204 case 0:
205 errnoent = errnoent0;
206 nerrnos = nerrnos0;
207 sysent = sysent0;
208 nsyscalls = nsyscalls0;
209 ioctlent = ioctlent0;
210 nioctlents = nioctlents0;
211 signalent = signalent0;
212 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000213 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000214 break;
215
216#if SUPPORTED_PERSONALITIES >= 2
217 case 1:
218 errnoent = errnoent1;
219 nerrnos = nerrnos1;
220 sysent = sysent1;
221 nsyscalls = nsyscalls1;
222 ioctlent = ioctlent1;
223 nioctlents = nioctlents1;
224 signalent = signalent1;
225 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000226 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000227 break;
228#endif /* SUPPORTED_PERSONALITIES >= 2 */
229
230#if SUPPORTED_PERSONALITIES >= 3
231 case 2:
232 errnoent = errnoent2;
233 nerrnos = nerrnos2;
234 sysent = sysent2;
235 nsyscalls = nsyscalls2;
236 ioctlent = ioctlent2;
237 nioctlents = nioctlents2;
238 signalent = signalent2;
239 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000240 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000241 break;
242#endif /* SUPPORTED_PERSONALITIES >= 3 */
243
244 default:
245 return -1;
246 }
247
248 current_personality = personality;
249 return 0;
250}
251
Roland McGrathe10e62a2004-09-04 04:20:43 +0000252
Roland McGrath9797ceb2002-12-30 10:23:00 +0000253static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000254
Roland McGrathe10e62a2004-09-04 04:20:43 +0000255static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000256 int bitflag;
257 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000258 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000259 char *argument_name;
260} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000261 { QUAL_TRACE, "trace", qual_syscall, "system call" },
262 { QUAL_TRACE, "t", qual_syscall, "system call" },
263 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
264 { QUAL_ABBREV, "a", qual_syscall, "system call" },
265 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
266 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
267 { QUAL_RAW, "raw", qual_syscall, "system call" },
268 { QUAL_RAW, "x", qual_syscall, "system call" },
269 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
270 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
271 { QUAL_SIGNAL, "s", qual_signal, "signal" },
272 { QUAL_FAULT, "fault", qual_fault, "fault" },
273 { QUAL_FAULT, "faults", qual_fault, "fault" },
274 { QUAL_FAULT, "m", qual_fault, "fault" },
275 { QUAL_READ, "read", qual_desc, "descriptor" },
276 { QUAL_READ, "reads", qual_desc, "descriptor" },
277 { QUAL_READ, "r", qual_desc, "descriptor" },
278 { QUAL_WRITE, "write", qual_desc, "descriptor" },
279 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
280 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000281 { 0, NULL, NULL, NULL },
282};
283
Roland McGrath9797ceb2002-12-30 10:23:00 +0000284static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000285qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000286 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000287 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000288 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000289 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000290{
Roland McGrath138c6a32006-01-12 09:50:49 +0000291 if (pers == 0 || pers < 0) {
292 if (not)
293 qual_flags0[n] &= ~opt->bitflag;
294 else
295 qual_flags0[n] |= opt->bitflag;
296 }
297
298#if SUPPORTED_PERSONALITIES >= 2
299 if (pers == 1 || pers < 0) {
300 if (not)
301 qual_flags1[n] &= ~opt->bitflag;
302 else
303 qual_flags1[n] |= opt->bitflag;
304 }
305#endif /* SUPPORTED_PERSONALITIES >= 2 */
306
307#if SUPPORTED_PERSONALITIES >= 3
308 if (pers == 2 || pers < 0) {
309 if (not)
310 qual_flags2[n] &= ~opt->bitflag;
311 else
312 qual_flags2[n] |= opt->bitflag;
313 }
314#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000315}
316
317static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000318qual_syscall(s, opt, not)
319 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000320 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000321 int not;
322{
323 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000324 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000325
Roland McGrath48a035f2006-01-12 09:45:56 +0000326 if (isdigit((unsigned char)*s)) {
327 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000328 if (i < 0 || i >= MAX_QUALS)
Roland McGrath48a035f2006-01-12 09:45:56 +0000329 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000330 qualify_one(i, opt, not, -1);
Roland McGrath48a035f2006-01-12 09:45:56 +0000331 return 0;
332 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000333 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000334 if (strcmp(s, sysent0[i].sys_name) == 0) {
335 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000336 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000337 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000338
339#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000340 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000341 if (strcmp(s, sysent1[i].sys_name) == 0) {
342 qualify_one(i, opt, not, 1);
343 rc = 0;
344 }
345#endif /* SUPPORTED_PERSONALITIES >= 2 */
346
347#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000348 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000349 if (strcmp(s, sysent2[i].sys_name) == 0) {
350 qualify_one(i, opt, not, 2);
351 rc = 0;
352 }
353#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000354
Roland McGrathfe6b3522005-02-02 04:40:11 +0000355 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000356}
357
358static int
359qual_signal(s, opt, not)
360 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000361 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000362 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000363{
364 int i;
365 char buf[32];
366
Roland McGrath48a035f2006-01-12 09:45:56 +0000367 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000368 int signo = atoi(s);
369 if (signo < 0 || signo >= MAX_QUALS)
370 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000371 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000372 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000373 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000374 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000375 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000376 strcpy(buf, s);
377 s = buf;
378 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000379 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380 if (strncmp(s, "SIG", 3) == 0)
381 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000382 for (i = 0; i <= NSIG; i++)
383 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000384 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000385 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000386 }
Roland McGrath76421df2005-02-02 03:51:18 +0000387 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000388}
389
390static int
391qual_fault(s, opt, not)
392 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000393 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000394 int not;
395{
396 return -1;
397}
398
399static int
400qual_desc(s, opt, not)
401 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000402 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000403 int not;
404{
Roland McGrath48a035f2006-01-12 09:45:56 +0000405 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000406 int desc = atoi(s);
407 if (desc < 0 || desc >= MAX_QUALS)
408 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000409 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000410 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000411 }
412 return -1;
413}
414
415static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000416lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000417 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000418{
419 if (strcmp(s, "file") == 0)
420 return TRACE_FILE;
421 if (strcmp(s, "ipc") == 0)
422 return TRACE_IPC;
423 if (strcmp(s, "network") == 0)
424 return TRACE_NETWORK;
425 if (strcmp(s, "process") == 0)
426 return TRACE_PROCESS;
427 if (strcmp(s, "signal") == 0)
428 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000429 if (strcmp(s, "desc") == 0)
430 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000431 return -1;
432}
433
434void
435qualify(s)
436char *s;
437{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000438 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000439 int not;
440 char *p;
441 int i, n;
442
443 opt = &qual_options[0];
444 for (i = 0; (p = qual_options[i].option_name); i++) {
445 n = strlen(p);
446 if (strncmp(s, p, n) == 0 && s[n] == '=') {
447 opt = &qual_options[i];
448 s += n + 1;
449 break;
450 }
451 }
452 not = 0;
453 if (*s == '!') {
454 not = 1;
455 s++;
456 }
457 if (strcmp(s, "none") == 0) {
458 not = 1 - not;
459 s = "all";
460 }
461 if (strcmp(s, "all") == 0) {
462 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000463 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 }
465 return;
466 }
467 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000468 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000469 }
470 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
471 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000472 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000473 if (sysent0[i].sys_flags & n)
474 qualify_one(i, opt, not, 0);
475
476#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000477 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000478 if (sysent1[i].sys_flags & n)
479 qualify_one(i, opt, not, 1);
480#endif /* SUPPORTED_PERSONALITIES >= 2 */
481
482#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000483 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000484 if (sysent2[i].sys_flags & n)
485 qualify_one(i, opt, not, 2);
486#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000487
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000488 continue;
489 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000490 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000491 fprintf(stderr, "strace: invalid %s `%s'\n",
492 opt->argument_name, p);
493 exit(1);
494 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000495 }
496 return;
497}
498
499static void
500dumpio(tcp)
501struct tcb *tcp;
502{
503 if (syserror(tcp))
504 return;
505 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
506 return;
Roland McGrath17352792005-06-07 23:21:26 +0000507 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000508 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000509#ifdef SYS_pread64
510 case SYS_pread64:
511#endif
512#if defined SYS_pread && SYS_pread64 != SYS_pread
513 case SYS_pread:
514#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000515#ifdef SYS_recv
516 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000517#elif defined SYS_sub_recv
518 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000519#endif
520#ifdef SYS_recvfrom
521 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000522#elif defined SYS_sub_recvfrom
523 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000524#endif
525 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
526 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
527 break;
528 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000529#ifdef SYS_pwrite64
530 case SYS_pwrite64:
531#endif
532#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
533 case SYS_pwrite:
534#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000535#ifdef SYS_send
536 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000537#elif defined SYS_sub_send
538 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539#endif
540#ifdef SYS_sendto
541 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000542#elif defined SYS_sub_sendto
543 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544#endif
545 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
546 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
547 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000548#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000549 case SYS_readv:
550 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
551 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
552 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000553#endif
554#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000555 case SYS_writev:
556 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
557 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
558 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000559#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560 }
561}
562
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000563#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000564enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000565#else /* FREEBSD */
566enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
567
568struct subcall {
569 int call;
570 int nsubcalls;
571 int subcalls[5];
572};
573
Roland McGratha4d48532005-06-08 20:45:28 +0000574static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000575 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000576#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000577 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000578#else
579 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
580#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000581 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
582};
583#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000584
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000585#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586
Roland McGratha4d48532005-06-08 20:45:28 +0000587static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588decode_subcall(tcp, subcall, nsubcalls, style)
589struct tcb *tcp;
590int subcall;
591int nsubcalls;
592enum subcall_style style;
593{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000594 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000595 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000596 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000597
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000598 switch (style) {
599 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000600 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
601 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 tcp->scno = subcall + tcp->u_arg[0];
603 if (sysent[tcp->scno].nargs != -1)
604 tcp->u_nargs = sysent[tcp->scno].nargs;
605 else
606 tcp->u_nargs--;
607 for (i = 0; i < tcp->u_nargs; i++)
608 tcp->u_arg[i] = tcp->u_arg[i + 1];
609 break;
610 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000611 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
612 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000613 tcp->scno = subcall + tcp->u_arg[0];
614 addr = tcp->u_arg[1];
615 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000616 if (size == sizeof(int)) {
617 unsigned int arg;
618 if (umove(tcp, addr, &arg) < 0)
619 arg = 0;
620 tcp->u_arg[i] = arg;
621 }
622 else if (size == sizeof(long)) {
623 unsigned long arg;
624 if (umove(tcp, addr, &arg) < 0)
625 arg = 0;
626 tcp->u_arg[i] = arg;
627 }
628 else
629 abort();
630 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 }
632 tcp->u_nargs = sysent[tcp->scno].nargs;
633 break;
634 case mask_style:
635 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000636 for (i = 0; mask; i++)
637 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000638 if (i >= nsubcalls)
639 return;
640 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 tcp->scno = subcall + i;
642 if (sysent[tcp->scno].nargs != -1)
643 tcp->u_nargs = sysent[tcp->scno].nargs;
644 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000645 case door_style:
646 /*
647 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000648 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000649 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000650 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
651 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000652 tcp->scno = subcall + tcp->u_arg[5];
653 if (sysent[tcp->scno].nargs != -1)
654 tcp->u_nargs = sysent[tcp->scno].nargs;
655 else
656 tcp->u_nargs--;
657 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000658#ifdef FREEBSD
659 case table_style:
660 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
661 if (subcalls_table[i].call == tcp->scno) break;
662 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
663 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
664 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
665 for (i = 0; i < tcp->u_nargs; i++)
666 tcp->u_arg[i] = tcp->u_arg[i + 1];
667 }
668 break;
669#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670 }
671}
672#endif
673
674struct tcb *tcp_last = NULL;
675
676static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000677internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000678{
679 /*
680 * We must always trace a few critical system calls in order to
681 * correctly support following forks in the presence of tracing
682 * qualifiers.
683 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000684 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000685
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000686 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
687 return 0;
688
689 func = sysent[tcp->scno].sys_func;
690
691 if (sys_exit == func)
692 return internal_exit(tcp);
693
694 if ( sys_fork == func
695#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
696 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000697#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000698#if UNIXWARE > 2
699 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000701 )
702 return internal_fork(tcp);
703
704#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
705 if (sys_clone == func)
706 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000707#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000708
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000709 if ( sys_execve == func
710#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
711 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000713#if UNIXWARE > 2
714 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000715#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000716 )
717 return internal_exec(tcp);
718
719 if ( sys_waitpid == func
720 || sys_wait4 == func
721#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
722 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000723#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000724#ifdef ALPHA
725 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000726#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000727 )
728 return internal_wait(tcp, 2);
729
730#if defined(LINUX) || defined(SVR4)
731 if (sys_waitid == func)
732 return internal_wait(tcp, 3);
733#endif
734
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000735 return 0;
736}
737
Wichert Akkermanc7926982000-04-10 22:22:31 +0000738
739#ifdef LINUX
740#if defined (I386)
741 static long eax;
742#elif defined (IA64)
743 long r8, r10, psr;
744 long ia32 = 0;
745#elif defined (POWERPC)
746 static long result,flags;
747#elif defined (M68K)
748 static int d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000749#elif defined(BFIN)
750 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000751#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000752 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000753#elif defined (ALPHA)
754 static long r0;
755 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000756#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000757 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000758 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000759#elif defined(LINUX_MIPSN32)
760 static long long a3;
761 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000762#elif defined(MIPS)
763 static long a3;
764 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000765#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000766 static long gpr2;
767 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000768 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000769#elif defined(HPPA)
770 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000771#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000772 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000773#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000774 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000775#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000776 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000777#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000778#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000779#ifdef FREEBSD
780 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000781#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000782
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000784get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000788#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000789#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000790 if (tcp->flags & TCB_WAITEXECVE) {
791 /*
792 * When the execve system call completes successfully, the
793 * new process still has -ENOSYS (old style) or __NR_execve
794 * (new style) in gpr2. We cannot recover the scno again
795 * by disassembly, because the image that executed the
796 * syscall is gone now. Fortunately, we don't want it. We
797 * leave the flag set so that syscall_fixup can fake the
798 * result.
799 */
800 if (tcp->flags & TCB_INSYSCALL)
801 return 1;
802 /*
803 * This is the SIGTRAP after execve. We cannot try to read
804 * the system call here either.
805 */
806 tcp->flags &= ~TCB_WAITEXECVE;
807 return 0;
808 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000809
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000810 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000811 return -1;
812
813 if (syscall_mode != -ENOSYS) {
814 /*
815 * Since kernel version 2.5.44 the scno gets passed in gpr2.
816 */
817 scno = syscall_mode;
818 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000819 /*
820 * Old style of "passing" the scno via the SVC instruction.
821 */
822
823 long opcode, offset_reg, tmp;
824 void * svc_addr;
825 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
826 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
827 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
828 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000829
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000830 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000831 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000832 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000833 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000834 if (errno) {
835 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000836 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000837 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000838
839 /*
840 * We have to check if the SVC got executed directly or via an
841 * EXECUTE instruction. In case of EXECUTE it is necessary to do
842 * instruction decoding to derive the system call number.
843 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
844 * so that this doesn't work if a SVC opcode is part of an EXECUTE
845 * opcode. Since there is no way to find out the opcode size this
846 * is the best we can do...
847 */
848
849 if ((opcode & 0xff00) == 0x0a00) {
850 /* SVC opcode */
851 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000852 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000853 else {
854 /* SVC got executed by EXECUTE instruction */
855
856 /*
857 * Do instruction decoding of EXECUTE. If you really want to
858 * understand this, read the Principles of Operations.
859 */
860 svc_addr = (void *) (opcode & 0xfff);
861
862 tmp = 0;
863 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000864 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000865 return -1;
866 svc_addr += tmp;
867
868 tmp = 0;
869 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000870 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000871 return -1;
872 svc_addr += tmp;
873
Denys Vlasenkofb036672009-01-23 16:30:26 +0000874 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000875 if (errno)
876 return -1;
877#if defined(S390X)
878 scno >>= 48;
879#else
880 scno >>= 16;
881#endif
882 tmp = 0;
883 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000884 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000885 return -1;
886
887 scno = (scno | tmp) & 0xff;
888 }
889 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000890#elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000891 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000892 return -1;
893 if (!(tcp->flags & TCB_INSYSCALL)) {
894 /* Check if we return from execve. */
895 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
896 tcp->flags &= ~TCB_WAITEXECVE;
897 return 0;
898 }
899 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000900#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000901 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000902 return -1;
903 /* Check if we return from execve. */
904 if (tcp->flags & TCB_WAITEXECVE && tcp->flags & TCB_INSYSCALL)
905 tcp->flags &= ~(TCB_INSYSCALL | TCB_WAITEXECVE);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000906#elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000907 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000908 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000909#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000910 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000911 return -1;
912
Roland McGrath761b5d72002-12-15 23:58:31 +0000913 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko8236f252009-01-02 18:10:08 +0000914 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000915 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000916 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000917
918 /* Check CS register value. On x86-64 linux it is:
919 * 0x33 for long mode (64 bit)
920 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000921 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000922 * to be cached.
923 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000924 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000925 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000926 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000927 case 0x23: currpers = 1; break;
928 case 0x33: currpers = 0; break;
929 default:
930 fprintf(stderr, "Unknown value CS=0x%02X while "
931 "detecting personality of process "
932 "PID=%d\n", (int)val, pid);
933 currpers = current_personality;
934 break;
935 }
936#if 0
937 /* This version analyzes the opcode of a syscall instruction.
938 * (int 0x80 on i386 vs. syscall on x86-64)
939 * It works, but is too complicated.
940 */
941 unsigned long val, rip, i;
942
Denys Vlasenko8236f252009-01-02 18:10:08 +0000943 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000944 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000945
Michal Ludvig0e035502002-09-23 15:41:01 +0000946 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000947 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000948 errno = 0;
949
Denys Vlasenko8236f252009-01-02 18:10:08 +0000950 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000951 if (errno)
952 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000953 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000954 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000955 /* x86-64: syscall = 0x0f 0x05 */
956 case 0x050f: currpers = 0; break;
957 /* i386: int 0x80 = 0xcd 0x80 */
958 case 0x80cd: currpers = 1; break;
959 default:
960 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000961 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000962 "Unknown syscall opcode (0x%04X) while "
963 "detecting personality of process "
964 "PID=%d\n", (int)call, pid);
965 break;
966 }
967#endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000968 if (currpers != current_personality) {
969 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000970 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000971 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000972 pid, names[current_personality]);
973 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000974 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000975#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000976# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000977 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000978 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000979 if (!(tcp->flags & TCB_INSYSCALL)) {
980 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000981 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000982 return -1;
983 } else {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000984 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000985 return -1;
986 }
Roland McGrathba954762003-03-05 06:29:06 +0000987 /* Check if we return from execve. */
988 if (tcp->flags & TCB_WAITEXECVE) {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000989#if defined PTRACE_GETSIGINFO
990 siginfo_t si;
991
992 tcp->flags &= ~TCB_WAITEXECVE;
993 /* If SIGTRAP is masked, execve's magic SIGTRAP
994 * is not delivered. We end up here on a subsequent
995 * ptrace stop instead. Luckily, we can check
996 * for the type of this SIGTRAP. execve's magic one
997 * has 0 (SI_USER) in si.si_code, ptrace stop has 5.
998 * (I don't know why 5).
999 */
1000 si.si_code = SI_USER;
1001 /* If PTRACE_GETSIGINFO fails, we assume it's
1002 * magic SIGTRAP. Moot anyway, PTRACE_GETSIGINFO
1003 * doesn't fail.
1004 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001005 ptrace(PTRACE_GETSIGINFO, tcp->pid, (void*) 0, (void*) &si);
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001006 if (si.si_code == SI_USER)
1007 return 0;
1008#else
Roland McGrathba954762003-03-05 06:29:06 +00001009 tcp->flags &= ~TCB_WAITEXECVE;
1010 return 0;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001011#endif
Roland McGrathba954762003-03-05 06:29:06 +00001012 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001013 } else {
1014 /* syscall in progress */
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001015 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001016 return -1;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001017 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001018 return -1;
1019 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001020#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001021 /*
1022 * Read complete register set in one go.
1023 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001024 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001025 return -1;
1026
1027 /*
1028 * We only need to grab the syscall number on syscall entry.
1029 */
1030 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001031 if (!(tcp->flags & TCB_INSYSCALL)) {
1032 /* Check if we return from execve. */
1033 if (tcp->flags & TCB_WAITEXECVE) {
1034 tcp->flags &= ~TCB_WAITEXECVE;
1035 return 0;
1036 }
1037 }
1038
Roland McGrath0f87c492003-06-03 23:29:04 +00001039 /*
1040 * Note: we only deal with only 32-bit CPUs here.
1041 */
1042 if (regs.ARM_cpsr & 0x20) {
1043 /*
1044 * Get the Thumb-mode system call number
1045 */
1046 scno = regs.ARM_r7;
1047 } else {
1048 /*
1049 * Get the ARM-mode system call number
1050 */
1051 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001052 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001053 if (errno)
1054 return -1;
1055
1056 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1057 tcp->flags &= ~TCB_WAITEXECVE;
1058 return 0;
1059 }
1060
Roland McGrathf691bd22006-04-25 07:34:41 +00001061 /* Handle the EABI syscall convention. We do not
1062 bother converting structures between the two
1063 ABIs, but basic functionality should work even
1064 if strace and the traced program have different
1065 ABIs. */
1066 if (scno == 0xef000000) {
1067 scno = regs.ARM_r7;
1068 } else {
1069 if ((scno & 0x0ff00000) != 0x0f900000) {
1070 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1071 scno);
1072 return -1;
1073 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001074
Roland McGrathf691bd22006-04-25 07:34:41 +00001075 /*
1076 * Fixup the syscall number
1077 */
1078 scno &= 0x000fffff;
1079 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001080 }
Roland McGrath56703312008-05-20 01:35:55 +00001081 if (scno & 0x0f0000) {
1082 /*
1083 * Handle ARM specific syscall
1084 */
1085 set_personality(1);
1086 scno &= 0x0000ffff;
1087 } else
1088 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001089
1090 if (tcp->flags & TCB_INSYSCALL) {
1091 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1092 tcp->flags &= ~TCB_INSYSCALL;
1093 }
1094 } else {
1095 if (!(tcp->flags & TCB_INSYSCALL)) {
1096 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1097 tcp->flags |= TCB_INSYSCALL;
1098 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001099 }
1100#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001101 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102 return -1;
Roland McGrath542c2c62008-05-20 01:11:56 +00001103#elif defined (LINUX_MIPSN32)
1104 unsigned long long regs[38];
1105
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001106 if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001107 return -1;
1108 a3 = regs[REG_A3];
1109 r2 = regs[REG_V0];
1110
1111 if(!(tcp->flags & TCB_INSYSCALL)) {
1112 scno = r2;
1113
1114 /* Check if we return from execve. */
1115 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1116 tcp->flags &= ~TCB_WAITEXECVE;
1117 return 0;
1118 }
1119
1120 if (scno < 0 || scno > nsyscalls) {
1121 if(a3 == 0 || a3 == -1) {
1122 if(debug)
1123 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1124 return 0;
1125 }
1126 }
1127 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001128#elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001129 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001130 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001131 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001132 if (upeek(tcp, REG_V0, &scno) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001133 return -1;
1134
Roland McGrath542c2c62008-05-20 01:11:56 +00001135 /* Check if we return from execve. */
1136 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1137 tcp->flags &= ~TCB_WAITEXECVE;
1138 return 0;
1139 }
1140
Wichert Akkermanf90da011999-10-31 21:15:38 +00001141 if (scno < 0 || scno > nsyscalls) {
1142 if(a3 == 0 || a3 == -1) {
1143 if(debug)
1144 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1145 return 0;
1146 }
1147 }
1148 } else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001149 if (upeek(tcp, REG_V0, &r2) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001150 return -1;
1151 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001152#elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001153 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001154 return -1;
1155
1156 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001157 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001158 return -1;
1159
1160 /* Check if we return from execve. */
1161 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1162 tcp->flags &= ~TCB_WAITEXECVE;
1163 return 0;
1164 }
1165
1166 /*
1167 * Do some sanity checks to figure out if it's
1168 * really a syscall entry
1169 */
1170 if (scno < 0 || scno > nsyscalls) {
1171 if (a3 == 0 || a3 == -1) {
1172 if (debug)
1173 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1174 return 0;
1175 }
1176 }
1177 }
1178 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001179 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001180 return -1;
1181 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001182#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001184 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185 return -1;
1186
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001187 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188 if (!(tcp->flags & TCB_INSYSCALL)) {
1189 /* Retrieve the syscall trap instruction. */
1190 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001191 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.r_pc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001192#if defined(SPARC64)
1193 trap >>= 32;
1194#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001195 if (errno)
1196 return -1;
1197
1198 /* Disassemble the trap to see what personality to use. */
1199 switch (trap) {
1200 case 0x91d02010:
1201 /* Linux/SPARC syscall trap. */
1202 set_personality(0);
1203 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001204 case 0x91d0206d:
1205 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001206 set_personality(2);
1207 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001208 case 0x91d02000:
1209 /* SunOS syscall trap. (pers 1) */
1210 fprintf(stderr,"syscall: SunOS no support\n");
1211 return -1;
1212 case 0x91d02008:
1213 /* Solaris 2.x syscall trap. (per 2) */
1214 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001215 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216 case 0x91d02009:
1217 /* NetBSD/FreeBSD syscall trap. */
1218 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1219 return -1;
1220 case 0x91d02027:
1221 /* Solaris 2.x gettimeofday */
1222 set_personality(1);
1223 break;
1224 default:
1225 /* Unknown syscall trap. */
1226 if(tcp->flags & TCB_WAITEXECVE) {
1227 tcp->flags &= ~TCB_WAITEXECVE;
1228 return 0;
1229 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001230#if defined (SPARC64)
1231 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1232#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001233 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001234#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 return -1;
1236 }
1237
1238 /* Extract the system call number from the registers. */
1239 if (trap == 0x91d02027)
1240 scno = 156;
1241 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001242 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001244 scno = regs.r_o0;
1245 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001246 }
1247 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001248#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001249 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001250 return -1;
1251 if (!(tcp->flags & TCB_INSYSCALL)) {
1252 /* Check if we return from execve. */
1253 if ((tcp->flags & TCB_WAITEXECVE)) {
1254 tcp->flags &= ~TCB_WAITEXECVE;
1255 return 0;
1256 }
1257 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001258#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001259 /*
1260 * In the new syscall ABI, the system call number is in R3.
1261 */
1262 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1263 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001264
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001265 if (scno < 0) {
1266 /* Odd as it may seem, a glibc bug has been known to cause
1267 glibc to issue bogus negative syscall numbers. So for
1268 our purposes, make strace print what it *should* have been */
1269 long correct_scno = (scno & 0xff);
1270 if (debug)
1271 fprintf(stderr,
1272 "Detected glibc bug: bogus system call"
1273 " number = %ld, correcting to %ld\n",
1274 scno,
1275 correct_scno);
1276 scno = correct_scno;
1277 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001278
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001279 if (!(tcp->flags & TCB_INSYSCALL)) {
1280 /* Check if we return from execve. */
1281 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1282 tcp->flags &= ~TCB_WAITEXECVE;
1283 return 0;
1284 }
1285 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001286#elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001287 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001288 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001289 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001290
1291 if (!(tcp->flags & TCB_INSYSCALL)) {
1292 /* Check if we return from execve. */
1293 if (tcp->flags & TCB_WAITEXECVE) {
1294 tcp->flags &= ~TCB_WAITEXECVE;
1295 return 0;
1296 }
1297 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001298#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001299#endif /* LINUX */
1300#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001301 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001302 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001303#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001304 /* new syscall ABI returns result in R0 */
1305 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1306 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001307#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001308 /* ABI defines result returned in r9 */
1309 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1310 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001311
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001312#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001313#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001315 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001317#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001318 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001319#else /* FREEBSD */
1320 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001321 perror("pread");
1322 return -1;
1323 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001324 switch (regs.r_eax) {
1325 case SYS_syscall:
1326 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001327 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1328 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001329 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001330 scno = regs.r_eax;
1331 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001332 }
1333#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001334#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001335#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001336 if (!(tcp->flags & TCB_INSYSCALL))
1337 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001338 return 1;
1339}
1340
Pavel Machek4dc3b142000-02-01 17:58:41 +00001341
Roland McGrath17352792005-06-07 23:21:26 +00001342long
1343known_scno(tcp)
1344struct tcb *tcp;
1345{
1346 long scno = tcp->scno;
1347 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1348 scno = sysent[scno].native_scno;
1349 else
1350 scno += NR_SYSCALL_BASE;
1351 return scno;
1352}
1353
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001354/* Called in trace_syscall at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001355 * Returns:
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001356 * 0: "ignore this syscall", bail out of trace_syscall silently.
1357 * 1: ok, continue in trace_syscall.
1358 * other: error, trace_syscall should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001359 * ("????" etc) and bail out.
1360 */
Roland McGratha4d48532005-06-08 20:45:28 +00001361static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001362syscall_fixup(tcp)
1363struct tcb *tcp;
1364{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001365#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001366 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001367
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001369 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370 if (
1371 scno == SYS_fork
1372#ifdef SYS_vfork
1373 || scno == SYS_vfork
1374#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001375#ifdef SYS_fork1
1376 || scno == SYS_fork1
1377#endif /* SYS_fork1 */
1378#ifdef SYS_forkall
1379 || scno == SYS_forkall
1380#endif /* SYS_forkall */
1381#ifdef SYS_rfork1
1382 || scno == SYS_rfork1
1383#endif /* SYS_fork1 */
1384#ifdef SYS_rforkall
1385 || scno == SYS_rforkall
1386#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001387 ) {
1388 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001389 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001390 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001391 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001392 }
1393 else {
1394 fprintf(stderr, "syscall: missing entry\n");
1395 tcp->flags |= TCB_INSYSCALL;
1396 }
1397 }
1398 }
1399 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001400 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001401 fprintf(stderr, "syscall: missing exit\n");
1402 tcp->flags &= ~TCB_INSYSCALL;
1403 }
1404 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001405#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001406#ifdef SUNOS4
1407 if (!(tcp->flags & TCB_INSYSCALL)) {
1408 if (scno == 0) {
1409 fprintf(stderr, "syscall: missing entry\n");
1410 tcp->flags |= TCB_INSYSCALL;
1411 }
1412 }
1413 else {
1414 if (scno != 0) {
1415 if (debug) {
1416 /*
1417 * This happens when a signal handler
1418 * for a signal which interrupted a
1419 * a system call makes another system call.
1420 */
1421 fprintf(stderr, "syscall: missing exit\n");
1422 }
1423 tcp->flags &= ~TCB_INSYSCALL;
1424 }
1425 }
1426#endif /* SUNOS4 */
1427#ifdef LINUX
1428#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001429 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001430 return -1;
1431 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1432 if (debug)
1433 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1434 return 0;
1435 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001436#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001437 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001438 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001439 if (current_personality == 1)
1440 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001441 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1442 if (debug)
1443 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1444 return 0;
1445 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001446#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001447 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001448 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001449 if (syscall_mode != -ENOSYS)
1450 syscall_mode = tcp->scno;
1451 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001452 if (debug)
1453 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1454 return 0;
1455 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001456 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1457 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1458 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1459 /*
1460 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1461 * flag set for the post-execve SIGTRAP to see and reset.
1462 */
1463 gpr2 = 0;
1464 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001465#elif defined (POWERPC)
1466# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001467 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001468 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001469 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001470 return -1;
1471 if (flags & SO_MASK)
1472 result = -result;
1473#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001474 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001475 return -1;
1476 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1477 if (debug)
1478 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1479 return 0;
1480 }
1481#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001482 /*
1483 * Nothing required
1484 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001485#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001486 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001487 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001488#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001489 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001490 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001491#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001492 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001493 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001494 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001495 return -1;
1496 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1497 if (debug)
1498 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1499 return 0;
1500 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001501#endif
1502#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001503 return 1;
1504}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001505
Roland McGrathc1e45922008-05-27 23:18:29 +00001506#ifdef LINUX
1507/*
1508 * Check the syscall return value register value for whether it is
1509 * a negated errno code indicating an error, or a success return value.
1510 */
1511static inline int
1512is_negated_errno(unsigned long int val)
1513{
1514 unsigned long int max = -(long int) nerrnos;
1515 if (personality_wordsize[current_personality] < sizeof(val)) {
1516 val = (unsigned int) val;
1517 max = (unsigned int) max;
1518 }
1519 return val > max;
1520}
1521#endif
1522
Roland McGratha4d48532005-06-08 20:45:28 +00001523static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001524get_error(tcp)
1525struct tcb *tcp;
1526{
1527 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001528#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001529#if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001530 if (is_negated_errno(gpr2)) {
1531 tcp->u_rval = -1;
1532 u_error = -gpr2;
1533 }
1534 else {
1535 tcp->u_rval = gpr2;
1536 u_error = 0;
1537 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001538#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001539#ifdef I386
Roland McGrathc1e45922008-05-27 23:18:29 +00001540 if (is_negated_errno(eax)) {
1541 tcp->u_rval = -1;
1542 u_error = -eax;
1543 }
1544 else {
1545 tcp->u_rval = eax;
1546 u_error = 0;
1547 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001548#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001549#ifdef X86_64
Roland McGrathc1e45922008-05-27 23:18:29 +00001550 if (is_negated_errno(rax)) {
1551 tcp->u_rval = -1;
1552 u_error = -rax;
1553 }
1554 else {
1555 tcp->u_rval = rax;
1556 u_error = 0;
1557 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001558#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001559#ifdef IA64
Roland McGrathc1e45922008-05-27 23:18:29 +00001560 if (ia32) {
1561 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001562
Roland McGrathc1e45922008-05-27 23:18:29 +00001563 err = (int)r8;
1564 if (is_negated_errno(err)) {
1565 tcp->u_rval = -1;
1566 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001567 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001568 else {
1569 tcp->u_rval = err;
1570 u_error = 0;
1571 }
1572 } else {
1573 if (r10) {
1574 tcp->u_rval = -1;
1575 u_error = r8;
1576 } else {
1577 tcp->u_rval = r8;
1578 u_error = 0;
1579 }
1580 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001581#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001582#ifdef MIPS
1583 if (a3) {
1584 tcp->u_rval = -1;
1585 u_error = r2;
1586 } else {
1587 tcp->u_rval = r2;
1588 u_error = 0;
1589 }
1590#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001591#ifdef POWERPC
Roland McGrathc1e45922008-05-27 23:18:29 +00001592 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001593 tcp->u_rval = -1;
1594 u_error = -result;
1595 }
1596 else {
1597 tcp->u_rval = result;
1598 u_error = 0;
1599 }
1600#else /* !POWERPC */
1601#ifdef M68K
Roland McGrathc1e45922008-05-27 23:18:29 +00001602 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001603 tcp->u_rval = -1;
1604 u_error = -d0;
1605 }
1606 else {
1607 tcp->u_rval = d0;
1608 u_error = 0;
1609 }
1610#else /* !M68K */
1611#ifdef ARM
Roland McGrathc1e45922008-05-27 23:18:29 +00001612 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001614 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615 }
1616 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001617 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001618 u_error = 0;
1619 }
1620#else /* !ARM */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001621#ifdef BFIN
1622 if (is_negated_errno(r0)) {
1623 tcp->u_rval = -1;
1624 u_error = -r0;
1625 } else {
1626 tcp->u_rval = r0;
1627 u_error = 0;
1628 }
1629#else /* !BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630#ifdef ALPHA
1631 if (a3) {
1632 tcp->u_rval = -1;
1633 u_error = r0;
1634 }
1635 else {
1636 tcp->u_rval = r0;
1637 u_error = 0;
1638 }
1639#else /* !ALPHA */
1640#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001641 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001643 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644 }
1645 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001646 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647 u_error = 0;
1648 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001649#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001650#ifdef SPARC64
1651 if (regs.r_tstate & 0x1100000000UL) {
1652 tcp->u_rval = -1;
1653 u_error = regs.r_o0;
1654 }
1655 else {
1656 tcp->u_rval = regs.r_o0;
1657 u_error = 0;
1658 }
1659#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001660#ifdef HPPA
Roland McGrathc1e45922008-05-27 23:18:29 +00001661 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001662 tcp->u_rval = -1;
1663 u_error = -r28;
1664 }
1665 else {
1666 tcp->u_rval = r28;
1667 u_error = 0;
1668 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001669#else
1670#ifdef SH
Roland McGrathc1e45922008-05-27 23:18:29 +00001671 /* interpret R0 as return value or error number */
1672 if (is_negated_errno(r0)) {
1673 tcp->u_rval = -1;
1674 u_error = -r0;
1675 }
1676 else {
1677 tcp->u_rval = r0;
1678 u_error = 0;
1679 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001680#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001681#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001682 /* interpret result as return value or error number */
1683 if (is_negated_errno(r9)) {
1684 tcp->u_rval = -1;
1685 u_error = -r9;
1686 }
1687 else {
1688 tcp->u_rval = r9;
1689 u_error = 0;
1690 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001691#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001692#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001693#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001694#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001695#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696#endif /* ALPHA */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001697#endif /* BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698#endif /* ARM */
1699#endif /* M68K */
1700#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001701#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001702#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001703#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001704#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001705#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706#endif /* LINUX */
1707#ifdef SUNOS4
1708 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001709 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710 return -1;
1711 u_error >>= 24; /* u_error is a char */
1712
1713 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001714 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715 return -1;
1716#endif /* SUNOS4 */
1717#ifdef SVR4
1718#ifdef SPARC
1719 /* Judicious guessing goes a long way. */
1720 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1721 tcp->u_rval = -1;
1722 u_error = tcp->status.pr_reg[R_O0];
1723 }
1724 else {
1725 tcp->u_rval = tcp->status.pr_reg[R_O0];
1726 u_error = 0;
1727 }
1728#endif /* SPARC */
1729#ifdef I386
1730 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001731 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001732 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001733 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734 }
1735 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001736 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001737#ifdef HAVE_LONG_LONG
1738 tcp->u_lrval =
1739 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1740 tcp->status.PR_REG[EAX];
1741#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001742 u_error = 0;
1743 }
1744#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001745#ifdef X86_64
1746 /* Wanna know how to kill an hour single-stepping? */
1747 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1748 tcp->u_rval = -1;
1749 u_error = tcp->status.PR_REG[RAX];
1750 }
1751 else {
1752 tcp->u_rval = tcp->status.PR_REG[RAX];
1753 u_error = 0;
1754 }
1755#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001756#ifdef MIPS
1757 if (tcp->status.pr_reg[CTX_A3]) {
1758 tcp->u_rval = -1;
1759 u_error = tcp->status.pr_reg[CTX_V0];
1760 }
1761 else {
1762 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1763 u_error = 0;
1764 }
1765#endif /* MIPS */
1766#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001767#ifdef FREEBSD
1768 if (regs.r_eflags & PSL_C) {
1769 tcp->u_rval = -1;
1770 u_error = regs.r_eax;
1771 } else {
1772 tcp->u_rval = regs.r_eax;
1773 tcp->u_lrval =
1774 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1775 u_error = 0;
1776 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001777#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001778 tcp->u_error = u_error;
1779 return 1;
1780}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001781
Roland McGrathb69f81b2002-12-21 23:25:18 +00001782int
1783force_result(tcp, error, rval)
1784 struct tcb *tcp;
1785 int error;
1786 long rval;
1787{
1788#ifdef LINUX
1789#if defined(S390) || defined(S390X)
1790 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001791 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1792 return -1;
1793#else /* !S390 && !S390X */
1794#ifdef I386
1795 eax = error ? -error : rval;
1796 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1797 return -1;
1798#else /* !I386 */
1799#ifdef X86_64
1800 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001801 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001802 return -1;
1803#else
1804#ifdef IA64
1805 if (ia32) {
1806 r8 = error ? -error : rval;
1807 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1808 return -1;
1809 }
1810 else {
1811 if (error) {
1812 r8 = error;
1813 r10 = -1;
1814 }
1815 else {
1816 r8 = rval;
1817 r10 = 0;
1818 }
1819 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1820 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1821 return -1;
1822 }
1823#else /* !IA64 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001824#ifdef BFIN
1825 r0 = error ? -error : rval;
1826 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1827 return -1;
1828#else /* !BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001829#ifdef MIPS
1830 if (error) {
1831 r2 = error;
1832 a3 = -1;
1833 }
1834 else {
1835 r2 = rval;
1836 a3 = 0;
1837 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001838 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001839 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1840 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1841 return -1;
1842#else
1843#ifdef POWERPC
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001844 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001845 return -1;
1846 if (error) {
1847 flags |= SO_MASK;
1848 result = error;
1849 }
1850 else {
1851 flags &= ~SO_MASK;
1852 result = rval;
1853 }
Roland McGratheb285352003-01-14 09:59:00 +00001854 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1855 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001856 return -1;
1857#else /* !POWERPC */
1858#ifdef M68K
1859 d0 = error ? -error : rval;
1860 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1861 return -1;
1862#else /* !M68K */
1863#ifdef ARM
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001864 regs.ARM_r0 = error ? -error : rval;
1865 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001866 return -1;
1867#else /* !ARM */
1868#ifdef ALPHA
1869 if (error) {
1870 a3 = -1;
1871 r0 = error;
1872 }
1873 else {
1874 a3 = 0;
1875 r0 = rval;
1876 }
1877 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1878 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1879 return -1;
1880#else /* !ALPHA */
1881#ifdef SPARC
1882 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1883 return -1;
1884 if (error) {
1885 regs.r_psr |= PSR_C;
1886 regs.r_o0 = error;
1887 }
1888 else {
1889 regs.r_psr &= ~PSR_C;
1890 regs.r_o0 = rval;
1891 }
1892 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1893 return -1;
1894#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001895#ifdef SPARC64
1896 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1897 return -1;
1898 if (error) {
1899 regs.r_tstate |= 0x1100000000UL;
1900 regs.r_o0 = error;
1901 }
1902 else {
1903 regs.r_tstate &= ~0x1100000000UL;
1904 regs.r_o0 = rval;
1905 }
1906 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1907 return -1;
1908#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001909#ifdef HPPA
1910 r28 = error ? -error : rval;
1911 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1912 return -1;
1913#else
1914#ifdef SH
1915 r0 = error ? -error : rval;
1916 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1917 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001918#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001919#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001920 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001921 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1922 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001923#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001924#endif /* SH */
1925#endif /* HPPA */
1926#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001927#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001928#endif /* ALPHA */
1929#endif /* ARM */
1930#endif /* M68K */
1931#endif /* POWERPC */
1932#endif /* MIPS */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001933#endif /* BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001934#endif /* IA64 */
1935#endif /* X86_64 */
1936#endif /* I386 */
1937#endif /* S390 || S390X */
1938#endif /* LINUX */
1939#ifdef SUNOS4
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001940 if (do_ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error), error << 24) < 0
1941 || do_ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0
1942 ) {
Roland McGrathb69f81b2002-12-21 23:25:18 +00001943 return -1;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001944 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001945#endif /* SUNOS4 */
1946#ifdef SVR4
1947 /* XXX no clue */
1948 return -1;
1949#endif /* SVR4 */
1950#ifdef FREEBSD
1951 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001952 perror("pread");
1953 return -1;
1954 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001955 if (error) {
1956 regs.r_eflags |= PSL_C;
1957 regs.r_eax = error;
1958 }
1959 else {
1960 regs.r_eflags &= ~PSL_C;
1961 regs.r_eax = rval;
1962 }
1963 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001964 perror("pwrite");
1965 return -1;
1966 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001967#endif /* FREEBSD */
1968
1969 /* All branches reach here on success (only). */
1970 tcp->u_error = error;
1971 tcp->u_rval = rval;
1972 return 0;
1973}
1974
Roland McGratha4d48532005-06-08 20:45:28 +00001975static int
1976syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001977struct tcb *tcp;
1978{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001979#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001980#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001981 {
1982 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001983 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1984 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001985 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001986 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001987 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001988 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001989 return -1;
1990 }
1991 }
1992#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001993 {
1994 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001995 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1996 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001997 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001998 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001999 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00002000 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2001 * for scno somewhere above here!
2002 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002003 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002004 return -1;
2005 }
2006 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002007#elif defined (IA64)
2008 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002009 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002010 unsigned long *out0, cfm, sof, sol, i;
2011 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002012 /* be backwards compatible with kernel < 2.4.4... */
2013# ifndef PT_RBS_END
2014# define PT_RBS_END PT_AR_BSP
2015# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002016
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002017 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002018 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002019 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002020 return -1;
2021
2022 sof = (cfm >> 0) & 0x7f;
2023 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002024 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002025
2026 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2027 && sysent[tcp->scno].nargs != -1)
2028 tcp->u_nargs = sysent[tcp->scno].nargs;
2029 else
2030 tcp->u_nargs = MAX_ARGS;
2031 for (i = 0; i < tcp->u_nargs; ++i) {
2032 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2033 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2034 return -1;
2035 }
2036 } else {
2037 int i;
2038
2039 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002040 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002041 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002042 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002043 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002044 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002045 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002046 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002047 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002048 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002049 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002050 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002051 return -1;
2052
2053 for (i = 0; i < 6; ++i)
2054 /* truncate away IVE sign-extension */
2055 tcp->u_arg[i] &= 0xffffffff;
2056
2057 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2058 && sysent[tcp->scno].nargs != -1)
2059 tcp->u_nargs = sysent[tcp->scno].nargs;
2060 else
2061 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002062 }
2063 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002064#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2065 /* N32 and N64 both use up to six registers. */
2066 {
2067 unsigned long long regs[38];
2068 int i, nargs;
2069
2070 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2071 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002072 else
Roland McGrath542c2c62008-05-20 01:11:56 +00002073 nargs = tcp->u_nargs = MAX_ARGS;
2074
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002075 if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002076 return -1;
2077
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002078 for (i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002079 tcp->u_arg[i] = regs[REG_A0 + i];
2080# if defined (LINUX_MIPSN32)
2081 tcp->ext_arg[i] = regs[REG_A0 + i];
2082# endif
2083 }
2084 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002085#elif defined (MIPS)
2086 {
2087 long sp;
2088 int i, nargs;
2089
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002090 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2091 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002092 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002093 nargs = tcp->u_nargs = MAX_ARGS;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002094 if (nargs > 4) {
2095 if (upeek(tcp, REG_SP, &sp) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002096 return -1;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002097 for (i = 0; i < 4; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002098 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002099 return -1;
2100 }
2101 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2102 (char *)(tcp->u_arg + 4));
2103 } else {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002104 for (i = 0; i < nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002105 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002106 return -1;
2107 }
2108 }
2109 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002110#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002111#ifndef PT_ORIG_R3
2112#define PT_ORIG_R3 34
2113#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002114 {
2115 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002116 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2117 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002118 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002119 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002120 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002121 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002122 (sizeof(unsigned long)*PT_ORIG_R3) :
2123 ((i+PT_R3)*sizeof(unsigned long)),
2124 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002125 return -1;
2126 }
2127 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002128#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002129 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002130 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002131
2132 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2133 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002134 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002135 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002136 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002137 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002139#elif defined (HPPA)
2140 {
2141 int i;
2142
2143 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2144 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002145 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002146 tcp->u_nargs = MAX_ARGS;
2147 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002148 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002149 return -1;
2150 }
2151 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002152#elif defined(ARM)
2153 {
2154 int i;
2155
2156 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2157 tcp->u_nargs = sysent[tcp->scno].nargs;
2158 else
2159 tcp->u_nargs = MAX_ARGS;
2160 for (i = 0; i < tcp->u_nargs; i++)
2161 tcp->u_arg[i] = regs.uregs[i];
2162 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002163#elif defined(BFIN)
2164 {
2165 int i;
2166 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2167
2168 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2169 tcp->u_nargs = sysent[tcp->scno].nargs;
2170 else
2171 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2172
2173 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002174 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002175 return -1;
2176 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002177#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002178 {
2179 int i;
2180 static int syscall_regs[] = {
2181 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2182 REG_REG0, REG_REG0+1, REG_REG0+2
2183 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002184
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002185 tcp->u_nargs = sysent[tcp->scno].nargs;
2186 for (i = 0; i < tcp->u_nargs; i++) {
2187 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2188 return -1;
2189 }
2190 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002191#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002192 {
2193 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002194 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002195 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2196
2197 /*
2198 * TODO: should also check that the number of arguments encoded
2199 * in the trap number matches the number strace expects.
2200 */
2201 /*
2202 assert(sysent[tcp->scno].nargs <
2203 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2204 */
2205
2206 tcp->u_nargs = sysent[tcp->scno].nargs;
2207 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002208 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002209 return -1;
2210 }
2211 }
2212
Michal Ludvig0e035502002-09-23 15:41:01 +00002213#elif defined(X86_64)
2214 {
2215 int i;
2216 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2217 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002218 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002219 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002220
Michal Ludvig0e035502002-09-23 15:41:01 +00002221 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2222 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002223 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002224 tcp->u_nargs = MAX_ARGS;
2225 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002226 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002227 return -1;
2228 }
2229 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002230#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002231 {
2232 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002233 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2234 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002235 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002236 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002237 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002238 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002239 return -1;
2240 }
2241 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002242#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002243#endif /* LINUX */
2244#ifdef SUNOS4
2245 {
2246 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002247 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2248 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002249 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002250 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002251 for (i = 0; i < tcp->u_nargs; i++) {
2252 struct user *u;
2253
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002254 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002255 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2256 return -1;
2257 }
2258 }
2259#endif /* SUNOS4 */
2260#ifdef SVR4
2261#ifdef MIPS
2262 /*
2263 * SGI is broken: even though it has pr_sysarg, it doesn't
2264 * set them on system call entry. Get a clue.
2265 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002266 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002267 tcp->u_nargs = sysent[tcp->scno].nargs;
2268 else
2269 tcp->u_nargs = tcp->status.pr_nsysarg;
2270 if (tcp->u_nargs > 4) {
2271 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2272 4*sizeof(tcp->u_arg[0]));
2273 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2274 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2275 }
2276 else {
2277 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2278 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2279 }
John Hughes25299712001-03-06 10:10:06 +00002280#elif UNIXWARE >= 2
2281 /*
2282 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2283 */
2284 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2285 tcp->u_nargs = sysent[tcp->scno].nargs;
2286 else
2287 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2288 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2289 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2290#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002291 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002292 tcp->u_nargs = sysent[tcp->scno].nargs;
2293 else
2294 tcp->u_nargs = tcp->status.pr_nsysarg;
2295 {
2296 int i;
2297 for (i = 0; i < tcp->u_nargs; i++)
2298 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2299 }
John Hughes25299712001-03-06 10:10:06 +00002300#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002301 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002302 tcp->u_nargs = sysent[tcp->scno].nargs;
2303 else
2304 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002305 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002306 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002307#else
2308 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002309#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002310#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002311#ifdef FREEBSD
2312 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2313 sysent[tcp->scno].nargs > tcp->status.val)
2314 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002315 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002316 tcp->u_nargs = tcp->status.val;
2317 if (tcp->u_nargs < 0)
2318 tcp->u_nargs = 0;
2319 if (tcp->u_nargs > MAX_ARGS)
2320 tcp->u_nargs = MAX_ARGS;
2321 switch(regs.r_eax) {
2322 case SYS___syscall:
2323 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2324 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002325 break;
2326 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002327 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2328 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002329 break;
2330 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002331 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2332 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002333 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002334 }
2335#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002336 return 1;
2337}
2338
2339int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002340trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002341{
2342 int sys_res;
2343 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002344 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002345
2346 if (tcp->flags & TCB_INSYSCALL) {
2347 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002348
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002349 /* Measure the exit time as early as possible to avoid errors. */
2350 if (dtime)
2351 gettimeofday(&tv, NULL);
2352
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002353 /* In code below,
2354 * res = 1: no error, continue
2355 * res = 0: return 0 at once (not an error)
2356 * any other value: error, complain and return the value
2357 *
2358 * BTW, why we don't just memorize syscall no. on entry
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002359 * in tcp->something?
2360 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002361 scno_good = res = get_scno(tcp);
2362 if (res == 0)
2363 return res;
2364 if (res == 1)
2365 res = syscall_fixup(tcp);
2366 if (res == 0)
2367 return res;
2368 if (res == 1)
2369 res = get_error(tcp);
2370 if (res == 0)
2371 return res;
2372 if (res == 1)
2373 internal_syscall(tcp);
2374
2375 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002376 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002377 tcp->flags &= ~TCB_INSYSCALL;
2378 return 0;
2379 }
2380
2381 if (tcp->flags & TCB_REPRINT) {
2382 printleader(tcp);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002383 if (scno_good != 1) {
2384 tprintf("<... syscall_?? resumed> ");
2385 } else {
2386 if (tcp->scno >= nsyscalls || tcp->scno < 0)
2387 tprintf("<... syscall_%lu resumed> ", tcp->scno);
2388 else
2389 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
2390 }
2391 /* [do we need to clear TCB_REPRINT?...] */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002392 }
2393
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002394 if (cflag)
2395 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002396
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002397 if (res != 1) {
2398 tprintf(") ");
2399 tabto(acolumn);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002400 tprintf("= ?");
2401 /* line will be finished by error handling code */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002402 tcp->flags &= ~TCB_INSYSCALL;
2403 return res;
2404 }
2405
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002406 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002407 || (qual_flags[tcp->scno] & QUAL_RAW))
2408 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002409 else {
2410 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002411 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002412 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002413 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002414 u_error = tcp->u_error;
2415 tprintf(") ");
2416 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002417 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2418 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002419 if (u_error)
2420 tprintf("= -1 (errno %ld)", u_error);
2421 else
2422 tprintf("= %#lx", tcp->u_rval);
2423 }
2424 else if (!(sys_res & RVAL_NONE) && u_error) {
2425 switch (u_error) {
2426#ifdef LINUX
2427 case ERESTARTSYS:
2428 tprintf("= ? ERESTARTSYS (To be restarted)");
2429 break;
2430 case ERESTARTNOINTR:
2431 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2432 break;
2433 case ERESTARTNOHAND:
2434 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2435 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002436 case ERESTART_RESTARTBLOCK:
2437 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2438 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002439#endif /* LINUX */
2440 default:
2441 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002442 if (u_error < 0)
2443 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002444 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002445 tprintf("%s (%s)", errnoent[u_error],
2446 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002447 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002448 tprintf("ERRNO_%ld (%s)", u_error,
2449 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002450 break;
2451 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002452 if ((sys_res & RVAL_STR) && tcp->auxstr)
2453 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002454 }
2455 else {
2456 if (sys_res & RVAL_NONE)
2457 tprintf("= ?");
2458 else {
2459 switch (sys_res & RVAL_MASK) {
2460 case RVAL_HEX:
2461 tprintf("= %#lx", tcp->u_rval);
2462 break;
2463 case RVAL_OCTAL:
2464 tprintf("= %#lo", tcp->u_rval);
2465 break;
2466 case RVAL_UDECIMAL:
2467 tprintf("= %lu", tcp->u_rval);
2468 break;
2469 case RVAL_DECIMAL:
2470 tprintf("= %ld", tcp->u_rval);
2471 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002472#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002473 case RVAL_LHEX:
2474 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002475 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002476 case RVAL_LOCTAL:
2477 tprintf("= %#llo", tcp->u_lrval);
2478 break;
2479 case RVAL_LUDECIMAL:
2480 tprintf("= %llu", tcp->u_lrval);
2481 break;
2482 case RVAL_LDECIMAL:
2483 tprintf("= %lld", tcp->u_lrval);
2484 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002485#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002486 default:
2487 fprintf(stderr,
2488 "invalid rval format\n");
2489 break;
2490 }
2491 }
2492 if ((sys_res & RVAL_STR) && tcp->auxstr)
2493 tprintf(" (%s)", tcp->auxstr);
2494 }
2495 if (dtime) {
2496 tv_sub(&tv, &tv, &tcp->etime);
2497 tprintf(" <%ld.%06ld>",
2498 (long) tv.tv_sec, (long) tv.tv_usec);
2499 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002500 printtrailer();
Pavel Machek4dc3b142000-02-01 17:58:41 +00002501
2502 dumpio(tcp);
2503 if (fflush(tcp->outf) == EOF)
2504 return -1;
2505 tcp->flags &= ~TCB_INSYSCALL;
2506 return 0;
2507 }
2508
2509 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002510 scno_good = res = get_scno(tcp);
2511 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002512 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002513 if (res == 1)
2514 res = syscall_fixup(tcp);
2515 if (res == 0)
2516 return res;
2517 if (res == 1)
2518 res = syscall_enter(tcp);
2519 if (res == 0)
2520 return res;
2521
2522 if (res != 1) {
2523 printleader(tcp);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002524 tcp->flags &= ~TCB_REPRINT; /* why? */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002525 tcp_last = tcp;
2526 if (scno_good != 1)
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002527 tprintf("syscall_??" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002528 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2529 tprintf("syscall_%lu(", tcp->scno);
2530 else
2531 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002532 /* Line will be finished by error handling code. */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002533 tcp->flags |= TCB_INSYSCALL;
2534 return res;
2535 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002536
Roland McGrath17352792005-06-07 23:21:26 +00002537 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002538#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002539 case SYS_socketcall:
2540 decode_subcall(tcp, SYS_socket_subcall,
2541 SYS_socket_nsubcalls, deref_style);
2542 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002543#endif
2544#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002545 case SYS_ipc:
2546 decode_subcall(tcp, SYS_ipc_subcall,
2547 SYS_ipc_nsubcalls, shift_style);
2548 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002549#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002550#ifdef SVR4
2551#ifdef SYS_pgrpsys_subcall
2552 case SYS_pgrpsys:
2553 decode_subcall(tcp, SYS_pgrpsys_subcall,
2554 SYS_pgrpsys_nsubcalls, shift_style);
2555 break;
2556#endif /* SYS_pgrpsys_subcall */
2557#ifdef SYS_sigcall_subcall
2558 case SYS_sigcall:
2559 decode_subcall(tcp, SYS_sigcall_subcall,
2560 SYS_sigcall_nsubcalls, mask_style);
2561 break;
2562#endif /* SYS_sigcall_subcall */
2563 case SYS_msgsys:
2564 decode_subcall(tcp, SYS_msgsys_subcall,
2565 SYS_msgsys_nsubcalls, shift_style);
2566 break;
2567 case SYS_shmsys:
2568 decode_subcall(tcp, SYS_shmsys_subcall,
2569 SYS_shmsys_nsubcalls, shift_style);
2570 break;
2571 case SYS_semsys:
2572 decode_subcall(tcp, SYS_semsys_subcall,
2573 SYS_semsys_nsubcalls, shift_style);
2574 break;
2575#if 0 /* broken */
2576 case SYS_utssys:
2577 decode_subcall(tcp, SYS_utssys_subcall,
2578 SYS_utssys_nsubcalls, shift_style);
2579 break;
2580#endif
2581 case SYS_sysfs:
2582 decode_subcall(tcp, SYS_sysfs_subcall,
2583 SYS_sysfs_nsubcalls, shift_style);
2584 break;
2585 case SYS_spcall:
2586 decode_subcall(tcp, SYS_spcall_subcall,
2587 SYS_spcall_nsubcalls, shift_style);
2588 break;
2589#ifdef SYS_context_subcall
2590 case SYS_context:
2591 decode_subcall(tcp, SYS_context_subcall,
2592 SYS_context_nsubcalls, shift_style);
2593 break;
2594#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002595#ifdef SYS_door_subcall
2596 case SYS_door:
2597 decode_subcall(tcp, SYS_door_subcall,
2598 SYS_door_nsubcalls, door_style);
2599 break;
2600#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002601#ifdef SYS_kaio_subcall
2602 case SYS_kaio:
2603 decode_subcall(tcp, SYS_kaio_subcall,
2604 SYS_kaio_nsubcalls, shift_style);
2605 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002606#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002607#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002608#ifdef FREEBSD
2609 case SYS_msgsys:
2610 case SYS_shmsys:
2611 case SYS_semsys:
2612 decode_subcall(tcp, 0, 0, table_style);
2613 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002614#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615#ifdef SUNOS4
2616 case SYS_semsys:
2617 decode_subcall(tcp, SYS_semsys_subcall,
2618 SYS_semsys_nsubcalls, shift_style);
2619 break;
2620 case SYS_msgsys:
2621 decode_subcall(tcp, SYS_msgsys_subcall,
2622 SYS_msgsys_nsubcalls, shift_style);
2623 break;
2624 case SYS_shmsys:
2625 decode_subcall(tcp, SYS_shmsys_subcall,
2626 SYS_shmsys_nsubcalls, shift_style);
2627 break;
2628#endif
2629 }
2630
2631 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002632 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002633 tcp->flags |= TCB_INSYSCALL;
2634 return 0;
2635 }
2636
2637 if (cflag) {
2638 gettimeofday(&tcp->etime, NULL);
2639 tcp->flags |= TCB_INSYSCALL;
2640 return 0;
2641 }
2642
2643 printleader(tcp);
2644 tcp->flags &= ~TCB_REPRINT;
2645 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002646 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002647 tprintf("syscall_%lu(", tcp->scno);
2648 else
2649 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002650 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2652 sys_res = printargs(tcp);
2653 else
2654 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2655 if (fflush(tcp->outf) == EOF)
2656 return -1;
2657 tcp->flags |= TCB_INSYSCALL;
2658 /* Measure the entrance time as late as possible to avoid errors. */
2659 if (dtime)
2660 gettimeofday(&tcp->etime, NULL);
2661 return sys_res;
2662}
2663
2664int
2665printargs(tcp)
2666struct tcb *tcp;
2667{
2668 if (entering(tcp)) {
2669 int i;
2670
2671 for (i = 0; i < tcp->u_nargs; i++)
2672 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2673 }
2674 return 0;
2675}
2676
2677long
2678getrval2(tcp)
2679struct tcb *tcp;
2680{
2681 long val = -1;
2682
2683#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002684#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002685 struct regs regs;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002686 if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002687 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002688 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002689#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002690 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002691 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002692#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002693 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002694 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002695#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002696#endif /* LINUX */
2697
2698#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002699 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002700 return -1;
2701#endif /* SUNOS4 */
2702
2703#ifdef SVR4
2704#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002705 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002706#endif /* SPARC */
2707#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002708 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002709#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002710#ifdef X86_64
2711 val = tcp->status.PR_REG[RDX];
2712#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002714 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002715#endif /* MIPS */
2716#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002717#ifdef FREEBSD
2718 struct reg regs;
2719 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2720 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002721#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002722 return val;
2723}
2724
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002725#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002726/*
2727 * Apparently, indirect system calls have already be converted by ptrace(2),
2728 * so if you see "indir" this program has gone astray.
2729 */
2730int
2731sys_indir(tcp)
2732struct tcb *tcp;
2733{
2734 int i, scno, nargs;
2735
2736 if (entering(tcp)) {
2737 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2738 fprintf(stderr, "Bogus syscall: %u\n", scno);
2739 return 0;
2740 }
2741 nargs = sysent[scno].nargs;
2742 tprintf("%s", sysent[scno].sys_name);
2743 for (i = 0; i < nargs; i++)
2744 tprintf(", %#lx", tcp->u_arg[i+1]);
2745 }
2746 return 0;
2747}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002748#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002749
2750int
2751is_restart_error(struct tcb *tcp)
2752{
2753#ifdef LINUX
2754 if (!syserror(tcp))
2755 return 0;
2756 switch (tcp->u_error) {
2757 case ERESTARTSYS:
2758 case ERESTARTNOINTR:
2759 case ERESTARTNOHAND:
2760 case ERESTART_RESTARTBLOCK:
2761 return 1;
2762 default:
2763 break;
2764 }
2765#endif /* LINUX */
2766 return 0;
2767}