blob: 26b1a9d71e58b37ed6967e993ed1cc20488c5ebd [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
38#include <signal.h>
39#include <time.h>
40#include <errno.h>
41#include <sys/user.h>
42#include <sys/syscall.h>
43#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044
Wichert Akkerman15dea971999-10-06 13:06:34 +000045#if HAVE_ASM_REG_H
Roland McGratheb9e2e82009-06-02 16:49:22 -070046#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000047# define fpq kernel_fpq
48# define fq kernel_fq
49# define fpu kernel_fpu
Roland McGratheb9e2e82009-06-02 16:49:22 -070050#endif
51#include <asm/reg.h>
52#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000053# undef fpq
54# undef fq
Roland McGrath761b5d72002-12-15 23:58:31 +000055# undef fpu
Roland McGratheb9e2e82009-06-02 16:49:22 -070056#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000057#endif
58
Wichert Akkerman15dea971999-10-06 13:06:34 +000059#ifdef HAVE_SYS_REG_H
Roland McGratheb9e2e82009-06-02 16:49:22 -070060#include <sys/reg.h>
61#ifndef PTRACE_PEEKUSR
62# define PTRACE_PEEKUSR PTRACE_PEEKUSER
63#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
Roland McGratheb9e2e82009-06-02 16:49:22 -070065#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Roland McGratheb9e2e82009-06-02 16:49:22 -070072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000075#endif
76
Roland McGrath6d1a65c2004-07-12 07:44:08 +000077#if defined (LINUX) && defined (SPARC64)
78# define r_pc r_tpc
79# undef PTRACE_GETREGS
80# define PTRACE_GETREGS PTRACE_GETREGS64
81# undef PTRACE_SETREGS
82# define PTRACE_SETREGS PTRACE_SETREGS64
83#endif /* LINUX && SPARC64 */
84
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000085#if defined(LINUX) && defined(IA64)
86# include <asm/ptrace_offsets.h>
87# include <asm/rse.h>
88#endif
89
Pavel Machekd8ae7e32000-02-01 17:17:25 +000090#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifdef LINUX
92#ifndef ERESTARTSYS
93#define ERESTARTSYS 512
94#endif
95#ifndef ERESTARTNOINTR
96#define ERESTARTNOINTR 513
97#endif
98#ifndef ERESTARTNOHAND
99#define ERESTARTNOHAND 514 /* restart if no handler.. */
100#endif
101#ifndef ENOIOCTLCMD
102#define ENOIOCTLCMD 515 /* No ioctl command */
103#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000104#ifndef ERESTART_RESTARTBLOCK
105#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
106#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#ifndef NSIG
108#define NSIG 32
109#endif
110#ifdef ARM
111#undef NSIG
112#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000113#undef NR_SYSCALL_BASE
114#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#endif
116#endif /* LINUX */
117
118#include "syscall.h"
119
120/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000121#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#define TF TRACE_FILE
123#define TI TRACE_IPC
124#define TN TRACE_NETWORK
125#define TP TRACE_PROCESS
126#define TS TRACE_SIGNAL
127
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000132int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133
134#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000135static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000136#include "syscallent1.h"
137};
Roland McGrathee36ce12004-09-04 03:53:10 +0000138static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000139int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140#endif /* SUPPORTED_PERSONALITIES >= 2 */
141
142#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000143static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#include "syscallent2.h"
145};
Roland McGrathee36ce12004-09-04 03:53:10 +0000146static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000147int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148#endif /* SUPPORTED_PERSONALITIES >= 3 */
149
Roland McGrathee36ce12004-09-04 03:53:10 +0000150const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000151int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152int nsyscalls;
153
154/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000155#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156#undef TF
157#undef TI
158#undef TN
159#undef TP
160#undef TS
161
Roland McGrathee36ce12004-09-04 03:53:10 +0000162static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163#include "errnoent.h"
164};
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166
167#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000168static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169#include "errnoent1.h"
170};
Roland McGrathee36ce12004-09-04 03:53:10 +0000171static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000172#endif /* SUPPORTED_PERSONALITIES >= 2 */
173
174#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000175static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176#include "errnoent2.h"
177};
Roland McGrathee36ce12004-09-04 03:53:10 +0000178static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000179#endif /* SUPPORTED_PERSONALITIES >= 3 */
180
Roland McGrathee36ce12004-09-04 03:53:10 +0000181const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182int nerrnos;
183
184int current_personality;
185
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000186#ifndef PERSONALITY0_WORDSIZE
187# define PERSONALITY0_WORDSIZE sizeof(long)
188#endif
189const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
190 PERSONALITY0_WORDSIZE,
191#if SUPPORTED_PERSONALITIES > 1
192 PERSONALITY1_WORDSIZE,
193#endif
194#if SUPPORTED_PERSONALITIES > 2
195 PERSONALITY2_WORDSIZE,
196#endif
197};;
198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000200set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201{
202 switch (personality) {
203 case 0:
204 errnoent = errnoent0;
205 nerrnos = nerrnos0;
206 sysent = sysent0;
207 nsyscalls = nsyscalls0;
208 ioctlent = ioctlent0;
209 nioctlents = nioctlents0;
210 signalent = signalent0;
211 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000212 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000213 break;
214
215#if SUPPORTED_PERSONALITIES >= 2
216 case 1:
217 errnoent = errnoent1;
218 nerrnos = nerrnos1;
219 sysent = sysent1;
220 nsyscalls = nsyscalls1;
221 ioctlent = ioctlent1;
222 nioctlents = nioctlents1;
223 signalent = signalent1;
224 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000225 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000226 break;
227#endif /* SUPPORTED_PERSONALITIES >= 2 */
228
229#if SUPPORTED_PERSONALITIES >= 3
230 case 2:
231 errnoent = errnoent2;
232 nerrnos = nerrnos2;
233 sysent = sysent2;
234 nsyscalls = nsyscalls2;
235 ioctlent = ioctlent2;
236 nioctlents = nioctlents2;
237 signalent = signalent2;
238 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000239 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 break;
241#endif /* SUPPORTED_PERSONALITIES >= 3 */
242
243 default:
244 return -1;
245 }
246
247 current_personality = personality;
248 return 0;
249}
250
Roland McGrathe10e62a2004-09-04 04:20:43 +0000251
Roland McGrath9797ceb2002-12-30 10:23:00 +0000252static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253
Roland McGrathe10e62a2004-09-04 04:20:43 +0000254static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 int bitflag;
256 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000257 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000258 char *argument_name;
259} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000260 { QUAL_TRACE, "trace", qual_syscall, "system call" },
261 { QUAL_TRACE, "t", qual_syscall, "system call" },
262 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
263 { QUAL_ABBREV, "a", qual_syscall, "system call" },
264 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
265 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
266 { QUAL_RAW, "raw", qual_syscall, "system call" },
267 { QUAL_RAW, "x", qual_syscall, "system call" },
268 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
269 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
270 { QUAL_SIGNAL, "s", qual_signal, "signal" },
271 { QUAL_FAULT, "fault", qual_fault, "fault" },
272 { QUAL_FAULT, "faults", qual_fault, "fault" },
273 { QUAL_FAULT, "m", qual_fault, "fault" },
274 { QUAL_READ, "read", qual_desc, "descriptor" },
275 { QUAL_READ, "reads", qual_desc, "descriptor" },
276 { QUAL_READ, "r", qual_desc, "descriptor" },
277 { QUAL_WRITE, "write", qual_desc, "descriptor" },
278 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
279 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 { 0, NULL, NULL, NULL },
281};
282
Roland McGrath9797ceb2002-12-30 10:23:00 +0000283static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000284qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000285 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000286 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000287 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000288 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000289{
Roland McGrath138c6a32006-01-12 09:50:49 +0000290 if (pers == 0 || pers < 0) {
291 if (not)
292 qual_flags0[n] &= ~opt->bitflag;
293 else
294 qual_flags0[n] |= opt->bitflag;
295 }
296
297#if SUPPORTED_PERSONALITIES >= 2
298 if (pers == 1 || pers < 0) {
299 if (not)
300 qual_flags1[n] &= ~opt->bitflag;
301 else
302 qual_flags1[n] |= opt->bitflag;
303 }
304#endif /* SUPPORTED_PERSONALITIES >= 2 */
305
306#if SUPPORTED_PERSONALITIES >= 3
307 if (pers == 2 || pers < 0) {
308 if (not)
309 qual_flags2[n] &= ~opt->bitflag;
310 else
311 qual_flags2[n] |= opt->bitflag;
312 }
313#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000314}
315
316static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000317qual_syscall(s, opt, not)
318 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000319 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000320 int not;
321{
322 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000323 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000324
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000325 if (isdigit((unsigned char)*s)) {
326 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000327 if (i < 0 || i >= MAX_QUALS)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000328 return -1;
329 qualify_one(i, opt, not, -1);
330 return 0;
Roland McGrath48a035f2006-01-12 09:45:56 +0000331 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000332 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 if (strcmp(s, sysent0[i].sys_name) == 0) {
334 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000335 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000336 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000337
338#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000339 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000340 if (strcmp(s, sysent1[i].sys_name) == 0) {
341 qualify_one(i, opt, not, 1);
342 rc = 0;
343 }
344#endif /* SUPPORTED_PERSONALITIES >= 2 */
345
346#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000347 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000348 if (strcmp(s, sysent2[i].sys_name) == 0) {
349 qualify_one(i, opt, not, 2);
350 rc = 0;
351 }
352#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000353
Roland McGrathfe6b3522005-02-02 04:40:11 +0000354 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000355}
356
357static int
358qual_signal(s, opt, not)
359 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000360 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000361 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000362{
363 int i;
364 char buf[32];
365
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000366 if (isdigit((unsigned char)*s)) {
367 int signo = atoi(s);
368 if (signo < 0 || signo >= MAX_QUALS)
369 return -1;
370 qualify_one(signo, opt, not, -1);
371 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000373 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000374 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375 strcpy(buf, s);
376 s = buf;
377 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000378 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379 if (strncmp(s, "SIG", 3) == 0)
380 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000381 for (i = 0; i <= NSIG; i++)
382 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000383 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000384 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000385 }
Roland McGrath76421df2005-02-02 03:51:18 +0000386 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387}
388
389static int
390qual_fault(s, opt, not)
391 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000392 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000393 int not;
394{
395 return -1;
396}
397
398static int
399qual_desc(s, opt, not)
400 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000401 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000402 int not;
403{
Roland McGrath48a035f2006-01-12 09:45:56 +0000404 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000405 int desc = atoi(s);
406 if (desc < 0 || desc >= MAX_QUALS)
407 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000408 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000409 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 }
411 return -1;
412}
413
414static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000416 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417{
418 if (strcmp(s, "file") == 0)
419 return TRACE_FILE;
420 if (strcmp(s, "ipc") == 0)
421 return TRACE_IPC;
422 if (strcmp(s, "network") == 0)
423 return TRACE_NETWORK;
424 if (strcmp(s, "process") == 0)
425 return TRACE_PROCESS;
426 if (strcmp(s, "signal") == 0)
427 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000428 if (strcmp(s, "desc") == 0)
429 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430 return -1;
431}
432
433void
434qualify(s)
435char *s;
436{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000437 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 int not;
439 char *p;
440 int i, n;
441
442 opt = &qual_options[0];
443 for (i = 0; (p = qual_options[i].option_name); i++) {
444 n = strlen(p);
445 if (strncmp(s, p, n) == 0 && s[n] == '=') {
446 opt = &qual_options[i];
447 s += n + 1;
448 break;
449 }
450 }
451 not = 0;
452 if (*s == '!') {
453 not = 1;
454 s++;
455 }
456 if (strcmp(s, "none") == 0) {
457 not = 1 - not;
458 s = "all";
459 }
460 if (strcmp(s, "all") == 0) {
461 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000462 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 }
464 return;
465 }
466 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000467 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000468 }
469 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
470 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000471 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000472 if (sysent0[i].sys_flags & n)
473 qualify_one(i, opt, not, 0);
474
475#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000476 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000477 if (sysent1[i].sys_flags & n)
478 qualify_one(i, opt, not, 1);
479#endif /* SUPPORTED_PERSONALITIES >= 2 */
480
481#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000482 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000483 if (sysent2[i].sys_flags & n)
484 qualify_one(i, opt, not, 2);
485#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000486
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487 continue;
488 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000489 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 fprintf(stderr, "strace: invalid %s `%s'\n",
491 opt->argument_name, p);
492 exit(1);
493 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000494 }
495 return;
496}
497
498static void
499dumpio(tcp)
500struct tcb *tcp;
501{
502 if (syserror(tcp))
503 return;
504 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
505 return;
Roland McGrath17352792005-06-07 23:21:26 +0000506 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000508#ifdef SYS_pread64
509 case SYS_pread64:
510#endif
511#if defined SYS_pread && SYS_pread64 != SYS_pread
512 case SYS_pread:
513#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514#ifdef SYS_recv
515 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000516#elif defined SYS_sub_recv
517 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000518#endif
519#ifdef SYS_recvfrom
520 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000521#elif defined SYS_sub_recvfrom
522 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523#endif
524 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
525 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
526 break;
527 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000528#ifdef SYS_pwrite64
529 case SYS_pwrite64:
530#endif
531#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
532 case SYS_pwrite:
533#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534#ifdef SYS_send
535 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000536#elif defined SYS_sub_send
537 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538#endif
539#ifdef SYS_sendto
540 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000541#elif defined SYS_sub_sendto
542 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543#endif
544 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
545 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
546 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000547#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000548 case SYS_readv:
549 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
550 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
551 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000552#endif
553#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000554 case SYS_writev:
555 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
556 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
557 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000558#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000559 }
560}
561
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000562#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000563enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000564#else /* FREEBSD */
565enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
566
567struct subcall {
568 int call;
569 int nsubcalls;
570 int subcalls[5];
571};
572
Roland McGratha4d48532005-06-08 20:45:28 +0000573static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000574 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000575#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000576 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000577#else
578 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
579#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000580 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
581};
582#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000584#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585
Roland McGratha4d48532005-06-08 20:45:28 +0000586static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000587decode_subcall(tcp, subcall, nsubcalls, style)
588struct tcb *tcp;
589int subcall;
590int nsubcalls;
591enum subcall_style style;
592{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000593 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000594 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000595 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000596
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597 switch (style) {
598 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000599 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
600 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000601 tcp->scno = subcall + tcp->u_arg[0];
602 if (sysent[tcp->scno].nargs != -1)
603 tcp->u_nargs = sysent[tcp->scno].nargs;
604 else
605 tcp->u_nargs--;
606 for (i = 0; i < tcp->u_nargs; i++)
607 tcp->u_arg[i] = tcp->u_arg[i + 1];
608 break;
609 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000610 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
611 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 tcp->scno = subcall + tcp->u_arg[0];
613 addr = tcp->u_arg[1];
614 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000615 if (size == sizeof(int)) {
616 unsigned int arg;
617 if (umove(tcp, addr, &arg) < 0)
618 arg = 0;
619 tcp->u_arg[i] = arg;
620 }
621 else if (size == sizeof(long)) {
622 unsigned long arg;
623 if (umove(tcp, addr, &arg) < 0)
624 arg = 0;
625 tcp->u_arg[i] = arg;
626 }
627 else
628 abort();
629 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 }
631 tcp->u_nargs = sysent[tcp->scno].nargs;
632 break;
633 case mask_style:
634 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000635 for (i = 0; mask; i++)
636 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000637 if (i >= nsubcalls)
638 return;
639 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640 tcp->scno = subcall + i;
641 if (sysent[tcp->scno].nargs != -1)
642 tcp->u_nargs = sysent[tcp->scno].nargs;
643 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000644 case door_style:
645 /*
646 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000647 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000648 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000649 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
650 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000651 tcp->scno = subcall + tcp->u_arg[5];
652 if (sysent[tcp->scno].nargs != -1)
653 tcp->u_nargs = sysent[tcp->scno].nargs;
654 else
655 tcp->u_nargs--;
656 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000657#ifdef FREEBSD
658 case table_style:
659 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
660 if (subcalls_table[i].call == tcp->scno) break;
661 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
662 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
663 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
664 for (i = 0; i < tcp->u_nargs; i++)
665 tcp->u_arg[i] = tcp->u_arg[i + 1];
666 }
667 break;
668#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000669 }
670}
671#endif
672
673struct tcb *tcp_last = NULL;
674
675static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000676internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000677{
678 /*
679 * We must always trace a few critical system calls in order to
680 * correctly support following forks in the presence of tracing
681 * qualifiers.
682 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000685 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
686 return 0;
687
688 func = sysent[tcp->scno].sys_func;
689
690 if (sys_exit == func)
691 return internal_exit(tcp);
692
693 if ( sys_fork == func
694#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
695 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000696#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000697#if UNIXWARE > 2
698 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000699#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000700 )
701 return internal_fork(tcp);
702
703#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
704 if (sys_clone == func)
705 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000706#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000707
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000708 if ( sys_execve == func
709#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
710 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000712#if UNIXWARE > 2
713 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000714#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000715 )
716 return internal_exec(tcp);
717
718 if ( sys_waitpid == func
719 || sys_wait4 == func
720#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
721 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000722#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000723#ifdef ALPHA
724 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000725#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000726 )
727 return internal_wait(tcp, 2);
728
729#if defined(LINUX) || defined(SVR4)
730 if (sys_waitid == func)
731 return internal_wait(tcp, 3);
732#endif
733
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000734 return 0;
735}
736
Wichert Akkermanc7926982000-04-10 22:22:31 +0000737
738#ifdef LINUX
739#if defined (I386)
740 static long eax;
741#elif defined (IA64)
742 long r8, r10, psr;
743 long ia32 = 0;
744#elif defined (POWERPC)
745 static long result,flags;
746#elif defined (M68K)
747 static int d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000748#elif defined(BFIN)
749 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000750#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000751 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000752#elif defined (ALPHA)
753 static long r0;
754 static long a3;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000755#elif defined(AVR32)
756 static struct pt_regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000757#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000758 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000759 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000760#elif defined(LINUX_MIPSN32)
761 static long long a3;
762 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000763#elif defined(MIPS)
764 static long a3;
765 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000766#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000767 static long gpr2;
768 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000769 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000770#elif defined(HPPA)
771 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000772#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000773 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000774#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000775 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000776#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000777 static long rax;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000778#elif defined(CRISV10) || defined(CRISV32)
779 static long r10;
Roland McGrath761b5d72002-12-15 23:58:31 +0000780#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000781#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000782#ifdef FREEBSD
783 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000784#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000785
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000787get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000788{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000792# if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000793 if (tcp->flags & TCB_WAITEXECVE) {
794 /*
795 * When the execve system call completes successfully, the
796 * new process still has -ENOSYS (old style) or __NR_execve
797 * (new style) in gpr2. We cannot recover the scno again
798 * by disassembly, because the image that executed the
799 * syscall is gone now. Fortunately, we don't want it. We
800 * leave the flag set so that syscall_fixup can fake the
801 * result.
802 */
803 if (tcp->flags & TCB_INSYSCALL)
804 return 1;
805 /*
806 * This is the SIGTRAP after execve. We cannot try to read
807 * the system call here either.
808 */
809 tcp->flags &= ~TCB_WAITEXECVE;
810 return 0;
811 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000812
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000813 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000814 return -1;
815
816 if (syscall_mode != -ENOSYS) {
817 /*
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000818 * Since kernel version 2.5.44 the scno gets passed in gpr2.
Roland McGrath2f924ca2003-06-26 22:23:28 +0000819 */
820 scno = syscall_mode;
821 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000822 /*
Michal Ludvig882eda82002-11-11 12:50:47 +0000823 * Old style of "passing" the scno via the SVC instruction.
824 */
825
826 long opcode, offset_reg, tmp;
827 void * svc_addr;
828 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
829 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
830 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
831 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000832
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000833 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000834 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000835 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000836 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000837 if (errno) {
838 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000839 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000840 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000841
842 /*
843 * We have to check if the SVC got executed directly or via an
844 * EXECUTE instruction. In case of EXECUTE it is necessary to do
845 * instruction decoding to derive the system call number.
846 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
847 * so that this doesn't work if a SVC opcode is part of an EXECUTE
848 * opcode. Since there is no way to find out the opcode size this
849 * is the best we can do...
850 */
851
852 if ((opcode & 0xff00) == 0x0a00) {
853 /* SVC opcode */
854 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000855 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000856 else {
857 /* SVC got executed by EXECUTE instruction */
858
859 /*
860 * Do instruction decoding of EXECUTE. If you really want to
861 * understand this, read the Principles of Operations.
862 */
863 svc_addr = (void *) (opcode & 0xfff);
864
865 tmp = 0;
866 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000867 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000868 return -1;
869 svc_addr += tmp;
870
871 tmp = 0;
872 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000873 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000874 return -1;
875 svc_addr += tmp;
876
Denys Vlasenkofb036672009-01-23 16:30:26 +0000877 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000878 if (errno)
879 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000880# if defined(S390X)
Michal Ludvig882eda82002-11-11 12:50:47 +0000881 scno >>= 48;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000882# else
Michal Ludvig882eda82002-11-11 12:50:47 +0000883 scno >>= 16;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000884# endif
Michal Ludvig882eda82002-11-11 12:50:47 +0000885 tmp = 0;
886 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000887 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000888 return -1;
889
890 scno = (scno | tmp) & 0xff;
891 }
892 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000893# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000894 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000895 return -1;
896 if (!(tcp->flags & TCB_INSYSCALL)) {
897 /* Check if we return from execve. */
898 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
899 tcp->flags &= ~TCB_WAITEXECVE;
900 return 0;
901 }
902 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000903# elif defined(AVR32)
904 /*
905 * Read complete register set in one go.
906 */
907 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, &regs) < 0)
908 return -1;
909
910 /*
911 * We only need to grab the syscall number on syscall entry.
912 */
913 if (!(tcp->flags & TCB_INSYSCALL)) {
914 scno = regs.r8;
915
916 /* Check if we return from execve. */
917 if (tcp->flags & TCB_WAITEXECVE) {
918 tcp->flags &= ~TCB_WAITEXECVE;
919 return 0;
920 }
921 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000922# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000923 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000924 return -1;
925 /* Check if we return from execve. */
926 if (tcp->flags & TCB_WAITEXECVE && tcp->flags & TCB_INSYSCALL)
927 tcp->flags &= ~(TCB_INSYSCALL | TCB_WAITEXECVE);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000928# elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000929 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000930 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000931# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000932 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000933 return -1;
934
Roland McGrath761b5d72002-12-15 23:58:31 +0000935 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +0000936 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000937 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000938 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000939
940 /* Check CS register value. On x86-64 linux it is:
941 * 0x33 for long mode (64 bit)
942 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000943 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000944 * to be cached.
945 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000946 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000947 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000948 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000949 case 0x23: currpers = 1; break;
950 case 0x33: currpers = 0; break;
951 default:
952 fprintf(stderr, "Unknown value CS=0x%02X while "
953 "detecting personality of process "
954 "PID=%d\n", (int)val, pid);
955 currpers = current_personality;
956 break;
957 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000958# if 0
Michal Ludvig0e035502002-09-23 15:41:01 +0000959 /* This version analyzes the opcode of a syscall instruction.
960 * (int 0x80 on i386 vs. syscall on x86-64)
961 * It works, but is too complicated.
962 */
963 unsigned long val, rip, i;
964
Denys Vlasenko8236f252009-01-02 18:10:08 +0000965 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000966 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000967
Michal Ludvig0e035502002-09-23 15:41:01 +0000968 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000969 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000970 errno = 0;
971
Denys Vlasenko8236f252009-01-02 18:10:08 +0000972 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000973 if (errno)
974 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000975 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000976 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000977 /* x86-64: syscall = 0x0f 0x05 */
978 case 0x050f: currpers = 0; break;
979 /* i386: int 0x80 = 0xcd 0x80 */
980 case 0x80cd: currpers = 1; break;
981 default:
982 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000983 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000984 "Unknown syscall opcode (0x%04X) while "
985 "detecting personality of process "
986 "PID=%d\n", (int)call, pid);
987 break;
988 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000989# endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000990 if (currpers != current_personality) {
991 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000992 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000993 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000994 pid, names[current_personality]);
995 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000996 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000997# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000998# define IA64_PSR_IS ((long)1 << 34)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700999 if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001000 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001001 if (!(tcp->flags & TCB_INSYSCALL)) {
1002 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001003 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001004 return -1;
1005 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001006 if (upeek (tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001007 return -1;
1008 }
Roland McGrathba954762003-03-05 06:29:06 +00001009 /* Check if we return from execve. */
1010 if (tcp->flags & TCB_WAITEXECVE) {
1011 tcp->flags &= ~TCB_WAITEXECVE;
1012 return 0;
1013 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001014 } else {
1015 /* syscall in progress */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001016 if (upeek (tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001017 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001018 if (upeek (tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001019 return -1;
1020 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001021# elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001022 /*
1023 * Read complete register set in one go.
1024 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001025 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001026 return -1;
1027
1028 /*
1029 * We only need to grab the syscall number on syscall entry.
1030 */
1031 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001032 if (!(tcp->flags & TCB_INSYSCALL)) {
1033 /* Check if we return from execve. */
1034 if (tcp->flags & TCB_WAITEXECVE) {
1035 tcp->flags &= ~TCB_WAITEXECVE;
1036 return 0;
1037 }
1038 }
1039
Roland McGrath0f87c492003-06-03 23:29:04 +00001040 /*
1041 * Note: we only deal with only 32-bit CPUs here.
1042 */
1043 if (regs.ARM_cpsr & 0x20) {
1044 /*
1045 * Get the Thumb-mode system call number
1046 */
1047 scno = regs.ARM_r7;
1048 } else {
1049 /*
1050 * Get the ARM-mode system call number
1051 */
1052 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001053 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001054 if (errno)
1055 return -1;
1056
1057 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1058 tcp->flags &= ~TCB_WAITEXECVE;
1059 return 0;
1060 }
1061
Roland McGrathf691bd22006-04-25 07:34:41 +00001062 /* Handle the EABI syscall convention. We do not
1063 bother converting structures between the two
1064 ABIs, but basic functionality should work even
1065 if strace and the traced program have different
1066 ABIs. */
1067 if (scno == 0xef000000) {
1068 scno = regs.ARM_r7;
1069 } else {
1070 if ((scno & 0x0ff00000) != 0x0f900000) {
1071 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1072 scno);
1073 return -1;
1074 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001075
Roland McGrathf691bd22006-04-25 07:34:41 +00001076 /*
1077 * Fixup the syscall number
1078 */
1079 scno &= 0x000fffff;
1080 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001081 }
Roland McGrath56703312008-05-20 01:35:55 +00001082 if (scno & 0x0f0000) {
1083 /*
1084 * Handle ARM specific syscall
1085 */
1086 set_personality(1);
1087 scno &= 0x0000ffff;
1088 } else
1089 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001090
1091 if (tcp->flags & TCB_INSYSCALL) {
1092 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1093 tcp->flags &= ~TCB_INSYSCALL;
1094 }
1095 } else {
1096 if (!(tcp->flags & TCB_INSYSCALL)) {
1097 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1098 tcp->flags |= TCB_INSYSCALL;
1099 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001101# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001102 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001104# elif defined (LINUX_MIPSN32)
Roland McGrath542c2c62008-05-20 01:11:56 +00001105 unsigned long long regs[38];
1106
Roland McGratheb9e2e82009-06-02 16:49:22 -07001107 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001108 return -1;
1109 a3 = regs[REG_A3];
1110 r2 = regs[REG_V0];
1111
1112 if(!(tcp->flags & TCB_INSYSCALL)) {
1113 scno = r2;
1114
1115 /* Check if we return from execve. */
1116 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1117 tcp->flags &= ~TCB_WAITEXECVE;
1118 return 0;
1119 }
1120
1121 if (scno < 0 || scno > nsyscalls) {
1122 if(a3 == 0 || a3 == -1) {
1123 if(debug)
1124 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1125 return 0;
1126 }
1127 }
1128 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001129# elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001130 if (upeek(tcp, REG_A3, &a3) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001131 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001132 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001133 if (upeek(tcp, REG_V0, &scno) < 0)
1134 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001135
Roland McGrath542c2c62008-05-20 01:11:56 +00001136 /* Check if we return from execve. */
1137 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1138 tcp->flags &= ~TCB_WAITEXECVE;
1139 return 0;
1140 }
1141
Wichert Akkermanf90da011999-10-31 21:15:38 +00001142 if (scno < 0 || scno > nsyscalls) {
1143 if(a3 == 0 || a3 == -1) {
1144 if(debug)
1145 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1146 return 0;
1147 }
1148 }
1149 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001150 if (upeek(tcp, REG_V0, &r2) < 0)
1151 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001152 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001153# elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001154 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155 return -1;
1156
1157 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001158 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159 return -1;
1160
1161 /* Check if we return from execve. */
1162 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1163 tcp->flags &= ~TCB_WAITEXECVE;
1164 return 0;
1165 }
1166
1167 /*
1168 * Do some sanity checks to figure out if it's
1169 * really a syscall entry
1170 */
1171 if (scno < 0 || scno > nsyscalls) {
1172 if (a3 == 0 || a3 == -1) {
1173 if (debug)
1174 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1175 return 0;
1176 }
1177 }
1178 }
1179 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001180 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 return -1;
1182 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001183# elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001185 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186 return -1;
1187
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001188 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189 if (!(tcp->flags & TCB_INSYSCALL)) {
1190 /* Retrieve the syscall trap instruction. */
1191 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001192 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.r_pc, 0);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001193# if defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001194 trap >>= 32;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001195# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001196 if (errno)
1197 return -1;
1198
1199 /* Disassemble the trap to see what personality to use. */
1200 switch (trap) {
1201 case 0x91d02010:
1202 /* Linux/SPARC syscall trap. */
1203 set_personality(0);
1204 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001205 case 0x91d0206d:
1206 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001207 set_personality(2);
1208 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001209 case 0x91d02000:
1210 /* SunOS syscall trap. (pers 1) */
1211 fprintf(stderr,"syscall: SunOS no support\n");
1212 return -1;
1213 case 0x91d02008:
1214 /* Solaris 2.x syscall trap. (per 2) */
1215 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001216 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001217 case 0x91d02009:
1218 /* NetBSD/FreeBSD syscall trap. */
1219 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1220 return -1;
1221 case 0x91d02027:
1222 /* Solaris 2.x gettimeofday */
1223 set_personality(1);
1224 break;
1225 default:
1226 /* Unknown syscall trap. */
1227 if(tcp->flags & TCB_WAITEXECVE) {
1228 tcp->flags &= ~TCB_WAITEXECVE;
1229 return 0;
1230 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001231# if defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001232 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001233# else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001234 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001235# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001236 return -1;
1237 }
1238
1239 /* Extract the system call number from the registers. */
1240 if (trap == 0x91d02027)
1241 scno = 156;
1242 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001243 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001244 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001245 scno = regs.r_o0;
1246 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247 }
1248 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001249# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001250 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001251 return -1;
1252 if (!(tcp->flags & TCB_INSYSCALL)) {
1253 /* Check if we return from execve. */
1254 if ((tcp->flags & TCB_WAITEXECVE)) {
1255 tcp->flags &= ~TCB_WAITEXECVE;
1256 return 0;
1257 }
1258 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001259# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001260 /*
1261 * In the new syscall ABI, the system call number is in R3.
1262 */
1263 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1264 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001265
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001266 if (scno < 0) {
1267 /* Odd as it may seem, a glibc bug has been known to cause
1268 glibc to issue bogus negative syscall numbers. So for
1269 our purposes, make strace print what it *should* have been */
1270 long correct_scno = (scno & 0xff);
1271 if (debug)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001272 fprintf(stderr,
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001273 "Detected glibc bug: bogus system call"
1274 " number = %ld, correcting to %ld\n",
1275 scno,
1276 correct_scno);
1277 scno = correct_scno;
1278 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001279
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001280 if (!(tcp->flags & TCB_INSYSCALL)) {
1281 /* Check if we return from execve. */
1282 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1283 tcp->flags &= ~TCB_WAITEXECVE;
1284 return 0;
1285 }
1286 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001287# elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001288 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001289 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001290 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001291
1292 if (!(tcp->flags & TCB_INSYSCALL)) {
1293 /* Check if we return from execve. */
1294 if (tcp->flags & TCB_WAITEXECVE) {
1295 tcp->flags &= ~TCB_WAITEXECVE;
1296 return 0;
1297 }
1298 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001299# elif defined(CRISV10) || defined(CRISV32)
1300 if (upeek(tcp, 4*PT_R9, &scno) < 0)
1301 return -1;
1302# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001303#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001304
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001305#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001306 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001308#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001309 /* new syscall ABI returns result in R0 */
1310 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1311 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001312#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001313 /* ABI defines result returned in r9 */
1314 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1315 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#endif
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001317
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001318#ifdef USE_PROCFS
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001319# ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001320 scno = tcp->status.PR_SYSCALL;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001321# else
1322# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001323 scno = tcp->status.PR_WHAT;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001324# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001325 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001326 perror("pread");
1327 return -1;
1328 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001329 switch (regs.r_eax) {
1330 case SYS_syscall:
1331 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001332 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1333 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001334 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001335 scno = regs.r_eax;
1336 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001337 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001338# endif /* FREEBSD */
1339# endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001340#endif /* USE_PROCFS */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001341
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001342 if (!(tcp->flags & TCB_INSYSCALL))
1343 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001344 return 1;
1345}
1346
Pavel Machek4dc3b142000-02-01 17:58:41 +00001347
Roland McGrath17352792005-06-07 23:21:26 +00001348long
1349known_scno(tcp)
1350struct tcb *tcp;
1351{
1352 long scno = tcp->scno;
1353 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1354 scno = sysent[scno].native_scno;
1355 else
1356 scno += NR_SYSCALL_BASE;
1357 return scno;
1358}
1359
Roland McGratheb9e2e82009-06-02 16:49:22 -07001360/* Called in trace_syscall() at each syscall entry and exit.
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001361 * Returns:
Roland McGratheb9e2e82009-06-02 16:49:22 -07001362 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1363 * 1: ok, continue in trace_syscall().
1364 * other: error, trace_syscall() should print error indicator
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001365 * ("????" etc) and bail out.
1366 */
Roland McGratha4d48532005-06-08 20:45:28 +00001367static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001368syscall_fixup(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001369{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001370#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001371 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001372
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001374 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375 if (
1376 scno == SYS_fork
1377#ifdef SYS_vfork
1378 || scno == SYS_vfork
1379#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001380#ifdef SYS_fork1
1381 || scno == SYS_fork1
1382#endif /* SYS_fork1 */
1383#ifdef SYS_forkall
1384 || scno == SYS_forkall
1385#endif /* SYS_forkall */
1386#ifdef SYS_rfork1
1387 || scno == SYS_rfork1
1388#endif /* SYS_fork1 */
1389#ifdef SYS_rforkall
1390 || scno == SYS_rforkall
1391#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001392 ) {
1393 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001394 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001395 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001396 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001397 }
1398 else {
1399 fprintf(stderr, "syscall: missing entry\n");
1400 tcp->flags |= TCB_INSYSCALL;
1401 }
1402 }
1403 }
1404 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001405 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001406 fprintf(stderr, "syscall: missing exit\n");
1407 tcp->flags &= ~TCB_INSYSCALL;
1408 }
1409 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001410#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001411#ifdef SUNOS4
1412 if (!(tcp->flags & TCB_INSYSCALL)) {
1413 if (scno == 0) {
1414 fprintf(stderr, "syscall: missing entry\n");
1415 tcp->flags |= TCB_INSYSCALL;
1416 }
1417 }
1418 else {
1419 if (scno != 0) {
1420 if (debug) {
1421 /*
1422 * This happens when a signal handler
1423 * for a signal which interrupted a
1424 * a system call makes another system call.
1425 */
1426 fprintf(stderr, "syscall: missing exit\n");
1427 }
1428 tcp->flags &= ~TCB_INSYSCALL;
1429 }
1430 }
1431#endif /* SUNOS4 */
1432#ifdef LINUX
1433#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001434 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435 return -1;
1436 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1437 if (debug)
1438 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1439 return 0;
1440 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001441#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001442 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001443 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001444 if (current_personality == 1)
1445 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001446 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1447 if (debug)
1448 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1449 return 0;
1450 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001451#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001452 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001453 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001454 if (syscall_mode != -ENOSYS)
1455 syscall_mode = tcp->scno;
1456 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001457 if (debug)
1458 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1459 return 0;
1460 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001461 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1462 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1463 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1464 /*
1465 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1466 * flag set for the post-execve SIGTRAP to see and reset.
1467 */
1468 gpr2 = 0;
1469 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001470#elif defined (POWERPC)
1471# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001472 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001473 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001474 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001475 return -1;
1476 if (flags & SO_MASK)
1477 result = -result;
1478#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001479 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001480 return -1;
1481 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1482 if (debug)
1483 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1484 return 0;
1485 }
1486#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001487 /*
1488 * Nothing required
1489 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001490#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001491 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001492 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001493#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001494 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001495 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001496#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001497 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001498 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001499 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001500 return -1;
1501 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1502 if (debug)
1503 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1504 return 0;
1505 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001506#elif defined(CRISV10) || defined(CRISV32)
1507 if (upeek(tcp->pid, 4*PT_R10, &r10) < 0)
1508 return -1;
1509 if (r10 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1510 if (debug)
1511 fprintf(stderr, "stray syscall exit: r10 = %ld\n", r10);
1512 return 0;
1513 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001514#endif
1515#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001516 return 1;
1517}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001518
Roland McGrathc1e45922008-05-27 23:18:29 +00001519#ifdef LINUX
1520/*
1521 * Check the syscall return value register value for whether it is
1522 * a negated errno code indicating an error, or a success return value.
1523 */
1524static inline int
1525is_negated_errno(unsigned long int val)
1526{
1527 unsigned long int max = -(long int) nerrnos;
1528 if (personality_wordsize[current_personality] < sizeof(val)) {
1529 val = (unsigned int) val;
1530 max = (unsigned int) max;
1531 }
1532 return val > max;
1533}
1534#endif
1535
Roland McGratha4d48532005-06-08 20:45:28 +00001536static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001537get_error(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001538{
1539 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001540#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001541# if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001542 if (is_negated_errno(gpr2)) {
1543 tcp->u_rval = -1;
1544 u_error = -gpr2;
1545 }
1546 else {
1547 tcp->u_rval = gpr2;
1548 u_error = 0;
1549 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001550# elif defined(I386)
Roland McGrathc1e45922008-05-27 23:18:29 +00001551 if (is_negated_errno(eax)) {
1552 tcp->u_rval = -1;
1553 u_error = -eax;
1554 }
1555 else {
1556 tcp->u_rval = eax;
1557 u_error = 0;
1558 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001559# elif defined(X86_64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001560 if (is_negated_errno(rax)) {
1561 tcp->u_rval = -1;
1562 u_error = -rax;
1563 }
1564 else {
1565 tcp->u_rval = rax;
1566 u_error = 0;
1567 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001568# elif defined(IA64)
Roland McGrathc1e45922008-05-27 23:18:29 +00001569 if (ia32) {
1570 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001571
Roland McGrathc1e45922008-05-27 23:18:29 +00001572 err = (int)r8;
1573 if (is_negated_errno(err)) {
1574 tcp->u_rval = -1;
1575 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001576 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001577 else {
1578 tcp->u_rval = err;
1579 u_error = 0;
1580 }
1581 } else {
1582 if (r10) {
1583 tcp->u_rval = -1;
1584 u_error = r8;
1585 } else {
1586 tcp->u_rval = r8;
1587 u_error = 0;
1588 }
1589 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001590# elif defined(MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001591 if (a3) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001592 tcp->u_rval = -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001593 u_error = r2;
1594 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001595 tcp->u_rval = r2;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001596 u_error = 0;
1597 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001598# elif defined(POWERPC)
Roland McGrathc1e45922008-05-27 23:18:29 +00001599 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001600 tcp->u_rval = -1;
1601 u_error = -result;
1602 }
1603 else {
1604 tcp->u_rval = result;
1605 u_error = 0;
1606 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001607# elif defined(M68K)
Roland McGrathc1e45922008-05-27 23:18:29 +00001608 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001609 tcp->u_rval = -1;
1610 u_error = -d0;
1611 }
1612 else {
1613 tcp->u_rval = d0;
1614 u_error = 0;
1615 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001616# elif defined(ARM)
Roland McGrathc1e45922008-05-27 23:18:29 +00001617 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001618 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001619 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 }
1621 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001622 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 u_error = 0;
1624 }
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001625# elif defined(AVR32)
1626 if (regs.r12 && (unsigned) -regs.r12 < nerrnos) {
1627 tcp->u_rval = -1;
1628 u_error = -regs.r12;
1629 }
1630 else {
1631 tcp->u_rval = regs.r12;
1632 u_error = 0;
1633 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001634# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001635 if (is_negated_errno(r0)) {
1636 tcp->u_rval = -1;
1637 u_error = -r0;
1638 } else {
1639 tcp->u_rval = r0;
1640 u_error = 0;
1641 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001642# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643 if (a3) {
1644 tcp->u_rval = -1;
1645 u_error = r0;
1646 }
1647 else {
1648 tcp->u_rval = r0;
1649 u_error = 0;
1650 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001651# elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001652 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001654 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655 }
1656 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001657 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001658 u_error = 0;
1659 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001660# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001661 if (regs.r_tstate & 0x1100000000UL) {
1662 tcp->u_rval = -1;
1663 u_error = regs.r_o0;
1664 }
1665 else {
1666 tcp->u_rval = regs.r_o0;
1667 u_error = 0;
1668 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001669# elif defined(HPPA)
Roland McGrathc1e45922008-05-27 23:18:29 +00001670 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001671 tcp->u_rval = -1;
1672 u_error = -r28;
1673 }
1674 else {
1675 tcp->u_rval = r28;
1676 u_error = 0;
1677 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001678# elif defined(SH)
Roland McGrathc1e45922008-05-27 23:18:29 +00001679 /* interpret R0 as return value or error number */
1680 if (is_negated_errno(r0)) {
1681 tcp->u_rval = -1;
1682 u_error = -r0;
1683 }
1684 else {
1685 tcp->u_rval = r0;
1686 u_error = 0;
1687 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001688# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001689 /* interpret result as return value or error number */
1690 if (is_negated_errno(r9)) {
1691 tcp->u_rval = -1;
1692 u_error = -r9;
1693 }
1694 else {
1695 tcp->u_rval = r9;
1696 u_error = 0;
1697 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001698# elif defined(CRISV10) || defined(CRISV32)
1699 if (r10 && (unsigned) -r10 < nerrnos) {
1700 tcp->u_rval = -1;
1701 u_error = -r10;
1702 }
1703 else {
1704 tcp->u_rval = r10;
1705 u_error = 0;
1706 }
1707# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708#endif /* LINUX */
1709#ifdef SUNOS4
1710 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001711 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712 return -1;
1713 u_error >>= 24; /* u_error is a char */
1714
1715 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001716 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717 return -1;
1718#endif /* SUNOS4 */
1719#ifdef SVR4
1720#ifdef SPARC
1721 /* Judicious guessing goes a long way. */
1722 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1723 tcp->u_rval = -1;
1724 u_error = tcp->status.pr_reg[R_O0];
1725 }
1726 else {
1727 tcp->u_rval = tcp->status.pr_reg[R_O0];
1728 u_error = 0;
1729 }
1730#endif /* SPARC */
1731#ifdef I386
1732 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001733 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001735 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001736 }
1737 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001738 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001739#ifdef HAVE_LONG_LONG
1740 tcp->u_lrval =
1741 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1742 tcp->status.PR_REG[EAX];
1743#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001744 u_error = 0;
1745 }
1746#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001747#ifdef X86_64
1748 /* Wanna know how to kill an hour single-stepping? */
1749 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1750 tcp->u_rval = -1;
1751 u_error = tcp->status.PR_REG[RAX];
1752 }
1753 else {
1754 tcp->u_rval = tcp->status.PR_REG[RAX];
1755 u_error = 0;
1756 }
1757#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001758#ifdef MIPS
1759 if (tcp->status.pr_reg[CTX_A3]) {
1760 tcp->u_rval = -1;
1761 u_error = tcp->status.pr_reg[CTX_V0];
1762 }
1763 else {
1764 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1765 u_error = 0;
1766 }
1767#endif /* MIPS */
1768#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001769#ifdef FREEBSD
1770 if (regs.r_eflags & PSL_C) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001771 tcp->u_rval = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001772 u_error = regs.r_eax;
1773 } else {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001774 tcp->u_rval = regs.r_eax;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001775 tcp->u_lrval =
1776 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1777 u_error = 0;
1778 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001779#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001780 tcp->u_error = u_error;
1781 return 1;
1782}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001783
Roland McGrathb69f81b2002-12-21 23:25:18 +00001784int
1785force_result(tcp, error, rval)
1786 struct tcb *tcp;
1787 int error;
1788 long rval;
1789{
1790#ifdef LINUX
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001791# if defined(S390) || defined(S390X)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001792 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001793 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1794 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001795# elif defined(I386)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001796 eax = error ? -error : rval;
1797 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1798 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001799# elif defined(X86_64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001800 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001801 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001802 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001803# elif defined(IA64)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001804 if (ia32) {
1805 r8 = error ? -error : rval;
1806 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1807 return -1;
1808 }
1809 else {
1810 if (error) {
1811 r8 = error;
1812 r10 = -1;
1813 }
1814 else {
1815 r8 = rval;
1816 r10 = 0;
1817 }
1818 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1819 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1820 return -1;
1821 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001822# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001823 r0 = error ? -error : rval;
1824 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1825 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001826# elif defined(MIPS)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001827 if (error) {
1828 r2 = error;
1829 a3 = -1;
1830 }
1831 else {
1832 r2 = rval;
1833 a3 = 0;
1834 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001835 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001836 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1837 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001838 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001839# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001840 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001841 return -1;
1842 if (error) {
1843 flags |= SO_MASK;
1844 result = error;
1845 }
1846 else {
1847 flags &= ~SO_MASK;
1848 result = rval;
1849 }
Roland McGratheb285352003-01-14 09:59:00 +00001850 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1851 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001852 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001853# elif defined(M68K)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001854 d0 = error ? -error : rval;
1855 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1856 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001857# elif defined(ARM)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001858 regs.ARM_r0 = error ? -error : rval;
1859 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001860 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001861# elif defined(AVR32)
1862 regs.r12 = error ? -error : rval;
1863 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_R12, regs.r12) < 0)
1864 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001865# elif defined(ALPHA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001866 if (error) {
1867 a3 = -1;
1868 r0 = error;
1869 }
1870 else {
1871 a3 = 0;
1872 r0 = rval;
1873 }
1874 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1875 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1876 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001877# elif defined(SPARC)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001878 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1879 return -1;
1880 if (error) {
1881 regs.r_psr |= PSR_C;
1882 regs.r_o0 = error;
1883 }
1884 else {
1885 regs.r_psr &= ~PSR_C;
1886 regs.r_o0 = rval;
1887 }
1888 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1889 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001890# elif defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001891 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1892 return -1;
1893 if (error) {
1894 regs.r_tstate |= 0x1100000000UL;
1895 regs.r_o0 = error;
1896 }
1897 else {
1898 regs.r_tstate &= ~0x1100000000UL;
1899 regs.r_o0 = rval;
1900 }
1901 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1902 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001903# elif defined(HPPA)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001904 r28 = error ? -error : rval;
1905 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1906 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001907# elif defined(SH)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001908 r0 = error ? -error : rval;
1909 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1910 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001911# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001912 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001913 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1914 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001915# endif
Roland McGrathb69f81b2002-12-21 23:25:18 +00001916#endif /* LINUX */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001917
Roland McGrathb69f81b2002-12-21 23:25:18 +00001918#ifdef SUNOS4
Roland McGratheb9e2e82009-06-02 16:49:22 -07001919 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1920 error << 24) < 0 ||
1921 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001922 return -1;
1923#endif /* SUNOS4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001924
Roland McGrathb69f81b2002-12-21 23:25:18 +00001925#ifdef SVR4
1926 /* XXX no clue */
1927 return -1;
1928#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001929
Roland McGrathb69f81b2002-12-21 23:25:18 +00001930#ifdef FREEBSD
1931 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001932 perror("pread");
1933 return -1;
1934 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001935 if (error) {
1936 regs.r_eflags |= PSL_C;
1937 regs.r_eax = error;
1938 }
1939 else {
1940 regs.r_eflags &= ~PSL_C;
1941 regs.r_eax = rval;
1942 }
1943 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001944 perror("pwrite");
1945 return -1;
1946 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001947#endif /* FREEBSD */
1948
1949 /* All branches reach here on success (only). */
1950 tcp->u_error = error;
1951 tcp->u_rval = rval;
1952 return 0;
1953}
1954
Roland McGratha4d48532005-06-08 20:45:28 +00001955static int
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001956syscall_enter(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001957{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001958#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001959#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001960 {
1961 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001962 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1963 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001964 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001965 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001966 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001967 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001968 return -1;
1969 }
1970 }
1971#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001972 {
1973 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001974 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1975 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001976 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001977 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001978 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001979 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1980 * for scno somewhere above here!
1981 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001982 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001983 return -1;
1984 }
1985 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001986#elif defined (IA64)
1987 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001988 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001989 unsigned long *out0, cfm, sof, sol, i;
1990 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001991 /* be backwards compatible with kernel < 2.4.4... */
1992# ifndef PT_RBS_END
1993# define PT_RBS_END PT_AR_BSP
1994# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001995
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001996 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001997 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001998 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001999 return -1;
2000
2001 sof = (cfm >> 0) & 0x7f;
2002 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002003 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002004
2005 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2006 && sysent[tcp->scno].nargs != -1)
2007 tcp->u_nargs = sysent[tcp->scno].nargs;
2008 else
2009 tcp->u_nargs = MAX_ARGS;
2010 for (i = 0; i < tcp->u_nargs; ++i) {
2011 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2012 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2013 return -1;
2014 }
2015 } else {
2016 int i;
2017
2018 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002019 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002020 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002021 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002022 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002023 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002024 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002025 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002026 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002027 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002028 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002029 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002030 return -1;
2031
2032 for (i = 0; i < 6; ++i)
2033 /* truncate away IVE sign-extension */
2034 tcp->u_arg[i] &= 0xffffffff;
2035
2036 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2037 && sysent[tcp->scno].nargs != -1)
2038 tcp->u_nargs = sysent[tcp->scno].nargs;
2039 else
2040 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002041 }
2042 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002043#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2044 /* N32 and N64 both use up to six registers. */
2045 {
2046 unsigned long long regs[38];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002047 int i, nargs;
Roland McGrath542c2c62008-05-20 01:11:56 +00002048
2049 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2050 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002051 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002052 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGrath542c2c62008-05-20 01:11:56 +00002053
Roland McGratheb9e2e82009-06-02 16:49:22 -07002054 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00002055 return -1;
2056
Roland McGratheb9e2e82009-06-02 16:49:22 -07002057 for(i = 0; i < nargs; i++) {
Roland McGrath542c2c62008-05-20 01:11:56 +00002058 tcp->u_arg[i] = regs[REG_A0 + i];
2059# if defined (LINUX_MIPSN32)
2060 tcp->ext_arg[i] = regs[REG_A0 + i];
2061# endif
2062 }
2063 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002064#elif defined (MIPS)
2065 {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002066 long sp;
2067 int i, nargs;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002068
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002069 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2070 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002071 else
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002072 nargs = tcp->u_nargs = MAX_ARGS;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002073 if(nargs > 4) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002074 if(upeek(tcp, REG_SP, &sp) < 0)
2075 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002076 for(i = 0; i < 4; i++) {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002077 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
2078 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002079 }
2080 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2081 (char *)(tcp->u_arg + 4));
2082 } else {
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002083 for(i = 0; i < nargs; i++) {
2084 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
2085 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002086 }
2087 }
2088 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002089#elif defined (POWERPC)
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002090# ifndef PT_ORIG_R3
2091# define PT_ORIG_R3 34
2092# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002093 {
2094 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002095 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2096 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002097 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002098 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002099 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002100 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002101 (sizeof(unsigned long)*PT_ORIG_R3) :
2102 ((i+PT_R3)*sizeof(unsigned long)),
2103 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002104 return -1;
2105 }
2106 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002107#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002108 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002109 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002110
2111 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2112 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002113 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002114 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002115 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002116 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002117 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002118#elif defined (HPPA)
2119 {
2120 int i;
2121
2122 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2123 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002124 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002125 tcp->u_nargs = MAX_ARGS;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002126 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002127 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002128 return -1;
2129 }
2130 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002131#elif defined(ARM)
2132 {
2133 int i;
2134
2135 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2136 tcp->u_nargs = sysent[tcp->scno].nargs;
2137 else
2138 tcp->u_nargs = MAX_ARGS;
2139 for (i = 0; i < tcp->u_nargs; i++)
2140 tcp->u_arg[i] = regs.uregs[i];
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002141 }
2142#elif defined(AVR32)
2143 tcp->u_nargs = sysent[tcp->scno].nargs;
2144 tcp->u_arg[0] = regs.r12;
2145 tcp->u_arg[1] = regs.r11;
2146 tcp->u_arg[2] = regs.r10;
2147 tcp->u_arg[3] = regs.r9;
2148 tcp->u_arg[4] = regs.r5;
2149 tcp->u_arg[5] = regs.r3;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002150#elif defined(BFIN)
2151 {
2152 int i;
2153 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2154
2155 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2156 tcp->u_nargs = sysent[tcp->scno].nargs;
2157 else
2158 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2159
2160 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002161 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002162 return -1;
2163 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002164#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002165 {
2166 int i;
2167 static int syscall_regs[] = {
2168 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2169 REG_REG0, REG_REG0+1, REG_REG0+2
2170 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002171
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002172 tcp->u_nargs = sysent[tcp->scno].nargs;
2173 for (i = 0; i < tcp->u_nargs; i++) {
2174 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2175 return -1;
2176 }
2177 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002178#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002179 {
2180 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002181 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002182 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2183
2184 /*
2185 * TODO: should also check that the number of arguments encoded
2186 * in the trap number matches the number strace expects.
2187 */
2188 /*
Dmitry V. Levin414fe7d2009-07-08 11:21:17 +00002189 assert(sysent[tcp->scno].nargs <
2190 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
Roland McGrathe1e584b2003-06-02 19:18:58 +00002191 */
2192
2193 tcp->u_nargs = sysent[tcp->scno].nargs;
2194 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002195 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002196 return -1;
2197 }
2198 }
2199
Michal Ludvig0e035502002-09-23 15:41:01 +00002200#elif defined(X86_64)
2201 {
2202 int i;
2203 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2204 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002205 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002206 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002207
Michal Ludvig0e035502002-09-23 15:41:01 +00002208 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2209 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002210 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002211 tcp->u_nargs = MAX_ARGS;
Michal Ludvig0e035502002-09-23 15:41:01 +00002212 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002213 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002214 return -1;
2215 }
2216 }
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002217#elif defined(CRISV10) || defined(CRISV32)
2218 {
2219 int i;
2220 static const int crisregs[] = {
2221 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12,
2222 4*PT_R13, 4*PT_MOF, 4*PT_SRP
2223 };
2224
2225 if (tcp->scno >= 0 && tcp->scno < nsyscalls)
2226 tcp->u_nargs = sysent[tcp->scno].nargs;
2227 else
2228 tcp->u_nargs = 0;
2229 for (i = 0; i < tcp->u_nargs; i++) {
2230 if (upeek(tcp->pid, crisregs[i], &tcp->u_arg[i]) < 0)
2231 return -1;
2232 }
2233 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002234#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002235 {
2236 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002237 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2238 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002239 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002240 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002241 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002242 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002243 return -1;
2244 }
2245 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002246#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247#endif /* LINUX */
2248#ifdef SUNOS4
2249 {
2250 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002251 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2252 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002253 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002254 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002255 for (i = 0; i < tcp->u_nargs; i++) {
2256 struct user *u;
2257
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002258 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2260 return -1;
2261 }
2262 }
2263#endif /* SUNOS4 */
2264#ifdef SVR4
2265#ifdef MIPS
2266 /*
2267 * SGI is broken: even though it has pr_sysarg, it doesn't
2268 * set them on system call entry. Get a clue.
2269 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002270 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002271 tcp->u_nargs = sysent[tcp->scno].nargs;
2272 else
2273 tcp->u_nargs = tcp->status.pr_nsysarg;
2274 if (tcp->u_nargs > 4) {
2275 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2276 4*sizeof(tcp->u_arg[0]));
2277 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2278 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2279 }
2280 else {
2281 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2282 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2283 }
John Hughes25299712001-03-06 10:10:06 +00002284#elif UNIXWARE >= 2
2285 /*
2286 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2287 */
2288 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2289 tcp->u_nargs = sysent[tcp->scno].nargs;
2290 else
2291 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2292 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2293 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2294#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002295 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002296 tcp->u_nargs = sysent[tcp->scno].nargs;
2297 else
2298 tcp->u_nargs = tcp->status.pr_nsysarg;
2299 {
2300 int i;
2301 for (i = 0; i < tcp->u_nargs; i++)
2302 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2303 }
John Hughes25299712001-03-06 10:10:06 +00002304#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002305 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002306 tcp->u_nargs = sysent[tcp->scno].nargs;
2307 else
2308 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002309 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002310 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002311#else
2312 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002313#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002314#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002315#ifdef FREEBSD
2316 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2317 sysent[tcp->scno].nargs > tcp->status.val)
2318 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002319 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002320 tcp->u_nargs = tcp->status.val;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002321 if (tcp->u_nargs < 0)
2322 tcp->u_nargs = 0;
2323 if (tcp->u_nargs > MAX_ARGS)
2324 tcp->u_nargs = MAX_ARGS;
2325 switch(regs.r_eax) {
2326 case SYS___syscall:
2327 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2328 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002329 break;
2330 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002331 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2332 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002333 break;
2334 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002335 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2336 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002337 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002338 }
2339#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002340 return 1;
2341}
2342
2343int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002344trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002345{
2346 int sys_res;
2347 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002348 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002349
2350 if (tcp->flags & TCB_INSYSCALL) {
2351 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002352
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002353 /* Measure the exit time as early as possible to avoid errors. */
2354 if (dtime)
2355 gettimeofday(&tv, NULL);
2356
Roland McGratheb9e2e82009-06-02 16:49:22 -07002357 /* BTW, why we don't just memorize syscall no. on entry
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002358 * in tcp->something?
2359 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002360 scno_good = res = get_scno(tcp);
2361 if (res == 0)
2362 return res;
2363 if (res == 1)
2364 res = syscall_fixup(tcp);
2365 if (res == 0)
2366 return res;
2367 if (res == 1)
2368 res = get_error(tcp);
2369 if (res == 0)
2370 return res;
2371 if (res == 1)
2372 internal_syscall(tcp);
2373
2374 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002375 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002376 tcp->flags &= ~TCB_INSYSCALL;
2377 return 0;
2378 }
2379
2380 if (tcp->flags & TCB_REPRINT) {
2381 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002382 tprintf("<... ");
2383 if (scno_good != 1)
2384 tprintf("????");
2385 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2386 tprintf("syscall_%lu", tcp->scno);
2387 else
2388 tprintf("%s", sysent[tcp->scno].sys_name);
2389 tprintf(" resumed> ");
Pavel Machek4dc3b142000-02-01 17:58:41 +00002390 }
2391
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002392 if (cflag)
2393 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002394
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002395 if (res != 1) {
2396 tprintf(") ");
2397 tabto(acolumn);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002398 tprintf("= ? <unavailable>");
2399 printtrailer();
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002400 tcp->flags &= ~TCB_INSYSCALL;
2401 return res;
2402 }
2403
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002404 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002405 || (qual_flags[tcp->scno] & QUAL_RAW))
2406 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002407 else {
2408 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002409 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002410 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002411 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002412 u_error = tcp->u_error;
2413 tprintf(") ");
2414 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002415 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2416 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002417 if (u_error)
2418 tprintf("= -1 (errno %ld)", u_error);
2419 else
2420 tprintf("= %#lx", tcp->u_rval);
2421 }
2422 else if (!(sys_res & RVAL_NONE) && u_error) {
2423 switch (u_error) {
2424#ifdef LINUX
2425 case ERESTARTSYS:
2426 tprintf("= ? ERESTARTSYS (To be restarted)");
2427 break;
2428 case ERESTARTNOINTR:
2429 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2430 break;
2431 case ERESTARTNOHAND:
2432 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2433 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002434 case ERESTART_RESTARTBLOCK:
2435 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2436 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002437#endif /* LINUX */
2438 default:
2439 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002440 if (u_error < 0)
2441 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002442 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002443 tprintf("%s (%s)", errnoent[u_error],
2444 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002445 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002446 tprintf("ERRNO_%ld (%s)", u_error,
2447 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002448 break;
2449 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002450 if ((sys_res & RVAL_STR) && tcp->auxstr)
2451 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002452 }
2453 else {
2454 if (sys_res & RVAL_NONE)
2455 tprintf("= ?");
2456 else {
2457 switch (sys_res & RVAL_MASK) {
2458 case RVAL_HEX:
2459 tprintf("= %#lx", tcp->u_rval);
2460 break;
2461 case RVAL_OCTAL:
2462 tprintf("= %#lo", tcp->u_rval);
2463 break;
2464 case RVAL_UDECIMAL:
2465 tprintf("= %lu", tcp->u_rval);
2466 break;
2467 case RVAL_DECIMAL:
2468 tprintf("= %ld", tcp->u_rval);
2469 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002470#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002471 case RVAL_LHEX:
2472 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002473 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002474 case RVAL_LOCTAL:
2475 tprintf("= %#llo", tcp->u_lrval);
2476 break;
2477 case RVAL_LUDECIMAL:
2478 tprintf("= %llu", tcp->u_lrval);
2479 break;
2480 case RVAL_LDECIMAL:
2481 tprintf("= %lld", tcp->u_lrval);
2482 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002483#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002484 default:
2485 fprintf(stderr,
2486 "invalid rval format\n");
2487 break;
2488 }
2489 }
2490 if ((sys_res & RVAL_STR) && tcp->auxstr)
2491 tprintf(" (%s)", tcp->auxstr);
2492 }
2493 if (dtime) {
2494 tv_sub(&tv, &tv, &tcp->etime);
2495 tprintf(" <%ld.%06ld>",
2496 (long) tv.tv_sec, (long) tv.tv_usec);
2497 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002498 printtrailer();
Pavel Machek4dc3b142000-02-01 17:58:41 +00002499
2500 dumpio(tcp);
2501 if (fflush(tcp->outf) == EOF)
2502 return -1;
2503 tcp->flags &= ~TCB_INSYSCALL;
2504 return 0;
2505 }
2506
2507 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002508 scno_good = res = get_scno(tcp);
2509 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002510 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002511 if (res == 1)
2512 res = syscall_fixup(tcp);
2513 if (res == 0)
2514 return res;
2515 if (res == 1)
2516 res = syscall_enter(tcp);
2517 if (res == 0)
2518 return res;
2519
2520 if (res != 1) {
2521 printleader(tcp);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002522 tcp->flags &= ~TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002523 tcp_last = tcp;
2524 if (scno_good != 1)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002525 tprintf("????" /* anti-trigraph gap */ "(");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002526 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2527 tprintf("syscall_%lu(", tcp->scno);
2528 else
2529 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002530 /*
2531 * " <unavailable>" will be added later by the code which
2532 * detects ptrace errors.
2533 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002534 tcp->flags |= TCB_INSYSCALL;
2535 return res;
2536 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002537
Roland McGrath17352792005-06-07 23:21:26 +00002538 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002539#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002540 case SYS_socketcall:
2541 decode_subcall(tcp, SYS_socket_subcall,
2542 SYS_socket_nsubcalls, deref_style);
2543 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002544#endif
2545#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002546 case SYS_ipc:
2547 decode_subcall(tcp, SYS_ipc_subcall,
2548 SYS_ipc_nsubcalls, shift_style);
2549 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002550#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002551#ifdef SVR4
2552#ifdef SYS_pgrpsys_subcall
2553 case SYS_pgrpsys:
2554 decode_subcall(tcp, SYS_pgrpsys_subcall,
2555 SYS_pgrpsys_nsubcalls, shift_style);
2556 break;
2557#endif /* SYS_pgrpsys_subcall */
2558#ifdef SYS_sigcall_subcall
2559 case SYS_sigcall:
2560 decode_subcall(tcp, SYS_sigcall_subcall,
2561 SYS_sigcall_nsubcalls, mask_style);
2562 break;
2563#endif /* SYS_sigcall_subcall */
2564 case SYS_msgsys:
2565 decode_subcall(tcp, SYS_msgsys_subcall,
2566 SYS_msgsys_nsubcalls, shift_style);
2567 break;
2568 case SYS_shmsys:
2569 decode_subcall(tcp, SYS_shmsys_subcall,
2570 SYS_shmsys_nsubcalls, shift_style);
2571 break;
2572 case SYS_semsys:
2573 decode_subcall(tcp, SYS_semsys_subcall,
2574 SYS_semsys_nsubcalls, shift_style);
2575 break;
2576#if 0 /* broken */
2577 case SYS_utssys:
2578 decode_subcall(tcp, SYS_utssys_subcall,
2579 SYS_utssys_nsubcalls, shift_style);
2580 break;
2581#endif
2582 case SYS_sysfs:
2583 decode_subcall(tcp, SYS_sysfs_subcall,
2584 SYS_sysfs_nsubcalls, shift_style);
2585 break;
2586 case SYS_spcall:
2587 decode_subcall(tcp, SYS_spcall_subcall,
2588 SYS_spcall_nsubcalls, shift_style);
2589 break;
2590#ifdef SYS_context_subcall
2591 case SYS_context:
2592 decode_subcall(tcp, SYS_context_subcall,
2593 SYS_context_nsubcalls, shift_style);
2594 break;
2595#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002596#ifdef SYS_door_subcall
2597 case SYS_door:
2598 decode_subcall(tcp, SYS_door_subcall,
2599 SYS_door_nsubcalls, door_style);
2600 break;
2601#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002602#ifdef SYS_kaio_subcall
2603 case SYS_kaio:
2604 decode_subcall(tcp, SYS_kaio_subcall,
2605 SYS_kaio_nsubcalls, shift_style);
2606 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002607#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002608#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002609#ifdef FREEBSD
2610 case SYS_msgsys:
2611 case SYS_shmsys:
2612 case SYS_semsys:
2613 decode_subcall(tcp, 0, 0, table_style);
2614 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002615#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002616#ifdef SUNOS4
2617 case SYS_semsys:
2618 decode_subcall(tcp, SYS_semsys_subcall,
2619 SYS_semsys_nsubcalls, shift_style);
2620 break;
2621 case SYS_msgsys:
2622 decode_subcall(tcp, SYS_msgsys_subcall,
2623 SYS_msgsys_nsubcalls, shift_style);
2624 break;
2625 case SYS_shmsys:
2626 decode_subcall(tcp, SYS_shmsys_subcall,
2627 SYS_shmsys_nsubcalls, shift_style);
2628 break;
2629#endif
2630 }
2631
2632 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002633 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002634 tcp->flags |= TCB_INSYSCALL;
2635 return 0;
2636 }
2637
2638 if (cflag) {
2639 gettimeofday(&tcp->etime, NULL);
2640 tcp->flags |= TCB_INSYSCALL;
2641 return 0;
2642 }
2643
2644 printleader(tcp);
2645 tcp->flags &= ~TCB_REPRINT;
2646 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002647 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002648 tprintf("syscall_%lu(", tcp->scno);
2649 else
2650 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002651 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002652 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2653 sys_res = printargs(tcp);
2654 else
2655 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2656 if (fflush(tcp->outf) == EOF)
2657 return -1;
2658 tcp->flags |= TCB_INSYSCALL;
2659 /* Measure the entrance time as late as possible to avoid errors. */
2660 if (dtime)
2661 gettimeofday(&tcp->etime, NULL);
2662 return sys_res;
2663}
2664
2665int
2666printargs(tcp)
2667struct tcb *tcp;
2668{
2669 if (entering(tcp)) {
2670 int i;
2671
2672 for (i = 0; i < tcp->u_nargs; i++)
2673 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2674 }
2675 return 0;
2676}
2677
2678long
2679getrval2(tcp)
2680struct tcb *tcp;
2681{
2682 long val = -1;
2683
2684#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002685#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002686 struct regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002687 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002688 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002689 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002690#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002691 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002692 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002693#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002694 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002695 return -1;
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002696#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002697#endif /* LINUX */
2698
2699#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002700 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002701 return -1;
2702#endif /* SUNOS4 */
2703
2704#ifdef SVR4
2705#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002706 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002707#endif /* SPARC */
2708#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002709 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002711#ifdef X86_64
2712 val = tcp->status.PR_REG[RDX];
2713#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002714#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002715 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002716#endif /* MIPS */
2717#endif /* SVR4 */
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00002718
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002719#ifdef FREEBSD
2720 struct reg regs;
2721 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2722 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002723#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002724 return val;
2725}
2726
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002727#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002728/*
2729 * Apparently, indirect system calls have already be converted by ptrace(2),
2730 * so if you see "indir" this program has gone astray.
2731 */
2732int
2733sys_indir(tcp)
2734struct tcb *tcp;
2735{
2736 int i, scno, nargs;
2737
2738 if (entering(tcp)) {
2739 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2740 fprintf(stderr, "Bogus syscall: %u\n", scno);
2741 return 0;
2742 }
2743 nargs = sysent[scno].nargs;
2744 tprintf("%s", sysent[scno].sys_name);
2745 for (i = 0; i < nargs; i++)
2746 tprintf(", %#lx", tcp->u_arg[i+1]);
2747 }
2748 return 0;
2749}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002750#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002751
2752int
2753is_restart_error(struct tcb *tcp)
2754{
2755#ifdef LINUX
2756 if (!syserror(tcp))
2757 return 0;
2758 switch (tcp->u_error) {
2759 case ERESTARTSYS:
2760 case ERESTARTNOINTR:
2761 case ERESTARTNOHAND:
2762 case ERESTART_RESTARTBLOCK:
2763 return 1;
2764 default:
2765 break;
2766 }
2767#endif /* LINUX */
2768 return 0;
2769}