blob: 8ecc8ed5eb836c71c6eebd7f4adf589651503da8 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
38#include <signal.h>
39#include <time.h>
40#include <errno.h>
41#include <sys/user.h>
42#include <sys/syscall.h>
43#include <sys/param.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044
Wichert Akkerman15dea971999-10-06 13:06:34 +000045#if HAVE_ASM_REG_H
Roland McGrath6d1a65c2004-07-12 07:44:08 +000046#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000047# define fpq kernel_fpq
48# define fq kernel_fq
49# define fpu kernel_fpu
50#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000051#include <asm/reg.h>
Roland McGrath6d1a65c2004-07-12 07:44:08 +000052#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000053# undef fpq
54# undef fq
Roland McGrath761b5d72002-12-15 23:58:31 +000055# undef fpu
Wichert Akkerman00a82ee2001-03-28 20:29:17 +000056#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000057#endif
58
Wichert Akkerman15dea971999-10-06 13:06:34 +000059#ifdef HAVE_SYS_REG_H
60#include <sys/reg.h>
61#ifndef PTRACE_PEEKUSR
62# define PTRACE_PEEKUSR PTRACE_PEEKUSER
63#endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman15dea971999-10-06 13:06:34 +000075#endif
76
Roland McGrath6d1a65c2004-07-12 07:44:08 +000077#if defined (LINUX) && defined (SPARC64)
78# define r_pc r_tpc
79# undef PTRACE_GETREGS
80# define PTRACE_GETREGS PTRACE_GETREGS64
81# undef PTRACE_SETREGS
82# define PTRACE_SETREGS PTRACE_SETREGS64
83#endif /* LINUX && SPARC64 */
84
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000085#if defined(LINUX) && defined(IA64)
86# include <asm/ptrace_offsets.h>
87# include <asm/rse.h>
88#endif
89
Pavel Machekd8ae7e32000-02-01 17:17:25 +000090#define NR_SYSCALL_BASE 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091#ifdef LINUX
92#ifndef ERESTARTSYS
93#define ERESTARTSYS 512
94#endif
95#ifndef ERESTARTNOINTR
96#define ERESTARTNOINTR 513
97#endif
98#ifndef ERESTARTNOHAND
99#define ERESTARTNOHAND 514 /* restart if no handler.. */
100#endif
101#ifndef ENOIOCTLCMD
102#define ENOIOCTLCMD 515 /* No ioctl command */
103#endif
Roland McGrath9c555e72003-07-09 09:47:59 +0000104#ifndef ERESTART_RESTARTBLOCK
105#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
106#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107#ifndef NSIG
108#define NSIG 32
109#endif
110#ifdef ARM
111#undef NSIG
112#define NSIG 32
Pavel Machekd8ae7e32000-02-01 17:17:25 +0000113#undef NR_SYSCALL_BASE
114#define NR_SYSCALL_BASE __NR_SYSCALL_BASE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115#endif
116#endif /* LINUX */
117
118#include "syscall.h"
119
120/* Define these shorthand notations to simplify the syscallent files. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000121#define TD TRACE_DESC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122#define TF TRACE_FILE
123#define TI TRACE_IPC
124#define TN TRACE_NETWORK
125#define TP TRACE_PROCESS
126#define TS TRACE_SIGNAL
127
Roland McGrathee36ce12004-09-04 03:53:10 +0000128static const struct sysent sysent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129#include "syscallent.h"
130};
Roland McGrathee36ce12004-09-04 03:53:10 +0000131static const int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000132int qual_flags0[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133
134#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000135static const struct sysent sysent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000136#include "syscallent1.h"
137};
Roland McGrathee36ce12004-09-04 03:53:10 +0000138static const int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000139int qual_flags1[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140#endif /* SUPPORTED_PERSONALITIES >= 2 */
141
142#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000143static const struct sysent sysent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#include "syscallent2.h"
145};
Roland McGrathee36ce12004-09-04 03:53:10 +0000146static const int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];
Roland McGrath138c6a32006-01-12 09:50:49 +0000147int qual_flags2[MAX_QUALS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148#endif /* SUPPORTED_PERSONALITIES >= 3 */
149
Roland McGrathee36ce12004-09-04 03:53:10 +0000150const struct sysent *sysent;
Roland McGrath138c6a32006-01-12 09:50:49 +0000151int *qual_flags;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152int nsyscalls;
153
154/* Now undef them since short defines cause wicked namespace pollution. */
Roland McGrath2fe7b132005-07-05 03:25:35 +0000155#undef TD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156#undef TF
157#undef TI
158#undef TN
159#undef TP
160#undef TS
161
Roland McGrathee36ce12004-09-04 03:53:10 +0000162static const char *const errnoent0[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163#include "errnoent.h"
164};
Roland McGrathee36ce12004-09-04 03:53:10 +0000165static const int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166
167#if SUPPORTED_PERSONALITIES >= 2
Roland McGrathee36ce12004-09-04 03:53:10 +0000168static const char *const errnoent1[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169#include "errnoent1.h"
170};
Roland McGrathee36ce12004-09-04 03:53:10 +0000171static const int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000172#endif /* SUPPORTED_PERSONALITIES >= 2 */
173
174#if SUPPORTED_PERSONALITIES >= 3
Roland McGrathee36ce12004-09-04 03:53:10 +0000175static const char *const errnoent2[] = {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176#include "errnoent2.h"
177};
Roland McGrathee36ce12004-09-04 03:53:10 +0000178static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000179#endif /* SUPPORTED_PERSONALITIES >= 3 */
180
Roland McGrathee36ce12004-09-04 03:53:10 +0000181const char *const *errnoent;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182int nerrnos;
183
184int current_personality;
185
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000186#ifndef PERSONALITY0_WORDSIZE
187# define PERSONALITY0_WORDSIZE sizeof(long)
188#endif
189const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
190 PERSONALITY0_WORDSIZE,
191#if SUPPORTED_PERSONALITIES > 1
192 PERSONALITY1_WORDSIZE,
193#endif
194#if SUPPORTED_PERSONALITIES > 2
195 PERSONALITY2_WORDSIZE,
196#endif
197};;
198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199int
Dmitry V. Levin3abe8b22006-12-20 22:37:21 +0000200set_personality(int personality)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201{
202 switch (personality) {
203 case 0:
204 errnoent = errnoent0;
205 nerrnos = nerrnos0;
206 sysent = sysent0;
207 nsyscalls = nsyscalls0;
208 ioctlent = ioctlent0;
209 nioctlents = nioctlents0;
210 signalent = signalent0;
211 nsignals = nsignals0;
Roland McGrath138c6a32006-01-12 09:50:49 +0000212 qual_flags = qual_flags0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000213 break;
214
215#if SUPPORTED_PERSONALITIES >= 2
216 case 1:
217 errnoent = errnoent1;
218 nerrnos = nerrnos1;
219 sysent = sysent1;
220 nsyscalls = nsyscalls1;
221 ioctlent = ioctlent1;
222 nioctlents = nioctlents1;
223 signalent = signalent1;
224 nsignals = nsignals1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000225 qual_flags = qual_flags1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000226 break;
227#endif /* SUPPORTED_PERSONALITIES >= 2 */
228
229#if SUPPORTED_PERSONALITIES >= 3
230 case 2:
231 errnoent = errnoent2;
232 nerrnos = nerrnos2;
233 sysent = sysent2;
234 nsyscalls = nsyscalls2;
235 ioctlent = ioctlent2;
236 nioctlents = nioctlents2;
237 signalent = signalent2;
238 nsignals = nsignals2;
Roland McGrath138c6a32006-01-12 09:50:49 +0000239 qual_flags = qual_flags2;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 break;
241#endif /* SUPPORTED_PERSONALITIES >= 3 */
242
243 default:
244 return -1;
245 }
246
247 current_personality = personality;
248 return 0;
249}
250
Roland McGrathe10e62a2004-09-04 04:20:43 +0000251
Roland McGrath9797ceb2002-12-30 10:23:00 +0000252static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253
Roland McGrathe10e62a2004-09-04 04:20:43 +0000254static const struct qual_options {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 int bitflag;
256 char *option_name;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000257 int (*qualify)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000258 char *argument_name;
259} qual_options[] = {
Roland McGrath9797ceb2002-12-30 10:23:00 +0000260 { QUAL_TRACE, "trace", qual_syscall, "system call" },
261 { QUAL_TRACE, "t", qual_syscall, "system call" },
262 { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
263 { QUAL_ABBREV, "a", qual_syscall, "system call" },
264 { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
265 { QUAL_VERBOSE, "v", qual_syscall, "system call" },
266 { QUAL_RAW, "raw", qual_syscall, "system call" },
267 { QUAL_RAW, "x", qual_syscall, "system call" },
268 { QUAL_SIGNAL, "signal", qual_signal, "signal" },
269 { QUAL_SIGNAL, "signals", qual_signal, "signal" },
270 { QUAL_SIGNAL, "s", qual_signal, "signal" },
271 { QUAL_FAULT, "fault", qual_fault, "fault" },
272 { QUAL_FAULT, "faults", qual_fault, "fault" },
273 { QUAL_FAULT, "m", qual_fault, "fault" },
274 { QUAL_READ, "read", qual_desc, "descriptor" },
275 { QUAL_READ, "reads", qual_desc, "descriptor" },
276 { QUAL_READ, "r", qual_desc, "descriptor" },
277 { QUAL_WRITE, "write", qual_desc, "descriptor" },
278 { QUAL_WRITE, "writes", qual_desc, "descriptor" },
279 { QUAL_WRITE, "w", qual_desc, "descriptor" },
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 { 0, NULL, NULL, NULL },
281};
282
Roland McGrath9797ceb2002-12-30 10:23:00 +0000283static void
Roland McGrath138c6a32006-01-12 09:50:49 +0000284qualify_one(n, opt, not, pers)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000285 int n;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000286 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000287 int not;
Roland McGrath138c6a32006-01-12 09:50:49 +0000288 int pers;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000289{
Roland McGrath138c6a32006-01-12 09:50:49 +0000290 if (pers == 0 || pers < 0) {
291 if (not)
292 qual_flags0[n] &= ~opt->bitflag;
293 else
294 qual_flags0[n] |= opt->bitflag;
295 }
296
297#if SUPPORTED_PERSONALITIES >= 2
298 if (pers == 1 || pers < 0) {
299 if (not)
300 qual_flags1[n] &= ~opt->bitflag;
301 else
302 qual_flags1[n] |= opt->bitflag;
303 }
304#endif /* SUPPORTED_PERSONALITIES >= 2 */
305
306#if SUPPORTED_PERSONALITIES >= 3
307 if (pers == 2 || pers < 0) {
308 if (not)
309 qual_flags2[n] &= ~opt->bitflag;
310 else
311 qual_flags2[n] |= opt->bitflag;
312 }
313#endif /* SUPPORTED_PERSONALITIES >= 3 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000314}
315
316static int
Roland McGrath9797ceb2002-12-30 10:23:00 +0000317qual_syscall(s, opt, not)
318 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000319 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000320 int not;
321{
322 int i;
Roland McGrathfe6b3522005-02-02 04:40:11 +0000323 int rc = -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000324
Roland McGrath48a035f2006-01-12 09:45:56 +0000325 if (isdigit((unsigned char)*s)) {
326 int i = atoi(s);
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000327 if (i < 0 || i >= MAX_QUALS)
Roland McGrath48a035f2006-01-12 09:45:56 +0000328 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000329 qualify_one(i, opt, not, -1);
Roland McGrath48a035f2006-01-12 09:45:56 +0000330 return 0;
331 }
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000332 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000333 if (strcmp(s, sysent0[i].sys_name) == 0) {
334 qualify_one(i, opt, not, 0);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000335 rc = 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000336 }
Roland McGrath138c6a32006-01-12 09:50:49 +0000337
338#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000339 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000340 if (strcmp(s, sysent1[i].sys_name) == 0) {
341 qualify_one(i, opt, not, 1);
342 rc = 0;
343 }
344#endif /* SUPPORTED_PERSONALITIES >= 2 */
345
346#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000347 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000348 if (strcmp(s, sysent2[i].sys_name) == 0) {
349 qualify_one(i, opt, not, 2);
350 rc = 0;
351 }
352#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000353
Roland McGrathfe6b3522005-02-02 04:40:11 +0000354 return rc;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000355}
356
357static int
358qual_signal(s, opt, not)
359 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000360 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000361 int not;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000362{
363 int i;
364 char buf[32];
365
Roland McGrath48a035f2006-01-12 09:45:56 +0000366 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000367 int signo = atoi(s);
368 if (signo < 0 || signo >= MAX_QUALS)
369 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000370 qualify_one(signo, opt, not, -1);
Roland McGrathfe6b3522005-02-02 04:40:11 +0000371 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000372 }
Roland McGrathd62b6712004-03-02 06:52:01 +0000373 if (strlen(s) >= sizeof buf)
Roland McGrathfe6b3522005-02-02 04:40:11 +0000374 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375 strcpy(buf, s);
376 s = buf;
377 for (i = 0; s[i]; i++)
Wichert Akkerman2ee6e452000-02-18 15:36:12 +0000378 s[i] = toupper((unsigned char)(s[i]));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379 if (strncmp(s, "SIG", 3) == 0)
380 s += 3;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000381 for (i = 0; i <= NSIG; i++)
382 if (strcmp(s, signame(i) + 3) == 0) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000383 qualify_one(i, opt, not, -1);
Roland McGrath76421df2005-02-02 03:51:18 +0000384 return 0;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000385 }
Roland McGrath76421df2005-02-02 03:51:18 +0000386 return -1;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000387}
388
389static int
390qual_fault(s, opt, not)
391 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000392 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000393 int not;
394{
395 return -1;
396}
397
398static int
399qual_desc(s, opt, not)
400 char *s;
Roland McGrathe10e62a2004-09-04 04:20:43 +0000401 const struct qual_options *opt;
Roland McGrath9797ceb2002-12-30 10:23:00 +0000402 int not;
403{
Roland McGrath48a035f2006-01-12 09:45:56 +0000404 if (isdigit((unsigned char)*s)) {
Roland McGrathfe6b3522005-02-02 04:40:11 +0000405 int desc = atoi(s);
406 if (desc < 0 || desc >= MAX_QUALS)
407 return -1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000408 qualify_one(desc, opt, not, -1);
Roland McGrath2b619022003-04-10 18:58:20 +0000409 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 }
411 return -1;
412}
413
414static int
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415lookup_class(s)
Roland McGrath9797ceb2002-12-30 10:23:00 +0000416 char *s;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000417{
418 if (strcmp(s, "file") == 0)
419 return TRACE_FILE;
420 if (strcmp(s, "ipc") == 0)
421 return TRACE_IPC;
422 if (strcmp(s, "network") == 0)
423 return TRACE_NETWORK;
424 if (strcmp(s, "process") == 0)
425 return TRACE_PROCESS;
426 if (strcmp(s, "signal") == 0)
427 return TRACE_SIGNAL;
Roland McGrath2fe7b132005-07-05 03:25:35 +0000428 if (strcmp(s, "desc") == 0)
429 return TRACE_DESC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430 return -1;
431}
432
433void
434qualify(s)
435char *s;
436{
Roland McGrathe10e62a2004-09-04 04:20:43 +0000437 const struct qual_options *opt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 int not;
439 char *p;
440 int i, n;
441
442 opt = &qual_options[0];
443 for (i = 0; (p = qual_options[i].option_name); i++) {
444 n = strlen(p);
445 if (strncmp(s, p, n) == 0 && s[n] == '=') {
446 opt = &qual_options[i];
447 s += n + 1;
448 break;
449 }
450 }
451 not = 0;
452 if (*s == '!') {
453 not = 1;
454 s++;
455 }
456 if (strcmp(s, "none") == 0) {
457 not = 1 - not;
458 s = "all";
459 }
460 if (strcmp(s, "all") == 0) {
461 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000462 qualify_one(i, opt, not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463 }
464 return;
465 }
466 for (i = 0; i < MAX_QUALS; i++) {
Roland McGrath138c6a32006-01-12 09:50:49 +0000467 qualify_one(i, opt, !not, -1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000468 }
469 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
470 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000471 for (i = 0; i < nsyscalls0; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000472 if (sysent0[i].sys_flags & n)
473 qualify_one(i, opt, not, 0);
474
475#if SUPPORTED_PERSONALITIES >= 2
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000476 for (i = 0; i < nsyscalls1; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000477 if (sysent1[i].sys_flags & n)
478 qualify_one(i, opt, not, 1);
479#endif /* SUPPORTED_PERSONALITIES >= 2 */
480
481#if SUPPORTED_PERSONALITIES >= 3
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000482 for (i = 0; i < nsyscalls2; i++)
Roland McGrath138c6a32006-01-12 09:50:49 +0000483 if (sysent2[i].sys_flags & n)
484 qualify_one(i, opt, not, 2);
485#endif /* SUPPORTED_PERSONALITIES >= 3 */
Dmitry V. Levinc18c7032007-08-22 21:43:30 +0000486
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487 continue;
488 }
Roland McGrath9797ceb2002-12-30 10:23:00 +0000489 if (opt->qualify(p, opt, not)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 fprintf(stderr, "strace: invalid %s `%s'\n",
491 opt->argument_name, p);
492 exit(1);
493 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000494 }
495 return;
496}
497
498static void
499dumpio(tcp)
500struct tcb *tcp;
501{
502 if (syserror(tcp))
503 return;
504 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS)
505 return;
Roland McGrath17352792005-06-07 23:21:26 +0000506 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000507 case SYS_read:
Roland McGrathaa510622004-08-31 07:47:45 +0000508#ifdef SYS_pread64
509 case SYS_pread64:
510#endif
511#if defined SYS_pread && SYS_pread64 != SYS_pread
512 case SYS_pread:
513#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514#ifdef SYS_recv
515 case SYS_recv:
Roland McGrath17352792005-06-07 23:21:26 +0000516#elif defined SYS_sub_recv
517 case SYS_sub_recv:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000518#endif
519#ifdef SYS_recvfrom
520 case SYS_recvfrom:
Roland McGrath17352792005-06-07 23:21:26 +0000521#elif defined SYS_sub_recvfrom
522 case SYS_sub_recvfrom:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523#endif
524 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
525 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval);
526 break;
527 case SYS_write:
Roland McGrathaa510622004-08-31 07:47:45 +0000528#ifdef SYS_pwrite64
529 case SYS_pwrite64:
530#endif
531#if defined SYS_pwrite && SYS_pwrite64 != SYS_pwrite
532 case SYS_pwrite:
533#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534#ifdef SYS_send
535 case SYS_send:
Roland McGrath17352792005-06-07 23:21:26 +0000536#elif defined SYS_sub_send
537 case SYS_sub_send:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538#endif
539#ifdef SYS_sendto
540 case SYS_sendto:
Roland McGrath17352792005-06-07 23:21:26 +0000541#elif defined SYS_sub_sendto
542 case SYS_sub_sendto:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543#endif
544 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
545 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
546 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000547#ifdef SYS_readv
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000548 case SYS_readv:
549 if (qual_flags[tcp->u_arg[0]] & QUAL_READ)
550 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
551 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000552#endif
553#ifdef SYS_writev
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000554 case SYS_writev:
555 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
556 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
557 break;
John Hughes1d08dcf2001-07-10 13:48:44 +0000558#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000559 }
560}
561
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000562#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000563enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000564#else /* FREEBSD */
565enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
566
567struct subcall {
568 int call;
569 int nsubcalls;
570 int subcalls[5];
571};
572
Roland McGratha4d48532005-06-08 20:45:28 +0000573static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000574 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000575#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000576 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000577#else
578 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
579#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000580 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
581};
582#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583
Denys Vlasenko8ba1cd72008-12-30 17:50:46 +0000584#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) || defined(__ARM_EABI__) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585
Roland McGratha4d48532005-06-08 20:45:28 +0000586static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000587decode_subcall(tcp, subcall, nsubcalls, style)
588struct tcb *tcp;
589int subcall;
590int nsubcalls;
591enum subcall_style style;
592{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000593 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000594 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000595 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000596
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597 switch (style) {
598 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000599 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
600 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000601 tcp->scno = subcall + tcp->u_arg[0];
602 if (sysent[tcp->scno].nargs != -1)
603 tcp->u_nargs = sysent[tcp->scno].nargs;
604 else
605 tcp->u_nargs--;
606 for (i = 0; i < tcp->u_nargs; i++)
607 tcp->u_arg[i] = tcp->u_arg[i + 1];
608 break;
609 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000610 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
611 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 tcp->scno = subcall + tcp->u_arg[0];
613 addr = tcp->u_arg[1];
614 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000615 if (size == sizeof(int)) {
616 unsigned int arg;
617 if (umove(tcp, addr, &arg) < 0)
618 arg = 0;
619 tcp->u_arg[i] = arg;
620 }
621 else if (size == sizeof(long)) {
622 unsigned long arg;
623 if (umove(tcp, addr, &arg) < 0)
624 arg = 0;
625 tcp->u_arg[i] = arg;
626 }
627 else
628 abort();
629 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 }
631 tcp->u_nargs = sysent[tcp->scno].nargs;
632 break;
633 case mask_style:
634 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000635 for (i = 0; mask; i++)
636 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000637 if (i >= nsubcalls)
638 return;
639 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640 tcp->scno = subcall + i;
641 if (sysent[tcp->scno].nargs != -1)
642 tcp->u_nargs = sysent[tcp->scno].nargs;
643 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000644 case door_style:
645 /*
646 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000647 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000648 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000649 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
650 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000651 tcp->scno = subcall + tcp->u_arg[5];
652 if (sysent[tcp->scno].nargs != -1)
653 tcp->u_nargs = sysent[tcp->scno].nargs;
654 else
655 tcp->u_nargs--;
656 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000657#ifdef FREEBSD
658 case table_style:
659 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
660 if (subcalls_table[i].call == tcp->scno) break;
661 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
662 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
663 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
664 for (i = 0; i < tcp->u_nargs; i++)
665 tcp->u_arg[i] = tcp->u_arg[i + 1];
666 }
667 break;
668#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000669 }
670}
671#endif
672
673struct tcb *tcp_last = NULL;
674
675static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000676internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000677{
678 /*
679 * We must always trace a few critical system calls in order to
680 * correctly support following forks in the presence of tracing
681 * qualifiers.
682 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000683 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000685 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
686 return 0;
687
688 func = sysent[tcp->scno].sys_func;
689
690 if (sys_exit == func)
691 return internal_exit(tcp);
692
693 if ( sys_fork == func
694#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
695 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000696#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000697#if UNIXWARE > 2
698 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000699#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000700 )
701 return internal_fork(tcp);
702
703#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
704 if (sys_clone == func)
705 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000706#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000707
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000708 if ( sys_execve == func
709#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
710 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000712#if UNIXWARE > 2
713 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000714#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000715 )
716 return internal_exec(tcp);
717
718 if ( sys_waitpid == func
719 || sys_wait4 == func
720#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
721 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000722#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000723#ifdef ALPHA
724 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000725#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000726 )
727 return internal_wait(tcp, 2);
728
729#if defined(LINUX) || defined(SVR4)
730 if (sys_waitid == func)
731 return internal_wait(tcp, 3);
732#endif
733
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000734 return 0;
735}
736
Wichert Akkermanc7926982000-04-10 22:22:31 +0000737
738#ifdef LINUX
739#if defined (I386)
740 static long eax;
741#elif defined (IA64)
742 long r8, r10, psr;
743 long ia32 = 0;
744#elif defined (POWERPC)
745 static long result,flags;
746#elif defined (M68K)
747 static int d0;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000748#elif defined(BFIN)
749 static long r0;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000750#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000751 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000752#elif defined (ALPHA)
753 static long r0;
754 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000755#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000756 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000757 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000758#elif defined(LINUX_MIPSN32)
759 static long long a3;
760 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000761#elif defined(MIPS)
762 static long a3;
763 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000764#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000765 static long gpr2;
766 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000767 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000768#elif defined(HPPA)
769 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000770#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000771 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000772#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000773 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000774#elif defined(X86_64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000775 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000776#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000777#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000778#ifdef FREEBSD
779 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000780#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000781
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782int
Denys Vlasenkofb036672009-01-23 16:30:26 +0000783get_scno(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000784{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785 long scno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000788#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000789 if (tcp->flags & TCB_WAITEXECVE) {
790 /*
791 * When the execve system call completes successfully, the
792 * new process still has -ENOSYS (old style) or __NR_execve
793 * (new style) in gpr2. We cannot recover the scno again
794 * by disassembly, because the image that executed the
795 * syscall is gone now. Fortunately, we don't want it. We
796 * leave the flag set so that syscall_fixup can fake the
797 * result.
798 */
799 if (tcp->flags & TCB_INSYSCALL)
800 return 1;
801 /*
802 * This is the SIGTRAP after execve. We cannot try to read
803 * the system call here either.
804 */
805 tcp->flags &= ~TCB_WAITEXECVE;
806 return 0;
807 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000808
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000809 if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
Roland McGrath2f924ca2003-06-26 22:23:28 +0000810 return -1;
811
812 if (syscall_mode != -ENOSYS) {
813 /*
814 * Since kernel version 2.5.44 the scno gets passed in gpr2.
815 */
816 scno = syscall_mode;
817 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000818 /*
819 * Old style of "passing" the scno via the SVC instruction.
820 */
821
822 long opcode, offset_reg, tmp;
823 void * svc_addr;
824 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
825 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
826 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
827 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000828
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000829 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig882eda82002-11-11 12:50:47 +0000830 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000831 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000832 opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000833 if (errno) {
834 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000835 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000836 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000837
838 /*
839 * We have to check if the SVC got executed directly or via an
840 * EXECUTE instruction. In case of EXECUTE it is necessary to do
841 * instruction decoding to derive the system call number.
842 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
843 * so that this doesn't work if a SVC opcode is part of an EXECUTE
844 * opcode. Since there is no way to find out the opcode size this
845 * is the best we can do...
846 */
847
848 if ((opcode & 0xff00) == 0x0a00) {
849 /* SVC opcode */
850 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000851 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000852 else {
853 /* SVC got executed by EXECUTE instruction */
854
855 /*
856 * Do instruction decoding of EXECUTE. If you really want to
857 * understand this, read the Principles of Operations.
858 */
859 svc_addr = (void *) (opcode & 0xfff);
860
861 tmp = 0;
862 offset_reg = (opcode & 0x000f0000) >> 16;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000863 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000864 return -1;
865 svc_addr += tmp;
866
867 tmp = 0;
868 offset_reg = (opcode & 0x0000f000) >> 12;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000869 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000870 return -1;
871 svc_addr += tmp;
872
Denys Vlasenkofb036672009-01-23 16:30:26 +0000873 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
Michal Ludvig882eda82002-11-11 12:50:47 +0000874 if (errno)
875 return -1;
876#if defined(S390X)
877 scno >>= 48;
878#else
879 scno >>= 16;
880#endif
881 tmp = 0;
882 offset_reg = (opcode & 0x00f00000) >> 20;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000883 if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
Michal Ludvig882eda82002-11-11 12:50:47 +0000884 return -1;
885
886 scno = (scno | tmp) & 0xff;
887 }
888 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000889#elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000890 if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000891 return -1;
892 if (!(tcp->flags & TCB_INSYSCALL)) {
893 /* Check if we return from execve. */
894 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
895 tcp->flags &= ~TCB_WAITEXECVE;
896 return 0;
897 }
898 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000899#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000900 if (upeek(tcp, PT_ORIG_P0, &scno))
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +0000901 return -1;
902 /* Check if we return from execve. */
903 if (tcp->flags & TCB_WAITEXECVE && tcp->flags & TCB_INSYSCALL)
904 tcp->flags &= ~(TCB_INSYSCALL | TCB_WAITEXECVE);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000905#elif defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000906 if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000907 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000908#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000909 if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000910 return -1;
911
Roland McGrath761b5d72002-12-15 23:58:31 +0000912 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko8236f252009-01-02 18:10:08 +0000913 static int currpers = -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000914 long val;
Denys Vlasenkofb036672009-01-23 16:30:26 +0000915 int pid = tcp->pid;
Michal Ludvig0e035502002-09-23 15:41:01 +0000916
917 /* Check CS register value. On x86-64 linux it is:
918 * 0x33 for long mode (64 bit)
919 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000920 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000921 * to be cached.
922 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000923 if (upeek(tcp, 8*CS, &val) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000924 return -1;
Denys Vlasenko8236f252009-01-02 18:10:08 +0000925 switch (val) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000926 case 0x23: currpers = 1; break;
927 case 0x33: currpers = 0; break;
928 default:
929 fprintf(stderr, "Unknown value CS=0x%02X while "
930 "detecting personality of process "
931 "PID=%d\n", (int)val, pid);
932 currpers = current_personality;
933 break;
934 }
935#if 0
936 /* This version analyzes the opcode of a syscall instruction.
937 * (int 0x80 on i386 vs. syscall on x86-64)
938 * It works, but is too complicated.
939 */
940 unsigned long val, rip, i;
941
Denys Vlasenko8236f252009-01-02 18:10:08 +0000942 if (upeek(tcp, 8*RIP, &rip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +0000943 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000944
Michal Ludvig0e035502002-09-23 15:41:01 +0000945 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
Denys Vlasenko8236f252009-01-02 18:10:08 +0000946 rip -= 2;
Michal Ludvig0e035502002-09-23 15:41:01 +0000947 errno = 0;
948
Denys Vlasenko8236f252009-01-02 18:10:08 +0000949 call = ptrace(PTRACE_PEEKTEXT, pid, (char *)rip, (char *)0);
Roland McGrath761b5d72002-12-15 23:58:31 +0000950 if (errno)
951 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000952 strerror(errno));
Denys Vlasenko8236f252009-01-02 18:10:08 +0000953 switch (call & 0xffff) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000954 /* x86-64: syscall = 0x0f 0x05 */
955 case 0x050f: currpers = 0; break;
956 /* i386: int 0x80 = 0xcd 0x80 */
957 case 0x80cd: currpers = 1; break;
958 default:
959 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000960 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000961 "Unknown syscall opcode (0x%04X) while "
962 "detecting personality of process "
963 "PID=%d\n", (int)call, pid);
964 break;
965 }
966#endif
Denys Vlasenko8236f252009-01-02 18:10:08 +0000967 if (currpers != current_personality) {
968 static const char *const names[] = {"64 bit", "32 bit"};
Michal Ludvig0e035502002-09-23 15:41:01 +0000969 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000970 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000971 pid, names[current_personality]);
972 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000973 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000974#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000975# define IA64_PSR_IS ((long)1 << 34)
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000976 if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000977 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000978 if (!(tcp->flags & TCB_INSYSCALL)) {
979 if (ia32) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000980 if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000981 return -1;
982 } else {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000983 if (upeek(tcp, PT_R15, &scno) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000984 return -1;
985 }
Roland McGrathba954762003-03-05 06:29:06 +0000986 /* Check if we return from execve. */
987 if (tcp->flags & TCB_WAITEXECVE) {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +0000988#if defined PTRACE_GETSIGINFO
989 siginfo_t si;
990
991 tcp->flags &= ~TCB_WAITEXECVE;
992 /* If SIGTRAP is masked, execve's magic SIGTRAP
993 * is not delivered. We end up here on a subsequent
994 * ptrace stop instead. Luckily, we can check
995 * for the type of this SIGTRAP. execve's magic one
996 * has 0 (SI_USER) in si.si_code, ptrace stop has 5.
997 * (I don't know why 5).
998 */
999 si.si_code = SI_USER;
1000 /* If PTRACE_GETSIGINFO fails, we assume it's
1001 * magic SIGTRAP. Moot anyway, PTRACE_GETSIGINFO
1002 * doesn't fail.
1003 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001004 ptrace(PTRACE_GETSIGINFO, tcp->pid, (void*) 0, (void*) &si);
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001005 if (si.si_code == SI_USER)
1006 return 0;
1007#else
Roland McGrathba954762003-03-05 06:29:06 +00001008 tcp->flags &= ~TCB_WAITEXECVE;
1009 return 0;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001010#endif
Roland McGrathba954762003-03-05 06:29:06 +00001011 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001012 } else {
1013 /* syscall in progress */
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001014 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001015 return -1;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00001016 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001017 return -1;
1018 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001020 /*
1021 * Read complete register set in one go.
1022 */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001023 if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
Roland McGrath0f87c492003-06-03 23:29:04 +00001024 return -1;
1025
1026 /*
1027 * We only need to grab the syscall number on syscall entry.
1028 */
1029 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001030 if (!(tcp->flags & TCB_INSYSCALL)) {
1031 /* Check if we return from execve. */
1032 if (tcp->flags & TCB_WAITEXECVE) {
1033 tcp->flags &= ~TCB_WAITEXECVE;
1034 return 0;
1035 }
1036 }
1037
Roland McGrath0f87c492003-06-03 23:29:04 +00001038 /*
1039 * Note: we only deal with only 32-bit CPUs here.
1040 */
1041 if (regs.ARM_cpsr & 0x20) {
1042 /*
1043 * Get the Thumb-mode system call number
1044 */
1045 scno = regs.ARM_r7;
1046 } else {
1047 /*
1048 * Get the ARM-mode system call number
1049 */
1050 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001051 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
Roland McGrath0f87c492003-06-03 23:29:04 +00001052 if (errno)
1053 return -1;
1054
1055 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1056 tcp->flags &= ~TCB_WAITEXECVE;
1057 return 0;
1058 }
1059
Roland McGrathf691bd22006-04-25 07:34:41 +00001060 /* Handle the EABI syscall convention. We do not
1061 bother converting structures between the two
1062 ABIs, but basic functionality should work even
1063 if strace and the traced program have different
1064 ABIs. */
1065 if (scno == 0xef000000) {
1066 scno = regs.ARM_r7;
1067 } else {
1068 if ((scno & 0x0ff00000) != 0x0f900000) {
1069 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1070 scno);
1071 return -1;
1072 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001073
Roland McGrathf691bd22006-04-25 07:34:41 +00001074 /*
1075 * Fixup the syscall number
1076 */
1077 scno &= 0x000fffff;
1078 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001079 }
Roland McGrath56703312008-05-20 01:35:55 +00001080 if (scno & 0x0f0000) {
1081 /*
1082 * Handle ARM specific syscall
1083 */
1084 set_personality(1);
1085 scno &= 0x0000ffff;
1086 } else
1087 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001088
1089 if (tcp->flags & TCB_INSYSCALL) {
1090 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1091 tcp->flags &= ~TCB_INSYSCALL;
1092 }
1093 } else {
1094 if (!(tcp->flags & TCB_INSYSCALL)) {
1095 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1096 tcp->flags |= TCB_INSYSCALL;
1097 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 }
1099#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001100 if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101 return -1;
Roland McGrath542c2c62008-05-20 01:11:56 +00001102#elif defined (LINUX_MIPSN32)
1103 unsigned long long regs[38];
1104
Denys Vlasenkofb036672009-01-23 16:30:26 +00001105 if (ptrace (PTRACE_GETREGS, tcp->pid, NULL, (long) &regs) < 0)
Roland McGrath542c2c62008-05-20 01:11:56 +00001106 return -1;
1107 a3 = regs[REG_A3];
1108 r2 = regs[REG_V0];
1109
1110 if(!(tcp->flags & TCB_INSYSCALL)) {
1111 scno = r2;
1112
1113 /* Check if we return from execve. */
1114 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1115 tcp->flags &= ~TCB_WAITEXECVE;
1116 return 0;
1117 }
1118
1119 if (scno < 0 || scno > nsyscalls) {
1120 if(a3 == 0 || a3 == -1) {
1121 if(debug)
1122 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1123 return 0;
1124 }
1125 }
1126 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001127#elif defined (MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001128 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001129 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001130 if(!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001131 if (upeek(tcp, REG_V0, &scno) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001132 return -1;
1133
Roland McGrath542c2c62008-05-20 01:11:56 +00001134 /* Check if we return from execve. */
1135 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1136 tcp->flags &= ~TCB_WAITEXECVE;
1137 return 0;
1138 }
1139
Wichert Akkermanf90da011999-10-31 21:15:38 +00001140 if (scno < 0 || scno > nsyscalls) {
1141 if(a3 == 0 || a3 == -1) {
1142 if(debug)
1143 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1144 return 0;
1145 }
1146 }
1147 } else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001148 if (upeek(tcp, REG_V0, &r2) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001149 return -1;
1150 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151#elif defined (ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001152 if (upeek(tcp, REG_A3, &a3) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153 return -1;
1154
1155 if (!(tcp->flags & TCB_INSYSCALL)) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001156 if (upeek(tcp, REG_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157 return -1;
1158
1159 /* Check if we return from execve. */
1160 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1161 tcp->flags &= ~TCB_WAITEXECVE;
1162 return 0;
1163 }
1164
1165 /*
1166 * Do some sanity checks to figure out if it's
1167 * really a syscall entry
1168 */
1169 if (scno < 0 || scno > nsyscalls) {
1170 if (a3 == 0 || a3 == -1) {
1171 if (debug)
1172 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1173 return 0;
1174 }
1175 }
1176 }
1177 else {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001178 if (upeek(tcp, REG_R0, &r0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 return -1;
1180 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001181#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182 /* Everything we need is in the current register set. */
Denys Vlasenkofb036672009-01-23 16:30:26 +00001183 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184 return -1;
1185
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001186 /* If we are entering, then disassemble the syscall trap. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001187 if (!(tcp->flags & TCB_INSYSCALL)) {
1188 /* Retrieve the syscall trap instruction. */
1189 errno = 0;
Denys Vlasenkofb036672009-01-23 16:30:26 +00001190 trap = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)regs.r_pc, 0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001191#if defined(SPARC64)
1192 trap >>= 32;
1193#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001194 if (errno)
1195 return -1;
1196
1197 /* Disassemble the trap to see what personality to use. */
1198 switch (trap) {
1199 case 0x91d02010:
1200 /* Linux/SPARC syscall trap. */
1201 set_personality(0);
1202 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001203 case 0x91d0206d:
1204 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001205 set_personality(2);
1206 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001207 case 0x91d02000:
1208 /* SunOS syscall trap. (pers 1) */
1209 fprintf(stderr,"syscall: SunOS no support\n");
1210 return -1;
1211 case 0x91d02008:
1212 /* Solaris 2.x syscall trap. (per 2) */
1213 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001214 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001215 case 0x91d02009:
1216 /* NetBSD/FreeBSD syscall trap. */
1217 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1218 return -1;
1219 case 0x91d02027:
1220 /* Solaris 2.x gettimeofday */
1221 set_personality(1);
1222 break;
1223 default:
1224 /* Unknown syscall trap. */
1225 if(tcp->flags & TCB_WAITEXECVE) {
1226 tcp->flags &= ~TCB_WAITEXECVE;
1227 return 0;
1228 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001229#if defined (SPARC64)
1230 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1231#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001232 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001233#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001234 return -1;
1235 }
1236
1237 /* Extract the system call number from the registers. */
1238 if (trap == 0x91d02027)
1239 scno = 156;
1240 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001241 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001242 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001243 scno = regs.r_o0;
1244 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245 }
1246 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001247#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001248 if (upeek(tcp, PT_GR20, &scno) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001249 return -1;
1250 if (!(tcp->flags & TCB_INSYSCALL)) {
1251 /* Check if we return from execve. */
1252 if ((tcp->flags & TCB_WAITEXECVE)) {
1253 tcp->flags &= ~TCB_WAITEXECVE;
1254 return 0;
1255 }
1256 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001257#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001258 /*
1259 * In the new syscall ABI, the system call number is in R3.
1260 */
1261 if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
1262 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001263
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001264 if (scno < 0) {
1265 /* Odd as it may seem, a glibc bug has been known to cause
1266 glibc to issue bogus negative syscall numbers. So for
1267 our purposes, make strace print what it *should* have been */
1268 long correct_scno = (scno & 0xff);
1269 if (debug)
1270 fprintf(stderr,
1271 "Detected glibc bug: bogus system call"
1272 " number = %ld, correcting to %ld\n",
1273 scno,
1274 correct_scno);
1275 scno = correct_scno;
1276 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001277
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001278 if (!(tcp->flags & TCB_INSYSCALL)) {
1279 /* Check if we return from execve. */
1280 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1281 tcp->flags &= ~TCB_WAITEXECVE;
1282 return 0;
1283 }
1284 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001285#elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001286 if (upeek(tcp, REG_SYSCALL, &scno) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001287 return -1;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001288 scno &= 0xFFFF;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001289
1290 if (!(tcp->flags & TCB_INSYSCALL)) {
1291 /* Check if we return from execve. */
1292 if (tcp->flags & TCB_WAITEXECVE) {
1293 tcp->flags &= ~TCB_WAITEXECVE;
1294 return 0;
1295 }
1296 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001297#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001298#endif /* LINUX */
1299#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001300 if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001301 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001302#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001303 /* new syscall ABI returns result in R0 */
1304 if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
1305 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001306#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001307 /* ABI defines result returned in r9 */
1308 if (upeek(tcp, REG_GENERAL(9), (long *)&r9) < 0)
1309 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001310
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001311#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001312#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001314 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001315#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001316#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001317 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001318#else /* FREEBSD */
1319 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001320 perror("pread");
1321 return -1;
1322 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001323 switch (regs.r_eax) {
1324 case SYS_syscall:
1325 case SYS___syscall:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001326 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1327 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001328 default:
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001329 scno = regs.r_eax;
1330 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001331 }
1332#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001334#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001335 if (!(tcp->flags & TCB_INSYSCALL))
1336 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001337 return 1;
1338}
1339
Pavel Machek4dc3b142000-02-01 17:58:41 +00001340
Roland McGrath17352792005-06-07 23:21:26 +00001341long
1342known_scno(tcp)
1343struct tcb *tcp;
1344{
1345 long scno = tcp->scno;
1346 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1347 scno = sysent[scno].native_scno;
1348 else
1349 scno += NR_SYSCALL_BASE;
1350 return scno;
1351}
1352
Denys Vlasenkobc161ec2009-01-02 18:02:45 +00001353/* Called in trace_syscall() at each syscall entry and exit.
1354 * Returns:
1355 * 0: "ignore this syscall", bail out of trace_syscall() silently.
1356 * 1: ok, continue in trace_syscall().
1357 * other: error, trace_syscall() should print error indicator
1358 * ("????" etc) and bail out.
1359 */
Roland McGratha4d48532005-06-08 20:45:28 +00001360static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001361syscall_fixup(tcp)
1362struct tcb *tcp;
1363{
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001364#ifdef USE_PROCFS
Roland McGrath17352792005-06-07 23:21:26 +00001365 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001366
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001368 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 if (
1370 scno == SYS_fork
1371#ifdef SYS_vfork
1372 || scno == SYS_vfork
1373#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001374#ifdef SYS_fork1
1375 || scno == SYS_fork1
1376#endif /* SYS_fork1 */
1377#ifdef SYS_forkall
1378 || scno == SYS_forkall
1379#endif /* SYS_forkall */
1380#ifdef SYS_rfork1
1381 || scno == SYS_rfork1
1382#endif /* SYS_fork1 */
1383#ifdef SYS_rforkall
1384 || scno == SYS_rforkall
1385#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001386 ) {
1387 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001388 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001389 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001390 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391 }
1392 else {
1393 fprintf(stderr, "syscall: missing entry\n");
1394 tcp->flags |= TCB_INSYSCALL;
1395 }
1396 }
1397 }
1398 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001399 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001400 fprintf(stderr, "syscall: missing exit\n");
1401 tcp->flags &= ~TCB_INSYSCALL;
1402 }
1403 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001404#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001405#ifdef SUNOS4
1406 if (!(tcp->flags & TCB_INSYSCALL)) {
1407 if (scno == 0) {
1408 fprintf(stderr, "syscall: missing entry\n");
1409 tcp->flags |= TCB_INSYSCALL;
1410 }
1411 }
1412 else {
1413 if (scno != 0) {
1414 if (debug) {
1415 /*
1416 * This happens when a signal handler
1417 * for a signal which interrupted a
1418 * a system call makes another system call.
1419 */
1420 fprintf(stderr, "syscall: missing exit\n");
1421 }
1422 tcp->flags &= ~TCB_INSYSCALL;
1423 }
1424 }
1425#endif /* SUNOS4 */
1426#ifdef LINUX
1427#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001428 if (upeek(tcp, 4*EAX, &eax) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001429 return -1;
1430 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1431 if (debug)
1432 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1433 return 0;
1434 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001435#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001436 if (upeek(tcp, 8*RAX, &rax) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001437 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001438 if (current_personality == 1)
1439 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001440 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1441 if (debug)
1442 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1443 return 0;
1444 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001445#elif defined (S390) || defined (S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001446 if (upeek(tcp, PT_GPR2, &gpr2) < 0)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001447 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001448 if (syscall_mode != -ENOSYS)
1449 syscall_mode = tcp->scno;
1450 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001451 if (debug)
1452 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1453 return 0;
1454 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001455 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1456 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1457 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1458 /*
1459 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1460 * flag set for the post-execve SIGTRAP to see and reset.
1461 */
1462 gpr2 = 0;
1463 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001464#elif defined (POWERPC)
1465# define SO_MASK 0x10000000
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001466 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001467 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001468 if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001469 return -1;
1470 if (flags & SO_MASK)
1471 result = -result;
1472#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001473 if (upeek(tcp, 4*PT_D0, &d0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001474 return -1;
1475 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1476 if (debug)
1477 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1478 return 0;
1479 }
1480#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001481 /*
1482 * Nothing required
1483 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001484#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001485 if (upeek(tcp, PT_R0, &r0) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001486 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001487#elif defined (HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001488 if (upeek(tcp, PT_GR28, &r28) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001489 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001490#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001491 if (upeek(tcp, PT_R10, &r10) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001492 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001493 if (upeek(tcp, PT_R8, &r8) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001494 return -1;
1495 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1496 if (debug)
1497 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1498 return 0;
1499 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001500#endif
1501#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001502 return 1;
1503}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001504
Roland McGrathc1e45922008-05-27 23:18:29 +00001505#ifdef LINUX
1506/*
1507 * Check the syscall return value register value for whether it is
1508 * a negated errno code indicating an error, or a success return value.
1509 */
1510static inline int
1511is_negated_errno(unsigned long int val)
1512{
1513 unsigned long int max = -(long int) nerrnos;
1514 if (personality_wordsize[current_personality] < sizeof(val)) {
1515 val = (unsigned int) val;
1516 max = (unsigned int) max;
1517 }
1518 return val > max;
1519}
1520#endif
1521
Roland McGratha4d48532005-06-08 20:45:28 +00001522static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001523get_error(tcp)
1524struct tcb *tcp;
1525{
1526 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001527#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001528#if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001529 if (is_negated_errno(gpr2)) {
1530 tcp->u_rval = -1;
1531 u_error = -gpr2;
1532 }
1533 else {
1534 tcp->u_rval = gpr2;
1535 u_error = 0;
1536 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001537#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001538#ifdef I386
Roland McGrathc1e45922008-05-27 23:18:29 +00001539 if (is_negated_errno(eax)) {
1540 tcp->u_rval = -1;
1541 u_error = -eax;
1542 }
1543 else {
1544 tcp->u_rval = eax;
1545 u_error = 0;
1546 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001548#ifdef X86_64
Roland McGrathc1e45922008-05-27 23:18:29 +00001549 if (is_negated_errno(rax)) {
1550 tcp->u_rval = -1;
1551 u_error = -rax;
1552 }
1553 else {
1554 tcp->u_rval = rax;
1555 u_error = 0;
1556 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001557#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001558#ifdef IA64
Roland McGrathc1e45922008-05-27 23:18:29 +00001559 if (ia32) {
1560 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001561
Roland McGrathc1e45922008-05-27 23:18:29 +00001562 err = (int)r8;
1563 if (is_negated_errno(err)) {
1564 tcp->u_rval = -1;
1565 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001566 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001567 else {
1568 tcp->u_rval = err;
1569 u_error = 0;
1570 }
1571 } else {
1572 if (r10) {
1573 tcp->u_rval = -1;
1574 u_error = r8;
1575 } else {
1576 tcp->u_rval = r8;
1577 u_error = 0;
1578 }
1579 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001580#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001581#ifdef MIPS
1582 if (a3) {
1583 tcp->u_rval = -1;
1584 u_error = r2;
1585 } else {
1586 tcp->u_rval = r2;
1587 u_error = 0;
1588 }
1589#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590#ifdef POWERPC
Roland McGrathc1e45922008-05-27 23:18:29 +00001591 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592 tcp->u_rval = -1;
1593 u_error = -result;
1594 }
1595 else {
1596 tcp->u_rval = result;
1597 u_error = 0;
1598 }
1599#else /* !POWERPC */
1600#ifdef M68K
Roland McGrathc1e45922008-05-27 23:18:29 +00001601 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602 tcp->u_rval = -1;
1603 u_error = -d0;
1604 }
1605 else {
1606 tcp->u_rval = d0;
1607 u_error = 0;
1608 }
1609#else /* !M68K */
1610#ifdef ARM
Roland McGrathc1e45922008-05-27 23:18:29 +00001611 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001612 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001613 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614 }
1615 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001616 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617 u_error = 0;
1618 }
1619#else /* !ARM */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001620#ifdef BFIN
1621 if (is_negated_errno(r0)) {
1622 tcp->u_rval = -1;
1623 u_error = -r0;
1624 } else {
1625 tcp->u_rval = r0;
1626 u_error = 0;
1627 }
1628#else /* !BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629#ifdef ALPHA
1630 if (a3) {
1631 tcp->u_rval = -1;
1632 u_error = r0;
1633 }
1634 else {
1635 tcp->u_rval = r0;
1636 u_error = 0;
1637 }
1638#else /* !ALPHA */
1639#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001640 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001642 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643 }
1644 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001645 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646 u_error = 0;
1647 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001648#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001649#ifdef SPARC64
1650 if (regs.r_tstate & 0x1100000000UL) {
1651 tcp->u_rval = -1;
1652 u_error = regs.r_o0;
1653 }
1654 else {
1655 tcp->u_rval = regs.r_o0;
1656 u_error = 0;
1657 }
1658#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001659#ifdef HPPA
Roland McGrathc1e45922008-05-27 23:18:29 +00001660 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001661 tcp->u_rval = -1;
1662 u_error = -r28;
1663 }
1664 else {
1665 tcp->u_rval = r28;
1666 u_error = 0;
1667 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001668#else
1669#ifdef SH
Roland McGrathc1e45922008-05-27 23:18:29 +00001670 /* interpret R0 as return value or error number */
1671 if (is_negated_errno(r0)) {
1672 tcp->u_rval = -1;
1673 u_error = -r0;
1674 }
1675 else {
1676 tcp->u_rval = r0;
1677 u_error = 0;
1678 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001679#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001680#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001681 /* interpret result as return value or error number */
1682 if (is_negated_errno(r9)) {
1683 tcp->u_rval = -1;
1684 u_error = -r9;
1685 }
1686 else {
1687 tcp->u_rval = r9;
1688 u_error = 0;
1689 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001690#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001691#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001692#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001693#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001694#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001695#endif /* ALPHA */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001696#endif /* BFIN */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001697#endif /* ARM */
1698#endif /* M68K */
1699#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001700#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001701#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001702#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001703#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001704#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001705#endif /* LINUX */
1706#ifdef SUNOS4
1707 /* get error code from user struct */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001708 if (upeek(tcp, uoff(u_error), &u_error) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709 return -1;
1710 u_error >>= 24; /* u_error is a char */
1711
1712 /* get system call return value */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001713 if (upeek(tcp, uoff(u_rval1), &tcp->u_rval) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714 return -1;
1715#endif /* SUNOS4 */
1716#ifdef SVR4
1717#ifdef SPARC
1718 /* Judicious guessing goes a long way. */
1719 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1720 tcp->u_rval = -1;
1721 u_error = tcp->status.pr_reg[R_O0];
1722 }
1723 else {
1724 tcp->u_rval = tcp->status.pr_reg[R_O0];
1725 u_error = 0;
1726 }
1727#endif /* SPARC */
1728#ifdef I386
1729 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001730 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001732 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733 }
1734 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001735 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001736#ifdef HAVE_LONG_LONG
1737 tcp->u_lrval =
1738 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1739 tcp->status.PR_REG[EAX];
1740#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001741 u_error = 0;
1742 }
1743#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001744#ifdef X86_64
1745 /* Wanna know how to kill an hour single-stepping? */
1746 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1747 tcp->u_rval = -1;
1748 u_error = tcp->status.PR_REG[RAX];
1749 }
1750 else {
1751 tcp->u_rval = tcp->status.PR_REG[RAX];
1752 u_error = 0;
1753 }
1754#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755#ifdef MIPS
1756 if (tcp->status.pr_reg[CTX_A3]) {
1757 tcp->u_rval = -1;
1758 u_error = tcp->status.pr_reg[CTX_V0];
1759 }
1760 else {
1761 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1762 u_error = 0;
1763 }
1764#endif /* MIPS */
1765#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001766#ifdef FREEBSD
1767 if (regs.r_eflags & PSL_C) {
1768 tcp->u_rval = -1;
1769 u_error = regs.r_eax;
1770 } else {
1771 tcp->u_rval = regs.r_eax;
1772 tcp->u_lrval =
1773 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1774 u_error = 0;
1775 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001776#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001777 tcp->u_error = u_error;
1778 return 1;
1779}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780
Roland McGrathb69f81b2002-12-21 23:25:18 +00001781int
1782force_result(tcp, error, rval)
1783 struct tcb *tcp;
1784 int error;
1785 long rval;
1786{
1787#ifdef LINUX
1788#if defined(S390) || defined(S390X)
1789 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001790 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1791 return -1;
1792#else /* !S390 && !S390X */
1793#ifdef I386
1794 eax = error ? -error : rval;
1795 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1796 return -1;
1797#else /* !I386 */
1798#ifdef X86_64
1799 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001800 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001801 return -1;
1802#else
1803#ifdef IA64
1804 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 }
1822#else /* !IA64 */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001823#ifdef BFIN
1824 r0 = error ? -error : rval;
1825 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_R0, r0) < 0)
1826 return -1;
1827#else /* !BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001828#ifdef MIPS
1829 if (error) {
1830 r2 = error;
1831 a3 = -1;
1832 }
1833 else {
1834 r2 = rval;
1835 a3 = 0;
1836 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001837 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001838 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1839 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1840 return -1;
1841#else
1842#ifdef POWERPC
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001843 if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001844 return -1;
1845 if (error) {
1846 flags |= SO_MASK;
1847 result = error;
1848 }
1849 else {
1850 flags &= ~SO_MASK;
1851 result = rval;
1852 }
Roland McGratheb285352003-01-14 09:59:00 +00001853 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1854 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001855 return -1;
1856#else /* !POWERPC */
1857#ifdef M68K
1858 d0 = error ? -error : rval;
1859 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1860 return -1;
1861#else /* !M68K */
1862#ifdef ARM
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001863 regs.ARM_r0 = error ? -error : rval;
1864 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001865 return -1;
1866#else /* !ARM */
1867#ifdef ALPHA
1868 if (error) {
1869 a3 = -1;
1870 r0 = error;
1871 }
1872 else {
1873 a3 = 0;
1874 r0 = rval;
1875 }
1876 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1877 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1878 return -1;
1879#else /* !ALPHA */
1880#ifdef SPARC
1881 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1882 return -1;
1883 if (error) {
1884 regs.r_psr |= PSR_C;
1885 regs.r_o0 = error;
1886 }
1887 else {
1888 regs.r_psr &= ~PSR_C;
1889 regs.r_o0 = rval;
1890 }
1891 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1892 return -1;
1893#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001894#ifdef SPARC64
1895 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1896 return -1;
1897 if (error) {
1898 regs.r_tstate |= 0x1100000000UL;
1899 regs.r_o0 = error;
1900 }
1901 else {
1902 regs.r_tstate &= ~0x1100000000UL;
1903 regs.r_o0 = rval;
1904 }
1905 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1906 return -1;
1907#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001908#ifdef HPPA
1909 r28 = error ? -error : rval;
1910 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1911 return -1;
1912#else
1913#ifdef SH
1914 r0 = error ? -error : rval;
1915 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1916 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001917#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001918#ifdef SH64
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001919 r9 = error ? -error : rval;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001920 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1921 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001922#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001923#endif /* SH */
1924#endif /* HPPA */
1925#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001926#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001927#endif /* ALPHA */
1928#endif /* ARM */
1929#endif /* M68K */
1930#endif /* POWERPC */
1931#endif /* MIPS */
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001932#endif /* BFIN */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001933#endif /* IA64 */
1934#endif /* X86_64 */
1935#endif /* I386 */
1936#endif /* S390 || S390X */
1937#endif /* LINUX */
1938#ifdef SUNOS4
1939 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1940 error << 24) < 0 ||
1941 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1942 return -1;
1943#endif /* SUNOS4 */
1944#ifdef SVR4
1945 /* XXX no clue */
1946 return -1;
1947#endif /* SVR4 */
1948#ifdef FREEBSD
1949 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001950 perror("pread");
1951 return -1;
1952 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001953 if (error) {
1954 regs.r_eflags |= PSL_C;
1955 regs.r_eax = error;
1956 }
1957 else {
1958 regs.r_eflags &= ~PSL_C;
1959 regs.r_eax = rval;
1960 }
1961 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001962 perror("pwrite");
1963 return -1;
1964 }
Roland McGrathb69f81b2002-12-21 23:25:18 +00001965#endif /* FREEBSD */
1966
1967 /* All branches reach here on success (only). */
1968 tcp->u_error = error;
1969 tcp->u_rval = rval;
1970 return 0;
1971}
1972
Roland McGratha4d48532005-06-08 20:45:28 +00001973static int
1974syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001975struct tcb *tcp;
1976{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001977#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001978#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001979 {
1980 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001981 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1982 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001983 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001984 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001985 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001986 if (upeek(tcp,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001987 return -1;
1988 }
1989 }
1990#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001991 {
1992 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001993 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1994 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001995 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001996 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001997 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001998 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1999 * for scno somewhere above here!
2000 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002001 if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002002 return -1;
2003 }
2004 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002005#elif defined (IA64)
2006 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002007 if (!ia32) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002008 unsigned long *out0, cfm, sof, sol, i;
2009 long rbs_end;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002010 /* be backwards compatible with kernel < 2.4.4... */
2011# ifndef PT_RBS_END
2012# define PT_RBS_END PT_AR_BSP
2013# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002014
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002015 if (upeek(tcp, PT_RBS_END, &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002016 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002017 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002018 return -1;
2019
2020 sof = (cfm >> 0) & 0x7f;
2021 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002022 out0 = ia64_rse_skip_regs((unsigned long *) rbs_end, -sof + sol);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002023
2024 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2025 && sysent[tcp->scno].nargs != -1)
2026 tcp->u_nargs = sysent[tcp->scno].nargs;
2027 else
2028 tcp->u_nargs = MAX_ARGS;
2029 for (i = 0; i < tcp->u_nargs; ++i) {
2030 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
2031 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
2032 return -1;
2033 }
2034 } else {
2035 int i;
2036
2037 if (/* EBX = out0 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002038 upeek(tcp, PT_R11, (long *) &tcp->u_arg[0]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002039 /* ECX = out1 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002040 || upeek(tcp, PT_R9, (long *) &tcp->u_arg[1]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002041 /* EDX = out2 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002042 || upeek(tcp, PT_R10, (long *) &tcp->u_arg[2]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002043 /* ESI = out3 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002044 || upeek(tcp, PT_R14, (long *) &tcp->u_arg[3]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002045 /* EDI = out4 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002046 || upeek(tcp, PT_R15, (long *) &tcp->u_arg[4]) < 0
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002047 /* EBP = out5 */
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002048 || upeek(tcp, PT_R13, (long *) &tcp->u_arg[5]) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002049 return -1;
2050
2051 for (i = 0; i < 6; ++i)
2052 /* truncate away IVE sign-extension */
2053 tcp->u_arg[i] &= 0xffffffff;
2054
2055 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2056 && sysent[tcp->scno].nargs != -1)
2057 tcp->u_nargs = sysent[tcp->scno].nargs;
2058 else
2059 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002060 }
2061 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002062#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2063 /* N32 and N64 both use up to six registers. */
2064 {
2065 unsigned long long regs[38];
2066 int i, nargs;
2067
2068 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2069 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002070 else
Roland McGrath542c2c62008-05-20 01:11:56 +00002071 nargs = tcp->u_nargs = MAX_ARGS;
2072
2073 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
2074 return -1;
2075
2076 for(i = 0; i < nargs; i++) {
2077 tcp->u_arg[i] = regs[REG_A0 + i];
2078# if defined (LINUX_MIPSN32)
2079 tcp->ext_arg[i] = regs[REG_A0 + i];
2080# endif
2081 }
2082 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002083#elif defined (MIPS)
2084 {
2085 long sp;
2086 int i, nargs;
2087
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002088 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2089 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002090 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002091 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002092 if(nargs > 4) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002093 if(upeek(tcp, REG_SP, &sp) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002094 return -1;
2095 for(i = 0; i < 4; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002096 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i])<0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002097 return -1;
2098 }
2099 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2100 (char *)(tcp->u_arg + 4));
2101 } else {
2102 for(i = 0; i < nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002103 if (upeek(tcp, REG_A0 + i, &tcp->u_arg[i]) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00002104 return -1;
2105 }
2106 }
2107 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002108#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002109#ifndef PT_ORIG_R3
2110#define PT_ORIG_R3 34
2111#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002112 {
2113 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002114 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2115 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002116 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002117 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002118 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002119 if (upeek(tcp, (i==0) ?
Roland McGratheb285352003-01-14 09:59:00 +00002120 (sizeof(unsigned long)*PT_ORIG_R3) :
2121 ((i+PT_R3)*sizeof(unsigned long)),
2122 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002123 return -1;
2124 }
2125 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002126#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002127 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002128 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002129
2130 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2131 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002132 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002133 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002134 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002135 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002136 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002137#elif defined (HPPA)
2138 {
2139 int i;
2140
2141 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2142 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002143 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002144 tcp->u_nargs = MAX_ARGS;
2145 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002146 if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002147 return -1;
2148 }
2149 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002150#elif defined(ARM)
2151 {
2152 int i;
2153
2154 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2155 tcp->u_nargs = sysent[tcp->scno].nargs;
2156 else
2157 tcp->u_nargs = MAX_ARGS;
2158 for (i = 0; i < tcp->u_nargs; i++)
2159 tcp->u_arg[i] = regs.uregs[i];
2160 }
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002161#elif defined(BFIN)
2162 {
2163 int i;
2164 int argreg[] = {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5};
2165
2166 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2167 tcp->u_nargs = sysent[tcp->scno].nargs;
2168 else
2169 tcp->u_nargs = sizeof(argreg) / sizeof(argreg[0]);
2170
2171 for (i = 0; i < tcp->u_nargs; ++i)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002172 if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00002173 return -1;
2174 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002175#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002176 {
2177 int i;
2178 static int syscall_regs[] = {
2179 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2180 REG_REG0, REG_REG0+1, REG_REG0+2
2181 };
Wichert Akkermanccef6372002-05-01 16:39:22 +00002182
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002183 tcp->u_nargs = sysent[tcp->scno].nargs;
2184 for (i = 0; i < tcp->u_nargs; i++) {
2185 if (upeek(tcp, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2186 return -1;
2187 }
2188 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002189#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002190 {
2191 int i;
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002192 /* Registers used by SH5 Linux system calls for parameters */
Roland McGrathe1e584b2003-06-02 19:18:58 +00002193 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2194
2195 /*
2196 * TODO: should also check that the number of arguments encoded
2197 * in the trap number matches the number strace expects.
2198 */
2199 /*
2200 assert(sysent[tcp->scno].nargs <
2201 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2202 */
2203
2204 tcp->u_nargs = sysent[tcp->scno].nargs;
2205 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002206 if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002207 return -1;
2208 }
2209 }
2210
Michal Ludvig0e035502002-09-23 15:41:01 +00002211#elif defined(X86_64)
2212 {
2213 int i;
2214 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2215 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002216 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002217 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002218
Michal Ludvig0e035502002-09-23 15:41:01 +00002219 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2220 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002221 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002222 tcp->u_nargs = MAX_ARGS;
2223 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002224 if (upeek(tcp, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002225 return -1;
2226 }
2227 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002228#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002229 {
2230 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002231 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2232 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002233 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002234 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002235 for (i = 0; i < tcp->u_nargs; i++) {
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002236 if (upeek(tcp, i*4, &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002237 return -1;
2238 }
2239 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002240#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002241#endif /* LINUX */
2242#ifdef SUNOS4
2243 {
2244 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002245 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2246 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002247 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002248 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002249 for (i = 0; i < tcp->u_nargs; i++) {
2250 struct user *u;
2251
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002252 if (upeek(tcp, uoff(u_arg[0]) +
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2254 return -1;
2255 }
2256 }
2257#endif /* SUNOS4 */
2258#ifdef SVR4
2259#ifdef MIPS
2260 /*
2261 * SGI is broken: even though it has pr_sysarg, it doesn't
2262 * set them on system call entry. Get a clue.
2263 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002264 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002265 tcp->u_nargs = sysent[tcp->scno].nargs;
2266 else
2267 tcp->u_nargs = tcp->status.pr_nsysarg;
2268 if (tcp->u_nargs > 4) {
2269 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2270 4*sizeof(tcp->u_arg[0]));
2271 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2272 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2273 }
2274 else {
2275 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2276 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2277 }
John Hughes25299712001-03-06 10:10:06 +00002278#elif UNIXWARE >= 2
2279 /*
2280 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2281 */
2282 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2283 tcp->u_nargs = sysent[tcp->scno].nargs;
2284 else
2285 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2286 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2287 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2288#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002289 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002290 tcp->u_nargs = sysent[tcp->scno].nargs;
2291 else
2292 tcp->u_nargs = tcp->status.pr_nsysarg;
2293 {
2294 int i;
2295 for (i = 0; i < tcp->u_nargs; i++)
2296 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2297 }
John Hughes25299712001-03-06 10:10:06 +00002298#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002299 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002300 tcp->u_nargs = sysent[tcp->scno].nargs;
2301 else
2302 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002303 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002304 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002305#else
2306 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002307#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002308#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002309#ifdef FREEBSD
2310 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2311 sysent[tcp->scno].nargs > tcp->status.val)
2312 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002313 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002314 tcp->u_nargs = tcp->status.val;
2315 if (tcp->u_nargs < 0)
2316 tcp->u_nargs = 0;
2317 if (tcp->u_nargs > MAX_ARGS)
2318 tcp->u_nargs = MAX_ARGS;
2319 switch(regs.r_eax) {
2320 case SYS___syscall:
2321 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2322 regs.r_esp + sizeof(int) + sizeof(quad_t));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002323 break;
2324 case SYS_syscall:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002325 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2326 regs.r_esp + 2 * sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002327 break;
2328 default:
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002329 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2330 regs.r_esp + sizeof(int));
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002331 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002332 }
2333#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002334 return 1;
2335}
2336
2337int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002338trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002339{
2340 int sys_res;
2341 struct timeval tv;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002342 int res, scno_good;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002343
2344 if (tcp->flags & TCB_INSYSCALL) {
2345 long u_error;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002346
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002347 /* Measure the exit time as early as possible to avoid errors. */
2348 if (dtime)
2349 gettimeofday(&tv, NULL);
2350
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002351 /* BTW, why we don't just memorize syscall no. on entry
2352 * in tcp->something?
2353 */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002354 scno_good = res = get_scno(tcp);
2355 if (res == 0)
2356 return res;
2357 if (res == 1)
2358 res = syscall_fixup(tcp);
2359 if (res == 0)
2360 return res;
2361 if (res == 1)
2362 res = get_error(tcp);
2363 if (res == 0)
2364 return res;
2365 if (res == 1)
2366 internal_syscall(tcp);
2367
2368 if (res == 1 && tcp->scno >= 0 && tcp->scno < nsyscalls &&
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002369 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002370 tcp->flags &= ~TCB_INSYSCALL;
2371 return 0;
2372 }
2373
2374 if (tcp->flags & TCB_REPRINT) {
2375 printleader(tcp);
2376 tprintf("<... ");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002377 if (scno_good != 1)
2378 tprintf("????");
2379 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002380 tprintf("syscall_%lu", tcp->scno);
2381 else
2382 tprintf("%s", sysent[tcp->scno].sys_name);
2383 tprintf(" resumed> ");
2384 }
2385
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002386 if (cflag)
2387 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002388
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002389 if (res != 1) {
2390 tprintf(") ");
2391 tabto(acolumn);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002392 tprintf("= ? <unavailable>");
2393 printtrailer();
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002394 tcp->flags &= ~TCB_INSYSCALL;
2395 return res;
2396 }
2397
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002398 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002399 || (qual_flags[tcp->scno] & QUAL_RAW))
2400 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002401 else {
2402 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002403 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002404 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002405 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002406 u_error = tcp->u_error;
2407 tprintf(") ");
2408 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002409 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2410 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002411 if (u_error)
2412 tprintf("= -1 (errno %ld)", u_error);
2413 else
2414 tprintf("= %#lx", tcp->u_rval);
2415 }
2416 else if (!(sys_res & RVAL_NONE) && u_error) {
2417 switch (u_error) {
2418#ifdef LINUX
2419 case ERESTARTSYS:
2420 tprintf("= ? ERESTARTSYS (To be restarted)");
2421 break;
2422 case ERESTARTNOINTR:
2423 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2424 break;
2425 case ERESTARTNOHAND:
2426 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2427 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002428 case ERESTART_RESTARTBLOCK:
2429 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2430 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002431#endif /* LINUX */
2432 default:
2433 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002434 if (u_error < 0)
2435 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002436 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002437 tprintf("%s (%s)", errnoent[u_error],
2438 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002439 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002440 tprintf("ERRNO_%ld (%s)", u_error,
2441 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002442 break;
2443 }
Dmitry V. Levin21a75342008-09-03 01:22:18 +00002444 if ((sys_res & RVAL_STR) && tcp->auxstr)
2445 tprintf(" (%s)", tcp->auxstr);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002446 }
2447 else {
2448 if (sys_res & RVAL_NONE)
2449 tprintf("= ?");
2450 else {
2451 switch (sys_res & RVAL_MASK) {
2452 case RVAL_HEX:
2453 tprintf("= %#lx", tcp->u_rval);
2454 break;
2455 case RVAL_OCTAL:
2456 tprintf("= %#lo", tcp->u_rval);
2457 break;
2458 case RVAL_UDECIMAL:
2459 tprintf("= %lu", tcp->u_rval);
2460 break;
2461 case RVAL_DECIMAL:
2462 tprintf("= %ld", tcp->u_rval);
2463 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002464#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002465 case RVAL_LHEX:
2466 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002467 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002468 case RVAL_LOCTAL:
2469 tprintf("= %#llo", tcp->u_lrval);
2470 break;
2471 case RVAL_LUDECIMAL:
2472 tprintf("= %llu", tcp->u_lrval);
2473 break;
2474 case RVAL_LDECIMAL:
2475 tprintf("= %lld", tcp->u_lrval);
2476 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002477#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002478 default:
2479 fprintf(stderr,
2480 "invalid rval format\n");
2481 break;
2482 }
2483 }
2484 if ((sys_res & RVAL_STR) && tcp->auxstr)
2485 tprintf(" (%s)", tcp->auxstr);
2486 }
2487 if (dtime) {
2488 tv_sub(&tv, &tv, &tcp->etime);
2489 tprintf(" <%ld.%06ld>",
2490 (long) tv.tv_sec, (long) tv.tv_usec);
2491 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002492 printtrailer();
Pavel Machek4dc3b142000-02-01 17:58:41 +00002493
2494 dumpio(tcp);
2495 if (fflush(tcp->outf) == EOF)
2496 return -1;
2497 tcp->flags &= ~TCB_INSYSCALL;
2498 return 0;
2499 }
2500
2501 /* Entering system call */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002502 scno_good = res = get_scno(tcp);
2503 if (res == 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002504 return res;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002505 if (res == 1)
2506 res = syscall_fixup(tcp);
2507 if (res == 0)
2508 return res;
2509 if (res == 1)
2510 res = syscall_enter(tcp);
2511 if (res == 0)
2512 return res;
2513
2514 if (res != 1) {
2515 printleader(tcp);
2516 tcp->flags &= ~TCB_REPRINT;
2517 tcp_last = tcp;
2518 if (scno_good != 1)
2519 tprintf("????" /* anti-trigraph gap */ "(");
2520 else if (tcp->scno >= nsyscalls || tcp->scno < 0)
2521 tprintf("syscall_%lu(", tcp->scno);
2522 else
2523 tprintf("%s(", sysent[tcp->scno].sys_name);
2524 /*
2525 * " <unavailable>" will be added later by the code which
2526 * detects ptrace errors.
2527 */
2528 tcp->flags |= TCB_INSYSCALL;
2529 return res;
2530 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002531
Roland McGrath17352792005-06-07 23:21:26 +00002532 switch (known_scno(tcp)) {
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002533#ifdef SYS_socket_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002534 case SYS_socketcall:
2535 decode_subcall(tcp, SYS_socket_subcall,
2536 SYS_socket_nsubcalls, deref_style);
2537 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002538#endif
2539#ifdef SYS_ipc_subcall
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002540 case SYS_ipc:
2541 decode_subcall(tcp, SYS_ipc_subcall,
2542 SYS_ipc_nsubcalls, shift_style);
2543 break;
Roland McGrathd5bd7e62008-08-25 03:16:26 +00002544#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002545#ifdef SVR4
2546#ifdef SYS_pgrpsys_subcall
2547 case SYS_pgrpsys:
2548 decode_subcall(tcp, SYS_pgrpsys_subcall,
2549 SYS_pgrpsys_nsubcalls, shift_style);
2550 break;
2551#endif /* SYS_pgrpsys_subcall */
2552#ifdef SYS_sigcall_subcall
2553 case SYS_sigcall:
2554 decode_subcall(tcp, SYS_sigcall_subcall,
2555 SYS_sigcall_nsubcalls, mask_style);
2556 break;
2557#endif /* SYS_sigcall_subcall */
2558 case SYS_msgsys:
2559 decode_subcall(tcp, SYS_msgsys_subcall,
2560 SYS_msgsys_nsubcalls, shift_style);
2561 break;
2562 case SYS_shmsys:
2563 decode_subcall(tcp, SYS_shmsys_subcall,
2564 SYS_shmsys_nsubcalls, shift_style);
2565 break;
2566 case SYS_semsys:
2567 decode_subcall(tcp, SYS_semsys_subcall,
2568 SYS_semsys_nsubcalls, shift_style);
2569 break;
2570#if 0 /* broken */
2571 case SYS_utssys:
2572 decode_subcall(tcp, SYS_utssys_subcall,
2573 SYS_utssys_nsubcalls, shift_style);
2574 break;
2575#endif
2576 case SYS_sysfs:
2577 decode_subcall(tcp, SYS_sysfs_subcall,
2578 SYS_sysfs_nsubcalls, shift_style);
2579 break;
2580 case SYS_spcall:
2581 decode_subcall(tcp, SYS_spcall_subcall,
2582 SYS_spcall_nsubcalls, shift_style);
2583 break;
2584#ifdef SYS_context_subcall
2585 case SYS_context:
2586 decode_subcall(tcp, SYS_context_subcall,
2587 SYS_context_nsubcalls, shift_style);
2588 break;
2589#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002590#ifdef SYS_door_subcall
2591 case SYS_door:
2592 decode_subcall(tcp, SYS_door_subcall,
2593 SYS_door_nsubcalls, door_style);
2594 break;
2595#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002596#ifdef SYS_kaio_subcall
2597 case SYS_kaio:
2598 decode_subcall(tcp, SYS_kaio_subcall,
2599 SYS_kaio_nsubcalls, shift_style);
2600 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002601#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002602#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002603#ifdef FREEBSD
2604 case SYS_msgsys:
2605 case SYS_shmsys:
2606 case SYS_semsys:
2607 decode_subcall(tcp, 0, 0, table_style);
2608 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002609#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002610#ifdef SUNOS4
2611 case SYS_semsys:
2612 decode_subcall(tcp, SYS_semsys_subcall,
2613 SYS_semsys_nsubcalls, shift_style);
2614 break;
2615 case SYS_msgsys:
2616 decode_subcall(tcp, SYS_msgsys_subcall,
2617 SYS_msgsys_nsubcalls, shift_style);
2618 break;
2619 case SYS_shmsys:
2620 decode_subcall(tcp, SYS_shmsys_subcall,
2621 SYS_shmsys_nsubcalls, shift_style);
2622 break;
2623#endif
2624 }
2625
2626 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002627 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002628 tcp->flags |= TCB_INSYSCALL;
2629 return 0;
2630 }
2631
2632 if (cflag) {
2633 gettimeofday(&tcp->etime, NULL);
2634 tcp->flags |= TCB_INSYSCALL;
2635 return 0;
2636 }
2637
2638 printleader(tcp);
2639 tcp->flags &= ~TCB_REPRINT;
2640 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002641 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002642 tprintf("syscall_%lu(", tcp->scno);
2643 else
2644 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002645 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002646 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2647 sys_res = printargs(tcp);
2648 else
2649 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2650 if (fflush(tcp->outf) == EOF)
2651 return -1;
2652 tcp->flags |= TCB_INSYSCALL;
2653 /* Measure the entrance time as late as possible to avoid errors. */
2654 if (dtime)
2655 gettimeofday(&tcp->etime, NULL);
2656 return sys_res;
2657}
2658
2659int
2660printargs(tcp)
2661struct tcb *tcp;
2662{
2663 if (entering(tcp)) {
2664 int i;
2665
2666 for (i = 0; i < tcp->u_nargs; i++)
2667 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2668 }
2669 return 0;
2670}
2671
2672long
2673getrval2(tcp)
2674struct tcb *tcp;
2675{
2676 long val = -1;
2677
2678#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002679#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002680 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002681 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2682 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002683 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002684#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002685 if (upeek(tcp, 4*(REG_REG0+1), &val) < 0)
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002686 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002687#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002688 if (upeek(tcp, PT_R9, &val) < 0)
Roland McGrathb4ce1762004-03-01 20:30:48 +00002689 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002690#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002691#endif /* LINUX */
2692
2693#ifdef SUNOS4
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002694 if (upeek(tcp, uoff(u_rval2), &val) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002695 return -1;
2696#endif /* SUNOS4 */
2697
2698#ifdef SVR4
2699#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002700 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002701#endif /* SPARC */
2702#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002703 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002704#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002705#ifdef X86_64
2706 val = tcp->status.PR_REG[RDX];
2707#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002708#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002709 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710#endif /* MIPS */
2711#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002712#ifdef FREEBSD
2713 struct reg regs;
2714 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2715 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002716#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002717 return val;
2718}
2719
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002720#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002721/*
2722 * Apparently, indirect system calls have already be converted by ptrace(2),
2723 * so if you see "indir" this program has gone astray.
2724 */
2725int
2726sys_indir(tcp)
2727struct tcb *tcp;
2728{
2729 int i, scno, nargs;
2730
2731 if (entering(tcp)) {
2732 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2733 fprintf(stderr, "Bogus syscall: %u\n", scno);
2734 return 0;
2735 }
2736 nargs = sysent[scno].nargs;
2737 tprintf("%s", sysent[scno].sys_name);
2738 for (i = 0; i < nargs; i++)
2739 tprintf(", %#lx", tcp->u_arg[i+1]);
2740 }
2741 return 0;
2742}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002743#endif /* SUNOS4 */
Dmitry V. Levin2e55ff42008-09-03 01:02:46 +00002744
2745int
2746is_restart_error(struct tcb *tcp)
2747{
2748#ifdef LINUX
2749 if (!syserror(tcp))
2750 return 0;
2751 switch (tcp->u_error) {
2752 case ERESTARTSYS:
2753 case ERESTARTNOINTR:
2754 case ERESTARTNOHAND:
2755 case ERESTART_RESTARTBLOCK:
2756 return 1;
2757 default:
2758 break;
2759 }
2760#endif /* LINUX */
2761 return 0;
2762}