blob: 10b6627a9468dc31472a692171eb84bb60111208 [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
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +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)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000329 return -1;
330 qualify_one(i, opt, not, -1);
331 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000332 }
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
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000367 if (isdigit((unsigned char)*s)) {
368 int signo = atoi(s);
369 if (signo < 0 || signo >= MAX_QUALS)
370 return -1;
371 qualify_one(signo, opt, not, -1);
372 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;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000756#elif defined(AVR32)
757 static struct pt_regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000758#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000759 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000760 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000761#elif defined(LINUX_MIPSN32)
762 static long long a3;
763 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000764#elif defined(MIPS)
765 static long a3;
766 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000767#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000768 static long gpr2;
769 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000770 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000771#elif defined(HPPA)
772 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000773#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000774 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000775#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000776 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000777#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000778 static long rax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000779#elif defined(CRISV10) || defined(CRISV32)
780 static long r10;
Roland McGrath761b5d72002-12-15 23:58:31 +0000781#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000782#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000783#ifdef FREEBSD
784 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000785#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000786
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000788get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000793# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000794 if (tcp->flags & TCB_WAITEXECVE) {
795 /*
796 * When the execve system call completes successfully, the
797 * new process still has -ENOSYS (old style) or __NR_execve
798 * (new style) in gpr2. We cannot recover the scno again
799 * by disassembly, because the image that executed the
800 * syscall is gone now. Fortunately, we don't want it. We
801 * leave the flag set so that syscall_fixup can fake the
802 * result.
803 */
804 if (tcp->flags & TCB_INSYSCALL)
805 return 1;
806 /*
807 * This is the SIGTRAP after execve. We cannot try to read
808 * the system call here either.
809 */
810 tcp->flags &= ~TCB_WAITEXECVE;
811 return 0;
812 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000813
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000814 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000815 return -1;
816
817 if (syscall_mode != -ENOSYS) {
818 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000819 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000820 */
821 scno = syscall_mode;
822 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000823 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000824 * Old style of "passing" the scno via the SVC instruction.
825 */
826
827 long opcode, offset_reg, tmp;
828 void * svc_addr;
829 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
830 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
831 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
832 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000833
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000834 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000835 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000836 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000837 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000838 if (errno) {
839 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000840 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000841 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000842
843 /*
844 * We have to check if the SVC got executed directly or via an
845 * EXECUTE instruction. In case of EXECUTE it is necessary to do
846 * instruction decoding to derive the system call number.
847 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
848 * so that this doesn't work if a SVC opcode is part of an EXECUTE
849 * opcode. Since there is no way to find out the opcode size this
850 * is the best we can do...
851 */
852
853 if ((opcode & 0xff00) == 0x0a00) {
854 /* SVC opcode */
855 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000856 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000857 else {
858 /* SVC got executed by EXECUTE instruction */
859
860 /*
861 * Do instruction decoding of EXECUTE. If you really want to
862 * understand this, read the Principles of Operations.
863 */
864 svc_addr = (void *) (opcode & 0xfff);
865
866 tmp = 0;
867 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000868 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000869 return -1;
870 svc_addr += tmp;
871
872 tmp = 0;
873 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000874 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000875 return -1;
876 svc_addr += tmp;
877
Denys Vlasenkofb036672009-01-23 16:30:26 +0000878 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000879 if (errno)
880 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000881# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000882 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000883# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000884 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000885# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000886 tmp = 0;
887 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000888 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000889 return -1;
890
891 scno = (scno | tmp) & 0xff;
892 }
893 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000894# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000895 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000896 return -1;
897 if (!(tcp->flags & TCB_INSYSCALL)) {
898 /* Check if we return from execve. */
899 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
900 tcp->flags &= ~TCB_WAITEXECVE;
901 return 0;
902 }
903 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000904# elif defined(AVR32)
905 /*
906 * Read complete register set in one go.
907 */
908 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
909 return -1;
910
911 /*
912 * We only need to grab the syscall number on syscall entry.
913 */
914 if (!(tcp->flags & TCB_INSYSCALL)) {
915 scno = regs.r8;
916
917 /* Check if we return from execve. */
918 if (tcp->flags & TCB_WAITEXECVE) {
919 tcp->flags &= ~TCB_WAITEXECVE;
920 return 0;
921 }
922 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000923# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000924 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000925 return -1;
926 /* Check if we return from execve. */
927 if (tcp->flags & TCB_WAITEXECVE && tcp->flags & TCB_INSYSCALL)
928 tcp->flags &= ~(TCB_INSYSCALL | TCB_WAITEXECVE);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000929# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000930 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000932# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000933 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000934 return -1;
935
Roland McGrath761b5d72002-12-15 23:58:31 +0000936 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000937 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000938 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000939 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000940
941 /* Check CS register value. On x86-64 linux it is:
942 * 0x33 for long mode (64 bit)
943 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000944 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000945 * to be cached.
946 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000947 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000948 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000949 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000950 case 0x23: currpers = 1; break;
951 case 0x33: currpers = 0; break;
952 default:
953 fprintf(stderr, "Unknown value CS=0x%02X while "
954 "detecting personality of process "
955 "PID=%d\n", (int)val, pid);
956 currpers = current_personality;
957 break;
958 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000959# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000960 /* This version analyzes the opcode of a syscall instruction.
961 * (int 0x80 on i386 vs. syscall on x86-64)
962 * It works, but is too complicated.
963 */
964 unsigned long val, rip, i;
965
Denys Vlasenko8236f252009-01-02 18:10:08 +0000966 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000967 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000968
Michal Ludvig0e035502002-09-23 15:41:01 +0000969 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000970 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000971 errno = 0;
972
Denys Vlasenko8236f252009-01-02 18:10:08 +0000973 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000974 if (errno)
975 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000976 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000977 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000978 /* x86-64: syscall = 0x0f 0x05 */
979 case 0x050f: currpers = 0; break;
980 /* i386: int 0x80 = 0xcd 0x80 */
981 case 0x80cd: currpers = 1; break;
982 default:
983 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000984 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000985 "Unknown syscall opcode (0x%04X) while "
986 "detecting personality of process "
987 "PID=%d\n", (int)call, pid);
988 break;
989 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000990# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000991 if (currpers != current_personality) {
992 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000993 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000994 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000995 pid, names[current_personality]);
996 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000997 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000998# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000999# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001000 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001001 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001002 if (!(tcp->flags & TCB_INSYSCALL)) {
1003 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001004 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001005 return -1;
1006 } else {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001007 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001008 return -1;
1009 }
Roland McGrathba954762003-03-05 06:29:06 +00001010 /* Check if we return from execve. */
1011 if (tcp->flags & TCB_WAITEXECVE) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001012# if defined PTRACE_GETSIGINFO
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001013 siginfo_t si;
1014
1015 tcp->flags &= ~TCB_WAITEXECVE;
1016 /* If SIGTRAP is masked, execve's magic SIGTRAP
1017 * is not delivered. We end up here on a subsequent
1018 * ptrace stop instead. Luckily, we can check
1019 * for the type of this SIGTRAP. execve's magic one
1020 * has 0 (SI_USER) in si.si_code, ptrace stop has 5.
1021 * (I don't know why 5).
1022 */
1023 si.si_code = SI_USER;
1024 /* If PTRACE_GETSIGINFO fails, we assume it's
1025 * magic SIGTRAP. Moot anyway, PTRACE_GETSIGINFO
1026 * doesn't fail.
1027 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001028 ptrace(PTRACE_GETSIGINFO, tcp->pid, (void*) 0, (void*) &si);
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001029 if (si.si_code == SI_USER)
1030 return 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001031# else
Roland McGrathba954762003-03-05 06:29:06 +00001032 tcp->flags &= ~TCB_WAITEXECVE;
1033 return 0;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001034# endif
Roland McGrathba954762003-03-05 06:29:06 +00001035 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001036 } else {
1037 /* syscall in progress */
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001038 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001039 return -1;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001040 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001041 return -1;
1042 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001043# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001044 /*
1045 * Read complete register set in one go.
1046 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001047 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001048 return -1;
1049
1050 /*
1051 * We only need to grab the syscall number on syscall entry.
1052 */
1053 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001054 if (!(tcp->flags & TCB_INSYSCALL)) {
1055 /* Check if we return from execve. */
1056 if (tcp->flags & TCB_WAITEXECVE) {
1057 tcp->flags &= ~TCB_WAITEXECVE;
1058 return 0;
1059 }
1060 }
1061
Roland McGrath0f87c492003-06-03 23:29:04 +00001062 /*
1063 * Note: we only deal with only 32-bit CPUs here.
1064 */
1065 if (regs.ARM_cpsr & 0x20) {
1066 /*
1067 * Get the Thumb-mode system call number
1068 */
1069 scno = regs.ARM_r7;
1070 } else {
1071 /*
1072 * Get the ARM-mode system call number
1073 */
1074 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001075 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001076 if (errno)
1077 return -1;
1078
1079 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1080 tcp->flags &= ~TCB_WAITEXECVE;
1081 return 0;
1082 }
1083
Roland McGrathf691bd22006-04-25 07:34:41 +00001084 /* Handle the EABI syscall convention. We do not
1085 bother converting structures between the two
1086 ABIs, but basic functionality should work even
1087 if strace and the traced program have different
1088 ABIs. */
1089 if (scno == 0xef000000) {
1090 scno = regs.ARM_r7;
1091 } else {
1092 if ((scno & 0x0ff00000) != 0x0f900000) {
1093 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1094 scno);
1095 return -1;
1096 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001097
Roland McGrathf691bd22006-04-25 07:34:41 +00001098 /*
1099 * Fixup the syscall number
1100 */
1101 scno &= 0x000fffff;
1102 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001103 }
Roland McGrath56703312008-05-20 01:35:55 +00001104 if (scno & 0x0f0000) {
1105 /*
1106 * Handle ARM specific syscall
1107 */
1108 set_personality(1);
1109 scno &= 0x0000ffff;
1110 } else
1111 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001112
1113 if (tcp->flags & TCB_INSYSCALL) {
1114 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1115 tcp->flags &= ~TCB_INSYSCALL;
1116 }
1117 } else {
1118 if (!(tcp->flags & TCB_INSYSCALL)) {
1119 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1120 tcp->flags |= TCB_INSYSCALL;
1121 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001123# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001124 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001126# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001127 unsigned long long regs[38];
1128
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001129 if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001130 return -1;
1131 a3 = regs[REG_A3];
1132 r2 = regs[REG_V0];
1133
1134 if(!(tcp->flags & TCB_INSYSCALL)) {
1135 scno = r2;
1136
1137 /* Check if we return from execve. */
1138 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1139 tcp->flags &= ~TCB_WAITEXECVE;
1140 return 0;
1141 }
1142
1143 if (scno < 0 || scno > nsyscalls) {
1144 if(a3 == 0 || a3 == -1) {
1145 if(debug)
1146 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1147 return 0;
1148 }
1149 }
1150 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001151# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001152 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001153 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001154 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001155 if (upeek(tcp, REG_V0, &scno) < 0)
1156 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001157
Roland McGrath542c2c62008-05-20 01:11:56 +00001158 /* Check if we return from execve. */
1159 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1160 tcp->flags &= ~TCB_WAITEXECVE;
1161 return 0;
1162 }
1163
Wichert Akkermanf90da011999-10-31 21:15:38 +00001164 if (scno < 0 || scno > nsyscalls) {
1165 if(a3 == 0 || a3 == -1) {
1166 if(debug)
1167 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1168 return 0;
1169 }
1170 }
1171 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001172 if (upeek(tcp, REG_V0, &r2) < 0)
1173 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001174 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001175# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001176 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 return -1;
1178
1179 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001180 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 return -1;
1182
1183 /* Check if we return from execve. */
1184 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1185 tcp->flags &= ~TCB_WAITEXECVE;
1186 return 0;
1187 }
1188
1189 /*
1190 * Do some sanity checks to figure out if it's
1191 * really a syscall entry
1192 */
1193 if (scno < 0 || scno > nsyscalls) {
1194 if (a3 == 0 || a3 == -1) {
1195 if (debug)
1196 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1197 return 0;
1198 }
1199 }
1200 }
1201 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001202 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203 return -1;
1204 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001205# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001206 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001207 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001208 return -1;
1209
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001210 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001211 if (!(tcp->flags & TCB_INSYSCALL)) {
1212 /* Retrieve the syscall trap instruction. */
1213 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001214 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.r_pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001215# if defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001216 trap >>= 32;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001217# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001218 if (errno)
1219 return -1;
1220
1221 /* Disassemble the trap to see what personality to use. */
1222 switch (trap) {
1223 case 0x91d02010:
1224 /* Linux/SPARC syscall trap. */
1225 set_personality(0);
1226 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001227 case 0x91d0206d:
1228 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001229 set_personality(2);
1230 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231 case 0x91d02000:
1232 /* SunOS syscall trap. (pers 1) */
1233 fprintf(stderr,"syscall: SunOS no support\n");
1234 return -1;
1235 case 0x91d02008:
1236 /* Solaris 2.x syscall trap. (per 2) */
1237 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001238 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001239 case 0x91d02009:
1240 /* NetBSD/FreeBSD syscall trap. */
1241 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1242 return -1;
1243 case 0x91d02027:
1244 /* Solaris 2.x gettimeofday */
1245 set_personality(1);
1246 break;
1247 default:
1248 /* Unknown syscall trap. */
1249 if(tcp->flags & TCB_WAITEXECVE) {
1250 tcp->flags &= ~TCB_WAITEXECVE;
1251 return 0;
1252 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001253# if defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001254 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001255# else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001256 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001257# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001258 return -1;
1259 }
1260
1261 /* Extract the system call number from the registers. */
1262 if (trap == 0x91d02027)
1263 scno = 156;
1264 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001265 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001267 scno = regs.r_o0;
1268 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001269 }
1270 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001271# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001272 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001273 return -1;
1274 if (!(tcp->flags & TCB_INSYSCALL)) {
1275 /* Check if we return from execve. */
1276 if ((tcp->flags & TCB_WAITEXECVE)) {
1277 tcp->flags &= ~TCB_WAITEXECVE;
1278 return 0;
1279 }
1280 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001281# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001282 /*
1283 * In the new syscall ABI, the system call number is in R3.
1284 */
1285 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1286 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001287
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001288 if (scno < 0) {
1289 /* Odd as it may seem, a glibc bug has been known to cause
1290 glibc to issue bogus negative syscall numbers. So for
1291 our purposes, make strace print what it *should* have been */
1292 long correct_scno = (scno & 0xff);
1293 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001294 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001295 "Detected glibc bug: bogus system call"
1296 " number = %ld, correcting to %ld\n",
1297 scno,
1298 correct_scno);
1299 scno = correct_scno;
1300 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001301
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001302 if (!(tcp->flags & TCB_INSYSCALL)) {
1303 /* Check if we return from execve. */
1304 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1305 tcp->flags &= ~TCB_WAITEXECVE;
1306 return 0;
1307 }
1308 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001309# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001310 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001311 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001312 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001313
1314 if (!(tcp->flags & TCB_INSYSCALL)) {
1315 /* Check if we return from execve. */
1316 if (tcp->flags & TCB_WAITEXECVE) {
1317 tcp->flags &= ~TCB_WAITEXECVE;
1318 return 0;
1319 }
1320 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001321# elif defined(CRISV10) || defined(CRISV32)
1322 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1323 return -1;
1324# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001325#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001326
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001328 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001330#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001331 /* new syscall ABI returns result in R0 */
1332 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1333 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001334#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001335 /* ABI defines result returned in r9 */
1336 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1337 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001338#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001339
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001340#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001341# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001342 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001343# else
1344# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001345 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001346# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001347 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001348 perror("pread");
1349 return -1;
1350 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001351 switch (regs.r_eax) {
1352 case SYS_syscall:
1353 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001354 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1355 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001356 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001357 scno = regs.r_eax;
1358 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001359 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001360# endif /* FREEBSD */
1361# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001362#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001363
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001364 if (!(tcp->flags & TCB_INSYSCALL))
1365 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001366 return 1;
1367}
1368
Pavel Machek4dc3b142000-02-01 17:58:41 +00001369
Roland McGrath17352792005-06-07 23:21:26 +00001370long
1371known_scno(tcp)
1372struct tcb *tcp;
1373{
1374 long scno = tcp->scno;
1375 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1376 scno = sysent[scno].native_scno;
1377 else
1378 scno += NR_SYSCALL_BASE;
1379 return scno;
1380}
1381
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001382/* Called in trace_syscall at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001383 * Returns:
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001384 * 0: "ignore this syscall", bail out of trace_syscall silently.
1385 * 1: ok, continue in trace_syscall.
1386 * other: error, trace_syscall should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001387 * ("????" etc) and bail out.
1388 */
Roland McGratha4d48532005-06-08 20:45:28 +00001389static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001390syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001391{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001392#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001393 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001394
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001395 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001396 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001397 if (
1398 scno == SYS_fork
1399#ifdef SYS_vfork
1400 || scno == SYS_vfork
1401#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001402#ifdef SYS_fork1
1403 || scno == SYS_fork1
1404#endif /* SYS_fork1 */
1405#ifdef SYS_forkall
1406 || scno == SYS_forkall
1407#endif /* SYS_forkall */
1408#ifdef SYS_rfork1
1409 || scno == SYS_rfork1
1410#endif /* SYS_fork1 */
1411#ifdef SYS_rforkall
1412 || scno == SYS_rforkall
1413#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001414 ) {
1415 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001416 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001417 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001418 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001419 }
1420 else {
1421 fprintf(stderr, "syscall: missing entry\n");
1422 tcp->flags |= TCB_INSYSCALL;
1423 }
1424 }
1425 }
1426 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001427 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001428 fprintf(stderr, "syscall: missing exit\n");
1429 tcp->flags &= ~TCB_INSYSCALL;
1430 }
1431 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001432#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001433#ifdef SUNOS4
1434 if (!(tcp->flags & TCB_INSYSCALL)) {
1435 if (scno == 0) {
1436 fprintf(stderr, "syscall: missing entry\n");
1437 tcp->flags |= TCB_INSYSCALL;
1438 }
1439 }
1440 else {
1441 if (scno != 0) {
1442 if (debug) {
1443 /*
1444 * This happens when a signal handler
1445 * for a signal which interrupted a
1446 * a system call makes another system call.
1447 */
1448 fprintf(stderr, "syscall: missing exit\n");
1449 }
1450 tcp->flags &= ~TCB_INSYSCALL;
1451 }
1452 }
1453#endif /* SUNOS4 */
1454#ifdef LINUX
1455#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001456 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001457 return -1;
1458 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1459 if (debug)
1460 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1461 return 0;
1462 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001463#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001464 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001465 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001466 if (current_personality == 1)
1467 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001468 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1469 if (debug)
1470 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1471 return 0;
1472 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001473#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001474 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001475 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001476 if (syscall_mode != -ENOSYS)
1477 syscall_mode = tcp->scno;
1478 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001479 if (debug)
1480 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1481 return 0;
1482 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001483 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1484 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1485 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1486 /*
1487 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1488 * flag set for the post-execve SIGTRAP to see and reset.
1489 */
1490 gpr2 = 0;
1491 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001492#elif defined (POWERPC)
1493# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001494 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001495 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001496 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001497 return -1;
1498 if (flags & SO_MASK)
1499 result = -result;
1500#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001501 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001502 return -1;
1503 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1504 if (debug)
1505 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1506 return 0;
1507 }
1508#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001509 /*
1510 * Nothing required
1511 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001512#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001513 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001514 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001515#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001516 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001517 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001518#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001519 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001520 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001521 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001522 return -1;
1523 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1524 if (debug)
1525 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1526 return 0;
1527 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001528#elif defined(CRISV10) || defined(CRISV32)
1529 if (upeek(tcp->pid, 4*PT_R10, &r10) < 0)
1530 return -1;
1531 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1532 if (debug)
1533 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1534 return 0;
1535 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001536#endif
1537#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001538 return 1;
1539}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001540
Roland McGrathc1e45922008-05-27 23:18:29 +00001541#ifdef LINUX
1542/*
1543 * Check the syscall return value register value for whether it is
1544 * a negated errno code indicating an error, or a success return value.
1545 */
1546static inline int
1547is_negated_errno(unsigned long int val)
1548{
1549 unsigned long int max = -(long int) nerrnos;
1550 if (personality_wordsize[current_personality] < sizeof(val)) {
1551 val = (unsigned int) val;
1552 max = (unsigned int) max;
1553 }
1554 return val > max;
1555}
1556#endif
1557
Roland McGratha4d48532005-06-08 20:45:28 +00001558static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001559get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001560{
1561 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001562#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001563# if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001564 if (is_negated_errno(gpr2)) {
1565 tcp->u_rval = -1;
1566 u_error = -gpr2;
1567 }
1568 else {
1569 tcp->u_rval = gpr2;
1570 u_error = 0;
1571 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001572# elif defined(I386)
Roland McGrathc1e45922008-05-27 23:18:29 +00001573 if (is_negated_errno(eax)) {
1574 tcp->u_rval = -1;
1575 u_error = -eax;
1576 }
1577 else {
1578 tcp->u_rval = eax;
1579 u_error = 0;
1580 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001581# elif defined(X86_64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001582 if (is_negated_errno(rax)) {
1583 tcp->u_rval = -1;
1584 u_error = -rax;
1585 }
1586 else {
1587 tcp->u_rval = rax;
1588 u_error = 0;
1589 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001590# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001591 if (ia32) {
1592 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001593
Roland McGrathc1e45922008-05-27 23:18:29 +00001594 err = (int)r8;
1595 if (is_negated_errno(err)) {
1596 tcp->u_rval = -1;
1597 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001598 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001599 else {
1600 tcp->u_rval = err;
1601 u_error = 0;
1602 }
1603 } else {
1604 if (r10) {
1605 tcp->u_rval = -1;
1606 u_error = r8;
1607 } else {
1608 tcp->u_rval = r8;
1609 u_error = 0;
1610 }
1611 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001612# elif defined(MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001613 if (a3) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001614 tcp->u_rval = -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001615 u_error = r2;
1616 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001617 tcp->u_rval = r2;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001618 u_error = 0;
1619 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001620# elif defined(POWERPC)
Roland McGrathc1e45922008-05-27 23:18:29 +00001621 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001622 tcp->u_rval = -1;
1623 u_error = -result;
1624 }
1625 else {
1626 tcp->u_rval = result;
1627 u_error = 0;
1628 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001629# elif defined(M68K)
Roland McGrathc1e45922008-05-27 23:18:29 +00001630 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631 tcp->u_rval = -1;
1632 u_error = -d0;
1633 }
1634 else {
1635 tcp->u_rval = d0;
1636 u_error = 0;
1637 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001638# elif defined(ARM)
Roland McGrathc1e45922008-05-27 23:18:29 +00001639 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001641 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642 }
1643 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001644 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645 u_error = 0;
1646 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001647# elif defined(AVR32)
1648 if (regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1649 tcp->u_rval = -1;
1650 u_error = -regs.r12;
1651 }
1652 else {
1653 tcp->u_rval = regs.r12;
1654 u_error = 0;
1655 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001656# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001657 if (is_negated_errno(r0)) {
1658 tcp->u_rval = -1;
1659 u_error = -r0;
1660 } else {
1661 tcp->u_rval = r0;
1662 u_error = 0;
1663 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001664# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001665 if (a3) {
1666 tcp->u_rval = -1;
1667 u_error = r0;
1668 }
1669 else {
1670 tcp->u_rval = r0;
1671 u_error = 0;
1672 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001673# elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001674 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001676 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677 }
1678 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001679 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001680 u_error = 0;
1681 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001682# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001683 if (regs.r_tstate & 0x1100000000UL) {
1684 tcp->u_rval = -1;
1685 u_error = regs.r_o0;
1686 }
1687 else {
1688 tcp->u_rval = regs.r_o0;
1689 u_error = 0;
1690 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001691# elif defined(HPPA)
Roland McGrathc1e45922008-05-27 23:18:29 +00001692 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001693 tcp->u_rval = -1;
1694 u_error = -r28;
1695 }
1696 else {
1697 tcp->u_rval = r28;
1698 u_error = 0;
1699 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001700# elif defined(SH)
Roland McGrathc1e45922008-05-27 23:18:29 +00001701 /* interpret R0 as return value or error number */
1702 if (is_negated_errno(r0)) {
1703 tcp->u_rval = -1;
1704 u_error = -r0;
1705 }
1706 else {
1707 tcp->u_rval = r0;
1708 u_error = 0;
1709 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001710# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001711 /* interpret result as return value or error number */
1712 if (is_negated_errno(r9)) {
1713 tcp->u_rval = -1;
1714 u_error = -r9;
1715 }
1716 else {
1717 tcp->u_rval = r9;
1718 u_error = 0;
1719 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001720# elif defined(CRISV10) || defined(CRISV32)
1721 if (r10 && (unsigned) -r10 < nerrnos) {
1722 tcp->u_rval = -1;
1723 u_error = -r10;
1724 }
1725 else {
1726 tcp->u_rval = r10;
1727 u_error = 0;
1728 }
1729# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001730#endif /* LINUX */
1731#ifdef SUNOS4
1732 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001733 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734 return -1;
1735 u_error >>= 24; /* u_error is a char */
1736
1737 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001738 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739 return -1;
1740#endif /* SUNOS4 */
1741#ifdef SVR4
1742#ifdef SPARC
1743 /* Judicious guessing goes a long way. */
1744 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1745 tcp->u_rval = -1;
1746 u_error = tcp->status.pr_reg[R_O0];
1747 }
1748 else {
1749 tcp->u_rval = tcp->status.pr_reg[R_O0];
1750 u_error = 0;
1751 }
1752#endif /* SPARC */
1753#ifdef I386
1754 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001755 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001756 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001757 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001758 }
1759 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001760 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001761#ifdef HAVE_LONG_LONG
1762 tcp->u_lrval =
1763 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1764 tcp->status.PR_REG[EAX];
1765#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001766 u_error = 0;
1767 }
1768#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001769#ifdef X86_64
1770 /* Wanna know how to kill an hour single-stepping? */
1771 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1772 tcp->u_rval = -1;
1773 u_error = tcp->status.PR_REG[RAX];
1774 }
1775 else {
1776 tcp->u_rval = tcp->status.PR_REG[RAX];
1777 u_error = 0;
1778 }
1779#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780#ifdef MIPS
1781 if (tcp->status.pr_reg[CTX_A3]) {
1782 tcp->u_rval = -1;
1783 u_error = tcp->status.pr_reg[CTX_V0];
1784 }
1785 else {
1786 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1787 u_error = 0;
1788 }
1789#endif /* MIPS */
1790#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001791#ifdef FREEBSD
1792 if (regs.r_eflags & PSL_C) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001793 tcp->u_rval = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001794 u_error = regs.r_eax;
1795 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001796 tcp->u_rval = regs.r_eax;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001797 tcp->u_lrval =
1798 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1799 u_error = 0;
1800 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001801#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001802 tcp->u_error = u_error;
1803 return 1;
1804}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001805
Roland McGrathb69f81b2002-12-21 23:25:18 +00001806int
1807force_result(tcp, error, rval)
1808 struct tcb *tcp;
1809 int error;
1810 long rval;
1811{
1812#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001813# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001814 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001815 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1816 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001817# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001818 eax = error ? -error : rval;
1819 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1820 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001821# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001822 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001823 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001824 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001825# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001826 if (ia32) {
1827 r8 = error ? -error : rval;
1828 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1829 return -1;
1830 }
1831 else {
1832 if (error) {
1833 r8 = error;
1834 r10 = -1;
1835 }
1836 else {
1837 r8 = rval;
1838 r10 = 0;
1839 }
1840 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1841 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1842 return -1;
1843 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001844# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001845 r0 = error ? -error : rval;
1846 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1847 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001848# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001849 if (error) {
1850 r2 = error;
1851 a3 = -1;
1852 }
1853 else {
1854 r2 = rval;
1855 a3 = 0;
1856 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001857 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001858 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1859 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001860 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001861# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001862 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001863 return -1;
1864 if (error) {
1865 flags |= SO_MASK;
1866 result = error;
1867 }
1868 else {
1869 flags &= ~SO_MASK;
1870 result = rval;
1871 }
Roland McGratheb285352003-01-14 09:59:00 +00001872 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1873 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001874 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001875# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001876 d0 = error ? -error : rval;
1877 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1878 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001879# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001880 regs.ARM_r0 = error ? -error : rval;
1881 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001882 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001883# elif defined(AVR32)
1884 regs.r12 = error ? -error : rval;
1885 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1886 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001887# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001888 if (error) {
1889 a3 = -1;
1890 r0 = error;
1891 }
1892 else {
1893 a3 = 0;
1894 r0 = rval;
1895 }
1896 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1897 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1898 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001899# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001900 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1901 return -1;
1902 if (error) {
1903 regs.r_psr |= PSR_C;
1904 regs.r_o0 = error;
1905 }
1906 else {
1907 regs.r_psr &= ~PSR_C;
1908 regs.r_o0 = rval;
1909 }
1910 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1911 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001912# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001913 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1914 return -1;
1915 if (error) {
1916 regs.r_tstate |= 0x1100000000UL;
1917 regs.r_o0 = error;
1918 }
1919 else {
1920 regs.r_tstate &= ~0x1100000000UL;
1921 regs.r_o0 = rval;
1922 }
1923 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1924 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001925# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001926 r28 = error ? -error : rval;
1927 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1928 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001929# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001930 r0 = error ? -error : rval;
1931 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1932 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001933# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001934 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001935 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1936 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001937# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001938#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001939
Roland McGrathb69f81b2002-12-21 23:25:18 +00001940#ifdef SUNOS4
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001941 if (do_ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error), error << 24) < 0
1942 || do_ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0
1943 ) {
Roland McGrathb69f81b2002-12-21 23:25:18 +00001944 return -1;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001945 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001946#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001947
Roland McGrathb69f81b2002-12-21 23:25:18 +00001948#ifdef SVR4
1949 /* XXX no clue */
1950 return -1;
1951#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001952
Roland McGrathb69f81b2002-12-21 23:25:18 +00001953#ifdef FREEBSD
1954 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001955 perror("pread");
1956 return -1;
1957 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001958 if (error) {
1959 regs.r_eflags |= PSL_C;
1960 regs.r_eax = error;
1961 }
1962 else {
1963 regs.r_eflags &= ~PSL_C;
1964 regs.r_eax = rval;
1965 }
1966 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001967 perror("pwrite");
1968 return -1;
1969 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001970#endif /* FREEBSD */
1971
1972 /* All branches reach here on success (only). */
1973 tcp->u_error = error;
1974 tcp->u_rval = rval;
1975 return 0;
1976}
1977
Roland McGratha4d48532005-06-08 20:45:28 +00001978static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001979syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001980{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001981#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001982#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001983 {
1984 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001985 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1986 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001987 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001988 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001989 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001990 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001991 return -1;
1992 }
1993 }
1994#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001995 {
1996 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001997 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1998 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001999 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002000 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002001 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00002002 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
2003 * for scno somewhere above here!
2004 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002005 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002006 return -1;
2007 }
2008 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002009#elif defined (IA64)
2010 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002011 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002012 unsigned long *out0, cfm, sof, sol, i;
2013 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002014 /* be backwards compatible with kernel < 2.4.4... */
2015# ifndef PT_RBS_END
2016# define PT_RBS_END PT_AR_BSP
2017# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002018
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002019 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002020 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002021 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002022 return -1;
2023
2024 sof = (cfm >> 0) & 0x7f;
2025 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002026 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002027
2028 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2029 && sysent[tcp->scno].nargs != -1)
2030 tcp->u_nargs = sysent[tcp->scno].nargs;
2031 else
2032 tcp->u_nargs = MAX_ARGS;
2033 for (i = 0; i < tcp->u_nargs; ++i) {
2034 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2035 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2036 return -1;
2037 }
2038 } else {
2039 int i;
2040
2041 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002042 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002043 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002044 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002045 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002046 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002047 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002048 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002049 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002050 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002051 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002052 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002053 return -1;
2054
2055 for (i = 0; i < 6; ++i)
2056 /* truncate away IVE sign-extension */
2057 tcp->u_arg[i] &= 0xffffffff;
2058
2059 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2060 && sysent[tcp->scno].nargs != -1)
2061 tcp->u_nargs = sysent[tcp->scno].nargs;
2062 else
2063 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002064 }
2065 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002066#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2067 /* N32 and N64 both use up to six registers. */
2068 {
2069 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002070 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002071
2072 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2073 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002074 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002075 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002076
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002077 if (do_ptrace(PTRACE_GETREGS, tcp, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002078 return -1;
2079
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002080 for (i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002081 tcp->u_arg[i] = regs[REG_A0 + i];
2082# if defined (LINUX_MIPSN32)
2083 tcp->ext_arg[i] = regs[REG_A0 + i];
2084# endif
2085 }
2086 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002087#elif defined (MIPS)
2088 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002089 long sp;
2090 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002091
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002092 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2093 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002094 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002095 nargs = tcp->u_nargs = MAX_ARGS;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002096 if (nargs > 4) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002097 if (upeek(tcp, REG_SP, &sp) < 0)
2098 return -1;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002099 for (i = 0; i < 4; i++) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002100 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
2101 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002102 }
2103 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2104 (char *)(tcp->u_arg + 4));
2105 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002106 for (i = 0; i < nargs; i++) {
2107 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2108 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002109 }
2110 }
2111 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002112#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002113# ifndef PT_ORIG_R3
2114# define PT_ORIG_R3 34
2115# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002116 {
2117 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002118 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2119 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002120 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002121 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002122 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002123 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002124 (sizeof(unsigned long)*PT_ORIG_R3) :
2125 ((i+PT_R3)*sizeof(unsigned long)),
2126 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002127 return -1;
2128 }
2129 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002130#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002131 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002132 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002133
2134 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2135 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002136 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002137 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002139 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002140 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002141#elif defined (HPPA)
2142 {
2143 int i;
2144
2145 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2146 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002147 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002148 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002149 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002150 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002151 return -1;
2152 }
2153 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002154#elif defined(ARM)
2155 {
2156 int i;
2157
2158 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2159 tcp->u_nargs = sysent[tcp->scno].nargs;
2160 else
2161 tcp->u_nargs = MAX_ARGS;
2162 for (i = 0; i < tcp->u_nargs; i++)
2163 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002164 }
2165#elif defined(AVR32)
2166 tcp->u_nargs = sysent[tcp->scno].nargs;
2167 tcp->u_arg[0] = regs.r12;
2168 tcp->u_arg[1] = regs.r11;
2169 tcp->u_arg[2] = regs.r10;
2170 tcp->u_arg[3] = regs.r9;
2171 tcp->u_arg[4] = regs.r5;
2172 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002173#elif defined(BFIN)
2174 {
2175 int i;
2176 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2177
2178 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2179 tcp->u_nargs = sysent[tcp->scno].nargs;
2180 else
2181 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2182
2183 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002184 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002185 return -1;
2186 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002187#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002188 {
2189 int i;
2190 static int syscall_regs[] = {
2191 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2192 REG_REG0, REG_REG0+1, REG_REG0+2
2193 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002194
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002195 tcp->u_nargs = sysent[tcp->scno].nargs;
2196 for (i = 0; i < tcp->u_nargs; i++) {
2197 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2198 return -1;
2199 }
2200 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002201#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002202 {
2203 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002204 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002205 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2206
2207 /*
2208 * TODO: should also check that the number of arguments encoded
2209 * in the trap number matches the number strace expects.
2210 */
2211 /*
2212 assert(sysent[tcp->scno].nargs <
2213 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2214 */
2215
2216 tcp->u_nargs = sysent[tcp->scno].nargs;
2217 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002218 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002219 return -1;
2220 }
2221 }
2222
Michal Ludvig0e035502002-09-23 15:41:01 +00002223#elif defined(X86_64)
2224 {
2225 int i;
2226 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2227 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002228 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002229 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002230
Michal Ludvig0e035502002-09-23 15:41:01 +00002231 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2232 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002233 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002234 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002235 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002236 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002237 return -1;
2238 }
2239 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002240#elif defined(CRISV10) || defined(CRISV32)
2241 {
2242 int i;
2243 static const int crisregs[] = {
2244 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2245 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2246 };
2247
2248 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2249 tcp->u_nargs = sysent[tcp->scno].nargs;
2250 else
2251 tcp->u_nargs = 0;
2252 for (i = 0; i < tcp->u_nargs; i++) {
2253 if (upeek(tcp->pid, crisregs[i], &tcp->u_arg[i]) < 0)
2254 return -1;
2255 }
2256 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002257#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002258 {
2259 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002260 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2261 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002262 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002263 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002264 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002265 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002266 return -1;
2267 }
2268 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002269#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002270#endif /* LINUX */
2271#ifdef SUNOS4
2272 {
2273 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002274 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2275 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002276 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002277 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002278 for (i = 0; i < tcp->u_nargs; i++) {
2279 struct user *u;
2280
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002281 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002282 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2283 return -1;
2284 }
2285 }
2286#endif /* SUNOS4 */
2287#ifdef SVR4
2288#ifdef MIPS
2289 /*
2290 * SGI is broken: even though it has pr_sysarg, it doesn't
2291 * set them on system call entry. Get a clue.
2292 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002293 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 tcp->u_nargs = sysent[tcp->scno].nargs;
2295 else
2296 tcp->u_nargs = tcp->status.pr_nsysarg;
2297 if (tcp->u_nargs > 4) {
2298 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2299 4*sizeof(tcp->u_arg[0]));
2300 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2301 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2302 }
2303 else {
2304 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2305 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2306 }
John Hughes25299712001-03-06 10:10:06 +00002307#elif UNIXWARE >= 2
2308 /*
2309 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2310 */
2311 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2312 tcp->u_nargs = sysent[tcp->scno].nargs;
2313 else
2314 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2315 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2316 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2317#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002318 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002319 tcp->u_nargs = sysent[tcp->scno].nargs;
2320 else
2321 tcp->u_nargs = tcp->status.pr_nsysarg;
2322 {
2323 int i;
2324 for (i = 0; i < tcp->u_nargs; i++)
2325 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2326 }
John Hughes25299712001-03-06 10:10:06 +00002327#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002328 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002329 tcp->u_nargs = sysent[tcp->scno].nargs;
2330 else
2331 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002332 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002333 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002334#else
2335 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002336#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002337#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002338#ifdef FREEBSD
2339 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2340 sysent[tcp->scno].nargs > tcp->status.val)
2341 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002342 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002343 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002344 if (tcp->u_nargs < 0)
2345 tcp->u_nargs = 0;
2346 if (tcp->u_nargs > MAX_ARGS)
2347 tcp->u_nargs = MAX_ARGS;
2348 switch(regs.r_eax) {
2349 case SYS___syscall:
2350 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2351 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002352 break;
2353 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002354 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2355 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002356 break;
2357 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002358 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2359 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002360 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002361 }
2362#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002363 return 1;
2364}
2365
2366int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002367trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002368{
2369 int sys_res;
2370 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002371 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002372
2373 if (tcp->flags & TCB_INSYSCALL) {
2374 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002375
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002376 /* Measure the exit time as early as possible to avoid errors. */
2377 if (dtime)
2378 gettimeofday(&tv, NULL);
2379
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002380 /* In code below,
2381 * res = 1: no error, continue
2382 * res = 0: return 0 at once (not an error)
2383 * any other value: error, complain and return the value
2384 *
2385 * BTW, why we don't just memorize syscall no. on entry
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002386 * in tcp->something?
2387 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002388 scno_good = res = get_scno(tcp);
2389 if (res == 0)
2390 return res;
2391 if (res == 1)
2392 res = syscall_fixup(tcp);
2393 if (res == 0)
2394 return res;
2395 if (res == 1)
2396 res = get_error(tcp);
2397 if (res == 0)
2398 return res;
2399 if (res == 1)
2400 internal_syscall(tcp);
2401
2402 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002403 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002404 tcp->flags &= ~TCB_INSYSCALL;
2405 return 0;
2406 }
2407
2408 if (tcp->flags & TCB_REPRINT) {
2409 printleader(tcp);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002410 if (scno_good != 1) {
2411 tprintf("<... syscall_?? resumed> ");
2412 } else {
2413 if (tcp->scno >= nsyscalls || tcp->scno < 0)
2414 tprintf("<... syscall_%lu resumed> ", tcp->scno);
2415 else
2416 tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
2417 }
2418 /* [do we need to clear TCB_REPRINT?...] */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002419 }
2420
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002421 if (cflag)
2422 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002423
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002424 if (res != 1) {
2425 tprintf(") ");
2426 tabto(acolumn);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002427 tprintf("= ?");
2428 /* line will be finished by error handling code */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002429 tcp->flags &= ~TCB_INSYSCALL;
2430 return res;
2431 }
2432
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002433 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002434 || (qual_flags[tcp->scno] & QUAL_RAW))
2435 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002436 else {
2437 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002438 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002439 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002440 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002441 u_error = tcp->u_error;
2442 tprintf(") ");
2443 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002444 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2445 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002446 if (u_error)
2447 tprintf("= -1 (errno %ld)", u_error);
2448 else
2449 tprintf("= %#lx", tcp->u_rval);
2450 }
2451 else if (!(sys_res & RVAL_NONE) && u_error) {
2452 switch (u_error) {
2453#ifdef LINUX
2454 case ERESTARTSYS:
2455 tprintf("= ? ERESTARTSYS (To be restarted)");
2456 break;
2457 case ERESTARTNOINTR:
2458 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2459 break;
2460 case ERESTARTNOHAND:
2461 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2462 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002463 case ERESTART_RESTARTBLOCK:
2464 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2465 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002466#endif /* LINUX */
2467 default:
2468 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002469 if (u_error < 0)
2470 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002471 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002472 tprintf("%s (%s)", errnoent[u_error],
2473 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002474 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002475 tprintf("ERRNO_%ld (%s)", u_error,
2476 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002477 break;
2478 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002479 if ((sys_res & RVAL_STR) && tcp->auxstr)
2480 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002481 }
2482 else {
2483 if (sys_res & RVAL_NONE)
2484 tprintf("= ?");
2485 else {
2486 switch (sys_res & RVAL_MASK) {
2487 case RVAL_HEX:
2488 tprintf("= %#lx", tcp->u_rval);
2489 break;
2490 case RVAL_OCTAL:
2491 tprintf("= %#lo", tcp->u_rval);
2492 break;
2493 case RVAL_UDECIMAL:
2494 tprintf("= %lu", tcp->u_rval);
2495 break;
2496 case RVAL_DECIMAL:
2497 tprintf("= %ld", tcp->u_rval);
2498 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002499#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002500 case RVAL_LHEX:
2501 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002502 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002503 case RVAL_LOCTAL:
2504 tprintf("= %#llo", tcp->u_lrval);
2505 break;
2506 case RVAL_LUDECIMAL:
2507 tprintf("= %llu", tcp->u_lrval);
2508 break;
2509 case RVAL_LDECIMAL:
2510 tprintf("= %lld", tcp->u_lrval);
2511 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002512#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002513 default:
2514 fprintf(stderr,
2515 "invalid rval format\n");
2516 break;
2517 }
2518 }
2519 if ((sys_res & RVAL_STR) && tcp->auxstr)
2520 tprintf(" (%s)", tcp->auxstr);
2521 }
2522 if (dtime) {
2523 tv_sub(&tv, &tv, &tcp->etime);
2524 tprintf(" <%ld.%06ld>",
2525 (long) tv.tv_sec, (long) tv.tv_usec);
2526 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002527 printtrailer();
Pavel Machek4dc3b142000-02-01 17:58:41 +00002528
2529 dumpio(tcp);
2530 if (fflush(tcp->outf) == EOF)
2531 return -1;
2532 tcp->flags &= ~TCB_INSYSCALL;
2533 return 0;
2534 }
2535
2536 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002537 scno_good = res = get_scno(tcp);
2538 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002539 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002540 if (res == 1)
2541 res = syscall_fixup(tcp);
2542 if (res == 0)
2543 return res;
2544 if (res == 1)
2545 res = syscall_enter(tcp);
2546 if (res == 0)
2547 return res;
2548
2549 if (res != 1) {
2550 printleader(tcp);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002551 tcp->flags &= ~TCB_REPRINT; /* why? */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002552 tcp_last = tcp;
2553 if (scno_good != 1)
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002554 tprintf("syscall_??" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002555 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2556 tprintf("syscall_%lu(", tcp->scno);
2557 else
2558 tprintf("%s(", sysent[tcp->scno].sys_name);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002559 /* Line will be finished by error handling code. */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002560 tcp->flags |= TCB_INSYSCALL;
2561 return res;
2562 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002563
Roland McGrath17352792005-06-07 23:21:26 +00002564 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002565#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002566 case SYS_socketcall:
2567 decode_subcall(tcp, SYS_socket_subcall,
2568 SYS_socket_nsubcalls, deref_style);
2569 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002570#endif
2571#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002572 case SYS_ipc:
2573 decode_subcall(tcp, SYS_ipc_subcall,
2574 SYS_ipc_nsubcalls, shift_style);
2575 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002576#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002577#ifdef SVR4
2578#ifdef SYS_pgrpsys_subcall
2579 case SYS_pgrpsys:
2580 decode_subcall(tcp, SYS_pgrpsys_subcall,
2581 SYS_pgrpsys_nsubcalls, shift_style);
2582 break;
2583#endif /* SYS_pgrpsys_subcall */
2584#ifdef SYS_sigcall_subcall
2585 case SYS_sigcall:
2586 decode_subcall(tcp, SYS_sigcall_subcall,
2587 SYS_sigcall_nsubcalls, mask_style);
2588 break;
2589#endif /* SYS_sigcall_subcall */
2590 case SYS_msgsys:
2591 decode_subcall(tcp, SYS_msgsys_subcall,
2592 SYS_msgsys_nsubcalls, shift_style);
2593 break;
2594 case SYS_shmsys:
2595 decode_subcall(tcp, SYS_shmsys_subcall,
2596 SYS_shmsys_nsubcalls, shift_style);
2597 break;
2598 case SYS_semsys:
2599 decode_subcall(tcp, SYS_semsys_subcall,
2600 SYS_semsys_nsubcalls, shift_style);
2601 break;
2602#if 0 /* broken */
2603 case SYS_utssys:
2604 decode_subcall(tcp, SYS_utssys_subcall,
2605 SYS_utssys_nsubcalls, shift_style);
2606 break;
2607#endif
2608 case SYS_sysfs:
2609 decode_subcall(tcp, SYS_sysfs_subcall,
2610 SYS_sysfs_nsubcalls, shift_style);
2611 break;
2612 case SYS_spcall:
2613 decode_subcall(tcp, SYS_spcall_subcall,
2614 SYS_spcall_nsubcalls, shift_style);
2615 break;
2616#ifdef SYS_context_subcall
2617 case SYS_context:
2618 decode_subcall(tcp, SYS_context_subcall,
2619 SYS_context_nsubcalls, shift_style);
2620 break;
2621#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002622#ifdef SYS_door_subcall
2623 case SYS_door:
2624 decode_subcall(tcp, SYS_door_subcall,
2625 SYS_door_nsubcalls, door_style);
2626 break;
2627#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002628#ifdef SYS_kaio_subcall
2629 case SYS_kaio:
2630 decode_subcall(tcp, SYS_kaio_subcall,
2631 SYS_kaio_nsubcalls, shift_style);
2632 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002633#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002634#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002635#ifdef FREEBSD
2636 case SYS_msgsys:
2637 case SYS_shmsys:
2638 case SYS_semsys:
2639 decode_subcall(tcp, 0, 0, table_style);
2640 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002641#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002642#ifdef SUNOS4
2643 case SYS_semsys:
2644 decode_subcall(tcp, SYS_semsys_subcall,
2645 SYS_semsys_nsubcalls, shift_style);
2646 break;
2647 case SYS_msgsys:
2648 decode_subcall(tcp, SYS_msgsys_subcall,
2649 SYS_msgsys_nsubcalls, shift_style);
2650 break;
2651 case SYS_shmsys:
2652 decode_subcall(tcp, SYS_shmsys_subcall,
2653 SYS_shmsys_nsubcalls, shift_style);
2654 break;
2655#endif
2656 }
2657
2658 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002659 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002660 tcp->flags |= TCB_INSYSCALL;
2661 return 0;
2662 }
2663
2664 if (cflag) {
2665 gettimeofday(&tcp->etime, NULL);
2666 tcp->flags |= TCB_INSYSCALL;
2667 return 0;
2668 }
2669
2670 printleader(tcp);
2671 tcp->flags &= ~TCB_REPRINT;
2672 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002673 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002674 tprintf("syscall_%lu(", tcp->scno);
2675 else
2676 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002677 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002678 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2679 sys_res = printargs(tcp);
2680 else
2681 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2682 if (fflush(tcp->outf) == EOF)
2683 return -1;
2684 tcp->flags |= TCB_INSYSCALL;
2685 /* Measure the entrance time as late as possible to avoid errors. */
2686 if (dtime)
2687 gettimeofday(&tcp->etime, NULL);
2688 return sys_res;
2689}
2690
2691int
2692printargs(tcp)
2693struct tcb *tcp;
2694{
2695 if (entering(tcp)) {
2696 int i;
2697
2698 for (i = 0; i < tcp->u_nargs; i++)
2699 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2700 }
2701 return 0;
2702}
2703
2704long
2705getrval2(tcp)
2706struct tcb *tcp;
2707{
2708 long val = -1;
2709
2710#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002711#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002712 struct regs regs;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002713 if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002714 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002715 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002716#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002717 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002718 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002719#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002720 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002721 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002722#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002723#endif /* LINUX */
2724
2725#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002726 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002727 return -1;
2728#endif /* SUNOS4 */
2729
2730#ifdef SVR4
2731#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002732 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002733#endif /* SPARC */
2734#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002735 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002736#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002737#ifdef X86_64
2738 val = tcp->status.PR_REG[RDX];
2739#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002740#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002741 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002742#endif /* MIPS */
2743#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002744
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002745#ifdef FREEBSD
2746 struct reg regs;
2747 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2748 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002749#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002750 return val;
2751}
2752
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002753#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002754/*
2755 * Apparently, indirect system calls have already be converted by ptrace(2),
2756 * so if you see "indir" this program has gone astray.
2757 */
2758int
2759sys_indir(tcp)
2760struct tcb *tcp;
2761{
2762 int i, scno, nargs;
2763
2764 if (entering(tcp)) {
2765 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2766 fprintf(stderr, "Bogus syscall: %u\n", scno);
2767 return 0;
2768 }
2769 nargs = sysent[scno].nargs;
2770 tprintf("%s", sysent[scno].sys_name);
2771 for (i = 0; i < nargs; i++)
2772 tprintf(", %#lx", tcp->u_arg[i+1]);
2773 }
2774 return 0;
2775}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002776#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002777
2778int
2779is_restart_error(struct tcb *tcp)
2780{
2781#ifdef LINUX
2782 if (!syserror(tcp))
2783 return 0;
2784 switch (tcp->u_error) {
2785 case ERESTARTSYS:
2786 case ERESTARTNOINTR:
2787 case ERESTARTNOHAND:
2788 case ERESTART_RESTARTBLOCK:
2789 return 1;
2790 default:
2791 break;
2792 }
2793#endif /* LINUX */
2794 return 0;
2795}