blob: 428b86860c1a86708305f2b441e0f6e893d309ab [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
548 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;
552#endif
553#ifdef SYS_writev
554 case SYS_writev:
555
556 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE)
557 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
558 break;
559#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560 }
561}
562
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000563#ifndef FREEBSD
Wichert Akkerman8829a551999-06-11 13:18:40 +0000564enum subcall_style { shift_style, deref_style, mask_style, door_style };
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000565#else /* FREEBSD */
566enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };
567
568struct subcall {
569 int call;
570 int nsubcalls;
571 int subcalls[5];
572};
573
Roland McGratha4d48532005-06-08 20:45:28 +0000574static const struct subcall subcalls_table[] = {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000575 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },
John Hughes61eeb552001-03-06 15:51:53 +0000576#ifdef SYS_semconfig
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000577 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },
John Hughes61eeb552001-03-06 15:51:53 +0000578#else
579 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },
580#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000581 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },
582};
583#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000584
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000585#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) ))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586
Roland McGratha4d48532005-06-08 20:45:28 +0000587static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588decode_subcall(tcp, subcall, nsubcalls, style)
589struct tcb *tcp;
590int subcall;
591int nsubcalls;
592enum subcall_style style;
593{
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000594 unsigned long addr, mask;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000595 int i;
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000596 int size = personality_wordsize[current_personality];
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000597
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000598 switch (style) {
599 case shift_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000600 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
601 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 tcp->scno = subcall + tcp->u_arg[0];
603 if (sysent[tcp->scno].nargs != -1)
604 tcp->u_nargs = sysent[tcp->scno].nargs;
605 else
606 tcp->u_nargs--;
607 for (i = 0; i < tcp->u_nargs; i++)
608 tcp->u_arg[i] = tcp->u_arg[i + 1];
609 break;
610 case deref_style:
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000611 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls)
612 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000613 tcp->scno = subcall + tcp->u_arg[0];
614 addr = tcp->u_arg[1];
615 for (i = 0; i < sysent[tcp->scno].nargs; i++) {
Roland McGrath4b2dcca2006-01-12 10:18:53 +0000616 if (size == sizeof(int)) {
617 unsigned int arg;
618 if (umove(tcp, addr, &arg) < 0)
619 arg = 0;
620 tcp->u_arg[i] = arg;
621 }
622 else if (size == sizeof(long)) {
623 unsigned long arg;
624 if (umove(tcp, addr, &arg) < 0)
625 arg = 0;
626 tcp->u_arg[i] = arg;
627 }
628 else
629 abort();
630 addr += size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 }
632 tcp->u_nargs = sysent[tcp->scno].nargs;
633 break;
634 case mask_style:
635 mask = (tcp->u_arg[0] >> 8) & 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000636 for (i = 0; mask; i++)
637 mask >>= 1;
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000638 if (i >= nsubcalls)
639 return;
640 tcp->u_arg[0] &= 0xff;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 tcp->scno = subcall + i;
642 if (sysent[tcp->scno].nargs != -1)
643 tcp->u_nargs = sysent[tcp->scno].nargs;
644 break;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000645 case door_style:
646 /*
647 * Oh, yuck. The call code is the *sixth* argument.
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000648 * (don't you mean the *last* argument? - JH)
Wichert Akkerman8829a551999-06-11 13:18:40 +0000649 */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000650 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls)
651 return;
Wichert Akkerman8829a551999-06-11 13:18:40 +0000652 tcp->scno = subcall + tcp->u_arg[5];
653 if (sysent[tcp->scno].nargs != -1)
654 tcp->u_nargs = sysent[tcp->scno].nargs;
655 else
656 tcp->u_nargs--;
657 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000658#ifdef FREEBSD
659 case table_style:
660 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++)
661 if (subcalls_table[i].call == tcp->scno) break;
662 if (i < sizeof(subcalls_table) / sizeof(struct subcall) &&
663 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) {
664 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]];
665 for (i = 0; i < tcp->u_nargs; i++)
666 tcp->u_arg[i] = tcp->u_arg[i + 1];
667 }
668 break;
669#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670 }
671}
672#endif
673
674struct tcb *tcp_last = NULL;
675
676static int
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000677internal_syscall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000678{
679 /*
680 * We must always trace a few critical system calls in order to
681 * correctly support following forks in the presence of tracing
682 * qualifiers.
683 */
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000684 int (*func)();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000685
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000686 if (tcp->scno < 0 || tcp->scno >= nsyscalls)
687 return 0;
688
689 func = sysent[tcp->scno].sys_func;
690
691 if (sys_exit == func)
692 return internal_exit(tcp);
693
694 if ( sys_fork == func
695#if defined(FREEBSD) || defined(LINUX) || defined(SUNOS4)
696 || sys_vfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000697#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000698#if UNIXWARE > 2
699 || sys_rfork == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000701 )
702 return internal_fork(tcp);
703
704#if defined(LINUX) && (defined SYS_clone || defined SYS_clone2)
705 if (sys_clone == func)
706 return internal_clone(tcp);
Roland McGrathc74c0b72004-09-01 19:39:46 +0000707#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000708
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000709 if ( sys_execve == func
710#if defined(SPARC) || defined(SPARC64) || defined(SUNOS4)
711 || sys_execv == func
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000713#if UNIXWARE > 2
714 || sys_rexecve == func
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000715#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000716 )
717 return internal_exec(tcp);
718
719 if ( sys_waitpid == func
720 || sys_wait4 == func
721#if defined(SVR4) || defined(FREEBSD) || defined(SUNOS4)
722 || sys_wait == func
Roland McGrath923f7502003-01-09 06:53:27 +0000723#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000724#ifdef ALPHA
725 || sys_osf_wait4 == func
Roland McGrath08267b82004-02-20 22:56:43 +0000726#endif
Dmitry V. Levinb2f86992006-12-21 11:44:28 +0000727 )
728 return internal_wait(tcp, 2);
729
730#if defined(LINUX) || defined(SVR4)
731 if (sys_waitid == func)
732 return internal_wait(tcp, 3);
733#endif
734
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000735 return 0;
736}
737
Wichert Akkermanc7926982000-04-10 22:22:31 +0000738
739#ifdef LINUX
740#if defined (I386)
741 static long eax;
742#elif defined (IA64)
743 long r8, r10, psr;
744 long ia32 = 0;
745#elif defined (POWERPC)
746 static long result,flags;
747#elif defined (M68K)
748 static int d0;
749#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000750 static struct pt_regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000751#elif defined (ALPHA)
752 static long r0;
753 static long a3;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000754#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman00a82ee2001-03-28 20:29:17 +0000755 static struct regs regs;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000756 static unsigned long trap;
Roland McGrath542c2c62008-05-20 01:11:56 +0000757#elif defined(LINUX_MIPSN32)
758 static long long a3;
759 static long long r2;
Wichert Akkermanc7926982000-04-10 22:22:31 +0000760#elif defined(MIPS)
761 static long a3;
762 static long r2;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000763#elif defined(S390) || defined(S390X)
Wichert Akkermanc7926982000-04-10 22:22:31 +0000764 static long gpr2;
765 static long pc;
Michal Ludvig882eda82002-11-11 12:50:47 +0000766 static long syscall_mode;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000767#elif defined(HPPA)
768 static long r28;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000769#elif defined(SH)
770 static long r0;
Roland McGrathf5a47772003-06-26 22:40:42 +0000771#elif defined(SH64)
Roland McGrath0f87c492003-06-03 23:29:04 +0000772 static long r9;
Michal Ludvig0e035502002-09-23 15:41:01 +0000773#elif defined(X86_64)
774 static long rax;
Roland McGrath761b5d72002-12-15 23:58:31 +0000775#endif
Wichert Akkermanc7926982000-04-10 22:22:31 +0000776#endif /* LINUX */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000777#ifdef FREEBSD
778 struct reg regs;
Roland McGrath761b5d72002-12-15 23:58:31 +0000779#endif /* FREEBSD */
Wichert Akkermanc7926982000-04-10 22:22:31 +0000780
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000781int
Pavel Machek4dc3b142000-02-01 17:58:41 +0000782get_scno(tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783struct tcb *tcp;
784{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785 long scno = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000786#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +0000788#endif /* !PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +0000791#if defined(S390) || defined(S390X)
Roland McGrath96dc5142003-01-20 10:23:04 +0000792 if (tcp->flags & TCB_WAITEXECVE) {
793 /*
794 * When the execve system call completes successfully, the
795 * new process still has -ENOSYS (old style) or __NR_execve
796 * (new style) in gpr2. We cannot recover the scno again
797 * by disassembly, because the image that executed the
798 * syscall is gone now. Fortunately, we don't want it. We
799 * leave the flag set so that syscall_fixup can fake the
800 * result.
801 */
802 if (tcp->flags & TCB_INSYSCALL)
803 return 1;
804 /*
805 * This is the SIGTRAP after execve. We cannot try to read
806 * the system call here either.
807 */
808 tcp->flags &= ~TCB_WAITEXECVE;
809 return 0;
810 }
Roland McGrath2f924ca2003-06-26 22:23:28 +0000811
812 if (upeek(pid, PT_GPR2, &syscall_mode) < 0)
813 return -1;
814
815 if (syscall_mode != -ENOSYS) {
816 /*
817 * Since kernel version 2.5.44 the scno gets passed in gpr2.
818 */
819 scno = syscall_mode;
820 } else {
Michal Ludvig882eda82002-11-11 12:50:47 +0000821 /*
822 * Old style of "passing" the scno via the SVC instruction.
823 */
824
825 long opcode, offset_reg, tmp;
826 void * svc_addr;
827 int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
828 PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
829 PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
830 PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
Roland McGrath761b5d72002-12-15 23:58:31 +0000831
Michal Ludvig882eda82002-11-11 12:50:47 +0000832 if (upeek(pid, PT_PSWADDR, &pc) < 0)
833 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000834 errno = 0;
Michal Ludvig882eda82002-11-11 12:50:47 +0000835 opcode = ptrace(PTRACE_PEEKTEXT, pid, (char *)(pc-sizeof(long)), 0);
Roland McGrath96dc5142003-01-20 10:23:04 +0000836 if (errno) {
837 perror("peektext(pc-oneword)");
Michal Ludvig882eda82002-11-11 12:50:47 +0000838 return -1;
Roland McGrath96dc5142003-01-20 10:23:04 +0000839 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000840
841 /*
842 * We have to check if the SVC got executed directly or via an
843 * EXECUTE instruction. In case of EXECUTE it is necessary to do
844 * instruction decoding to derive the system call number.
845 * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
846 * so that this doesn't work if a SVC opcode is part of an EXECUTE
847 * opcode. Since there is no way to find out the opcode size this
848 * is the best we can do...
849 */
850
851 if ((opcode & 0xff00) == 0x0a00) {
852 /* SVC opcode */
853 scno = opcode & 0xff;
Roland McGrath761b5d72002-12-15 23:58:31 +0000854 }
Michal Ludvig882eda82002-11-11 12:50:47 +0000855 else {
856 /* SVC got executed by EXECUTE instruction */
857
858 /*
859 * Do instruction decoding of EXECUTE. If you really want to
860 * understand this, read the Principles of Operations.
861 */
862 svc_addr = (void *) (opcode & 0xfff);
863
864 tmp = 0;
865 offset_reg = (opcode & 0x000f0000) >> 16;
866 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
867 return -1;
868 svc_addr += tmp;
869
870 tmp = 0;
871 offset_reg = (opcode & 0x0000f000) >> 12;
872 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
873 return -1;
874 svc_addr += tmp;
875
876 scno = ptrace(PTRACE_PEEKTEXT, pid, svc_addr, 0);
877 if (errno)
878 return -1;
879#if defined(S390X)
880 scno >>= 48;
881#else
882 scno >>= 16;
883#endif
884 tmp = 0;
885 offset_reg = (opcode & 0x00f00000) >> 20;
886 if (offset_reg && (upeek(pid, gpr_offset[offset_reg], &tmp) < 0))
887 return -1;
888
889 scno = (scno | tmp) & 0xff;
890 }
891 }
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000892#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000893 if (upeek(pid, sizeof(unsigned long)*PT_R0, &scno) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 return -1;
895 if (!(tcp->flags & TCB_INSYSCALL)) {
896 /* Check if we return from execve. */
897 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
898 tcp->flags &= ~TCB_WAITEXECVE;
899 return 0;
900 }
901 }
902#elif defined (I386)
903 if (upeek(pid, 4*ORIG_EAX, &scno) < 0)
904 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000905#elif defined (X86_64)
906 if (upeek(pid, 8*ORIG_RAX, &scno) < 0)
907 return -1;
908
Roland McGrath761b5d72002-12-15 23:58:31 +0000909 if (!(tcp->flags & TCB_INSYSCALL)) {
910 static int currpers=-1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000911 long val;
912
913 /* Check CS register value. On x86-64 linux it is:
914 * 0x33 for long mode (64 bit)
915 * 0x23 for compatibility mode (32 bit)
Roland McGrath761b5d72002-12-15 23:58:31 +0000916 * It takes only one ptrace and thus doesn't need
Michal Ludvig0e035502002-09-23 15:41:01 +0000917 * to be cached.
918 */
919 if (upeek(pid, 8*CS, &val) < 0)
920 return -1;
921 switch(val)
922 {
923 case 0x23: currpers = 1; break;
924 case 0x33: currpers = 0; break;
925 default:
926 fprintf(stderr, "Unknown value CS=0x%02X while "
927 "detecting personality of process "
928 "PID=%d\n", (int)val, pid);
929 currpers = current_personality;
930 break;
931 }
932#if 0
933 /* This version analyzes the opcode of a syscall instruction.
934 * (int 0x80 on i386 vs. syscall on x86-64)
935 * It works, but is too complicated.
936 */
937 unsigned long val, rip, i;
938
939 if(upeek(pid, 8*RIP, &rip)<0)
940 perror("upeek(RIP)");
Roland McGrath761b5d72002-12-15 23:58:31 +0000941
Michal Ludvig0e035502002-09-23 15:41:01 +0000942 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
943 rip-=2;
944 errno = 0;
945
Roland McGrath761b5d72002-12-15 23:58:31 +0000946 call = ptrace(PTRACE_PEEKTEXT,pid,(char *)rip,0);
947 if (errno)
948 printf("ptrace_peektext failed: %s\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000949 strerror(errno));
950 switch (call & 0xffff)
951 {
952 /* x86-64: syscall = 0x0f 0x05 */
953 case 0x050f: currpers = 0; break;
954 /* i386: int 0x80 = 0xcd 0x80 */
955 case 0x80cd: currpers = 1; break;
956 default:
957 currpers = current_personality;
Roland McGrath761b5d72002-12-15 23:58:31 +0000958 fprintf(stderr,
Michal Ludvig0e035502002-09-23 15:41:01 +0000959 "Unknown syscall opcode (0x%04X) while "
960 "detecting personality of process "
961 "PID=%d\n", (int)call, pid);
962 break;
963 }
964#endif
965 if(currpers != current_personality)
966 {
967 char *names[]={"64 bit", "32 bit"};
968 set_personality(currpers);
Roland McGrath761b5d72002-12-15 23:58:31 +0000969 printf("[ Process PID=%d runs in %s mode. ]\n",
Michal Ludvig0e035502002-09-23 15:41:01 +0000970 pid, names[current_personality]);
971 }
Roland McGrath761b5d72002-12-15 23:58:31 +0000972 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000973#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000974# define IA64_PSR_IS ((long)1 << 34)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000975 if (upeek (pid, PT_CR_IPSR, &psr) >= 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000976 ia32 = (psr & IA64_PSR_IS) != 0;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000977 if (!(tcp->flags & TCB_INSYSCALL)) {
978 if (ia32) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +0000979 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000980 return -1;
981 } else {
982 if (upeek (pid, PT_R15, &scno) < 0)
983 return -1;
984 }
Roland McGrathba954762003-03-05 06:29:06 +0000985 /* Check if we return from execve. */
986 if (tcp->flags & TCB_WAITEXECVE) {
987 tcp->flags &= ~TCB_WAITEXECVE;
988 return 0;
989 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000990 } else {
991 /* syscall in progress */
992 if (upeek (pid, PT_R8, &r8) < 0)
993 return -1;
994 if (upeek (pid, PT_R10, &r10) < 0)
995 return -1;
996 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000997#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +0000998 /*
999 * Read complete register set in one go.
1000 */
1001 if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)&regs) == -1)
1002 return -1;
1003
1004 /*
1005 * We only need to grab the syscall number on syscall entry.
1006 */
1007 if (regs.ARM_ip == 0) {
Roland McGrath9bc63402007-11-01 21:42:18 +00001008 if (!(tcp->flags & TCB_INSYSCALL)) {
1009 /* Check if we return from execve. */
1010 if (tcp->flags & TCB_WAITEXECVE) {
1011 tcp->flags &= ~TCB_WAITEXECVE;
1012 return 0;
1013 }
1014 }
1015
Roland McGrath0f87c492003-06-03 23:29:04 +00001016 /*
1017 * Note: we only deal with only 32-bit CPUs here.
1018 */
1019 if (regs.ARM_cpsr & 0x20) {
1020 /*
1021 * Get the Thumb-mode system call number
1022 */
1023 scno = regs.ARM_r7;
1024 } else {
1025 /*
1026 * Get the ARM-mode system call number
1027 */
1028 errno = 0;
1029 scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
1030 if (errno)
1031 return -1;
1032
1033 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
1034 tcp->flags &= ~TCB_WAITEXECVE;
1035 return 0;
1036 }
1037
Roland McGrathf691bd22006-04-25 07:34:41 +00001038 /* Handle the EABI syscall convention. We do not
1039 bother converting structures between the two
1040 ABIs, but basic functionality should work even
1041 if strace and the traced program have different
1042 ABIs. */
1043 if (scno == 0xef000000) {
1044 scno = regs.ARM_r7;
1045 } else {
1046 if ((scno & 0x0ff00000) != 0x0f900000) {
1047 fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
1048 scno);
1049 return -1;
1050 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001051
Roland McGrathf691bd22006-04-25 07:34:41 +00001052 /*
1053 * Fixup the syscall number
1054 */
1055 scno &= 0x000fffff;
1056 }
Roland McGrath0f87c492003-06-03 23:29:04 +00001057 }
Roland McGrath56703312008-05-20 01:35:55 +00001058 if (scno & 0x0f0000) {
1059 /*
1060 * Handle ARM specific syscall
1061 */
1062 set_personality(1);
1063 scno &= 0x0000ffff;
1064 } else
1065 set_personality(0);
Roland McGrath0f87c492003-06-03 23:29:04 +00001066
1067 if (tcp->flags & TCB_INSYSCALL) {
1068 fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
1069 tcp->flags &= ~TCB_INSYSCALL;
1070 }
1071 } else {
1072 if (!(tcp->flags & TCB_INSYSCALL)) {
1073 fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
1074 tcp->flags |= TCB_INSYSCALL;
1075 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076 }
1077#elif defined (M68K)
1078 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
1079 return -1;
Roland McGrath542c2c62008-05-20 01:11:56 +00001080#elif defined (LINUX_MIPSN32)
1081 unsigned long long regs[38];
1082
1083 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
1084 return -1;
1085 a3 = regs[REG_A3];
1086 r2 = regs[REG_V0];
1087
1088 if(!(tcp->flags & TCB_INSYSCALL)) {
1089 scno = r2;
1090
1091 /* Check if we return from execve. */
1092 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1093 tcp->flags &= ~TCB_WAITEXECVE;
1094 return 0;
1095 }
1096
1097 if (scno < 0 || scno > nsyscalls) {
1098 if(a3 == 0 || a3 == -1) {
1099 if(debug)
1100 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1101 return 0;
1102 }
1103 }
1104 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00001105#elif defined (MIPS)
1106 if (upeek(pid, REG_A3, &a3) < 0)
1107 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001108 if(!(tcp->flags & TCB_INSYSCALL)) {
1109 if (upeek(pid, REG_V0, &scno) < 0)
1110 return -1;
1111
Roland McGrath542c2c62008-05-20 01:11:56 +00001112 /* Check if we return from execve. */
1113 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1114 tcp->flags &= ~TCB_WAITEXECVE;
1115 return 0;
1116 }
1117
Wichert Akkermanf90da011999-10-31 21:15:38 +00001118 if (scno < 0 || scno > nsyscalls) {
1119 if(a3 == 0 || a3 == -1) {
1120 if(debug)
1121 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
1122 return 0;
1123 }
1124 }
1125 } else {
1126 if (upeek(pid, REG_V0, &r2) < 0)
1127 return -1;
1128 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129#elif defined (ALPHA)
1130 if (upeek(pid, REG_A3, &a3) < 0)
1131 return -1;
1132
1133 if (!(tcp->flags & TCB_INSYSCALL)) {
1134 if (upeek(pid, REG_R0, &scno) < 0)
1135 return -1;
1136
1137 /* Check if we return from execve. */
1138 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1139 tcp->flags &= ~TCB_WAITEXECVE;
1140 return 0;
1141 }
1142
1143 /*
1144 * Do some sanity checks to figure out if it's
1145 * really a syscall entry
1146 */
1147 if (scno < 0 || scno > nsyscalls) {
1148 if (a3 == 0 || a3 == -1) {
1149 if (debug)
1150 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno);
1151 return 0;
1152 }
1153 }
1154 }
1155 else {
1156 if (upeek(pid, REG_R0, &r0) < 0)
1157 return -1;
1158 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001159#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160 /* Everything we need is in the current register set. */
1161 if (ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) < 0)
1162 return -1;
1163
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 /* If we are entering, then disassemble the syscall trap. */
1165 if (!(tcp->flags & TCB_INSYSCALL)) {
1166 /* Retrieve the syscall trap instruction. */
1167 errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001168 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001169#if defined(SPARC64)
1170 trap >>= 32;
1171#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 if (errno)
1173 return -1;
1174
1175 /* Disassemble the trap to see what personality to use. */
1176 switch (trap) {
1177 case 0x91d02010:
1178 /* Linux/SPARC syscall trap. */
1179 set_personality(0);
1180 break;
Wichert Akkermandacfb6e1999-06-03 14:21:07 +00001181 case 0x91d0206d:
1182 /* Linux/SPARC64 syscall trap. */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001183 set_personality(2);
1184 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185 case 0x91d02000:
1186 /* SunOS syscall trap. (pers 1) */
1187 fprintf(stderr,"syscall: SunOS no support\n");
1188 return -1;
1189 case 0x91d02008:
1190 /* Solaris 2.x syscall trap. (per 2) */
1191 set_personality(1);
Roland McGrath761b5d72002-12-15 23:58:31 +00001192 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 case 0x91d02009:
1194 /* NetBSD/FreeBSD syscall trap. */
1195 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n");
1196 return -1;
1197 case 0x91d02027:
1198 /* Solaris 2.x gettimeofday */
1199 set_personality(1);
1200 break;
1201 default:
1202 /* Unknown syscall trap. */
1203 if(tcp->flags & TCB_WAITEXECVE) {
1204 tcp->flags &= ~TCB_WAITEXECVE;
1205 return 0;
1206 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001207#if defined (SPARC64)
1208 fprintf(stderr,"syscall: unknown syscall trap %08lx %016lx\n", trap, regs.r_tpc);
1209#else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001210 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001211#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001212 return -1;
1213 }
1214
1215 /* Extract the system call number from the registers. */
1216 if (trap == 0x91d02027)
1217 scno = 156;
1218 else
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001219 scno = regs.r_g1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001220 if (scno == 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001221 scno = regs.r_o0;
1222 memmove (&regs.r_o0, &regs.r_o1, 7*sizeof(regs.r_o0));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001223 }
1224 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001225#elif defined(HPPA)
1226 if (upeek(pid, PT_GR20, &scno) < 0)
1227 return -1;
1228 if (!(tcp->flags & TCB_INSYSCALL)) {
1229 /* Check if we return from execve. */
1230 if ((tcp->flags & TCB_WAITEXECVE)) {
1231 tcp->flags &= ~TCB_WAITEXECVE;
1232 return 0;
1233 }
1234 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001235#elif defined(SH)
1236 /*
1237 * In the new syscall ABI, the system call number is in R3.
1238 */
1239 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0)
1240 return -1;
1241
1242 if (scno < 0) {
1243 /* Odd as it may seem, a glibc bug has been known to cause
1244 glibc to issue bogus negative syscall numbers. So for
1245 our purposes, make strace print what it *should* have been */
1246 long correct_scno = (scno & 0xff);
1247 if (debug)
1248 fprintf(stderr,
Michal Ludvig53b320f2002-09-23 13:30:09 +00001249 "Detected glibc bug: bogus system call number = %ld, "
1250 "correcting to %ld\n",
Wichert Akkermanccef6372002-05-01 16:39:22 +00001251 scno,
1252 correct_scno);
1253 scno = correct_scno;
1254 }
1255
1256
1257 if (!(tcp->flags & TCB_INSYSCALL)) {
1258 /* Check if we return from execve. */
1259 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
1260 tcp->flags &= ~TCB_WAITEXECVE;
1261 return 0;
1262 }
1263 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001264#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001265 if (upeek(pid, REG_SYSCALL, &scno) < 0)
1266 return -1;
1267 scno &= 0xFFFF;
1268
1269 if (!(tcp->flags & TCB_INSYSCALL)) {
1270 /* Check if we return from execve. */
1271 if (tcp->flags & TCB_WAITEXECVE) {
1272 tcp->flags &= ~TCB_WAITEXECVE;
1273 return 0;
1274 }
1275 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001276#endif /* SH64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001277#endif /* LINUX */
1278#ifdef SUNOS4
1279 if (upeek(pid, uoff(u_arg[7]), &scno) < 0)
1280 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001281#elif defined(SH)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001282 /* new syscall ABI returns result in R0 */
1283 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0)
1284 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001285#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001286 /* ABI defines result returned in r9 */
1287 if (upeek(pid, REG_GENERAL(9), (long *)&r9) < 0)
1288 return -1;
1289
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001290#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001291#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292#ifdef HAVE_PR_SYSCALL
John Hughes25299712001-03-06 10:10:06 +00001293 scno = tcp->status.PR_SYSCALL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001294#else /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001295#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001296 scno = tcp->status.PR_WHAT;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001297#else /* FREEBSD */
1298 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1299 perror("pread");
1300 return -1;
1301 }
1302 switch (regs.r_eax) {
1303 case SYS_syscall:
1304 case SYS___syscall:
1305 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
1306 break;
1307 default:
1308 scno = regs.r_eax;
1309 break;
1310 }
1311#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001312#endif /* !HAVE_PR_SYSCALL */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001313#endif /* USE_PROCFS */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +00001314 if (!(tcp->flags & TCB_INSYSCALL))
1315 tcp->scno = scno;
Pavel Machek4dc3b142000-02-01 17:58:41 +00001316 return 1;
1317}
1318
Pavel Machek4dc3b142000-02-01 17:58:41 +00001319
Roland McGrath17352792005-06-07 23:21:26 +00001320long
1321known_scno(tcp)
1322struct tcb *tcp;
1323{
1324 long scno = tcp->scno;
1325 if (scno >= 0 && scno < nsyscalls && sysent[scno].native_scno != 0)
1326 scno = sysent[scno].native_scno;
1327 else
1328 scno += NR_SYSCALL_BASE;
1329 return scno;
1330}
1331
Roland McGratha4d48532005-06-08 20:45:28 +00001332static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001333syscall_fixup(tcp)
1334struct tcb *tcp;
1335{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001336#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001337 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001338#else /* USE_PROCFS */
Roland McGrath17352792005-06-07 23:21:26 +00001339 int scno = known_scno(tcp);
Pavel Machek4dc3b142000-02-01 17:58:41 +00001340
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001341 if (!(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001342 if (tcp->status.PR_WHY != PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001343 if (
1344 scno == SYS_fork
1345#ifdef SYS_vfork
1346 || scno == SYS_vfork
1347#endif /* SYS_vfork */
John Hughes4e36a812001-04-18 15:11:51 +00001348#ifdef SYS_fork1
1349 || scno == SYS_fork1
1350#endif /* SYS_fork1 */
1351#ifdef SYS_forkall
1352 || scno == SYS_forkall
1353#endif /* SYS_forkall */
1354#ifdef SYS_rfork1
1355 || scno == SYS_rfork1
1356#endif /* SYS_fork1 */
1357#ifdef SYS_rforkall
1358 || scno == SYS_rforkall
1359#endif /* SYS_rforkall */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001360 ) {
1361 /* We are returning in the child, fake it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001362 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001363 trace_syscall(tcp);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001364 tcp->status.PR_WHY = PR_SYSEXIT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001365 }
1366 else {
1367 fprintf(stderr, "syscall: missing entry\n");
1368 tcp->flags |= TCB_INSYSCALL;
1369 }
1370 }
1371 }
1372 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001373 if (tcp->status.PR_WHY != PR_SYSEXIT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374 fprintf(stderr, "syscall: missing exit\n");
1375 tcp->flags &= ~TCB_INSYSCALL;
1376 }
1377 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001378#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001379#ifdef SUNOS4
1380 if (!(tcp->flags & TCB_INSYSCALL)) {
1381 if (scno == 0) {
1382 fprintf(stderr, "syscall: missing entry\n");
1383 tcp->flags |= TCB_INSYSCALL;
1384 }
1385 }
1386 else {
1387 if (scno != 0) {
1388 if (debug) {
1389 /*
1390 * This happens when a signal handler
1391 * for a signal which interrupted a
1392 * a system call makes another system call.
1393 */
1394 fprintf(stderr, "syscall: missing exit\n");
1395 }
1396 tcp->flags &= ~TCB_INSYSCALL;
1397 }
1398 }
1399#endif /* SUNOS4 */
1400#ifdef LINUX
1401#if defined (I386)
1402 if (upeek(pid, 4*EAX, &eax) < 0)
1403 return -1;
1404 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1405 if (debug)
1406 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax);
1407 return 0;
1408 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001409#elif defined (X86_64)
1410 if (upeek(pid, 8*RAX, &rax) < 0)
1411 return -1;
Roland McGrath998fac72004-06-23 01:40:45 +00001412 if (current_personality == 1)
1413 rax = (long int)(int)rax; /* sign extend from 32 bits */
Michal Ludvig0e035502002-09-23 15:41:01 +00001414 if (rax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1415 if (debug)
1416 fprintf(stderr, "stray syscall exit: rax = %ld\n", rax);
1417 return 0;
1418 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001419#elif defined (S390) || defined (S390X)
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001420 if (upeek(pid, PT_GPR2, &gpr2) < 0)
1421 return -1;
Michal Ludvig882eda82002-11-11 12:50:47 +00001422 if (syscall_mode != -ENOSYS)
1423 syscall_mode = tcp->scno;
1424 if (gpr2 != syscall_mode && !(tcp->flags & TCB_INSYSCALL)) {
Wichert Akkerman12f75d12000-02-14 16:23:40 +00001425 if (debug)
1426 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2);
1427 return 0;
1428 }
Roland McGrath96dc5142003-01-20 10:23:04 +00001429 else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
1430 == (TCB_INSYSCALL|TCB_WAITEXECVE))
1431 && (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
1432 /*
1433 * Fake a return value of zero. We leave the TCB_WAITEXECVE
1434 * flag set for the post-execve SIGTRAP to see and reset.
1435 */
1436 gpr2 = 0;
1437 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001438#elif defined (POWERPC)
1439# define SO_MASK 0x10000000
Roland McGratheb285352003-01-14 09:59:00 +00001440 if (upeek(pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001441 return -1;
Roland McGratheb285352003-01-14 09:59:00 +00001442 if (upeek(pid, sizeof(unsigned long)*PT_R3, &result) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001443 return -1;
1444 if (flags & SO_MASK)
1445 result = -result;
1446#elif defined (M68K)
1447 if (upeek(pid, 4*PT_D0, &d0) < 0)
1448 return -1;
1449 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1450 if (debug)
1451 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0);
1452 return 0;
1453 }
1454#elif defined (ARM)
Roland McGrath0f87c492003-06-03 23:29:04 +00001455 /*
1456 * Nothing required
1457 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001458#elif defined (HPPA)
1459 if (upeek(pid, PT_GR28, &r28) < 0)
1460 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001461#elif defined(IA64)
1462 if (upeek(pid, PT_R10, &r10) < 0)
1463 return -1;
1464 if (upeek(pid, PT_R8, &r8) < 0)
1465 return -1;
1466 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
1467 if (debug)
1468 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8);
1469 return 0;
1470 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001471#endif
1472#endif /* LINUX */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001473 return 1;
1474}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001475
Roland McGrathc1e45922008-05-27 23:18:29 +00001476#ifdef LINUX
1477/*
1478 * Check the syscall return value register value for whether it is
1479 * a negated errno code indicating an error, or a success return value.
1480 */
1481static inline int
1482is_negated_errno(unsigned long int val)
1483{
1484 unsigned long int max = -(long int) nerrnos;
1485 if (personality_wordsize[current_personality] < sizeof(val)) {
1486 val = (unsigned int) val;
1487 max = (unsigned int) max;
1488 }
1489 return val > max;
1490}
1491#endif
1492
Roland McGratha4d48532005-06-08 20:45:28 +00001493static int
Pavel Machek4dc3b142000-02-01 17:58:41 +00001494get_error(tcp)
1495struct tcb *tcp;
1496{
1497 int u_error = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001498#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001499#if defined(S390) || defined(S390X)
Roland McGrathc1e45922008-05-27 23:18:29 +00001500 if (is_negated_errno(gpr2)) {
1501 tcp->u_rval = -1;
1502 u_error = -gpr2;
1503 }
1504 else {
1505 tcp->u_rval = gpr2;
1506 u_error = 0;
1507 }
Michal Ludvig10a88d02002-10-07 14:31:00 +00001508#else /* !S390 && !S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001509#ifdef I386
Roland McGrathc1e45922008-05-27 23:18:29 +00001510 if (is_negated_errno(eax)) {
1511 tcp->u_rval = -1;
1512 u_error = -eax;
1513 }
1514 else {
1515 tcp->u_rval = eax;
1516 u_error = 0;
1517 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001518#else /* !I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001519#ifdef X86_64
Roland McGrathc1e45922008-05-27 23:18:29 +00001520 if (is_negated_errno(rax)) {
1521 tcp->u_rval = -1;
1522 u_error = -rax;
1523 }
1524 else {
1525 tcp->u_rval = rax;
1526 u_error = 0;
1527 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001528#else
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001529#ifdef IA64
Roland McGrathc1e45922008-05-27 23:18:29 +00001530 if (ia32) {
1531 int err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001532
Roland McGrathc1e45922008-05-27 23:18:29 +00001533 err = (int)r8;
1534 if (is_negated_errno(err)) {
1535 tcp->u_rval = -1;
1536 u_error = -err;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001537 }
Roland McGrathc1e45922008-05-27 23:18:29 +00001538 else {
1539 tcp->u_rval = err;
1540 u_error = 0;
1541 }
1542 } else {
1543 if (r10) {
1544 tcp->u_rval = -1;
1545 u_error = r8;
1546 } else {
1547 tcp->u_rval = r8;
1548 u_error = 0;
1549 }
1550 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001551#else /* !IA64 */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001552#ifdef MIPS
1553 if (a3) {
1554 tcp->u_rval = -1;
1555 u_error = r2;
1556 } else {
1557 tcp->u_rval = r2;
1558 u_error = 0;
1559 }
1560#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001561#ifdef POWERPC
Roland McGrathc1e45922008-05-27 23:18:29 +00001562 if (is_negated_errno(result)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001563 tcp->u_rval = -1;
1564 u_error = -result;
1565 }
1566 else {
1567 tcp->u_rval = result;
1568 u_error = 0;
1569 }
1570#else /* !POWERPC */
1571#ifdef M68K
Roland McGrathc1e45922008-05-27 23:18:29 +00001572 if (is_negated_errno(d0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001573 tcp->u_rval = -1;
1574 u_error = -d0;
1575 }
1576 else {
1577 tcp->u_rval = d0;
1578 u_error = 0;
1579 }
1580#else /* !M68K */
1581#ifdef ARM
Roland McGrathc1e45922008-05-27 23:18:29 +00001582 if (is_negated_errno(regs.ARM_r0)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583 tcp->u_rval = -1;
Roland McGrath0f87c492003-06-03 23:29:04 +00001584 u_error = -regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001585 }
1586 else {
Roland McGrath0f87c492003-06-03 23:29:04 +00001587 tcp->u_rval = regs.ARM_r0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001588 u_error = 0;
1589 }
1590#else /* !ARM */
1591#ifdef ALPHA
1592 if (a3) {
1593 tcp->u_rval = -1;
1594 u_error = r0;
1595 }
1596 else {
1597 tcp->u_rval = r0;
1598 u_error = 0;
1599 }
1600#else /* !ALPHA */
1601#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001602 if (regs.r_psr & PSR_C) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001603 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001604 u_error = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605 }
1606 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001607 tcp->u_rval = regs.r_o0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001608 u_error = 0;
1609 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001610#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001611#ifdef SPARC64
1612 if (regs.r_tstate & 0x1100000000UL) {
1613 tcp->u_rval = -1;
1614 u_error = regs.r_o0;
1615 }
1616 else {
1617 tcp->u_rval = regs.r_o0;
1618 u_error = 0;
1619 }
1620#else /* !SPARC64 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001621#ifdef HPPA
Roland McGrathc1e45922008-05-27 23:18:29 +00001622 if (is_negated_errno(r28)) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001623 tcp->u_rval = -1;
1624 u_error = -r28;
1625 }
1626 else {
1627 tcp->u_rval = r28;
1628 u_error = 0;
1629 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00001630#else
1631#ifdef SH
Roland McGrathc1e45922008-05-27 23:18:29 +00001632 /* interpret R0 as return value or error number */
1633 if (is_negated_errno(r0)) {
1634 tcp->u_rval = -1;
1635 u_error = -r0;
1636 }
1637 else {
1638 tcp->u_rval = r0;
1639 u_error = 0;
1640 }
Roland McGrathe1e584b2003-06-02 19:18:58 +00001641#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001642#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001643 /* interpret result as return value or error number */
Roland McGrathc1e45922008-05-27 23:18:29 +00001644 if (is_negated_errno(r9)) {
Roland McGrathe1e584b2003-06-02 19:18:58 +00001645 tcp->u_rval = -1;
1646 u_error = -r9;
1647 }
1648 else {
1649 tcp->u_rval = r9;
1650 u_error = 0;
1651 }
Roland McGrathf5a47772003-06-26 22:40:42 +00001652#endif /* SH64 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001653#endif /* SH */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001654#endif /* HPPA */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001656#endif /* SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657#endif /* ALPHA */
1658#endif /* ARM */
1659#endif /* M68K */
1660#endif /* POWERPC */
Wichert Akkermanf90da011999-10-31 21:15:38 +00001661#endif /* MIPS */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001662#endif /* IA64 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001663#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664#endif /* I386 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001665#endif /* S390 || S390X */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666#endif /* LINUX */
1667#ifdef SUNOS4
1668 /* get error code from user struct */
1669 if (upeek(pid, uoff(u_error), &u_error) < 0)
1670 return -1;
1671 u_error >>= 24; /* u_error is a char */
1672
1673 /* get system call return value */
1674 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0)
1675 return -1;
1676#endif /* SUNOS4 */
1677#ifdef SVR4
1678#ifdef SPARC
1679 /* Judicious guessing goes a long way. */
1680 if (tcp->status.pr_reg[R_PSR] & 0x100000) {
1681 tcp->u_rval = -1;
1682 u_error = tcp->status.pr_reg[R_O0];
1683 }
1684 else {
1685 tcp->u_rval = tcp->status.pr_reg[R_O0];
1686 u_error = 0;
1687 }
1688#endif /* SPARC */
1689#ifdef I386
1690 /* Wanna know how to kill an hour single-stepping? */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001691 if (tcp->status.PR_REG[EFL] & 0x1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692 tcp->u_rval = -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001693 u_error = tcp->status.PR_REG[EAX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001694 }
1695 else {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001696 tcp->u_rval = tcp->status.PR_REG[EAX];
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001697#ifdef HAVE_LONG_LONG
1698 tcp->u_lrval =
1699 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) +
1700 tcp->status.PR_REG[EAX];
1701#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001702 u_error = 0;
1703 }
1704#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00001705#ifdef X86_64
1706 /* Wanna know how to kill an hour single-stepping? */
1707 if (tcp->status.PR_REG[EFLAGS] & 0x1) {
1708 tcp->u_rval = -1;
1709 u_error = tcp->status.PR_REG[RAX];
1710 }
1711 else {
1712 tcp->u_rval = tcp->status.PR_REG[RAX];
1713 u_error = 0;
1714 }
1715#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716#ifdef MIPS
1717 if (tcp->status.pr_reg[CTX_A3]) {
1718 tcp->u_rval = -1;
1719 u_error = tcp->status.pr_reg[CTX_V0];
1720 }
1721 else {
1722 tcp->u_rval = tcp->status.pr_reg[CTX_V0];
1723 u_error = 0;
1724 }
1725#endif /* MIPS */
1726#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001727#ifdef FREEBSD
1728 if (regs.r_eflags & PSL_C) {
1729 tcp->u_rval = -1;
1730 u_error = regs.r_eax;
1731 } else {
1732 tcp->u_rval = regs.r_eax;
1733 tcp->u_lrval =
1734 ((unsigned long long) regs.r_edx << 32) + regs.r_eax;
1735 u_error = 0;
1736 }
Roland McGrath761b5d72002-12-15 23:58:31 +00001737#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00001738 tcp->u_error = u_error;
1739 return 1;
1740}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001741
Roland McGrathb69f81b2002-12-21 23:25:18 +00001742int
1743force_result(tcp, error, rval)
1744 struct tcb *tcp;
1745 int error;
1746 long rval;
1747{
1748#ifdef LINUX
1749#if defined(S390) || defined(S390X)
1750 gpr2 = error ? -error : rval;
Roland McGrathb69f81b2002-12-21 23:25:18 +00001751 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
1752 return -1;
1753#else /* !S390 && !S390X */
1754#ifdef I386
1755 eax = error ? -error : rval;
1756 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
1757 return -1;
1758#else /* !I386 */
1759#ifdef X86_64
1760 rax = error ? -error : rval;
Roland McGrath998fac72004-06-23 01:40:45 +00001761 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 8), rax) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001762 return -1;
1763#else
1764#ifdef IA64
1765 if (ia32) {
1766 r8 = error ? -error : rval;
1767 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
1768 return -1;
1769 }
1770 else {
1771 if (error) {
1772 r8 = error;
1773 r10 = -1;
1774 }
1775 else {
1776 r8 = rval;
1777 r10 = 0;
1778 }
1779 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
1780 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
1781 return -1;
1782 }
1783#else /* !IA64 */
1784#ifdef MIPS
1785 if (error) {
1786 r2 = error;
1787 a3 = -1;
1788 }
1789 else {
1790 r2 = rval;
1791 a3 = 0;
1792 }
Roland McGrath542c2c62008-05-20 01:11:56 +00001793 /* PTRACE_POKEUSER is OK even for n32 since rval is only a long. */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001794 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1795 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
1796 return -1;
1797#else
1798#ifdef POWERPC
Roland McGratheb285352003-01-14 09:59:00 +00001799 if (upeek(tcp->pid, sizeof(unsigned long)*PT_CCR, &flags) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001800 return -1;
1801 if (error) {
1802 flags |= SO_MASK;
1803 result = error;
1804 }
1805 else {
1806 flags &= ~SO_MASK;
1807 result = rval;
1808 }
Roland McGratheb285352003-01-14 09:59:00 +00001809 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_CCR), flags) < 0 ||
1810 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(sizeof(unsigned long)*PT_R3), result) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001811 return -1;
1812#else /* !POWERPC */
1813#ifdef M68K
1814 d0 = error ? -error : rval;
1815 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
1816 return -1;
1817#else /* !M68K */
1818#ifdef ARM
Roland McGrath7c051d22003-06-26 22:29:32 +00001819 regs.ARM_r0 = error ? -error : rval;
1820 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), regs.ARM_r0) < 0)
Roland McGrathb69f81b2002-12-21 23:25:18 +00001821 return -1;
1822#else /* !ARM */
1823#ifdef ALPHA
1824 if (error) {
1825 a3 = -1;
1826 r0 = error;
1827 }
1828 else {
1829 a3 = 0;
1830 r0 = rval;
1831 }
1832 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
1833 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
1834 return -1;
1835#else /* !ALPHA */
1836#ifdef SPARC
1837 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1838 return -1;
1839 if (error) {
1840 regs.r_psr |= PSR_C;
1841 regs.r_o0 = error;
1842 }
1843 else {
1844 regs.r_psr &= ~PSR_C;
1845 regs.r_o0 = rval;
1846 }
1847 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1848 return -1;
1849#else /* !SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001850#ifdef SPARC64
1851 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
1852 return -1;
1853 if (error) {
1854 regs.r_tstate |= 0x1100000000UL;
1855 regs.r_o0 = error;
1856 }
1857 else {
1858 regs.r_tstate &= ~0x1100000000UL;
1859 regs.r_o0 = rval;
1860 }
1861 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
1862 return -1;
1863#else /* !SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001864#ifdef HPPA
1865 r28 = error ? -error : rval;
1866 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
1867 return -1;
1868#else
1869#ifdef SH
1870 r0 = error ? -error : rval;
1871 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
1872 return -1;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001873#else
Roland McGrathf5a47772003-06-26 22:40:42 +00001874#ifdef SH64
Roland McGrathe1e584b2003-06-02 19:18:58 +00001875 r9 = error ? -error : rval;
1876 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)REG_GENERAL(9), r9) < 0)
1877 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001878#endif /* SH64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001879#endif /* SH */
1880#endif /* HPPA */
1881#endif /* SPARC */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001882#endif /* SPARC64 */
Roland McGrathb69f81b2002-12-21 23:25:18 +00001883#endif /* ALPHA */
1884#endif /* ARM */
1885#endif /* M68K */
1886#endif /* POWERPC */
1887#endif /* MIPS */
1888#endif /* IA64 */
1889#endif /* X86_64 */
1890#endif /* I386 */
1891#endif /* S390 || S390X */
1892#endif /* LINUX */
1893#ifdef SUNOS4
1894 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
1895 error << 24) < 0 ||
1896 ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
1897 return -1;
1898#endif /* SUNOS4 */
1899#ifdef SVR4
1900 /* XXX no clue */
1901 return -1;
1902#endif /* SVR4 */
1903#ifdef FREEBSD
1904 if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1905 perror("pread");
1906 return -1;
1907 }
1908 if (error) {
1909 regs.r_eflags |= PSL_C;
1910 regs.r_eax = error;
1911 }
1912 else {
1913 regs.r_eflags &= ~PSL_C;
1914 regs.r_eax = rval;
1915 }
1916 if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
1917 perror("pwrite");
1918 return -1;
1919 }
1920#endif /* FREEBSD */
1921
1922 /* All branches reach here on success (only). */
1923 tcp->u_error = error;
1924 tcp->u_rval = rval;
1925 return 0;
1926}
1927
Roland McGratha4d48532005-06-08 20:45:28 +00001928static int
1929syscall_enter(tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00001930struct tcb *tcp;
1931{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001932#ifndef USE_PROCFS
Pavel Machek4dc3b142000-02-01 17:58:41 +00001933 int pid = tcp->pid;
Roland McGrath761b5d72002-12-15 23:58:31 +00001934#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001935#ifdef LINUX
Michal Ludvig10a88d02002-10-07 14:31:00 +00001936#if defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001937 {
1938 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001939 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1940 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001941 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001942 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001943 for (i = 0; i < tcp->u_nargs; i++) {
Michal Ludvig10a88d02002-10-07 14:31:00 +00001944 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+i*sizeof(long), &tcp->u_arg[i]) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001945 return -1;
1946 }
1947 }
1948#elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001949 {
1950 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001951 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
1952 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00001953 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001954 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001955 for (i = 0; i < tcp->u_nargs; i++) {
Wichert Akkermanb859bea1999-04-18 22:50:50 +00001956 /* WTA: if scno is out-of-bounds this will bomb. Add range-check
1957 * for scno somewhere above here!
1958 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001959 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0)
1960 return -1;
1961 }
1962 }
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001963#elif defined (IA64)
1964 {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001965 if (!ia32) {
1966 unsigned long *out0, *rbs_end, cfm, sof, sol, i;
1967 /* be backwards compatible with kernel < 2.4.4... */
1968# ifndef PT_RBS_END
1969# define PT_RBS_END PT_AR_BSP
1970# endif
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001971
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001972 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001973 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001974 if (upeek(pid, PT_CFM, (long *) &cfm) < 0)
1975 return -1;
1976
1977 sof = (cfm >> 0) & 0x7f;
1978 sol = (cfm >> 7) & 0x7f;
1979 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol);
1980
1981 if (tcp->scno >= 0 && tcp->scno < nsyscalls
1982 && sysent[tcp->scno].nargs != -1)
1983 tcp->u_nargs = sysent[tcp->scno].nargs;
1984 else
1985 tcp->u_nargs = MAX_ARGS;
1986 for (i = 0; i < tcp->u_nargs; ++i) {
1987 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i),
1988 sizeof(long), (char *) &tcp->u_arg[i]) < 0)
1989 return -1;
1990 }
1991 } else {
1992 int i;
1993
1994 if (/* EBX = out0 */
1995 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0
1996 /* ECX = out1 */
1997 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0
1998 /* EDX = out2 */
1999 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0
2000 /* ESI = out3 */
2001 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0
2002 /* EDI = out4 */
2003 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0
2004 /* EBP = out5 */
2005 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0)
2006 return -1;
2007
2008 for (i = 0; i < 6; ++i)
2009 /* truncate away IVE sign-extension */
2010 tcp->u_arg[i] &= 0xffffffff;
2011
2012 if (tcp->scno >= 0 && tcp->scno < nsyscalls
2013 && sysent[tcp->scno].nargs != -1)
2014 tcp->u_nargs = sysent[tcp->scno].nargs;
2015 else
2016 tcp->u_nargs = 5;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002017 }
2018 }
Roland McGrath542c2c62008-05-20 01:11:56 +00002019#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
2020 /* N32 and N64 both use up to six registers. */
2021 {
2022 unsigned long long regs[38];
2023 int i, nargs;
2024
2025 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2026 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrathc1e45922008-05-27 23:18:29 +00002027 else
Roland McGrath542c2c62008-05-20 01:11:56 +00002028 nargs = tcp->u_nargs = MAX_ARGS;
2029
2030 if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
2031 return -1;
2032
2033 for(i = 0; i < nargs; i++) {
2034 tcp->u_arg[i] = regs[REG_A0 + i];
2035# if defined (LINUX_MIPSN32)
2036 tcp->ext_arg[i] = regs[REG_A0 + i];
2037# endif
2038 }
2039 }
Wichert Akkermanf90da011999-10-31 21:15:38 +00002040#elif defined (MIPS)
2041 {
2042 long sp;
2043 int i, nargs;
2044
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002045 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2046 nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002047 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002048 nargs = tcp->u_nargs = MAX_ARGS;
Wichert Akkermanf90da011999-10-31 21:15:38 +00002049 if(nargs > 4) {
2050 if(upeek(pid, REG_SP, &sp) < 0)
2051 return -1;
2052 for(i = 0; i < 4; i++) {
2053 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0)
2054 return -1;
2055 }
2056 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]),
2057 (char *)(tcp->u_arg + 4));
2058 } else {
2059 for(i = 0; i < nargs; i++) {
2060 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0)
2061 return -1;
2062 }
2063 }
2064 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002065#elif defined (POWERPC)
Roland McGrath761b5d72002-12-15 23:58:31 +00002066#ifndef PT_ORIG_R3
2067#define PT_ORIG_R3 34
2068#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002069 {
2070 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002071 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2072 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002073 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002074 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002075 for (i = 0; i < tcp->u_nargs; i++) {
Roland McGratheb285352003-01-14 09:59:00 +00002076 if (upeek(pid, (i==0) ?
2077 (sizeof(unsigned long)*PT_ORIG_R3) :
2078 ((i+PT_R3)*sizeof(unsigned long)),
2079 &tcp->u_arg[i]) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002080 return -1;
2081 }
2082 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002083#elif defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002084 {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002085 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002086
2087 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2088 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002089 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002090 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002091 for (i = 0; i < tcp->u_nargs; i++)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002092 tcp->u_arg[i] = *((&regs.r_o0) + i);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002093 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002094#elif defined (HPPA)
2095 {
2096 int i;
2097
2098 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2099 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002100 else
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002101 tcp->u_nargs = MAX_ARGS;
2102 for (i = 0; i < tcp->u_nargs; i++) {
2103 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
2104 return -1;
2105 }
2106 }
Roland McGrath0f87c492003-06-03 23:29:04 +00002107#elif defined(ARM)
2108 {
2109 int i;
2110
2111 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2112 tcp->u_nargs = sysent[tcp->scno].nargs;
2113 else
2114 tcp->u_nargs = MAX_ARGS;
2115 for (i = 0; i < tcp->u_nargs; i++)
2116 tcp->u_arg[i] = regs.uregs[i];
2117 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002118#elif defined(SH)
2119 {
Roland McGrath761b5d72002-12-15 23:58:31 +00002120 int i;
Wichert Akkermanccef6372002-05-01 16:39:22 +00002121 static int syscall_regs[] = {
2122 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7,
2123 REG_REG0, REG_REG0+1, REG_REG0+2
2124 };
2125
2126 tcp->u_nargs = sysent[tcp->scno].nargs;
2127 for (i = 0; i < tcp->u_nargs; i++) {
2128 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0)
2129 return -1;
2130 }
2131 }
Roland McGrathf5a47772003-06-26 22:40:42 +00002132#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00002133 {
2134 int i;
2135 /* Registers used by SH5 Linux system calls for parameters */
2136 static int syscall_regs[] = { 2, 3, 4, 5, 6, 7 };
2137
2138 /*
2139 * TODO: should also check that the number of arguments encoded
2140 * in the trap number matches the number strace expects.
2141 */
2142 /*
2143 assert(sysent[tcp->scno].nargs <
2144 sizeof(syscall_regs)/sizeof(syscall_regs[0]));
2145 */
2146
2147 tcp->u_nargs = sysent[tcp->scno].nargs;
2148 for (i = 0; i < tcp->u_nargs; i++) {
2149 if (upeek(pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
2150 return -1;
2151 }
2152 }
2153
Michal Ludvig0e035502002-09-23 15:41:01 +00002154#elif defined(X86_64)
2155 {
2156 int i;
2157 static int argreg[SUPPORTED_PERSONALITIES][MAX_ARGS] = {
2158 {RDI,RSI,RDX,R10,R8,R9}, /* x86-64 ABI */
Roland McGrath5a9c6ad2005-02-02 03:06:52 +00002159 {RBX,RCX,RDX,RSI,RDI,RBP} /* i386 ABI */
Michal Ludvig0e035502002-09-23 15:41:01 +00002160 };
Roland McGrath761b5d72002-12-15 23:58:31 +00002161
Michal Ludvig0e035502002-09-23 15:41:01 +00002162 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2163 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002164 else
Michal Ludvig0e035502002-09-23 15:41:01 +00002165 tcp->u_nargs = MAX_ARGS;
2166 for (i = 0; i < tcp->u_nargs; i++) {
2167 if (upeek(pid, argreg[current_personality][i]*8, &tcp->u_arg[i]) < 0)
2168 return -1;
2169 }
2170 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002171#else /* Other architecture (like i386) (32bits specific) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002172 {
2173 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002174 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2175 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002176 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002177 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002178 for (i = 0; i < tcp->u_nargs; i++) {
2179 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0)
2180 return -1;
2181 }
2182 }
Roland McGrath761b5d72002-12-15 23:58:31 +00002183#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002184#endif /* LINUX */
2185#ifdef SUNOS4
2186 {
2187 int i;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002188 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2189 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002190 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002191 tcp->u_nargs = MAX_ARGS;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002192 for (i = 0; i < tcp->u_nargs; i++) {
2193 struct user *u;
2194
2195 if (upeek(pid, uoff(u_arg[0]) +
2196 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0)
2197 return -1;
2198 }
2199 }
2200#endif /* SUNOS4 */
2201#ifdef SVR4
2202#ifdef MIPS
2203 /*
2204 * SGI is broken: even though it has pr_sysarg, it doesn't
2205 * set them on system call entry. Get a clue.
2206 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002207 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002208 tcp->u_nargs = sysent[tcp->scno].nargs;
2209 else
2210 tcp->u_nargs = tcp->status.pr_nsysarg;
2211 if (tcp->u_nargs > 4) {
2212 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2213 4*sizeof(tcp->u_arg[0]));
2214 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16,
2215 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4));
2216 }
2217 else {
2218 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0],
2219 tcp->u_nargs*sizeof(tcp->u_arg[0]));
2220 }
John Hughes25299712001-03-06 10:10:06 +00002221#elif UNIXWARE >= 2
2222 /*
2223 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit
2224 */
2225 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
2226 tcp->u_nargs = sysent[tcp->scno].nargs;
2227 else
2228 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg;
2229 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
2230 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
2231#elif defined (HAVE_PR_SYSCALL)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002232 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002233 tcp->u_nargs = sysent[tcp->scno].nargs;
2234 else
2235 tcp->u_nargs = tcp->status.pr_nsysarg;
2236 {
2237 int i;
2238 for (i = 0; i < tcp->u_nargs; i++)
2239 tcp->u_arg[i] = tcp->status.pr_sysarg[i];
2240 }
John Hughes25299712001-03-06 10:10:06 +00002241#elif defined (I386)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002242 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002243 tcp->u_nargs = sysent[tcp->scno].nargs;
2244 else
2245 tcp->u_nargs = 5;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002246 umoven(tcp, tcp->status.PR_REG[UESP] + 4,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg);
John Hughes25299712001-03-06 10:10:06 +00002248#else
2249 I DONT KNOW WHAT TO DO
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002250#endif /* !HAVE_PR_SYSCALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002251#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002252#ifdef FREEBSD
2253 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2254 sysent[tcp->scno].nargs > tcp->status.val)
2255 tcp->u_nargs = sysent[tcp->scno].nargs;
Roland McGrath761b5d72002-12-15 23:58:31 +00002256 else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002257 tcp->u_nargs = tcp->status.val;
2258 if (tcp->u_nargs < 0)
2259 tcp->u_nargs = 0;
2260 if (tcp->u_nargs > MAX_ARGS)
2261 tcp->u_nargs = MAX_ARGS;
2262 switch(regs.r_eax) {
2263 case SYS___syscall:
2264 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2265 regs.r_esp + sizeof(int) + sizeof(quad_t));
2266 break;
2267 case SYS_syscall:
2268 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2269 regs.r_esp + 2 * sizeof(int));
2270 break;
2271 default:
2272 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long),
2273 regs.r_esp + sizeof(int));
2274 break;
2275 }
2276#endif /* FREEBSD */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002277 return 1;
2278}
2279
2280int
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002281trace_syscall(struct tcb *tcp)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002282{
2283 int sys_res;
2284 struct timeval tv;
2285 int res;
2286
2287 /* Measure the exit time as early as possible to avoid errors. */
2288 if (dtime && (tcp->flags & TCB_INSYSCALL))
2289 gettimeofday(&tv, NULL);
2290
2291 res = get_scno(tcp);
2292 if (res != 1)
2293 return res;
2294
2295 res = syscall_fixup(tcp);
2296 if (res != 1)
2297 return res;
2298
2299 if (tcp->flags & TCB_INSYSCALL) {
2300 long u_error;
2301 res = get_error(tcp);
2302 if (res != 1)
2303 return res;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002304
2305 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002306 if (tcp->scno >= 0 && tcp->scno < nsyscalls &&
2307 !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002308 tcp->flags &= ~TCB_INSYSCALL;
2309 return 0;
2310 }
2311
2312 if (tcp->flags & TCB_REPRINT) {
2313 printleader(tcp);
2314 tprintf("<... ");
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002315 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Pavel Machek4dc3b142000-02-01 17:58:41 +00002316 tprintf("syscall_%lu", tcp->scno);
2317 else
2318 tprintf("%s", sysent[tcp->scno].sys_name);
2319 tprintf(" resumed> ");
2320 }
2321
Dmitry V. Levin7d61ff12006-12-21 21:15:04 +00002322 if (cflag)
2323 return count_syscall(tcp, &tv);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002324
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002325 if (tcp->scno >= nsyscalls || tcp->scno < 0
Pavel Machek4dc3b142000-02-01 17:58:41 +00002326 || (qual_flags[tcp->scno] & QUAL_RAW))
2327 sys_res = printargs(tcp);
Michal Ludvig17f8fb32002-11-06 13:17:21 +00002328 else {
2329 if (not_failing_only && tcp->u_error)
Roland McGrath761b5d72002-12-15 23:58:31 +00002330 return 0; /* ignore failed syscalls */
Pavel Machek4dc3b142000-02-01 17:58:41 +00002331 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
Roland McGrath761b5d72002-12-15 23:58:31 +00002332 }
Pavel Machek4dc3b142000-02-01 17:58:41 +00002333 u_error = tcp->u_error;
2334 tprintf(") ");
2335 tabto(acolumn);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002336 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
2337 qual_flags[tcp->scno] & QUAL_RAW) {
Pavel Machek4dc3b142000-02-01 17:58:41 +00002338 if (u_error)
2339 tprintf("= -1 (errno %ld)", u_error);
2340 else
2341 tprintf("= %#lx", tcp->u_rval);
2342 }
2343 else if (!(sys_res & RVAL_NONE) && u_error) {
2344 switch (u_error) {
2345#ifdef LINUX
2346 case ERESTARTSYS:
2347 tprintf("= ? ERESTARTSYS (To be restarted)");
2348 break;
2349 case ERESTARTNOINTR:
2350 tprintf("= ? ERESTARTNOINTR (To be restarted)");
2351 break;
2352 case ERESTARTNOHAND:
2353 tprintf("= ? ERESTARTNOHAND (To be restarted)");
2354 break;
Roland McGrath9c555e72003-07-09 09:47:59 +00002355 case ERESTART_RESTARTBLOCK:
2356 tprintf("= ? ERESTART_RESTARTBLOCK (To be restarted)");
2357 break;
Pavel Machek4dc3b142000-02-01 17:58:41 +00002358#endif /* LINUX */
2359 default:
2360 tprintf("= -1 ");
Wichert Akkerman4527dae2002-03-31 19:03:29 +00002361 if (u_error < 0)
2362 tprintf("E??? (errno %ld)", u_error);
Pavel Machek4dc3b142000-02-01 17:58:41 +00002363 else if (u_error < nerrnos)
Roland McGrath761b5d72002-12-15 23:58:31 +00002364 tprintf("%s (%s)", errnoent[u_error],
2365 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002366 else
Roland McGrath761b5d72002-12-15 23:58:31 +00002367 tprintf("ERRNO_%ld (%s)", u_error,
2368 strerror(u_error));
Pavel Machek4dc3b142000-02-01 17:58:41 +00002369 break;
2370 }
2371 }
2372 else {
2373 if (sys_res & RVAL_NONE)
2374 tprintf("= ?");
2375 else {
2376 switch (sys_res & RVAL_MASK) {
2377 case RVAL_HEX:
2378 tprintf("= %#lx", tcp->u_rval);
2379 break;
2380 case RVAL_OCTAL:
2381 tprintf("= %#lo", tcp->u_rval);
2382 break;
2383 case RVAL_UDECIMAL:
2384 tprintf("= %lu", tcp->u_rval);
2385 break;
2386 case RVAL_DECIMAL:
2387 tprintf("= %ld", tcp->u_rval);
2388 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002389#ifdef HAVE_LONG_LONG
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002390 case RVAL_LHEX:
2391 tprintf("= %#llx", tcp->u_lrval);
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002392 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002393 case RVAL_LOCTAL:
2394 tprintf("= %#llo", tcp->u_lrval);
2395 break;
2396 case RVAL_LUDECIMAL:
2397 tprintf("= %llu", tcp->u_lrval);
2398 break;
2399 case RVAL_LDECIMAL:
2400 tprintf("= %lld", tcp->u_lrval);
2401 break;
Wichert Akkerman16a03d22000-08-10 02:14:04 +00002402#endif
Pavel Machek4dc3b142000-02-01 17:58:41 +00002403 default:
2404 fprintf(stderr,
2405 "invalid rval format\n");
2406 break;
2407 }
2408 }
2409 if ((sys_res & RVAL_STR) && tcp->auxstr)
2410 tprintf(" (%s)", tcp->auxstr);
2411 }
2412 if (dtime) {
2413 tv_sub(&tv, &tv, &tcp->etime);
2414 tprintf(" <%ld.%06ld>",
2415 (long) tv.tv_sec, (long) tv.tv_usec);
2416 }
2417 printtrailer(tcp);
2418
2419 dumpio(tcp);
2420 if (fflush(tcp->outf) == EOF)
2421 return -1;
2422 tcp->flags &= ~TCB_INSYSCALL;
2423 return 0;
2424 }
2425
2426 /* Entering system call */
2427 res = syscall_enter(tcp);
2428 if (res != 1)
2429 return res;
2430
Roland McGrath17352792005-06-07 23:21:26 +00002431 switch (known_scno(tcp)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002432#ifdef LINUX
Roland McGrath5e48c542008-05-19 23:50:24 +00002433#if !defined (ALPHA) && !defined(MIPS) && !defined(HPPA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002434 case SYS_socketcall:
2435 decode_subcall(tcp, SYS_socket_subcall,
2436 SYS_socket_nsubcalls, deref_style);
2437 break;
2438 case SYS_ipc:
2439 decode_subcall(tcp, SYS_ipc_subcall,
2440 SYS_ipc_nsubcalls, shift_style);
2441 break;
Roland McGrath5e48c542008-05-19 23:50:24 +00002442#endif /* !(ALPHA || MIPS || HPPA) */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002443#endif /* LINUX */
2444#ifdef SVR4
2445#ifdef SYS_pgrpsys_subcall
2446 case SYS_pgrpsys:
2447 decode_subcall(tcp, SYS_pgrpsys_subcall,
2448 SYS_pgrpsys_nsubcalls, shift_style);
2449 break;
2450#endif /* SYS_pgrpsys_subcall */
2451#ifdef SYS_sigcall_subcall
2452 case SYS_sigcall:
2453 decode_subcall(tcp, SYS_sigcall_subcall,
2454 SYS_sigcall_nsubcalls, mask_style);
2455 break;
2456#endif /* SYS_sigcall_subcall */
2457 case SYS_msgsys:
2458 decode_subcall(tcp, SYS_msgsys_subcall,
2459 SYS_msgsys_nsubcalls, shift_style);
2460 break;
2461 case SYS_shmsys:
2462 decode_subcall(tcp, SYS_shmsys_subcall,
2463 SYS_shmsys_nsubcalls, shift_style);
2464 break;
2465 case SYS_semsys:
2466 decode_subcall(tcp, SYS_semsys_subcall,
2467 SYS_semsys_nsubcalls, shift_style);
2468 break;
2469#if 0 /* broken */
2470 case SYS_utssys:
2471 decode_subcall(tcp, SYS_utssys_subcall,
2472 SYS_utssys_nsubcalls, shift_style);
2473 break;
2474#endif
2475 case SYS_sysfs:
2476 decode_subcall(tcp, SYS_sysfs_subcall,
2477 SYS_sysfs_nsubcalls, shift_style);
2478 break;
2479 case SYS_spcall:
2480 decode_subcall(tcp, SYS_spcall_subcall,
2481 SYS_spcall_nsubcalls, shift_style);
2482 break;
2483#ifdef SYS_context_subcall
2484 case SYS_context:
2485 decode_subcall(tcp, SYS_context_subcall,
2486 SYS_context_nsubcalls, shift_style);
2487 break;
2488#endif /* SYS_context_subcall */
Wichert Akkerman8829a551999-06-11 13:18:40 +00002489#ifdef SYS_door_subcall
2490 case SYS_door:
2491 decode_subcall(tcp, SYS_door_subcall,
2492 SYS_door_nsubcalls, door_style);
2493 break;
2494#endif /* SYS_door_subcall */
John Hughesbdf48f52001-03-06 15:08:09 +00002495#ifdef SYS_kaio_subcall
2496 case SYS_kaio:
2497 decode_subcall(tcp, SYS_kaio_subcall,
2498 SYS_kaio_nsubcalls, shift_style);
2499 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002500#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002501#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002502#ifdef FREEBSD
2503 case SYS_msgsys:
2504 case SYS_shmsys:
2505 case SYS_semsys:
2506 decode_subcall(tcp, 0, 0, table_style);
2507 break;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002508#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002509#ifdef SUNOS4
2510 case SYS_semsys:
2511 decode_subcall(tcp, SYS_semsys_subcall,
2512 SYS_semsys_nsubcalls, shift_style);
2513 break;
2514 case SYS_msgsys:
2515 decode_subcall(tcp, SYS_msgsys_subcall,
2516 SYS_msgsys_nsubcalls, shift_style);
2517 break;
2518 case SYS_shmsys:
2519 decode_subcall(tcp, SYS_shmsys_subcall,
2520 SYS_shmsys_nsubcalls, shift_style);
2521 break;
2522#endif
2523 }
2524
2525 internal_syscall(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002526 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002527 tcp->flags |= TCB_INSYSCALL;
2528 return 0;
2529 }
2530
2531 if (cflag) {
2532 gettimeofday(&tcp->etime, NULL);
2533 tcp->flags |= TCB_INSYSCALL;
2534 return 0;
2535 }
2536
2537 printleader(tcp);
2538 tcp->flags &= ~TCB_REPRINT;
2539 tcp_last = tcp;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002540 if (tcp->scno >= nsyscalls || tcp->scno < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002541 tprintf("syscall_%lu(", tcp->scno);
2542 else
2543 tprintf("%s(", sysent[tcp->scno].sys_name);
Roland McGrath761b5d72002-12-15 23:58:31 +00002544 if (tcp->scno >= nsyscalls || tcp->scno < 0 ||
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002545 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit))
2546 sys_res = printargs(tcp);
2547 else
2548 sys_res = (*sysent[tcp->scno].sys_func)(tcp);
2549 if (fflush(tcp->outf) == EOF)
2550 return -1;
2551 tcp->flags |= TCB_INSYSCALL;
2552 /* Measure the entrance time as late as possible to avoid errors. */
2553 if (dtime)
2554 gettimeofday(&tcp->etime, NULL);
2555 return sys_res;
2556}
2557
2558int
2559printargs(tcp)
2560struct tcb *tcp;
2561{
2562 if (entering(tcp)) {
2563 int i;
2564
2565 for (i = 0; i < tcp->u_nargs; i++)
2566 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
2567 }
2568 return 0;
2569}
2570
2571long
2572getrval2(tcp)
2573struct tcb *tcp;
2574{
2575 long val = -1;
2576
2577#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002578#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002579 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002580 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
2581 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002582 val = regs.r_o1;
Roland McGrath6b1d43e2003-03-31 01:05:01 +00002583#elif defined(SH)
2584 if (upeek(tcp->pid, 4*(REG_REG0+1), &val) < 0)
2585 return -1;
Roland McGrathb4ce1762004-03-01 20:30:48 +00002586#elif defined(IA64)
2587 if (upeek(tcp->pid, PT_R9, &val) < 0)
2588 return -1;
Roland McGrath920e6bb2005-03-15 02:15:20 +00002589#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002590#endif /* LINUX */
2591
2592#ifdef SUNOS4
2593 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0)
2594 return -1;
2595#endif /* SUNOS4 */
2596
2597#ifdef SVR4
2598#ifdef SPARC
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002599 val = tcp->status.PR_REG[R_O1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002600#endif /* SPARC */
2601#ifdef I386
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002602 val = tcp->status.PR_REG[EDX];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002603#endif /* I386 */
Michal Ludvig0e035502002-09-23 15:41:01 +00002604#ifdef X86_64
2605 val = tcp->status.PR_REG[RDX];
2606#endif /* X86_64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002607#ifdef MIPS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002608 val = tcp->status.PR_REG[CTX_V1];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002609#endif /* MIPS */
2610#endif /* SVR4 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002611#ifdef FREEBSD
2612 struct reg regs;
2613 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
2614 val = regs.r_edx;
Roland McGrath761b5d72002-12-15 23:58:31 +00002615#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002616 return val;
2617}
2618
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002619#ifdef SUNOS4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002620/*
2621 * Apparently, indirect system calls have already be converted by ptrace(2),
2622 * so if you see "indir" this program has gone astray.
2623 */
2624int
2625sys_indir(tcp)
2626struct tcb *tcp;
2627{
2628 int i, scno, nargs;
2629
2630 if (entering(tcp)) {
2631 if ((scno = tcp->u_arg[0]) > nsyscalls) {
2632 fprintf(stderr, "Bogus syscall: %u\n", scno);
2633 return 0;
2634 }
2635 nargs = sysent[scno].nargs;
2636 tprintf("%s", sysent[scno].sys_name);
2637 for (i = 0; i < nargs; i++)
2638 tprintf(", %#lx", tcp->u_arg[i+1]);
2639 }
2640 return 0;
2641}
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +00002642#endif /* SUNOS4 */